Videos nach dem Download automatisch transkodieren

This commit is contained in:
Stefan Bethke 2011-09-11 22:05:36 +00:00
parent 7011a68f47
commit bc44a7f91d
3 changed files with 165 additions and 126 deletions

View file

@ -1,3 +1,4 @@
tivo
toc-formatted.xml
toc.xml
*.pyc

View file

@ -1,6 +1,6 @@
#!/usr/local/bin/python
# $Schlepperbande: src/tivomirror/tivomirror,v 1.41 2011/01/13 17:26:33 stb Exp $
# $Schlepperbande: src/tivomirror/tivomirror,v 1.42 2011/07/04 21:10:43 stb Exp $
#
# Stefans Script, um die Sendungen vom Tivo runterzuladen und in MPEG4
# zu transkodieren.
@ -19,6 +19,7 @@ import sys
import time
import urllib2
import xml.dom.minidom
import tivomp4
host = "tivo.lassitu.de"
mak = "7194378159"
@ -87,6 +88,28 @@ class TivoException(Exception):
def __str__(self):
return repr(self.value)
class TivoItem:
def __init__(self, i):
self.title = getTagText(i, "Title")
self.episode = getTagText(i, "EpisodeTitle")
self.date = getTagText(i, "CaptureDate")
self.date = datetime.datetime.utcfromtimestamp(int(self.date, 16))
self.datestr = self.date.strftime("%Y%m%d-%H%M")
self.url = getTagText(i, "Url")
self.inprogress = getTagText(i, "InProgress")
self.available = getTagText(i, "Available")
self.sourcesize = int(getTagText(i, "SourceSize"))
self.highdef = getTagText(i, "HighDefinition")
self.ar = 43
if arset.has_key(self.title):
self.ar = arset[self.title]
elif self.highdef == "Yes":
self.ar = "hd"
if self.episode == "":
self.episode = self.datestr
def __str__(self):
return repr(self.title)
def gettoc():
url = "https://" + host + "/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying&Recurse=Yes"
pwmgr.add_password(None, url, "tivo", mak)
@ -106,7 +129,7 @@ def getText(nodelist):
def getTagText(element, tagname):
try:
return getText(i.getElementsByTagName(tagname)[0].childNodes)
return getText(element.getElementsByTagName(tagname)[0].childNodes)
except IndexError:
return ""
@ -142,53 +165,8 @@ def waitForProcs(pids):
raise TivoException("error executing processes")
def transcode(file, src, passno, ar):
print "--- transcoding pass %d" % passno
try:
os.remove(tmpmp4)
except OSError:
pass
transcode_opts = [ "ffmpeg" ];
# transcode_opts.extend(["-t", "60"]) # testing only: only 60 seconds
#transcode_opts.extend(["-aspect", "4:3"])
transcode_opts.extend(["-i", src])
if passno == 1:
transcode_opts.extend(["-an"])
else:
transcode_opts.extend(["-acodec", "libfaac", "-ab", "96kb"])
transcode_opts.extend(["-pass", "%d" % passno])
transcode_opts.extend(["-vcodec", "libx264"])
if passno == 1:
transcode_opts.extend(["-vpre", "fastfirstpass"])
else:
transcode_opts.extend(["-vpre", "hq"])
transcode_opts.extend(["-threads", "0", "-b", "900k", "-bt", "900k"])
if ar == 43:
transcode_opts.extend(["-croptop", "4", "-cropbottom", "4", "-cropleft", "6", "-cropright", "6"])
#transcode_opts.extend(["-s", "480x352"])
transcode_opts.extend(["-s", "624x352"])
#transcode_opts.extend(["-aspect", "4:3"])
elif ar == 149:
transcode_opts.extend(["-croptop", "34", "-cropbottom", "34", "-cropleft", "6", "-cropright", "6"])
transcode_opts.extend(["-s", "546x352"])
transcode_opts.extend(["-aspect", "14:9"])
else:
transcode_opts.extend(["-croptop", "60", "-cropbottom", "60", "-cropleft", "6", "-cropright", "6"])
transcode_opts.extend(["-s", "624x352"])
transcode_opts.extend(["-aspect", "16:9"])
transcode_opts.extend(["-y", "-deinterlace"])
if passno == 1:
transcode_opts.extend(["-f", "mp4", "/dev/null"])
else:
transcode_opts.append(tmpmp4)
print " %s" % " ".join(transcode_opts)
subprocess.check_call(transcode_opts)
def download(file, url, mak, target):
print "--- dowloading \"%s\"" % (url)
print "--- downloading \"%s\"" % (url)
start = time.time()
p_curl = subprocess.Popen(["curl", "--anyauth", "--fail", \
"--insecure", "--cookie", "tivo/.cookies.txt", \
@ -204,10 +182,10 @@ def download(file, url, mak, target):
os.remove(target)
except OSError:
pass
raise e
raise
size = os.path.getsize(target)
if size < 1024:
print "error transcoding file: too small"
print "error downloadig file: too small"
os.remove(target)
raise TivoException("downloaded file is too small")
elapsed = time.time() - start
@ -216,20 +194,22 @@ def download(file, url, mak, target):
size/1e9, elapsed/3600, int(elapsed / 60) % 60, throughput/1e3)
def download_decode(file, url, mak, ar):
def download_decode(item, mak):
#target = tmpmp2
target = "%s.mpg" % file
target = "%s.mpg" % item.file
try:
os.makedirs(dir)
os.makedirs(item.dir)
except OSError:
pass
#if os.path.exists(target):
# print " reusing existing download file"
#else:
download(file, url, mak, target)
return
transcode(file, target, 1, ar)
transcode(file, target, 2, ar)
if os.path.exists(target):
print " reusing existing download file"
else:
try:
download(item.file, item.url, mak, target)
except Exception, e:
os.remove(target)
raise
tivomp4.transcode(target, tmpmp4, item.ar)
print "--- copying to \"%s\"" % file
shutil.copy(tmpmp4, "%s.mp4" % file)
os.remove(tmpmp2)
@ -241,75 +221,65 @@ def savetoc(toc):
fd.write(toc)
fd.close()
curdir = os.getcwd()
os.chdir(tmp)
avail = getAvail(targetdir)
if avail < minfree:
def main():
curdir = os.getcwd()
os.chdir(tmp)
avail = getAvail(targetdir)
if avail < minfree:
print "%s: %.1fG available, at least %.1fG needed, stopping" % \
(targetdir, avail / gig, minfree / gig)
sys.exit(1)
downloaddb = anydbm.open(os.path.expanduser("~") + "/.tivo-downloads", "c")
print "*** Getting listing"
toc = gettoc()
savetoc(toc)
dom = xml.dom.minidom.parseString(toc)
cookiejar.save()
downloaddb = anydbm.open(os.path.expanduser("~") + "/.tivo-downloads", "c")
print "*** Getting listing"
toc = gettoc()
savetoc(toc)
dom = xml.dom.minidom.parseString(toc)
cookiejar.save()
items = dom.getElementsByTagName("Item")
print "*** %d shows listed" % (items.length)
for i in items:
title = getTagText(i, "Title")
episode = getTagText(i, "EpisodeTitle")
date = getTagText(i, "CaptureDate")
date = datetime.datetime.utcfromtimestamp(int(date, 16))
datestr = date.strftime("%Y%m%d-%H%M")
url = getTagText(i, "Url")
inprogress = getTagText(i, "InProgress")
available = getTagText(i, "Available")
sourcesize = int(getTagText(i, "SourceSize"))
if episode == "":
episode = datestr
name = "%s - %s" % (title, episode)
#dir = "%s/tivo/%s" % (curdir, re.sub("[:/]", "-", title))
dir = "%s/%s" % (targetdir, re.sub("[:/]", "-", title))
file = "%s/%s" % (dir, re.sub("[:/]", "-", name))
name = name.encode("utf-8");
dir = dir.encode("utf-8");
file = file.encode("utf-8");
items = dom.getElementsByTagName("Item")
print "*** %d shows listed" % (items.length)
for i in items:
item = TivoItem(i)
item.name = "%s - %s" % (item.title, item.episode)
#dir = "%s/tivo/%s" % (curdir, re.sub("[:/]", "-", item.title))
item.dir = "%s/%s" % (targetdir, re.sub("[:/]", "-", item.title))
item.file = "%s/%s" % (item.dir, re.sub("[:/]", "-", item.name))
item.name = item.name.encode("utf-8");
item.dir = item.dir.encode("utf-8");
item.file = item.file.encode("utf-8");
ar = 43
if arset.has_key(title):
ar = arset[title]
if inprogress == "Yes":
print "*** skipping \"%s\": is currently being recorded" % name
if item.inprogress == "Yes":
print "*** skipping \"%s\": is currently being recorded" % item.name
continue
if available == "No":
print "*** skipping \"%s\": is not available" % name
if item.available == "No":
print "*** skipping \"%s\": is not available" % item.name
continue
if downloaddb.has_key(name):
#print "*** skipping \"%s\": already downloaded" % name
if downloaddb.has_key(item.name):
#print "*** skipping \"%s\": already downloaded" % item.name
continue
if excludes.has_key(title) or excludes.has_key(episode) or excludes.has_key(name):
if excludes.has_key(item.title) or excludes.has_key(item.episode) or excludes.has_key(item.name):
#print "*** skipping \"%s\": excluded" % name
continue
print "*** downloading \"%s\": %.3fGB" % (name, sourcesize / 1e9)
print "*** downloading \"%s\": %.3fGB" % (item.name, item.sourcesize / 1e9)
try:
download_decode(file, url, mak, ar)
download_decode(item, mak)
try:
os.utime(file, [date, date])
os.utime(item.file, [item.date, item.date])
except Exception, e:
print "Urgh:", e
downloaddb[name] = datestr
downloaddb[item.name] = item.datestr
if getattr(downloaddb, "sync", None) and callable(downloaddb.sync):
downloaddb.sync()
# stop after the first successful download since the tivo hangs easily
print "Stopping after one successful transfer"
break
except TivoException, e:
print "Error processing \"%s\": %s" % (name, e)
print "Error processing \"%s\": %s" % (item.name, e)
print "*** Completed"
downloaddb.close()
print "*** Completed"
downloaddb.close()
if __name__ == "__main__":
main()

68
src/tivomirror/tivomp4.py Executable file
View file

@ -0,0 +1,68 @@
#!/usr/local/bin/python
import getopt
import shutil
import subprocess
import sys
def transcode(src, tgt, fmt):
transcode_opts = [ "ffmpeg" ];
#transcode_opts.extend(["-t", "60"]) # testing only: only 60 seconds
transcode_opts.extend(["-loglevel", "error"])
transcode_opts.extend(["-i", src])
#transcode_opts.extend(["-acodec", "libfaac"])
transcode_opts.extend(["-ac", "2", "-ab", "128k"])
transcode_opts.extend(["-vcodec", "libx264"])
transcode_opts.extend(["-tune", "film", "-profile", "main"])
if fmt == "hd":
transcode_opts.extend(["-s", "1280x720"])
transcode_opts.extend(["-threads", "0", "-b", "4000k"])
else:
transcode_opts.extend(["-threads", "0", "-b", "900k", "-bt", "900k"])
if str(fmt) == "43":
pass
elif str(fmt) == "149":
transcode_opts.extend(["-vf", "crop=640:412"])
transcode_opts.extend(["-aspect", "14:9"])
else:
transcode_opts.extend(["-vf", "crop=640:360"])
transcode_opts.extend(["-aspect", "16:9"])
transcode_opts.extend(["-y", "-deinterlace", "-vsync", "1"])
transcode_opts.append(tgt)
print " %s" % " ".join(transcode_opts)
subprocess.check_call(transcode_opts)
class Usage(Exception):
def __init__(self, msg):
self.msg = msg;
def __str__(self):
return repr(self.msg)
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
except getopt.error, msg:
raise Usage(msg)
for (o, v) in opts:
if o == "-h":
print >>sys.stderr, "help text"
return 0
if len(args) != 3:
raise Usage("wrong number of arguments")
transcode(args[1], args[2], args[0])
except Usage, err:
print >>sys.stderr, err.msg
print >>sys.stderr, "tivomp4 format source destination"
print >>sys.stderr, "for help use --help"
return 64
if __name__ == "__main__":
sys.exit(main())