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) # noinspection PyStatementEffect """ C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -n "cp70051.edgefcs.net" -a "tv 4ondemand" -y "mp4:/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3Rh cnRfdGltZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1 NTRiY2U5ODMxMDMwYWQxZWEwNzNhZmUxNjI=" -l 2 C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -r rtmpe://cp70051.edgefcs.net/ tv4ondemand/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3RhcnRfdGlt ZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1NTRiY2U5 ODMxMDMwYWQxZWEwNzNhZmUxNjI= """ # retrieve the mediaurl data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=self.localIP) stream_info = JsonHelper(data) m3u8_url = stream_info.get_value("playbackItem", "manifestUrl") if m3u8_url is None: return item part = item.create_new_empty_media_part() if AddonSettings.use_adaptive_stream_add_on() and False: subtitle = M3u8.get_subtitle(m3u8_url, proxy=self.proxy) stream = part.append_media_stream(m3u8_url, 0) M3u8.set_input_stream_addon_input(stream, self.proxy) item.complete = True else: m3u8_data = UriHandler.open(m3u8_url, proxy=self.proxy, additional_headers=self.localIP) subtitle = M3u8.get_subtitle(m3u8_url, proxy=self.proxy, play_list_data=m3u8_data) for s, b, a in M3u8.get_streams_from_m3u8(m3u8_url, self.proxy, play_list_data=m3u8_data, map_audio=True): item.complete = True if not item.isLive and "-video" not in s: continue if a and "-audio" not in s: # remove any query parameters video_part = s.rsplit("?", 1)[0] video_part = video_part.rsplit("-", 1)[-1] video_part = "-%s" % (video_part, ) s = a.replace(".m3u8", video_part) part.append_media_stream(s, b) if subtitle: subtitle = subtitle.replace(".m3u8", ".webvtt") part.Subtitle = SubtitleHelper.download_subtitle(subtitle, format="m3u8srt", proxy=self.proxy) return item
def UpdateVideoItem(self, item): """ Accepts an item. It returns an updated item. Usually retrieves the MediaURL and the Thumb! It should return a completed item. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) # noinspection PyStatementEffect """ data-video-id="1613274" data-video-type="video" data-video-src="http://media.vrtnieuws.net/2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-title="Het journaal 1 - 25/04/13" data-video-rtmp-server="rtmp://vrt.flash.streampower.be/vrtnieuws" data-video-rtmp-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-rtmpt-server="rtmpt://vrt.flash.streampower.be/vrtnieuws" data-video-rtmpt-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-iphone-server="http://iphone.streampower.be/vrtnieuws_nogeo/_definst_" data-video-iphone-path="2013/04/135132051ONL1304255866693.urlMP4_H.264.m4v" data-video-mobile-server="rtsp://mp4.streampower.be/vrt/vrt_mobile/vrtnieuws_nogeo" data-video-mobile-path="2013/04/135132051ONL1304255866693.url3GP_MPEG4.3gp" data-video-sitestat-program="het_journaal_1_-_250413_id_1-1613274" """ # now the mediaurl is derived. First we try WMV data = UriHandler.Open(item.url, proxy=self.proxy) # descriptions = Regexer.DoRegex('<div class="longdesc"><p>([^<]+)</', data) # Logger.Trace(descriptions) # for desc in descriptions: # item.description = desc data = data.replace("\\/", "/") urls = Regexer.DoRegex(self.mediaUrlRegex, data) part = item.CreateNewEmptyMediaPart() for url in urls: Logger.Trace(url) if url[0] == "src": flv = url[1] bitrate = 750 else: flvServer = url[1] flvPath = url[2] if url[0] == "rtmp-server": flv = "%s//%s" % (flvServer, flvPath) bitrate = 750 elif url[0] == "rtmpt-server": continue #flv = "%s//%s" % (flvServer, flvPath) #flv = self.GetVerifiableVideoUrl(flv) #bitrate = 1500 elif url[0] == "iphone-server": flv = "%s/%s" % (flvServer, flvPath) if not flv.endswith("playlist.m3u8"): flv = "%s/playlist.m3u8" % (flv, ) for s, b in M3u8.GetStreamsFromM3u8(flv, self.proxy): item.complete = True part.AppendMediaStream(s, b) # no need to continue adding the streams continue elif url[0] == "mobile-server": flv = "%s/%s" % (flvServer, flvPath) bitrate = 250 else: flv = "%s/%s" % (flvServer, flvPath) bitrate = 0 part.AppendMediaStream(flv, bitrate) item.complete = True return item
def update_video_for_mzid(self, item, mzid, live=False): # NOSONAR """ Updates a video item based on the MZID :param MediaItem item: the parent item :param str mzid: the MZID """ # 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, channel=self) 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') == 'true' 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, 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 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, 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 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 # endregion 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) # noinspection PyStatementEffect """ data-video-id="1613274" data-video-type="video" data-video-src="http://media.vrtnieuws.net/2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-title="Het journaal 1 - 25/04/13" data-video-rtmp-server="rtmp://vrt.flash.streampower.be/vrtnieuws" data-video-rtmp-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-rtmpt-server="rtmpt://vrt.flash.streampower.be/vrtnieuws" data-video-rtmpt-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv" data-video-iphone-server="http://iphone.streampower.be/vrtnieuws_nogeo/_definst_" data-video-iphone-path="2013/04/135132051ONL1304255866693.urlMP4_H.264.m4v" data-video-mobile-server="rtsp://mp4.streampower.be/vrt/vrt_mobile/vrtnieuws_nogeo" data-video-mobile-path="2013/04/135132051ONL1304255866693.url3GP_MPEG4.3gp" data-video-sitestat-program="het_journaal_1_-_250413_id_1-1613274" """ # now the mediaurl is derived. First we try WMV data = UriHandler.open(item.url, proxy=self.proxy) data = data.replace("\\/", "/") urls = Regexer.do_regex(self.mediaUrlRegex, data) part = item.create_new_empty_media_part() for url in urls: Logger.trace(url) if url[0] == "src": flv = url[1] bitrate = 750 else: flv_server = url[1] flv_path = url[2] if url[0] == "rtmp-server": flv = "%s//%s" % (flv_server, flv_path) bitrate = 750 elif url[0] == "rtmpt-server": continue # Not working for now #flv = "%s//%s" % (flv_server, flv_path) #flv = self.get_verifiable_video_url(flv) #bitrate = 1500 elif url[0] == "iphone-server": flv = "%s/%s" % (flv_server, flv_path) if not flv.endswith("playlist.m3u8"): flv = "%s/playlist.m3u8" % (flv,) for s, b in M3u8.get_streams_from_m3u8(flv, self.proxy): item.complete = True part.append_media_stream(s, b) # no need to continue adding the streams continue elif url[0] == "mobile-server": flv = "%s/%s" % (flv_server, flv_path) bitrate = 250 else: flv = "%s/%s" % (flv_server, flv_path) bitrate = 0 part.append_media_stream(flv, bitrate) item.complete = True return item
def UpdateVideoItem(self, item): """ Accepts an item. It returns an updated item. Usually retrieves the MediaURL and the Thumb! It should return a completed item. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) # rtmpt://vrt.flash.streampower.be/een//2011/07/1000_110723_getipt_neefs_wiels_Website_EEN.flv # http://www.een.be/sites/een.be/modules/custom/vrt_video/player/player_4.3.swf # now the mediaurl is derived. First we try WMV data = UriHandler.Open(item.url, proxy=self.proxy) part = item.CreateNewEmptyMediaPart() if "mediazone.vrt.be" not in item.url: # Extract actual media data videoId = Regexer.DoRegex('data-video=[\'"]([^"\']+)[\'"]', data)[0] # if videoId.startswith("http"): # Logger.Info("Found direct stream. Not processing any further.") # part.AppendMediaStream(videoId, 0) # item.complete = True # return item url = "https://mediazone.vrt.be/api/v1/een/assets/%s" % (videoId, ) data = UriHandler.Open(url, proxy=self.proxy) json = JsonHelper(data) urls = json.GetValue("targetUrls") for urlInfo in urls: Logger.Trace(urlInfo) if urlInfo["type"].lower() != "hls": continue hlsUrl = urlInfo["url"] for s, b in M3u8.GetStreamsFromM3u8(hlsUrl, self.proxy): part.AppendMediaStream(s, b) # urls = Regexer.DoRegex(self.mediaUrlRegex, data) # Logger.Trace(urls) # part = item.CreateNewEmptyMediaPart() # for url in urls: # if not url[1] == "": # mediaurl = "%s//%s" % (url[0], url[1]) # the extra slash in the url causes the application name in the RTMP stream to be "een" instead of "een/2011" # else: # mediaurl = url[0] # # mediaurl = mediaurl.replace(" ", "%20") # # if "rtmp" in mediaurl: # mediaurl = self.GetVerifiableVideoUrl(mediaurl) # # In some cases the RTMPT does not work. Let's just try the RTMP first and then add the original if the RTMP version fails. # part.AppendMediaStream(mediaurl.replace("rtmpt://", "rtmp://"), 650) # elif "rtsp" in mediaurl: # part.AppendMediaStream(mediaurl, 600) # elif mediaurl.startswith("http") and "m3u8" in mediaurl: # # http://iphone.streampower.be/een_nogeo/_definst_/2013/08/1000_130830_placetobe_marjolein_Website_Een_M4V.m4v/playlist.m3u8 # mediaurl = mediaurl.rstrip() # for s, b in M3u8.GetStreamsFromM3u8(mediaurl, self.proxy): # part.AppendMediaStream(s, b) # else: # Logger.Warning("Media url was not recognised: %s", mediaurl) item.complete = True return item
def add_others(self, data): """ Performs pre-process actions for data processing. Accepts an data from the process_folder_list method, BEFORE the items are processed. Allows setting of parameters (like title etc) for the channel. Inside this method the <data> could be changed and additional items can be created. The return values should always be instantiated in at least ("", []). :param str data: The retrieve data that was loaded for the current item and URL. :return: A tuple of the data and a list of MediaItems that were generated. :rtype: tuple[str|JsonHelper,list[MediaItem]] """ Logger.info("Performing Pre-Processing") items = [] others = MediaItem( "\b.: Populair :.", "https://api.kijk.nl/v2/default/sections/popular_PopularVODs?offset=0" ) items.append(others) days = MediaItem("\b.: Deze week :.", "#lastweek") items.append(days) search = MediaItem("\b.: Zoeken :.", "searchSite") search.complete = True search.icon = self.icon search.thumb = self.noImage search.dontGroup = True search.HttpHeaders = {"X-Requested-With": "XMLHttpRequest"} items.append(search) if self.channelCode == "veronica": live = LanguageHelper.get_localized_string( LanguageHelper.LiveStreamTitleId) live_radio = MediaItem("Radio Veronica {}".format(live), "") live_radio.type = "video" live_radio.icon = self.icon live_radio.thumb = self.noImage live_radio.dontGroup = True part = live_radio.create_new_empty_media_part() live_stream = "https://talparadiohls-i.akamaihd.net/hls/live/585615/VR-Veronica-1/playlist.m3u8" if AddonSettings.use_adaptive_stream_add_on(with_encryption=False, channel=self): stream = part.append_media_stream(live_stream, 0) M3u8.set_input_stream_addon_input(stream, self.proxy) live_radio.complete = True else: for s, b in M3u8.get_streams_from_m3u8(live_stream, self.proxy): live_radio.complete = True part.append_media_stream(s, b) items.append(live_radio) Logger.debug("Pre-Processing finished") return data, items
def UpdateLiveItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated Returns: The original item with more data added to it's properties. 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. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) data = UriHandler.Open(item.url, proxy=self.proxy, additionalHeaders=item.HttpHeaders) json = JsonHelper(data) videoPlayLists = json.GetValue("Video", "Playlists", "Playlist") part = item.CreateNewEmptyMediaPart() for playList in videoPlayLists: streams = playList["url"] Logger.Trace("Found %s streams", len(streams)) for stream in streams: streamUrl = stream["text"] if ".m3u8" in streamUrl: for s, b in M3u8.GetStreamsFromM3u8(streamUrl, self.proxy): item.complete = True # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) else: Logger.Debug("Cannot use stream url: %s", streamUrl) # videoInfo = json.GetValue("content", "videoInfos") # # part = item.CreateNewEmptyMediaPart() # if "HLSurlHD" in videoInfo: # # HLSurlHD=http://srfvodhd-vh.akamaihd.net/i/vod/potzmusig/2015/03/potzmusig_20150307_184438_v_webcast_h264_,q10,q20,q30,q40,q50,q60,.mp4.csmil/master.m3u8 # for s, b in M3u8.GetStreamsFromM3u8(videoInfo["HLSurlHD"], self.proxy): # item.complete = True # # s = self.GetVerifiableVideoUrl(s) # part.AppendMediaStream(s, b) # elif "HLSurl" in videoInfo: # # HLSurl=http://srfvodhd-vh.akamaihd.net/i/vod/potzmusig/2015/03/potzmusig_20150307_184438_v_webcast_h264_,q10,q20,q30,q40,.mp4.csmil/master.m3u8 # for s, b in M3u8.GetStreamsFromM3u8(videoInfo["HLSurl"], self.proxy): # item.complete = True # # s = self.GetVerifiableVideoUrl(s) # part.AppendMediaStream(s, b) # # if "downloadLink" in videoInfo: # # downloadLink=http://podcastsource.sf.tv/nps/podcast/10vor10/2015/03/10vor10_20150304_215030_v_podcast_h264_q10.mp4 # part.AppendMediaStream(videoInfo["downloadLink"], 1000) 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) # 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 """ video_data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=self.localIP) if not video_data: return item video_data = JsonHelper(video_data) video_info = video_data.get_value("data", "attributes") part = item.create_new_empty_media_part() m3u8url = video_info["streaming"]["hls"]["url"] m3u8data = UriHandler.open(m3u8url, self.proxy) if AddonSettings.use_adaptive_stream_add_on(): stream = part.append_media_stream(m3u8url, 0) item.complete = True M3u8.set_input_stream_addon_input(stream, self.proxy) else: # user agent for all sub m3u8 and ts requests needs to be the same part.HttpHeaders[ "user-agent"] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)" for s, b, a in M3u8.get_streams_from_m3u8( m3u8url, self.proxy, append_query_string=False, map_audio=True, play_list_data=m3u8data): item.complete = True if a: audio_part = a.split("-prog_index.m3u8", 1)[0] audio_id = audio_part.rsplit("/", 1)[-1] s = s.replace("-prog_index.m3u8", "-{0}-prog_index.m3u8".format(audio_id)) part.append_media_stream(s, b) if self.language == "se": vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data, language="sv") elif self.language == "dk": vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data, language="da") else: vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data) # https://dplaynordics-vod-80.akamaized.net/dplaydni/259/0/hls/243241001/1112635959-prog_index.m3u8?version_hash=bb753129&hdnts=st=1518218118~exp=1518304518~acl=/*~hmac=bdeefe0ec880f8614e14af4d4a5ca4d3260bf2eaa8559e1eb8ba788645f2087a vtt_url = vtt_url.replace("-prog_index.m3u8", "-0.vtt") part.Subtitle = SubtitleHelper.download_subtitle(vtt_url, format='srt', proxy=self.proxy) return item
def UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated Returns: The original item with more data added to it's properties. 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. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) url = item.url if self.localIP: item.HttpHeaders.update(self.localIP) if ".m3u8" not in item.url: data = UriHandler.Open(url, proxy=self.proxy, additionalHeaders=item.HttpHeaders) json = JsonHelper(data) url = json.GetValue("mediaUrl") if url is None: Logger.Warning("Could not find mediaUrl in %s", item.url) return f4mNeedle = "/manifest.f4m" if f4mNeedle in url: Logger.Info("Found F4m stream. Converting to M3u8.") url = url[:url.index(f4mNeedle)].replace("/z/", "/i/").replace("http:", "https:") url = "%s/master.m3u8" % (url, ) # are there subs? They are added as URL parameter part = item.CreateNewEmptyMediaPart() subMatches = Regexer.DoRegex('https*%3a%2f%2.+master.m3u8', url) if subMatches: subUrl = HtmlEntityHelper.UrlDecode(subMatches[0]) Logger.Info("Item has subtitles: %s", subUrl) subTitle = SubtitleHelper.DownloadSubtitle(subUrl, format="m3u8srt", proxy=self.proxy) if subTitle: part.Subtitle = subTitle for s, b in M3u8.GetStreamsFromM3u8(url, self.proxy, headers=item.HttpHeaders): item.complete = True # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) if self.localIP: part.HttpHeaders.update(self.localIP) return item
def __update_video_from_brightcove(self, item, data, use_adaptive_with_encryption): """ Updates an existing MediaItem with more data based on an MPD stream. :param str data: Stream info retrieved from BrightCove. :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 """ part = item.create_new_empty_media_part() # Then try the new BrightCove JSON bright_cove_regex = '<video[^>]+data-video-id="(?<videoId>[^"]+)[^>]+data-account="(?<videoAccount>[^"]+)' bright_cove_data = Regexer.do_regex( Regexer.from_expresso(bright_cove_regex), data) if not bright_cove_data: Logger.warning("Error updating using BrightCove data: %s", item) return item Logger.info("Found new BrightCove JSON data") bright_cove_url = 'https://edge.api.brightcove.com/playback/v1/accounts/' \ '%(videoAccount)s/videos/%(videoId)s' % bright_cove_data[0] headers = { "Accept": "application/json;pk=BCpkADawqM3ve1c3k3HcmzaxBvD8lXCl89K7XEHiKutxZArg2c5RhwJHJANOwPwS_4o7UsC4RhIzXG8Y69mrwKCPlRkIxNgPQVY9qG78SJ1TJop4JoDDcgdsNrg" } bright_cove_data = UriHandler.open(bright_cove_url, proxy=self.proxy, additional_headers=headers) bright_cove_json = JsonHelper(bright_cove_data) streams = [ d for d in bright_cove_json.get_value("sources") if d["container"] == "M2TS" ] # Old filter # streams = filter(lambda d: d["container"] == "M2TS", bright_cove_json.get_value("sources")) if not streams: Logger.warning("Error extracting streams from BrightCove data: %s", item) return item # noinspection PyTypeChecker stream_url = streams[0]["src"] # these streams work better with the the InputStreamAddon because it removes the # "range" http header if use_adaptive_with_encryption: Logger.info("Using InputStreamAddon for playback of HLS stream") strm = part.append_media_stream(stream_url, 0) strm.add_property("inputstreamaddon", "inputstream.adaptive") strm.add_property("inputstream.adaptive.manifest_type", "hls") item.complete = True return item for s, b in M3u8.get_streams_from_m3u8(stream_url, self.proxy): item.complete = True part.append_media_stream(s, b) 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) 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_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)
def UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated Returns: The original item with more data added to it's properties. 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. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) data = UriHandler.Open(item.url, proxy=self.proxy) json = JsonHelper(data, Logger.Instance()) videoData = json.GetValue("video") if videoData: part = item.CreateNewEmptyMediaPart() spoofIp = self._GetSetting("spoof_ip", valueForNone="0.0.0.0") if spoofIp: part.HttpHeaders["X-Forwarded-For"] = spoofIp # get the videos videoUrls = videoData.get("videoReferences") for videoUrl in videoUrls: # Logger.Trace(videoUrl) streamInfo = videoUrl['url'] if "manifest.f4m" in streamInfo: continue elif "master.m3u8" in streamInfo: for s, b in M3u8.GetStreamsFromM3u8( streamInfo, self.proxy, headers=part.HttpHeaders): item.complete = True part.AppendMediaStream(s, b) #m3u8Data = UriHandler.Open(streamInfo, proxy=self.proxy) #urls = Regexer.DoRegex(self.mediaUrlRegex, m3u8Data) #Logger.Trace(urls) #for url in urls: #part.AppendMediaStream(url[1].strip(), url[0]) # subtitles subtitles = videoData.get("subtitleReferences") if subtitles: Logger.Trace(subtitles) subUrl = subtitles[0]["url"] fileName = "%s.srt" % (EncodingHelper.EncodeMD5(subUrl), ) subData = UriHandler.Open(subUrl, proxy=self.proxy) # correct the subs regex = re.compile("^1(\d:)", re.MULTILINE) subData = re.sub(regex, "0\g<1>", subData) subData = re.sub("--> 1(\d):", "--> 0\g<1>:", subData) localCompletePath = os.path.join(Config.cacheDir, fileName) Logger.Debug("Saving subtitle to: %s", localCompletePath) f = open(localCompletePath, 'w') f.write(subData) f.close() part.Subtitle = localCompletePath item.complete = True return item
def GetLiveStreamsFromNpo(url, cacheDir, proxy=None, headers=None): """ Retrieve NPO Player Live streams from a different number of stream urls. @param url: (String) The url to download @param cacheDir: (String) The cache dir where to find the 'uzg-i.js' file. @param headers: (dict) Possible HTTP Headers @param proxy: (Proxy) The proxy to use for opening Can be used like this: part = item.CreateNewEmptyMediaPart() for s, b in NpoStream.GetStreamsFromNpo(m3u8Url, self.proxy): item.complete = True # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) """ if url.startswith("http://ida.omroep.nl/aapi/"): Logger.Debug( "Already found an IDA data url '%s'. Using it to fetch the streams.", url) # we already have the m3u8 actualStreamData = UriHandler.Open(url, proxy=proxy, additionalHeaders=headers) url = NpoStream.__FetchActualStream(actualStreamData, proxy) elif url.endswith("m3u8"): Logger.Debug( "Found a stream url '%s'. Using a call to IDA to determine the actual streams.", url) hashCode = NpoStream.GetNpoToken(proxy, cacheDir) actualStreamData = UriHandler.Open( "http://ida.omroep.nl/aapi/?stream=%s&token=%s" % (url, hashCode), proxy=proxy, additionalHeaders=headers) url = NpoStream.__FetchActualStream(actualStreamData, proxy) elif url.startswith("http://e.omroep.nl/metadata/"): Logger.Debug( "Found a metadata url '%s'. Determining the actual stream url's", url) jsonData = UriHandler.Open(url, proxy=proxy) json = JsonHelper(jsonData, Logger.Instance()) streams = [] for stream in json.GetValue("streams"): if stream['type'] != "hls": continue url = stream['url'] for k, v in NpoStream.GetLiveStreamsFromNpo(url, cacheDir, proxy=proxy, headers=headers): streams.append((k, v)) return streams else: Logger.Warning("None-stream url found: %s", url) return [] return M3u8.GetStreamsFromM3u8(url, proxy=proxy)
def UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated Returns: The original item with more data added to it's properties. 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. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) # noinspection PyStatementEffect """ C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -n "cp70051.edgefcs.net" -a "tv 4ondemand" -y "mp4:/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3Rh cnRfdGltZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1 NTRiY2U5ODMxMDMwYWQxZWEwNzNhZmUxNjI=" -l 2 C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -r rtmpe://cp70051.edgefcs.net/ tv4ondemand/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3RhcnRfdGlt ZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1NTRiY2U5 ODMxMDMwYWQxZWEwNzNhZmUxNjI= """ # retrieve the mediaurl # data = UriHandler.Open(item.url, proxy=self.proxy) spoofIp = self._GetSetting("spoof_ip", "0.0.0.0") if spoofIp: data = UriHandler.Open( item.url, proxy=self.proxy, additionalHeaders={"X-Forwarded-For": spoofIp}) else: data = UriHandler.Open(item.url, proxy=self.proxy) urlRegex = "<bitrate>(\d+)</bitrate>\W+<mediaFormat>([^<]+)</mediaFormat>\W+(?:<scheme>([^<]+)</scheme>\W+<server>([^<]+)</server>\W+){0,1}<base>([^<]+)</base>\W+<url>([^<]+)</url>" # urlRegex = "<bitrate>(\d+)</bitrate>\W+<mediaFormat>([^<]+)</mediaFormat>\W+<scheme>([^<]+)</scheme>\W+<server>([^<]+)</server>\W+<base>([^<]+)</base>\W+<url>([^<]+)</url>" item.MediaItemParts = [] part = item.CreateNewEmptyMediaPart() for result in Regexer.DoRegex(urlRegex, data): Logger.Trace(result) if "smi" in result[1]: subTitleUrl = result[5] part.Subtitle = subtitlehelper.SubtitleHelper.DownloadSubtitle( subTitleUrl, proxy=self.proxy) else: if "rtmp" in result[-1]: Logger.Trace("RTMP Stream found") bitrate = result[0] # get the actual path pos = string.find(result[5], '/') path = result[5][pos:] url = "%s%s" % (result[4], path) url = self.GetVerifiableVideoUrl(url) part.AppendMediaStream(url, bitrate) elif result[-1].endswith("master.m3u8"): Logger.Trace("M3U8 Stream found") for s, b in M3u8.GetStreamsFromM3u8( result[-1], self.proxy): part.AppendMediaStream(s, b) else: Logger.Trace("Other Stream found") bitrate = result[0] url = result[5] part.AppendMediaStream(url, bitrate) 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) 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 UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated Returns: The original item with more data added to it's properties. 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. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) data = UriHandler.Open(item.url, proxy=self.proxy, additionalHeaders=item.HttpHeaders) videoId = Regexer.DoRegex('data-video="([^"]+)"', data)[-1] url = "https://mediazone.vrt.be/api/v1/canvas/assets/%s" % (videoId, ) data = UriHandler.Open(url, proxy=self.proxy, additionalHeaders=item.HttpHeaders) json = JsonHelper(data) geoLocked = str(json.GetValue("metaInfo", "allowedRegion").lower()) hideGeoLocked = AddonSettings.HideGeoLockedItemsForLocation(geoLocked) if hideGeoLocked: geoRegion = AddonSettings.HideGeoLockedItemsForLocation( geoLocked, True) Logger.Warning( "Found GEO Locked item for region '%s'. Current region is '%s'", geoLocked, geoRegion) return item part = item.CreateNewEmptyMediaPart() for video in json.GetValue("targetUrls"): videoType = video["type"].lower() url = video["url"] if videoType == "progressive_download": bitrate = 1000 elif videoType == "hls": for s, b in M3u8.GetStreamsFromM3u8(url, self.proxy): # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) continue elif videoType == "rtmp": # url=rtmp://vod.stream.vrt.be/mediazone_canvas/_definst_/mp4:2015/11/mz-ast-79a551d6-2621-4a0f-9af0-a272fb0954db-1/video_1296.mp4 url = url.replace("_definst_/mp4:", "?slist=") bitrate = 1100 else: Logger.Debug("Found unhandled stream type '%s':%s", videoType, url) continue part.AppendMediaStream(url, bitrate) item.complete = True return item
def __UpdateVideoItem(self, item, episodeId): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated episodeId : String - The episodeId, e.g.: VARA_xxxxxx Returns: The original item with more data added to it's properties. 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. """ Logger.Trace("Using Generic UpdateVideoItem method") # get the subtitle subTitleUrl = "http://e.omroep.nl/tt888/%s" % (episodeId,) subTitlePath = subtitlehelper.SubtitleHelper.DownloadSubtitle(subTitleUrl, episodeId + ".srt", format='srt', proxy=self.proxy) # we need an hash code hashCode = NpoStream.GetNpoToken(self.proxy, Config.cacheDir) item.MediaItemParts = [] part = item.CreateNewEmptyMediaPart() part.Subtitle = subTitlePath # then we fetch alternative streams locations and start with the non-adapative ones streamsUrls = [] directStreamVideos = AddonSettings.GetUzgCacheDuration() == 0 streamSource = [ "http://ida.omroep.nl/odi/?prid=%s&puboptions=h264_bb,h264_sb,h264_std&adaptive=no&part=1&token=%s" % ( episodeId, hashCode,)] if directStreamVideos: # if we stream, then we first look for adaptive streams Logger.Debug("UZG is configured to streams, so also check for the adaptive streams") streamSource.insert(0, "http://ida.omroep.nl/odi/?prid=%s&puboptions=adaptive&adaptive=yes&part=1&token=%s" % ( episodeId, hashCode,)) else: Logger.Debug("UZG is configured to download. Not going to fetch the adaptive streams") # get the actual stream locations streams: for streamSourceUrl in streamSource: streamUrlData = UriHandler.Open(streamSourceUrl, proxy=self.proxy, noCache=True) streamJson = JsonHelper(streamUrlData, logger=Logger.Instance()) for url in streamJson.GetValue('streams'): Logger.Trace("Going to look for streams in: %s", url) streamsUrls.append(url) # should we cache before playback if not directStreamVideos: part.CanStream = False # now we should now actually go and fetch urls for url in streamsUrls: data = UriHandler.Open(url, proxy=self.proxy) jsonData = JsonHelper(data, logger=Logger.Instance()) # check for errors streamData = jsonData.GetValue() if "errorstring" in streamData: Logger.Warning("Found error response: %s", streamData["errorstring"]) continue # either do m3u8 or hls if "m3u8" in url.lower(): Logger.Trace("Processing M3U8 Json: %s", url) m3u8url = jsonData.GetValue("url") if m3u8url is None: Logger.Warning("Could not find stream in: %s", m3u8url) continue Logger.Trace("Processing M3U8 Streams: %s", m3u8url) for s, b in M3u8.GetStreamsFromM3u8(m3u8url, self.proxy): item.complete = True part.AppendMediaStream(s, b) # if we found an adaptive m3u8, we take that one as it's better Logger.Info("Found M3u8 streams and using those. Stop looking further for non-adaptive ones.") break else: Logger.Trace("Processing HLS: %s", url) if "h264_bb" in url: bitrate = 500 elif "h264_sb" in url: bitrate = 220 elif "h264_std" in url: bitrate = 1000 else: bitrate = None protocol = jsonData.GetValue('protocol') if protocol: url = "%s://%s%s" % (protocol, jsonData.GetValue('server'), jsonData.GetValue('path')) part.AppendMediaStream(url, bitrate=bitrate) else: Logger.Warning("Found UZG Stream without a protocol. Probably a expired page.") if not item.HasMediaItemParts(): Logger.Warning("Apparently no streams were present in the normal places. Trying streams in metadata") # fetch the meta data to get more streams metaUrl = "http://e.omroep.nl/metadata/%s" % (episodeId,) metaData = UriHandler.Open(metaUrl, proxy=self.proxy) metaJson = JsonHelper(metaData, logger=Logger.Instance()) # sometimes there are streams direct in the meta data file directStreams = metaJson.GetValue("streams", fallback=[]) for stream in directStreams: quality = stream.get("kwaliteit", 0) if quality == 1: bitrate = 180 elif quality == 2: bitrate = 1000 elif quality == 3: bitrate = 1500 else: bitrate = 0 if "formaat" in stream and stream["formaat"] == "h264": bitrate += 1 part.AppendMediaStream(stream["url"], bitrate) # now we can get extra info from the data item.description = metaJson.GetValue("info") item.title = metaJson.GetValue('aflevering_titel') station = metaJson.GetValue('streamSense', 'station') if station is None: item.icon = self.icon elif station.startswith('nederland_1'): item.icon = self.GetImageLocation("1large.png") elif station.startswith('nederland_2'): item.icon = self.GetImageLocation("2large.png") elif station.startswith('nederland_3'): item.icon = self.GetImageLocation("3large.png") Logger.Trace("Icon for station %s = %s", station, item.icon) # <image size="380x285" ratio="4:3">http://u.omroep.nl/n/a/2010-12/380x285_boerzoektvrouw_yvon.png</image> thumbUrls = metaJson.GetValue('images') # , {"size": "380x285"}, {"ratio":"4:3"}) Logger.Trace(thumbUrls) if thumbUrls: thumbUrl = thumbUrls[-1]['url'] if "http" not in thumbUrl: thumbUrl = "http://u.omroep.nl/n/a/%s" % (thumbUrl,) else: thumbUrl = self.noImage item.thumb = thumbUrl item.complete = True return item
def get_streams_from_npo(url, episode_id, proxy=None, headers=None): """ Retrieve NPO Player Live streams from a different number of stream urls. @param url: (String) The url to download @param episode_id: (String) The NPO episode ID @param headers: (dict) Possible HTTP Headers @param proxy: (Proxy) The proxy to use for opening Can be used like this: part = item.create_new_empty_media_part() for s, b in NpoStream.get_streams_from_npo(m3u8Url, self.proxy): item.complete = True # s = self.get_verifiable_video_url(s) part.append_media_stream(s, b) """ if url: Logger.info("Determining streams for url: %s", url) episode_id = url.split("/")[-1] elif episode_id: Logger.info("Determining streams for VideoId: %s", episode_id) else: Logger.error("No url or streamId specified!") return [] # we need an hash code token_json_data = UriHandler.open("http://ida.omroep.nl/app.php/auth", no_cache=True, proxy=proxy, additional_headers=headers) token_json = JsonHelper(token_json_data) token = token_json.get_value("token") url = "http://ida.omroep.nl/app.php/%s?adaptive=yes&token=%s" % ( episode_id, token) stream_data = UriHandler.open(url, proxy=proxy, additional_headers=headers) if not stream_data: return [] stream_json = JsonHelper(stream_data, logger=Logger.instance()) stream_infos = stream_json.get_value("items")[0] Logger.trace(stream_infos) streams = [] for stream_info in stream_infos: Logger.debug("Found stream info: %s", stream_info) if stream_info["format"] == "mp3": streams.append((stream_info["url"], 0)) continue elif stream_info["contentType"] == "live": Logger.debug("Found live stream") url = stream_info["url"] url = url.replace("jsonp", "json") live_url_data = UriHandler.open(url, proxy=proxy, additional_headers=headers) live_url = live_url_data.strip("\"").replace("\\", "") Logger.trace(live_url) streams += M3u8.get_streams_from_m3u8(live_url, proxy, headers=headers) elif stream_info["format"] == "hls": m3u8_info_url = stream_info["url"] m3u8_info_data = UriHandler.open(m3u8_info_url, proxy=proxy, additional_headers=headers) m3u8_info_json = JsonHelper(m3u8_info_data, logger=Logger.instance()) m3u8_url = m3u8_info_json.get_value("url") streams += M3u8.get_streams_from_m3u8(m3u8_url, proxy, headers=headers) elif stream_info["format"] == "mp4": bitrates = {"hoog": 1000, "normaal": 500} url = stream_info["url"] if "contentType" in stream_info and stream_info[ "contentType"] == "url": mp4_url = url else: url = url.replace("jsonp", "json") mp4_url_data = UriHandler.open(url, proxy=proxy, additional_headers=headers) mp4_info_json = JsonHelper(mp4_url_data, logger=Logger.instance()) mp4_url = mp4_info_json.get_value("url") bitrate = bitrates.get(stream_info["label"].lower(), 0) if bitrate == 0 and "/ipod/" in mp4_url: bitrate = 200 elif bitrate == 0 and "/mp4/" in mp4_url: bitrate = 500 streams.append((mp4_url, bitrate)) return streams
def __UpdateVideoItem(self, item, videoId): # we need a token: token = self.__GetToken() # deviceId = AddonSettings.GetClientId() mediaUrl = "https://vod.medialaan.io/vod/v2/videos/" \ "%s" \ "/watch?deviceId=%s" % ( videoId, uuid.uuid4() ) auth = "apikey=%s&access_token=%s" % (self.__apiKey, token) headers = {"Authorization": auth} data = UriHandler.Open(mediaUrl, proxy=self.proxy, additionalHeaders=headers) jsonData = JsonHelper(data) dashInfo = jsonData.GetValue("response", "dash-cenc") if self.__dashStreamsSupported and dashInfo: Logger.Debug("Using Dash streams to playback") dashInfo = jsonData.GetValue("response", "dash-cenc") licenseUrl = dashInfo["widevineLicenseServerURL"] streamUrl = dashInfo["url"] sessionId = jsonData.GetValue("request", "access_token") licenseHeader = { "merchant": "medialaan", "userId": self.__userId, "sessionId": sessionId } licenseHeader = JsonHelper.Dump(licenseHeader, False) licenseHeaders = "x-dt-custom-data={0}&Content-Type=application/octstream".format( base64.b64encode(licenseHeader)) kodiProps = { "inputstreamaddon": "inputstream.adaptive", "inputstream.adaptive.manifest_type": "mpd", "inputstream.adaptive.license_type": "com.widevine.alpha", "inputstream.adaptive.license_key": "{0}?specConform=true|{1}|R{{SSM}}|".format( licenseUrl, licenseHeaders or "") } part = item.CreateNewEmptyMediaPart() stream = part.AppendMediaStream(streamUrl, 0) # noinspection PyTypeChecker for k, v in kodiProps.iteritems(): stream.AddProperty(k, v) else: Logger.Debug( "No Dash streams supported or no Dash streams available. Using M3u8 streams" ) m3u8Url = jsonData.GetValue("response", "hls-encrypted", "url") if not m3u8Url: m3u8Url = jsonData.GetValue("response", "uri") # m3u8Url = jsonData.GetValue("response", "hls-drm-uri") # not supported by Kodi part = item.CreateNewEmptyMediaPart() # Set the Range header to a proper value to make all streams start at the beginning. Make # sure that a complete TS part comes in a single call otherwise we get stuttering. byteRange = 10 * 1024 * 1024 Logger.Debug( "Setting an 'Range' http header of bytes=0-%d to force playback at the start " "of a stream and to include a full .ts part.", byteRange) part.HttpHeaders["Range"] = 'bytes=0-%d' % (byteRange, ) for s, b in M3u8.GetStreamsFromM3u8(m3u8Url, self.proxy): item.complete = True # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) return item