This repository has been archived by the owner on Jun 7, 2022. It is now read-only.
forked from vitorgalvao/tiny-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprogressbar
executable file
·173 lines (142 loc) · 5.23 KB
/
progressbar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/bin/bash
readonly program="$(basename "${0}")"
# Defaults
bar_color='#f12b24'
bar_height_percent='1'
bar_pos='bottom'
seconds_delay='1.5'
output_file='output.gif'
function message {
echo "${1}"
}
function wrong_arguments {
echo 'You need either give multiple images or one video file as arguments' >&2
usage
exit 1
}
function depends_on {
local -r all_deps=("${@}")
local missing_deps=()
for dep in "${all_deps[@]}"; do
command -v "${dep}" > /dev/null || missing_deps+=("${dep}")
done
if [[ "${#missing_deps[@]}" -gt 0 ]]; then
echo 'Missing required tools:' >&2
printf ' %s\n' "${missing_deps[@]}" >&2
exit 1
fi
}
function usage {
echo "
Usage:
${program} [options] <file...>
Options:
-c, --bar-color <color> Default: #f12b24.
-s, --bar-height <integer> Bar’s height as a percent of the total height. Default: 1.
-p, --bar-position [top|bottom] Default: bottom.
-d, --delay <number> Delay between each frame, in seconds. Default: 1.5.
-o, --output-file <file> File to output to. Default: output.gif in current directory. Saves to video when given the .mov extension.
-g, --gifski Use gifski for the conversion.
-h, --help Show this help.
" | sed -E 's/^ {4}//'
}
# Options
args=()
while [[ "${1}" ]]; do
case "${1}" in
-h | --help)
usage
exit 0
;;
-c | --bar-color)
bar_color="${2}"
shift
;;
-s | --bar-height)
bar_height_percent="${2}"
shift
;;
-p | --bar-position)
bar_pos="${2}"
shift
;;
-d | --delay)
seconds_delay="${2}"
shift
;;
-o | --output-file)
output_file="${2}"
shift
;;
-g | --gifski)
use_gifski='true'
;;
--)
shift
args+=("${@}")
break
;;
-*)
echo "Unrecognised option: ${1}"
exit 1
;;
*)
args+=("${1}")
;;
esac
shift
done
set -- "${args[@]}"
trap 'exit 1' SIGINT
depends_on 'convert' 'identify' 'ffmpeg' 'ffprobe' 'gfv'
# Determine if working from images or video
[[ "${#}" -eq 0 ]] && wrong_arguments
if [[ "${#}" -eq 1 ]]; then
[[ "$(file --mime-type --brief "${1}")" != 'video'* ]] && wrong_arguments
readonly background_video="${1}"
else
readonly background_video="$(mktemp).mov"
readonly images=("${@}")
for file in "${images[@]}"; do
[[ "$(file --mime-type --brief "${file}")" != 'image'* ]] && wrong_arguments
done
readonly frame_delay="$(bc <<< "${seconds_delay} * 100")"
message 'Generating intermediary video file…'
convert -delay "${frame_delay}" "${images[@]}" "${background_video}"
fi
message 'Generating progress bar…'
readonly total_frames="$(ffprobe -loglevel error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "${background_video}")"
readonly total_steps="$(bc <<< "${total_frames} - 1")" # Remove one from the total since we will start counting steps from 0. This is for the logic of having no bar on the first step and to map to the array correctly.
readonly canvas_width="$(ffprobe -loglevel error -count_frames -show_entries stream=width -of default=nokey=1:noprint_wrappers=1 "${background_video}")"
readonly canvas_height="$(ffprobe -loglevel error -count_frames -show_entries stream=height -of default=nokey=1:noprint_wrappers=1 "${background_video}")"
readonly bar_height_px="$(bc <<< "${canvas_height} * ${bar_height_percent} / 100")"
[[ "${bar_pos}" == 'top' ]] && readonly bar_ystart='0' || readonly bar_ystart="$(bc <<< "${canvas_height} - ${bar_height_px}")"
readonly bar_yend="$(bc <<< "${bar_ystart} + ${bar_height_px}")"
readonly tmp_bar_graphics_dir="$(mktemp -d)"
readonly tmp_bar_video="$(mktemp).mov"
# Make bar graphics.
for step_name in $(seq -w 0 "${total_steps}"); do
[[ "${step_name}" =~ ^0+$ ]] && step_number='0' || step_number="$(sed -E 's/^0+//' <<< "${step_name}")" # Remove leading zeros
if [[ "${step_number}" -eq 0 ]]; then
bar_width='0' # First frame shold never have a bar. Without this we'd have to divide by zero.
elif [[ "${step_number}" -eq "${total_steps}" ]]; then
bar_width="${canvas_width}" # Last frame should always fill the full width. Without this we may get a fractional result slightly smaller.
else
bar_width="$(bc -l <<< "${canvas_width} / ${total_steps} * ${step_number}")"
fi
convert -size "${canvas_width}"x"${canvas_height}" canvas:transparent -fill "${bar_color}" -draw "rectangle 0,${bar_ystart} ${bar_width},${bar_yend}" "${tmp_bar_graphics_dir}/${step_name}.png"
done
# Make bar graphics into a video and superimpose on the original.
ffmpeg -loglevel error -pattern_type glob -i "${tmp_bar_graphics_dir}/*.png" -vcodec png "${tmp_bar_video}"
readonly tmp_superimposed_video="$(mktemp).mov"
ffmpeg -i "${background_video}" -i "${tmp_bar_video}" -filter_complex overlay "${tmp_superimposed_video}"
# Make gif
message 'Creating gif…'
if [[ "${output_file}" == *'.mov' ]]; then
mv "${tmp_superimposed_video}" "${output_file}"
else
options=()
[[ -n "${use_gifski}" ]] && options+=('--gifski')
gfv "${options[@]}" "${tmp_superimposed_video}" --output-file "${output_file}"
fi
message "Saved to ${output_file}"