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