def get_live(self, id): res = self.session.http.get(self.live_api_url.format(id)) user_data = self.session.http.json(res, schema=self.live_schema) if user_data['channel']['is_streaming']: self.category = 'Live' stream_id = user_data['channel']['channel_id'] elif 'hostee' in user_data['channel']: self.category = 'Hosted by {}'.format( user_data["channel"]["hostee"]["nickname"]) stream_id = user_data['channel']['hostee']['channel_id'] else: log.info('User is offline') return self.author = user_data['user']['nickname'] self.title = user_data['channel']['name'] res = self.session.http.get(self.streams_api_url.format(stream_id)) streams = self.session.http.json(res, schema=validate.Schema({ "default_mirror": validate.text, "mirror_list": [{ "name": validate.text, "url_domain": validate.url(), }], "source_stream_url_path": validate.text, "stream_addr_list": [{ "resolution": validate.text, "url_path": validate.text, }], })) mirror = (next( filter(lambda item: item["name"] == streams["default_mirror"], streams["mirror_list"]), None) or next(iter(streams["mirror_list"]), None)) if not mirror: return auto = next( filter(lambda item: item["resolution"] == "Auto", streams["stream_addr_list"]), None) if auto: for s in HLSStream.parse_variant_playlist( self.session, urljoin(mirror["url_domain"], auto["url_path"])).items(): yield s if streams["source_stream_url_path"]: yield "source", HLSStream( self.session, urljoin(mirror["url_domain"], streams["source_stream_url_path"]))
def _get_streams(self): """ Find the streams for web.tv :return: """ headers = {} res = self.session.http.get(self.url, headers=headers) headers["Referer"] = self.url sources = self._sources_re.findall(res.text) if len(sources): sdata = parse_json(sources[0], schema=self._sources_schema) for source in sdata: log.debug(f"Found stream of type: {source['type']}") if source["type"] == "application/vnd.apple.mpegurl": url = update_scheme("https://", source["src"], force=False) try: # try to parse the stream as a variant playlist variant = HLSStream.parse_variant_playlist( self.session, url, headers=headers) if variant: yield from variant.items() else: # and if that fails, try it as a plain HLS stream yield 'live', HLSStream(self.session, url, headers=headers) except OSError: log.warning( "Could not open the stream, perhaps the channel is offline" )
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 _get_streams(self): res = self.session.http.get(self.url) m = self.epg_re.search(res.text) channel_id = m and m.group(1) if channel_id: log.debug("Channel ID: {0}".format(channel_id)) if channel_id == "332": # there is a special backup stream for channel 332 bk_res = self.session.http.get(self.backup_332_api) bk_data = self.session.http.json(bk_res) if bk_data and bk_data["backup"]: log.info("Using backup stream for channel 332") return HLSStream.parse_variant_playlist(self.session, self.backup_332_stream) api_res = self.session.http.post(self.api_url, headers={"Content-Type": 'application/json'}, data=json.dumps(dict(channelno=channel_id, mode="prod", audioCode="", format="HLS", callerReferenceNo="20140702122500"))) data = self.session.http.json(api_res) for stream_url in data.get("asset", {}).get("hls", {}).get("adaptive", []): return HLSStream.parse_variant_playlist(self.session, stream_url)
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): api_urls = self.session.http.get(self.url, schema=self.channel_id_schema) _api_url = list(api_urls)[0] log.debug("API URL: {0}".format(_api_url)) player_api_url = self.session.http.get(_api_url, schema=self.player_api_schema) for api_url in player_api_url: log.debug("Player API URL: {0}".format(api_url)) for source in self.session.http.get(api_url, schema=self.stream_schema): log.debug("Stream source: {0} ({1})".format( source['src'], source.get("type", "n/a"))) if "type" not in source or source[ "type"] == "application/vnd.apple.mpegurl": streams = HLSStream.parse_variant_playlist( self.session, source["src"]) if not streams: yield "live", HLSStream(self.session, source["src"]) else: yield from streams.items() elif source["type"] == "application/dash+xml": yield from DASHStream.parse_manifest( self.session, source["src"]).items()
def test_hls_stream_master(session, common_args): stream = HLSStream(session, "http://host/stream.m3u8?foo=bar", "http://host/master.m3u8?foo=bar", **common_args) assert stream.to_url( ) == "http://host/stream.m3u8?foo=bar&queryparamkey=queryparamval" assert stream.to_manifest_url( ) == "http://host/master.m3u8?foo=bar&queryparamkey=queryparamval"
def test_repr(self): session = Streamlink() stream = HLSStream(session, "https://foo.bar/playlist.m3u8") self.assertEqual(repr(stream), "<HLSStream ['hls', 'https://foo.bar/playlist.m3u8']>") stream = HLSStream(session, "https://foo.bar/playlist.m3u8", "https://foo.bar/master.m3u8") self.assertEqual(repr(stream), "<HLSStream ['hls', 'https://foo.bar/playlist.m3u8', 'https://foo.bar/master.m3u8']>")
def test_hls_stream(session, common_args): stream = HLSStream(session, "http://host/stream.m3u8?foo=bar", **common_args) assert stream.to_url( ) == "http://host/stream.m3u8?foo=bar&queryparamkey=queryparamval" with pytest.raises(TypeError) as cm: stream.to_manifest_url() assert str( cm.value) == "<HLSStream [hls]> cannot be translated to a manifest URL"
def test_hls_stream(session, common_args, expected_headers): stream = HLSStream(session, "http://host/stream.m3u8?foo=bar", **common_args) assert stream.__json__() == { "type": "hls", "url": "http://host/stream.m3u8?foo=bar&sessionqueryparamkey=sessionqueryparamval&queryparamkey=queryparamval", "headers": expected_headers, }
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): api = self._create_api() media_id = int(self.match.group("media_id")) try: # the media.stream_data field is required, no stream data is returned otherwise info = api.get_info(media_id, fields=[ "media.name", "media.series_name", "media.media_type", "media.stream_data" ], schema=_media_schema) except CrunchyrollAPIError as err: raise PluginError(f"Media lookup error: {err.msg}") if not info: return streams = {} self.title = info.get("name") self.author = info.get("series_name") self.category = info.get("media_type") info = info["stream_data"] # The adaptive quality stream sometimes a subset of all the other streams listed, ultra is no included has_adaptive = any( [s["quality"] == "adaptive" for s in info["streams"]]) if has_adaptive: log.debug("Loading streams from adaptive playlist") for stream in filter(lambda x: x["quality"] == "adaptive", info["streams"]): for q, s in HLSStream.parse_variant_playlist( self.session, stream["url"]).items(): # rename the bitrates to low, mid, or high. ultra doesn't seem to appear in the adaptive streams name = STREAM_NAMES.get(q, q) streams[name] = s # If there is no adaptive quality stream then parse each individual result for stream in info["streams"]: if stream["quality"] != "adaptive": # the video_encode_id indicates that the stream is not a variant playlist if "video_encode_id" in stream: streams[stream["quality"]] = HLSStream( self.session, stream["url"]) else: # otherwise the stream url is actually a list of stream qualities for q, s in HLSStream.parse_variant_playlist( self.session, stream["url"]).items(): # rename the bitrates to low, mid, or high. ultra doesn't seem to appear in the adaptive streams name = STREAM_NAMES.get(q, q) streams[name] = s return streams
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)) streams = HLSStream.parse_variant_playlist(self.session, url, **params) return streams if streams else { "live": HLSStream(self.session, url, **params) }
def _get_streams(self): channel = self.match.group('channel') res = self.session.http.get(self.api_url.format(channel)) hls_url = self.session.http.json(res, schema=self._data_schema) log.debug('URL={0}'.format(hls_url)) streams = HLSStream.parse_variant_playlist(self.session, hls_url) if not streams: return {'live': HLSStream(self.session, hls_url)} else: return streams
def _get_streams(self): live_url = self._get_live_url() if not live_url: log.info("This stream may be off-air or not available in your country") return if self._is_token_based_site(): token = self._get_token() if not token: return return HLSStream.parse_variant_playlist(self.session, update_qsd(live_url, {"iut": token})) else: return HLSStream.parse_variant_playlist(self.session, live_url)
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): res = self.session.http.get(self.url) m = self._hls_re.search(res.text) if not m: log.debug('No video URL found.') return hls_url = m.group('url') log.debug('URL={0}'.format(hls_url)) streams = HLSStream.parse_variant_playlist(self.session, hls_url) if not streams: return {'live': HLSStream(self.session, hls_url)} else: return streams
def _get_streams(self): channel = self.match.group("channel") self.session.http.headers.update({ 'User-Agent': useragents.CHROME, 'Referer': self.url }) data = '{"liveStreamID":"%s"}' % (channel) try: res = self.session.http.post(self.API_URL.format(channel), data=data) res_json = self.session.http.json(res, schema=self._api_schema) log.trace("{0!r}".format(res_json)) http_url = res_json[0]["url"] except Exception as e: log.info("Stream currently unavailable.") log.debug(str(e)) return https_url = http_url.replace("http:", "https:") yield "live", HTTPStream(self.session, https_url) if 'pull-rtmp' in http_url: rtmp_url = http_url.replace("http:", "rtmp:").replace(".flv", "") stream = RTMPStream(self.session, { "rtmp": rtmp_url, "live": True, "pageUrl": self.url, }) yield "live", stream if 'wansu-' in http_url: hls_url = http_url.replace(".flv", "/playlist.m3u8") else: hls_url = http_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: yield from s.items()
def _get_streams(self): try: self._login() except Exception as e: raise PluginError("SPWN login failed") from e m = self._URL_RE.match(self.url) eid = m.group("eid") event_info = self._get_event_data(eid) self.title = event_info.get("title", eid) log.info(f"Found SPWN event: {self.title}") stream_info = self._get_streaming_key(eid) if stream_info.get("isError"): raise PluginError("Error fetching stream info from SPWN API") cookies = stream_info.get("cookies") if not cookies: if not stream_info.get("hasTickets"): log.error("You do not have a ticket for this event") return msg = stream_info.get("msg", "") log.info(f"No available stream for this event: {msg}") return video_id = stream_info.get("videoIds", []).pop() info = cookies.get(video_id, {}).get("default", {}) for k, v in info.get("cookie", {}).items(): cookie = requests.cookies.create_cookie(k, v) self.session.http.cookies.set_cookie(cookie) url = info.get("url") if not url: raise PluginError(f"No stream URL for {video_id}") return HLSStream.parse_variant_playlist(self.session, url)
def _get_streams(self): res = self.session.http.get(self.url) m = self._re_channel_id.search(res.text) if not m: return res = self.session.http.get( "https://www.rtvs.sk/json/live5f.json", params={ "c": m.group(1), "b": "mozilla", "p": "win", "f": "0", "d": "1", } ) videos = parse_json(res.text, schema=validate.Schema({ "clip": { "sources": [{ "src": validate.url(), "type": str, }], }}, validate.get(("clip", "sources")), validate.filter(lambda n: n["type"] == "application/x-mpegurl"), )) for video in videos: yield from HLSStream.parse_variant_playlist(self.session, video["src"]).items()
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 _get_streams(self): api_url = self.session.http.get(self.url, schema=self._data_content_schema) if api_url and (api_url.startswith("/") or api_url.startswith("http")): api_url = urljoin(self.url, api_url) stream_url = self.session.http.get(api_url, schema=self._api_schema, headers={"Referer": self.url}) elif api_url and api_url.startswith("[{"): stream_url = self._api_schema.validate(api_url) else: if api_url is not None: log.error( "_data_content_schema returns invalid data: {0}".format( api_url)) return parsed = urlparse(stream_url) api_url = urljoin( self.url, self._token_api_path.format(url=stream_url, netloc="{0}://{1}".format( parsed.scheme, parsed.netloc), time=int(time()))) stream_url = self.session.http.get(api_url, schema=self._stream_schema, headers={"Referer": self.url}) return HLSStream.parse_variant_playlist(self.session, stream_url)
def mediaselector(self, vpid): urls = defaultdict(set) for platform in self.platforms: url = self.api_url.format(vpid=vpid, vpid_hash=self._hash_vpid(vpid), platform=platform) log.debug(f"Info API request: {url}") medias = self.session.http.get(url, schema=self.mediaselector_schema) for media in medias: for connection in media["connection"]: urls[connection.get("transferFormat")].add( connection["href"]) for stream_type, urls in urls.items(): log.debug(f"{len(urls)} {stream_type} streams") for url in list(urls): try: if stream_type == "hls": yield from HLSStream.parse_variant_playlist( self.session, url).items() if stream_type == "dash": yield from DASHStream.parse_manifest( self.session, url).items() log.debug(f" OK: {url}") except Exception: log.debug(f" FAIL: {url}")
def _get_streams(self): hls_url = self.session.http.get(self.url, schema=validate.Schema( validate.transform(self._re_hls.search), validate.any(None, validate.get("hls_url")) )) if hls_url is not None: return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): postdata = { "clientID": self.match.group(1), "showEncoder": True, "showMediaAssets": True, "showStreams": True, "includePrivate": False, "advancedDetails": True, "VAST": True, "eventID": self.match.group(2) } headers = { "Content-Type": "application/json", "wsc-api-key": self.WSC_API_KEY, "Authorization": "embedder" } res = self.session.http.post(self.API_URL, data=json.dumps(postdata), headers=headers) api_response = self.session.http.json(res, schema=self.api_response_schema) if api_response is None: return hls_url = api_response["data"]["streamingURIs"]["main"] return HLSStream.parse_variant_playlist( self.session, update_scheme("https://", hls_url))
def _get_streams_live(self): log.debug("Getting live HLS streams for {0}".format(self.channel)) try: data = json.dumps({ "query": """query {{ userByDisplayName(displayname:"{displayname}") {{ livestream {{ title }} username }} }}""".format(displayname=self.channel) }) res = self.session.http.post("https://graphigo.prd.dlive.tv/", data=data) res = self.session.http.json(res, schema=self._schema_userByDisplayName) if res["livestream"] is None: return except PluginError: return self.author = self.channel self.title = res["livestream"]["title"] hls_url = "https://live.prd.dlive.tv/hls/live/{0}.m3u8".format( res["username"]) return HLSStream.parse_variant_playlist(self.session, hls_url)
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_streams(self, video_id): data = self.session.http.get( "https://cloudac.mildom.com/nonolive/videocontent/playback/getPlaybackDetail", params={ "__platform": "web", "v_id": video_id, }, schema=validate.Schema( validate.parse_json(), { "code": int, validate.optional("message"): str, validate.optional("body"): { "playback": { "video_link": [{ "name": str, "url": validate.url() }], }, }, })) log.trace(f"{data!r}") if data["code"] != 0: log.debug(data.get("message", "Mildom API returned an error")) return for stream in data["body"]["playback"]["video_link"]: yield stream["name"], HLSStream(self.session, stream["url"])
def _get_streams(self): nickname = self.match.group('nickname') res = self.session.http.get(f'https://wasd.tv/api/channels/nicknames/{nickname}') channel_id = self.session.http.json(res, schema=self._api_nicknames_schema) res = self.session.http.get( 'https://wasd.tv/api/v2/media-containers', params={ 'media_container_status': 'RUNNING', 'limit': '1', 'offset': '0', 'channel_id': channel_id, 'media_container_type': 'SINGLE,COOP', } ) json_res = self.session.http.json(res, schema=self._api_schema) log.trace('{0!r}'.format(json_res)) if not json_res: raise PluginError('No data returned from URL={0}'.format(res.url)) for stream in json_res['media_container_streams']: log.debug('media_container_status: {0}, media_container_online_status: {1}'.format( json_res['media_container_status'], json_res['media_container_online_status'])) for stream in stream['stream_media']: if stream['media_status'] == 'STOPPED': hls_url = stream['media_meta']['media_archive_url'] elif stream['media_status'] == 'RUNNING': hls_url = stream['media_meta']['media_url'] yield from HLSStream.parse_variant_playlist(self.session, hls_url).items()
def _get_streams(self): video_id = self.session.http.get(self.url, schema=self.json_data_schema) if video_id is None: return log.debug('API ID: {0}'.format(video_id)) api_url = self.api_url.format(video_id) stream = self.session.http.get(api_url, schema=self.api_schema) log.trace('{0!r}'.format(stream)) if stream['type'].lower() != 'live': log.error('Invalid stream type "{0}"'.format(stream['type'])) return json_post_data = { 'requestorId': 'nbcnews', 'pid': video_id, 'application': 'NBCSports', 'version': 'v1', 'platform': 'desktop', 'token': '', 'resourceId': '', 'inPath': 'false', 'authenticationType': 'unauth', 'cdn': 'akamai', 'url': stream['sourceUrl'], } url = self.session.http.post( self.token_url, json=json_post_data, schema=self.token_schema, ) return HLSStream.parse_variant_playlist(self.session, url)