def update_json_video(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: %s', item.name) data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=self.httpHeaders) json_data = JsonHelper(data) streams = json_data.get_value("formats") if not streams: return item qualities = {"720p": 1600, "480p": 1200, "360p": 500, "other": 0} # , "http-hls": 1500, "3gp-mob01": 300, "flv-web01": 500} part = item.create_new_empty_media_part() urls = [] for stream in streams: url = stream["url"].values()[-1] if url in urls: # duplicate url, ignore continue urls.append(url) # actually process the url if not url.endswith(".m3u8"): part.append_media_stream( url=url, bitrate=qualities.get(stream.get("name", "other"), 0) ) item.complete = True # elif AddonSettings.use_adaptive_stream_add_on(): # content_type, url = UriHandler.header(url, self.proxy) # stream = part.append_media_stream(url, 0) # M3u8.SetInputStreamAddonInput(stream, self.proxy) # item.complete = True else: content_type, url = UriHandler.header(url, self.proxy) for s, b in M3u8.get_streams_from_m3u8(url, self.proxy): item.complete = True part.append_media_stream(s, b) 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("Updating a (Live) video item") content, url = UriHandler.header(item.url, proxy=self.proxy) part = item.create_new_empty_media_part() if AddonSettings.use_adaptive_stream_add_on(): part = item.create_new_empty_media_part() stream = part.append_media_stream(url, 0) M3u8.set_input_stream_addon_input(stream, self.proxy, item.HttpHeaders) item.complete = True else: for s, b in M3u8.get_streams_from_m3u8(url, self.proxy, append_query_string=True): item.complete = True part.append_media_stream(s, b) 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) # we need to fetch the actual url as it might differ for single video items data, secure_url = UriHandler.header(item.url, proxy=self.proxy) # Get the MZID secure_url = secure_url.rstrip("/") secure_url = "%s.mssecurevideo.json" % (secure_url, ) data = UriHandler.open(secure_url, proxy=self.proxy, additional_headers=item.HttpHeaders) secure_data = JsonHelper(data, logger=Logger.instance()) mzid = secure_data.get_value( list(secure_data.json.keys())[0], "videoid") return self.update_video_for_mzid(item, mzid)
def update_video_item(self, item): # NOSONAR """ 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) # we need to fetch the actual url as it might differ for single video items data, secure_url = UriHandler.header(item.url, proxy=self.proxy) # Get the MZID secure_url = secure_url.rstrip("/") secure_url = "%s.mssecurevideo.json" % (secure_url, ) data = UriHandler.open(secure_url, proxy=self.proxy, additional_headers=item.HttpHeaders) secure_data = JsonHelper(data, logger=Logger.instance()) mzid = secure_data.get_value( list(secure_data.json.keys())[0], "videoid") # region New URL retrieval with DRM protection # 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=vrtvideo"\ .format(HtmlEntityHelper.url_encode(mzid), HtmlEntityHelper.url_encode(token)) asset_data = UriHandler.open(asset_url, proxy=self.proxy, 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) part = item.create_new_empty_media_part() srt = None # see if we prefer hls over dash hls_prio = 2 if self._get_setting("hls_over_dash", False) 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, 0) M3u8.set_input_stream_addon_input(stream, self.proxy) 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, self.proxy) else: m3u8_data = UriHandler.open(video_url, self.proxy) for s, b, a in M3u8.get_streams_from_m3u8( video_url, self.proxy, 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, proxy=self.proxy) if not srt: 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, self.proxy) 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, self.proxy, license_key=encryption_key) if video_type.startswith("hls") and srt is None: srt = M3u8.get_subtitle(video_url, proxy=self.proxy) if srt: srt = srt.replace(".m3u8", ".vtt") part.Subtitle = SubtitleHelper.download_subtitle( srt, format="webvtt") item.complete = True # endregion return item
def update_json_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 """ headers = {"accept": "application/vnd.sbs.ovp+json; version=2.0"} data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=headers) if UriHandler.instance().status.code == 404: Logger.warning("No normal stream found. Trying newer method") new_url = item.url.replace("https://embed.kijk.nl/api/", "https://embed.kijk.nl/") item.url = new_url[:new_url.index("?")] return self.__update_embedded_video(item) json = JsonHelper(data) embed_url = json.get_value("metadata", "embedURL") if embed_url: Logger.warning( "Embed URL found. Using that to determine the streams.") item.url = embed_url try: return self.__update_embedded_video(item) except: Logger.warning("Failed to update embedded item:", exc_info=True) use_adaptive_with_encryption = AddonSettings.use_adaptive_stream_add_on( with_encryption=True, channel=self) mpd_info = json.get_value("entitlements", "play") # is there MPD information in the API response? if mpd_info is not None: return self.__update_video_from_mpd(item, mpd_info, use_adaptive_with_encryption) # Try the plain M3u8 streams part = item.create_new_empty_media_part() m3u8_url = json.get_value("playlist") use_adaptive = AddonSettings.use_adaptive_stream_add_on(channel=self) # with the Accept: application/vnd.sbs.ovp+json; version=2.0 header, the m3u8 streams that # are brightcove based have an url paramter instead of an empty m3u8 file Logger.debug("Trying standard M3u8 streams.") if m3u8_url != "https://embed.kijk.nl/api/playlist/.m3u8" \ and "hostingervice=brightcove" not in m3u8_url: for s, b in M3u8.get_streams_from_m3u8(m3u8_url, self.proxy, append_query_string=True): if "_enc_" in s: continue if use_adaptive: # we have at least 1 none encrypted streams Logger.info("Using HLS InputStreamAddon") strm = part.append_media_stream(m3u8_url, 0) M3u8.set_input_stream_addon_input(strm, proxy=self.proxy) item.complete = True return item part.append_media_stream(s, b) item.complete = True return item Logger.warning("No M3u8 data found. Falling back to BrightCove") video_id = json.get_value("vpakey") # videoId = json.get_value("videoId") -> Not all items have a videoId mpd_manifest_url = "https://embed.kijk.nl/video/%s?width=868&height=491" % ( video_id, ) referer = "https://embed.kijk.nl/video/%s" % (video_id, ) data = UriHandler.open(mpd_manifest_url, proxy=self.proxy, referer=referer) # First try to find an M3u8 m3u8_urls = Regexer.do_regex('https:[^"]+.m3u8', data) for m3u8_url in m3u8_urls: m3u8_url = m3u8_url.replace("\\", "") # We need the actual URI to make this work, so fetch it. m3u8_url = UriHandler.header(m3u8_url, proxy=self.proxy)[-1] Logger.debug("Found direct M3u8 in brightcove data.") if use_adaptive: # we have at least 1 none encrypted streams Logger.info("Using HLS InputStreamAddon") strm = part.append_media_stream(m3u8_url, 0) M3u8.set_input_stream_addon_input(strm, proxy=self.proxy) item.complete = True return item for s, b in M3u8.get_streams_from_m3u8(m3u8_url, self.proxy, append_query_string=True): item.complete = True part.append_media_stream(s, b) return item return self.__update_video_from_brightcove( item, data, use_adaptive_with_encryption)