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 ] ])))
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')
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()
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_)))
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()
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'
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
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()
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
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 ''))
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))
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()
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'))
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()
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
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)
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()
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)
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)]
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()
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, ))
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()
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()