]> code.delx.au - webdl/blob - sbs.py
Fixed SBS downloader
[webdl] / sbs.py
1 #!/usr/bin/env python
2 # vim:ts=4:sts=4:sw=4:noet
3
4 from common import grab_html, grab_json, grab_xml, download_rtmp, download_urllib, Node
5
6 import collections
7
8 BASE = "http://www.sbs.com.au"
9 MENU_URL = "/api/video_feed/f/dYtmxB/%s?startIndex=%d"
10 VIDEO_URL = BASE + "/ondemand/video/single/%s"
11
12 NS = {
13 "smil": "http://www.w3.org/2005/SMIL21/Language",
14 }
15
16 SECTIONS = [
17 "section-sbstv",
18 "section-programs",
19 ]
20
21 CATEGORY_MAP = {
22 "Factual": "Documentary",
23 }
24
25
26 class SbsNode(Node):
27 def __init__(self, title, parent, video_id):
28 Node.__init__(self, title, parent)
29 self.title = title
30 self.video_id = video_id.split("/")[-1]
31 self.can_download = True
32
33 def download(self):
34 doc = grab_html(VIDEO_URL % self.video_id, 0)
35 desc_url = None
36 for script in doc.xpath("//script", namespaces=NS):
37 if not script.text:
38 continue
39 for line in script.text.split("\n"):
40 if line.find("player.releaseUrl") < 0:
41 continue
42 desc_url = line[line.find("\"")+1 : line.rfind("\"")]
43 break
44 if desc_url is not None:
45 break
46 if desc_url is None:
47 raise Exception("Failed to get JSON URL for " + self.title)
48
49 doc = grab_xml(desc_url, 0)
50 best_url = None
51 best_bitrate = 0
52 for video in doc.xpath("//smil:video", namespaces=NS):
53 bitrate = int(video.attrib["system-bitrate"])
54 if best_bitrate == 0 or best_bitrate < bitrate:
55 best_bitrate = bitrate
56 best_url = video.attrib["src"]
57
58 ext = best_url.rsplit(".", 1)[1]
59 filename = self.title + "." + ext
60 best_url += "?v=2.5.14&fp=MAC%2011,1,102,55&r=FLQDD&g=YNANAXRIYFYO"
61 return download_urllib(filename, best_url)
62
63 def fill_entry(get_catnode, entry):
64 title = entry["title"]
65 video_id = entry["id"]
66 info = collections.defaultdict(list)
67 for d in entry["media$categories"]:
68 if not d.has_key("media$scheme"):
69 continue
70 info[d["media$scheme"]].append(d["media$name"])
71
72 if "Section/Promos" in info.get("Section", []):
73 # ignore promos
74 return
75
76 for category in info.get("Genre", ["$UnknownCategory$"]):
77 category = CATEGORY_MAP.get(category, category)
78 parent_node = get_catnode(category)
79 SbsNode(title, parent_node, video_id)
80
81
82 def fill_section(get_catnode, section):
83 index = 1
84 while True:
85 doc = grab_json(BASE + MENU_URL % (section, index), 3600)
86 if len(doc.get("entries", [])) == 0:
87 break
88 for entry in doc["entries"]:
89 fill_entry(get_catnode, entry)
90 index += doc["itemsPerPage"]
91
92 class SbsRoot(Node):
93 def __init__(self, parent=None):
94 Node.__init__(self, "SBS", parent)
95 self.catnodes = {}
96
97 def get_catnode(self, name):
98 try:
99 return self.catnodes[name]
100 except KeyError:
101 n = Node(name, self)
102 self.catnodes[name] = n
103 return n
104
105 def fill_children(self):
106 for section in SECTIONS:
107 fill_section(self.get_catnode, section)
108
109 def fill_nodes(root_node):
110 SbsRoot(root_node)
111