1919
2020getString = xbmcaddon .Addon ().getLocalizedString
2121LIVE_CHANNELS = getString (30004 )
22- GEMS = {
23- 'featured' : getString (30005 ),
24- 'shows' : getString (30006 ),
25- 'documentaries' : getString (30024 ),
26- 'kids' : getString (30025 )
27- }
2822SEARCH = getString (30026 )
2923
3024
@@ -56,38 +50,64 @@ def authorize():
5650 return True
5751
5852
59- def play (labels , image , url ):
53+ def play (labels , image , data ):
6054 """Play the stream using the configured player."""
61- item = xbmcgui .ListItem (labels ['title' ], path = url )
62- if image :
63- item .setArt ({'thumb' : image , 'poster' : image })
64- item .setInfo (type = "Video" , infoLabels = labels )
65- helper = inputstreamhelper .Helper ('hls' )
66- if not xbmcaddon .Addon ().getSettingBool ("ffmpeg" ) and helper .check_inputstream ():
67- item .setProperty ('inputstream' , 'inputstream.adaptive' )
68- item .setProperty ('inputstream.adaptive.manifest_type' , 'hls' )
69- xbmcplugin .setResolvedUrl (plugin .handle , True , item )
70- if url is None :
55+ if not 'url' in data :
7156 xbmcgui .Dialog ().ok (getString (30010 ), getString (30011 ))
72-
57+ return
58+
59+ (lic , tok ) = GemV2 .get_stream_drm (data )
60+ is_helper = None
61+ mime = None
62+ drm = None
63+ if data ['type' ] == 'hls' :
64+ is_helper = inputstreamhelper .Helper ('hls' )
65+ elif data ['type' ] == 'dash' :
66+ drm = 'com.widevine.alpha'
67+ is_helper = inputstreamhelper .Helper ('mpd' , drm = drm )
68+ mime = 'application/dash+xml'
69+
70+ if is_helper is None :
71+ xbmcgui .Dialog ().ok (getString (30027 ), getString (30027 ))
72+ return
73+
74+ if is_helper .check_inputstream ():
75+ url = data ['url' ]
76+ play_item = xbmcgui .ListItem (path = url )
77+ play_item .setInfo (type = "Video" , infoLabels = labels )
78+ if mime :
79+ play_item .setMimeType (mime )
80+ play_item .setContentLookup (False )
81+
82+ if int (xbmc .getInfoLabel ('System.BuildVersion' ).split ('.' )[0 ]) >= 19 :
83+ play_item .setProperty ('inputstream' , is_helper .inputstream_addon )
84+ else :
85+ play_item .setProperty ('inputstreamaddon' , is_helper .inputstream_addon )
86+
87+ if drm :
88+ play_item .setProperty ('inputstream.adaptive.license_type' , drm )
89+ license_headers = {
90+ 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0' ,
91+ 'Content-Type' : 'application/octet-stream' ,
92+ 'Origin' : 'https://gem.cbc.ca' ,
93+ 'x-dt-auth-token' : tok , # string containing "Bearer eyJ...."
94+ }
95+ license_config = [ lic , urlencode (license_headers ), 'R{SSM}' , 'R' ]
96+ license_key = '|' .join (license_config )
97+ play_item .setProperty ('inputstream.adaptive.license_key' , license_key )
98+ xbmcplugin .setResolvedUrl (plugin .handle , True , play_item )
7399
74100def add_items (handle , items ):
75101 for item in items :
76102 list_item = xbmcgui .ListItem (item ['title' ])
77103 list_item .setInfo (type = "Video" , infoLabels = CBC .get_labels (item ))
78- image = item ['image' ].replace ('(Size)' , '224' )
104+ image = item ['image' ][ 'url' ] .replace ('(Size)' , '224' )
79105 list_item .setArt ({'thumb' : image , 'poster' : image })
80106 item_type = item ['type' ]
81107 is_folder = True
82- if item_type == 'SHOW' :
83- url = plugin .url_for (gem_show_menu , item ['id' ])
84- elif item_type == 'ASSET' :
85- url = plugin .url_for (gem_asset , item ['id' ])
86- list_item .setProperty ('IsPlayable' , 'true' )
87- is_folder = False
88- elif item_type == 'SEASON' :
89- # ignore the season and go to the show (its what the web UI does)
90- url = plugin .url_for (gem_show_menu , item ['id' ].split ('/' )[0 ])
108+ if item_type .lower () == 'show' or item_type .lower () == 'media' :
109+ p = GemV2 .normalized_format_path (item )
110+ url = plugin .url_for (layout_menu , p )
91111 else :
92112 log (f'Unable to handle shelf item type "{ item_type } ".' , True )
93113 url = None
@@ -143,9 +163,12 @@ def live_channels_add_only(station):
143163@plugin .route ('/channels/play' )
144164def play_live_channel ():
145165 labels = dict (parse_qsl (plugin .args ['labels' ][0 ])) if 'labels' in plugin .args else None
146- chans = LiveChannels ()
147- url = chans .get_channel_stream (plugin .args ['id' ][0 ])
148- return play (labels , plugin .args ['image' ][0 ], url )
166+ data = GemV2 .get_stream (plugin .args ['id' ][0 ], plugin .args ['app_code' ][0 ])
167+ if not 'url' in data :
168+ log ('Failed to get stream URL, attempting to authorize.' )
169+ if authorize ():
170+ data = GemV2 .get_stream (plugin .args ['id' ][0 ], plugin .args ['app_code' ][0 ])
171+ return play (labels , plugin .args ['image' ][0 ] if 'image' in plugin .args else None , data )
149172
150173@plugin .route ('/channels' )
151174def live_channels_menu ():
@@ -169,131 +192,11 @@ def live_channels_menu():
169192 (getString (30017 ), 'RunPlugin({})' .format (plugin .url_for (live_channels_add_only , callsign ))),
170193 ])
171194 xbmcplugin .addDirectoryItem (plugin .handle ,
172- plugin .url_for (play_live_channel , id = channel ['idMedia' ],
195+ plugin .url_for (play_live_channel , id = channel ['idMedia' ], app_code = 'medianetlive' ,
173196 labels = urlencode (labels ), image = image ), item , False )
174197 xbmcplugin .endOfDirectory (plugin .handle )
175198
176199
177- @plugin .route ('/gem/show/episode' )
178- def gem_episode ():
179- """Play an episode."""
180- json_str = plugin .args ['query' ][0 ]
181- episode = json .loads (json_str )
182-
183- # get the url, and failing that, attempt authorization, then retry
184- resp = GemV2 ().get_episode (episode ['url' ])
185- url = None if not resp else resp ['url' ] if 'url' in resp else None
186- if not url :
187- log ('Failed to get stream URL, attempting to authorize.' )
188- if authorize ():
189- resp = GemV2 ().get_episode (episode ['url' ])
190- url = resp ['url' ] if 'url' in resp else None
191-
192- labels = episode ['labels' ]
193- play (labels , None , url )
194-
195-
196- @plugin .route ('/gem/show/season' )
197- def gem_show_season ():
198- """Create a menu for a show season."""
199- xbmcplugin .setContent (plugin .handle , 'videos' )
200- json_str = plugin .args ['query' ][0 ]
201- # remember show['season'] is season details but there is general show info in show as well
202- show = json .loads (json_str )
203- for episode in show ['season' ]['assets' ]:
204- item = xbmcgui .ListItem (episode ['title' ])
205- image = episode ['image' ].replace ('(Size)' , '224' )
206- item .setArt ({'thumb' : image , 'poster' : image })
207- item .setProperty ('IsPlayable' , 'true' )
208- labels = GemV2 .get_labels (show , episode )
209- item .setInfo (type = "Video" , infoLabels = labels )
210- episode_info = {'url' : episode ['playSession' ]['url' ], 'labels' : labels }
211- url = plugin .url_for (gem_episode , query = json .dumps (episode_info ))
212- xbmcplugin .addDirectoryItem (plugin .handle , url , item , False )
213- xbmcplugin .endOfDirectory (plugin .handle )
214-
215-
216- @plugin .route ('/gem/asset/<path:asset>' )
217- def gem_asset (asset ):
218- asset_layout = GemV2 .get_asset_by_id (asset )
219- resp = GemV2 .get_episode (asset_layout ['playSession' ]['url' ])
220- url = None if not resp else resp ['url' ] if 'url' in resp else None
221- if not url :
222- log ('Failed to get stream URL, attempting to authorize.' )
223- if authorize ():
224- resp = GemV2 ().get_episode (asset_layout ['playSession' ]['url' ])
225- url = resp ['url' ] if 'url' in resp else None
226- labels = GemV2 .get_labels ({'title' : asset_layout ['series' ]}, asset_layout )
227- image = asset_layout ['image' ]
228- play (labels , image , url )
229-
230-
231- def gem_add_film_assets (assets ):
232- for asset in assets :
233- labels = GemV2 .get_labels ({'title' : asset ['series' ]}, asset )
234- image = asset ['image' ]
235- item = xbmcgui .ListItem (labels ['title' ])
236- item .setInfo (type = "Video" , infoLabels = labels )
237- item .setArt ({'thumb' : image , 'poster' : image })
238- item .setProperty ('IsPlayable' , 'true' )
239- episode_info = {'url' : asset ['playSession' ]['url' ], 'labels' : labels }
240- url = plugin .url_for (gem_episode , query = json .dumps (episode_info ))
241- xbmcplugin .addDirectoryItem (plugin .handle , url , item , False )
242-
243-
244- @plugin .route ('/gem/show/<show_id>' )
245- def gem_show_menu (show_id ):
246- """Create a menu for a shelfs items."""
247- xbmcplugin .setContent (plugin .handle , 'videos' )
248- show_layout = GemV2 .get_show_layout_by_id (show_id )
249- show = {k : v for (k , v ) in show_layout .items () if k not in ['sponsors' , 'seasons' ]}
250- for season in show_layout ['seasons' ]:
251-
252- # films seem to have been shoe-horned (with teeth) into the structure oddly -- compensate
253- if season ['title' ] == 'Film' :
254- gem_add_film_assets (season ['assets' ])
255- else :
256- labels = GemV2 .get_labels (season , season )
257- item = xbmcgui .ListItem (season ['title' ])
258- item .setInfo (type = "Video" , infoLabels = labels )
259- image = season ['image' ].replace ('(Size)' , '224' )
260- item .setArt ({'thumb' : image , 'poster' : image })
261- show ['season' ] = season
262- url = plugin .url_for (gem_show_season , query = json .dumps (show ))
263- xbmcplugin .addDirectoryItem (plugin .handle , url , item , True )
264-
265- xbmcplugin .endOfDirectory (plugin .handle )
266-
267-
268- @plugin .route ('/gem/shelf' )
269- def gem_shelf_menu ():
270- """Create a menu item for each shelf."""
271- handle = plugin .handle
272- xbmcplugin .setContent (handle , 'videos' )
273- json_str = plugin .args ['query' ][0 ]
274- shelf_items = json .loads (json_str )
275- add_items (handle , shelf_items )
276- xbmcplugin .addSortMethod (plugin .handle , xbmcplugin .SORT_METHOD_TITLE_IGNORE_THE )
277- xbmcplugin .endOfDirectory (handle )
278-
279-
280- @plugin .route ('/gem/categories/<category_id>' )
281- def gem_category_menu (category_id ):
282- """Populate a menu with categorical content."""
283- handle = plugin .handle
284- xbmcplugin .setContent (handle , 'videos' )
285- category = GemV2 .get_category (category_id )
286- for show in category ['items' ]:
287- item = xbmcgui .ListItem (show ['title' ])
288- item .setInfo (type = "Video" , infoLabels = CBC .get_labels (show ))
289- image = show ['image' ].replace ('(Size)' , '224' )
290- item .setArt ({'thumb' : image , 'poster' : image })
291- url = plugin .url_for (gem_show_menu , show ['id' ])
292- xbmcplugin .addDirectoryItem (handle , url , item , True )
293- xbmcplugin .addSortMethod (handle , xbmcplugin .SORT_METHOD_TITLE_IGNORE_THE )
294- xbmcplugin .endOfDirectory (handle )
295-
296-
297200@plugin .route ('/gem/search' )
298201def search ():
299202 handle = plugin .handle
@@ -303,23 +206,24 @@ def search():
303206 xbmcplugin .endOfDirectory (handle )
304207
305208
306- @plugin .route ('/gem/layout/<layout>' )
209+ @plugin .route ('/gem/layout/<path: layout>' )
307210def layout_menu (layout ):
308211 """Populate the menu with featured items."""
309212 handle = plugin .handle
310213 xbmcplugin .setContent (handle , 'videos' )
311- layout = GemV2 .get_layout (layout )
312- if 'categories' in layout :
313- for category in layout ['categories' ]:
314- item = xbmcgui .ListItem (category ['title' ])
315- url = plugin .url_for (gem_category_menu , category ['id' ])
316- xbmcplugin .addDirectoryItem (handle , url , item , True )
317- if 'shelves' in layout :
318- for shelf in layout ['shelves' ]:
319- item = xbmcgui .ListItem (shelf ['title' ])
320- shelf_items = json .dumps (shelf ['items' ])
321- url = plugin .url_for (gem_shelf_menu , query = shelf_items )
322- xbmcplugin .addDirectoryItem (handle , url , item , True )
214+ for f in GemV2 .get_format (layout ):
215+ n = GemV2 .normalized_format_item (f )
216+ p = GemV2 .normalized_format_path (f )
217+ item = xbmcgui .ListItem (n ['label' ])
218+ if 'art' in n :
219+ item .setArt (n ['art' ])
220+ item .setInfo (type = "Video" , infoLabels = n ['info_labels' ])
221+ if n ['playable' ]:
222+ item .setProperty ('IsPlayable' , 'true' )
223+ url = plugin .url_for (play_live_channel , id = p , app_code = n ['app_code' ])
224+ else :
225+ url = plugin .url_for (layout_menu , p )
226+ xbmcplugin .addDirectoryItem (handle , url , item , not n ['playable' ])
323227 xbmcplugin .endOfDirectory (handle )
324228
325229
@@ -334,8 +238,8 @@ def main_menu():
334238
335239 handle = plugin .handle
336240 xbmcplugin .setContent (handle , 'videos' )
337- for key , value in GEMS . items ():
338- xbmcplugin .addDirectoryItem (handle , plugin .url_for (layout_menu , key ), xbmcgui .ListItem (value ), True )
241+ for c in GemV2 . get_browse ():
242+ xbmcplugin .addDirectoryItem (handle , plugin .url_for (layout_menu , c [ 'url' ] ), xbmcgui .ListItem (c [ 'title' ] ), True )
339243 xbmcplugin .addDirectoryItem (handle , plugin .url_for (live_channels_menu ), xbmcgui .ListItem (LIVE_CHANNELS ), True )
340244 xbmcplugin .addDirectoryItem (handle , plugin .url_for (search ), xbmcgui .ListItem (SEARCH ), True )
341245 xbmcplugin .endOfDirectory (handle )
0 commit comments