aboutsummaryrefslogtreecommitdiffstats
path: root/.config/init/funcs/make-gif
blob: 3221e979572aac5b37d300473ded88794477b340 (plain)
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
#!/usr/bin/env zsh
# export a clip from a video as a gif

local callstr="$0"
local hasgsic=$(whence gifsicle)

usage() {
	[[ "$1" != "" ]] && echo -e "\e[1;31merror:\e[0m $1\n"
	echo "Usage: $callstr [OPTIONS...] <infile> <outfile>"
	echo ""
	echo "           description  option     default val"
	echo "            start time  -s <time>  00:00:00"
	echo "     length in seconds  -t <int>   full length"
	echo "               gif fps  -f <int>   10"
	echo "       gif pixel width  -w <int>   480"
	echo "         use subtitles  -b"
	echo "    use subtitle track  -n <int>   0"
	[[ $hasgsic ]] && echo "optimise with gifsicle  -g"
	echo "       print this help  -h"
	exit 1
}

local start="00:00:00"
local length=""
local fps=10
local width=480
local subs=""
local strack=0
local gsic=""

local timepat='^(([0-9][0-9]:){1,2}[0-9][0-9]|[0-9]+)$'
local intpat='^[0-9]+$'

# tmp var used to old '-t' if length is used
local t=""

# really annoying, but no other good way to do this
if [[ $hasgsic ]]; then
	while getopts s:t:f:w:bhn:g opt; do
		case "$opt" in
			s) 
				[[ ! $(echo $OPTARG | grep -oE "$timepat") ]] \
					&& usage "malformed start timestamp"
				start="$OPTARG"
				;;
			t)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "length must be an integer"
				length=$OPTARG
				t="-t"
				;;
			f)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "start time must be an integer"
				fps=$OPTARG
				;;
			w)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "fps must be an integer"
				width=$OPTARG
				;;
			b) subs=true ;;
			n)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "sub track specifier must be an integer"
				strack=$OPTARG
				;;
			g) gsic=true ;;
			h) usage ;;
			[?]) usage ;;
		esac
	done
else
	while getopts s:t:f:w:bhn: opt; do
		case "$opt" in
			s) 
				[[ ! $(echo $OPTARG | grep -oE "$timepat") ]] \
					&& usage "malformed start timestamp"
				start="$OPTARG"
				;;
			t)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "length must be an integer"
				length=$OPTARG
				t="-t"
				;;
			f)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "start time must be an integer"
				fps=$OPTARG
				;;
			w)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "fps must be an integer"
				width=$OPTARG
				;;
			b) subs=true ;;
			n)
				[[ ! $(echo $OPTARG | grep -oE "$intpat") ]] \
					&& usage "sub track specifier must be an integer"
				strack=$OPTARG
				;;
			h) usage ;;
			[?]) usage ;;
		esac
	done
fi
shift $OPTIND-1

[[ ${#@} -gt 2 ]] && usage "trailing arguments detected"

[[ ${#@} -lt 2 ]] && usage "no output file specified"

[[ "${2:e}" != "gif" ]] && usage "output file must have a .gif file extension"

[[ ! -f "$1" ]] && usage "input file not found"

local paltmp="make-gif"
while [[ -f "${paltmp}-palette.png" ]] || [[ -f "${paltmp}-in" ]]; do
	paltmp="${paltmp}-1"
done

ln -s "$1" "${paltmp}-in"

local fferr

if [[ $subs ]]; then
	echo "pass 1..."
	ffmpeg -loglevel 16 -y -ss $start $t $length -i "$1" -copyts \
		-vf "subtitles=${paltmp}-in:si=$strack,fps=$fps,scale=$width:-1:flags=lanczos,palettegen" \
		${paltmp}-palette.png
	[[ $? -ne 0 ]] && fferr=true
	[[ ! $fferr ]] && echo "pass 2..." && ffmpeg -loglevel 24 \
		-ss $start $t $length -i "$1" -i ${paltmp}-palette.png \
		-copyts -filter_complex \
		"subtitles=${paltmp}-in:si=$strack,fps=$fps,scale=$width:-1:flags=lanczos[x];[x][1:v]paletteuse" \
		"$2"
else
	echo "pass 1..."
	ffmpeg -loglevel 16 -y -ss "$start" $t $length -i "$1" \
		-vf "fps=$fps,scale=$width:-1:flags=lanczos,palettegen" \
		${paltmp}-palette.png
	[[ $? -ne 0 ]] && fferr=true
	[[ ! $fferr ]] && echo "pass 2..." && ffmpeg -loglevel 24 \
		-ss $start $t $length -i "$1" -i ${paltmp}-palette.png -filter_complex \
		"fps=$fps,scale=$width:-1:flags=lanczos[x];[x][1:v]paletteuse" \
		"$2"
fi

rm -f ${paltmp}-palette.png
rm -f ${paltmp}-in

if [[ -f "$2" ]] && [[ ! $fferr ]]; then
	if [[ $gsic ]]; then
		local gsictmp="$2.out"
		while [[ -f "$gsictmp" ]]; do
			gsictmp="$gsictmp.out"
		done
		echo "optimising..."
		gifsicle -O3 -i "$2" -o "$gsictmp"
		[[ $? -eq 0 ]] && rm -f "$2" && mv "$gsictmp" "$2"
	fi
fi