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 tivo
toc-formatted.xml toc-formatted.xml
toc.xml toc.xml
*.pyc

View file

@ -1,6 +1,6 @@
#!/usr/local/bin/python #!/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 # Stefans Script, um die Sendungen vom Tivo runterzuladen und in MPEG4
# zu transkodieren. # zu transkodieren.
@ -19,6 +19,7 @@ import sys
import time import time
import urllib2 import urllib2
import xml.dom.minidom import xml.dom.minidom
import tivomp4
host = "tivo.lassitu.de" host = "tivo.lassitu.de"
mak = "7194378159" mak = "7194378159"
@ -87,6 +88,28 @@ class TivoException(Exception):
def __str__(self): def __str__(self):
return repr(self.value) 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(): def gettoc():
url = "https://" + host + "/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying&Recurse=Yes" url = "https://" + host + "/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying&Recurse=Yes"
pwmgr.add_password(None, url, "tivo", mak) pwmgr.add_password(None, url, "tivo", mak)
@ -106,7 +129,7 @@ def getText(nodelist):
def getTagText(element, tagname): def getTagText(element, tagname):
try: try:
return getText(i.getElementsByTagName(tagname)[0].childNodes) return getText(element.getElementsByTagName(tagname)[0].childNodes)
except IndexError: except IndexError:
return "" return ""
@ -142,53 +165,8 @@ def waitForProcs(pids):
raise TivoException("error executing processes") 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): def download(file, url, mak, target):
print "--- dowloading \"%s\"" % (url) print "--- downloading \"%s\"" % (url)
start = time.time() start = time.time()
p_curl = subprocess.Popen(["curl", "--anyauth", "--fail", \ p_curl = subprocess.Popen(["curl", "--anyauth", "--fail", \
"--insecure", "--cookie", "tivo/.cookies.txt", \ "--insecure", "--cookie", "tivo/.cookies.txt", \
@ -204,10 +182,10 @@ def download(file, url, mak, target):
os.remove(target) os.remove(target)
except OSError: except OSError:
pass pass
raise e raise
size = os.path.getsize(target) size = os.path.getsize(target)
if size < 1024: if size < 1024:
print "error transcoding file: too small" print "error downloadig file: too small"
os.remove(target) os.remove(target)
raise TivoException("downloaded file is too small") raise TivoException("downloaded file is too small")
elapsed = time.time() - start elapsed = time.time() - start
@ -216,20 +194,22 @@ def download(file, url, mak, target):
size/1e9, elapsed/3600, int(elapsed / 60) % 60, throughput/1e3) 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 = tmpmp2
target = "%s.mpg" % file target = "%s.mpg" % item.file
try: try:
os.makedirs(dir) os.makedirs(item.dir)
except OSError: except OSError:
pass pass
#if os.path.exists(target): if os.path.exists(target):
# print " reusing existing download file" print " reusing existing download file"
#else: else:
download(file, url, mak, target) try:
return download(item.file, item.url, mak, target)
transcode(file, target, 1, ar) except Exception, e:
transcode(file, target, 2, ar) os.remove(target)
raise
tivomp4.transcode(target, tmpmp4, item.ar)
print "--- copying to \"%s\"" % file print "--- copying to \"%s\"" % file
shutil.copy(tmpmp4, "%s.mp4" % file) shutil.copy(tmpmp4, "%s.mp4" % file)
os.remove(tmpmp2) os.remove(tmpmp2)
@ -241,75 +221,65 @@ def savetoc(toc):
fd.write(toc) fd.write(toc)
fd.close() fd.close()
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)
curdir = os.getcwd() downloaddb = anydbm.open(os.path.expanduser("~") + "/.tivo-downloads", "c")
os.chdir(tmp) print "*** Getting listing"
avail = getAvail(targetdir) toc = gettoc()
if avail < minfree: savetoc(toc)
print "%s: %.1fG available, at least %.1fG needed, stopping" % \ dom = xml.dom.minidom.parseString(toc)
(targetdir, avail / gig, minfree / gig) cookiejar.save()
sys.exit(1)
downloaddb = anydbm.open(os.path.expanduser("~") + "/.tivo-downloads", "c") items = dom.getElementsByTagName("Item")
print "*** Getting listing" print "*** %d shows listed" % (items.length)
toc = gettoc() for i in items:
savetoc(toc) item = TivoItem(i)
dom = xml.dom.minidom.parseString(toc) item.name = "%s - %s" % (item.title, item.episode)
cookiejar.save() #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");
items = dom.getElementsByTagName("Item") if item.inprogress == "Yes":
print "*** %d shows listed" % (items.length) print "*** skipping \"%s\": is currently being recorded" % item.name
for i in items: continue
title = getTagText(i, "Title") if item.available == "No":
episode = getTagText(i, "EpisodeTitle") print "*** skipping \"%s\": is not available" % item.name
date = getTagText(i, "CaptureDate") continue
date = datetime.datetime.utcfromtimestamp(int(date, 16)) if downloaddb.has_key(item.name):
datestr = date.strftime("%Y%m%d-%H%M") #print "*** skipping \"%s\": already downloaded" % item.name
url = getTagText(i, "Url") continue
inprogress = getTagText(i, "InProgress") if excludes.has_key(item.title) or excludes.has_key(item.episode) or excludes.has_key(item.name):
available = getTagText(i, "Available") #print "*** skipping \"%s\": excluded" % name
sourcesize = int(getTagText(i, "SourceSize")) continue
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");
ar = 43
if arset.has_key(title):
ar = arset[title]
if inprogress == "Yes": print "*** downloading \"%s\": %.3fGB" % (item.name, item.sourcesize / 1e9)
print "*** skipping \"%s\": is currently being recorded" % name
continue
if available == "No":
print "*** skipping \"%s\": is not available" % name
continue
if downloaddb.has_key(name):
#print "*** skipping \"%s\": already downloaded" % name
continue
if excludes.has_key(title) or excludes.has_key(episode) or excludes.has_key(name):
#print "*** skipping \"%s\": excluded" % name
continue
print "*** downloading \"%s\": %.3fGB" % (name, sourcesize / 1e9)
try:
download_decode(file, url, mak, ar)
try: try:
os.utime(file, [date, date]) download_decode(item, mak)
except Exception, e: try:
print "Urgh:", e os.utime(item.file, [item.date, item.date])
downloaddb[name] = datestr except Exception, e:
if getattr(downloaddb, "sync", None) and callable(downloaddb.sync): print "Urgh:", e
downloaddb.sync() downloaddb[item.name] = item.datestr
# stop after the first successful download since the tivo hangs easily if getattr(downloaddb, "sync", None) and callable(downloaddb.sync):
print "Stopping after one successful transfer" downloaddb.sync()
break # stop after the first successful download since the tivo hangs easily
except TivoException, e: print "Stopping after one successful transfer"
print "Error processing \"%s\": %s" % (name, e) break
except TivoException, e:
print "Error processing \"%s\": %s" % (item.name, e)
print "*** Completed" print "*** Completed"
downloaddb.close() 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())