-
Notifications
You must be signed in to change notification settings - Fork 0
/
tivotranscode
executable file
·313 lines (264 loc) · 9.39 KB
/
tivotranscode
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#!/bin/bash
usage() {
cat << EOF
Usage: `basename $0` [options]
OPTIONS:
-h, --help Show this message.
-f, --first-run Connects to the tivo and saves the show and tivo access info to the given files
-s, --show-list File containing a list of shows titles to transcode. default to '~/.tvt-shows'
-t, --tivo TiVo IP Address / host name. default to '~/.tvt-host'
-m, --media-key Media Access Key default to '~/.tvt-mak'
-d, --dest username@sftpserver:/path/to/save/into default to '~/.tvt-dest'
-v, --verbose Instructs the script to be verbose about what it's doing.
EOF
}
LONG_OPTIONS=0
FIRSTRUN=0
SHOWLIST=""
TIVO=""
MAK=""
FULLDEST=""
DEST=""
DESTDIR=""
VERBOSE=0
# Determine getopt support, and parse all the parameters we need.
getopt -T
if [[ $? -eq 4 ]]; then
set -- $(getopt -o "hfs:t:m:d:v" -l "help,first-run,show-list:,tivo:,media-key:,dest:,verbose" -- "$@")
else
set -- $(getopt hfs:t:m:d:v "$@")
fi
while [ $# -gt 0 ]; do
case "$1" in
-h | --help ) usage; exit 1;;
-f | --first-run ) FIRSTRUN=1; shift ;;
-s | --show-list ) SHOWLIST="$2"; shift 2;;
-t | --tivo ) TIVO="$2"; shift 2;;
-m | --media-key ) MAK="$2"; shift 2;;
-v | --verbose ) VERBOSE=1; shift;;
-d | --dest ) FULLDEST="$2"; echo $1; shift 2;;
-- ) shift; break;;
-* ) echo "Unrecognized option $1" 1>&2; exit 1;;
* ) break;;
esac
done
if [[ "$SHOWLIST" == "" ]]; then
SHOWLIST=$(readlink -f ~/.tvt-shows)
elif [[ "$SHOWLIST" == "-" ]]; then
SHOWLIST="/dev/stdin"
fi
if [[ "$TIVO" == "" ]]; then
TIVO=`cat ~/.tvt-host`
else
TIVO=`echo $TIVO | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"`
fi
if [[ "$MAK" == "" ]]; then
MAK=`cat ~/.tvt-mak`
else
MAK=`echo $MAK | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"`
fi
if [[ "$FULLDEST" == "" ]]; then
FULLDEST=`cat ~/.tvt-destination`
else
FULLDEST=`echo $FULLDEST | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"`
fi
DEST=${FULLDEST%%:*}
DESTDIR=${FULLDEST##*:}
PROCESSEDLIST=`readlink -f ~/.tvt-processed-shows`
if [[ "$VERBOSE" == "1" ]]; then
echo "Showlist: $SHOWLIST"
echo "Processed: $PROCESSEDLIST"
echo "Tivo: $TIVO"
echo "Mak: $MAK"
echo "Destination: $DEST"
echo " Directory: $DESTDIR"
echo "Verbose: $VERBOSE"
echo "Firstrun: $FIRSTRUN"
fi
if [[ "$FIRSTRUN" == "1" ]]; then
# make sure the showlist isn't /dev/stdin
if [[ "$SHOWLIST" == "/dev/stdin" ]]; then
echo "You cannot save firstrun data to /dev/stdin. Please specify a show list file."
usage
exit 1
fi
# We need these options
if [[ -z $TIVO ]] || [[ -z $MAK ]]; then
usage
exit 1
fi
fi
xsltprocpath=`whereis xsltproc | grep '/xsltproc' | wc -l`
if [[ "$xsltprocpath" == "0" ]]; then
echo "Could not find xsltproc on PATH. Please check to make sure it's propertly installed."
exit 1
fi
tivodecodeonpath=`whereis tivodecode | grep '/tivodecode' | wc -l`
if [[ "$tivodecodeonpath" == "0" ]]; then
echo "Could not find tivodecode on PATH. Please check to make sure it's properly installed."
exit 1
fi
handbrakeclionpath=`whereis HandBrakeCLI | grep '/HandBrakeCLI' | wc -l`
if [[ "$handbrakeclionpath" == "0" ]]; then
echo "Could not find HandBrakeCLI on PATH. Please check to make sure it's properly installed."
exit 1
fi
# getShowList(outputfilename)
# Parses the global NOWPLAYING list and writes all the show titles (individual and folders)
# Which are not special 'HD' or 'TiVo Suggestions' to tthe given file. You can
# use this to get a list of all the shows on the tivo, and then only select the
# ones you want to process each run.
function getShowList {
local output="$1"
# Get the list of folders from the NOWPLAYING output, parsing out the URLs to get the episode lists.
echo $NOWPLAYING | xsltproc lib/listfolders.xsl - | sed 's/|.*//g' > $output
# Get the list of individual shows from the NOWPLAYING, append to output.
echo $NOWPLAYING | xsltproc lib/listshows.xsl - >> $output
}
# Construct the global SUBSCRIBED array, and a function to load it.
SUBSCRIBED=()
function loadSubscribed {
while read TITLE; do
SUBSCRIBED+=("${TITLE}")
done < $SHOWLIST
}
# Construct the global LOCKNAME, and a function to get it, or kill the process.
LOCKNAME="encode_$TIVO.lock"
function lockOrDie {
lockfile -5 $LOCKNAME
if [[ $? -ne 0 ]]; then
echo "Could not obtain lock to process shows for TiVo $TIVO. Perhaps another process is still running?"
exit 1
fi
}
# Removes the lock file.
function cleanupLock {
rm -f $LOCKNAME
}
# isProcessed(showname, programid)
# returns 0 if the show has never been processed, false otherwise.
function isNotProcessed {
PROCESSED=`fgrep "$1:$2" $PROCESSEDLIST`
# return values in bash are so silly.
if [[ "$PROCESSED" == "" ]]; then
return 0
else
return 1
fi
}
# cleanShowName(showname, outputvar)
function cleanShowName() {
eval $2=`sed -s "s/'//" <<< "\\"$1\\"" | sed -s "s/\!//"`
}
# processShow(nowplayingxml, showname)
# Parses the provided nowplaying xml (can be global or show-specific) for programids matching the given show name
# Downloads & decodes the mpeg streams from the tivo.
function processShow {
local PROGRAMIDS
PROGRAMIDS=`echo $1 | xsltproc --stringparam ShowTitle "$2" lib/programid.xsl - `
for PROGRAMID in $PROGRAMIDS; do
if isNotProcessed "$2" $PROGRAMID; then
echo "Processing $2:$PROGRAMID" 1>&2
# Parse the URL from the now playing.
local MPEGURL
MPEGURL=`echo $1 | xsltproc --stringparam ProgramId "$PROGRAMID" lib/mpegurl.xsl -`
local TARGETFILENAME
TARGETFILENAME=`echo $1 | xsltproc --stringparam ProgramId "$PROGRAMID" lib/targetfilename.xsl -`
# Paranoia, if we end up with an empty file name, default to the program id as a last resort.
if [[ "$TARGETFILENAME" == "" ]]; then
TARGETFILENAME="$PROGRAMID"
fi
# Make sure the output directory exists and then prefix it.
local TARGETDIRNAME
cleanShowName "$2" TARGETDIRNAME
mkdir -p "$TARGETDIRNAME"
TARGETFILENAME="$TARGETDIRNAME/$TARGETFILENAME.m4v"
echo " Downloading & Decoding from $MPEGURL"
if [[ ! -f $PROGRAMID.mpg ]]; then
curl --cookie sid=abc -s --digest -k -u tivo:$MAK -c cookies.txt "$MPEGURL" | tivodecode -m $MAK -o $PROGRAMID.mpg -
fi
echo " Transcoding... to $TARGETFILENAME"
if [[ -f $PROGRAMID.mpg ]] && [[ ! -f $TARGETFILENAME ]]; then
nice -n 20 HandBrakeCLI -i $PROGRAMID.mpg -o "$TARGETFILENAME" -f mp4 -O -e x264 --x264-profile high -b 1100 --two-pass -r 29.97 -a 1 -E faac -B 160 -6 stereo -R Auto --gain 5.0 --detelecine --decomb --strict-anamorphic
echo "$2:$PROGRAMID" >> $PROCESSEDLIST
else
echo " Skipping transcode. I'm either missing $PROGRAMID.mpg, or $TARGETFILENAME already exists."
fi
rm $PROGRAMID.mpg
else
echo "Skipping $2:$PROGRAMID. This episode has already been processed. Please remove it from your TiVo." 1>&2
fi
done
if [[ "$PROGRAMIDS" == " " ]]; then
# Found nothing
return 0
else
# Found something
return 1
fi
}
# Function which loads the subscriptions into the global array, then takes action
# on each show in the array, looking for episodes on the TiVo to process.
function processSubscriptions {
loadSubscribed
# Clean up an existing transfer script.
if [[ -f transfer_script ]]; then
rm transfer_script
fi
# For every showname we're subscribed to, look for a ProgramID with that show title from the global Now Playing list.
for SHOW in "${SUBSCRIBED[@]}"; do
# processShow returns true if we didn't find anything.
if processShow "$NOWPLAYING" "$SHOW"; then
local TITLEPLAYINGURL
TITLEPLAYINGURL=`echo $NOWPLAYING | xsltproc lib/listfolders.xsl - | grep "$SHOW" | sed 's/.*|//g'`
echo "Getting the Now Playing list for episodes of $SHOW from $TITLEPLAYINGURL"
local TITLEPLAYING
TITLEPLAYING="`curl -s --digest -k -u tivo:$MAK "$TITLEPLAYINGURL"`"
if processShow "$TITLEPLAYING" "$SHOW"; then
echo "Did not find any pending episodes on the TiVo for $SHOW"
fi
fi
local TARGETDIRNAME
cleanShowName "$SHOW" TARGETDIRNAME
# If we have a destination and a show directory, add it to the things to sftp.
if [[ -d $TARGETDIRNAME ]]; then
echo "cd $DESTDIR" >> transfer_script
echo "put -r \"$TARGETDIRNAME\"" >> transfer_script
fi
done
# now let's run the script if there is one.
if [[ -f transfer_script ]]; then
sftp -b transfer_script "$DEST"
rm transfer_script
fi
# now clean up the local directories
for SHOW in "${SUBSCRIBED[@]}"; do
local TARGETDIRNAME
cleanShowName "$SHOW" TARGETDIRNAME
if [[ -d $TARGETDIRNAME ]]; then
rm -fr "$TARGETDIRNAME"
fi
done
}
# Get a global NowPlaying list (of individual shows and folders)
# We recurse into folders manually when we need to, so that we can get the full
# listing of -all- the shows (and episodes if necessary)
NOWPLAYING="`curl -s --digest -k -u tivo:$MAK "https://$TIVO/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying"`"
# If this is a first run, we are going to save data.
if [[ "$NOWPLAYING" != "" ]] && [[ "$FIRSTRUN" == "1" ]]; then
echo "$TIVO" > ~/.tvt-host
echo "$MAK" > ~/.tvt-mak
getShowList $SHOWLIST
elif [[ "$NOWPLAYING" != "" ]]; then
if [[ ! -f $SHOWLIST ]]; then
echo "Could not read from specified show list file: $SHOWLIST" 1>&2
exit 1
fi
# Make sure we have a file to keep a list of all the things we've already proces`.
touch $PROCESSEDLIST
lockOrDie
processSubscriptions
cleanupLock
else
echo "Could not contact TiVo at specified URL."
fi