--- /dev/null
+#!/usr/bin/env python
+
+import json
+from lxml import etree
+import signal
+import subprocess
+import urllib
+
+BASE_URL = "http://www.abc.net.au/iview/"
+CONFIG_URL = BASE_URL + "xml/config.xml"
+HASH_URL = BASE_URL + "images/iview.jpg"
+NS = {
+ "auth": "http://www.abc.net.au/iView/Services/iViewHandshaker",
+}
+
+def grab_xml(path):
+ f = urllib.urlopen(path)
+ doc = etree.parse(f)
+ f.close()
+ return doc
+
+def grab_json(path):
+ f = urllib.urlopen(path)
+ doc = json.load(f)
+ f.close()
+ return doc
+
+def choose(options, allow_multi):
+ skeys = sorted(options.keys())
+ for i, key in enumerate(skeys):
+ print " %d) %s" % (i+1, key)
+ print " 0) Back"
+ while True:
+ try:
+ values = map(int, raw_input("Choose> ").split())
+ if len(values) == 0:
+ continue
+ if 0 in values:
+ return
+ values = [options[skeys[value-1]] for value in values]
+ if allow_multi:
+ return values
+ else:
+ if len(values) == 1:
+ return values[0]
+ except ValueError:
+ pass
+
+def download_rtmp(filename, vbase, vpath):
+ cmd = [
+ "rtmpdump",
+ "-o", filename,
+ "-r", vbase,
+ "-y", vpath,
+ "--swfVfy", HASH_URL,
+ ]
+ try:
+ p = subprocess.Popen(cmd)
+ p.wait()
+ except KeyboardInterrupt:
+ print "Cancelled", cmd
+ try:
+ p.terminate()
+ p.wait()
+ except KeyboardInterrupt:
+ p.send_signal(signal.SIGKILL)
+ p.wait()
+
+def download_video(title, vpath):
+ auth_doc = grab_xml(PARAMS["auth"])
+ vbase = auth_doc.xpath("//auth:server/text()", namespaces=NS)[0]
+ token = auth_doc.xpath("//auth:token/text()", namespaces=NS)[0]
+ vbase += "?auth=" + token
+ vpath, ext = vpath.rsplit(".", 1)
+ vpath = ext + ":" + vpath
+ filename = title + "." + ext
+ download_rtmp(filename, vbase, vpath)
+
+def get_categories():
+ categories_doc = grab_xml(BASE_URL + PARAMS["categories"])
+ categories = {}
+ for category in categories_doc.xpath("//category[@genre='true']"):
+ cid = category.attrib["id"]
+ name = category.xpath("name/text()")[0]
+ categories[name] = cid
+ return categories
+
+def get_series(cid):
+ series_list_doc = grab_json(PARAMS["api"] + "seriesIndex")
+ episode_list = {}
+ for series in series_list_doc:
+ categories = series["e"].split()
+ if cid not in categories:
+ continue
+ sid = series["a"]
+ series_title = series["b"].replace("&", "&")
+ series_doc = grab_json(PARAMS["api"] + "series=" + sid)[0]
+ for episode in series_doc["f"]:
+ vpath = episode["n"]
+ episode_title = episode["b"].strip()
+ if series_title != episode_title:
+ episode_title = series_title + " " + episode_title
+ episode_list[episode_title] = (episode_title, vpath)
+ return episode_list
+
+
+
+def main():
+ config_doc = grab_xml(CONFIG_URL)
+ global PARAMS
+ PARAMS = dict((p.attrib["name"], p.attrib["value"]) for p in config_doc.xpath("/config/param"))
+
+ while True:
+ cid = choose(get_categories(), allow_multi=False)
+ if cid is None:
+ continue
+ while True:
+ sid = choose(get_series(cid), allow_multi=False)
+ if sid is None:
+ break
+ while True:
+ generator = choose(get_episodes(sid), allow_multi=True)
+ if generator is None:
+ break
+ for title, vpath in generator:
+ download_video(title, vpath)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except (KeyboardInterrupt, EOFError):
+ print "\nExiting..."
+