1#!/usr/local/bin/bash
2
3# force indendation settings
4# vim: ts=4 shiftwidth=4 expandtab
5
6########################################################################
7########################################################################
8########################################################################
9
10#  Copyright (C) 2017 Tomasz Wisniewski aka
11#       DAGON <tomasz.wisni3wski@gmail.com>
12#
13#  http://github.com/dagon666
14#  http://pcarduino.blogspot.co.uk
15#
16#
17#  This program is free software: you can redistribute it and/or modify
18#  it under the terms of the GNU General Public License as published by
19#  the Free Software Foundation, either version 3 of the License, or
20#  (at your option) any later version.
21#
22#  This program is distributed in the hope that it will be useful,
23#  but WITHOUT ANY WARRANTY; without even the implied warranty of
24#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25#  GNU General Public License for more details.
26#
27#  You should have received a copy of the GNU General Public License
28#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
29
30########################################################################
31########################################################################
32########################################################################
33
34declare -r ___g_fsUnlink=0
35declare -r ___g_fsStat=1
36declare -r ___g_fsBase64=2
37declare -r ___g_fsMd5=3
38declare -r ___g_fsCp=4
39declare -r ___g_fs7z=5
40declare -r ___g_fsFps=6
41
42declare -a ___g_fsWrappers=( 'none' 'none' 'none' \
43    'none' 'cp' 'none' 'none' )
44
45___g_fsGarbageCollectorLog=
46
47########################################################################
48
49#
50# @brief configure the stat tool
51#
52_fs_configureStat_GV() {
53    [ "${___g_fsWrappers[$___g_fsStat]}" = 'none' ] || return $G_RETNOACT
54    # verify stat tool
55    ___g_fsWrappers[$___g_fsStat]="stat -c%s "
56
57    if wrappers_isSystemDarwin || wrappers_isSystemFreeBSD; then
58        # stat may be installed through macports, check if
59        # there's a need to reconfigure it to BSD flavour
60        ${___g_fsWrappers[$___g_fsStat]} "$0" >/dev/null 2>&1 ||
61            ___g_fsWrappers[$___g_fsStat]="stat -f%z "
62    fi
63}
64
65#
66# configure the base64 tool
67#
68_fs_configureBase64_GV() {
69    [ "${___g_fsWrappers[$___g_fsBase64]}" = 'none' ] || return $G_RETNOACT
70    ___g_fsWrappers[$___g_fsBase64]="base64 -d"
71
72    # verify base64
73    wrappers_isSystemDarwin &&
74        ___g_fsWrappers[$___g_fsBase64]="base64 -D"
75    wrappers_isSystemFreeBSD &&
76        ___g_fsWrappers[$___g_fsBase64]="base64 -d"
77}
78
79#
80# configure the md5 tool
81#
82_fs_configureMd5_GV() {
83    [ "${___g_fsWrappers[$___g_fsMd5]}" = 'none' ] || return $G_RETNOACT
84
85    # verify md5 tool
86    ___g_fsWrappers[$___g_fsMd5]="md5sum"
87    wrappers_isSystemDarwin &&
88        ___g_fsWrappers[$___g_fsMd5]="md5"
89    wrappers_isSystemFreeBSD &&
90        ___g_fsWrappers[$___g_fsMd5]="md5"
91}
92
93#
94# @brief configure the unlink tool
95#
96_fs_configureUnlink_GV() {
97    [ "${___g_fsWrappers[$___g_fsUnlink]}" = 'none' ] || return $G_RETNOACT
98
99    ___g_fsWrappers[$___g_fsUnlink]='rm -rf'
100    tools_isDetected "unlink" &&
101        ___g_fsWrappers[$___g_fsUnlink]='unlink'
102}
103
104#
105# @brief verify presence of any of the 7z tools
106#
107_fs_configure7z_GV() {
108    [ "${___g_fsWrappers[$___g_fs7z]}" = 'none' ] || return $G_RETNOACT
109    local k=''
110
111    # use 7z or 7za only, 7zr doesn't support passwords
112    declare -a t7zs=( '7za' '7z' )
113
114    for k in "${t7zs[@]}"; do
115        tools_isDetected "$k" &&
116            ___g_fsWrappers[$___g_fs7z]="$k" &&
117            break
118    done
119}
120
121#
122# @brief exit callback performing temporary files garbage collection
123#
124_fs_garbageCollectorCleaner() {
125    [ -z "$___g_fsGarbageCollectorLog" ] && return
126
127    logging_debug $LINENO $"usuwam pliki tymczasowe"
128
129    local entry=
130    while IFS='' read -r entry && [ -n "$entry"  ]; do
131        [ -e "$entry" ] && {
132            logging_debug $LINENO $"usuwam" "[$entry]"
133            rm -rf "$entry"
134        }
135    done < "$___g_fsGarbageCollectorLog"
136
137    logging_debug $LINENO \
138        $"usuwam dziennik plikow tymczasowych" "[$___g_fsGarbageCollectorLog]"
139    rm -rf "$___g_fsGarbageCollectorLog"
140}
141
142#
143# @brief garbage collector callback installer
144#
145_fs_configureGarbageCollector() {
146    [ -n "$___g_fsGarbageCollectorLog" ] && return
147    ___g_fsGarbageCollectorLog=$(mktemp -t napi.gclog.XXXXXXXX)
148    trap _fs_garbageCollectorCleaner EXIT
149}
150
151#
152# @brief verify configured fps tool
153#
154_fs_verifyFpsTool() {
155    # don't do anything if the tool has been already marked as unavailable
156    [ "${___g_fsWrappers[$___g_fsFps]}" = 'unavailable' ] &&
157        return $G_RETUNAV
158
159    # verify selected fps tool
160    if [ "${___g_fsWrappers[$___g_fsFps]}" = 'none' ] ||
161        ! tools_isInGroupAndDetected 'fps' \
162        "${___g_fsWrappers[$___g_fsFps]}"; then
163        # choose first available as the default tool
164        local firstav=''
165        firstav=$(tools_getFirstAvailableFromGroup_SO "fps")
166        [ -z "$firstav" ] && return $G_RETPARAM
167        ___g_fsWrappers[$___g_fsFps]="$firstav"
168    fi
169}
170
171#
172# @brief detect fps of the video file
173# @param tool
174# @param filepath
175#
176_fs_getFpsWithTool() {
177    local fps=0
178    local tbr=0
179    local t="${1:-none}"
180
181    local tmp=''
182    declare -a atmp=()
183
184    # don't bother if there's no tool available or not specified
185    if [ -z "$t" ] ||
186        [ "$t" = "none" ] ||
187        [ "$t" = "unavailable" ] ||
188        ! tools_isDetected "$t"; then
189        echo $fps
190        # shellcheck disable=SC2086
191        return $G_RETPARAM
192    fi
193
194    case "$t" in
195        'mplayer' | 'mplayer2' )
196        fps=$($t -identify -vo null \
197            -ao null \
198            -frames 0 "$2" 2> /dev/null | \
199            grep ID_VIDEO_FPS | \
200            cut -d '=' -f 2)
201        ;;
202
203        'mediainfo' )
204        fps=$($t --Output='Video;%FrameRate%' "$2")
205        ;;
206
207        'ffmpeg' )
208        tmp=$($t -i "$2" 2>&1 | grep "Video:")
209        tbr=$(echo "$tmp" | \
210            sed 's/, /\n/g' | \
211            tr -d ')(' | \
212            grep tbr | \
213            cut -d ' ' -f 1)
214        fps=$(echo "$tmp" | \
215            sed 's/, /\n/g' | \
216            grep fps | \
217            cut -d ' ' -f 1)
218        [ -z "$fps" ] && fps="$tbr"
219        ;;
220
221        'ffprobe' )
222        tmp=$("$t" -v 0 \
223            -select_streams v \
224            -print_format csv \
225            -show_entries \
226            stream=avg_frame_rate,r_frame_rate -- "$2" | \
227            tr ',' ' ')
228        atmp=( $tmp )
229
230        local i=0
231        for i in 1 2; do
232            local a=$(echo "${atmp[$i]}" | cut -d '/' -f 1)
233            local b=$(echo "${atmp[$i]}" | cut -d '/' -f 2)
234            [ "${atmp[$i]}" != "0/0" ] && fps=$(wrappers_floatDiv "$a" "$b")
235        done
236        ;;
237
238        *)
239        ;;
240    esac
241
242    # just a precaution
243    echo "$fps" | cut -d ' ' -f 1
244}
245
246########################################################################
247
248#
249# @brief configure the library
250#
251fs_configure_GV() {
252    _fs_configureStat_GV
253    _fs_configureBase64_GV
254    _fs_configureMd5_GV
255    _fs_configureUnlink_GV
256    _fs_configure7z_GV
257    _fs_configureGarbageCollector
258    _fs_verifyFpsTool
259}
260
261#
262# @brief stat wrapper
263#
264fs_stat_SO() {
265    ${___g_fsWrappers[$___g_fsStat]} "$@"
266}
267
268#
269# @brief base64 wrapper
270#
271fs_base64Decode_SO() {
272    ${___g_fsWrappers[$___g_fsBase64]} "$@"
273}
274
275#
276# @brief md5 wrapper
277#
278fs_md5_SO() {
279    ${___g_fsWrappers[$___g_fsMd5]} "$@"
280}
281
282#
283# @brief wrapper for copy function
284#
285fs_cp() {
286    ${___g_fsWrappers[$___g_fsCp]} "$@"
287}
288
289#
290# @brief set copy executable
291#
292fs_setCp_GV() {
293    ___g_fsWrappers[$___g_fsCp]="${1:-cp}"
294}
295
296#
297# @brief unlink wrapper
298#
299fs_unlink() {
300    ${___g_fsWrappers[$___g_fsUnlink]} "$@"
301}
302
303#
304# @brief 7z wrapper
305#
306fs_7z_SO() {
307    [ "${___g_fsWrappers[$___g_fs7z]}" != 'none' ] &&
308        ${___g_fsWrappers[$___g_fs7z]} "$@"
309}
310
311#
312# @brief returns true if 7z is available
313#
314fs_is7zAvailable() {
315    [ "${___g_fsWrappers[$___g_fs7z]}" != 'none' ]
316}
317
318#
319# @brief adds a given file to be garbage collected at exit
320#
321fs_garbageCollect() {
322    [ -e "$1" ] && echo "$1" >> "$___g_fsGarbageCollectorLog"
323}
324
325#
326# @brief adds a given file to be garbage collected at exit
327# The file does not have to exist when being added
328#
329fs_garbageCollectUnexisting() {
330    echo "$1" >> "$___g_fsGarbageCollectorLog"
331}
332
333#
334# @brief create temporary directory
335#
336fs_mktempDir_SO() {
337    local dirPath=$(mktemp -d -t napi.XXXXXXXX)
338    fs_garbageCollect "${dirPath}/"
339    echo "${dirPath}/"
340}
341
342#
343# @brief create temporary file
344#
345fs_mktempFile_SO() {
346    local filePath=$(mktemp -t napi.XXXXXXXX)
347    fs_garbageCollect "${filePath}"
348    echo "${filePath}"
349}
350
351#
352# @brief: check if the given file is a supported video file
353# @param: video filename
354#
355fs_isVideoFile() {
356    local filename=$(basename "$1")
357    local extension=$(wrappers_getExt_SO "$filename" | wrappers_lcase_SO)
358    local formats=( 'avi' 'rmvb' 'mov' 'mp4' 'mpg' 'mkv' \
359        'mpeg' 'wmv' '3gp' 'asf' 'divx' \
360        'm4v' 'mpe' 'ogg' 'ogv' 'qt' )
361
362    assoc_lookupKey_SO "$extension" "${formats[@]}" >/dev/null
363}
364
365#
366# @brief set fps tool
367#
368fs_setFpsTool_GV() {
369    ___g_fsWrappers[$___g_fsFps]="${1:-none}"
370
371    _fs_verifyFpsTool ||
372        ___g_fsWrappers[$___g_fsFps]="unavailable"
373}
374
375#
376# @brief get fps of a media file
377#
378fs_getFps_SO() {
379    [ "${___g_fsWrappers[$___g_fsFps]}" = 'none' ] &&
380        return "$G_RETUNAV"
381    _fs_getFpsWithTool "${___g_fsWrappers[$___g_fsFps]}" "$@"
382}
383
384# EOF
385