def handle(self, connection): path_file_ext = connection.path[connection.path.rfind('.') + 1:] if connection.splittedpath[ 1] == 'stat' and connection.splittedpath.__len__() == 2: if query_get(connection.query, 'action') == 'get_status': Stat.SendResponse( 200, 'json', ensure_binary( json.dumps(self.getStatusJSON(), ensure_ascii=True)), connection) else: try: Stat.SendResponse(200, 'html', Stat.getReqFileContent('index.html'), connection) except: connection.send_error(404, 'Not Found') elif path_file_ext: try: Stat.SendResponse( 200, path_file_ext, Stat.getReqFileContent( connection.path.replace(r'/stat', '')), connection) except: connection.send_error(404, 'Not Found') else: connection.send_error(404, 'Not Found')
def exportm3u(self, **params): ''' Exports m3u playlist params: hostport= '', path='', empty_header=False, archive=False, parse_url=True, header=None, query=None ''' def line_generator(item): ''' Generates EXTINF line with url ''' item = item.copy() # {'group': XXX, 'tvg': XXX, 'logo': XXX, 'name': XXX, 'tvgid': XXX, 'url': XXX} params.update({'name': quote(ensure_str(item.get('name').replace('"', "'").replace(',', '.')), '')}) url = item['url'] if not params.get('parse_url'): if params.get('path') and params.get('path').endswith('channel'): # For plugins channel name maping params.update({'value': url}) item['url'] = urlunparse(u'{schema};{netloc};{path}/{value}.{ext};;{query};'.format(**params).split(';')) elif url.startswith(('http://', 'https://')) and url.endswith(('.acelive', '.acestream', '.acemedia', '.torrent')): # For .acelive and .torrent params.update({'value': quote(url,'')}) item['url'] = urlunparse(u'{schema};{netloc};/url/{value}/{name}.{ext};;{query};'.format(**params).split(';')) elif url.startswith('infohash://'): # For INFOHASHes params.update({'value': url.split('/')[2]}) item['url'] = urlunparse(u'{schema};{netloc};/infohash/{value}/{name}.{ext};;{query};'.format(**params).split(';')) elif url.startswith('acestream://'): # For PIDs params.update({'value': url.split('/')[2]}) item['url'] = urlunparse(u'{schema};{netloc};/content_id/{value}/{name}.{ext};;{query};'.format(**params).split(';')) elif params.get('archive') and url.isdigit(): # For archive channel id's params.update({'value': url}) item['url'] = urlunparse(u'{schema};{netloc};/archive/play;;id={value};'.format(**params).split(';')) elif not params.get('archive') and url.isdigit(): # For channel id's params.update({'value': url}) item['url'] = urlunparse(u'{schema};{netloc};/channels/play;;id={value};'.format(**params).split(';')) return self.m3uchanneltemplate.format(**item) params.update({'schema': 'http', 'netloc': params.get('hostport'), 'ext': query_get(params.get('query',''), 'ext', 'ts')}) return ensure_binary(params.get('header', self.m3uemptyheader if params.get('empty_header') else self.m3uheader) + ''.join(map(line_generator, self.sort(self.itemlist))))
def Playlistparser(self): try: s = requests.Session() s.mount('file://', FileAdapter()) with s.get(config.url, headers=self.headers, proxies=config.proxies, stream=False, timeout=30) as playlist: if playlist.status_code != 304: if playlist.encoding is None: playlist.encoding = 'utf-8' playlist = playlist.json() self.headers['If-Modified-Since'] = gevent.time.strftime( '%a, %d %b %Y %H:%M:%S %Z', gevent.time.gmtime(self.playlisttime)) self.playlist = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) self.picons = picons.logomap self.channels = {} m = requests.auth.hashlib.md5() logging.info('[%s]: playlist %s downloaded' % (self.__class__.__name__, config.url)) try: urlpattern = requests.utils.re.compile( r'^(acestream|infohash)://[0-9a-f]{40}$|^(http|https)://.*.(acelive|acestream|acemedia|torrent)$' ) for channel in playlist['channels']: name = channel['name'] url = 'infohash://{url}'.format(**channel) channel['group'] = channel.pop('cat') channel['logo'] = self.picons[name] = channel.get( 'logo', picons.logomap.get(name)) channel['tvgid'] = channel.pop('program') if requests.utils.re.search(urlpattern, url): self.channels[name] = url channel['url'] = quote(ensure_str(name), '') self.playlist.addItem(channel) m.update(ensure_binary(name)) except Exception as e: logging.error("[%s]: can't parse JSON! %s" % (self.__class__.__name__, repr(e))) return False self.etag = '"' + m.hexdigest() + '"' logging.debug('[%s]: plugin playlist generated' % self.__class__.__name__) self.playlisttime = gevent.time.time() except requests.exceptions.RequestException: logging.error("[%s]: can't download %s playlist!" % (self.__class__.__name__, config.url)) return False except: logging.error(traceback.format_exc()) return False
def Playlistparser(self): try: s = requests.Session() s.mount('file://', FileAdapter()) with s.get(config.url, headers=self.headers, proxies=config.proxies, stream=False, timeout=30) as r: if r.status_code != 304: if r.encoding is None: r.encoding = 'utf-8' self.headers['If-Modified-Since'] = gevent.time.strftime( '%a, %d %b %Y %H:%M:%S %Z', gevent.time.gmtime(self.playlisttime)) self.playlist = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) self.picons = picons.logomap self.channels = {} m = requests.auth.hashlib.md5() logging.info('[%s]: playlist %s downloaded' % (self.__class__.__name__, config.url)) pattern = requests.utils.re.compile( r',(?P<name>.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?' ) urlpattern = requests.utils.re.compile( r'^(acestream|infohash)://[0-9a-f]{40}$|^(http|https)://.*.(acelive|acestream|acemedia|torrent)$' ) for match in pattern.finditer(r.text, requests.auth.re.MULTILINE): itemdict = match.groupdict() name = itemdict.get('name', '') itemdict['logo'] = self.picons[name] = itemdict.get( 'logo', picons.logomap.get(name)) url = itemdict['url'] if requests.utils.re.search(urlpattern, url): self.channels[name] = url itemdict['url'] = quote(ensure_str(name), '') self.playlist.addItem(itemdict) m.update(ensure_binary(name)) self.etag = '"' + m.hexdigest() + '"' logging.debug('[%s]: plugin playlist generated' % self.__class__.__name__) self.playlisttime = gevent.time.time() except requests.exceptions.RequestException: logging.error("[%s]: can't download %s playlist!" % (self.__class__.__name__, config.url)) return False except: logging.error(traceback.format_exc()) return False return True
def send_error(self, errorcode=500, logmsg='Dying with error', loglevel=logging.ERROR): ''' Close connection with error ''' try: self.send_response(errorcode) self.send_header('Content-Type', 'text/plain') self.send_header('Content-Length', len(logmsg)) self.send_header('Connection', 'Close') self.end_headers() self.wfile.write(ensure_binary(logmsg)) finally: logging.log(loglevel, logmsg) self.handlerGreenlet.kill()
def handleRequest(self): ''' Main request handler path: /{reqtype}/{reqtype_value}/{file_indexes}/{developer_id}/{affiliate_id}/{zone_id}/{stream_id}/{fname}.{ext} ''' logger = logging.getLogger('handleRequest') # Make handler parameters dict self.__dict__.update({}.fromkeys( aceclient.acemessages.AceConst.START_PARAMS, '0' )) # [file_indexes, developer_id, affiliate_id, zone_id, stream_id] self.__dict__.update({ k: v for (k, v) in [(aceclient.acemessages.AceConst.START_PARAMS[i - 3], self.splittedpath[i] if self.splittedpath[i].isdigit() else '0') for i in range(3, len(self.splittedpath))] }) self.__dict__.update({ self.reqtype: unquote(self.splittedpath[2]), # {reqtype: reqtype_value} 'ace': AceConfig.ace, 'acesex': AceConfig.acesex, 'aceage': AceConfig.aceage, 'acekey': AceConfig.acekey, 'connect_timeout': AceConfig.aceconntimeout, 'result_timeout': AceConfig.aceresulttimeout, 'videoseekback': AceConfig.videoseekback, 'videotimeout': AceConfig.videotimeout, 'stream_type': ' '.join([ '{}={}'.format(k, v) for k, v in AceConfig.acestreamtype.items() ]), # request http or hls from AceEngine 'sessionID': self.handlerGreenlet.name[ self.handlerGreenlet.name.rfind('-') + 1:], # Greenlet.minimal_ident A small, unique non-negative integer 'connectionTime': gevent.time.time(), 'clientDetail': None, 'channelIcon': self.__dict__.get( 'channelIcon', 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' ), }) # End parameters dict try: self.q = gevent.queue.Queue(maxsize=AceConfig.videotimeout) transcoder = gevent.event.AsyncResult() out = self.wfile gevent.spawn(wrap_errors(gevent.socket.error, self.rfile.read)).link( lambda x: self.handlerGreenlet.kill() ) # Client disconection watchdog try: if not AceProxy.clientcounter.idleAce: logger.debug( 'Create a connection with AceStream on {ace[aceHostIP]}:{ace[aceAPIport]}' .format(**self.__dict__)) AceProxy.clientcounter.idleAce = aceclient.AceClient( self.__dict__) AceProxy.clientcounter.idleAce.GetAUTH() if self.reqtype not in ('direct_url', 'efile_url'): self.__dict__.update( AceProxy.clientcounter.idleAce.GetCONTENTINFO( self.__dict__)) self.channelName = ensure_str( self.__dict__.get( 'channelName', next( iter([ x[0] for x in self.files if x[1] == int(self.file_indexes) ]), 'NoNameChannel'))) else: self.channelName = ensure_str( self.__dict__.get('channelName', 'NoNameChannel')) self.infohash = requests.auth.hashlib.sha1( ensure_binary(self.path)).hexdigest() AceProxy.clientcounter.idleAce._title = self.channelName except Exception as e: AceProxy.clientcounter.idleAce._read.kill() logging.debug('Error 404') self.send_error(404, '%s' % repr(e), logging.ERROR) self.ext = self.__dict__.get( 'ext', self.channelName[self.channelName.rfind('.') + 1:]) if self.ext == self.channelName: self.ext = query_get(self.query, 'ext', 'ts') mimetype = mimetypes.guess_type( '{channelName}.{ext}'.format(**self.__dict__))[0] try: # If &fmt transcode key present in request fmt = query_get(self.query, 'fmt') if fmt: if AceConfig.osplatform != 'Windows': if fmt in AceConfig.transcodecmd: stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL popen_params = { 'bufsize': 1048576, 'stdin': gevent.subprocess.PIPE, 'stdout': self.wfile, 'stderr': stderr, 'shell': False } try: gevent.spawn(lambda: psutil.Popen( AceConfig.transcodecmd[fmt], **popen_params )).link(transcoder) out = transcoder.get(timeout=2.0).stdin logger.info( '[{channelName}]: Transcoding to [{clientip}] started' .format(**self.__dict__)) except: logger.error( '[{channelName}]: Error starting transcoding to [{clientip}]! Is ffmpeg or VLC installed?' .format(**self.__dict__)) else: logger.error( "[{channelName}]: Can't found fmt key. Transcoding to [{clientip}] not started!" .format(**self.__dict__)) elif AceConfig.osplatform == 'Windows': logger.error( '[{channelName}]: Not applicable in Windnows OS. Transcoding to [{clientip}] not started!' .format(**self.__dict__)) if AceProxy.clientcounter.addClient(self) == 1: # Create broadcast if it does not exist yet gevent.spawn( StreamReader, self.ace.GetBroadcastStartParams(self.__dict__) ).link(lambda x: logger.debug( '[{channelName}]: Broadcast destroyed. Last client disconnected' .format(**self.__dict__))) logger.debug('[{channelName}]: Broadcast created'.format( **self.__dict__)) else: logger.debug( '[{channelName}]: Broadcast already exists'.format( **self.__dict__)) logger.info( '[{channelName}]: Streaming to [{clientip}] started'. format(**self.__dict__)) # Sending videostream headers to client response_use_chunked = False if ( transcoder.value or self.request_version == 'HTTP/1.0') else AceConfig.use_chunked drop_headers = [] proxy_headers = { 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=%s, max=100' % AceConfig.videotimeout, 'Accept-Ranges': 'none', 'Transfer-Encoding': 'chunked', 'Content-Type': 'video/MP2T' if mimetype is None else mimetype, } if not response_use_chunked: self.protocol_version = 'HTTP/1.0' proxy_headers['Connection'] = 'Close' drop_headers.extend(['Transfer-Encoding', 'Keep-Alive']) response_headers = [(k, v) for (k, v) in proxy_headers.items() if k not in drop_headers] self.send_response(200) logger.debug('[%s]: Sending HTTPAceProxy headers: %s' % (self.clientip, dict(response_headers))) gevent.joinall([ gevent.spawn(self.send_header, k, v) for (k, v) in response_headers ]) self.end_headers() # write data to client while it is alive for chunk in self.q: out.write(b'%X\r\n%s\r\n' % (len(chunk), chunk) if response_use_chunked else chunk) except aceclient.AceException as e: _ = AceProxy.pool.map( lambda x: x.send_error(500, repr(e), logging.ERROR), AceProxy.clientcounter.getClientsList(self.infohash)) except gevent.socket.error: pass # Client disconnected except gevent.GreenletExit: AceProxy.clientcounter.idleAce._read.kill() finally: AceProxy.clientcounter.deleteClient(self) logger.info( '[{channelName}]: Streaming to [{clientip}] finished'.format( **self.__dict__)) if transcoder.value: try: transcoder.value.kill() logger.info( '[{channelName}]: Transcoding to [{clientip}] stoped'. format(**self.__dict__)) except: pass
def handle(self, connection): P2pproxy.logger.debug('Handling request') hostport = connection.headers['Host'] self.params = parse_qs(connection.query) # /channels/ branch if connection.reqtype in ('channels', 'channels.m3u'): if connection.path.endswith('play'): # /channels/play?id=[id] channel_id = self.params.get('id', [''])[0] if not channel_id: # /channels/play?id=&_=[epoch timestamp] is Torrent-TV widget proxy check # P2pProxy simply closes connection on this request sending Server header, so do we if self.params.get('_', [''])[0]: P2pproxy.logger.debug('Status check') response_headers = { 'Content-Type': 'text/plain;charset=utf-8', 'Server': 'P2pProxy/1.0.4.4 HTTPAceProxy', 'Access-Control-Allow-Origin': '*', 'Connection': 'close' } connection.send_response(200) for k, v in response_headers.items(): connection.send_header(k, v) connection.wfile.write('\r\n') return else: connection.send_error(400, 'Bad request') # Bad request try: stream_type, stream, translations_list = TorrentTvApi( config.email, config.password).stream_source(channel_id) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) name = logo = '' for channel in translations_list: if channel.getAttribute('id') == channel_id: name = channel.getAttribute('name') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = config.logobase + logo break if stream_type not in ('torrent', 'contentid'): connection.send_error( 404, 'Unknown stream type: %s' % stream_type, logging.ERROR) elif stream_type == 'torrent': connection.path = '/url/%s/%s.ts' % (quote(stream, ''), name) elif stream_type == 'contentid': connection.path = '/content_id/%s/%s.ts' % (stream, name) connection.__dict__.update( {'splittedpath': connection.path.split('/')}) connection.__dict__.update({ 'channelName': name, 'channelIcon': logo, 'reqtype': connection.splittedpath[1].lower() }) return # /channels/?filter=[filter]&group=[group]&type=m3u elif connection.reqtype == 'channels.m3u' or self.params.get( 'type', [''])[0] == 'm3u': param_group = self.params.get('group', [''])[0] if param_group and 'all' in param_group: param_group = None try: translations_list = TorrentTvApi( config.email, config.password).translations( self.params.get('filter', ['all'])[0]) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) P2pproxy.logger.debug('Generating requested m3u playlist') for channel in translations_list: group_id = channel.getAttribute('group') if param_group and not group_id in param_group.split(','): continue # filter channels by &group=1,2,5... name = channel.getAttribute('name') group = TorrentTvApi.CATEGORIES[int(group_id)] cid = channel.getAttribute('id') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = config.logobase + logo fields = { 'name': name, 'id': cid, 'url': cid, 'group': group, 'logo': logo, 'tvgid': config.tvgid.format(**fields) if channel.getAttribute('epg_id') != '0' else '' } playlistgen.addItem(fields) P2pproxy.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u( hostport=hostport, header=config.m3uheadertemplate, fmt=self.params.get('fmt', [''])[0]) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') try: h = connection.headers.get('Accept-Encoding').split(',')[0] exported = P2pproxy.compress_method[h].compress( exported) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.end_headers() connection.wfile.write(exported) # /channels/?filter=[filter] else: try: translations_list = TorrentTvApi( config.email, config.password).translations( self.params.get('filter', ['all'])[0], True) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) P2pproxy.logger.debug('Exporting m3u playlist') response_headers = { 'Access-Control-Allow-Origin': '*', 'Connection': 'close', 'Content-Type': 'text/xml;charset=utf-8', 'Content-Length': len(translations_list) } try: h = connection.headers.get('Accept-Encoding').split(',')[0] translations_list = P2pproxy.compress_method[h].compress( translations_list) + P2pproxy.compress_method[h].flush( ) connection.send_header('Content-Encoding', h) except: pass response_headers['Content-Length'] = len(translations_list) connection.send_response(200) for k, v in response_headers.items(): connection.send_header(k, v) connection.end_headers() connection.wfile.write(translations_list) # same as /channels request elif connection.reqtype == 'xbmc.pvr' and connection.path.endswith( 'playlist'): connection.send_response(200) connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Connection', 'close') connection.send_header('Content-Type', 'text/xml;charset=utf-8') try: translations_list = TorrentTvApi(config.email, config.password).translations( 'all', True) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) try: h = connection.headers.get('Accept-Encoding').split(',')[0] translations_list = P2pproxy.compress_method[h].compress( translations_list) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(translations_list)) connection.end_headers() P2pproxy.logger.debug('Exporting m3u playlist') connection.wfile.write(translations_list) # /archive/ branch elif connection.reqtype == 'archive': if connection.path.endswith( ('dates', 'dates.m3u')): # /archive/dates.m3u d = datetime.now() delta = timedelta(days=1) playlistgen = PlaylistGenerator() hostport = connection.headers['Host'] days = int(self.params.get('days', ['7'])[0]) suffix = '&suffix=%s' % self.params.get( 'suffix')[0] if 'suffix' in self.params else '' for i in range(days): dfmt = d.strftime('%d-%m-%Y') url = 'http://%s/archive/playlist/?date=%s%s' % ( hostport, dfmt, suffix) playlistgen.addItem({ 'group': '', 'tvg': '', 'name': dfmt, 'url': url }) d -= delta exported = playlistgen.exportm3u(hostport=hostport, empty_header=True, parse_url=False, fmt=self.params.get( 'fmt', [''])[0]) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') try: h = connection.headers.get('Accept-Encoding').split(',')[0] exported = P2pproxy.compress_method[h].compress( exported) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.end_headers() connection.wfile.write(exported) return elif connection.path.endswith( ('playlist', 'playlist.m3u')): # /archive/playlist.m3u dates = [] if 'date' in self.params: for d in self.params['date']: dates.append(self.parse_date(d).strftime('%d-%m-%Y')) else: d = datetime.now() delta = timedelta(days=1) days = int(self.params.get('days', ['7'])[0]) for i in range(days): dates.append(d.strftime('%d-%m-%Y')) d -= delta connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') try: channels_list = TorrentTvApi( config.email, config.password).archive_channels() except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) hostport = connection.headers['Host'] playlistgen = PlaylistGenerator() suffix = '&suffix=%s' % self.params.get( 'suffix')[0] if 'suffix' in self.params else '' for channel in channels_list: epg_id = channel.getAttribute('epg_id') name = channel.getAttribute('name') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = config.logobase + logo for d in dates: n = name + ' (' + d + ')' if len(dates) > 1 else name url = 'http://%s/archive/?type=m3u&date=%s&channel_id=%s%s' % ( hostport, d, epg_id, suffix) playlistgen.addItem({ 'group': name, 'tvg': '', 'name': n, 'url': url, 'logo': logo }) exported = playlistgen.exportm3u(hostport=hostport, empty_header=True, parse_url=False, fmt=self.params.get( 'fmt', [''])[0]) try: h = connection.headers.get('Accept-Encoding').split(',')[0] exported = P2pproxy.compress_method[h].compress( exported) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.end_headers() connection.wfile.write(exported) return elif connection.path.endswith('channels'): # /archive/channels connection.send_response(200) connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Connection', 'close') connection.send_header('Content-Type', 'text/xml;charset=utf-8') try: archive_channels = TorrentTvApi( config.email, config.password).archive_channels(True) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) P2pproxy.logger.debug('Exporting m3u playlist') try: h = connection.headers.get('Accept-Encoding').split(',')[0] archive_channels = P2pproxy.compress_method[h].compress( archive_channels) + P2pproxy.compress_method[h].flush( ) connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(archive_channels)) connection.end_headers() connection.wfile.write(archive_channels) return if connection.path.endswith( 'play'): # /archive/play?id=[record_id] record_id = self.params.get('id', [''])[0] if not record_id: connection.send_error(400, 'Bad request') # Bad request try: stream_type, stream = TorrentTvApi( config.email, config.password).archive_stream_source(record_id) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) if stream_type not in ('torrent', 'contentid'): connection.send_error( 404, 'Unknown stream type: %s' % stream_type, logging.ERROR) elif stream_type == 'torrent': connection.path = '/url/%s/stream.ts' % quote(stream, '') elif stream_type == 'contentid': connection.path = '/content_id/%s/stream.ts' % stream connection.__dict__.update( {'splittedpath': connection.path.split('/')}) connection.__dict__.update( {'reqtype': connection.splittedpath[1].lower()}) return # /archive/?type=m3u&date=[param_date]&channel_id=[param_channel] elif self.params.get('type', [''])[0] == 'm3u': playlistgen = PlaylistGenerator() param_channel = self.params.get('channel_id', [''])[0] d = self.get_date_param() if not param_channel: try: channels_list = TorrentTvApi( config.email, config.password).archive_channels() except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) for channel in channels_list: channel_id = channel.getAttribute('epg_id') try: try: records_list = TorrentTvApi( config.email, config.password).records(channel_id, d) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) channel_name = channel.getAttribute('name') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = config.logobase + logo for record in records_list: name = record.getAttribute('name') record_id = record.getAttribute('record_id') playlistgen.addItem({ 'group': channel_name, 'tvg': '', 'name': name, 'url': record_id, 'logo': logo }) except: P2pproxy.logger.debug( 'Failed to load archive for %s' % channel_id) else: try: records_list = TorrentTvApi(config.email, config.password).records( param_channel, d) channels_list = TorrentTvApi( config.email, config.password).archive_channels() except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) P2pproxy.logger.debug('Generating archive m3u playlist') for record in records_list: record_id = record.getAttribute('record_id') channel_id = record.getAttribute('epg_id') name = record.getAttribute('name') d = datetime.fromtimestamp( float( record.getAttribute('time'))).strftime('%H:%M') n = '%s %s' % (d, name) logo = '' for channel in channels_list: if channel.getAttribute('epg_id') == channel_id: channel_name = channel.getAttribute('name') logo = channel.getAttribute('logo') if channel_name != '': name = '(' + channel_name + ') ' + name if logo != '' and config.fullpathlogo: logo = config.logobase + logo playlistgen.addItem({ 'group': channel_name, 'name': n, 'url': record_id, 'logo': logo, 'tvg': '' }) P2pproxy.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u(hostport=hostport, empty_header=True, archive=True, fmt=self.params.get( 'fmt', [''])[0]) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') try: h = connection.headers.get('Accept-Encoding').split(',')[0] exported = P2pproxy.compress_method[h].compress( exported) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.end_headers() connection.wfile.write(exported) # /archive/?date=[param_date]&channel_id=[param_channel] else: param_date = self.params.get('date', [''])[0] if not param_date: d = datetime.now() else: try: d = parse_date(param_date) except: return param_channel = self.params.get('channel_id', [''])[0] if not param_channel: connection.send_error( 500, 'Got /archive/ request but no channel_id specified!', logging.ERROR) connection.send_response(200) connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Connection', 'close') connection.send_header('Content-Type', 'text/xml;charset=utf-8') try: records_list = TorrentTvApi(config.email, config.password).records( param_channel, d.strftime('%d-%m-%Y'), True) except Exception as err: connection.send_error(404, '%s' % repr(err), logging.ERROR) P2pproxy.logger.debug('Exporting m3u playlist') try: h = connection.headers.get('Accept-Encoding').split(',')[0] records_list = P2pproxy.compress_method[h].compress( records_list) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(records_list)) connection.end_headers() connection.wfile.write(records_list) # Used to generate logomap for the torrenttv plugin elif connection.reqtype == 'logobase': logomap = {} try: import config.picons.torrenttv as picons logomap = { k: v[v.rfind('/') + 1:] for k, v in picons.logomap.items() if v is not None } except: pass #try: translations_list = TorrentTvApi(config.email, config.password).translations('all') #except Exception as err: # connection.send_error(404, '%s' % repr(err), logging.ERROR) # return #logomap.update({ channel.getAttribute('name'):channel.getAttribute('logo') for channel in translations_list }) import requests url = 'http://hmxuku36whbypzxi.onion/trash/ttv-list/ttv_logo.json' proxies = { 'http': 'socks5h://192.168.2.1:9100', 'https': 'socks5h://192.168.2.1:9100' } with requests.get(url, proxies=proxies, timeout=30) as r: logomap.update(r.json()) connection.send_response(200) if self.params.get('format', [''])[0] == 'json': from requests.compat import json exported = ensure_binary( json.dumps(logomap, ensure_ascii=False)) connection.send_header('Content-Type', 'application/json') else: exported = "logobase = '%s'\nlogomap = {\n" % config.logobase exported += ''.join(" u'%s': logobase + '%s',\n" % (name, logo) for name, logo in logomap.items()) exported += '}\n' exported = ensure_binary(exported) connection.send_header('Content-Type', 'text/plain;charset=utf-8') try: h = connection.headers.get('Accept-Encoding').split(',')[0] exported = P2pproxy.compress_method[h].compress( exported) + P2pproxy.compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.end_headers() connection.wfile.write(exported) P2pproxy.logger.debug('%s picon channels exported' % len(logomap))
def READY(request_key='', product_key=AceConst.ACE_KEY): return 'READY key={}-{}'.format( product_key.split('-')[0], hashlib.sha1(ensure_binary(request_key + product_key)).hexdigest())
def Playlistparser(self): try: s = requests.Session() s.mount('file://', FileAdapter()) for index in range(3): try: logging.info("[%s]: get: %s" % (self.__class__.__name__, config.url)) with s.get(config.url, headers=self.headers, proxies=config.proxies, stream=False, timeout=(5,30)) as playlist: if playlist.status_code != 304: if playlist.encoding is None: playlist.encoding = 'utf-8' playlist = playlist.json() self.headers['If-Modified-Since'] = gevent.time.strftime('%a, %d %b %Y %H:%M:%S %Z', gevent.time.gmtime(self.playlisttime)) self.playlist = PlaylistGenerator(m3uchanneltemplate=config.m3uchanneltemplate) self.picons = picons.logomap self.channels = {} m = requests.auth.hashlib.md5() logging.info('[%s]: playlist %s downloaded' % (self.__class__.__name__, config.url)) try: for item in playlist: channel = {} name = item['name'] channel['name'] = name channel['url'] = 'infohash://{}'.format(item['infohash']) if 'categories' in item: channel['group'] = item['categories'][0] else: channel['group'] = u'tv' print('No category: ', item) channel['logo'] = self.picons[name] = channel.get('logo', get_logo(picons.logomap, name)) channel['availability'] = item['availability'] print("Added: ", channel) self.playlist.addItem(channel) m.update(ensure_binary(name)) #urlpattern = requests.utils.re.compile(r'^(acestream|infohash)://[0-9a-f]{40}$|^(http|https)://.*.(acelive|acestream|acemedia|torrent)$') #for channel in playlist['channels']: # name = channel['name'] # url = 'acestream://{url}'.format(**channel) # channel['group'] = channel.pop('cat') # channel['logo'] = self.picons[name] = channel.get('logo', get_logo(picons.logomap, name)) # # if requests.utils.re.search(urlpattern, url): # self.channels[name] = url # channel['url'] = quote(ensure_str(name),'') # # self.playlist.addItem(channel) # m.update(ensure_binary(name)) except Exception as e: print("Exception1: ", e) logging.error("[%s]: can't parse JSON! %s" % (self.__class__.__name__, repr(e))) return False self.etag = '"' + m.hexdigest() + '"' logging.debug('[%s]: plugin playlist generated' % self.__class__.__name__) self.playlisttime = gevent.time.time() logging.info("Return True") print("Return True") return True except ValueError as e: print("Exception2: ", e) logging.error("[%s]: can't parse %s playlist, attempt: %d" % (self.__class__.__name__, config.url, index + 1)) if index + 1 < 3: logging.error("Sleeping") time.sleep((index + 1) * 2) logging.error("Sleeping end") else: logging.error("Return False") return False except requests.exceptions.RequestException: logging.error("[%s]: can't download %s playlist!" % (self.__class__.__name__, config.url)) return False except: logging.error("[%s]: can't parse %s playlist!" % (self.__class__.__name__, config.url)) logging.error(traceback.format_exc()) return False