Example #1
0
    def _calculate_token(cls):
        credentials = {
            'username': Configuration.get_configuration_parameter('VADERSTREAMS_USERNAME'),
            'password': SecurityManager.decrypt_password(
                Configuration.get_configuration_parameter('VADERSTREAMS_PASSWORD')).decode(),
        }

        return base64.b64encode(json.dumps(credentials, separators=(',', ':')).encode()).decode()
Example #2
0
    def start_https_server(cls):
        try:
            Privilege.become_privileged_user()
            SecurityManager.determine_certificate_validity()
            cls._https_server_thread = cls._start_server(is_secure=True)
        except SSLError:
            logger.error(
                'Failed to start HTTPS Server\n'
                'Make sure the certificate and key files specified match\n'
                'Certificate file path => %s\n'
                'Key file path         => %s',
                SecurityManager.get_certificate_file_path(),
                SecurityManager.get_key_file_path(),
            )
        except OSError:
            error_message = ['Failed to start HTTPS Server']

            certificate_or_key_file_not_found = False

            if not os.path.exists(SecurityManager.get_certificate_file_path()):
                certificate_or_key_file_not_found = True

                error_message.append(
                    'SSL file not found\n'
                    'Certificate file path => {0}'.format(
                        SecurityManager.get_certificate_file_path()))

            if not os.path.exists(SecurityManager.get_key_file_path()):
                if certificate_or_key_file_not_found:
                    error_message[1] = error_message[1].replace(
                        'SSL file', 'SSL files')
                    error_message.append('Key file path         => {0}'.format(
                        SecurityManager.get_key_file_path()))
                else:
                    certificate_or_key_file_not_found = True

                    error_message.append(
                        'SSL file not found\n'
                        'Key file path => {0}'.format(
                            SecurityManager.get_key_file_path()))

            if not certificate_or_key_file_not_found:
                (status, value_, traceback_) = sys.exc_info()

                error_message.append('\n'.join(
                    traceback.format_exception(status, value_, traceback_)))

            logger.error('\n'.join(error_message))
        finally:
            Privilege.become_unprivileged_user()
Example #3
0
    def _request_epg_json(cls, epg_json_path, epg_json_file_name,
                          request_parameters):
        username = Configuration.get_configuration_parameter(
            'VADERSTREAMS_USERNAME')
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter(
                'VADERSTREAMS_PASSWORD')).decode()

        url = '{0}{1}'.format(VaderStreamsConstants.BASE_URL, epg_json_path)

        logger.debug(
            'Downloading %s\n'
            'URL => %s\n'
            '  Parameters\n'
            '    username => %s\n'
            '    password => %s%s',
            epg_json_file_name,
            url,
            username,
            '\u2022' * len(password),
            '' if request_parameters is None
            or 'category_id' not in request_parameters else
            '\n    category => {0}'.format(request_parameters['category_id']),
        )

        requests_session = requests.Session()
        response = Utility.make_http_request(
            requests_session.get,
            url,
            params={
                'username': username,
                'password': password,
                **request_parameters
            },
            headers=requests_session.headers,
            cookies=requests_session.cookies.get_dict(),
            stream=True,
        )

        if response.status_code == requests.codes.OK:
            response.raw.decode_content = True

            logger.trace(Utility.assemble_response_from_log_message(response))

            return response.raw

        logger.error(Utility.assemble_response_from_log_message(response))

        response.raise_for_status()
Example #4
0
    def _generate_playlist_m3u8_static_track_url(cls, track_information,
                                                 **kwargs):
        channel_number = kwargs['channel_number']
        playlist_protocol = kwargs['playlist_protocol']

        username = Configuration.get_configuration_parameter(
            'CRYSTALCLEAR_USERNAME')
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter(
                'CRYSTALCLEAR_PASSWORD')).decode()

        track_information.append('{0}{1}{2}/{3}/{4}{5}\n'.format(
            ProvidersController.get_provider_map_class(
                cls._provider_name).constants_class().BASE_URL,
            'live/' if playlist_protocol == 'hls' else '', username, password,
            channel_number, '.m3u8' if playlist_protocol == 'hls' else ''))
Example #5
0
    def start_proxy(
        cls,
        configuration_file_path,
        optional_settings_file_path,
        db_file_path,
        log_file_path,
        recordings_directory_path,
        certificate_file_path,
        key_file_path,
    ):
        Configuration.set_configuration_file_path(configuration_file_path)
        OptionalSettings.set_optional_settings_file_path(
            optional_settings_file_path)
        Database.set_database_file_path(db_file_path)
        Logging.set_log_file_path(log_file_path)
        PVR.set_recordings_directory_path(recordings_directory_path)
        SecurityManager.set_certificate_file_path(certificate_file_path)
        SecurityManager.set_key_file_path(key_file_path)

        ProvidersController.initialize()

        OptionalSettings.read_optional_settings_file()
        Database.initialize()
        SecurityManager.initialize()

        Configuration.read_configuration_file()

        CacheManager.initialize()
        HTMLTemplateEngine.initialize()
        HTTPRequestHandler.initialize()
        PVR.initialize()

        Configuration.start_configuration_file_watchdog_observer()
        OptionalSettings.start_optional_settings_file_watchdog_observer()
        Logging.start_logging_configuration_file_watchdog_observer()

        cls.start_http_server()
        cls.start_https_server()

        PVR.start()

        while not cls._shutdown_proxy_event.is_set():
            if cls._http_server_thread:
                cls._http_server_thread.join()

            if cls._https_server_thread:
                cls._https_server_thread.join()

            cls._shutdown_proxy_event.wait(0.5)

        Configuration.join_configuration_file_watchdog_observer()
        OptionalSettings.join_optional_settings_file_watchdog_observer()
        Logging.join_logging_configuration_file_watchdog_observer()
Example #6
0
    def _generate_playlist_m3u8_static_track_url(cls, track_information, **kwargs):
        channel_number = kwargs['channel_number']
        playlist_protocol = kwargs['playlist_protocol']

        url = Configuration.get_configuration_parameter('{0}_URL'.format(cls._provider_name.upper()))
        username = Configuration.get_configuration_parameter('{0}_USERNAME'.format(cls._provider_name.upper()))
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter('{0}_PASSWORD'.format(cls._provider_name.upper()))).decode()

        track_information.append(
            '{0}{1}{2}/{3}/{4}{5}\n'.format(
                url,
                'live/' if playlist_protocol == 'hls'
                else '',
                username,
                password,
                channel_number,
                '.m3u8' if playlist_protocol == 'hls'
                else '.ts'))
Example #7
0
    def process_configuration_file_updates(cls):
        with cls._lock.writer_lock:
            message_to_log = []

            purge_http_sessions = False
            restart_http_server = False
            restart_https_server = False

            # <editor-fold desc="Detect and handle SERVER_PASSWORD change">
            if cls._configuration[
                    'SERVER_PASSWORD'] != cls._previous_configuration[
                        'SERVER_PASSWORD']:
                purge_http_sessions = True

                message_to_log.append(
                    'Detected a change in the password option in the [Server] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls._previous_configuration['SERVER_PASSWORD'],
                        cls._configuration['SERVER_PASSWORD']))
            # </editor-fold>

            # <editor-fold desc="Detect and handle SERVER_HOSTNAME_<LOOPBACK,PRIVATE,PUBLIC> change">
            loopback_hostname_updated = False
            private_hostname_updated = False
            public_hostname_updated = False

            if cls._configuration['SERVER_HOSTNAME_LOOPBACK'] != \
                    cls._previous_configuration['SERVER_HOSTNAME_LOOPBACK']:
                loopback_hostname_updated = True

                message_to_log.append(
                    'Detected a change in the loopback option in the [Hostnames] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls.
                        _previous_configuration['SERVER_HOSTNAME_LOOPBACK'],
                        cls._configuration['SERVER_HOSTNAME_LOOPBACK']))

            if cls._configuration[
                    'SERVER_HOSTNAME_PRIVATE'] != cls._previous_configuration[
                        'SERVER_HOSTNAME_PRIVATE']:
                private_hostname_updated = True

                message_to_log.append(
                    'Detected a change in the private option in the [Hostnames] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls._previous_configuration['SERVER_HOSTNAME_PRIVATE'],
                        cls._configuration['SERVER_HOSTNAME_PRIVATE']))

            if cls._configuration[
                    'SERVER_HOSTNAME_PUBLIC'] != cls._previous_configuration[
                        'SERVER_HOSTNAME_PUBLIC']:
                public_hostname_updated = True

                message_to_log.append(
                    'Detected a change in the public option in the [Hostnames] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls._previous_configuration['SERVER_HOSTNAME_PUBLIC'],
                        cls._configuration['SERVER_HOSTNAME_PUBLIC']))

            if loopback_hostname_updated or private_hostname_updated or public_hostname_updated:
                restart_https_server = True
            # </editor-fold>

            # <editor-fold desc="Detect and handle SERVER_HTTP_PORT change">
            if cls._configuration[
                    'SERVER_HTTP_PORT'] != cls._previous_configuration[
                        'SERVER_HTTP_PORT']:
                restart_http_server = True

                message_to_log.append(
                    'Detected a change in the http option in the [Ports] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls._previous_configuration['SERVER_HTTP_PORT'],
                        cls._configuration['SERVER_HTTP_PORT']))
            # </editor-fold>

            # <editor-fold desc="Detect and handle SERVER_HTTPS_PORT change">
            if cls._configuration[
                    'SERVER_HTTPS_PORT'] != cls._previous_configuration[
                        'SERVER_HTTPS_PORT']:
                restart_https_server = True

                message_to_log.append(
                    'Detected a change in the https option in the [Ports] section\n'
                    'Old value => {0}\n'
                    'New value => {1}\n'.format(
                        cls._previous_configuration['SERVER_HTTPS_PORT'],
                        cls._configuration['SERVER_HTTPS_PORT']))
            # </editor-fold>

            if purge_http_sessions:
                from iptv_proxy.http_server import HTTPRequestHandler

                message_to_log.append(
                    'Action => Purge all user HTTP/S sessions')

                with Database.get_write_lock():
                    db_session = Database.create_session()

                    try:
                        HTTPRequestHandler.purge_http_sessions(db_session)
                        db_session.commit()
                    except Exception:
                        (type_, value_, traceback_) = sys.exc_info()
                        logger.error('\n'.join(
                            traceback.format_exception(type_, value_,
                                                       traceback_)))

                        db_session.rollback()
                    finally:
                        db_session.close()

            if restart_http_server:
                from iptv_proxy.controller import Controller

                message_to_log.append('Action => Restart HTTP server')

                Controller.shutdown_http_server()
                Controller.start_http_server()

            if restart_https_server:
                from iptv_proxy.security import SecurityManager

                message_to_log.append('Action => Restart HTTPS server')

                if SecurityManager.get_auto_generate_self_signed_certificate():
                    SecurityManager.generate_self_signed_certificate()

                    from iptv_proxy.controller import Controller

                    Controller.shutdown_https_server()
                    Controller.start_https_server()

            if message_to_log:
                logger.debug('\n'.join(message_to_log))

            for provider_name in sorted(
                    ProvidersController.get_providers_map_class()):
                ProvidersController.get_provider_map_class(
                    provider_name).configuration_class(
                    ).process_configuration_file_updates(
                        cls._configuration, cls._previous_configuration)
Example #8
0
    def _refresh_session(cls):
        requests_session = requests.Session()

        if Configuration.get_configuration_parameter(
                'SMOOTHSTREAMS_SERVICE') == 'viewmmasr':
            url = 'https://www.mma-tv.net/loginForm.php'
        else:
            url = 'https://auth.smoothstreams.tv/hash_api.php'

        username = Configuration.get_configuration_parameter(
            'SMOOTHSTREAMS_USERNAME')
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter(
                'SMOOTHSTREAMS_PASSWORD')).decode()
        site = Configuration.get_configuration_parameter(
            'SMOOTHSTREAMS_SERVICE')

        logger.debug('Retrieving SmoothStreams authorization token\n'
                     'URL => {0}\n'
                     '  Parameters\n'
                     '    username => {0}\n'
                     '    password => {1}\n'
                     '    site     => {2}'.format(url, username,
                                                  '\u2022' * len(password),
                                                  site))

        response = Utility.make_http_request(
            requests_session.get,
            url,
            params={
                'username': username,
                'password': password,
                'site': site
            },
            headers=requests_session.headers,
            cookies=requests_session.cookies.get_dict())

        response_status_code = response.status_code
        if response_status_code != requests.codes.OK and response_status_code != requests.codes.NOT_FOUND:
            logger.error(Utility.assemble_response_from_log_message(response))

            response.raise_for_status()

        logger.trace(
            Utility.assemble_response_from_log_message(response,
                                                       is_content_json=True,
                                                       do_print_content=True))

        authorization_token_response = response.json()
        session = {}

        if 'code' in authorization_token_response:
            if authorization_token_response['code'] == '0':
                logger.error(
                    'Failed to retrieve SmoothStreams authorization token\n'
                    'Error => {0}'.format(
                        authorization_token_response['error']))
            elif authorization_token_response['code'] == '1':
                session['authorization_token'] = authorization_token_response[
                    'hash']
                session['expires_on'] = datetime.now(pytz.utc) + timedelta(
                    seconds=(authorization_token_response['valid'] * 60))
                session['requests_session'] = requests_session

                logger.info('Retrieved SmoothStreams authorization token\n'
                            'Hash       => {0}\n'
                            'Expires On => {1}'.format(
                                session['authorization_token'],
                                session['expires_on'].astimezone(
                                    tzlocal.get_localzone()).strftime(
                                        '%Y-%m-%d %H:%M:%S%z')))
        else:
            logger.error(
                'Failed to retrieve SmoothStreams authorization token\n'
                'Error => JSON response contains no [\'code\'] field')

        if response_status_code != requests.codes.OK:
            response.raise_for_status()

        return session
Example #9
0
    def download_ts_file(
        cls,
        client_ip_address,
        client_uuid,
        requested_path,
        requested_query_string_parameters,
    ):
        authorization_token = requested_query_string_parameters.get(
            'authorization_token')
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        hostname = requested_query_string_parameters.get('hostname')
        leaf_directory = requested_query_string_parameters.get(
            'leaf_directory')
        port = requested_query_string_parameters.get('port')
        scheme = requested_query_string_parameters.get('scheme')

        IPTVProxy.refresh_serviceable_clients(client_uuid, client_ip_address)
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_request_date_time_in_utc',
            datetime.now(pytz.utc))

        username = Configuration.get_configuration_parameter(
            '{0}_USERNAME'.format(cls._provider_name.upper()))
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter('{0}_PASSWORD'.format(
                cls._provider_name.upper()))).decode()

        requests_session = requests.Session()

        target_url = '{0}://{1}{2}/hls{3}{4}/{5}/{6}/{7}/{8}{9}'.format(
            scheme,
            hostname,
            port,
            'r' if authorization_token else '',
            '/{0}'.format(authorization_token) if authorization_token else '',
            username,
            password,
            channel_number,
            leaf_directory,
            re.sub(r'(/.*)?(/.*\.ts)', r'\2', requested_path),
        )

        logger.debug(
            'Proxying request\n'
            'Source IP      => %s\n'
            'Requested path => %s\n'
            '  Parameters\n'
            '    channel_number => %s\n'
            '    client_uuid    => %s\n'
            '    hostname       => %s\n'
            '    port           => %s\n'
            '    scheme         => %s\n'
            'Target path    => %s',
            client_ip_address,
            requested_path,
            channel_number,
            client_uuid,
            hostname,
            port,
            scheme,
            target_url,
        )

        response = Utility.make_http_request(
            requests_session.get,
            target_url,
            headers=requests_session.headers,
            cookies=requests_session.cookies.get_dict(),
        )

        if response.status_code == requests.codes.OK:
            logger.trace(
                Utility.assemble_response_from_log_message(
                    response, is_content_binary=True))

            IPTVProxy.set_serviceable_client_parameter(
                client_uuid,
                'last_requested_ts_file_path',
                re.sub(r'(/.*)?(/.*\.ts)', r'\2', requested_path)[1:],
            )

            return response.content

        logger.error(Utility.assemble_response_from_log_message(response))

        response.raise_for_status()
Example #10
0
    def download_playlist_m3u8(
        cls,
        client_ip_address,
        client_uuid,
        requested_path,
        requested_query_string_parameters,
    ):
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        http_token = requested_query_string_parameters.get('http_token')
        protocol = requested_query_string_parameters.get('protocol')

        IPTVProxy.refresh_serviceable_clients(client_uuid, client_ip_address)
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_request_date_time_in_utc',
            datetime.now(pytz.utc))
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_requested_channel_number', channel_number)

        url = Configuration.get_configuration_parameter('{0}_URL'.format(
            cls._provider_name.upper()))
        username = Configuration.get_configuration_parameter(
            '{0}_USERNAME'.format(cls._provider_name.upper()))
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter('{0}_PASSWORD'.format(
                cls._provider_name.upper()))).decode()

        if protocol == 'hls':
            requests_session = requests.Session()

            target_url = '{0}live/{1}/{2}/{3}.m3u8'.format(
                url, username, password, channel_number)

            logger.debug(
                'Proxying request\n'
                'Source IP      => %s\n'
                'Requested path => %s\n'
                '  Parameters\n'
                '    channel_number => %s\n'
                '    client_uuid    => %s\n'
                '    protocol       => %s\n'
                'Target path    => %s',
                client_ip_address,
                requested_path,
                channel_number,
                client_uuid,
                protocol,
                target_url,
            )

            response = Utility.make_http_request(
                requests_session.get,
                target_url,
                headers=requests_session.headers,
                cookies=requests_session.cookies.get_dict(),
            )

            if response.status_code == requests.codes.OK:
                logger.trace(
                    Utility.assemble_response_from_log_message(
                        response, is_content_text=True, do_print_content=True))

                with cls._do_reduce_hls_stream_delay_lock.reader_lock:
                    if cls._do_reduce_hls_stream_delay:
                        chunks_m3u8 = cls._reduce_hls_stream_delay(
                            response.text,
                            client_uuid,
                            channel_number,
                            number_of_segments_to_keep=2,
                        )
                    else:
                        chunks_m3u8 = response.text

                parsed_url = urllib.parse.urlparse(response.request.url)
                scheme = parsed_url.scheme
                hostname = parsed_url.hostname
                port = (':{0}'.format(parsed_url.port)
                        if parsed_url.port is not None else '')

                return re.sub(
                    r'/hls/(.*)/(.*)/(.*)/(.*)/(.*).ts',
                    r'\5.ts?'
                    'authorization_token=&'
                    'channel_number={0}&'
                    'client_uuid={1}&'
                    'hostname={2}&'
                    'http_token={3}&'
                    r'leaf_directory=\4&'
                    'port={4}&'
                    'scheme={5}'.format(
                        channel_number,
                        client_uuid,
                        urllib.parse.quote(hostname),
                        urllib.parse.quote(http_token) if http_token else '',
                        urllib.parse.quote(port),
                        scheme,
                    ),
                    chunks_m3u8,
                )
            elif response.status_code == requests.codes.FOUND:
                logger.trace(
                    Utility.assemble_response_from_log_message(
                        response,
                        is_content_text=False,
                        do_print_content=False))

                parsed_url = urllib.parse.urlparse(
                    response.headers['Location'])
                scheme = parsed_url.scheme
                hostname = parsed_url.hostname
                port = (':{0}'.format(parsed_url.port)
                        if parsed_url.port is not None else '')

                return ('#EXTM3U\n'
                        '#EXT-X-VERSION:3\n'
                        '#EXT-X-STREAM-INF:BANDWIDTH=8388608\n'
                        'chunks.m3u8?authorization_token={0}&'
                        'channel_number={1}&'
                        'client_uuid={2}&'
                        'hostname={3}&'
                        'http_token={4}&'
                        'port={5}&'
                        'scheme={6}'.format(
                            dict(urllib.parse.parse_qsl(
                                parsed_url.query))['token'],
                            channel_number,
                            client_uuid,
                            urllib.parse.quote(hostname),
                            urllib.parse.quote(http_token)
                            if http_token else '',
                            urllib.parse.quote(port),
                            scheme,
                        ))

            logger.error(Utility.assemble_response_from_log_message(response))

            response.raise_for_status()
        elif protocol == 'mpegts':
            provider_map_class = ProvidersController.get_provider_map_class(
                cls._provider_name)

            return ('#EXTM3U\n'
                    '#EXTINF:-1 ,{0}\n'
                    '{1}live/{2}/{3}/{4}.ts'
                    ''.format(
                        provider_map_class.epg_class().get_channel_name(
                            int(channel_number)),
                        url,
                        username,
                        password,
                        channel_number,
                    ))
Example #11
0
    def download_chunks_m3u8(
        cls,
        client_ip_address,
        client_uuid,
        requested_path,
        requested_query_string_parameters,
    ):
        authorization_token = requested_query_string_parameters.get(
            'authorization_token')
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        client_uuid = requested_query_string_parameters.get('client_uuid')
        hostname = requested_query_string_parameters.get('hostname')
        http_token = requested_query_string_parameters.get('http_token')
        port = requested_query_string_parameters.get('port')
        scheme = requested_query_string_parameters.get('scheme')

        IPTVProxy.refresh_serviceable_clients(client_uuid, client_ip_address)
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_request_date_time_in_utc',
            datetime.now(pytz.utc))
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_requested_channel_number', channel_number)

        username = Configuration.get_configuration_parameter(
            '{0}_USERNAME'.format(cls._provider_name.upper()))
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter('{0}_PASSWORD'.format(
                cls._provider_name.upper()))).decode()

        requests_session = requests.Session()

        target_url = '{0}://{1}{2}/live/{3}/{4}/{5}.m3u8'.format(
            scheme, hostname, port, username, password, channel_number)

        logger.debug(
            'Proxying request\n'
            'Source IP      => %s\n'
            'Requested path => %s\n'
            '  Parameters\n'
            '    authorization_token => %s\n'
            '    channel_number  => %s\n'
            '    client_uuid     => %s\n'
            '    hostname        => %s\n'
            '    port            => %s\n'
            '    scheme          => %s\n'
            'Target path    => %s\n'
            '  Parameters\n'
            '    token => %s',
            client_ip_address,
            requested_path,
            authorization_token,
            channel_number,
            client_uuid,
            hostname,
            port,
            scheme,
            target_url,
            authorization_token,
        )

        response = Utility.make_http_request(
            requests_session.get,
            target_url,
            params={'token': authorization_token},
            headers=requests_session.headers,
            cookies=requests_session.cookies.get_dict(),
        )

        if response.status_code == requests.codes.OK:
            logger.trace(
                Utility.assemble_response_from_log_message(
                    response, is_content_text=True, do_print_content=True))

            with cls._do_reduce_hls_stream_delay_lock.reader_lock:
                if cls._do_reduce_hls_stream_delay:
                    chunks_m3u8 = cls._reduce_hls_stream_delay(
                        response.text,
                        client_uuid,
                        channel_number,
                        number_of_segments_to_keep=2,
                    )
                else:
                    chunks_m3u8 = response.text

                return re.sub(
                    r'/hlsr/(.*)/(.*)/(.*)/(.*)/(.*)/(.*).ts',
                    r'\6.ts?'
                    r'authorization_token=\1&'
                    'channel_number={0}&'
                    'client_uuid={1}&'
                    'hostname={2}&'
                    'http_token={3}&'
                    r'leaf_directory=\5&'
                    'port={4}&'
                    'scheme={5}'.format(
                        channel_number,
                        client_uuid,
                        urllib.parse.quote(hostname),
                        urllib.parse.quote(http_token) if http_token else '',
                        urllib.parse.quote(port),
                        scheme,
                    ),
                    chunks_m3u8,
                )
        else:
            logger.error(Utility.assemble_response_from_log_message(response))

            response.raise_for_status()
Example #12
0
    def download_chunks_m3u8(cls, client_ip_address, client_uuid,
                             requested_path,
                             requested_query_string_parameters):
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        http_token = requested_query_string_parameters.get('http_token')
        protocol = requested_query_string_parameters.get('protocol')

        IPTVProxy.refresh_serviceable_clients(client_uuid, client_ip_address)
        IPTVProxy.set_serviceable_client_parameter(
            client_uuid, 'last_request_date_time_in_utc',
            datetime.now(pytz.utc))

        username = Configuration.get_configuration_parameter(
            '{0}_USERNAME'.format(cls._provider_name.upper()))
        password = SecurityManager.decrypt_password(
            Configuration.get_configuration_parameter('{0}_PASSWORD'.format(
                cls._provider_name.upper()))).decode()

        if protocol == 'hls':
            requests_session = requests.Session()

            target_url = '{0}live/{1}/{2}/{3}.m3u8'.format(
                ProvidersController.get_provider_map_class(
                    cls._provider_name).constants_class().BASE_URL, username,
                password, channel_number)

            logger.debug('Proxying request\n'
                         'Source IP      => {0}\n'
                         'Requested path => {1}\n'
                         '  Parameters\n'
                         '    channel_number => {2}\n'
                         '    client_uuid    => {3}\n'
                         '    protocol       => {4}\n'
                         'Target path    => {5}'.format(
                             client_ip_address, requested_path, channel_number,
                             client_uuid, protocol, target_url))

            response = Utility.make_http_request(
                requests_session.get,
                target_url,
                headers=requests_session.headers,
                cookies=requests_session.cookies.get_dict())

            if response.status_code == requests.codes.OK:
                logger.trace(
                    Utility.assemble_response_from_log_message(
                        response, is_content_text=True, do_print_content=True))

                with cls._do_reduce_hls_stream_delay_lock.reader_lock:
                    if cls._do_reduce_hls_stream_delay:
                        chunks_m3u8 = cls._reduce_hls_stream_delay(
                            response.text,
                            client_uuid,
                            channel_number,
                            number_of_segments_to_keep=2)
                    else:
                        chunks_m3u8 = response.text

                IPTVProxy.set_serviceable_client_parameter(
                    client_uuid, 'last_requested_channel_number',
                    channel_number)

                match = re.search(
                    r'http://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:\d+)?',
                    response.request.url)

                server = match.group(1)
                port = match.group(2) if len(match.groups()) == 2 else ':80'

                return re.sub(
                    r'/hlsr/(.*)/(.*)/(.*)/(.*)/(.*)/(.*).ts', r'\6.ts?'
                    r'authorization_token=\1&'
                    'channel_number={0}&'
                    'client_uuid={1}&'
                    'http_token={2}&'
                    r'leaf_directory=\5&'
                    'port={3}&'
                    'server={4}'.format(
                        channel_number, client_uuid,
                        urllib.parse.quote(http_token) if http_token else '',
                        urllib.parse.quote(port), urllib.parse.quote(server)),
                    chunks_m3u8)
            else:
                logger.error(
                    Utility.assemble_response_from_log_message(response))

                response.raise_for_status()
        elif protocol == 'mpegts':
            provider_map_class = ProvidersController.get_provider_map_class(
                cls._provider_name)

            return '#EXTM3U\n' \
                   '#EXTINF:-1 ,{0}\n' \
                   '{1}{2}/{3}/{4}' \
                   ''.format(provider_map_class.constants_class().BASE_URL,
                             provider_map_class.epg_class().get_channel_name(int(channel_number)),
                             username,
                             password,
                             channel_number)