class RTPPlay(Plugin): _m3u8_re = re.compile( r""" hls:\s*(?:(["'])(?P<string>[^"']+)\1 | decodeURIComponent\((?P<obfuscated>\[.*?])\.join\() """, re.VERBOSE) _schema_hls = validate.Schema( validate.transform(_m3u8_re.search), validate.any( None, validate.all(validate.get("string"), validate.text, validate.any(validate.length(0), validate.url())), validate.all(validate.get("obfuscated"), validate.text, validate.parse_json(), validate.transform(lambda arr: unquote("".join(arr))), validate.url()), validate.all( validate.get("obfuscated_b64"), validate.text, validate.parse_json(), validate.transform(lambda arr: unquote("".join(arr))), validate.transform(lambda b64: b64decode(b64).decode("utf-8")), validate.url()))) def _get_streams(self): self.session.http.headers.update({ "User-Agent": useragents.CHROME, "Referer": self.url }) hls_url = self.session.http.get(self.url, schema=self._schema_hls) if not hls_url: return return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): url = self.session.http.get( "https://stream.1tv.ru/api/playlist/1tvch_as_array.json", data={"r": random.randint(1, 100000)}, schema=validate.Schema( validate.parse_json(), {"hls": [validate.url()]}, validate.get("hls"), validate.get(0), )) if not url: return if "georestrictions" in url: log.error("Stream is geo-restricted") return hls_session = self.session.http.get( "https://stream.1tv.ru/get_hls_session", schema=validate.Schema( validate.parse_json(), {"s": validate.transform(unquote)}, )) url = update_qsd(url, qsd=hls_session, safe="/:") yield from HLSStream.parse_variant_playlist(self.session, url, name_fmt="{pixels}_{bitrate}").items()
def _get_live_streams(self): video_id = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//div[@data-google-src]/@data-video-id"))) if video_id: return self.session.streams( f"https://www.youtube.com/watch?v={video_id}") info_url = self.session.http.get( self.API_URL.format(subdomain=self.match.group("subdomain")), schema=validate.Schema( validate.parse_json(), {"url": validate.url()}, validate.get("url"), validate.transform( lambda url: update_scheme("https://", url)))) hls_url = self.session.http.get(info_url, schema=validate.Schema( validate.parse_json(), { "status": "ok", "protocol": "hls", "primary": validate.url() }, validate.get("primary"))) return HLSStream.parse_variant_playlist(self.session, hls_url)
def _hello(self): log.debug('_hello ...') app_token = self.session.http.get( '{0}/token.json'.format(self.base_url), schema=validate.Schema(validate.parse_json(), { 'success': bool, 'session_token': validate.text, }, validate.get('session_token'))) if self._uuid: __uuid = self._uuid else: __uuid = str(uuid.uuid4()) self._session_attributes.set('uuid', __uuid, expires=self.TIME_SESSION) params = { 'app_version': '3.2120.1', 'client_app_token': app_token, 'format': 'json', 'lang': 'en', 'uuid': __uuid, } res = self.session.http.post( '{0}/zapi/v3/session/hello'.format(self.base_url), headers=self.headers, data=params, schema=validate.Schema( validate.parse_json(), validate.any({'active': bool}, {'success': bool}))) if res.get('active') or res.get('success'): log.debug('Hello was successful.') else: log.debug('Hello failed.')
class OlympicChannel(Plugin): _token_api_path = "/tokenGenerator?url={url}&domain={netloc}&_ts={time}" _api_schema = validate.Schema( validate.parse_json(), [{ validate.optional("src"): validate.url(), validate.optional("srcType"): "HLS", }], validate.transform(lambda v: v[0].get("src")), ) _data_url_re = re.compile(r'data-content-url="([^"]+)"') _data_content_re = re.compile( r'data-d3vp-plugin="THEOplayer"\s*data-content="([^"]+)"') _data_content_schema = validate.Schema( validate.any( validate.all( validate.transform(_data_url_re.search), validate.any(None, validate.get(1)), ), validate.all( validate.transform(_data_content_re.search), validate.any(None, validate.get(1)), ), ), validate.any(None, validate.transform(html_unescape)), ) _stream_schema = validate.Schema( validate.parse_json(), validate.url(), ) 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)
class AtresPlayer(Plugin): state_re = re.compile(r"""window.__PRELOADED_STATE__\s*=\s*({.*?});""", re.DOTALL) channel_id_schema = validate.Schema( validate.transform(state_re.search), validate.any( None, validate.all( validate.get(1), validate.parse_json(), validate.transform(search_dict, key="href"), ))) player_api_schema = validate.Schema( validate.any( None, validate.all( validate.parse_json(), validate.transform(search_dict, key="urlVideo"), ))) stream_schema = validate.Schema( validate.parse_json(), { "sources": [ validate.all({ "src": validate.url(), validate.optional("type"): validate.text }) ] }, validate.get("sources")) def __init__(self, url): # must be HTTPS super().__init__(update_scheme("https://", url)) 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 _get_streams(self): re_room_id = re.compile( r"share_url:\"https:[^?]+?\?room_id=(?P<room_id>\d+)\"") room_id = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//script[contains(text(),'share_url:\"https:')][1]/text()" ), validate.any( None, validate.all(validate.transform(re_room_id.search), validate.any(None, validate.get("room_id")))))) if not room_id: return live_status, self.title = self.session.http.get( "https://www.showroom-live.com/api/live/live_info", params={"room_id": room_id}, schema=validate.Schema( validate.parse_json(), { "live_status": int, "room_name": str, }, validate.union_get( "live_status", "room_name", ))) if live_status != self.LIVE_STATUS: log.info("This stream is currently offline") return url = self.session.http.get( "https://www.showroom-live.com/api/live/streaming_url", params={ "room_id": room_id, "abr_available": 1, }, schema=validate.Schema( validate.parse_json(), { "streaming_url_list": [{ "type": str, "url": validate.url(), }] }, validate.get("streaming_url_list"), validate.filter(lambda p: p["type"] == "hls_all"), validate.get((0, "url"))), ) res = self.session.http.get(url, acceptable_status=(200, 403, 404)) if res.headers["Content-Type"] != "application/x-mpegURL": log.error("This stream is restricted") return return HLSStream.parse_variant_playlist(self.session, url)
def test_parse_json(self): assert validate(parse_json(), '{"a": ["b", true, false, null, 1, 2.3]}') == { "a": ["b", True, False, None, 1, 2.3] } with self.assertRaises(ValueError) as cm: validate(parse_json(), "invalid") assert str( cm.exception ) == "Unable to parse JSON: Expecting value: line 1 column 1 (char 0) ('invalid')"
def get_vod(self, vod_id): vod_data = self.session.http.get( f"https://aloula.faulio.com/api/v1/video/{vod_id}", acceptable_status=(200, 401), schema=validate.Schema( validate.parse_json(), validate.any( validate.all( { "blocks": [{ "id": str, "program_title": str, "title": str, "season_number": int, "episode": int, }] }, validate.get(("blocks", 0)), ), { "cms_error": str, "message": str }, ), ), ) log.trace(f"{vod_data!r}") if "cms_error" in vod_data and vod_data["cms_error"] == "auth": log.error( "This stream requires a login; specify appropriate Authorization and profile HTTP headers" ) return if "cms_error" in vod_data: log.error( f"API error: {vod_data['cms_error']} ({vod_data['message']})") return self.id = vod_data["id"] self.author = vod_data["program_title"] self.title = vod_data["title"] self.category = f"S{vod_data['season_number']}E{vod_data['episode']}" hls_url = self.session.http.get( f"https://aloula.faulio.com/api/v1/video/{vod_id}/player", schema=validate.Schema( validate.parse_json(), {"settings": { "protocols": { "hls": validate.url() } }}, validate.get(("settings", "protocols", "hls")), ), ) return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): params = self.session.http.get( self.url, schema=validate.Schema( validate.transform(self._re_player_manager.search), validate.any( None, validate.all( validate.get("json"), validate.parse_json(), { "contentId": validate.any(str, int), validate.optional("streamId"): str, validate.optional("idec"): str, validate.optional("token"): str })))) if not params: log.error("Could not find player manager data") return params.update({ "video": (unquote(params.pop("token")) if params.get("token") is not None else params.pop("streamId")), "noflash": "yes", "embedded": "0", }) url_parsed = urlparse(self.url) skip_vods = url_parsed.netloc.endswith( "m4sport.hu") and url_parsed.path.startswith("/elo") self.session.http.headers.update({"Referer": self.url}) playlists = self.session.http.get( self.PLAYER_URL, params=params, schema=validate.Schema( validate.transform(self._re_player_json.search), validate.any( None, validate.all( validate.get("json"), validate.parse_json(), {"playlist": [{ "file": validate.url(), "type": str }]}, validate.get("playlist"), validate.filter(lambda p: p["type"] == "hls"), validate.filter( lambda p: not skip_vods or "vod" not in p["file"]), validate.map( lambda p: update_scheme("https://", p["file"])))))) for url in playlists or []: yield from HLSStream.parse_variant_playlist(self.session, url).items()
def _get_streams(self): self.session.http.headers.update( {"Referer": "https://tviplayer.iol.pt/"}) data = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//script[contains(text(),'.m3u8')]/text()"), validate.text, validate.transform(self._re_jsonData.search), validate.any( None, validate.all( validate.get("json"), validate.parse_json(), { "id": validate.text, "liveType": validate.text, "videoType": validate.text, "videoUrl": validate.url(path=validate.endswith(".m3u8")), validate.optional("channel"): validate.text, })))) if not data: return log.debug("{0!r}".format(data)) if data["liveType"].upper() == "DIRETO" and data["videoType"].upper( ) == "LIVE": geo_path = "live" else: geo_path = "vod" data_geo = self.session.http.get( "https://services.iol.pt/direitos/rights/{0}?id={1}".format( geo_path, data['id']), acceptable_status=(200, 403), schema=validate.Schema( validate.parse_json(), { "code": validate.text, "error": validate.any(None, validate.text), "detail": validate.text, })) log.debug("{0!r}".format(data_geo)) if data_geo["detail"] != "ok": log.error("{0}".format(data_geo['detail'])) return wmsAuthSign = self.session.http.get( "https://services.iol.pt/matrix?userId=", schema=validate.Schema(validate.text)) hls_url = update_qsd(data["videoUrl"], {"wmsAuthSign": wmsAuthSign}) return HLSStream.parse_variant_playlist(self.session, hls_url)
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_streams(self): channel = self.match.group("channel") channels = [ # ((channels), (path, channel)) (("5-tv", "tv-5", "5tv"), ("tv5", "tv-5")), (("chetv", "ctc-che", "che_ext"), ("ctc", "ctc-che")), (("ctc"), ("ctc", "ctc")), (("ctclove", "ctc-love", "ctc_love_ext"), ("ctc", "ctc-love")), (("domashniy", "ctc-dom", "domashniy_ext"), ("ctc", "ctc-dom")), (("iz"), ("iz", "iz")), (("mir"), ("mtrkmir", "mir")), (("muztv"), ("muztv", "muztv")), (("ren", "ren-tv", "rentv"), ("nmg", "ren-tv")), (("russia1"), ("vgtrk", "russia1")), (("russia24"), ("vgtrk", "russia24")), (("russiak", "kultura"), ("vgtrk", "russiak")), (("spas"), ("spas", "spas")), (("tvc"), ("tvc", "tvc")), (("tvzvezda", "zvezda"), ("zvezda", "zvezda")), (("u", "u_ott"), ("utv", "u_ott")), ] for c in channels: if channel in c[0]: path, channel = c[1] break else: log.error(f"Unsupported channel: {channel}") return res_token = self.session.http.get( "https://media.mediavitrina.ru/get_token", schema=validate.Schema( validate.parse_json(), {"result": {"token": str}}, validate.get("result"), )) url = self.session.http.get( update_qsd(f"https://media.mediavitrina.ru/api/v2/{path}/playlist/{channel}_as_array.json", qsd=res_token), schema=validate.Schema( validate.parse_json(), {"hls": [validate.url()]}, validate.get("hls"), validate.get(0), )) if not url: return if "georestrictions" in url: log.error("Stream is geo-restricted") return yield from HLSStream.parse_variant_playlist(self.session, url, name_fmt="{pixels}_{bitrate}").items()
def __init__(self, url: str): super().__init__(url) self._json_data_re = re.compile(r'teliaPlayer\((\{.*?\})\);', re.DOTALL) self.main_page_schema = validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//iframe[contains(@src, 'ltv.lsm.lv/embed')][1]/@src"), validate.url()) self.embed_code_schema = validate.Schema( validate.parse_html(), validate.xml_xpath_string(".//live[1]/@*[name()=':embed-data']"), str, validate.parse_json(), {"source": { "embed_code": str }}, validate.get(("source", "embed_code")), validate.parse_html(), validate.xml_xpath_string(".//iframe[@src][1]/@src"), ) self.player_apicall_schema = validate.Schema( validate.transform(self._json_data_re.search), validate.any( None, validate.all( validate.get(1), validate.transform(lambda s: s.replace("'", '"')), validate.transform( lambda s: re.sub(r",\s*\}", "}", s, flags=re.DOTALL)), validate.parse_json(), {"channel": str}, validate.get("channel")))) self.sources_schema = validate.Schema( validate.parse_json(), { "source": { "sources": validate.all([{ "type": str, "src": validate.url() }], validate.filter(lambda src: src["type"] == "application/x-mpegURL"), validate.map(lambda src: src.get("src"))), } }, validate.get(("source", "sources")))
def _get_streams(self): data = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//script[@id='js-live-data'][@data-json]/@data-json"), validate.any( None, validate.all( validate.parse_json(), { "is_live": int, "room_id": int, validate.optional("room"): { "content_region_permission": int, "is_free": int } }, )))) if not data: # URL without livestream return log.debug(f"{data!r}") if data["is_live"] != 1: log.info("This stream is currently offline") return url = self.session.http.get( "https://www.showroom-live.com/api/live/streaming_url", params={ "room_id": data["room_id"], "abr_available": 1 }, schema=validate.Schema( validate.parse_json(), { "streaming_url_list": [{ "type": str, "url": validate.url(), }] }, validate.get("streaming_url_list"), validate.filter(lambda p: p["type"] == "hls_all"), validate.get((0, "url"))), ) res = self.session.http.get(url, acceptable_status=(200, 403, 404)) if res.headers["Content-Type"] != "application/x-mpegURL": log.error("This stream is restricted") return return ShowroomHLSStream.parse_variant_playlist(self.session, url)
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): email = self.get_option('email') password = self.get_option('password') if self.options.get('purge_credentials'): self.reset_session() log.info('All credentials were successfully removed.') elif (self._authed and not self._session_control): # check every two hours, if the session is actually valid log.debug('Session control for {0}'.format(self.domain)) active = self.session.http.get( f'{self.base_url}/zapi/v3/session', schema=validate.Schema(validate.parse_json(), {'active': bool}, validate.get('active')) ) if active: self._session_attributes.set( 'session_control', True, expires=self.TIME_CONTROL) log.debug('User is logged in') else: log.debug('User is not logged in') self._authed = False if not self._authed and (not email and not password): log.error( 'A login for Zattoo is required, use --zattoo-email EMAIL' ' --zattoo-password PASSWORD to set them') return if not self._authed: self._hello() self._login(email, password) if self._authed: return self._watch()
def _login(self, email, password): log.debug('_login ...') data = self.session.http.post( f'{self.base_url}/zapi/v3/account/login', headers=self.headers, data={ 'login': email, 'password': password, 'remember': 'true', 'format': 'json', }, acceptable_status=(200, 400), schema=validate.Schema(validate.parse_json(), validate.any( {'active': bool, 'power_guide_hash': str}, {'success': bool}, )), ) if data.get('active'): log.debug('Login was successful.') else: log.debug('Login failed.') return self._authed = data['active'] self.save_cookies(default_expires=self.TIME_SESSION) self._session_attributes.set('power_guide_hash', data['power_guide_hash'], expires=self.TIME_SESSION) self._session_attributes.set( 'session_control', True, expires=self.TIME_CONTROL)
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_live(self, live_slug): live_data = self.session.http.get( "https://aloula.faulio.com/api/v1/channels", schema=validate.Schema( validate.parse_json(), [{ "id": int, "url": str, "title": str, "has_live": bool, "has_vod": bool, "streams": { "hls": validate.url(), }, }], validate.filter(lambda k: k["url"] == live_slug), ), ) if not live_data: return live_data = live_data[0] log.trace(f"{live_data!r}") if not live_data["has_live"]: log.error("Stream is not live") return self.id = live_data["id"] self.author = "SBA" self.title = live_data["title"] self.category = "Live" return HLSStream.parse_variant_playlist(self.session, live_data["streams"]["hls"])
class VTVgo(Plugin): AJAX_URL = 'https://vtvgo.vn/ajax-get-stream' _params_re = re.compile( r'''var\s+(?P<key>(?:type_)?id|time|token)\s*=\s*["']?(?P<value>[^"']+)["']?;''' ) _schema_params = validate.Schema( validate.transform(lambda html: next(tag.text for tag in itertags( html, "script") if "setplayer(" in tag.text)), validate.transform(_params_re.findall), [("id", int), ("type_id", str), ("time", str), ("token", str)]) _schema_stream_url = validate.Schema(validate.parse_json(), {"stream_url": [validate.url()]}, validate.get("stream_url"), validate.get(0)) def _get_streams(self): self.session.http.headers.update({ 'Origin': 'https://vtvgo.vn', 'Referer': self.url, 'X-Requested-With': 'XMLHttpRequest', }) params = self.session.http.get(self.url, schema=self._schema_params) log.trace('{0!r}'.format(params)) hls_url = self.session.http.post(self.AJAX_URL, data=dict(params), schema=self._schema_stream_url) return HLSStream.parse_variant_playlist(self.session, hls_url)
class CNEWS(Plugin): _json_data_re = re.compile(r'jQuery\.extend\(Drupal\.settings, ({.*})\);') _dailymotion_url = 'https://www.dailymotion.com/embed/video/{}' _data_schema = validate.Schema( validate.transform(_json_data_re.search), validate.any( None, validate.all( validate.get(1), validate.parse_json(), { validate.optional('dm_player_live_dailymotion'): { validate.optional('video_id'): str, }, validate.optional('dm_player_node_dailymotion'): { validate.optional('video_id'): str, }, }, )), ) def _get_streams(self): data = self.session.http.get(self.url, schema=self._data_schema) if 'dm_player_node_dailymotion' in data: return self.session.streams( self._dailymotion_url.format( data['dm_player_node_dailymotion']['video_id'])) elif 'dm_player_live_dailymotion' in data: return self.session.streams( self._dailymotion_url.format( data['dm_player_live_dailymotion']['video_id']))
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"])
class RaiPlay(Plugin): _re_data = re.compile(r"data-video-json\s*=\s*\"([^\"]+)\"") _schema_data = validate.Schema( validate.transform(_re_data.search), validate.any(None, validate.get(1)) ) _schema_json = validate.Schema( validate.parse_json(), validate.get("video"), validate.get("content_url"), validate.url() ) def _get_streams(self): json_url = self.session.http.get(self.url, schema=self._schema_data) if not json_url: return json_url = urlunparse(urlparse(self.url)._replace(path=json_url)) log.debug("Found JSON URL: {0}".format(json_url)) stream_url = self.session.http.get(json_url, schema=self._schema_json) log.debug("Found stream URL: {0}".format(stream_url)) res = self.session.http.request("HEAD", stream_url) # status code will be 200 even if geo-blocked, so check the returned content-type if not res or not res.headers or res.headers["Content-Type"] == "video/mp4": log.error("Geo-restricted content") return for stream in HLSStream.parse_variant_playlist(self.session, stream_url).items(): yield stream
def get_wss_api_url(self): try: data = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_find( ".//script[@id='embedded-data'][@data-props]"), validate.get("data-props"), validate.parse_json(), { "site": { "relive": { "webSocketUrl": validate.url(scheme="wss") }, validate.optional("frontendId"): int } }, validate.get("site"), validate.union_get(("relive", "webSocketUrl"), "frontendId"))) except PluginError: return wss_api_url, frontend_id = data if frontend_id is not None: wss_api_url = update_qsd(wss_api_url, {"frontend_id": frontend_id}) return wss_api_url
def encrypt_password(self, email, password): """ Get the RSA key for the user and encrypt the users password :param email: steam account :param password: password for account :return: encrypted password """ rsadata = self.session.http.get( self._get_rsa_key_url, params=dict(username=email, donotcache=str(int(time.time() * 1000))), schema=validate.Schema( validate.parse_json(), { "publickey_exp": validate.all(str, validate.transform(lambda x: int(x, 16))), "publickey_mod": validate.all(str, validate.transform(lambda x: int(x, 16))), "success": True, "timestamp": str, "token_gid": str })) rsa = RSA.construct( (rsadata["publickey_mod"], rsadata["publickey_exp"])) cipher = PKCS1_v1_5.new(rsa) return base64.b64encode(cipher.encrypt( password.encode("utf8"))), rsadata["timestamp"]
def _get_streams_delfi(self, src): try: data = self.session.http.get(src, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string(".//script[contains(text(),'embedJs.setAttribute(')][1]/text()"), validate.any(None, validate.all( validate.text, validate.transform(re.compile(r"embedJs\.setAttribute\('src',\s*'(.+?)'").search), validate.any(None, validate.all( validate.get(1), validate.transform(lambda url: parse_qsd(urlparse(url).fragment)), {"stream": validate.text}, validate.get("stream"), validate.parse_json(), {"versions": [{ "hls": validate.text }]}, validate.get("versions") )) )) )) except PluginError: log.error("Failed to get streams from iframe") return for stream in data: src = update_scheme("https://", stream["hls"], force=False) for s in HLSStream.parse_variant_playlist(self.session, src).items(): yield s
def _get_streams_api(self, video_id): log.debug("Found video ID: {0}".format(video_id)) tld = self.match.group("tld") try: data = self.session.http.get( self._api.get(tld, "lt"), params=dict(video_id=video_id), schema=validate.Schema( validate.parse_json(), { "success": True, "data": { "versions": { validate.text: validate.all( [{ "type": validate.text, "src": validate.text, }], validate.filter(lambda item: item["type"] == "application/x-mpegurl") ) } } }, validate.get(("data", "versions")) ) ) except PluginError: log.error("Failed to get streams from API") return for stream in itertools.chain(*data.values()): src = update_scheme("https://", stream["src"], force=False) for s in HLSStream.parse_variant_playlist(self.session, src).items(): yield s
def _get_vod_streams(self, data): schema_vod_list = validate.Schema( validate.any( validate.all({"video": { "videoStory": dict }}, validate.get(("video", "videoStory"))), validate.all({"quicktakeVideo": { "videoStory": dict }}, validate.get(("quicktakeVideo", "videoStory")))), {"video": { "bmmrId": str }}, validate.get(("video", "bmmrId"))) schema_url = validate.all({"url": validate.url()}, validate.get("url")) try: video_id = schema_vod_list.validate(data) except PluginError: log.error("Could not find videoId") return log.debug(f"Found videoId: {video_id}") vod_url = self.VOD_API_URL.format(video_id) secureStreams, streams, self.title = self.session.http.get( vod_url, schema=validate.Schema( validate.parse_json(), { validate.optional("secureStreams"): [schema_url], validate.optional("streams"): [schema_url], "title": str }, validate.union_get("secureStreams", "streams", "title"))) return secureStreams or streams
class Streamable(Plugin): meta_re = re.compile(r'''var\s*videoObject\s*=\s*({.*});''') config_schema = validate.Schema( validate.transform(meta_re.search), validate.any(None, validate.all( validate.get(1), validate.parse_json(), { "files": {validate.text: {"url": validate.url(), "width": int, "height": int, "bitrate": int}} }) ) ) 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)