def _get_streams(self): headers = {'User-Agent': CHROME} res = self.session.http.get(self.url, headers=headers) param = self._param_re.search(res.text).group('param') _json_url = urljoin(self._base_link, param) _json_object = self.session.http.get(_json_url, headers=headers).json() stream = _json_object.get('url') if stream.endswith('.mp4'): raise NoStreamsError('Stream is probably geo-locked to Greece') headers.update({"Referer": self.url}) parse_hls = bool(strtobool(self.get_option('parse_hls'))) if parse_hls: return HLSStream.parse_variant_playlist(self.session, stream, headers=headers) else: return dict(live=HTTPStream(self.session, stream, headers=headers))
def _get_video_streams(self): self.logger.debug("Getting video steams for {0} (type={1})".format(self.video_id, self.video_type)) self._authenticate() if self.video_type == "b": self.video_type = "a" try: videos = self.api.videos(self.video_type + self.video_id, schema=_video_schema) except PluginError as err: if "HTTP/1.1 0 ERROR" in str(err): raise NoStreamsError(self.url) else: raise # Parse the "t" query parameter on broadcasts and adjust # start offset if needed. time_offset = self.params.get("t") if time_offset: try: time_offset = hours_minutes_seconds(time_offset) except ValueError: time_offset = 0 videos["start_offset"] += time_offset return self._create_playlist_streams(videos)
def _get_streams(self): match = _url_re.match(self.url) res = self.session.http.get(STREAM_INFO_URL, params=match.groupdict(), acceptable_status=STATUS_UNAVAILABLE) if res.status_code in STATUS_UNAVAILABLE: return data = self.session.http.json(res, schema=_stream_schema) if data.get("hls_url"): hls_url = data["hls_url"] hls_name = "live" elif data.get("replay_url"): self.logger.info("Live Stream ended, using replay instead") hls_url = data["replay_url"] hls_name = "replay" else: raise NoStreamsError(self.url) streams = HLSStream.parse_variant_playlist(self.session, hls_url) if not streams: return {hls_name: HLSStream(self.session, hls_url)} else: return streams
def _get_streams(self): headers = {'User-Agent': CHROME} if 'web-tv-live' in self.url: live = True else: live = False self.url = self.url.replace('episodeinner', 'episodes').replace('showID', 'show') res = self.session.http.get(self.url, headers=headers) if live: tags = list(itertags(res.text, 'script')) tag = [i for i in tags if 'm3u8' in i.text][0].text m3u8 = re.search(r'''["'](http.+?\.m3u8)['"]''', tag) if m3u8: m3u8 = m3u8.group(1) else: raise NoStreamsError('Ant1 CY Broadcast is currently disabled') else: eid = dict(parse_qsl(urlparse(self.url).query))['episodeID'] tags = [ i for i in list(itertags(res.text, 'a')) if eid in i.attributes.get('data-innerurl', '') ] tag = tags[0].attributes.get('data-video') m3u8 = re.search(r""(http.+?master\.m3u8)"", tag).group(1) stream = self.session.http.get(self._api_url.format(m3u8), headers=headers).text headers.update({"Referer": self.url}) try: parse_hls = bool(strtobool(self.get_option('parse_hls'))) except AttributeError: parse_hls = True if parse_hls: return HLSStream.parse_variant_playlist(self.session, stream, headers=headers) else: return dict( stream=HTTPStream(self.session, stream, headers=headers))
def get_streamer_data(self): res = self.session.http.get(self.api_lives) data = self.session.http.json(res, schema=self._data_lives_schema) log.debug("Found {0} streams".format(len(data))) m = self._url_re.match(self.url) for item in data: if item["owner"]["user"]["unique_name"] == m.group("user"): return item raise NoStreamsError(self.url)
def follow_vk_redirect(self): # If this is a 'videos' catalog URL # with an video ID in the GET request, get that instead if self.matches[1]: try: parsed_url = urlparse(self.url) true_path = next( unquote(v).split('/')[0] for k, v in parse_qsl(parsed_url.query) if k == "z") self.url = parsed_url.scheme + '://' + parsed_url.netloc + '/' + true_path except StopIteration: raise NoStreamsError(self.url)
def _access_token(self, is_live, channel_or_vod): try: sig, token = self.api.access_token(is_live, channel_or_vod) except (PluginError, TypeError): raise NoStreamsError(self.url) try: restricted_bitrates = self.api.parse_token(token) except PluginError: restricted_bitrates = [] return sig, token, restricted_bitrates
def find_videopage(self): self.logger.debug("Not a videopage") res = http.get(self.url) m = self._videopage_re.search(res.text) if not m: self.logger.debug( "No stream path, stream might be offline or invalid url.") raise NoStreamsError(self.url) path = m.group("path") self.logger.debug("Found new path: {0}".format(path)) return urljoin(self.url, path)
def _get_streams(self): deviceid = str(uuid.uuid4()) appkeysecret = self._generate_applicationkeysecret(deviceid) json_data = { "deviceId": deviceid, "applicationKeySecret": appkeysecret } res = self.session.http.post(self._USER_API, json=json_data) jsonres = self.session.http.json(res, schema=self._USER_SCHEMA) self.usertoken = jsonres['token'] # for authorzation matchresult = self._url_re.match(self.url) if matchresult.group("onair"): onair = matchresult.group("onair") if onair == "news-global": self._CHANNEL = update_qsd(self._CHANNEL, {"division": "1"}) res = self.session.http.get(self._CHANNEL) jsonres = self.session.http.json(res, schema=self._CHANNEL_SCHEMA) channels = jsonres["channels"] for channel in channels: if onair == channel["id"]: break else: raise NoStreamsError(self.url) playlisturl = channel["playback"]["hls"] elif matchresult.group("episode"): episode = matchresult.group("episode") if not self._is_playable("episode", episode): log.error("Premium stream is not playable") return {} playlisturl = self._PRGM3U8.format(episode) elif matchresult.group("slots"): slots = matchresult.group("slots") if not self._is_playable("slots", slots): log.error("Premium stream is not playable") return {} playlisturl = self._SLOTM3U8.format(slots) log.debug("URL={0}".format(playlisturl)) # hook abematv private protocol self.session.http.mount( "abematv-license://", AbemaTVLicenseAdapter(self.session, deviceid, self.usertoken)) streams = HLSStream.parse_variant_playlist(self.session, playlisturl) if not streams: return {"live": HLSStream(self.session, playlisturl)} else: return streams
def get_streamer_data(self): headers = { "X-Requested-With": "https://sketch.pixiv.net/lives", } res = self.session.http.get(self.api_lives, headers=headers) data = self.session.http.json(res, schema=self._data_lives_schema) log.debug("Found {0} streams".format(len(data))) m = self._url_re.match(self.url) for item in data: if item["owner"]["user"]["unique_name"] == m.group("user"): return item raise NoStreamsError(self.url)
def _access_token(self, is_live, channel_or_vod): try: sig, token = self.api.access_token(is_live, channel_or_vod) except PluginError as err: if "404 Client Error" in str(err): raise NoStreamsError(self.url) else: raise try: restricted_bitrates = self.api.parse_token(token) except PluginError: restricted_bitrates = [] return sig, token, restricted_bitrates
def _get_streams(self): room_id = self.match.group("room_id") res = self.session.http.get(self.api_url.format(room_id)) data = self._data_re.search(res.text) if not data: return try: hls_url = parse_json(data.group("data"), schema=self._data_schema) except Exception: raise NoStreamsError(self.url) log.debug("URL={0}".format(hls_url)) return {"live": HLSStream(self.session, hls_url)}
def _access_token(self, endpoint, asset): try: sig, token = self.api.access_token(endpoint, asset) except PluginError as err: if "404 Client Error" in str(err): raise NoStreamsError(self.url) else: raise try: restricted_bitrates = self.api.token(token) except PluginError: restricted_bitrates = [] return sig, token, restricted_bitrates
def _get_desktop_streams(self, channel_id): password = self.options.get("password") channel = self._get_module_info("channel", channel_id, password, schema=_channel_schema) if not isinstance(channel.get("stream"), list): raise NoStreamsError(self.url) streams = {} for provider in channel["stream"]: try: provider_url = provider["url"] provider_name = provider["name"] except KeyError: continue for stream_index, stream_info in enumerate(provider["streams"]): if not isinstance(stream_info, dict): continue stream = None stream_height = int(stream_info.get("height", 0)) stream_name = stream_info.get("description") if not stream_name: if stream_height > 0: if not stream_info.get("isTranscoded"): stream_name = "{0}p+".format(stream_height) else: stream_name = "{0}p".format(stream_height) else: stream_name = "live" if stream_name in streams: provider_name_clean = provider_name.replace("uhs_", "") stream_name += "_alt_{0}".format(provider_name_clean) if provider_name.startswith("uhs_"): stream = UHSStream(self.session, channel_id, self.url, provider_name, stream_index, password) elif provider_url.startswith("rtmp"): playpath = stream_info["streamName"] stream = self._create_rtmp_stream(provider_url, playpath) if stream: streams[stream_name] = stream return streams
def get_live_id(self, username): """Get the livestream videoid from a username. https://developer.dailymotion.com/tools/apiexplorer#/user/videos/list """ params = {"flags": "live_onair"} api_user_videos = USER_INFO_URL.format(username) + "/videos" try: res = http.get(api_user_videos.format(username), params=params) except Exception as e: self.logger.error("invalid username") raise NoStreamsError(self.url) data = http.json(res, schema=_live_id_schema) if data["total"] > 0: media_id = data["list"][0]["id"] return media_id return False
def _get_streams(self): log.debug('Version 2018-07-12') log.info('This is a custom plugin. ' 'For support visit https://github.com/back-to/plugins') hls_urls = [] hds_urls = [] self.session.http.headers.update({'User-Agent': useragents.FIREFOX}) match = self._url_re.match(self.url) if match is None: return video_id = match.group('id') log.debug('video_id: {0}'.format(video_id)) res = self.session.http.get(self.api_play.format(video_id, self.url)) data = self.session.http.json(res, schema=self._video_schema) live_data = data.get('live_streams') vod_data = data.get('video_balancer') if live_data: log.debug('Found live_data') for d in live_data['hls']: hls_urls.append(d['url']) for e in live_data['hds']: hds_urls.append(e['url']) elif vod_data: log.debug('Found vod_data') hls_urls.append(vod_data['m3u8']) hds_urls.append(vod_data['default']) else: log.error('This video is not available in your region.') raise NoStreamsError(self.url) for hls_url in hls_urls: log.debug('HLS URL: {0}'.format(hls_url)) for s in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield s for hds_url in hds_urls: log.debug('HDS URL: {0}'.format(hds_url)) for s in HDSStream.parse_manifest(self.session, hds_url).items(): yield s
def _access_token(self, type="live"): try: if type == "live": endpoint = "channels" value = self.channel elif type == "video": endpoint = "vods" value = self.video_id sig, token = self.api.access_token(endpoint, value, schema=_access_token_schema) except PluginError as err: if "404 Client Error" in str(err): raise NoStreamsError(self.url) else: raise return sig, token
def _get_streams(self): match = self._player_embed_re.match(self.url) if match: channel_id = match.group("channel_id") else: try: res = http.get(self.url) except Exception as e: raise NoStreamsError(self.url) channel_id = self._find_channel_id(res.text) if not channel_id: return self.logger.info("Channel ID: {0}".format(channel_id)) res = http.get(self.PLAYER_EMBED_URL.format(channel_id)) items = self._find_stream_id(res.text) if not items: return a = b = False for stream in items: if stream["abr"] == "hls": try: for s in HLSStream.parse_variant_playlist( self.session, stream["streamUrl"]).items(): yield s except IOError: a = True elif stream["abr"] == "hds": try: for s in HDSStream.parse_manifest( self.session, stream["streamUrl"]).items(): yield s except IOError: b = True if a and b: self.logger.warning( "Could not open the stream, perhaps the channel is offline")
def _get_video_streams(self): self._authenticate() if self.video_type == "b": self.video_type = "a" try: videos = self.api.videos(self.video_type + self.video_id, schema=_video_schema) except PluginError as err: if "HTTP/1.1 0 ERROR" in str(err): raise NoStreamsError(self.url) else: raise # Parse the "t" query parameter on broadcasts and adjust # start offset if needed. time_offset = self.params.get("t") if time_offset: videos["start_offset"] += time_to_offset(self.params.get("t")) return self._create_playlist_streams(videos)
def get_hls_url(self): self.session.http.cookies.clear() url_parts = self.session.http.get( url=self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string(".//iframe[contains(@src,'embed')]/@src"))) if not url_parts: raise NoStreamsError("Missing url_parts") log.trace(f"url_parts={url_parts}") self.session.http.headers.update({"Referer": self.url}) try: url_ovva = self.session.http.get( url=urljoin(self.url, url_parts), schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string(".//script[@type='text/javascript'][contains(text(),'ovva-player')]/text()"), str, validate.transform(self._re_data.search), validate.get(1), validate.transform(lambda x: b64decode(x).decode()), validate.parse_json(), {"balancer": validate.url()}, validate.get("balancer") )) except (PluginError, TypeError) as err: log.error(f"ovva-player: {err}") return log.debug(f"url_ovva={url_ovva}") url_hls = self.session.http.get( url=url_ovva, schema=validate.Schema( validate.transform(lambda x: x.split("=")), ["302", validate.url(path=validate.endswith(".m3u8"))], validate.get(1))) return url_hls
def _get_streams(self): headers = {'User-Agent': CHROME} self.url = self.url.replace(u'ρικ', quote(u'ρικ'.encode('utf-8'))) get_page = self.session.http.get(self.url, headers=headers) tags = list(itertags(get_page.text, 'script')) if 'live-tv' in self.url: tag = [i for i in tags if 'm3u8' in i.text][0].text try: stream = re.search(r'''["'](http.+?\.m3u8)['"]''', tag).group(1) except IndexError: raise NoStreamsError('RIK Broadcast is currently disabled') else: tag = [i for i in tags if '.mp4' in i.text and 'sources' in i.text][0].text stream = re.search(r'''file: ['"](.+?\.mp4)['"]''', tag).group(1) headers.update({"Referer": self.url}) try: parse_hls = bool(strtobool(self.get_option('parse_hls'))) except AttributeError: parse_hls = True if parse_hls and 'live-tv' in self.url: return HLSStream.parse_variant_playlist(self.session, stream, headers=headers) else: return dict(stream=HTTPStream(self.session, stream, headers=headers))
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE is_paid_show = False # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get swf url and cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: raise NoStreamsError(self.url) if not r.ok: self.logger.debug("Status code for {}: {}", r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) match = swf_re.search(r.text) if match: swf_url = urljoin(baseurl, match.group()) self.logger.debug("swf url found: {}", swf_url) else: # most likely it means that country/region banned # can try use default swf-url swf_url = urljoin(baseurl, CONST_DEFAULT_SWF_LOCATION) self.logger.debug("swf url not found. Will try {}", swf_url) # create amf query amf_message = AMFMessage("svDirectAmf.getRoomData", "/1", [stream_page_path, is_paid_show]) amf_packet = AMFPacket(version=0) amf_packet.messages.append(amf_message) # send request and close http-session r = http_session.post(url=amf_gateway_url, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=bytes(amf_packet.serialize())) http_session.close() if r.status_code != 200: raise PluginError("unexpected status code for {}: {}", r.url, r.status_code) amf_response = AMFPacket.deserialize(BytesIO(r.content)) if len(amf_response.messages ) != 1 or amf_response.messages[0].target_uri != "/1/onResult": raise PluginError("unexpected response from amf gate") stream_source_info = amf_msg_schema.validate( amf_response.messages[0].value) self.logger.debug("source stream info:\n{}", stream_source_info) stream_params = { "live": True, "realtime": True, "flashVer": CONST_FLASH_VER, "swfUrl": swf_url, "tcUrl": stream_source_info['localData']['NC_ConnUrl'], "rtmp": stream_source_info['localData']['NC_ConnUrl'], "pageUrl": stream_page_url, "playpath": "%s?uid=%s" % (''.join(('stream_', stream_page_path)), self._get_stream_uid(stream_source_info['userData']['username'])), "conn": [ "S:{0}".format(stream_source_info['userData']['username']), "S:{0}".format( stream_source_info['localData']['NC_AccessKey']), "B:0", "S:{0}".format(stream_source_info['localData']['dataKey']) ] } self.logger.debug("Stream params:\n{}", stream_params) stream = RTMPStream(self.session, stream_params) return {'live': stream}
def _get_streams(self): self.session.http.headers.update({'User-Agent': useragents.FIREFOX}) log.debug('Version 2018-07-12') log.info('This is a custom plugin. ') match = self._url_re.match(self.url) username = match.group('username') user_id = match.group('user_id') servers = self._get_servers() chat_servers = servers['chat_servers'] message, php_message = self._websocket_data(username, chat_servers) if user_id and not username: data = self._php_fallback(username, user_id, php_message) else: log.debug('Attempting to use WebSocket data') data = self._dict_re.search(message) if data is None: raise NoStreamsError(self.url) data = parse_json(data.group('data'), schema=self._data_schema) vs = data['vs'] ok_vs = [0, 90] if vs not in ok_vs: if vs == 2: log.info('Model is currently away') elif vs == 12: log.info('Model is currently in a private show') elif vs == 13: log.info('Model is currently in a group show') elif vs == 127: log.info('Model is currently offline') else: log.error('Stream status: {0}'.format(vs)) raise NoStreamsError(self.url) log.debug('VS: {0}'.format(vs)) nm = data['nm'] uid = data['uid'] uid_video = uid + 100000000 camserver = data['u']['camserv'] server, server_type = self._get_camserver(servers, camserver) if server is None and not user_id: fallback_data = self._php_fallback(username, user_id, php_message) camserver = fallback_data['u']['camserv'] server, server_type = self._get_camserver(servers, camserver) log.info('Username: {0}'.format(nm)) log.info('User ID: {0}'.format(uid)) if not server: raise PluginError('Missing video server') log.debug('Video server: {0}'.format(server)) log.debug('Video server_type: {0}'.format(server_type)) if server_type == 'h5video_servers': DASH_VIDEO_URL = 'https://{0}.myfreecams.com/NxServer/ngrp:mfc_{1}.f4v_desktop/manifest.mpd'.format( server, uid_video) HLS_VIDEO_URL = 'https://{0}.myfreecams.com/NxServer/ngrp:mfc_{1}.f4v_mobile/playlist.m3u8'.format( server, uid_video) elif server_type == 'wzobs_servers': DASH_VIDEO_URL = '' HLS_VIDEO_URL = 'https://{0}.myfreecams.com/NxServer/ngrp:mfc_a_{1}.f4v_mobile/playlist.m3u8'.format( server, uid_video) elif server_type == 'ngvideo_servers': raise PluginError('ngvideo_servers are not supported.') else: raise PluginError('Unknow server type.') log.debug('HLS URL: {0}'.format(HLS_VIDEO_URL)) for s in HLSStream.parse_variant_playlist(self.session, HLS_VIDEO_URL).items(): yield s if DASH_VIDEO_URL and self.get_option('dash'): log.debug('DASH URL: {0}'.format(DASH_VIDEO_URL)) for s in DASHStream.parse_manifest(self.session, DASH_VIDEO_URL).items(): yield s
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: raise NoStreamsError(self.url) if not r.ok: self.logger.debug("Status code for {0}: {1}", r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) headers = { 'User-Agent': useragents.CHROME, 'Referer': stream_page_url, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format( stream_page_path) self.logger.debug('DATA: {0}'.format(str(data))) # send request and close http-session r = http_session.post(url=amf_gateway_url, headers=headers, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=data) http_session.close() if r.status_code != 200: raise PluginError("unexpected status code for {0}: {1}", r.url, r.status_code) stream_source_info = amf_msg_schema.validate(json.loads(r.text)) self.logger.debug("source stream info:\n{0}", stream_source_info) if not stream_source_info: return urlnoproto = stream_source_info['localData']['videoServerUrl'] urlnoproto = update_scheme('https://', urlnoproto) performer = stream_source_info['performerData']['username'] hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format( urlnoproto, performer) if hls_url: self.logger.debug('HLS URL: {0}'.format(hls_url)) try: for s in HLSStream.parse_variant_playlist( self.session, hls_url, headers=headers).items(): yield s except Exception as e: if '404' in str(e): self.logger.error('Stream is currently offline or private') else: self.logger.error(str(e)) return
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: print(colored('\n => Performer is OFFLINE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit() if not r.ok: self.logger.debug('Status code for {0}: {1}', r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) headers = { 'User-Agent': useragents.CHROME, 'Referer': stream_page_url, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format( stream_page_path) self.logger.debug('DATA: {0}'.format(str(data))) # send request and close http-session r = http_session.post(url=amf_gateway_url, headers=headers, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=data) http_session.close() if r.status_code != 200: raise PluginError('unexpected status code for {0}: {1}', r.url, r.status_code) stream_source_info = amf_msg_schema.validate(json.loads(r.text)) self.logger.debug('source stream info:\n{0}', stream_source_info) if not stream_source_info: return performer = stream_source_info['performerData']['username'] real_name = stream_source_info['performerData']['displayName'] performer_id = stream_source_info['performerData']['userId'] print(colored('\n => Performer => {} <=', 'yellow', 'on_blue')).format(real_name) print(colored('\n => Performer ID => {} <=', 'yellow', 'on_blue')).format(performer_id) urlnoproto = stream_source_info['localData']['videoServerUrl'] urlnoproto = update_scheme('https://', urlnoproto) hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format( urlnoproto, performer) server = re.sub('https://', '', urlnoproto) print(colored('\n => Server => {} <=', 'yellow', 'on_blue')).format(server) if hls_url: try: for s in HLSStream.parse_variant_playlist( self.session, hls_url, headers=headers).items(): while True: try: print mode = int( raw_input( colored( ' => Mode => EXIT(5) YTDL-TS(4) SL(3) LS(2) FFMPEG(1) FFPLAY(0) => ', 'yellow', 'on_blue'))) break except ValueError: print( colored('\n => Input must be a number <=', 'yellow', 'on_red')) if mode == 0: mod = 'FFPLAY' if mode == 1: mod = 'FFMPEG' if mode == 2: mod = 'LS' if mode == 3: mod = 'SL' if mode == 4: mod = 'YTDL-TS' if mode == 5: mod = 'EXIT' timestamp = str(time.strftime('%d%m%Y-%H%M%S')) stime = str(time.strftime('%H:%M:%S')) path = config.get('folders', 'output_folder_BC') fn = real_name + '_BC_' + timestamp fn1 = real_name + '_BC_' + timestamp + '.flv' fn2 = real_name + '_BC_' + timestamp + '.mp4' fn3 = real_name + '_BC_' + timestamp + '.ts' pf1 = (path + fn1) pf2 = (path + fn2) pf3 = (path + fn3) ffmpeg = config.get('files', 'ffmpeg') ffplay = config.get('files', 'ffplay') livestreamer = config.get('files', 'livestreamer') streamlink = config.get('files', 'streamlink') youtube = config.get('files', 'youtube') if mod == 'FFPLAY': print( colored('\n => HLS URL => {} <=', 'yellow', 'on_blue')).format(hls_url) print( colored('\n => FFPLAY => {} <=', 'yellow', 'on_magenta')).format(fn) print command = ( '{} -hide_banner -loglevel panic -i {} -infbuf -autoexit -window_title "{} * {} * {}"' .format(ffplay, hls_url, real_name, stime, urlnoproto)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) if mod == 'FFMPEG': print( colored('\n => HLS URL => {} <=', 'yellow', 'on_blue')).format(hls_url) print( colored('\n => FFMPEG-REC => {} <=', 'yellow', 'on_red')).format(fn1) print command = ( '{} -hide_banner -loglevel panic -i {} -c:v copy -c:a aac -b:a 160k {}' .format(ffmpeg, hls_url, pf1)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) if mod == 'LS': print( colored('\n => LS-REC >>> {} <<<', 'yellow', 'on_red')).format(fn2) print command = ( '{} hlsvariant://"{}" best -Q -o "{}"'.format( livestreamer, hls_url, pf2)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) if mod == 'SL': print( colored('\n => SL-REC >>> {} <<<', 'yellow', 'on_red')).format(fn2) print command = ('{} hls://"{}" best -Q -o "{}"'.format( streamlink, hls_url, pf2)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) if mod == 'YTDL-TS': print( colored('\n => HLS URL => {} <=', 'yellow', 'on_blue')).format(hls_url) print( colored('\n => YTDL-TS-REC => {} <=', 'yellow', 'on_red')).format(fn3) command = ( '{} --hls-use-mpegts --no-part {} -q -o {}'.format( youtube, hls_url, pf3)) os.system(command) print(colored('\n => END <= ', 'yellow', 'on_blue')) sys.exit() if mod == 'EXIT': print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(3) sys.exit() except Exception as e: if '404' in str(e): print( colored('\n => Performer is AWAY or PRIVATE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit()
def _get_streams(self): # Get domain name self.domain = _url_re.match(self.url).group('domain') # Set header data for user-agent hdr = {'User-Agent': USER_AGENT.format('sv_SE')} # Parse video ID from data received from supplied URL res = http.get(self.url, headers=hdr).text match = _videoid_re.search(res) if not match: # Video ID not found self.logger.error('Failed to parse video ID') return {} videoId = match.group('id') # Get data from general API to validate that stream is playable res = http.get(GENERAL_API_URL.format(self.domain, videoId), headers=hdr) data = http.json(res, schema=_api_schema) if not data['data']: # No data item found self.logger.error( 'Unable to find "data" item in general API response') return {} if not self._is_playable(data): # Stream not playable self.logger.error( 'Stream is not playable (Premium or DRM-protected content)') return {} # Get geo data, validate and form cookie consisting of # geo data + expiry timestamp (current time + 1 hour) res = http.get(GEO_DATA_URL.format(self.domain), headers=hdr) geo = http.json(res, schema=_geo_schema) timestamp = (int(time.time()) + 3600) * 1000 cookie = 'dsc-geo=%s' % quote('{"countryCode":"%s","expiry":%s}' % (geo, timestamp)) # Append cookie to headers hdr['Cookie'] = cookie # Get available streams using stream API try: res = http.get(STREAM_API_URL.format(self.domain, videoId, 'hls'), headers=hdr, verify=False) data = http.json(res, schema=_media_schema) media = data.copy() res = http.get(STREAM_API_URL.format(self.domain, videoId, 'hds'), headers=hdr, verify=False) data = http.json(res, schema=_media_schema) media.update(data) except PluginError as err: # Likely geo-restricted if any(e in str(err) for e in ('401 Client Error', '403 Client Error')): self.logger.error('Failed to access stream API, ' 'may be due to geo-restriction') raise NoStreamsError(self.url) else: raise # Reformat data into list with stream format and url streams = [{'format': k, 'url': media[k]} for k in media] # Create mapper for supported stream types (HLS/HDS) mapper = StreamMapper(cmp=lambda type, video: video['format'] == type) mapper.map('hls', self._create_streams, HLSStream.parse_variant_playlist) mapper.map('hds', self._create_streams, HDSStream.parse_manifest) # Feed stream data to mapper and return all streams found return mapper(streams)
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: print(colored('\n => Performer is OFFLINE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit() if not r.ok: self.logger.debug('Status code for {0}: {1}', r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) headers = { 'User-Agent': useragents.CHROME, 'Referer': stream_page_url, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format( stream_page_path) self.logger.debug('DATA: {0}'.format(str(data))) # send request and close http-session r = http_session.post(url=amf_gateway_url, headers=headers, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=data) http_session.close() if r.status_code != 200: raise PluginError('unexpected status code for {0}: {1}', r.url, r.status_code) stream_source_info = amf_msg_schema.validate(json.loads(r.text)) self.logger.debug('source stream info:\n{0}', stream_source_info) if not stream_source_info: return performer = stream_source_info['performerData']['username'] real_name = stream_source_info['performerData']['displayName'] performer_id = stream_source_info['performerData']['userId'] print(colored('\n => Performer => {} <=', 'yellow', 'on_blue')).format(real_name) print(colored('\n => Performer ID => {} <=', 'yellow', 'on_blue')).format(performer_id) urlnoproto = stream_source_info['localData']['videoServerUrl'] urlnoproto = update_scheme('https://', urlnoproto) hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format( urlnoproto, performer) server = re.sub('https://', '', urlnoproto) print(colored('\n => Server => {} <=', 'yellow', 'on_blue')).format(server) if hls_url: try: for s in HLSStream.parse_variant_playlist( self.session, hls_url, headers=headers).items(): timestamp = str(time.strftime('%d%m%Y-%H%M%S')) path = config.get('folders', 'output_folder_BC') fn = real_name + '_BC_' + timestamp + '.flv' pf = (path + fn) ffmpeg = config.get('files', 'ffmpeg') print( colored('\n => FFMPEG-24/7-REC => {} <=', 'yellow', 'on_red')).format(fn) print command = ( '{} -hide_banner -loglevel panic -i {} -c:v copy -c:a aac -b:a 160k {}' .format(ffmpeg, hls_url, pf)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) sys.exit() except Exception as e: if '404' in str(e): print( colored('\n => Performer is AWAY or PRIVATE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit()