Пример #1
0
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)
Пример #2
0
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
Пример #3
0
    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)
Пример #4
0
    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
Пример #5
0
 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?")
Пример #6
0
 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?")
Пример #7
0
 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?")
Пример #8
0
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
Пример #9
0
 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
Пример #10
0
    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
Пример #11
0
 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
Пример #12
0
 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&#58;//'):
         new_url = 'http:' + new_url[9:]
     elif new_url.startswith('https&#58;//'):
         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
Пример #14
0
    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)
Пример #15
0
    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)
Пример #16
0
 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())
Пример #17
0
 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())
Пример #18
0
    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
Пример #19
0
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