]>
code.delx.au - webdl/blob - brightcove.py
5 from common
import grab_json
, download_hls
, download_http
, Node
, append_to_qs
7 CH9_TOKEN
= "ogxhPgSphIVa2hhxbi9oqtYwtg032io4B4-ImwddYliFWHqS0UfMEw.."
8 CH10_TOKEN
= "lWCaZyhokufjqe7H4TLpXwHSTnNXtqHxyMvoNOsmYA_GRaZ4zcwysw.."
10 BRIGHTCOVE_API
= "http://api.brightcove.com/services/library?"
13 class BrightcoveVideoNode(Node
):
14 def __init__(self
, title
, parent
, token
, video_id
):
15 Node
.__init
__(self
, title
, parent
)
16 self
.can_download
= True
18 self
.video_id
= video_id
22 try_streams
= [self
.try_widevine
, self
.try_hls
]
24 while f
is None and try_streams
:
25 f
= try_streams
.pop()()
28 logging
.error("No HLS or Widevine stream available for: %s", self
.title
)
34 desc_url
= append_to_qs(BRIGHTCOVE_API
, {
36 "command": "find_video_by_id",
37 "video_fields": "HLSURL",
38 "video_id": self
.video_id
,
41 doc
= grab_json(desc_url
, 3600)
42 video_url
= doc
["HLSURL"]
46 filename
= self
.title
+ ".ts"
47 return lambda: download_hls(filename
, video_url
)
49 def try_widevine(self
):
50 desc_url
= append_to_qs(BRIGHTCOVE_API
, {
52 "command": "find_video_by_id",
53 "video_fields": "WVMRenditions",
54 "video_id": self
.video_id
,
57 doc
= grab_json(desc_url
, 3600)
59 renditions
= doc
["WVMRenditions"]
63 best_rendition
= sorted(renditions
, key
=lambda r
: r
["frameHeight"])[-1]
64 video_url
= best_rendition
["url"]
65 filename
= self
.title
+ ".ts"
67 return lambda: download_http(filename
, video_url
)
70 class BrightcoveRootNode(Node
):
71 def __init__(self
, title
, parent
, token
):
72 Node
.__init
__(self
, title
, parent
)
74 self
.series_nodes
= {}
76 def get_series_node(self
, series_name
):
77 series_name
= series_name
.split("-")[0].strip()
78 key
= series_name
.lower()
79 node
= self
.series_nodes
.get(key
, None)
81 node
= Node(series_name
, self
)
82 self
.series_nodes
[key
] = node
85 def fill_children(self
):
87 while page_number
< 100:
88 url
= self
.get_all_videos_url(page_number
)
91 page
= grab_json(url
, 3600)
96 for video_desc
in items
:
97 self
.process_video(video_desc
)
99 def process_video(self
, video_desc
):
100 if not video_desc
["customFields"]:
103 video_id
= video_desc
["id"]
104 title
= self
.get_video_title(video_desc
)
105 series_name
= self
.get_series_name(video_desc
)
107 parent_node
= self
.get_series_node(series_name
)
108 BrightcoveVideoNode(title
, parent_node
, self
.token
, video_id
)
110 def get_video_title(self
, video_desc
):
111 raise NotImplementedError()
113 def get_series_name(self
, video_desc
):
114 raise NotImplementedError()
116 def get_all_videos_url(self
, page_number
):
117 raise NotImplementedError()
120 class Ch9RootNode(BrightcoveRootNode
):
121 def __init__(self
, root_node
):
122 BrightcoveRootNode
.__init
__(self
, "Nine", root_node
, CH9_TOKEN
)
124 def get_video_title(self
, video_desc
):
125 title
= video_desc
["name"]
126 season
= video_desc
["customFields"].get("season", "")
127 episode
= video_desc
["customFields"].get("episode", "1").rjust(2, "0")
128 series
= self
.get_series_name(video_desc
)
130 if re
.match(R
"ep(isode)?\s*[0-9]+\s*:", title
.lower()):
131 title
= title
.split(":", 1)[1].strip()
133 title
= "%s - %sx%s - %s" % (
141 def get_series_name(self
, video_desc
):
142 series
= video_desc
["customFields"].get("series", None)
144 series
= video_desc
["name"]
147 def get_all_videos_url(self
, page_number
):
148 return append_to_qs(BRIGHTCOVE_API
, {
150 "command": "search_videos",
151 "video_fields": "id,name,customFields",
152 "custom_fields": "series,season,episode",
153 "sort_by": "PUBLISH_DATE",
154 "page_number": str(page_number
),
158 class Ch10RootNode(BrightcoveRootNode
):
159 def __init__(self
, root_node
):
160 BrightcoveRootNode
.__init
__(self
, "Ten", root_node
, CH10_TOKEN
)
162 def get_video_title(self
, video_desc
):
163 return video_desc
["name"]
165 def get_series_name(self
, video_desc
):
166 return video_desc
["customFields"]["tv_show"]
168 def get_all_videos_url(self
, page_number
):
169 return append_to_qs(BRIGHTCOVE_API
, {
171 "command": "search_videos",
172 "video_fields": "id,name,customFields",
173 "custom_fields": "tv_show",
174 "sort_by": "PUBLISH_DATE",
175 "any": "video_type_long_form:Full Episode",
176 "page_number": str(page_number
),
180 def fill_nodes(root_node
):
181 Ch9RootNode(root_node
)
182 Ch10RootNode(root_node
)