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 arglist_from_query(path): old_data = parse_qsl(urlparse(path).query) arglist = [] for k, v in old_data: if k == 'q': # backwards compatibility --q k = 'default-stream' arglist += ['--{0}'.format(unquote(k)), unquote(v)] return arglist
def follow_vk_redirect(self): if self._has_video_id(): return 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" and len(v) > 0) self.url = "{0}://{1}/{2}".format(parsed_url.scheme, parsed_url.netloc, true_path) if self._has_video_id(): return except StopIteration: pass try: self.url = self.session.http.get( self.url, schema=validate.Schema( validate.parse_html(), validate.xml_xpath_string( ".//head/meta[@property='og:url'][@content]/@content"), validate.text)) except PluginError: pass if self._has_video_id(): return raise NoStreamsError(self.url)
def _iframe_unescape(self, res_text): '''search for unescaped iframes Args: res_text: Content from self._res_text Returns: (list) A list of iframe urls or False if no iframe was found ''' unescape_iframe = self._unescape_iframe_re.findall(res_text) if unescape_iframe: unescape_text = [] for data in unescape_iframe: unescape_text += [unquote(data)] unescape_text = ','.join(unescape_text) unescape_iframe = self._iframe_re.findall(unescape_text) if unescape_iframe: log.debug('Found unescape_iframe: {0}'.format( len(unescape_iframe))) return unescape_iframe log.debug('No unescape_iframe') return False
def production_id(self): if self._stream not in CHANNEL_MAP: res = http.get(self.url, verify=False) production_id_match = re.findall(r'data-video-production-id="(.+?)"', res.text) if production_id_match: return unquote(production_id_match[0]) else: self.logger.error(u"No production ID found, has the page layout changed?")
def production_id(self): if self._stream not in CHANNEL_MAP: res = http.get(self.url, verify=False) production_id_match = re.findall(r"&productionId=(.*?)['&\"]", res.text, flags=re.DOTALL) if production_id_match: return unquote(production_id_match[0]) else: self.logger.error(u"No production ID found, has the page layout changed?")
def production_id(self): if self._stream not in CHANNEL_MAP: res = http.get(self.url, verify=False) production_id_match = re.findall(r'data-video-production-id="(.+?)"', res.text) if production_id_match: return unquote(production_id_match[0]) else: self.logger.error(u"No production ID found, has the page layout changed?")
def unpack_unescape(text): while True: m = unpack_unescape_re.search(text) if m: text = text.replace(m.group(0), unquote(m.group(1))) else: break return text
def follow_vk_redirect(cls, url): # If this is a 'videos' catalog URL with an video ID in the GET request, get that instead parsed_url = urlparse(url) if parsed_url.path.startswith('/videos-'): query = {v[0]: v[1] for v in [q.split('=') for q in parsed_url.query.split('&')] if v[0] == 'z'} try: true_path = unquote(query['z']).split('/')[0] return parsed_url.scheme + '://' + parsed_url.netloc + '/' + true_path except KeyError: # No redirect found in query string, so return the catalog url and fail later return url else: return 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(validate.text, int), validate.optional("streamId"): validate.text, validate.optional("idec"): validate.text, validate.optional("token"): validate.text } )) )) 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": validate.text }]}, 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 []: for s in HLSStream.parse_variant_playlist(self.session, url).items(): yield s
def _unescape_type(self, _re, _type_re): '''search for unescaped iframes or m3u8 URLs''' unescape_type = _re.findall(self.html_text) if unescape_type: unescape_text = [] for data in unescape_type: unescape_text += [unquote(data)] unescape_text = ','.join(unescape_text) unescape_type = _type_re.findall(unescape_text) if unescape_type: log.debug('Found unescape_type: {0}'.format( len(unescape_type))) return unescape_type log.trace('No unescape_type') return False
def follow_vk_redirect(cls, url): # If this is a 'videos' catalog URL with an video ID in the GET request, get that instead parsed_url = urlparse(url) if parsed_url.path.startswith('/videos-'): query = { v[0]: v[1] for v in [q.split('=') for q in parsed_url.query.split('&')] if v[0] == 'z' } try: true_path = unquote(query['z']).split('/')[0] return parsed_url.scheme + '://' + parsed_url.netloc + '/' + true_path except KeyError: # No redirect found in query string, so return the catalog url and fail later return url else: return url
def repair_url(self, url, base_url, stream_base=''): # remove \ new_url = url.replace('\\', '') # repairs broken scheme if new_url.startswith('http://'): new_url = 'http:' + new_url[9:] elif new_url.startswith('https://'): new_url = 'https:' + new_url[10:] new_url = unquote(new_url) # creates a valid url from path only urls # and adds missing scheme for // urls if stream_base and new_url[1] != '/': if new_url[0] == '/': new_url = new_url[1:] new_url = urljoin(stream_base, new_url) else: new_url = urljoin(base_url, new_url) return new_url
def _get_streams(self): username = self.get_option('username') password = self.get_option('password') if username is None or password is None: self.logger.error( "PC-YourFreeTV requires authentication, use --pcyourfreetv-username " "and --pcyourfreetv-password to set your username/password combination" ) return if self.login(username, password): self.logger.info("Successfully logged in as {0}", username) # Get a fresh authorization token res = http.get(self.LIVE_TV_URL) match = self._token_re.search(res.text) if match is None: return # Retrieve URL page and search for stream data res = http.get(self.url, params=parse_qsl(match.group('tokens'))) match = self._player_re.search(res.text) if match is None: return while match is not None: player = unquote(match.group('player')) match = self._player_re.search(player) match = self._video_url_re.search(player) if match is None: return video_url = match.group('video_url') if '.m3u8' in video_url: streams = HLSStream.parse_variant_playlist(self.session, video_url) if len(streams) != 0: for stream in streams.items(): yield stream else: # Not a HLS playlist yield 'live', HLSStream(self.session, video_url)
def _get_streams(self): username = self.get_option('username') password = self.get_option('password') if username is None or password is None: self.logger.error( "PC-YourFreeTV requires authentication, use --pcyourfreetv-username " "and --pcyourfreetv-password to set your username/password combination" ) return if self.login(username, password): self.logger.info("Successfully logged in as {0}", username) # Retrieve URL iframe res = http.get(self.url) match = self._iframe_re.search(res.text) if match is None: return res = http.get(match.group('iframe')) players = self._player_re.findall(res.text) if len(players) == 0 is None: return while len(players) > 0: player = unquote(players[-1]) players = self._player_re.findall(player) match = self._video_url_re.search(player) if match is None: return video_url = match.group('video_url') if '.m3u8' in video_url: streams = HLSStream.parse_variant_playlist(self.session, video_url) if len(streams) != 0: for stream in streams.items(): yield stream else: # Not a HLS playlist yield 'live', HLSStream(self.session, video_url)
def hls_session(self): res = self.session.http.get(update_scheme(self.url, self._session_api)) data = self.session.http.json(res) # the values are already quoted, we don't want them quoted return dict((k, unquote(v)) for k, v in data.items())
def hls_session(self): res = self.session.http.get(update_scheme(self.url, self._session_api)) data = self.session.http.json(res) # the values are already quoted, we don't want them quoted return dict((k, unquote(v)) for k, v in data.items())
def _websocket_data(self, username, chat_servers): '''Get data from the websocket. Args: username: Model Username chat_servers: servername from self._get_servers Returns: message: data to create a video url. php_message: data for self._php_fallback ''' try_to_connect = 0 while (try_to_connect < 5): try: xchat = str(random.choice(chat_servers)) host = 'wss://{0}.myfreecams.com/fcsl'.format(xchat) ws = create_connection(host) ws.send('hello fcserver\n\0') r_id = str(uuid.uuid4().hex[0:32]) ws.send('1 0 0 20071025 0 {0}@guest:guest\n'.format(r_id)) log.debug('Websocket server {0} connected'.format(xchat)) try_to_connect = 5 except Exception: try_to_connect += 1 log.debug( 'Failed to connect to WS server: {0} - try {1}'.format( xchat, try_to_connect)) if try_to_connect == 5: log.error('can\'t connect to the websocket') raise buff = '' php_message = '' ws_close = 0 while ws_close == 0: socket_buffer = ws.recv() socket_buffer = buff + socket_buffer buff = '' while True: ws_answer = self._socket_re.search(socket_buffer) if bool(ws_answer) == 0: break FC = ws_answer.group(1) FCTYPE = int(FC[6:]) message_length = int(FC[0:6]) message = socket_buffer[6:6 + message_length] if len(message) < message_length: buff = ''.join(socket_buffer) break message = unquote(message) if FCTYPE == 1 and username: ws.send('10 0 0 20 0 {0}\n'.format(username)) elif FCTYPE == 81: php_message = message if username is None: ws_close = 1 elif FCTYPE == 10: ws_close = 1 socket_buffer = socket_buffer[6 + message_length:] if len(socket_buffer) == 0: break ws.send('99 0 0 0 0') ws.close() return message, php_message
def main_play(HTTPBase, redirect=False): # parse url query data old_data = parse_qsl(urlparse(HTTPBase.path).query) arglist = [] for k, v in old_data: arglist += ['--{0}'.format(unquote(k)), unquote(v)] parser = build_parser() args = setup_args(parser, arglist, ignore_unknown=True) # create a new session for every request session = Streamlink() log.info('User-Agent: {0}'.format(HTTPBase.headers.get( 'User-Agent', '???'))) log.info('Client: {0}'.format(HTTPBase.client_address)) log.info('Address: {0}'.format(HTTPBase.address_string())) setup_plugins(session, args) setup_plugin_args(session, parser) # call setup args again once the plugin specific args have been added args = setup_args(parser, arglist, ignore_unknown=True) args = setup_config_args(session, args, parser, arglist) logger.root.setLevel(args.loglevel) setup_http_session(session, args) if args.url: setup_options(session, args) try: plugin = session.resolve_url(args.url) setup_plugin_options(session, args, plugin) log.info('Found matching plugin {0} for URL {1}', plugin.module, args.url) plugin_args = [] for parg in plugin.arguments: value = plugin.get_option(parg.dest) if value: plugin_args.append((parg, value)) if plugin_args: log.debug('Plugin specific arguments:') for parg, value in plugin_args: log.debug(' {0}={1} ({2})'.format( parg.argument_name(plugin.module), value if not parg.sensitive else ('*' * 8), parg.dest)) if redirect is True: streams = session.streams(args.url, stream_types=['hls', 'http']) else: streams = session.streams( args.url, stream_types=args.stream_types, sorting_excludes=args.stream_sorting_excludes) except NoPluginError: log.error('No plugin can handle URL: {0}', args.url) HTTPBase._headers(404, 'text/html', connection='close') return except PluginError as err: log.error('PluginError {0}', str(err)) HTTPBase._headers(404, 'text/html', connection='close') return if not streams: log.error('No playable streams found on this URL: {0}', args.url) HTTPBase._headers(404, 'text/html', connection='close') return if args.default_stream and not args.stream: args.stream = args.default_stream if not args.stream: args.stream = ['best'] stream_ended = False validstreams = format_valid_streams(plugin, streams) for stream_name in args.stream: if stream_name in streams: log.info('Available streams: {0}', validstreams) '''Decides what to do with the selected stream.''' stream_name = resolve_stream_name(streams, stream_name) stream = streams[stream_name] # Find any streams with a '_alt' suffix and attempt # to use these in case the main stream is not usable. alt_streams = list( filter(lambda k: stream_name + '_alt' in k, sorted(streams.keys()))) for stream_name in [stream_name] + alt_streams: stream = streams[stream_name] stream_type = type(stream).shortname() log.info('Opening stream: {0} ({1})', stream_name, stream_type) if isinstance(stream, (RTMPStream)): log.info('RTMP streams ' 'might not work on every platform.') elif isinstance(stream, (MuxedStream, DASHStream)): log.info('FFmpeg streams (dash, muxed) ' 'might not work on every platform.') # 301 if redirect is True: log.info('301 - URL: {0}'.format(stream.url)) HTTPBase.send_response(301) HTTPBase.send_header('Location', stream.url) HTTPBase.end_headers() log.info('301 - done') stream_ended = True break # play try: fd = stream.open() except StreamError as err: log.error('Could not open stream: {0}'.format(err)) continue cache = 4096 HTTPBase._headers(200, 'video/unknown') try: log.debug('Pre-buffering {0} bytes'.format(cache)) while True: buff = fd.read(cache) if not buff: log.error('No Data for buff!') break HTTPBase.wfile.write(buff) HTTPBase.wfile.close() except socket.error as e: if isinstance(e.args, tuple): if e.errno == errno.EPIPE: # remote peer disconnected log.info('Detected remote disconnect') else: log.error(str(e)) else: log.error(str(e)) fd.close() log.info('Stream ended') fd = None stream_ended = True break if not stream_ended: HTTPBase._headers(404, 'text/html', connection='close') return err = ('The specified stream(s) \'{0}\' could not be ' 'found'.format(', '.join(args.stream))) log.error('{0}.\n Available streams: {1}', err, validstreams) HTTPBase._headers(404, 'text/html', connection='close') return else: HTTPBase._headers(404, 'text/html', connection='close') log.error('No URL provided.') return