def __update_video_from_mpd(self, item, mpd_info, use_adaptive_with_encryption): """ Updates an existing MediaItem with more data based on an MPD stream. :param dict[str,str] mpd_info: Stream info retrieved from the stream json. :param bool use_adaptive_with_encryption: Do we use the Adaptive InputStream add-on? :param MediaItem item: The original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug("Updating streams using BrightCove data.") part = item.create_new_empty_media_part() mpd_manifest_url = "https:{0}".format(mpd_info["mediaLocator"]) mpd_data = UriHandler.open(mpd_manifest_url, proxy=self.proxy) subtitles = Regexer.do_regex(r'<BaseURL>([^<]+\.vtt)</BaseURL>', mpd_data) if subtitles: Logger.debug("Found subtitle: %s", subtitles[0]) subtitle = SubtitleHelper.download_subtitle(subtitles[0], proxy=self.proxy, format="webvtt") part.Subtitle = subtitle if use_adaptive_with_encryption: # We can use the adaptive add-on with encryption Logger.info("Using MPD InputStreamAddon") license_url = Regexer.do_regex('licenseUrl="([^"]+)"', mpd_data)[0] token = "Bearer {0}".format(mpd_info["playToken"]) key_headers = {"Authorization": token} license_key = Mpd.get_license_key(license_url, key_headers=key_headers) stream = part.append_media_stream(mpd_manifest_url, 0) Mpd.set_input_stream_addon_input(stream, self.proxy, license_key=license_key) item.complete = True else: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName) # Get the authentication part right. token = self.__authenticator.get_authentication_token() headers = {"Authorization": "Bearer {}".format(token)} video_data = UriHandler.open(item.url, additional_headers=headers) video_json = JsonHelper(video_data) license_url = video_json.get_value("licenseUrl") video_manifest = video_json.get_value("manifest") token = video_json.get_value("token") key_headers = { "Authorization": "Bearer {0}".format(token), "content-type": "application/octet-stream" } part = item.create_new_empty_media_part() stream = part.append_media_stream(video_manifest, 0) from resources.lib.streams.mpd import Mpd license_key = Mpd.get_license_key(license_url, key_headers=key_headers, key_type="A") Mpd.set_input_stream_addon_input(stream, license_key=license_key) item.complete = True return item
def __update_dash_video(self, item, stream_info): """ :param MediaItem item: The item that was updated :param JsonHelper stream_info: The stream info """ if not AddonSettings.use_adaptive_stream_add_on(with_encryption=True): XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item playback_item = stream_info.get_value("playbackItem") stream_url = playback_item["manifestUrl"] part = item.create_new_empty_media_part() stream = part.append_media_stream(stream_url, 0) license_info = playback_item.get("license", None) if license_info is not None: license_key_token = license_info["token"] auth_token = license_info["castlabsToken"] header = { "x-dt-auth-token": auth_token, "content-type": "application/octstream" } license_url = license_info["castlabsServer"] license_key = Mpd.get_license_key(license_url, key_value=license_key_token, key_headers=header) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy, license_key=license_key) item.isDrmProtected = False else: Mpd.set_input_stream_addon_input(stream, proxy=self.proxy) item.complete = True return item
def update_graphql_item(self, item): """ Updates video items that are encrypted. This could be the default for Krypton! :param MediaItem item: The item to update. :return: An updated item. :rtype: MediaItem """ sources = item.metaData["sources"] part = item.create_new_empty_media_part() hls_over_dash = self._get_setting("hls_over_dash") == "true" for src in sources: stream_type = src["type"] url = src["file"] drm = src["drm"] if "?filter=" in url: url = url[:url.index("?filter=")] if stream_type == "dash" and not drm: bitrate = 0 if hls_over_dash else 2 stream = part.append_media_stream(url, bitrate) item.complete = Mpd.set_input_stream_addon_input( stream, self.proxy) elif stream_type == "dash" and drm and "widevine" in drm: bitrate = 0 if hls_over_dash else 1 stream = part.append_media_stream(url, bitrate) # fetch the authentication token: # url = self.__get_api_persisted_url("drmToken", "634c83ae7588a877e2bb67d078dda618cfcfc70ac073aef5e134e622686c0bb6", variables={}) url = self.__get_api_query_url("drmToken", "{token,expiration}") token_data = UriHandler.open(url, proxy=self.proxy, no_cache=True) token_json = JsonHelper(token_data) token = token_json.get_value("data", "drmToken", "token") # we need to POST to this url using this wrapper: key_url = drm["widevine"]["url"] release_pid = drm["widevine"]["releasePid"] encryption_json = '{{"getRawWidevineLicense":{{"releasePid":"{}","widevineChallenge":"b{{SSM}}"}}}}'.format( release_pid) encryption_key = Mpd.get_license_key( key_url=key_url, key_type="b", key_value=encryption_json, key_headers={ "Content-Type": "application/json", "authorization": "Basic {}".format(token) }) Mpd.set_input_stream_addon_input(stream, license_key=encryption_key) item.complete = True elif stream_type == "m3u8" and not drm: bitrate = 2 if hls_over_dash else 0 item.complete = M3u8.update_part_with_m3u8_streams( part, url, proxy=self.proxy, channel=self, bitrate=bitrate) else: Logger.debug("Found incompatible stream: %s", src) subtitle = None for sub in item.metaData.get("subtitles", []): subtitle = sub["file"] part.Subtitle = subtitle # If we are here, we can playback. item.isDrmProtected = False return item
def __update_embedded_video(self, item): """ Updates video items that are encrypted. This could be the default for Krypton! :param MediaItem item: The item to update. :return: An updated item. :rtype: MediaItem """ data = UriHandler.open(item.url, proxy=self.proxy) if UriHandler.instance().status.code == 404: title, message = Regexer.do_regex( r'<h1>([^<]+)</h1>\W+<p>([^<]+)<', data)[0] XbmcWrapper.show_dialog(title, message) return item start_needle = "var playerConfig =" start_data = data.index(start_needle) + len(start_needle) end_data = data.index("var talpaPlayer") data = data[start_data:end_data].strip().rstrip(";") json = JsonHelper(data) has_drm_only = True adaptive_available = AddonSettings.use_adaptive_stream_add_on( with_encryption=False, channel=self) adaptive_available_encrypted = AddonSettings.use_adaptive_stream_add_on( with_encryption=True, channel=self) for play_list_entry in json.get_value("playlist"): part = item.create_new_empty_media_part() for source in play_list_entry["sources"]: stream_type = source["type"] stream_url = source["file"] stream_drm = source.get("drm") if not stream_drm: has_drm_only = False if stream_type == "m3u8": Logger.debug("Found non-encrypted M3u8 stream: %s", stream_url) M3u8.update_part_with_m3u8_streams(part, stream_url, proxy=self.proxy, channel=self) item.complete = True elif stream_type == "dash" and adaptive_available: Logger.debug("Found non-encrypted Dash stream: %s", stream_url) stream = part.append_media_stream(stream_url, 1) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy) item.complete = True else: Logger.debug("Unknown stream source: %s", source) else: compatible_drm = "widevine" if compatible_drm not in stream_drm or stream_type != "dash": Logger.debug("Found encrypted %s stream: %s", stream_type, stream_url) continue Logger.debug("Found Widevine encrypted Dash stream: %s", stream_url) license_url = stream_drm[compatible_drm]["url"] pid = stream_drm[compatible_drm]["releasePid"] encryption_json = '{"getRawWidevineLicense":' \ '{"releasePid":"%s", "widevineChallenge":"b{SSM}"}' \ '}' % (pid,) headers = { "Content-Type": "application/json", "Origin": "https://embed.kijk.nl", "Referer": stream_url } encryption_key = Mpd.get_license_key( license_url, key_type=None, key_value=encryption_json, key_headers=headers) stream = part.append_media_stream(stream_url, 0) Mpd.set_input_stream_addon_input( stream, proxy=self.proxy, license_key=encryption_key) item.complete = True subs = [ s['file'] for s in play_list_entry.get("tracks", []) if s.get('kind') == "captions" ] if subs: subtitle = SubtitleHelper.download_subtitle(subs[0], format="webvtt") part.Subtitle = subtitle if has_drm_only and not adaptive_available_encrypted: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName) data = UriHandler.open(item.url, proxy=self.proxy) json_data, _ = self.extract_json(data) video_id = json_data.get_value("versions", 0, "id") stream_data_url = "http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/iptv-all/vpid/{}".format(video_id) # this URL is one from the webbrowser but requires a security part. So NOT: # streamDataUrl = "http://open.live.bbc.co.uk/mediaselector/5/select/version # /2.0/mediaset/pc/vpid/%s" % (vid,) # # but: # streamDataUrl = "http://open.live.bbc.co.uk/mediaselector/5/select/version # /2.0/mediaset/pc/vpid/%s/atk/2214e42b5729dcdd012dfb61a3054d39309ccd31/asn/1/ # And I don't know where that one comes from part = item.create_new_empty_media_part() stream_data = UriHandler.open(stream_data_url, proxy=self.proxy) # Reroute for debugging # from debug.router import Router # streamData = Router.get_via("uk", streamDataUrl, self.proxy) connection_datas = Regexer.do_regex( r'<media bitrate="(\d+)"[^>]+>\W*' r'(<connection[^>]+>\W*)' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?' r'(<connection[^>]+>\W*)?</media>', stream_data) for connection_data in connection_datas: # first the bitrate bitrate = int(connection_data[0]) Logger.trace("Found Media: %s", connection_data) # go through the available connections for connection in connection_data[1:]: if not connection: continue connection_xml = XmlHelper(connection) stream_bitrate = bitrate Logger.trace("Analyzing Connection: %s", connection) supplier = connection_xml.get_tag_attribute("connection", {"supplier": None}) protocol = connection_xml.get_tag_attribute("connection", {"protocol": None}) transfer_format = connection_xml.get_tag_attribute("connection", {"transferFormat": None}) Logger.debug("Found connection information:\n" "Protocol: %s\n" "TransferFormat: %s\n" "Supplier: %s\n" "Bitrate: %s", protocol, transfer_format, supplier, bitrate) if protocol.startswith("http"): if transfer_format != "hls": # and transfer_format != "dash": Logger.debug("Ignoring TransferFormat: %s", transfer_format) continue if "lime" in supplier or "mf_akamai_uk" in supplier: # Prefer others stream_bitrate -= 1 # Logger.debug("Ignoring Supplier: %s", supplier) # continue url = connection_xml.get_tag_attribute("connection", {"href": None}) elif protocol.startswith("rtmp"): Logger.warning("Ignoring RTMP for now") continue else: Logger.warning("Unknown protocol: %s", protocol) continue if transfer_format == "hls": item.complete = M3u8.update_part_with_m3u8_streams(part, url, proxy=self.proxy, bitrate=stream_bitrate) elif transfer_format == "dash": strm = part.append_media_stream(url, bitrate) Mpd.set_input_stream_addon_input(strm, self.proxy) # get the subtitle subtitles = Regexer.do_regex( '<connection href="(http://www.bbc.co.uk/iplayer/subtitles/[^"]+/)([^/]+.xml)"', stream_data) if len(subtitles) > 0: subtitle = subtitles[0] subtitle_url = "%s%s" % (subtitle[0], subtitle[1]) part.Subtitle = subtitlehelper.SubtitleHelper.download_subtitle( subtitle_url, subtitle[1], "ttml", proxy=self.proxy) item.complete = True Logger.trace('finishing update_video_item: %s.', item) return item
def add_mpd_stream_from_npo(url, episode_id, part, proxy=None, headers=None, live=False): """ Extracts the Dash streams for the given url or episode id :param str|None url: The url to download :param str episode_id: The NPO episode ID :param dict headers: Possible HTTP Headers :param ProxyInfo proxy: The proxy to use for opening :param bool live: Is this a live stream? :rtype: str|None :return: An error message if an error occurred. for s, b, p in NpoStream.GetMpdStreamFromNpo(None, episodeId, proxy=self.proxy): item.complete = True stream = part.append_media_stream(s, b) for k, v in p.iteritems(): stream.add_property(k, v) """ if url: Logger.info("Determining MPD streams for url: %s", url) episode_id = url.split("/")[-1] elif episode_id: Logger.info("Determining MPD streams for VideoId: %s", episode_id) else: Logger.error("No url or streamId specified!") return None token_headers = {"x-requested-with": "XMLHttpRequest"} token_headers.update(headers or {}) data = UriHandler.open("https://www.npostart.nl/api/token", proxy=proxy, additional_headers=token_headers) token = JsonHelper(data).get_value("token") post_data = {"_token": token} data = UriHandler.open( "https://www.npostart.nl/player/{0}".format(episode_id), proxy=proxy, additional_headers=headers, data=post_data) Logger.trace("Episode Data: %s", data) token = JsonHelper(data).get_value("token") Logger.debug("Found token %s", token) stream_data_url = "https://start-player.npo.nl/video/{0}/streams?" \ "profile=dash-widevine" \ "&quality=npo" \ "&tokenId={1}" \ "&streamType=broadcast" \ "&mobile=0" \ "&isChromecast=0".format(episode_id, token) data = UriHandler.open(stream_data_url, proxy=proxy, additional_headers=headers) Logger.trace("Stream Data: %s", data) stream_data = JsonHelper(data) error = stream_data.get_value("html") if error: error = Regexer.do_regex(r'message">\s*<p>([^<]+)', error) if bool(error): return error[0] return "Unspecified error retrieving streams" stream_url = stream_data.get_value("stream", "src") if stream_url is None: return None # Encryption? license_url = stream_data.get_value("stream", "keySystemOptions", 0, "options", "licenseUrl") if license_url: Logger.info("Using encrypted Dash for NPO") license_headers = stream_data.get_value("stream", "keySystemOptions", 0, "options", "httpRequestHeaders") if license_headers: license_headers = '&'.join( ["{}={}".format(k, v) for k, v in license_headers.items()]) license_type = stream_data.get_value("stream", "keySystemOptions", 0, "name") license_key = "{0}|{1}|R{{SSM}}|".format(license_url, license_headers or "") else: Logger.info("Using non-encrypted Dash for NPO") license_type = None license_key = None # Actually set the stream stream = part.append_media_stream(stream_url, 0) # M3u8.set_input_stream_addon_input(stream, proxy, headers) Mpd.set_input_stream_addon_input( stream, proxy, headers, license_key=license_key, license_type=license_type, manifest_update=None if not live else "full") return None
def get_stream_info(self, item, mzid, live=False, hls_over_dash=False): # NOSONAR """ Updates an item with Vualto stream data. :param MediaItem item: The Mediaitem to update :param str mzid: The MZ ID of the stream :param bool live: Indicator if the stream is live or not :param bool hls_over_dash: Should we prefer HLS over Dash? :return: An updated MediaItem :rtype: MediaItem """ # We need a player token token_data = UriHandler.open("https://media-services-public.vrt.be/" "vualto-video-aggregator-web/rest/external/v1/tokens", data="", additional_headers={"Content-Type": "application/json"}) token = JsonHelper(token_data).get_value("vrtPlayerToken") asset_url = "https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/" \ "external/v1/videos/{0}?vrtPlayerToken={1}&client={2}" \ .format(mzid, HtmlEntityHelper.url_encode(token), self.client_id) asset_data = UriHandler.open(asset_url, no_cache=True) asset_data = JsonHelper(asset_data) drm_key = asset_data.get_value("drm") drm_protected = drm_key is not None adaptive_available = AddonSettings.use_adaptive_stream_add_on( with_encryption=drm_protected, channel=self.channel) part = item.create_new_empty_media_part() srt = None # see if we prefer hls over dash hls_prio = 2 if hls_over_dash else 0 for target_url in asset_data.get_value("targetUrls"): video_type = target_url["type"] video_url = target_url["url"] if video_type == "hls_aes" and drm_protected and adaptive_available: # no difference in encrypted or not. Logger.debug("Found HLS AES encrypted stream and a DRM key") stream = part.append_media_stream(video_url, hls_prio) M3u8.set_input_stream_addon_input(stream) elif video_type == "hls" and not drm_protected: # no difference in encrypted or not. if adaptive_available: Logger.debug("Found standard HLS stream and without DRM protection") stream = part.append_media_stream(video_url, hls_prio) M3u8.set_input_stream_addon_input(stream) else: m3u8_data = UriHandler.open(video_url) for s, b, a in M3u8.get_streams_from_m3u8(video_url, play_list_data=m3u8_data, map_audio=True): item.complete = True if a: audio_part = a.rsplit("-", 1)[-1] audio_part = "-%s" % (audio_part,) s = s.replace(".m3u8", audio_part) part.append_media_stream(s, b) srt = M3u8.get_subtitle(video_url, play_list_data=m3u8_data) if not srt or live: # If there is not SRT don't download it. If it a live stream with subs, # don't use it as it is not supported by Kodi continue srt = srt.replace(".m3u8", ".vtt") part.Subtitle = SubtitleHelper.download_subtitle(srt, format="webvtt") elif video_type == "mpeg_dash" and adaptive_available: if not drm_protected: Logger.debug("Found standard MPD stream and without DRM protection") stream = part.append_media_stream(video_url, 1) Mpd.set_input_stream_addon_input(stream) else: stream = part.append_media_stream(video_url, 1) encryption_json = '{{"token":"{0}","drm_info":[D{{SSM}}],"kid":"{{KID}}"}}' \ .format(drm_key) encryption_key = Mpd.get_license_key( key_url="https://widevine-proxy.drm.technology/proxy", key_type="D", key_value=encryption_json, key_headers={"Content-Type": "text/plain;charset=UTF-8"} ) Mpd.set_input_stream_addon_input(stream, license_key=encryption_key) if video_type.startswith("hls") and srt is None: srt = M3u8.get_subtitle(video_url) if not srt or live: # If there is not SRT don't download it. If it a live stream with subs, # don't use it as it is not supported by Kodi continue srt = srt.replace(".m3u8", ".vtt") part.Subtitle = SubtitleHelper.download_subtitle(srt, format="webvtt") item.complete = True return item
def __update_item_from_video_references(self, item, videos, subtitles=None): # NOSONAR """ :param MediaItem item: The original MediaItem that needs updating. :param list[any] videos: Videos to add. :param dict subtitles: Subtitle information. :return: Updated MediaItem :rtype: MediaItem """ item.MediaItemParts = [] part = item.create_new_empty_media_part() if self.localIP: part.HttpHeaders.update(self.localIP) use_input_stream = AddonSettings.use_adaptive_stream_add_on( channel=self) for video in videos: video_format = video.get("format", "") if not video_format: video_format = video.get("playerType", "") video_format = video_format.lower() if ("dash" in video_format and not video_format == "dash") or "hds" in video_format: Logger.debug("Skipping video format: %s", video_format) continue Logger.debug("Found video item for format: %s", video_format) url = video['url'] if any(filter(lambda s: s.Url == url, part.MediaStreams)): Logger.debug("Skippping duplicate Stream url: %s", url) continue if video_format == "dash" and use_input_stream: stream = part.append_media_stream(video['url'], 1) Mpd.set_input_stream_addon_input(stream, self.proxy) elif "m3u8" in url: alt_index = url.find("m3u8?") if alt_index > 0: url = url[0:alt_index + 4] if "-fmp4.m3u8" in url or "-lowbw.m3u8" in url: Logger.trace("Ignoring: %s", url) continue M3u8.update_part_with_m3u8_streams(part, url, encrypted=False, proxy=self.proxy, headers=part.HttpHeaders, channel=self) elif video["url"].startswith("rtmp"): # just replace some data in the URL part.append_media_stream( self.get_verifiable_video_url(video["url"]).replace( "_definst_", "?slist="), video[1]) else: part.append_media_stream(url, 0) if subtitles: Logger.info("Found subtitles to play") for sub in subtitles: sub_format = sub["format"].lower() url = sub["url"] if sub_format == "websrt": sub_url = url # elif subFormat == "webvtt": # Logger.Info("Found M3u8 subtitle, replacing with WSRT") # start, name, index = sub[-1].rsplit("/", 2) # subUrl = "%s/%s/%s.wsrt" % (start, name, name) else: # look for more continue part.Subtitle = subtitlehelper.SubtitleHelper.download_subtitle( sub_url, format="srt", proxy=self.proxy, replace={"&": "&"}) # stop when finding one break item.complete = True return item
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName) if not AddonSettings.use_adaptive_stream_add_on(with_encryption=False): Logger.error("Cannot playback video without adaptive stream addon") return item # https://www.foxsports.nl/api/video/videodata/2945190 data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=item.HttpHeaders) video_id = Regexer.do_regex(r'data-videoid="(\d+)" ', data)[-1] data = UriHandler.open( "https://www.foxsports.nl/api/video/videodata/%s" % (video_id, ), proxy=self.proxy, additional_headers=item.HttpHeaders, no_cache=True) stream_id = Regexer.do_regex('<uri>([^>]+)</uri>', data)[-1] # POST https://d3api.foxsports.nl/api/V2/entitlement/tokenize post_data = { "Type": 1, "User": "", "VideoId": "{0}".format(video_id), "VideoSource": "{0}".format(stream_id), "VideoKind": "vod", "AssetState": "3", "PlayerType": "HTML5", "VideoSourceFormat": "DASH", "VideoSourceName": "DASH", # "VideoSourceFormat": "HLS", # "VideoSourceName": "HLS", "DRMType": "widevine", "AuthType": "Token", "ContentKeyData": "", "Other__": "playerName=HTML5-Web-vod|ae755267-8482-455b-9055-529b643ece1d|" "undefined|undefined|undefined|2945541|HTML5|web|diva.MajorVersion=4|" "diva.MinorVersion=2|diva.PatchVersion=13" } data = UriHandler.open( "https://d3api.foxsports.nl/api/V2/entitlement/tokenize", json=post_data, no_cache=True, proxy=self.proxy) stream_info = JsonHelper(data) stream_url = stream_info.get_value("ContentUrl") if not stream_url: message = "Protected stream: {0}".format( stream_info.get_value("Message")) XbmcWrapper.show_notification(None, message, notification_type=XbmcWrapper.Error, display_time=5000) license_url = stream_info.get_value("LicenseURL") part = item.create_new_empty_media_part() stream = part.append_media_stream(stream_url, 0) license_key = Mpd.get_license_key(license_url) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy, license_key=license_key) return item
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName) data = UriHandler.open(item.url, proxy=self.proxy) json = JsonHelper(data, Logger.instance()) video_data = json.get_value("video") if video_data: part = item.create_new_empty_media_part() if self.localIP: part.HttpHeaders.update(self.localIP) # Get the videos video_infos = video_data.get("videoReferences") # Similar to SVT supported_formats = { "dash": 2, "dash-avc-51": 3, "hls": 0, "hls-ts-avc-51": 1, "ios": 0 } for video_info in video_infos: video_type = video_info["playerType"] video_url = video_info['url'] if video_type not in supported_formats: Logger.debug("Ignoring %s: %s", video_type, video_url) continue if "hls" in video_type or "ios" in video_type: M3u8.update_part_with_m3u8_streams(part, video_url) elif "dash" in video_type: stream = part.append_media_stream(video_url, supported_formats[video_type]) Mpd.set_input_stream_addon_input(stream, self.proxy) else: continue # stream_info = video_info['url'] # if "manifest.f4m" in stream_info: # continue # elif "master.m3u8" in stream_info: # for s, b in M3u8.get_streams_from_m3u8(stream_info, self.proxy, headers=part.HttpHeaders): # item.complete = True # part.append_media_stream(s, b) # subtitles subtitles = video_data.get("subtitleReferences") if subtitles and subtitles[0]["url"]: Logger.trace(subtitles) sub_url = subtitles[0]["url"] file_name = "%s.srt" % (EncodingHelper.encode_md5(sub_url),) sub_data = UriHandler.open(sub_url, proxy=self.proxy) # correct the subs regex = re.compile(r"^1(\d:)", re.MULTILINE) sub_data = re.sub(regex, r"0\g<1>", sub_data) sub_data = re.sub(r"--> 1(\d):", r"--> 0\g<1>:", sub_data) local_complete_path = os.path.join(Config.cacheDir, file_name) Logger.debug("Saving subtitle to: %s", local_complete_path) with open(local_complete_path, 'w') as f: f.write(sub_data) part.Subtitle = local_complete_path item.complete = True return item