def _create_adaptive_streams(self, adaptive_formats): streams = {} adaptive_streams = {} best_audio_itag = None # Extract audio streams from the adaptive format list for url, label, itag, mimeType in adaptive_formats: if url is None: continue # extract any high quality streams only available in adaptive formats adaptive_streams[itag] = url stream_type, stream_codecs = mimeType if stream_type == "audio": streams[f"audio_{stream_codecs}"] = HTTPStream(self.session, url) # find the best quality audio stream m4a, opus or vorbis if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]: best_audio_itag = itag if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session): aurl = adaptive_streams[best_audio_itag] for itag, name in self.adp_video.items(): if itag not in adaptive_streams: continue vurl = adaptive_streams[itag] log.debug(f"MuxedStream: v {itag} a {best_audio_itag} = {name}") streams[name] = MuxedStream( self.session, HTTPStream(self.session, vurl), HTTPStream(self.session, aurl) ) return streams
def test_http_stream(session, common_args): stream = HTTPStream(session, "http://host/stream?foo=bar", **common_args) assert stream.to_url( ) == "http://host/stream?foo=bar&queryparamkey=queryparamval" with pytest.raises(TypeError) as cm: stream.to_manifest_url() assert str( cm.value ) == "<HTTPStream [http]> cannot be translated to a manifest URL"
def _get_streams(self): if "player.vimeo.com" in self.url: data = self.session.http.get(self.url, schema=self._player_schema) else: api_url = self.session.http.get(self.url, schema=self._config_url_schema) if not api_url: return data = self.session.http.get(api_url, schema=self._config_schema) videos = data["request"]["files"] streams = [] for stream_type in ("hls", "dash"): if stream_type not in videos: continue for _, video_data in videos[stream_type]["cdns"].items(): log.trace("{0!r}".format(video_data)) url = video_data.get("url") if stream_type == "hls": for stream in HLSStream.parse_variant_playlist( self.session, url).items(): streams.append(stream) elif stream_type == "dash": p = urlparse(url) if p.path.endswith("dash.mpd"): # LIVE url = self.session.http.get(url).json()["url"] elif p.path.endswith("master.json"): # VOD url = url.replace("master.json", "master.mpd") else: log.error("Unsupported DASH path: {0}".format(p.path)) continue for stream in DASHStream.parse_manifest(self.session, url).items(): streams.append(stream) for stream in videos.get("progressive", []): streams.append( (stream["quality"], HTTPStream(self.session, stream["url"]))) if self.get_option("mux_subtitles") and data["request"].get( "text_tracks"): substreams = { s["lang"]: HTTPStream(self.session, "https://vimeo.com" + s["url"]) for s in data["request"]["text_tracks"] } for quality, stream in streams: yield quality, MuxedStream(self.session, stream, subtitles=substreams) else: for stream in streams: yield stream
def test_http_stream(session, common_args, expected_headers): stream = HTTPStream(session, "http://host/path?foo=bar", **common_args) assert stream.__json__() == { "type": "http", "url": "http://host/path?foo=bar&sessionqueryparamkey=sessionqueryparamval&queryparamkey=queryparamval", "method": "GET", "body": None, "headers": expected_headers, }
def _get_streams(self): if "empty" in self.url: return if "UnsortableStreamNames" in self.url: def gen(): for i in range(3): yield "vod", HTTPStream(self.session, "http://test.se/stream") return gen() if "NoStreamsError" in self.url: raise NoStreamsError(self.url) streams = {} streams["test"] = TestStream(self.session) streams["hls"] = HLSStream(self.session, "http://test.se/playlist.m3u8") streams["http"] = HTTPStream(self.session, "http://test.se/stream") streams["240p"] = HTTPStream(self.session, "http://test.se/stream") streams["360p"] = HTTPStream(self.session, "http://test.se/stream") streams["1080p"] = HTTPStream(self.session, "http://test.se/stream") streams["350k"] = HTTPStream(self.session, "http://test.se/stream") streams["800k"] = HTTPStream(self.session, "http://test.se/stream") streams["1500k"] = HTTPStream(self.session, "http://test.se/stream") streams["3000k"] = HTTPStream(self.session, "http://test.se/stream") streams["480p"] = [ HTTPStream(self.session, "http://test.se/stream"), HLSStream(self.session, "http://test.se/playlist.m3u8") ] return streams
def __init__(self, session_, url, force_restart=False, start_offset=0, duration=None, **args): HTTPStream.__init__(self, session_, url, **args) self.force_restart = force_restart self.start_offset = start_offset self.duration = duration
def _get_streams(self): res = self.session.http.get(self.url) m = self._re_idAsset.search(res.text) if m: content_id = m.group(1) log.debug(f"Found content with id: {content_id}") stream_data = self.zclient.get_cdn_list(content_id, schema=self.cdn_schema) quality_map = None streams = [] for stream in stream_data: # only use one stream _one_m3u8 = False _one_mp4 = False for url in stream["urls"]: p_url = urlparse(url) if p_url.path.endswith(".m3u8"): if _one_m3u8: continue try: streams.extend( HLSStream.parse_variant_playlist( self.session, url).items()) _one_m3u8 = True except OSError as err: log.error(str(err)) elif p_url.path.endswith(".mp4"): if _one_mp4: continue if quality_map is None: # only make the request when it is necessary quality_map = self._get_quality_map(content_id) # rename the HTTP sources to match the HLS sources quality = quality_map.get(stream["quality"], stream["quality"]) streams.append((quality, HTTPStream(self.session, url))) _one_mp4 = True subtitles = None if self.get_option("mux_subtitles"): subtitles = self._get_subtitles(content_id) if subtitles: substreams = {} for i, subtitle in enumerate(subtitles): substreams[subtitle["lang"]] = HTTPStream( self.session, subtitle["src"]) for q, s in streams: yield q, MuxedStream(self.session, s, subtitles=substreams) else: for s in streams: yield s
def _parse_streams(self, res): stream_url = validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//head/meta[@property='og:video:url'][@content][1]/@content") ).validate(res.text) if not stream_url: log.debug("No meta og:video:url") else: if ".mpd" in stream_url: for s in DASHStream.parse_manifest(self.session, stream_url).items(): yield s return elif ".mp4" in stream_url: yield "vod", HTTPStream(self.session, stream_url) return for match in self._src_re.finditer(res.text): stream_url = match.group("url") if "\\/" in stream_url: # if the URL is json encoded, decode it stream_url = parse_json("\"{}\"".format(stream_url)) if ".mpd" in stream_url: for s in DASHStream.parse_manifest(self.session, stream_url).items(): yield s elif ".mp4" in stream_url: yield match.group(1), HTTPStream(self.session, stream_url) else: log.debug("Non-dash/mp4 stream: {0}".format(stream_url)) match = self._dash_manifest_re.search(res.text) if match: # facebook replaces "<" characters with the substring "\\x3C" manifest = match.group("manifest").replace("\\/", "/") if is_py3: manifest = bytes(unquote_plus(manifest), "utf-8").decode("unicode_escape") else: manifest = unquote_plus(manifest).decode("string_escape") # Ignore unsupported manifests until DASH SegmentBase support is implemented if "SegmentBase" in manifest: log.error("Skipped DASH manifest with SegmentBase streams") else: for s in DASHStream.parse_manifest(self.session, manifest).items(): yield s
def test_http_stream(self): url = "http://test.se/stream" stream = HTTPStream(self.session, url, headers={"User-Agent": "Test"}) self.assertEqual( {"type": "http", "url": url, "method": "GET", "body": None, "headers": { "User-Agent": "Test", "Accept": "*/*", "Accept-Encoding": DEFAULT_ACCEPT_ENCODING, "Connection": "keep-alive", }}, stream.__json__() )
def _get_streams(self): player_js = self.session.http.get( self.url, schema=validate.Schema( validate.transform(self._re_player.search), validate.any( None, validate.Schema( validate.get(1), validate.transform( lambda url: update_scheme("https:", url)))))) if not player_js: return log.debug(f"Found player js {player_js}") data = self.session.http.get( player_js, schema=validate.Schema( validate.transform(self._re_json.match), validate.get(1), validate.parse_json(), validate.get("mediaResource"), validate.get("dflt"), { validate.optional("audioURL"): validate.url(), validate.optional("videoURL"): validate.url() })) if data.get("videoURL"): yield from HLSStream.parse_variant_playlist( self.session, update_scheme("https:", data.get("videoURL"))).items() if data.get("audioURL"): yield "audio", HTTPStream( self.session, update_scheme("https:", data.get("audioURL")))
def _get_streams(self): data = self.match.groupdict() url = update_scheme("https://", data.get("url"), force=False) params = parse_params(data.get("params")) log.debug("URL={0}; params={1}".format(url, params)) return {"live": HTTPStream(self.session, url, **params)}
def _get_streams(self): streams = self.session.http.get(self.url, schema=self._stream_schema) if streams is None: return if streams['type'] != 'STATION': return stream_urls = set() for stream in streams['streams']: log.trace('{0!r}'.format(stream)) url = stream['url'] url_no_scheme = urlunparse(urlparse(url)._replace(scheme='')) if url_no_scheme in stream_urls: continue stream_urls.add(url_no_scheme) if stream['contentFormat'] in ('audio/mpeg', 'audio/aac'): yield 'live', HTTPStream(self.session, url, allow_redirects=True) elif stream['contentFormat'] == 'video/MP2T': streams = HLSStream.parse_variant_playlist(self.session, stream["url"]) if not streams: yield stream["quality"], HLSStream(self.session, stream["url"]) else: for s in streams.items(): yield s
def _get_streams(self): # Construct manifest URL for this program. program_type, program_id = self.match.groups() manifest_type = self._program_type_map.get(program_type) if manifest_type is None: log.error(f"Unknown program type '{program_type}'") return None # Fetch program_id. res = self.session.http.get(self.url) m = self._program_id_re.search(res.text) if m is not None: program_id = m.group(1) elif program_id is None: log.error("Could not extract program ID from URL") return None manifest_url = urljoin( self._psapi_url, f"playback/manifest/{manifest_type}/{program_id}") # Extract media URL. res = self.session.http.get(manifest_url) manifest = self.session.http.json(res, schema=self._playable_schema) if 'nonPlayable' in manifest: reason = manifest["nonPlayable"]["reason"] log.error(f"Not playable ({reason})") return None self._set_metadata(manifest) asset = manifest['playable']['assets'][0] # Some streams such as podcasts are not HLS but plain files. if asset['format'] == 'HLS': return HLSStream.parse_variant_playlist(self.session, asset['url']) else: return [("live", HTTPStream(self.session, asset['url']))]
def _get_vod(self, root): schema_vod = validate.Schema( validate.xml_xpath_string( ".//script[@type='application/ld+json'][contains(text(),'VideoObject')][1]/text()" ), str, validate.transform( lambda jsonlike: re.sub(r"[\r\n]+", "", jsonlike)), validate.parse_json(), validate.any( validate.all( {"@graph": [dict]}, validate.get("@graph"), validate.filter(lambda obj: obj["@type"] == "VideoObject"), validate.get(0)), dict), {"contentUrl": validate.url()}, validate.get("contentUrl"), validate.transform( lambda content_url: update_scheme("https://", content_url))) try: vod = schema_vod.validate(root) except PluginError: return if urlparse(vod).path.endswith(".m3u8"): return HLSStream.parse_variant_playlist(self.session, vod) return {"vod": HTTPStream(self.session, vod)}
def __json__(self): json = HTTPStream.__json__(self) # Pretty sure HLS is GET only. del json["method"] del json["body"] return json
def _get_streams(self): data = self.session.http.get(self.url, schema=self.config_schema) for info in data["files"].values(): stream_url = update_scheme("https://", info["url"]) # pick the smaller of the two dimensions, for landscape v. portrait videos res = min(info["width"], info["height"]) yield "{0}p".format(res), HTTPStream(self.session, stream_url)
def _get_clips(self): try: sig, token, streams = self.api.clips(self.clip_name) except (PluginError, TypeError): return for quality, stream in streams: yield quality, HTTPStream(self.session, update_qsd(stream, {"sig": sig, "token": token}))
def _get_streams(self): res = self._get_res(self.url) if self.match.group( "channel") and not self.match.group("channel_live"): initial = self._get_data_from_regex(res, self._re_ytInitialData, "initial data") video_id = self._data_video_id(initial) if video_id is None: log.error("Could not find videoId on channel page") return self.url = self._url_canonical.format(video_id=video_id) res = self._get_res(self.url) data = self._get_data_from_regex(res, self._re_ytInitialPlayerResponse, "initial player response") if not self._data_status(data): data = self._get_data_from_api(res) if not self._data_status(data, True): return self.id, self.author, self.category, self.title, is_live = self._schema_videodetails( data) log.debug(f"Using video ID: {self.id}") if is_live: log.debug("This video is live.") streams = {} hls_manifest, formats, adaptive_formats = self._schema_streamingdata( data) protected = next( (True for url, *_ in formats + adaptive_formats if url is None), False) if protected: log.debug("This video may be protected.") for url, label in formats: if url is None: continue streams[label] = HTTPStream(self.session, url) if not is_live: streams.update(self._create_adaptive_streams(adaptive_formats)) if hls_manifest: streams.update( HLSStream.parse_variant_playlist(self.session, hls_manifest, name_key="pixels")) if not streams and protected: raise PluginError( "This plugin does not support protected videos, try youtube-dl instead" ) return streams
def _get_video_streams(self): res = self.session.http.get(self.url) match = self._video_player_re.search(res.text) if match is None: return player_url = match.group('player_url') stream_data = self.session.http.get(player_url, schema=self._video_stream_schema) if stream_data is None: return # Check geolocation to prevent further errors when stream is parsed if not self.check_geolocation(stream_data['geoLocRestriction']): log.error('Stream is geo-restricted') return # Check whether streams are DRM-protected if stream_data.get('drm', False): log.error('Stream is DRM-protected') return now = datetime.datetime.now() try: if isinstance(stream_data['sources'], dict): urls = [] for profile, url in stream_data['sources'].items(): if not url or url in urls: continue match = self._stream_size_re.match(url) if match is not None: quality = match.group('size') else: quality = profile yield quality, HTTPStream(self.session, url) urls.append(url) hls_url = stream_data.get('urlHls') or stream_data.get('streamUrlHls') if hls_url: if stream_data.get('isLive', False): # Live streams require a token hls_url = self.tokenize_stream(hls_url) yield from HLSStream.parse_variant_playlist(self.session, hls_url).items() dash_url = stream_data.get('urlDash') or stream_data.get('streamUrlDash') if dash_url: if stream_data.get('isLive', False): # Live streams require a token dash_url = self.tokenize_stream(dash_url) yield from DASHStream.parse_manifest(self.session, dash_url).items() except OSError as err: if '403 Client Error' in str(err): # Check whether video is expired if 'startDate' in stream_data: if now < self.iso8601_to_epoch(stream_data['startDate']): log.error('Stream is not yet available') elif 'endDate' in stream_data: if now > self.iso8601_to_epoch(stream_data['endDate']): log.error('Stream has expired')
def _parse_streams(self, res): _found_stream_url = False for meta in itertags(res.text, "meta"): if meta.attributes.get("property") == "og:video:url": stream_url = html_unescape(meta.attributes.get("content")) if ".mpd" in stream_url: for s in DASHStream.parse_manifest(self.session, stream_url).items(): yield s _found_stream_url = True elif ".mp4" in stream_url: yield "vod", HTTPStream(self.session, stream_url) _found_stream_url = True break else: log.debug("No meta og:video:url") if _found_stream_url: return for match in self._src_re.finditer(res.text): stream_url = match.group("url") if "\\/" in stream_url: # if the URL is json encoded, decode it stream_url = parse_json("\"{}\"".format(stream_url)) if ".mpd" in stream_url: yield from DASHStream.parse_manifest(self.session, stream_url).items() elif ".mp4" in stream_url: yield match.group(1), HTTPStream(self.session, stream_url) else: log.debug("Non-dash/mp4 stream: {0}".format(stream_url)) match = self._dash_manifest_re.search(res.text) if match: # facebook replaces "<" characters with the substring "\\x3C" manifest = match.group("manifest").replace("\\/", "/") manifest = bytes(unquote_plus(manifest), "utf-8").decode("unicode_escape") # Ignore unsupported manifests until DASH SegmentBase support is implemented if "SegmentBase" in manifest: log.error("Skipped DASH manifest with SegmentBase streams") else: yield from DASHStream.parse_manifest(self.session, manifest).items()
def _get_http_streams(self, info): name = QUALITY_MAP.get(info["_quality"], "vod") urls = info["_stream"] if not isinstance(info["_stream"], list): urls = [urls] for url in urls: stream = HTTPStream(self.session, update_scheme("https://", url)) yield name, stream
def _get_streams(self): channel = self.match.group("channel") vod_id = self.match.group("vod_id") is_group = self.match.group("is_group") if is_py3: adapter = TLSSecLevel1Adapter() self.session.http.mount("https://filmon.com", adapter) self.session.http.mount("https://www.filmon.com", adapter) self.session.http.mount("https://vms-admin.filmon.com/", adapter) # get cookies self.session.http.get(self.url) if vod_id: data = self.api.vod(vod_id) for _, stream in data["streams"].items(): if stream["url"].endswith(".m3u8"): streams = HLSStream.parse_variant_playlist(self.session, stream["url"]) if not streams: yield stream["quality"], HLSStream(self.session, stream["url"]) else: for s in streams.items(): yield s elif stream["url"].endswith(".mp4"): yield stream["quality"], HTTPStream(self.session, stream["url"]) else: log.error("Unsupported stream type") return else: if channel and not channel.isdigit(): _id = self.cache.get(channel) if _id is None: _id = self.session.http.get(self.url, schema=self._channel_id_schema) log.debug("Found channel ID: {0}".format(_id)) # do not cache a group url if _id and not is_group: self.cache.set(channel, _id, expires=self.TIME_CHANNEL) else: log.debug("Found cached channel ID: {0}".format(_id)) else: _id = channel if _id is None: raise PluginError("Unable to find channel ID: {0}".format(channel)) try: data = self.api.channel(_id) for stream in data["streams"]: yield stream["quality"], FilmOnHLS(self.session, channel=_id, quality=stream["quality"]) except Exception: if channel and not channel.isdigit(): self.cache.set(channel, None, expires=0) log.debug("Reset cached channel: {0}".format(channel)) raise
def _get_streams(self): self.session.set_option("ffmpeg-start-at-zero", True) self.session.http.headers.update({"Accept-Language": "en-US"}) done = False res = self.session.http.get(self.url) log.trace(f"{res.url}") for title in itertags(res.text, "title"): if title.text.startswith("Log into Facebook"): log.error("Video is not available, You must log in to continue.") return for s in self._parse_streams(res): done = True yield s if done: return # fallback on to playlist log.debug("Falling back to playlist regex") match = self._playlist_re.search(res.text) playlist = match and match.group(1) if playlist: match = self._plurl_re.search(playlist) if match: url = match.group(1) yield "sd", HTTPStream(self.session, url) return # fallback to tahoe player url log.debug("Falling back to tahoe player") video_id = self.match.group("video_id") url = self._TAHOE_URL.format(video_id) data = { "__a": 1, "__pc": self._DEFAULT_PC, "__rev": self._DEFAULT_REV, "fb_dtsg": "", } match = self._pc_re.search(res.text) if match: data["__pc"] = match.group(1) match = self._rev_re.search(res.text) if match: data["__rev"] = match.group(1) match = self._dtsg_re.search(res.text) if match: data["fb_dtsg"] = match.group(1) res = self.session.http.post( url, headers={"Content-Type": "application/x-www-form-urlencoded"}, data=urlencode(data).encode("ascii") ) for s in self._parse_streams(res): yield s
def get_streams(self, video_id): log.debug(f"Finding streams for video: {video_id}") player_url = self.URL_PLAYER.format( account_id=self.account_id, player_id=self.player_id, video_id=video_id ) policy_key = self.session.http.get( player_url, params={"videoId": video_id}, schema=validate.Schema( validate.transform(re.compile(r"""policyKey\s*:\s*(?P<q>['"])(?P<key>[\w-]+)(?P=q)""").search), validate.any(None, validate.get("key")) ) ) if not policy_key: raise PluginError("Could not find Brightcove policy key") log.debug(f"Found policy key: {policy_key}") self.session.http.headers.update({"Referer": player_url}) sources, self.title = self.session.http.get( self.URL_API.format(account_id=self.account_id, video_id=video_id), headers={"Accept": f"application/json;pk={policy_key}"}, schema=validate.Schema( validate.parse_json(), { "sources": [{ "src": validate.url(), validate.optional("type"): str, validate.optional("container"): str, validate.optional("height"): int, validate.optional("avg_bitrate"): int, }], validate.optional("name"): str, }, validate.union_get("sources", "name") ) ) for source in sources: if source.get("type") in ("application/vnd.apple.mpegurl", "application/x-mpegURL"): yield from HLSStream.parse_variant_playlist(self.session, source.get("src")).items() elif source.get("container") == "MP4": # determine quality name if source.get("height"): q = f"{source.get('height')}p" elif source.get("avg_bitrate"): q = f"{source.get('avg_bitrate') // 1000}k" else: q = "live" yield q, HTTPStream(self.session, source.get("src"))
def __json__(self): json = HTTPStream.__json__(self) if self.url_master: json["master"] = self.to_manifest_url() # Pretty sure HLS is GET only. del json["method"] del json["body"] return json
def _get_streams(self): try: data_url = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_find(".//*[@data-ctrl-player]"), validate.get("data-ctrl-player"), validate.transform(lambda s: s.replace("'", "\"")), validate.parse_json(), {"url": validate.text}, validate.get("url"))) except PluginError: return data_url = urljoin(self._URL_DATA_BASE, data_url) log.debug("Player URL: '{0}'", data_url) self.title, media = self.session.http.get( data_url, schema=validate.Schema( validate.parse_json(name="MEDIAINFO"), { "mc": { validate.optional("_title"): validate.text, "_mediaArray": [ validate.all( { "_mediaStreamArray": [ validate.all( { "_quality": validate.any( validate.text, int), "_stream": [validate.url()], }, validate.union_get( "_quality", ("_stream", 0))) ] }, validate.get("_mediaStreamArray"), validate.transform(dict)) ] } }, validate.get("mc"), validate.union_get("_title", ("_mediaArray", 0)))) if media.get("auto"): for s in HLSStream.parse_variant_playlist( self.session, media.get("auto")).items(): yield s else: for quality, stream in media.items(): yield self._QUALITY_MAP.get(quality, quality), HTTPStream( self.session, stream)
def _get_clips(self): try: (((sig, token), streams), (self.author, self.category), self.title) = self.api.clips(self.clip_name) except (PluginError, TypeError): return for quality, stream in streams: yield quality, HTTPStream( self.session, update_qsd(stream, { "sig": sig, "token": token }))
def _get_streams(self): channel = self.match.group("channel") self.session.http.headers.update({"Referer": self.url}) data = self.session.http.post( "https://wap-api.17app.co/api/v1/lives/{0}/viewers/alive".format( channel), data={"liveStreamID": channel}, schema=validate.Schema( validate.parse_json(), validate.any( { "rtmpUrls": [{ validate.optional("provider"): validate.any(int, None), "url": validate.url(path=validate.endswith(".flv")), }] }, { "errorCode": int, "errorMessage": str }, ), ), acceptable_status=(200, 403, 404, 420)) log.trace("{0!r}".format(data)) if data.get("errorCode"): log.error("{0} - {1}".format( data['errorCode'], data['errorMessage'].replace('Something wrong: ', ''))) return flv_url = data["rtmpUrls"][0]["url"] yield "live", HTTPStream(self.session, flv_url) if "wansu-" in flv_url: hls_url = flv_url.replace(".flv", "/playlist.m3u8") else: hls_url = flv_url.replace("live-hdl", "live-hls").replace(".flv", ".m3u8") s = HLSStream.parse_variant_playlist(self.session, hls_url) if not s: yield "live", HLSStream(self.session, hls_url) else: if len(s) == 1: for _n, _s in s.items(): yield "live", _s else: for _s in s.items(): yield _s
def _get_streams(self): docid = self.match.group(1) log.debug("Google Docs ID: {0}".format(docid)) res = self.session.http.get(self.api_url, params=dict(docid=docid)) data = dict(parse_qsl(res.text)) if data["status"] == "ok": fmts = dict([s.split('/')[:2] for s in data["fmt_list"].split(",")]) streams = [s.split('|') for s in data["fmt_stream_map"].split(",")] for qcode, url in streams: _, h = fmts[qcode].split("x") yield "{0}p".format(h), HTTPStream(self.session, url) else: log.error("{0} (ID: {1})".format(data["reason"], docid))
def _get_streams(self): video_id = self.match.group('video_id') if video_id is not None: # VOD live = False player_url = self.VOD_PLAYER_URL.format(video_id) else: # Live live = True player_url = self.LIVE_PLAYER_URL res = self.session.http.get(player_url) playlist = re.findall(self._playlist_re, res.text) index = 0 if not live: # Get the index for the video on the playlist match = self._vod_video_index_re.search(res.text) if match is None: return index = int(match.group('video_index')) if not playlist: return videos = self._video_schema.validate(playlist[index]) for video in videos: video_url = video['file'] # Ignore non-supported MSS streams if 'isml/Manifest' in video_url: continue try: if '.m3u8' in video_url: for stream in HLSStream.parse_variant_playlist( self.session, video_url).items(): yield stream elif '.mp4' in video_url: match = self._mp4_bitrate_re.match(video_url) if match is not None: bitrate = '%sk' % match.group('bitrate') else: bitrate = 'vod' yield bitrate, HTTPStream(self.session, video_url) except IOError as err: if '403 Client Error' in str(err): log.error( 'Failed to access stream, may be due to geo-restriction' ) raise