]> code.delx.au - webdl/blob - sbs.py
Improved error message for SBS
[webdl] / sbs.py
1 #!/usr/bin/env python
2 # vim:ts=4:sts=4:sw=4:noet
3
4 from common import grab_text, grab_html, grab_json, grab_xml, download_rtmp, download_urllib, Node, append_to_qs
5
6 import collections
7 import urlparse
8
9 BASE = "http://www.sbs.com.au"
10 VIDEO_MENU = BASE + "/ondemand/js/video-menu"
11 VIDEO_URL = BASE + "/ondemand/video/single/%s"
12 VIDEO_MAGIC = {
13 "v": "2.5.14",
14 "fp": "MAC 11,1,102,55",
15 "r": "FLQDD",
16 "g": "YNANAXRIYFYO",
17 }
18 SWF_URL = "http://resources.sbs.com.au/vod/theplatform/core/current/swf/flvPlayer.swf"
19
20 NS = {
21 "smil": "http://www.w3.org/2005/SMIL21/Language",
22 }
23
24
25 class SbsNode(Node):
26 def __init__(self, title, parent, video_id):
27 Node.__init__(self, title, parent)
28 self.title = title
29 self.video_id = video_id.split("/")[-1]
30 self.can_download = True
31
32 def download(self):
33 doc = grab_html(VIDEO_URL % self.video_id, 0)
34 meta_video = doc.xpath("//meta[@property='og:video']")[0]
35 swf_url = meta_video.attrib["content"]
36 swf_url_qs = urlparse.parse_qs(urlparse.urlparse(swf_url).query)
37 desc_url = swf_url_qs["v"][0]
38
39 doc = grab_text(desc_url, 0)
40 doc_qs = urlparse.parse_qs(doc)
41 desc_url = doc_qs["releaseUrl"][0]
42
43 doc = grab_xml(desc_url, 0)
44 error = doc.xpath("//smil:param[@name='exception']/@value", namespaces=NS)
45 if error:
46 raise Exception("Error downloading, SBS said: " + error[0])
47
48 video = doc.xpath("//smil:video", namespaces=NS)[0]
49 video_url = video.attrib["src"]
50 if not video_url:
51 raise Exception("Unsupported video '%s': %s" % (self.title, desc_url))
52 ext = urlparse.urlsplit(video_url).path.rsplit(".", 1)[1]
53 filename = self.title + "." + ext
54 video_url = append_to_qs(video_url, VIDEO_MAGIC)
55 return download_urllib(filename, video_url, referrer=SWF_URL)
56
57 class SbsNavNode(Node):
58 def __init__(self, title, parent, url):
59 Node.__init__(self, title, parent)
60 self.url = url
61
62 def fill_children(self):
63 try:
64 doc = grab_json(BASE + self.url, 3600)
65 except ValueError:
66 # SBS sends XML as an error message :\
67 return
68 if len(doc.get("entries", [])) == 0:
69 return
70 for entry in doc["entries"]:
71 self.fill_entry(entry)
72
73 def fill_entry(self, entry):
74 title = entry["title"]
75 video_id = entry["id"]
76 SbsNode(title, self, video_id)
77
78 class SbsRootNode(Node):
79 def __init__(self, parent):
80 Node.__init__(self, "SBS", parent)
81
82 def fill_children(self):
83 menu = grab_json(VIDEO_MENU, 3600, skip_assignment=True)
84 for name in menu.keys():
85 self.fill_category(self, menu[name])
86
87 def create_nav_node(self, name, parent, cat_data, url_key):
88 try:
89 url = cat_data[url_key]
90 except KeyError:
91 return
92 if url.strip():
93 SbsNavNode(name, parent, url)
94
95 def fill_category(self, parent, cat_data):
96 if not cat_data.has_key("children"):
97 name = cat_data["name"]
98 self.create_nav_node(name, parent, cat_data, "url")
99 return
100
101 node = Node(cat_data["name"], parent)
102 self.create_nav_node("-Featured", node, cat_data, "furl")
103 self.create_nav_node("-Latest", node, cat_data, "url")
104 self.create_nav_node("-Most Popular", node, cat_data, "purl")
105
106 children = cat_data.get("children", [])
107 if isinstance(children, dict):
108 children = [children[k] for k in sorted(children.keys())]
109 for child_cat in children:
110 self.fill_category(node, child_cat)
111
112 def fill_nodes(root_node):
113 SbsRootNode(root_node)
114