def _get_live_streams(self, params, swf_url): for key, quality in QUALITY_MAP.items(): key_url = "{0}URL".format(key) url = params.get(key_url) if not url: continue try: res = http.get(url, exception=IOError) except IOError: continue if quality == "hds": streams = HDSStream.parse_manifest(self.session, res.url) for name, stream in streams.items(): if key == "source": name += "+" yield name, stream elif res.text.startswith("rtmp"): match = _rtmp_re.match(res.text) if not match: continue stream = RTMPStream(self.session, { "rtmp": match.group("host"), "app": match.group("app"), "playpath": match.group("playpath"), "swfVfy": swf_url, "live": True }) yield quality, stream
def _get_live_streams(self, params, swf_url): for key, quality in QUALITY_MAP.items(): key_url = "{0}URL".format(key) url = params.get(key_url) if not url: continue try: res = http.get(url, exception=IOError) except IOError: continue if quality == "hds": streams = HDSStream.parse_manifest(self.session, res.url) for name, stream in streams.items(): if key == "source": name += "+" yield name, stream elif res.text.startswith("rtmp"): match = _rtmp_re.match(res.text) if not match: continue stream = RTMPStream( self.session, { "rtmp": match.group("host"), "app": match.group("app"), "playpath": match.group("playpath"), "swfVfy": swf_url, "live": True }) yield quality, stream
def get_live_streams(self): res = self._get_live_page(self.res) match = re.search("flashvars\s+=\s+({.+?});", res.text) if not match: raise NoStreamsError(self.url) flashvars = parse_json(match.group(1), "flashvars JSON") flashvars["uip"] = self._get_user_ip() levels = re.findall("setFlashLevel\((\d+)\);", res.text) streams = {} for level in levels: params = self._create_gox_params(flashvars, level) res = urlget(self.GOXLiveURL, params=params, session=self.rsession) gox = GOXFile(res.text) for entry in gox.filter_entries("live"): try: s = HDSStream.parse_manifest(self.session, entry.ref[0]) streams.update(s) except IOError: self.logger.warning("Unable to parse manifest") break return streams
def get_alt_live_streams(self): res = self._get_live_page(self.res) match = re.search('jQuery.post\("/live/ajaxGetUrl.gom", ({.+?}),', res.text) if not match: raise NoStreamsError(self.url) ajaxparams = match.group(1) ajaxparams = dict(re.findall("(\w+):(\d+)", ajaxparams)) levels = re.findall("setFlashLevel\((\d+)\);.+?<span class=\"qtype\">(\w+)</span>", res.text) streams = {} for level, quality in levels: params = ajaxparams.copy() params["level"] = level quality = quality.lower() res = urlopen(self.GetStreamURL, data=params, session=self.rsession) url = unquote(res.text) if not urlparse(url).path.endswith(".f4m"): continue try: s = HDSStream.parse_manifest(self.session, url) if len(s) > 0: bitrate, stream = list(s.items())[0] streams[quality] = stream except IOError: self.logger.warning("Unable to parse manifest") return streams
def _create_streams(self, type_, video_id): url = self._generate_security_url(type_, video_id) res = http.get(url) return HDSStream.parse_manifest(self.session, res.text, cookies=res.cookies)
def _get_streams_from_id(self, stream_id): res = urlget(CONFIG_URL, params=dict(id=stream_id)) config = res_json(res) media = verifyjson(config, "media") if not (media and isinstance(media, list)): return streams = {} media = media[0] hds_manifest = media.get("name") hls_manifest = media.get("hlsUrl") if hds_manifest: try: hds_streams = HDSStream.parse_manifest(self.session, hds_manifest) streams.update(hds_streams) except IOError as err: if not re.search(r"(404|400) Client Error", str(err)): self.logger.error("Failed to parse HDS manifest: {0}", err) if hls_manifest: try: hls_streams = HLSStream.parse_variant_playlist(self.session, hls_manifest, nameprefix="mobile_") streams.update(hls_streams) except IOError as err: if not re.search(r"(404|400) Client Error", str(err)): self.logger.error("Failed to parse HLS playlist: {0}", err) return streams
def _get_streams(self): match = _url_re.match(self.url) video_id = match.group("video_id") res = http.get(ASSET_URL.format(video_id)) assets = http.xml(res, schema=_asset_schema) streams = {} for asset in assets: base = asset["base"] url = asset["url"] if urlparse(url).path.endswith(".f4m"): streams.update( HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL) ) elif base.startswith("rtmp"): name = "{0}k".format(asset["bitrate"]) params = { "rtmp": asset["base"], "playpath": url, "live": True } streams[name] = RTMPStream(self.session, params) return streams
def _get_streams(self): if not RTMPStream.is_usable(self.session): self.logger.warning("rtmpdump is not usable, only HDS streams will be available") self.logger.debug("Fetching stream info") match = re.search("/\w*/(live|video)*/(\d+)", self.url) if not match: return stream_id = match.group(2) res = http.get(API_URL, params=dict(ak="web", id=stream_id)) root = parse_xml(res.text.encode("utf8")) streams = {} for formitaet in root.iter('formitaet'): url = formitaet.find('url').text quality = formitaet.find('quality').text if formitaet.get('basetype') == "h264_aac_f4f_http_f4m_http": hds_streams = HDSStream.parse_manifest(self.session, url) streams.update(hds_streams) elif formitaet.get('basetype') == 'h264_aac_mp4_rtmp_zdfmeta_http': streams[quality] = RTMPStream(self.session, { "rtmp": self._get_stream(url), "pageUrl": self.url, }) return streams
def _get_streams(self): res = http.get(self.url) match = _manifest_re.search(res.content) manifest = match.group(1) streams = {} streams.update( HDSStream.parse_manifest(self.session, manifest, pvswf=SWF_URL)) return streams
def _get_streams(self): res = http.get(self.url) match = _manifest_re.search(res.text) manifest = match.group(1) streams = {} streams.update( HDSStream.parse_manifest(self.session, manifest, pvswf=SWF_URL) ) return streams
def _get_smil_streams(self, info): res = http.get(info["_stream"]) smil = http.xml(res, "SMIL config", schema=_smil_schema) streams = {} for video in smil["videos"]: url = "{0}/{1}{2}".format(smil["base"], video, HDCORE_PARAMETER) streams.update( HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)) return streams
def _get_smil_streams(self, info): res = http.get(info["_stream"]) smil = http.xml(res, "SMIL config", schema=_smil_schema) for video in smil["videos"]: url = "{0}/{1}{2}".format(smil["base"], video, HDCORE_PARAMETER) streams = HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL) # TODO: Replace with "yield from" when dropping Python 2. for stream in streams.items(): yield stream
def _get_smil_streams(self, info): res = http.get(info["_stream"]) smil = http.xml(res, "SMIL config", schema=_smil_schema) streams = {} for video in smil["videos"]: url = "{0}/{1}{2}".format(smil["base"], video, HDCORE_PARAMETER) streams.update( HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL) ) return streams
def _get_streams(self): res = http.get(self.url) match = _meta_xmlurl_id_re.search(res.text) if not match: return xml_info_url = STREAMS_INFO_URL.format(match.group(1)) video_info_res = http.get(xml_info_url) parsed_info = http.xml(video_info_res) live_el = parsed_info.find("live") live = live_el is not None and live_el.text == "1" streams = {} hdsurl_el = parsed_info.find("hdsurl") if hdsurl_el is not None and hdsurl_el.text is not None: hdsurl = hdsurl_el.text streams.update(HDSStream.parse_manifest(self.session, hdsurl)) if live: vurls_el = parsed_info.find("vurls") if vurls_el is not None: for i, vurl_el in enumerate(vurls_el): bitrate = vurl_el.get("bitrate") name = bitrate + "k" if bitrate is not None else "rtmp{0}".format( i) params = { "rtmp": vurl_el.text, } streams[name] = RTMPStream(self.session, params) parsed_urls = set() mobileurls_el = parsed_info.find("mobileurls") if mobileurls_el is not None: for mobileurl_el in mobileurls_el: text = mobileurl_el.text if not text: continue if text in parsed_urls: continue parsed_urls.add(text) url = urlparse(text) if url[0] == "http" and url[2].endswith("m3u8"): streams.update( HLSStream.parse_variant_playlist(self.session, text)) return streams
def _get_streams(self): res = http.get(API_URL) data = http.json(res, schema=_schema) streams = {} for livestreams in data["live-streams"]: for stream in livestreams["streams"]: url = stream["streamUrl"] for name, stream in HDSStream.parse_manifest(self.session, url).items(): if name.endswith("k"): streams[name] = stream return streams
def _get_streams(self): res = http.get(API_URL) data = http.json(res, schema=_schema) streams = {} for livestreams in data["live-streams"]: for stream in livestreams["streams"]: url = stream["streamUrl"] for name, stream in HDSStream.parse_manifest( self.session, url).items(): if name.endswith("k"): streams[name] = stream return streams
def _get_streams(self): res = http.get(self.url) match = _meta_xmlurl_id_re.search(res.text) if not match: return; xml_info_url = STREAMS_INFO_URL.format(match.group(1)) video_info_res = http.get(xml_info_url) parsed_info = http.xml(video_info_res) live_el = parsed_info.find("live"); live = live_el is not None and live_el.text == "1" streams = { } hdsurl_el = parsed_info.find("hdsurl"); if hdsurl_el is not None and hdsurl_el.text is not None: hdsurl = hdsurl_el.text streams.update(HDSStream.parse_manifest(self.session, hdsurl)) if live: vurls_el = parsed_info.find("vurls"); if vurls_el is not None: for i, vurl_el in enumerate(vurls_el): bitrate = vurl_el.get("bitrate") name = bitrate + "k" if bitrate is not None else "rtmp{0}".format(i) params = { "rtmp": vurl_el.text, } streams[name] = RTMPStream(self.session, params) parsed_urls = set() mobileurls_el = parsed_info.find("mobileurls"); if mobileurls_el is not None: for mobileurl_el in mobileurls_el: text = mobileurl_el.text if not text: continue if text in parsed_urls: continue parsed_urls.add(text) url = urlparse(text) if url[0] == "http" and url[2].endswith("m3u8"): streams.update(HLSStream.parse_variant_playlist(self.session, text)) return streams
def _get_streams(self): self.logger.debug("Fetching stream info") res = http.get(self.url, params=dict(output="json")) json = http.json(res) if not isinstance(json, dict): raise PluginError("Invalid JSON response") streams = {} video = verifyjson(json, "video") videos = verifyjson(video, "videoReferences") for video in videos: if not ("url" in video and "playerType" in video): continue url = video["url"] if video["playerType"] == "flash": if url.startswith("rtmp"): stream = RTMPStream( self.session, { "rtmp": url, "pageUrl": PAGE_URL, "swfVfy": SWF_URL, "live": True }) streams[str(video["bitrate"]) + "k"] = stream elif "manifest.f4m" in url: try: hdsstreams = HDSStream.parse_manifest( self.session, url) streams.update(hdsstreams) except IOError as err: self.logger.warning("Failed to get HDS manifest: {0}", err) elif video["playerType"] == "ios": try: hlsstreams = HLSStream.parse_variant_playlist( self.session, url) streams.update(hlsstreams) except IOError as err: self.logger.warning("Failed to get variant playlist: {0}", err) return streams
def _get_streams(self): match = _url_re.match(self.url) stream_id = match.group("stream_id") or self._find_stream_id() if not stream_id: return res = http.get(STREAM_API_URL.format(stream_id)) stream_info = http.json(res, schema=_stream_schema) streams = {} swf_url = None for name, stream_url in stream_info.items(): if stream_url.endswith(".m3u8"): try: streams.update( HLSStream.parse_variant_playlist(self.session, stream_url) ) except IOError as err: self.logger.error("Failed to fetch HLS streams: {0}", err) elif stream_url.endswith(".f4m"): try: streams.update( HDSStream.parse_manifest(self.session, stream_url) ) except IOError as err: self.logger.error("Failed to fetch HDS streams: {0}", err) elif stream_url.startswith("rtmp://"): swf_url = swf_url or self._get_swf_url() params = { "rtmp": stream_url, "pageUrl": self.url, "swfVfy": swf_url, } if stream_url.endswith(".mp4"): tcurl, playpath = rtmpparse(stream_url) params["rtmp"] = tcurl params["playpath"] = playpath else: params["live"] = True streams[name] = RTMPStream(self.session, params) return streams
def _get_streams(self): self.logger.debug("Fetching stream info") res = http.get(self.url, params=dict(output="json")) json = http.json(res) if not isinstance(json, dict): raise PluginError("Invalid JSON response") streams = {} video = verifyjson(json, "video") videos = verifyjson(video, "videoReferences") for video in videos: if not ("url" in video and "playerType" in video): continue url = video["url"] if video["playerType"] == "flash": if url.startswith("rtmp"): stream = RTMPStream(self.session, { "rtmp": url, "pageUrl": PAGE_URL, "swfVfy": SWF_URL, "live": True }) streams[str(video["bitrate"]) + "k"] = stream elif "manifest.f4m" in url: try: hdsstreams = HDSStream.parse_manifest(self.session, url) streams.update(hdsstreams) except IOError as err: self.logger.warning("Failed to get HDS manifest: {0}", err) elif video["playerType"] == "ios": try: hlsstreams = HLSStream.parse_variant_playlist(self.session, url) streams.update(hlsstreams) except IOError as err: self.logger.warning("Failed to get variant playlist: {0}", err) return streams
def _get_streams(self): match = _url_re.match(self.url) video_id = match.group("video_id") res = http.get(ASSET_URL.format(video_id)) assets = http.xml(res, schema=_asset_schema) streams = {} for asset in assets: base = asset["base"] url = asset["url"] if urlparse(url).path.endswith(".f4m"): streams.update( HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)) elif base.startswith("rtmp"): name = "{0}k".format(asset["bitrate"]) params = {"rtmp": asset["base"], "playpath": url, "live": True} streams[name] = RTMPStream(self.session, params) return streams
def get_alt_live_streams(self): res = self._get_live_page(self.res) match = re.search('jQuery.post\("/live/ajaxGetUrl.gom", ({.+?}),', res.text) if not match: raise NoStreamsError(self.url) ajaxparams = match.group(1) ajaxparams = dict(re.findall("(\w+):(\d+)", ajaxparams)) levels = re.findall( "setFlashLevel\((\d+)\);.+?<span class=\"qtype\">(\w+)</span>", res.text) streams = {} for level, quality in levels: params = ajaxparams.copy() params["level"] = level quality = quality.lower() res = urlopen(self.GetStreamURL, data=params, session=self.rsession) url = unquote(res.text) if not urlparse(url).path.endswith(".f4m"): continue try: s = HDSStream.parse_manifest(self.session, url) if len(s) > 0: bitrate, stream = list(s.items())[0] streams[quality] = stream except IOError: self.logger.warning("Unable to parse manifest") return streams
def get_alt_live_streams(self): res = self._get_live_page(self.res) match = re.search('jQuery.post\("/live/ajaxGetUrl.gom", ({.+?}),', res.text) if not match: raise NoStreamsError(self.url) ajaxparams = match.group(1) ajaxparams = dict(re.findall("(\w+):(\d+)", ajaxparams)) levels = re.findall("setFlashLevel\((\d+)\);", res.text) streams = {} for level in levels: params = ajaxparams.copy() params["level"] = level res = urlopen(self.GetStreamURL, data=params, session=self.rsession) url = unquote(res.text) if not urlparse(url).path.endswith(".f4m"): continue try: s = HDSStream.parse_manifest(self.session, url) streams.update(s) except IOError: self.logger.warning("Unable to parse manifest") # Hack to rename incorrect bitrate specified by GOM to something # more sane. for name, stream in streams.items(): if name == "1k": streams["1000k"] = stream del streams[name] return streams
def _get_vod_streams(self, params): manifest_url = params.get("autoURL") if not manifest_url: return res = http.get(manifest_url) if res.headers.get("Content-Type") == "application/f4m+xml": streams = HDSStream.parse_manifest(self.session, res.url) # TODO: Replace with "yield from" when dropping Python 2. for __ in streams.items(): yield __ else: manifest = http.json(res, schema=_vod_manifest_schema) for params in manifest["alternates"]: name = "{0}p".format(params["height"]) stream = self._create_flv_playlist(params["template"]) yield name, stream failovers = params.get("failover", []) for failover in failovers: stream = self._create_flv_playlist(failover) yield name, stream
def _get_hds_streams(self, info): # Needs the hdcore parameter added url = info["_stream"] + HDCORE_PARAMETER return HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL).items()
def _get_rtmp_streams(self, channelname): self.logger.debug("Fetching stream info") res = http.get(STREAM_INFO_URL.format(channelname)) json = http.json(res) if not isinstance(json, dict): raise PluginError("Invalid JSON response") if not json: raise PluginError("JSON is empty") # This is ugly, not sure how to fix it. back_json_node = json["sequence"][0]["layerList"][0] if back_json_node["name"] != "background": raise PluginError("JSON data has unexpected structure") rep_node = self._get_node_by_name(back_json_node["sequenceList"], "reporting")["layerList"] main_node = self._get_node_by_name(back_json_node["sequenceList"], "main")["layerList"] if not (rep_node and main_node): raise PluginError("Error parsing stream RTMP url") swfurl = self._get_node_by_name(rep_node, "reporting")["param"]["extraParams"]["videoSwfURL"] feeds_params = self._get_node_by_name(main_node, "video")["param"] if not (swfurl and feeds_params): raise PluginError("Error parsing stream RTMP url") # Different feed qualities are available are a dict under "live" # In some cases where there's only 1 quality available, # it seems the "live" is absent. We use the single stream available # under the "customURL" key. streams = {} if "mode" in feeds_params and feeds_params["mode"] == "live": for key, quality in QUALITY_MAP.items(): url = feeds_params.get("{0}URL".format(key)) if not url: continue try: res = http.get(url, exception=IOError) except IOError: continue if quality == "hds": hds_streams = HDSStream.parse_manifest(self.session, res.url) streams.update(hds_streams) else: match = re.match(RTMP_SPLIT_REGEX, res.text) if not match: self.logger.warning("Failed to split RTMP URL: {0}", res.text) continue stream = RTMPStream(self.session, { "rtmp": match.group("host"), "app": match.group("app"), "playpath": match.group("playpath"), "swfVfy": swfurl, "live": True }) self.logger.debug("Adding URL: {0}", res.text) streams[quality] = stream return streams
def _get_hds_streams(self, info): # Needs the hdcore parameter added url = info["_stream"] + HDCORE_PARAMETER return HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)
def _get_rtmp_streams(self, channelname): self.logger.debug("Fetching stream info") res = http.get(STREAM_INFO_URL.format(channelname)) json = http.json(res) if not isinstance(json, dict): raise PluginError("Invalid JSON response") if not json: raise PluginError("JSON is empty") # This is ugly, not sure how to fix it. back_json_node = json["sequence"][0]["layerList"][0] if back_json_node["name"] != "background": raise PluginError("JSON data has unexpected structure") rep_node = self._get_node_by_name(back_json_node["sequenceList"], "reporting")["layerList"] main_node = self._get_node_by_name(back_json_node["sequenceList"], "main")["layerList"] if not (rep_node and main_node): raise PluginError("Error parsing stream RTMP url") swfurl = self._get_node_by_name( rep_node, "reporting")["param"]["extraParams"]["videoSwfURL"] feeds_params = self._get_node_by_name(main_node, "video")["param"] if not (swfurl and feeds_params): raise PluginError("Error parsing stream RTMP url") # Different feed qualities are available are a dict under "live" # In some cases where there's only 1 quality available, # it seems the "live" is absent. We use the single stream available # under the "customURL" key. streams = {} if "mode" in feeds_params and feeds_params["mode"] == "live": for key, quality in QUALITY_MAP.items(): url = feeds_params.get("{0}URL".format(key)) if not url: continue try: res = http.get(url, exception=IOError) except IOError: continue if quality == "hds": hds_streams = HDSStream.parse_manifest( self.session, res.url) streams.update(hds_streams) else: match = re.match(RTMP_SPLIT_REGEX, res.text) if not match: self.logger.warning("Failed to split RTMP URL: {0}", res.text) continue stream = RTMPStream( self.session, { "rtmp": match.group("host"), "app": match.group("app"), "playpath": match.group("playpath"), "swfVfy": swfurl, "live": True }) self.logger.debug("Adding URL: {0}", res.text) streams[quality] = stream return streams
def get_vod_streams(self): match = re.search("flashvars\s+=\s+({.+?});", self.res.text) if not match: raise NoStreamsError(self.url) flashvars = parse_json(match.group(1), "flashvars JSON") match = re.search("var jsonData\s+= eval \((.+?)\);", self.res.text, re.DOTALL) if not match: raise NoStreamsError(self.url) playlists = parse_json(match.group(1), "playlist JSON") self.logger.info("Playlist items found:") for i, playlist in enumerate(playlists): for fvars in playlist: if self.url[-1] != "/": url = self.url + "/" else: url = self.url url = urljoin(url, "?set={1}&lang={0}".format(i, fvars["set"])) self.logger.info("[Set {1} ({0})] {2}", self.Lang[i], fvars["set"], url) params = parse_qsd(urlparse(self.url).query) currentset = int(params.get("set", "1")) lang = int(params.get("lang", "0")) flashvars.update(playlists[lang][currentset - 1]) flashvars["uip"] = self._get_user_ip() streams = {} for level in self.VODQualityLevels: params = self._create_gox_params(flashvars, level) res = urlget(self.GOXVODURL, params=params, session=self.rsession) gox = GOXFile(res.text) entries = gox.filter_entries("vod") for entry in entries: try: s = HDSStream.parse_manifest(self.session, entry.ref[0]) streams.update(s) except IOError: self.logger.warning("Unable to parse manifest") if len(streams) == 0: self.logger.warning(("Unable to access any streams, " "make sure you have access to this VOD")) return streams