Exemple #1
0
    def determine_certificate_validity(cls):
        server_hostname_loopback = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_LOOPBACK')
        server_hostname_private = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_PRIVATE')
        server_hostname_public = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_PUBLIC')

        with open(cls._certificate_file_path, 'rb') as input_file:
            certificate = x509.load_pem_x509_certificate(
                input_file.read(), default_backend())
            certificate_subjects = certificate.extensions.get_extension_for_oid(
                x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
            ).value.get_values_for_type(x509.DNSName)

            logger.debug(
                'Certificate status\n'
                'File path  => {0}\n'
                'Expires on => {1}\n'
                'Subjects   => {2}\n\n'
                '{3}'.format(
                    cls._certificate_file_path,
                    certificate.not_valid_after.replace(tzinfo=pytz.utc).
                    astimezone(
                        tzlocal.get_localzone()).strftime('%Y-%m-%d %H:%M:%S'),
                    ', '.join(certificate_subjects), '\n'.join([
                        'Certificate is {0}valid for domain => {1}'.format(
                            '' if server_hostname in certificate_subjects else
                            'not ', server_hostname) for server_hostname in [
                                server_hostname_loopback,
                                server_hostname_private, server_hostname_public
                            ]
                    ])))
Exemple #2
0
    def generate_self_signed_certificate(cls):
        ip_address_location = Utility.determine_ip_address_location()

        if ip_address_location is not None:
            private_key = rsa.generate_private_key(public_exponent=65537,
                                                   key_size=2048,
                                                   backend=default_backend())

            with open(DEFAULT_SSL_KEY_FILE_PATH, 'wb') as output_file:
                output_file.write(
                    private_key.private_bytes(
                        encoding=serialization.Encoding.PEM,
                        format=serialization.PrivateFormat.TraditionalOpenSSL,
                        encryption_algorithm=serialization.NoEncryption(),
                    ))

            current_date_time_in_utc = datetime.now(pytz.utc)

            subject = issuer = x509.Name([
                x509.NameAttribute(NameOID.COUNTRY_NAME,
                                   ip_address_location['countryCode']),
                x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                                   ip_address_location['region']),
                x509.NameAttribute(NameOID.LOCALITY_NAME,
                                   ip_address_location['city']),
                x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'IPTVProxy'),
                x509.NameAttribute(
                    NameOID.COMMON_NAME,
                    Configuration.get_configuration_parameter(
                        'SERVER_HOSTNAME_PUBLIC'),
                ),
            ])

            certificate = (x509.CertificateBuilder(
            ).subject_name(subject).issuer_name(issuer).public_key(
                private_key.public_key()).serial_number(
                    x509.random_serial_number()
                ).not_valid_before(current_date_time_in_utc).not_valid_after(
                    current_date_time_in_utc +
                    timedelta(days=10 * 365)).add_extension(
                        x509.SubjectAlternativeName([
                            x509.DNSName(
                                Configuration.get_configuration_parameter(
                                    'SERVER_HOSTNAME_LOOPBACK')),
                            x509.DNSName(
                                Configuration.get_configuration_parameter(
                                    'SERVER_HOSTNAME_PRIVATE')),
                            x509.DNSName(
                                Configuration.get_configuration_parameter(
                                    'SERVER_HOSTNAME_PUBLIC')),
                        ]),
                        critical=False,
                    ).sign(private_key, hashes.SHA256(), default_backend()))

            with open(DEFAULT_SSL_CERTIFICATE_FILE_PATH, 'wb') as output_file:
                output_file.write(
                    certificate.public_bytes(serialization.Encoding.PEM))
        else:
            logger.error('Failed to generate self signed certificate')
Exemple #3
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()
Exemple #4
0
    def generate_playlist_m3u8(cls, is_server_secure, client_ip_address,
                               client_uuid, requested_query_string_parameters,
                               providers):
        http_token = requested_query_string_parameters.get('http_token')
        playlist_protocol = requested_query_string_parameters.get('protocol')
        playlist_type = requested_query_string_parameters.get('type')

        try:
            client_ip_address_type = Utility.determine_ip_address_type(
                client_ip_address)
            server_hostname = Configuration.get_configuration_parameter(
                'SERVER_HOSTNAME_{0}'.format(client_ip_address_type.value))
            server_port = Configuration.get_configuration_parameter(
                'SERVER_HTTP{0}_PORT'.format('S' if is_server_secure else ''))

            playlist_m3u8 = [
                '#EXTM3U x-tvg-url="{0}://{1}:{2}/live/epg.xml"\n'.format(
                    'https' if is_server_secure else 'http', server_hostname,
                    server_port)
            ]

            for (provider_name, provider) in sorted(list(providers.items())):
                provider_protocol = playlist_protocol
                provider_type = playlist_type

                try:
                    provider_protocol = requested_query_string_parameters[
                        '{0}_protocol'.format(provider_name)]
                except KeyError:
                    pass

                try:
                    provider_type = requested_query_string_parameters[
                        '{0}_type'.format(provider_name)]
                except KeyError:
                    pass

                generate_playlist_m3u8_tracks_mapping = dict(
                    client_uuid=client_uuid,
                    http_token=http_token,
                    is_server_secure=is_server_secure,
                    playlist_protocol=provider_protocol,
                    playlist_type=provider_type,
                    server_hostname=server_hostname,
                    server_port=server_port)

                playlist_m3u8.append(''.join(
                    provider.api_class().generate_playlist_m3u8_tracks(
                        generate_playlist_m3u8_tracks_mapping)))

            logger.debug('Generated live IPTVProxy playlist.m3u8')

            return ''.join(playlist_m3u8)
        except (KeyError, ValueError):
            (status, value_, traceback_) = sys.exc_info()

            logger.error('\n'.join(
                traceback.format_exception(status, value_, traceback_)))
Exemple #5
0
    def download_ts_file(cls, client_ip_address, client_uuid, requested_path,
                         requested_query_string_parameters):
        authorization_token = requested_query_string_parameters.get(
            'wmsAuthSign')
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        nimble_session_id = requested_query_string_parameters.get(
            'nimblesessionid')

        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)

        requests_session = cls._get_session_parameter('requests_session')

        target_url = 'https://{0}.smoothstreams.tv/{1}/ch{2}q1.stream{3}'.format(
            Configuration.get_configuration_parameter('SMOOTHSTREAMS_SERVER'),
            Configuration.get_configuration_parameter('SMOOTHSTREAMS_SERVICE'),
            channel_number, re.sub(r'(/.*)?(/.*\.ts)', r'\2', requested_path))

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

        response = Utility.make_http_request(
            requests_session.get,
            target_url,
            params={
                'nimblesessionid': nimble_session_id,
                'wmsAuthSign': 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_binary=True))

            return response.content
        else:
            logger.error(Utility.assemble_response_from_log_message(response))

            response.raise_for_status()
Exemple #6
0
    def generate_xmltv(cls,
                       is_server_secure,
                       authorization_required,
                       client_ip_address,
                       providers_map_class,
                       number_of_days,
                       style):
        current_date_time_in_utc = datetime.now(pytz.utc)

        yield '<?xml version="1.0" encoding="utf-8"?>\n<tv date="{0}" generator-info-name="IPTVProxy {1}">\n'.format(
            current_date_time_in_utc.strftime('%Y%m%d%H%M%S %z'),
            VERSION)

        client_ip_address_type = Utility.determine_ip_address_type(client_ip_address)
        server_password = Configuration.get_configuration_parameter('SERVER_PASSWORD')
        server_hostname = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_{0}'.format(client_ip_address_type.value))
        server_port = Configuration.get_configuration_parameter(
            'SERVER_HTTP{0}_PORT'.format('S' if is_server_secure
                                         else ''))

        cutoff_date_time_in_local = datetime.now(tzlocal.get_localzone()).replace(
            hour=0,
            minute=0,
            second=0,
            microsecond=0) + timedelta(days=int(number_of_days) + 1)
        cutoff_date_time_in_utc = cutoff_date_time_in_local.astimezone(pytz.utc)

        for provider_map_class in providers_map_class.values():
            with provider_map_class.database_class().get_access_lock().shared_lock:
                db_session = provider_map_class.database_class().create_session()

                try:
                    if style.capitalize() == EPGStyle.COMPLETE.value:
                        query_channels_xmltv = provider_map_class.database_access_class().query_channels_complete_xmltv
                        query_programs_xmltv = provider_map_class.database_access_class().query_programs_complete_xmltv
                    else:
                        query_channels_xmltv = provider_map_class.database_access_class().query_channels_minimal_xmltv
                        query_programs_xmltv = provider_map_class.database_access_class().query_programs_minimal_xmltv

                    for channel_row in query_channels_xmltv(db_session):
                        yield channel_row.xmltv.format(
                            's' if is_server_secure
                            else '',
                            server_hostname,
                            server_port,
                            '?http_token={0}'.format(server_password) if authorization_required
                            else '')

                    for program_row in query_programs_xmltv(db_session, cutoff_date_time_in_utc):
                        yield program_row.xmltv
                finally:
                    db_session.close()

        yield '</tv>\n'
Exemple #7
0
    def _update_epg(cls, **kwargs):
        with cls._lock:
            super()._update_epg()

            channel_name_map = kwargs['channel_name_map']
            do_use_provider_icons = kwargs['do_use_provider_icons']

            was_exception_raised = False

            VaderStreamsDatabase.initialize_temporary()

            db_session = VaderStreamsDatabase.create_temporary_session()

            try:
                if Configuration.get_configuration_parameter('VADERSTREAMS_EPG_SOURCE') == \
                        VaderStreamsEPGSource.OTHER.value:
                    cls._parse_external_epg_xml(db_session,
                                                channel_name_map=channel_name_map,
                                                do_use_provider_icons=do_use_provider_icons)
                elif Configuration.get_configuration_parameter('VADERSTREAMS_EPG_SOURCE') == \
                        VaderStreamsEPGSource.PROVIDER.value:
                    parsed_channel_xmltv_id_to_channel = {}

                    cls._parse_epg_json(db_session,
                                        channel_name_map,
                                        do_use_provider_icons, parsed_channel_xmltv_id_to_channel)
                    cls._parse_epg_xml(db_session, parsed_channel_xmltv_id_to_channel)

                db_session.add(VaderStreamsSetting('epg_settings_md5', cls._calculate_epg_settings_md5(**kwargs)))
                db_session.add(VaderStreamsSetting('last_epg_refresh_date_time_in_utc',
                                                   datetime.strftime(datetime.now(pytz.utc), '%Y-%m-%d %H:%M:%S%z')))

                db_session.commit()
            except Exception:
                was_exception_raised = True

                db_session.rollback()

                raise
            finally:
                cls._initialize_refresh_epg_timer(do_set_timer_for_retry=was_exception_raised)

                db_session.close()

                if not was_exception_raised:
                    try:
                        VaderStreamsDatabase.migrate()
                    except Exception:
                        cls._initialize_refresh_epg_timer(do_set_timer_for_retry=True)

                        raise
Exemple #8
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()
Exemple #9
0
    def generate_vod_index_playlist_m3u8(cls, is_server_secure,
                                         client_ip_address, client_uuid,
                                         http_token):
        playlist_m3u8 = []

        client_ip_address_type = Utility.determine_ip_address_type(
            client_ip_address)
        server_hostname = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_{0}'.format(client_ip_address_type.value))
        server_port = Configuration.get_configuration_parameter(
            'SERVER_HTTP{0}_PORT'.format('S' if is_server_secure else ''))

        db_session = Database.create_session()

        try:
            for persistent_recording in DatabaseAccess.query_persisted_recordings(
                    db_session):
                playlist_m3u8.append(
                    '#EXTINF:-1,{0} - [{1} - {2}]\n'
                    '{3}\n'.format(
                        persistent_recording.program_title,
                        persistent_recording.start_date_time_in_utc.astimezone(
                            tzlocal.get_localzone()).strftime(
                                '%Y-%m-%d %H:%M:%S%z'),
                        persistent_recording.end_date_time_in_utc.astimezone(
                            tzlocal.get_localzone()).strftime(
                                '%Y-%m-%d %H:%M:%S%z'),
                        cls.generate_vod_recording_playlist_url(
                            is_server_secure,
                            server_hostname,
                            server_port,
                            client_uuid,
                            persistent_recording.id,
                            http_token,
                        ),
                    ))
        finally:
            db_session.close()

        if playlist_m3u8:
            playlist_m3u8 = '#EXTM3U\n{0}'.format(''.join(playlist_m3u8))

            logger.debug('Generated VOD playlist.m3u8')
        else:
            logger.debug(
                'No persistent recordings found. VOD playlist.m3u8 will not be generated'
            )

        return playlist_m3u8
Exemple #10
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 ''))
Exemple #11
0
    def _generate_playlist_m3u8_static_track_url(cls, track_information,
                                                 **kwargs):
        channel_number = kwargs['channel_number']
        playlist_protocol = kwargs['playlist_protocol']
        authorization_token = kwargs['authorization_token']

        track_information.append(
            '{0}://{1}.smoothstreams.tv:{2}/{3}/ch{4:02}q1.stream{5}?wmsAuthSign={6}\n'
            .format(
                'https' if playlist_protocol in ['hls', 'mpegts'] else 'rtmp',
                Configuration.get_configuration_parameter(
                    'SMOOTHSTREAMS_SERVER'),
                '443' if playlist_protocol in ['hls', 'mpegts'] else '3635',
                Configuration.get_configuration_parameter(
                    'SMOOTHSTREAMS_SERVICE'), int(channel_number),
                '/mpeg.2ts' if playlist_protocol == 'mpegts' else '',
                authorization_token))
Exemple #12
0
    def shutdown_proxy(cls):
        cls._shutdown_proxy_event.set()

        ProvidersController.terminate()
        CacheManager.cancel_cleanup_cache_timer()
        PVR.cancel_start_recording_timer()
        PVR.stop()

        if cls._http_server_thread:
            cls._http_server_thread.stop()

        if cls._https_server_thread:
            cls._https_server_thread.stop()

        Configuration.stop_configuration_file_watchdog_observer()
        OptionalSettings.stop_optional_settings_file_watchdog_observer()
        Logging.stop_logging_configuration_file_watchdog_observer()
Exemple #13
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'))
Exemple #14
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()
Exemple #15
0
    def _start_server(cls, is_secure):
        server_port = Configuration.get_configuration_parameter(
            'SERVER_HTTP{0}_PORT'.format('S' if is_secure else ''))

        server_address = ('', int(server_port))

        server_thread = HTTPServerThread(server_address, is_secure=is_secure)
        server_thread.start()

        return server_thread
Exemple #16
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)

        cls.refresh_session()

        if protocol == 'hls':
            authorization_token = cls._get_session_parameter(
                'authorization_token')
            requests_session = cls._get_session_parameter('requests_session')

            target_url = 'https://{0}.smoothstreams.tv/{1}/ch{2}q1.stream{3}'.format(
                Configuration.get_configuration_parameter(
                    'SMOOTHSTREAMS_SERVER'),
                Configuration.get_configuration_parameter(
                    'SMOOTHSTREAMS_SERVICE'), channel_number,
                re.sub(r'(/.*)?(/.*\.m3u8)', r'\2', requested_path))

            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}\n'
                         '  Parameters\n'
                         '    wmsAuthSign    => {6}'.format(
                             client_ip_address, requested_path, channel_number,
                             client_uuid, protocol, target_url,
                             authorization_token))

            response = Utility.make_http_request(
                requests_session.get,
                target_url,
                params={'wmsAuthSign': 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))

                return response.text.replace(
                    'chunks.m3u8?',
                    'chunks.m3u8?channel_number={0}&client_uuid={1}&http_token={2}&'
                    .format(
                        channel_number, client_uuid,
                        urllib.parse.quote(http_token) if http_token else ''))
            else:
                logger.error(
                    Utility.assemble_response_from_log_message(response))

                response.raise_for_status()
        elif protocol == 'mpegts':
            authorization_token = cls._get_session_parameter(
                'authorization_token')

            return '#EXTM3U\n' \
                   '#EXTINF:-1 ,{0}\n' \
                   'https://{1}.smoothstreams.tv:443/{2}/ch{3}q1.stream/mpeg.2ts?' \
                   'wmsAuthSign={4}'.format(SmoothStreamsEPG.get_channel_name(int(channel_number)),
                                            Configuration.get_configuration_parameter(
                                                'SMOOTHSTREAMS_SERVER'),
                                            Configuration.get_configuration_parameter(
                                                'SMOOTHSTREAMS_SERVICE'),
                                            channel_number,
                                            authorization_token)
        elif protocol == 'rtmp':
            authorization_token = cls._get_session_parameter(
                'authorization_token')

            return '#EXTM3U\n' \
                   '#EXTINF:-1 ,{0}\n' \
                   'rtmp://{1}.smoothstreams.tv:3635/{2}/ch{3}q1.stream?' \
                   'wmsAuthSign={4}'.format(SmoothStreamsEPG.get_channel_name(int(channel_number)),
                                            Configuration.get_configuration_parameter(
                                                'SMOOTHSTREAMS_SERVER'),
                                            Configuration.get_configuration_parameter(
                                                'SMOOTHSTREAMS_SERVICE'),
                                            channel_number,
                                            authorization_token)
Exemple #17
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
 def __init__(self):
     self._configuration = Configuration.get_configuration_copy()
Exemple #19
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)
Exemple #20
0
    def generate_playlist_m3u8_tracks(
        cls,
        generate_playlist_m3u8_tracks_mapping,
        sort_by=M388PlaylistSortOrder.CHANNEL_NAME.value,
    ):
        client_uuid = generate_playlist_m3u8_tracks_mapping['client_uuid']
        http_token = generate_playlist_m3u8_tracks_mapping['http_token']
        is_server_secure = generate_playlist_m3u8_tracks_mapping[
            'is_server_secure']
        playlist_protocol = generate_playlist_m3u8_tracks_mapping[
            'playlist_protocol']
        playlist_type = generate_playlist_m3u8_tracks_mapping['playlist_type']
        server_hostname = generate_playlist_m3u8_tracks_mapping[
            'server_hostname']
        server_port = generate_playlist_m3u8_tracks_mapping['server_port']

        provider_map_class = ProvidersController.get_provider_map_class(
            cls._provider_name)

        if (playlist_protocol not in provider_map_class.constants_class().
                VALID_PLAYLIST_PROTOCOL_VALUES):
            playlist_protocol = Configuration.get_configuration_parameter(
                '{0}_PLAYLIST_PROTOCOL'.format(cls.__name__.upper()))

        if (playlist_type not in provider_map_class.constants_class().
                VALID_PLAYLIST_TYPE_VALUES):
            playlist_type = Configuration.get_configuration_parameter(
                '{0}_PLAYLIST_TYPE'.format(cls.__name__.upper()))

        authorization_token = None

        tracks = {}

        with provider_map_class.database_class().get_access_lock().shared_lock:
            db_session = provider_map_class.database_class().create_session()

            try:
                for (channel_row) in provider_map_class.database_access_class(
                ).query_channels_pickle(db_session):
                    channel = pickle.loads(channel_row.pickle)

                    track_information = [
                        '#EXTINF:-1 group-title="{0}" '
                        'tvg-id="{1}" '
                        'tvg-name="{2}" '
                        'tvg-logo="{3}" '
                        'channel-id="{4}",{2}\n'.format(
                            channel.m3u8_group,
                            channel.xmltv_id,
                            channel.display_names[0].text,
                            channel.icons[0].source.format(
                                's' if is_server_secure else '',
                                server_hostname,
                                server_port,
                                '?http_token={0}'.format(
                                    urllib.parse.quote(http_token))
                                if http_token else '',
                            ).replace(' ', '%20'),
                            channel.number,
                        )
                    ]

                    if playlist_type == 'dynamic':
                        generate_playlist_m3u8_track_url_mapping = dict(
                            channel_number=channel.number,
                            client_uuid=client_uuid,
                            http_token=http_token,
                            is_server_secure=is_server_secure,
                            playlist_protocol=playlist_protocol,
                            server_hostname=server_hostname,
                            server_port=server_port,
                        )

                        track_information.append('{0}\n'.format(
                            cls.generate_playlist_m3u8_track_url(
                                generate_playlist_m3u8_track_url_mapping)))
                    elif playlist_type == 'static':
                        if authorization_token is None:
                            authorization_token = (
                                cls._retrieve_fresh_authorization_token())

                        cls._generate_playlist_m3u8_static_track_url(
                            track_information,
                            channel_number=channel.number,
                            playlist_protocol=playlist_protocol,
                            authorization_token=authorization_token,
                        )

                    if sort_by == M388PlaylistSortOrder.CHANNEL_NAME.value:
                        tracks['{0} {1} {2}'.format(
                            channel.m3u8_group,
                            channel.display_names[0].text,
                            channel.number,
                        )] = ''.join(track_information)
                    elif sort_by == M388PlaylistSortOrder.CHANNEL_NUMBER.value:
                        tracks[channel.number] = ''.join(track_information)
            finally:
                db_session.close()

        if not sort_by:
            return [
                tracks[channel_name] for channel_name in sorted(
                    tracks, key=lambda channel_name_: channel_name_.lower())
            ]

        return [tracks[channel_number] for channel_number in sorted(tracks)]
Exemple #21
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()
Exemple #22
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,
                    ))
Exemple #23
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()
Exemple #24
0
    def download_chunks_m3u8(cls, client_ip_address, client_uuid,
                             requested_path,
                             requested_query_string_parameters):
        authorization_token = requested_query_string_parameters.get(
            'wmsAuthSign')
        channel_number = requested_query_string_parameters.get(
            'channel_number')
        http_token = requested_query_string_parameters.get('http_token')
        nimble_session_id = requested_query_string_parameters.get(
            'nimblesessionid')

        nimble_session_id = cls._map_nimble_session_id(client_ip_address,
                                                       channel_number,
                                                       client_uuid,
                                                       nimble_session_id,
                                                       authorization_token)

        IPTVProxy.refresh_serviceable_clients(client_uuid, client_ip_address)

        authorization_token = cls._get_session_parameter('authorization_token')
        requests_session = cls._get_session_parameter('requests_session')

        target_url = 'https://{0}.smoothstreams.tv/{1}/ch{2}q1.stream{3}'.format(
            Configuration.get_configuration_parameter('SMOOTHSTREAMS_SERVER'),
            Configuration.get_configuration_parameter('SMOOTHSTREAMS_SERVICE'),
            channel_number, re.sub(r'(/.*)?(/.*\.m3u8)', r'\2',
                                   requested_path))

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

        response = Utility.make_http_request(
            requests_session.get,
            target_url,
            params={
                'nimblesessionid': nimble_session_id,
                'wmsAuthSign': 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))

            return response.text.replace(
                '.ts?',
                '.ts?channel_number={0}&client_uuid={1}&http_token={2}&'.
                format(channel_number, client_uuid,
                       urllib.parse.quote(http_token) if http_token else ''))
        else:
            logger.error(Utility.assemble_response_from_log_message(response))

            response.raise_for_status()