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