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