def play(asset, play_type=PLAY_FROM_LIVE, **kwargs): play_type = int(play_type) from_start = False if play_type == PLAY_FROM_START or ( play_type == PLAY_FROM_ASK and not gui.yes_no(_.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START)): from_start = True stream = api.play(asset, True) item = plugin.Item( path=stream['url'], inputstream=inputstream.Widevine( license_key=stream['license']['@uri']), headers=HEADERS, ) drm_data = stream['license'].get('drmData') if drm_data: item.headers['x-axdrm-message'] = drm_data if from_start: item.resume_from = 1 return item
def play(asset, play_type=PLAY_FROM_LIVE, **kwargs): play_type = int(play_type) from_start = False if play_type == PLAY_FROM_START or ( play_type == PLAY_FROM_ASK and not gui.yes_no(_.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START)): from_start = True stream = api.play(asset, True) item = plugin.Item( path=stream['url'], inputstream=inputstream.Widevine( license_key=stream['license']['@uri']), headers=HEADERS, ) drm_data = stream['license'].get('drmData') if drm_data: item.headers['x-axdrm-message'] = drm_data if from_start: item.properties['ResumeTime'] = '1' item.properties['TotalTime'] = '1' if kwargs.get(ROUTE_LIVE_TAG): item.inputstream.properties['manifest_update_parameter'] = 'full' return item
def play(id, **kwargs): data = api.play(id) headers = {} headers.update(HEADERS) drm_info = data.get('drmInfo') or {} cookies = data.get('cookie') or {} if drm_info: if drm_info['drmScheme'].lower() == 'widevine': ia = inputstream.Widevine(license_key=drm_info['drmLicenseUrl'], ) headers.update(drm_info.get('drmKeyRequestProperties') or {}) else: raise PluginError('Unsupported Stream!') else: ia = inputstream.HLS(live=True) return plugin.Item( path=data['url'], inputstream=ia, headers=headers, cookies=cookies, resume_from=LIVE_HEAD, ## Need to seek to live over multi-periods )
def play(slug, **kwargs): data, content = api.play(slug) headers = { 'Authorization': 'Bearer {}'.format(userdata.get('access_token')), } item = plugin.Item( path = data['url'], inputstream = inputstream.MPD(), headers = headers, ) if 'drm' in data: item.inputstream = inputstream.Widevine(license_key = data['drm']['licenseUrl']) item.proxy_data['manifest_middleware'] = plugin.url_for(mpd_request) if settings.getBool('wv_secure'): item.inputstream.properties['license_flags'] = 'force_secure_decoder' item.play_next = {} if ':episode' in slug: item.update( label = content['titles']['full'], art = {'thumb': _image(content['images'].get('tileburnedin')), 'fanart': _image(content['images'].get('tile'), size='1920x1080')}, info = { 'plot': content['summaries']['short'], 'duration': content['duration'], 'tvshowtitle': content['seriesTitles']['full'], 'season': content.get('seasonNumber', 1), 'episode': content.get('numberInSeason', content.get('numberInSeries', 1)), 'mediatype': 'episode' }, ) if settings.getBool('play_next_episode', True): item.play_next['next_file'] = _get_play_path(content.get('next')) elif ':feature' in slug: item.update( label = content['titles']['full'], art = {'thumb': _image(content['images'].get('tileburnedin')), 'fanart':_image(content['images'].get('tile'), size='1920x1080')}, info = { 'plot': content['summaries']['short'], 'duration': content['duration'], 'year': content['releaseYear'], 'mediatype': 'movie', }, ) if settings.getBool('play_next_movie', False): for slug in content.get('similars', []): if ':feature' in slug: item.play_next['next_file'] = 'urn:hbo:feature:' + slug.split(':')[3] break if not settings.getBool('ignore_subs', False): for row in data.get('textTracks', []): item.subtitles.append([row['url'], row['language']]) return item
def _play_videos(videos): if not videos: plugin.exception('No videos found') default_audio = settings.getEnum('audio_lang', AUDIO_LANGS) if len(videos) == 1: chosen = videos[0] else: videos = sorted(videos, key=lambda x: x['language']) chosen = None for video in videos: if video['language']['iso_639_3'].lower() == default_audio: chosen = video break if not chosen: index = gui.select(_.SELECT_LANG, [x['language']['name'] for x in videos]) if index < 0: return chosen = videos[index] url, license_url = api.play(chosen['id']) item = plugin.Item( inputstream=inputstream.Widevine(license_url), path=url, headers=HEADERS, use_proxy= True, # Needed for https://github.com/xbmc/inputstream.adaptive/pull/606 ) return item
def _play(program_id, play_type=None, is_live=False): play_type = int(play_type) if play_type else None program_data, play_data = api.play(program_id) headers = HEADERS.copy() headers['dt-custom-data'] = play_data['drm']['customData'] item = plugin.Item( path = play_data['videoUrl'], headers = headers, inputstream = inputstream.Widevine( license_key = play_data['drm']['licenseServerUrl'], license_data = play_data['drm']['init_data'], response = 'JBlicense', ), ) if is_live and (play_type == PLAY_FROM_START or (play_type == PLAY_FROM_ASK and not gui.yes_no(_.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START))): item.properties['ResumeTime'] = '1' item.properties['TotalTime'] = '1' for row in play_data.get('captions', []): item.subtitles.append([row['url'], row['language']]) # for chapter in program_data.get('chapters', []): # if chapter['name'] == 'Intro': # item.properties['TotalTime'] = item.properties['ResumeTime'] = str(chapter['end']/1000 - 1) # elif chapter['name'] == 'Credits': # item.play_next = {'time': chapter['start']/1000} return item
def play_channel(id, **kwargs): url, license_url, headers = api.play_channel(id) return plugin.Item( inputstream = inputstream.Widevine(license_url, properties={'manifest_update_parameter': 'full'}), headers = headers, path = url, )
def play_asset(stream_url, content_id, **kwargs): url, license_url, headers = api.play_asset(stream_url, content_id) return plugin.Item( inputstream = inputstream.Widevine(license_url), headers = headers, path = url, )
def play_video(id, **kwargs): url, license_url, headers = api.play_video(id) return plugin.Item( inputstream = inputstream.Widevine(license_url), headers = headers, path = url, )
def play(channel_id, call_letter, **kwargs): data = api.play(channel_id, call_letter) item = plugin.Item( path=data['url'], headers={'X-AxDRM-Message': data['DRMToken']}, inputstream=inputstream.Widevine(license_key='{}?KID={}'.format( data['LicenseURL'], data['KeyID']), ), ) return item
def play_video(index, **kwargs): video = VIDEO_TESTS[int(index)] item = plugin.Item(path=video['url'], ) if video['type'] == 'ia_hls': item.inputstream = inputstream.HLS(force=True, live=False) elif video['type'] == 'ia_mpd': item.inputstream = inputstream.MPD() elif video['type'] == 'ia_widevine': item.inputstream = inputstream.Widevine(video.get('license_key')) return item
def _play(media_type, id): url, license_url = api.play(media_type, id) item = plugin.Item( inputstream = inputstream.Widevine(license_key=license_url), path = url, headers = HEADERS, ) if media_type == TYPE_LIVE: item.inputstream.properties['manifest_update_parameter'] = 'full' return item
def play_channel(id, **kwargs): url, license = api.play_channel(id) item = plugin.Item( path=url, headers=HEADERS, inputstream=inputstream.Widevine(license_key=license, ), ) if kwargs.get(ROUTE_LIVE_TAG): item.inputstream.properties['manifest_update_parameter'] = 'full' return item
def play(channel_id, **kwargs): url = api.play(channel_id) license_path = plugin.url_for(license_request, channel_id=channel_id) return plugin.Item( path=url, inputstream=inputstream.Widevine(license_key=license_path, challenge='b{SSM}', response='B'), headers=HEADERS, proxy_data={'default_language': settings.get('default_language')}, )
def play_channel(slug, **kwargs): channel = Channel.get_by_id(slug) split = channel.url.split('|') headers = { 'user-agent': DEFAULT_USERAGENT, } if len(split) > 1: _headers = dict( parse_qsl(u'{}'.format(split[1]), keep_blank_values=True)) for key in _headers: if _headers[key].startswith(' '): _headers[key] = u'%20{}'.format(_headers[key][1:]) headers[key.lower()] = _headers[key] item = plugin.Item( label=channel.name, art={'thumb': channel.logo}, path=split[0], properties=channel.properties, headers=headers, playable=True, ) if channel.radio: item.use_proxy = False manifest_type = channel.properties.get( 'inputstream.adaptive.manifest_type', '') license_type = channel.properties.get('inputstream.adaptive.license_type', '') if license_type.lower() == 'com.widevine.alpha': inputstream.Widevine().check() elif manifest_type.lower() == 'hls': inputstream.HLS(force=True, live=True).check() elif manifest_type.lower() == 'ism': inputstream.Playready().check() elif manifest_type.lower() == 'mpd': inputstream.MPD().check() elif not channel.radio and '.m3u8' in split[0].lower( ) and settings.getBool('use_ia_hls_live'): item.inputstream = inputstream.HLS(live=True) return item
def get_stream(self, film_id): play_data = self._session.get('/services/content/v4/media_content/play/film/{}'.format(film_id), params={'encoding_type':'dash', 'drm':'widevine'}).json() if 'error' in play_data: raise APIError(play_data['error']) mpd_url = play_data['streams'][0]['url'] key_url = BASE_URL.format('/services/license/widevine/cenc?context={}'.format(play_data['streams'][0]['drm_key_encoded'].strip())) item = plugin.Item( path = play_data['streams'][0]['url'], inputstream = inputstream.Widevine(license_key=key_url), headers = self._session.headers, ) return item
def _play(asset_id, is_linear=False, is_live=False): url, license = api.play(asset_id, is_linear=is_linear) item = plugin.Item( path = url, headers = HEADERS, inputstream = inputstream.Widevine( license_key = license, ), ) if is_live: item.inputstream.properties['manifest_update_parameter'] = 'full' return item
def play(channel_id=None, vod_id=None, **kwargs): asset = api.play(channel_id, vod_id) _headers = {} _headers.update(HEADERS) _headers.update({ 'Authorization': asset['DrmToken'], 'X-CB-Ticket': asset['DrmTicket'], 'X-ErDRM-Message': asset['DrmTicket'], }) return plugin.Item( path=asset['Path'], inputstream=inputstream.Widevine(license_key=WV_LICENSE_URL), headers=_headers, )
def play(video_id, **kwargs): url, license_url, token, data = api.play(video_id) item = _parse_item(data) item.proxy_data['manifest_middleware'] = plugin.url_for(mpd_request) headers = { 'authorization': 'Bearer {}'.format(token), } item.update( path=url, headers=headers, inputstream=inputstream.Widevine(license_key=license_url, ), ) return item
def play(id, **kwargs): url, license = api.play_media(id) item = plugin.Item( path = url, headers = HEADERS, inputstream = inputstream.Widevine( license_key = license, challenge = '', content_type = '', response = 'JBlicense', ), ) if kwargs.get(ROUTE_LIVE_TAG): item.inputstream.properties['manifest_update_parameter'] = 'full' gui.text(OLD_MESSAGE) return item
def play(id, play_type=PLAY_FROM_LIVE, **kwargs): mpd_url, license, headers, from_start = api.play(id) item = plugin.Item( path=mpd_url, inputstream=inputstream.Widevine(license_key=license), headers=headers, use_proxy=True, ) play_type = int(play_type) if from_start and ( play_type == PLAY_FROM_START or (play_type == PLAY_FROM_ASK and not gui.yes_no( _.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START)) ): item.properties['ResumeTime'] = 1 item.properties['TotalTime'] = 1 return item
def play(self, slug): resp = self._session.get('/videos/{slug}'.format(slug=slug), allow_redirects=False) if resp.status_code == 302 or 'The device limit for your account has been reached' in resp.text: raise APIError(_.DEVICE_LIMIT) page = resp.text.replace(' ', '').strip() play_url = re.search('embed_url:"(.*?)"', page).group(1) resp = self._session.get(play_url) page = resp.text.replace(' ', '').strip() event_id = re.search('eventId:(.*?),', page) if event_id: config_url = LIVESTREAM_URL.format(event_id=event_id.group(1)) else: config_url = re.search('"config_url":"(.*?)"', page).group(1) config_url = config_url.encode().decode('unicode_escape') data = self._session.get(config_url, headers={ 'Referer': 'https://embed.vhx.tv/' }).json() if data.get('secure_m3u8_url'): return data['secure_m3u8_url'], inputstream.HLS() default_cdn = data['request']['files']['dash']['default_cdn'] mpd_url = data['request']['files']['dash']['cdns'][default_cdn][ 'url'] #.replace('.json?base64_init=1', '.mpd') mpd_url = mpd_url.replace('.json', '.mpd') if data['request'].get('drm'): license_url = self._session.get( data['request']['drm']['cdms']['widevine']['license_url']).text ia = inputstream.Widevine(license_key=license_url) else: ia = inputstream.MPD() return mpd_url, ia
def play(id, play_type=PLAY_FROM_LIVE, **kwargs): mpd_url, license, headers, from_start = api.play(id) item = plugin.Item( path=mpd_url, inputstream=inputstream.Widevine(license_key=license), headers=headers, ) play_type = int(play_type) if from_start and ( play_type == PLAY_FROM_START or (play_type == PLAY_FROM_ASK and not gui.yes_no( _.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START)) ): item.resume_from = 1 elif ROUTE_LIVE_TAG in kwargs: ## Need below to seek to live over multi-periods item.resume_from = LIVE_HEAD return item
def play(media_id, media_type, start=None, duration=None, **kwargs): if start: start = int(start) now = arrow.utcnow() if start > now.timestamp: raise PluginError(_.NOT_STARTED_YET) elif start < now.shift(hours=-24).timestamp: raise PluginError(_.EVENT_EXPIRED) data = api.play(media_id, media_type, start, duration) headers = HEADERS headers.update({'Authorization': 'bearer {}'.format(data['drmToken'])}) item = plugin.Item( path = data['path'], inputstream = inputstream.Widevine(license_key=WIDEVINE_URL), headers = headers, ) if media_type == MEDIA_CHANNEL: item.inputstream.properties['manifest_update_parameter'] = 'full' return item
def play(id, start_from=0, play_type=PLAY_FROM_LIVE, **kwargs): asset = api.stream(id) start_from = int(start_from) play_type = int(play_type) is_live = kwargs.get(ROUTE_LIVE_TAG) == ROUTE_LIVE_SUFFIX streams = [asset['recommendedStream']] streams.extend(asset['alternativeStreams']) streams = [s for s in streams if s['mediaFormat'] in SUPPORTED_FORMATS] if not streams: raise PluginError(_.NO_STREAM) prefer_cdn = settings.getEnum('prefer_cdn', AVAILABLE_CDNS) if prefer_cdn == CDN_AUTO: try: prefer_cdn = api.use_cdn(is_live)['useCDN'] except Exception as e: log.debug('Failed to get preferred cdn') prefer_cdn = None providers = [prefer_cdn] providers.extend([s['provider'] for s in streams]) streams = sorted(streams, key=lambda k: (providers.index(k['provider']), SUPPORTED_FORMATS.index(k['mediaFormat']))) stream = streams[0] log.debug('Stream CDN: {provider} | Stream Format: {mediaFormat}'.format( **stream)) item = plugin.Item( path=stream['manifest']['uri'], art=False, headers=HEADERS, ) item.headers.update( {'authorization': 'Bearer {}'.format(userdata.get('access_token'))}) if is_live and (play_type == PLAY_FROM_LIVE or (play_type == PLAY_FROM_ASK and gui.yes_no(_.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START))): play_type = PLAY_FROM_LIVE start_from = 0 ## Cloudfront streams start from correct position if stream['provider'] == CDN_CLOUDFRONT and start_from: start_from = 1 if stream['mediaFormat'] == FORMAT_DASH: item.inputstream = inputstream.MPD() elif stream['mediaFormat'] == FORMAT_HLS_TS: force = (is_live and play_type == PLAY_FROM_LIVE and asset['assetType'] != 'live-linear') item.inputstream = inputstream.HLS(force=force, live=is_live) if force and not item.inputstream.check(): raise PluginError(_.HLS_REQUIRED) elif stream['mediaFormat'] == FORMAT_HLS_FMP4: item.inputstream = inputstream.HLS(force=True, live=is_live) if not item.inputstream.check(): raise PluginError(_.HLS_REQUIRED) elif stream['mediaFormat'] in (FORMAT_DRM_DASH, FORMAT_DRM_DASH_HEVC): item.inputstream = inputstream.Widevine(license_key=LICENSE_URL, ) if start_from and not kwargs[ROUTE_RESUME_TAG]: item.properties['ResumeTime'] = start_from item.properties['TotalTime'] = start_from return item
def play(slug, skip_intro=None, **kwargs): data, content = api.play(slug) headers = { 'Authorization': 'Bearer {}'.format(userdata.get('access_token')), } item = plugin.Item( path=data['url'], inputstream=inputstream.MPD(), headers=headers, ) if 'drm' in data: item.inputstream = inputstream.Widevine( license_key=data['drm']['licenseUrl']) item.proxy_data['manifest_middleware'] = plugin.url_for(mpd_request) if settings.getBool('wv_secure'): item.inputstream.properties[ 'license_flags'] = 'force_secure_decoder' # resume_from = None # if kwargs[ROUTE_RESUME_TAG]: # pass # if settings.getBool('disney_sync', False): # continue_watching = api.continue_watching() # resume_from = continue_watching.get(video['contentId'], 0) # item.properties['ForceResume'] = True # elif (int(skip_intro) if skip_intro is not None else settings.getBool('skip_intros', False)): # resume_from = _get_milestone(data.get('annotations'), 'SKIP', default=0) # if resume_from is not None: # item.properties['ResumeTime'] = resume_from # item.properties['TotalTime'] = resume_from item.play_next = {} if ':episode' in slug: item.update( label=content['titles']['full'], art={ 'thumb': _image(content['images'].get('tileburnedin')), 'fanart': _image(content['images'].get('tile'), size='1920x1080') }, info={ 'plot': content['summaries']['short'], 'duration': content['duration'], 'tvshowtitle': content['seriesTitles']['full'], 'season': content.get('seasonNumber', 1), 'episode': content.get('numberInSeason', content.get('numberInSeries', 1)), 'mediatype': 'episode' }, ) if settings.getBool('play_next_episode', True): item.play_next['next_file'] = _get_play_path(content.get('next')) elif ':feature' in slug: item.update( label=content['titles']['full'], art={ 'thumb': _image(content['images'].get('tileburnedin')), 'fanart': _image(content['images'].get('tile'), size='1920x1080') }, info={ 'plot': content['summaries']['short'], 'duration': content['duration'], 'year': content['releaseYear'], 'mediatype': 'movie', }, ) if settings.getBool('play_next_movie', False): for slug in content.get('similars', []): if ':feature' in slug: item.play_next[ 'next_file'] = 'urn:hbo:feature:' + slug.split(':')[3] break for row in data.get('textTracks', []): item.subtitles.append([row['url'], row['language']]) return item
def play(id, start_from=0, play_type=PLAY_FROM_LIVE, **kwargs): asset = api.stream(id) start_from = int(start_from) play_type = int(play_type) is_live = kwargs.get(ROUTE_LIVE_TAG) == ROUTE_LIVE_SUFFIX streams = [asset['recommendedStream']] streams.extend(asset['alternativeStreams']) streams = [s for s in streams if s['mediaFormat'] in SUPPORTED_FORMATS] if not streams: raise PluginError(_.NO_STREAM) providers = SUPPORTED_PROVIDERS[:] providers.extend([s['provider'] for s in streams]) streams = sorted(streams, key=lambda k: (providers.index(k['provider']), SUPPORTED_FORMATS.index(k['mediaFormat']))) stream = streams[0] log.debug('Stream CDN: {provider} | Stream Format: {mediaFormat}'.format( **stream)) item = plugin.Item( path=stream['manifest']['uri'], art=False, headers=HEADERS, use_proxy=True, #required to support dolby 5.1 and license requests ) if is_live and (play_type == PLAY_FROM_LIVE or (play_type == PLAY_FROM_ASK and gui.yes_no(_.PLAY_FROM, yeslabel=_.PLAY_FROM_LIVE, nolabel=_.PLAY_FROM_START))): play_type = PLAY_FROM_LIVE start_from = 0 if stream['mediaFormat'] == FORMAT_DASH: item.inputstream = inputstream.MPD() elif stream['mediaFormat'] == FORMAT_HLS_TS: force = (is_live and play_type == PLAY_FROM_LIVE) item.inputstream = inputstream.HLS(force=force, live=is_live) if force and not item.inputstream.check(): raise PluginError(_.HLS_REQUIRED) elif stream['mediaFormat'] == FORMAT_HLS_FMP4: item.inputstream = inputstream.HLS(force=True, live=is_live) if not item.inputstream.check(): raise PluginError(_.HLS_REQUIRED) elif stream['mediaFormat'] in (FORMAT_DRM_DASH, FORMAT_DRM_DASH_HEVC): item.inputstream = inputstream.Widevine( license_key=plugin.url_for(license_request)) if start_from: item.properties['ResumeTime'] = start_from item.properties['TotalTime'] = start_from return item
def play(content_id=None, family_id=None, skip_intro=None, **kwargs): if KODI_VERSION > 18: ver_required = '2.6.0' else: ver_required = '2.4.5' ia = inputstream.Widevine( license_key=api.get_config()['services']['drm']['client']['endpoints'] ['widevineLicense']['href'], manifest_type='hls', mimetype='application/vnd.apple.mpegurl', ) if not ia.check() or not inputstream.require_version(ver_required): gui.ok( _(_.IA_VER_ERROR, kodi_ver=KODI_VERSION, ver_required=ver_required)) if family_id: data = api.video_bundle(family_id) if not data.get('video'): raise PluginError(_.NO_VIDEO_FOUND) video = data['video'] else: data = api.videos(content_id) if not data.get('videos'): raise PluginError(_.NO_VIDEO_FOUND) video = data['videos'][0] playback_url = video['mediaMetadata']['playbackUrls'][0]['href'] playback_data = api.playback_data(playback_url) media_stream = playback_data['stream']['complete'] original_language = video.get('originalLanguage') or 'en' headers = api.session.headers ia.properties['original_audio_language'] = original_language ## Allow fullres worldwide ## media_stream = media_stream.replace('/mickey/ps01/', '/ps01/') ############## item = _parse_video(video) item.update( path=media_stream, inputstream=ia, headers=headers, proxy_data={ 'default_language': original_language, 'original_language': original_language }, ) if kwargs[ROUTE_RESUME_TAG] and settings.getBool('disney_sync', False): continue_watching = api.continue_watching() item.resume_from = continue_watching.get(video['contentId'], 0) item.force_resume = True elif (int(skip_intro) if skip_intro is not None else settings.getBool( 'skip_intros', False)): item.resume_from = _get_milestone( video.get('milestones'), 'intro_end', default=0) / 1000 item.play_next = {} if settings.getBool('skip_credits', False): next_start = _get_milestone( video.get('milestones'), 'up_next', default=0) / 1000 item.play_next['time'] = next_start if video['programType'] == 'episode' and settings.getBool( 'play_next_episode', True): data = api.up_next(video['contentId']) for row in data.get('items', []): if row['type'] == 'DmcVideo' and row[ 'programType'] == 'episode' and row[ 'encodedSeriesId'] == video['encodedSeriesId']: item.play_next['next_file'] = _get_play_path(row['contentId']) break elif video['programType'] != 'episode' and settings.getBool( 'play_next_movie', False): data = api.up_next(video['contentId']) for row in data.get('items', []): if row['type'] == 'DmcVideo' and row['programType'] != 'episode': item.play_next['next_file'] = _get_play_path(row['contentId']) break if settings.getBool('wv_secure', False): item.inputstream.properties['license_flags'] = 'force_secure_decoder' if settings.getBool('disney_sync', False): telemetry = playback_data['tracking']['telemetry'] item.callback = { 'type': 'interval', 'interval': 20, 'callback': plugin.url_for(callback, media_id=telemetry['mediaId'], fguid=telemetry['fguid']), } return item
def play(asset_id, **kwargs): use_ia_hls = settings.getBool('use_ia_hls') stream_data = api.get_stream_data(asset_id) token = userdata.get('access_token') play_item = plugin.Item( art=False, headers={'Authorization': 'Bearer {}'.format(token)}, cookies={ 'access_token': token, 'client_id': CLIENT_ID }, ) is_drm = stream_data.get('course_is_drmed', False) hls_url = stream_data.get('hls_url') if hls_url and not is_drm: play_item.path = hls_url play_item.inputstream = inputstream.HLS(live=False) return play_item stream_urls = stream_data.get('stream_urls') or {} streams = stream_urls.get('Video') or stream_urls.get('Audio') or [] CODECS = { 'libx264': 'H.264', 'libx265': 'H.265', } urls = [] qualities = [] for item in streams: if item['type'] != 'application/x-mpegURL': data = stream_data['data']['outputs'][item['label']] if data.get('migrated_from_non_labeled_conversions'): bandwidth, resolution = BANDWIDTH_MAP.get(int(item['label'])) codecs, fps = '', '' else: fps = _(_.QUALITY_FPS, fps=float(data['frame_rate'])) resolution = '{}x{}'.format(data['width'], data['height']) bandwidth = data[ 'video_bitrate_in_kbps'] * 1000 #(or total_bitrate_in_kbps) codecs = CODECS.get(data.get('video_codec'), '') urls.append([bandwidth, item['file']]) qualities.append([ bandwidth, _(_.QUALITY_BITRATE, bandwidth=float(bandwidth) / 1000000, resolution=resolution, fps=fps, codecs=codecs) ]) if not urls: for row in stream_data.get('media_sources') or []: if row['type'] == 'application/x-mpegURL' and 'encrypted-files' not in row[ 'src']: urls.append([row['src'], inputstream.HLS(live=False)]) if row['type'] == 'application/dash+xml': play_item.path = row['src'] if is_drm: token = stream_data['media_license_token'] ia = inputstream.Widevine(license_key=WV_URL.format( token=token)) else: ia = inputstream.MPD() urls.append([row['src'], ia]) if urls: urls = sorted(urls, key=lambda x: isinstance(x[1], inputstream.Widevine)) play_item.path = urls[0][0] play_item.inputstream = urls[0][1] if isinstance(play_item.inputstream, inputstream.Widevine): system, arch = get_system_arch() if system == 'Windows' or (system == 'Linux' and arch == 'armv7'): gui.ok(_.VMP_WARNING) return play_item if not urls: raise plugin.Error(_.NO_STREAM_ERROR) quality = kwargs.get(QUALITY_TAG) if quality is None: quality = settings.getEnum('default_quality', QUALITY_TYPES, default=QUALITY_ASK) else: quality = int(quality) urls = sorted(urls, key=lambda s: s[0], reverse=True) qualities = sorted(qualities, key=lambda s: s[0], reverse=True) if quality == QUALITY_CUSTOM: quality = int(settings.getFloat('max_bandwidth') * 1000000) elif quality == QUALITY_ASK: quality = select_quality(qualities) if quality == QUALITY_BEST: quality = qualities[0][0] elif quality == QUALITY_LOWEST: quality = qualities[-1][0] play_item.path = urls[-1][1] for item in urls: if item[0] <= quality: play_item.path = item[1] break return play_item