-
Notifications
You must be signed in to change notification settings - Fork 12
/
matchsubtitles
executable file
·167 lines (140 loc) · 4.57 KB
/
matchsubtitles
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
#!/bin/bash
#
# Rename subtitles (.srt files) to match the given video files
#
# Copyright (C) 2011 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
# License: GPLv3 or later, at your choice. See <http://www.gnu.org/licenses/gpl>
#
# For updated versions, see https://github.com/MestreLion/scripts/
#
# For an example on how to use it via GUI/File Manager, see the Nautilus action
# wrapper in `nautilus-scripts/Match subtitles`
#
# TODO: Support for multiple language subtitles ( *.xx.srt )
# FIXME: undo file should handle chained renames of the same file
self="${0##*/}"
run=0
verbose=0
undo=
fatal() {
local msg="$1"
if [[ "$msg" ]]; then
printf "%s: %s\nTry '%s --help' for more information\n" \
"$self" "$msg" "$self" >&2
fi
exit 1
}
usage() {
cat << USAGEDOC
Rename subtitles (.srt files) to match the given video files
Usage: $self [--undo FILE] [--verbose] [--run] [--] [FILE|DIR]...
Options:
--undo FILE - Create an undo script to revert the renaming. Run ./FILE to revert
--run - If not used, will not actually rename subtitles, only show what will be done
Video files are *.avi, *.mkv, *.mpg, *.mpeg and *.ogv. All other files are ignored
Files that already have a matching subtitle and subtitles that already have a matching video will be ignored
For desired results, files in same dir must be given in alphabetical order (use globs for that).
Example:
$self --run ~/Videos/Lost /shared/csi/miami_s1* '/movies/star wars'
Copyright (C) 2011 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
License: GPLv3 or later, at your choice. See <http://www.gnu.org/licenses/gpl>
USAGEDOC
exit
}
printundo() {
local header="$1"
local oldfile="$2"
local newfile="$3"
if [[ -z "$header" ]]; then
printf '#Automatically generated by %s at %s\n' "$self" "$(date +'%F %T')"
printf '#arguments:'
printf ' %q' "${args[@]}"
printf '\ncd %q\n' "$PWD"
fi
printf "mv -- %q %q\n" "$oldfile" "$newfile"
}
addfiles() {
local arg="$1"
if [[ -f "$arg" ]]; then files+=( "$arg" ); return; fi # add file
if [[ -d "$arg" ]]; then files+=( "${arg%/}/"* ); return; fi # add files in dir
fatal "$(printf '%q' "$arg"): not a file or directory"
}
#save for log
args=( "$@" )
# command line parsing
while [[ $# -gt 0 ]]; do
arg="$1"; shift
case "$arg" in
-h|--help ) usage ;;
-t|--run ) run=1 ;;
-v|--verbose) verbose=1 ;;
-u|--undo ) undo="$1";shift ;;
-- ) break ;;
* ) addfiles "$arg" ;;
esac
done
for arg; do addfiles "$arg"; done # add remaining files after --
if [[ "${#files[@]}" -eq 0 ]]; then addfiles "$PWD"; fi # no files given: add current dir
# set the verbose -v option for mv
v=()
if ((verbose)); then v=("-v"); fi
# loop the files
prevdir=""
match=0
for video in "${files[@]}"; do
# File exists? (can be an umatched glob or empty dir)
if ! [[ -f "$video" ]]; then continue; fi
# Split full filename in file, title, ext and dir (with trailing '/')
file="${video##*/}"
title="${file%.*}"
ext="${file#"$title"}"
ext="${ext#.}"
dir="${video%"$file"}"
dir="${dir:-./}"
# Is it a video?
shopt -s nocasematch
case "${ext}" in avi|mpg|mpeg|mkv|mp4|ogv) ;; *) continue ;; esac
shopt -u nocasematch
# Has a matching subtitle already?
subtitle="${video%."$ext"}.srt"
if [[ -f "$subtitle" ]]; then continue; fi
# Populate the unmatched subtitles array for this dir
if [[ "$dir" != "$prevdir" ]]; then
prevdir="$dir"
allsubs=( "${dir%/}"/*.[Ss][Rr][Tt] )
subtitles=()
s=0
for sub in "${allsubs[@]}"; do
if [[ -f "$sub" ]]; then
matchsub=""
for f in "${sub%.[Ss][Rr][Tt]}".{avi,mpg,mpeg,mkv,mp4,ogv}; do
if [[ -f "$f" ]]; then matchsub=1; break; fi
done
if [[ -z "$matchsub" ]]; then subtitles+=( "$sub" ); fi
fi
done
fi
# Are there any avaliable, unmatched subtitles left in this dir?
if ! (( s < ${#subtitles[@]} )); then continue; fi
# Rename the first subtitle
if ((run)); then
mv "${v[@]}" -- "${subtitles[s]}" "${subtitle}" ||
fatal "could not rename ${subtitles[s]}"
if [[ "$undo" ]]; then
printundo "$match" "${subtitle}" "${subtitles[s]}" >> "$undo" ||
fatal "could not write to undo file $undo"
fi
elif ((verbose)); then
printf '# mv -- %q %q\n' "${subtitles[s]}" "${subtitle}"
fi
match=1
(( s++ ))
done
if ((verbose && match && ! run)); then
echo "Dry run, no rename was executed. Use --run to apply"
fi
if [[ "$undo" ]] && ((match && run)); then
printf '\n' >> "$undo" || fatal "could not write to undo file $undo"
chmod +x "$undo" || fatal "could not set to executable undo script $undo"
if ((verbose)); then echo "undo file created: $undo"; fi
fi