]> code.delx.au - monosys/blob - ripping/iview-downloader
e8d2ba032b78bfe9b707ba2d6d98e6137eb5e0ea
[monosys] / ripping / iview-downloader
1 #!/usr/bin/env python
2
3 import json
4 from lxml import etree
5 import signal
6 import subprocess
7 import urllib
8
9 BASE_URL = "http://www.abc.net.au/iview/"
10 CONFIG_URL = BASE_URL + "xml/config.xml"
11 HASH_URL = BASE_URL + "images/iview.jpg"
12 NS = {
13 "auth": "http://www.abc.net.au/iView/Services/iViewHandshaker",
14 }
15
16 def grab_xml(path):
17 f = urllib.urlopen(path)
18 doc = etree.parse(f)
19 f.close()
20 return doc
21
22 def grab_json(path):
23 f = urllib.urlopen(path)
24 doc = json.load(f)
25 f.close()
26 return doc
27
28 def choose(options, allow_multi):
29 skeys = sorted(options.keys())
30 for i, key in enumerate(skeys):
31 print " %d) %s" % (i+1, key)
32 print " 0) Back"
33 while True:
34 try:
35 values = map(int, raw_input("Choose> ").split())
36 if len(values) == 0:
37 continue
38 if 0 in values:
39 return
40 values = [options[skeys[value-1]] for value in values]
41 if allow_multi:
42 return values
43 else:
44 if len(values) == 1:
45 return values[0]
46 except ValueError:
47 pass
48
49 def download_rtmp(filename, vbase, vpath):
50 cmd = [
51 "rtmpdump",
52 "-o", filename,
53 "-r", vbase,
54 "-y", vpath,
55 "--swfVfy", HASH_URL,
56 ]
57 try:
58 p = subprocess.Popen(cmd)
59 p.wait()
60 except KeyboardInterrupt:
61 print "Cancelled", cmd
62 try:
63 p.terminate()
64 p.wait()
65 except KeyboardInterrupt:
66 p.send_signal(signal.SIGKILL)
67 p.wait()
68
69 def download_video(title, vpath):
70 auth_doc = grab_xml(PARAMS["auth"])
71 vbase = auth_doc.xpath("//auth:server/text()", namespaces=NS)[0]
72 token = auth_doc.xpath("//auth:token/text()", namespaces=NS)[0]
73 vbase += "?auth=" + token
74 vpath, ext = vpath.rsplit(".", 1)
75 vpath = ext + ":" + vpath
76 filename = title + "." + ext
77 download_rtmp(filename, vbase, vpath)
78
79 def get_categories():
80 categories_doc = grab_xml(BASE_URL + PARAMS["categories"])
81 categories = {}
82 for category in categories_doc.xpath("//category[@genre='true']"):
83 cid = category.attrib["id"]
84 name = category.xpath("name/text()")[0]
85 categories[name] = cid
86 return categories
87
88 def get_episodes(cid):
89 series_list_doc = grab_json(PARAMS["api"] + "seriesIndex")
90 episode_list = {}
91 for series in series_list_doc:
92 categories = series["e"].split()
93 if cid not in categories:
94 continue
95 sid = series["a"]
96 series_title = series["b"].replace("&", "&")
97 series_doc = grab_json(PARAMS["api"] + "series=" + sid)[0]
98 for episode in series_doc["f"]:
99 vpath = episode["n"]
100 episode_title = episode["b"].strip()
101 if series_title != episode_title:
102 episode_title = series_title + " " + episode_title
103 episode_list[episode_title] = (episode_title, vpath)
104 return episode_list
105
106
107
108 def main():
109 config_doc = grab_xml(CONFIG_URL)
110 global PARAMS
111 PARAMS = dict((p.attrib["name"], p.attrib["value"]) for p in config_doc.xpath("/config/param"))
112
113 while True:
114 cid = choose(get_categories(), allow_multi=False)
115 if cid is None:
116 continue
117 while True:
118 generator = choose(get_episodes(cid), allow_multi=True)
119 if generator is None:
120 break
121 for title, vpath in generator:
122 download_video(title, vpath)
123
124 if __name__ == "__main__":
125 try:
126 main()
127 except (KeyboardInterrupt, EOFError):
128 print "\nExiting..."
129