]> code.delx.au - webdl/blob - brightcove.py
e52e15cff1f28c21a2e82dc6568154592082f502
[webdl] / brightcove.py
1 import re
2 import sys
3
4 from common import grab_json, download_hls, Node, append_to_qs
5
6 CH9_TOKEN = "ogxhPgSphIVa2hhxbi9oqtYwtg032io4B4-ImwddYliFWHqS0UfMEw.."
7 CH10_TOKEN = "lWCaZyhokufjqe7H4TLpXwHSTnNXtqHxyMvoNOsmYA_GRaZ4zcwysw.."
8
9 BRIGHTCOVE_API = "http://api.brightcove.com/services/library?"
10
11
12 class BrightcoveVideoNode(Node):
13 def __init__(self, title, parent, token, video_id):
14 Node.__init__(self, title, parent)
15 self.can_download = True
16 self.token = token
17 self.video_id = video_id
18
19 def download(self):
20 desc_url = append_to_qs(BRIGHTCOVE_API, {
21 "token": self.token,
22 "command": "find_video_by_id",
23 "video_fields": "HLSURL",
24 "video_id": self.video_id,
25 })
26 doc = grab_json(desc_url, 3600)
27 video_url = doc["HLSURL"]
28 if not video_url:
29 raise Exception("No HLS stream available for: " + self.title)
30
31 filename = self.title + ".ts"
32 return download_hls(filename, video_url)
33
34 class BrightcoveRootNode(Node):
35 def __init__(self, title, parent, token):
36 Node.__init__(self, title, parent)
37 self.token = token
38 self.series_nodes = {}
39
40 def get_series_node(self, series_name):
41 series_name = series_name.split("-")[0].strip()
42 key = series_name.lower()
43 node = self.series_nodes.get(key, None)
44 if node is None:
45 node = Node(series_name, self)
46 self.series_nodes[key] = node
47 return node
48
49 def fill_children(self):
50 page_number = 0
51 while page_number < 100:
52 sys.stdout.write(".")
53 sys.stdout.flush()
54 url = self.get_all_videos_url(page_number)
55 page_number += 1
56
57 page = grab_json(url, 3600)
58 items = page["items"]
59 if len(items) == 0:
60 break
61
62 for video_desc in items:
63 self.process_video(video_desc)
64 print
65
66 def process_video(self, video_desc):
67 if not video_desc["customFields"]:
68 return
69
70 video_id = video_desc["id"]
71 title = self.get_video_title(video_desc)
72 series_name = self.get_series_name(video_desc)
73
74 parent_node = self.get_series_node(series_name)
75 BrightcoveVideoNode(title, parent_node, self.token, video_id)
76
77 def get_video_title(self, video_desc):
78 raise NotImplementedError()
79
80 def get_series_name(self, video_desc):
81 raise NotImplementedError()
82
83 def get_all_videos_url(self, page_number):
84 raise NotImplementedError()
85
86
87 class Ch9RootNode(BrightcoveRootNode):
88 def __init__(self, root_node):
89 BrightcoveRootNode.__init__(self, "Nine", root_node, CH9_TOKEN)
90
91 def get_video_title(self, video_desc):
92 title = video_desc["name"]
93 season = video_desc["customFields"].get("season", "")
94 episode = video_desc["customFields"].get("episode", "1").rjust(2, "0")
95 series = self.get_series_name(video_desc)
96
97 if re.match(R"ep(isode)?\s*[0-9]+\s*:", title.lower()):
98 title = title.split(":", 1)[1].strip()
99
100 title = "%s - %sx%s - %s" % (
101 series,
102 season,
103 episode,
104 title
105 )
106 return title
107
108 def get_series_name(self, video_desc):
109 series = video_desc["customFields"].get("series", None)
110 if not series:
111 series = video_desc["name"]
112 return series
113
114 def get_all_videos_url(self, page_number):
115 return append_to_qs(BRIGHTCOVE_API, {
116 "token": self.token,
117 "command": "search_videos",
118 "video_fields": "id,name,customFields",
119 "custom_fields": "series,season,episode",
120 "sort_by": "PUBLISH_DATE",
121 "page_number": str(page_number),
122 })
123
124
125 class Ch10RootNode(BrightcoveRootNode):
126 def __init__(self, root_node):
127 BrightcoveRootNode.__init__(self, "Ten", root_node, CH10_TOKEN)
128
129 def get_video_title(self, video_desc):
130 return video_desc["name"]
131
132 def get_series_name(self, video_desc):
133 return video_desc["customFields"]["tv_show"]
134
135 def get_all_videos_url(self, page_number):
136 return append_to_qs(BRIGHTCOVE_API, {
137 "token": self.token,
138 "command": "search_videos",
139 "video_fields": "id,name,customFields",
140 "custom_fields": "tv_show",
141 "sort_by": "PUBLISH_DATE",
142 "any": "video_type_long_form:Full Episode",
143 "page_number": str(page_number),
144 })
145
146
147 def fill_nodes(root_node):
148 Ch9RootNode(root_node)
149 Ch10RootNode(root_node)
150