-
Notifications
You must be signed in to change notification settings - Fork 0
/
wapamux
executable file
·276 lines (212 loc) · 6.42 KB
/
wapamux
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/bin/sh
# wapamux
#
# Remux all video files of a specific type found in the current directory into
# a subdirectory. If a muxopt.json file is found in the current directory, a
# sanitized version of it is passed to mkvmerge as an options file.
#
# Requires: mkvmerge (from the mkvtoolnix package), sed.
#
# This script is in the public domain and was originally written by
# Dennis Murczak <https://github.com/lortordermur/>
#### GLOBALS ####
ext="mkv"
forcedext=
opts=
stripopts=
optsfile="muxopt.json"
tmpfile="~muxtemp.json"
outdir="__converted__"
#### FUNCTIONS ####
usage () {
echo "Usage: $(basename $0) [-s | --scan-headers | -t | --strip-titles] [fileext]"
echo "
Remuxes all files ending in .fileext found in the current directory into a
subdirectory '$outdir'. fileext defaults to 'mkv'.
If a file '$optsfile' is found in the current directory,
it is assumed that the directory contains a TV or anime series. In this case
a sanitized version of the option file (sans input and output filespecs) is
passed to mkvmerge for each video file. Header metadata has to match across
files for this to work, and an according safeguard check is done. Also, if an
option file is present, fileext can be determined automagically.
The -t parameter causes all processed video files to be stripped of their
title fields.
Without an option file, a plain batch convert/remux without verification or
altering of file metadata is done.
Prepending the -s or --scan-headers option only does the metadata
verification pass, regardless of the presence of '$optsfile'.
An exit status of 0 is returned on an error-free run, 1 in case of a file-
related problem or failure of an external command, 2 if the metadata
consistency check is unsuccessful.
"
exit 0
}
commandexists () {
command -v "$1" > /dev/null || { echo "Required command '$1' not found! $2" && echo && exit 1; }
}
filesexist () {
files=$(ls *.$ext) 2> /dev/null
if [ ! "$files" ]; then
echo "No matching files found for *.$ext! Exiting."
echo
echo "For usage information, try -h or --help."
echo
exit 1
fi
}
countfiles () {
ls -l *.$ext | wc -l
}
scanheaders () {
# Check uniformity of MKV headers and error out on first mismatch
local mkvi=
local mkvi_old=
local numfiles=$(countfiles)
echo "Starting metadata scan of all .$ext files."
echo
for f in *.$ext; do
echo "Checking headers: $f"
# Compare the order, type, language and codec (in case of multiple same
# language tracks) of the video file's tracks to the last iteration.
# "id": (track ID) as a grep pattern will also catch attached subtitle
# fonts, which are often mixed up inbetween files, so we use "number":
# (the track number) instead.
mkvi=$(mkvmerge --identify --identification-format json "$f" | grep -E '"codec": |"number": |"language": |"type": ')
if [ "$?" -ne "0" ]; then
echo "Not a supported video file: $f"
echo
rm -f $tmpfile
exit 1
fi
# FIXME: We have to check for the single-file case inside the loop for now
# so mkvmerge --identify can throw an error if the file is corrupt.
[ "$numfiles" -eq "1" ] && { echo "Single file: Skipping metadata scan." && echo && return; }
if [ -n "$mkvi_old" ]; then
if [ "$mkvi" != "$mkvi_old" ]; then
echo
echo "Metadata mismatch: $f"
echo $1
echo
rm -f $tmpfile
exit 2
fi
fi
mkvi_old=$mkvi
done
echo
echo "Metadata seems consistent across all files."
echo
}
processfiles () {
local numfiles=$(countfiles)
local c="0"
local fb
local of
mkdir -p $outdir
for f in *.$ext; do
c=$(($c+1))
echo "Processing ($c/$numfiles): $f"
echo
fb=$(basename "$f" .$ext)
of="$outdir/$fb.mkv"
mkvmerge --identify "$f"
mkvmerge --output "$of" $opts "$f"
# Some error checking, just in case
if [ "$?" -ne "0" ]; then
echo "There was a problem with mkvmerge. Aborting."
echo
rm -f $tmpfile
exit 1
fi
# mkvpropedit returns nonzero so it goes below the error check
[ "$stripopts" ] && mkvpropedit "$of" $stripopts
echo
# Force writing of the file's cached data to storage
sync "$of"
done
rm -f $tmpfile
echo "All done!"
echo
exit 0
}
#### MAIN ####
commandexists "mkvmerge" "Please install mkvtoolnix."
commandexists "mkvpropedit" "Please install mkvtoolnix."
commandexists "sed" "Sed is love, sed is life."
commandexists "sync" "Please install some implementation of the Unix 'sync' command."
# TODO: Implement a parameter shifter.
if [ "$1" ]; then
case $1 in
"--help" | "-h")
usage
;;
"--scan-headers" | "-s")
[ "$2" ] && { ext="$2" && forcedext=$ext; }
filesexist
scanheaders "Metadata is not consistent across files. Try wapasplit for a multipass remux."
exit 0
;;
"--strip-titles" | "-t")
stripopts="--delete title"
[ "$2" ] && { ext="$2" && forcedext=$ext; }
;;
*)
ext="$1"
forcedext=$ext
;;
esac
fi
# Catch CTRL+C & friends so we don’t leave a temp file.
trap "rm -f $tmpfile; exit" HUP INT TERM
if [ -f $optsfile ]; then
optsfileext=$(grep -A1 -e '"(",$' $optsfile | tr . \\n | tail -n1 | sed 's/",$//')
[ -z "$forcedext" ] && [ -n "$optsfileext" ] && ext=$optsfileext
fi
filesexist
# Renice ourself to bg priority.
renice -n 19 $$ > /dev/null
echo "Preparing to remux all .$ext files to a subdirectory. Continue [Y/n/?]?"
read -r ans
case $ans in
"y" | "Y" | "")
break
;;
"?")
usage
;;
*)
echo "Aborting."
echo
exit 0
;;
esac
# If muxopt.json is present, assume the directory contains a series and header
# scan the video files first.
if [ -f $optsfile ]; then
echo "$optsfile found. Assuming the directory contains a TV or anime series."
echo
opts="@$tmpfile"
# Temporarily filter filenames, name tags, UI language etc. out of the
# options. This will fail with trailing spaces, as it matches to the end of
# line.
sed -e '/"--ui-language",$/,+1d
/"--output",$/,+1d
/"--title",$/,+1d
/"(",$/,+2d
/"--track-name",$/,+1d' $optsfile > $tmpfile
scanheaders "Cannot apply options; consider doing multiple passes instead. Exiting."
echo "Start remux now [Y/n]?"
read -r ans
case $ans in
"y" | "Y" | "")
break
;;
*)
echo "Aborting."
echo
rm -f $tmpfile
exit 0
;;
esac
fi
processfiles