except ImportError:
import md5 as hashlib
import os
+import re
import shutil
import signal
import subprocess
import tempfile
import time
import urllib
+import urlparse
import autosocks
self.parent = parent
self.children = []
self.can_download = False
+ self.sort_children = False
def get_children(self):
if not self.children:
f.close()
return doc
-def grab_json(url, max_age):
+def grab_json(url, max_age, skip_assignment=False):
f = urlopen(url, max_age)
- doc = json.load(f)
+ if skip_assignment:
+ text = f.read()
+ pos = text.find("=")
+ doc = json.loads(text[pos+1:])
+ else:
+ doc = json.load(f)
f.close()
return doc
pass
return False
+def natural_sort(l, key=None):
+ ignore_list = ["a", "the"]
+ def key_func(k):
+ if key is not None:
+ k = key(k)
+ k = k.lower()
+ newk = []
+ for c in re.split("([0-9]+)", k):
+ c = c.strip()
+ if c.isdigit():
+ newk.append(int(c))
+ else:
+ for subc in c.split():
+ if subc not in ignore_list:
+ newk.append(subc)
+ return newk
+
+ return sorted(l, key=key_func)
+
+def append_to_qs(url, params):
+ r = list(urlparse.urlsplit(url))
+ qs = urlparse.parse_qs(r[3])
+ qs.update(params)
+ r[3] = urllib.urlencode(qs, True)
+ url = urlparse.urlunsplit(r)
+ return url
+
#!/usr/bin/env python
# vim:ts=4:sts=4:sw=4:noet
-from common import load_root_node
+from common import load_root_node, natural_sort
import sys
def choose(options, allow_multi):
- skeys = sorted(options.keys())
- for i, key in enumerate(skeys):
- print " %d) %s" % (i+1, key)
- print " 0) Back"
+ reverse_map = {}
+ for i, (key, value) in enumerate(options):
+ print "%3d) %s" % (i+1, key)
+ reverse_map[i+1] = value
+ print " 0) Back"
while True:
try:
values = map(int, raw_input("Choose> ").split())
continue
if 0 in values:
return
- values = [options[skeys[value-1]] for value in values]
+ values = [reverse_map[value] for value in values]
if allow_multi:
return values
else:
node = load_root_node()
while True:
- options = {}
+ options = []
will_download = True
for n in node.get_children():
- options[n.title] = n
+ options.append((n.title, n))
if not n.can_download:
will_download = False
+ if node.sort_children:
+ options = natural_sort(options, key=lambda x: x[0])
result = choose(options, allow_multi=will_download)
if result is None:
if node.parent is not None:
}
class IviewNode(Node):
- def __init__(self, title, parent, vpath):
+ def __init__(self, title, parent, params, vpath):
Node.__init__(self, title, parent)
+ self.params = params
self.vpath = vpath
self.can_download = True
def download(self):
- auth_doc = grab_xml(PARAMS["auth"], 0)
+ auth_doc = grab_xml(self.params["auth"], 0)
vbase = auth_doc.xpath("//auth:server/text()", namespaces=NS)[0]
token = auth_doc.xpath("//auth:token/text()", namespaces=NS)[0]
vbase += "?auth=" + token
return download_rtmp(filename, vbase, vpath, HASH_URL)
-class IviewSeries(Node):
- def __init__(self, series_title, series_id, parent):
- Node.__init__(self, series_title, parent)
- self.series_title = series_title
+class IviewSeriesNode(Node):
+ def __init__(self, title, parent, params, series_id):
+ Node.__init__(self, title, parent)
+ self.params = params
self.series_id = series_id
+ self.sort_children = True
def fill_children(self):
- series_doc = grab_json(PARAMS["api"] + "series=" + self.series_id, 3600)
+ series_doc = grab_json(self.params["api"] + "series=" + self.series_id, 3600)
if not series_doc:
return
for episode in series_doc[0]["f"]:
vpath = episode["n"]
episode_title = episode["b"].strip()
- if not episode_title.startswith(self.series_title):
- episode_title = self.series_title + " " + episode_title
+ if not episode_title.startswith(self.title):
+ episode_title = self.title + " " + episode_title
if episode_title.lower().endswith(" (final)"):
episode_title = episode_title[:-8]
- IviewNode(episode_title, self, vpath)
+ IviewNode(episode_title, self, self.params, vpath)
+
+class IviewRootNode(Node):
+ def __init__(self, parent):
+ Node.__init__(self, "ABC iView", parent)
+ self.sort_children = True
+
+ def fill_children(self):
+ config_doc = grab_xml(CONFIG_URL, 24*3600)
+ params = dict((p.attrib["name"], p.attrib["value"]) for p in config_doc.xpath("/config/param"))
+
+ categories_doc = grab_xml(BASE_URL + params["categories"], 24*3600)
+ categories_map = {}
+ for category in categories_doc.xpath("//category[@genre='true']"):
+ cid = category.attrib["id"]
+ category_name = category.xpath("name/text()")[0]
+ category_node = Node(category_name, self)
+ category_node.sort_children = True
+ categories_map[cid] = category_node
+
+ # Create a duplicate of each series within each category that it appears
+ series_list_doc = grab_json(params["api"] + "seriesIndex", 3600)
+ for series in series_list_doc:
+ categories = series["e"].split()
+ sid = series["a"]
+
+ series_title = series["b"].replace("&", "&")
+ for cid in categories:
+ category_node = categories_map.get(cid, None)
+ if category_node:
+ IviewSeriesNode(series_title, category_node, params, sid)
def fill_nodes(root_node):
- root_node = Node("ABC iView", root_node)
-
- config_doc = grab_xml(CONFIG_URL, 24*3600)
- global PARAMS
- PARAMS = dict((p.attrib["name"], p.attrib["value"]) for p in config_doc.xpath("/config/param"))
-
- categories_doc = grab_xml(BASE_URL + PARAMS["categories"], 24*3600)
- categories_map = {}
- for category in categories_doc.xpath("//category[@genre='true']"):
- cid = category.attrib["id"]
- category_name = category.xpath("name/text()")[0]
- category_node = Node(category_name, root_node)
- categories_map[cid] = category_node
-
- # Create a duplicate of each series within each category that it appears
- series_list_doc = grab_json(PARAMS["api"] + "seriesIndex", 3600)
- for series in series_list_doc:
- categories = series["e"].split()
- sid = series["a"]
-
- series_title = series["b"].replace("&", "&")
- for cid in categories:
- category_node = categories_map.get(cid, None)
- if category_node:
- IviewSeries(series_title, sid, category_node)
+ IviewRootNode(root_node)