def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Connection', 'close') connection.end_headers() return # 15 minutes cache if not Allfon.playlist or (int(time.time()) - Allfon.playlisttime > 15 * 60): if not self.downloadPlaylist(): connection.dieWithError() return playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) Allfon.logger.debug('Generating requested m3u playlist') pattern = requests.auth.re.compile( r',(?P<name>.+)[\r\n].+[\r\n].+[\r\n](?P<url>[^\r\n]+)?') for match in pattern.finditer(Allfon.playlist.text, requests.auth.re.MULTILINE): playlistgen.addItem(match.groupdict()) Allfon.logger.debug('Exporting m3u playlist') params = parse_qs(connection.query) add_ts = True if connection.path.endswith('/ts') else False exported = playlistgen.exportm3u(hostport, header=config.m3uheadertemplate, add_ts=add_ts, fmt=params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Access-Control-Allow-Origin', '*') try: h = connection.headers.get('Accept-Encoding').split(',')[0] compress_method = { 'zlib': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS), 'deflate': zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS), 'gzip': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) } exported = compress_method[h].compress( exported) + compress_method[h].flush() connection.send_header('Content-Encoding', h) except: pass connection.send_header('Content-Length', len(exported)) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
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 handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Connection', 'close') connection.end_headers() return query = urlparse(connection.path).query self.params = parse_qs(query) url = None list_type = self.getparam('type') if not list_type or list_type.startswith('ttv'): url = config.url_ttv elif list_type.startswith('mob_ttv'): url = config.url_mob_ttv elif list_type.startswith('allfon'): url = config.url_allfon # 15 minutes cache if not Torrenttelik.playlist or ( int(time.time()) - Torrenttelik.playlisttime > 15 * 60): if not self.downloadPlaylist(url): connection.dieWithError() return try: channels = Torrenttelik.playlist.json()['channels'] except Exception as e: Torrenttelik.logger.error("Can't parse JSON! %s" % repr(e)) return add_ts = False try: if connection.splittedpath[2].lower() == 'ts': add_ts = True except: pass playlistgen = PlaylistGenerator() for channel in channels: channel['group'] = channel.get('cat', '') playlistgen.addItem(channel) header = '#EXTM3U url-tvg="%s" tvg-shift=%d deinterlace=1 m3uautoload=1 cache=1000\n' % ( config.tvgurl, config.tvgshift) exported = playlistgen.exportm3u( hostport, header=header, add_ts=add_ts, fmt=self.getparam('fmt')).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def Playlistparser(self): try: with requests.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' 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() self.logger.info('Playlist %s downloaded' % config.url) try: for channel in playlist.json()['channels']: channel['name'] = name = channel.get('name', '') channel[ 'url'] = url = 'acestream://%s' % channel.get( 'url') channel['group'] = channel.get('cat') if not 'logo' in channel: channel['logo'] = picons.logomap.get(name) self.picons[name] = channel['logo'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url channel['url'] = quote( ensure_str(name) + '.ts', '') self.playlist.addItem(channel) m.update(name.encode('utf-8')) except Exception as e: self.logger.error("Can't parse JSON! %s" % repr(e)) return self.etag = '"' + m.hexdigest() + '"' self.logger.debug('torrent-telik.m3u playlist generated') self.playlisttime = gevent.time.time() except requests.exceptions.RequestException: self.logger.error("Can't download %s playlist!" % config.url) return False except: self.logger.error(traceback.format_exc()) return False return True
def downloadPlaylist(self): headers = {'User-Agent': 'Magic Browser'} try: origin = requests.get(config.url, headers=headers, proxies=config.proxies, timeout=30).text.encode('utf-8') self.logger.info('TTV playlist %s downloaded' % config.url) self.playlisttime = int(time.time()) self.playlist = PlaylistGenerator(m3uchanneltemplate=config.m3uchanneltemplate) self.channels = dict() m = hashlib.md5() if self.updatelogos: try: translations_list = TorrentTvApi(p2pconfig.email, p2pconfig.password).translations('all') for channel in translations_list: name = channel.getAttribute('name').encode('utf-8') logo = channel.getAttribute('logo').encode('utf-8') if channel.getAttribute('epg_id') not in ('0', '', ' '): self.epg_id[name.decode('utf-8')] = 'ttv%s' % channel.getAttribute('id').encode('utf-8') if not name.decode('utf-8') in self.logomap: self.logomap[name.decode('utf-8')] = config.logobase + logo self.logger.debug("Logos updated") self.updatelogos = False except: self.updatelogos = False # p2pproxy plugin seems not configured self.logger.debug('Generating requested m3u playlist') pattern = re.compile(r',(?P<name>\S.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?') for match in pattern.finditer(origin, re.MULTILINE): itemdict = match.groupdict() encname = itemdict.get('name') name = encname.decode('utf-8') logo = self.logomap.get(name) itemdict['logo'] = logo if logo else 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' tvgid = self.epg_id.get(name) if tvgid: itemdict['tvgid'] = tvgid url = itemdict['url'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url itemdict['url'] = requests.compat.quote(encname,'') + '.ts' self.playlist.addItem(itemdict) m.update(encname) self.etag = '"' + m.hexdigest() + '"' except requests.exceptions.ConnectionError: self.logger.error("Can't download TTV playlist!"); return False except: self.logger.error(traceback.format_exc()); return False return True
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() self.logger.info('Playlist %s downloaded' % config.url) pattern = requests.auth.re.compile( r',(?P<name>.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?' ) for match in pattern.finditer(r.text, requests.auth.re.MULTILINE): itemdict = match.groupdict() name = itemdict.get('name', '') if not 'logo' in itemdict: itemdict['logo'] = picons.logomap.get(name) self.picons[name] = itemdict['logo'] url = itemdict['url'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive', '.acestream', '.acemedia', '.torrent'))): self.channels[name] = url itemdict['url'] = quote(ensure_str('%s.ts' % name), '') self.playlist.addItem(itemdict) m.update(name.encode('utf-8')) self.etag = '"' + m.hexdigest() + '"' self.logger.debug('torrenttv.m3u playlist generated') self.playlisttime = gevent.time.time() except requests.exceptions.RequestException: self.logger.error("Can't download %s playlist!" % config.url) return False except: self.logger.error(traceback.format_exc()) return False return True
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Connection', 'close') connection.end_headers() return self.params = { k: [v] for k, v in (requests.compat.unquote(x).split('=') for x in [ s2 for s1 in connection.query.split('&') for s2 in s1.split(';') ] if '=' in x) } # 15 minutes cache if not Torrenttelik.playlist or ( int(time.time()) - Torrenttelik.playlisttime > 15 * 60): if not self.downloadPlaylist(config.url): connection.dieWithError() return add_ts = True if connection.path.endswith('/ts') else False playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) Torrenttelik.logger.debug('Generating requested m3u playlist') try: for channel in Torrenttelik.playlist['channels']: channel['group'] = channel.get('cat', '') channel['url'] = 'acestream://%s' % channel.get('url', '') playlistgen.addItem(channel) except Exception as e: Torrenttelik.logger.error("Can't parse JSON! %s" % repr(e)) return Torrenttelik.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u( hostport, header=config.m3uheadertemplate, add_ts=add_ts, fmt=self.getparam('fmt')).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def downloadPlaylist(self): headers = {'User-Agent': 'Magic Browser', 'Accept-Encoding': 'gzip,deflate', 'Connection': 'close'} try: if config.useproxy: origin = requests.get(config.url, headers=headers, proxies=config.proxies, timeout=30).text else: origin = requests.get(config.url, headers=headers, timeout=5).text self.logger.info('TTV playlist ' + config.url + ' downloaded') self.playlisttime = int(time.time()) self.playlist = PlaylistGenerator() self.channels = dict() m = hashlib.md5() pattern = re.compile(r',(?P<name>\S.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?') for match in pattern.finditer(origin.encode('UTF-8'), re.MULTILINE): itemdict = match.groupdict() encname = itemdict.get('name') name = encname.decode('UTF-8') logo = self.logomap.get(name) url = itemdict['url'] if logo: itemdict['logo'] = logo if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url itemdict['url'] = requests.utils.quote(encname, '') + '.mp4' self.playlist.addItem(itemdict) m.update(encname) self.etag = '"' + m.hexdigest() + '"' except requests.exceptions.ConnectionError: self.logger.error("Can't download TTV playlist!") return False if self.updatelogos: try: api = TorrentTvApi(p2pconfig.email, p2pconfig.password) translations = api.translations('all') logos = dict() for channel in translations: name = channel.getAttribute('name').encode('utf-8') logo = channel.getAttribute('logo').encode('utf-8') logos[name] = config.logobase + logo self.logomap = logos self.logger.debug("Logos updated") self.updatelogos = False except: self.updatelogos = False # p2pproxy plugin seems not configured return True
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Connection', 'close') connection.end_headers() return # 15 minutes cache if not Allfon.playlist or (int(time.time()) - Allfon.playlisttime > 15 * 60): if not self.downloadPlaylist(): connection.dieWithError() return add_ts = True if connection.path.endswith('/ts') else False playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) Allfon.logger.debug('Generating requested m3u playlist') pattern = re.compile( r',(?P<name>\S.+)[\r\n].+[\r\n].+[\r\n](?P<url>[^\r\n]+)?') for match in pattern.finditer(Allfon.playlist, re.MULTILINE): playlistgen.addItem(match.groupdict()) Allfon.logger.debug('Exporting m3u playlist') params = { k: [v] for k, v in (requests.compat.unquote(x).split('=') for x in [ s2 for s1 in connection.query.split('&') for s2 in s1.split(';') ] if '=' in x) } fmt = params['fmt'][0] if 'fmt' in params else None exported = playlistgen.exportm3u(hostport, header=config.m3uheadertemplate, add_ts=add_ts, fmt=fmt) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def add_playlists(n): cursor, conn = open_connection() gen_playlist = PlaylistGenerator() data = gen_playlist.get_primary_key_data(n) for d in data: params = gen_playlist.get_params() print('id: ', d, params, sep=': ') cursor.execute( 'insert into playlist (id, name, quantity, author, duration, icon_path) VALUES (%s, %s, %s, %s, %s, ' '%s);commit;', (d, params.get('name'), params.get('quantity'), params.get('author'), params.get('duration'), params.get('icon_path'))) print(n, "Playlists added", sep=' ') close_connection(cursor, conn)
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Connection', 'close') connection.end_headers() return # 15 minutes cache if not Allfon.playlist or (int(time.time()) - Allfon.playlisttime > 15 * 60): if not self.downloadPlaylist(): connection.dieWithError() return matches = re.finditer( r'\#EXTINF\:0\,(?P<name>\S.+)\n.+\n.+\n(?P<url>^acestream.+$)', Allfon.playlist, re.MULTILINE) add_ts = False try: if connection.splittedpath[2].lower() == 'ts': add_ts = True except: pass playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) for match in matches: playlistgen.addItem(match.groupdict()) Allfon.logger.info('AllFon playlist created') url = urlparse(connection.path) params = parse_qs(url.query) fmt = params['fmt'][0] if 'fmt' in params else None header = '#EXTM3U url-tvg="%s" tvg-shift=%d deinterlace=1 m3uautoload=1 cache=1000\n' % ( config.tvgurl, config.tvgshift) exported = playlistgen.exportm3u(hostport, header=header, add_ts=add_ts, fmt=fmt) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Connection', 'close') connection.end_headers() return params = parse_qs(connection.query) # 15 minutes cache if not Torrenttelik.playlist or ( int(time.time()) - Torrenttelik.playlisttime > 15 * 60): if not self.downloadPlaylist(config.url): connection.dieWithError() return add_ts = True if connection.path.endswith('/ts') else False playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) Torrenttelik.logger.debug('Generating requested m3u playlist') try: for channel in Torrenttelik.playlist['channels']: channel['group'] = channel.get('cat', '') channel['url'] = 'acestream://%s' % channel.get('url', '') playlistgen.addItem(channel) except Exception as e: Torrenttelik.logger.error("Can't parse JSON! %s" % repr(e)) return Torrenttelik.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u(hostport, header=config.m3uheadertemplate, add_ts=add_ts, fmt=params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Connection', 'close') connection.end_headers() return # 15 minutes cache if not Allfon.playlist or (int(time.time()) - Allfon.playlisttime > 15 * 60): if not self.downloadPlaylist(): connection.dieWithError() return playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) Allfon.logger.debug('Generating requested m3u playlist') pattern = re.compile( r',(?P<name>.+)[\r\n].+[\r\n].+[\r\n](?P<url>[^\r\n]+)?') for match in pattern.finditer(Allfon.playlist, re.MULTILINE): playlistgen.addItem(match.groupdict()) Allfon.logger.debug('Exporting m3u playlist') params = parse_qs(connection.query) add_ts = True if connection.path.endswith('/ts') else False exported = playlistgen.exportm3u(hostport, header=config.m3uheadertemplate, add_ts=add_ts, fmt=params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def handle(self, connection, headers_only=False): hostport = connection.headers['Host'] if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Connection', 'close') connection.end_headers() return # 15 minutes cache if not Allfon.playlist or (int(time.time()) - Allfon.playlisttime > 15 * 60): if not self.downloadPlaylist(): connection.dieWithError() return add_ts = True if connection.path.endswith('/ts') else False playlistgen = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) pattern = re.compile( r',(?P<name>\S.+)[\r\n].+[\r\n].+[\r\n](?P<url>[^\r\n]+)?') for match in pattern.finditer(Allfon.playlist, re.MULTILINE): playlistgen.addItem(match.groupdict()) Allfon.logger.info('AllFon playlist created') params = parse_qs(connection.query) fmt = params['fmt'][0] if 'fmt' in params else None header = '#EXTM3U url-tvg="%s" tvg-shift=%d deinterlace=1 m3uautoload=1 cache=1000\n' % ( config.tvgurl, config.tvgshift) exported = playlistgen.exportm3u(hostport, header=header, add_ts=add_ts, fmt=fmt) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() connection.wfile.write(exported)
def handle(self, connection, headers_only=False): P2pproxy.logger.debug('Handling request') hostport = connection.headers['Host'] self.params = parse_qs(connection.query) # /channels/ branch if connection.reqtype in ('channels', 'channels.m3u'): # /channels/play?id=[id] if len( connection.splittedpath ) == 3 and connection.splittedpath[2].split('?')[0] == 'play': channel_id = self.get_param('id') 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.get_param('_'): P2pproxy.logger.debug('Status check') connection.send_response(200) connection.send_header('Access-Control-Allow-Origin', '*') connection.send_header('Connection', 'close') connection.send_header('Content-Type', 'text/plain;charset=utf-8') connection.send_header('Server', 'P2pProxy/1.0.4.4 AceProxy') connection.wfile.write('\r\n') return else: connection.dieWithError(400, 'Bad request') # Bad request return if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'video/mpeg') connection.end_headers() return stream_url = None stream_type, stream, translations_list = self.api.stream_source( channel_id) name = logo = '' for channel in translations_list: if channel.getAttribute('id') == channel_id: name = channel.getAttribute('name') logo = channel.getAttribute('logo') if config.fullpathlogo: logo = P2pproxy.TTVU + logo break if stream_type == 'torrent': stream_url = re.sub( '^(http.+)$', lambda match: '/url/' + requests.utils.quote( match.group(0), '') + '/stream.mp4', stream) elif stream_type == 'contentid': stream_url = re.sub( '^([0-9a-f]{40})', lambda match: '/content_id/' + requests.utils.quote( match.group(0), '') + '/stream.mp4', stream) connection.path = stream_url connection.splittedpath = stream_url.split('/') connection.reqtype = connection.splittedpath[1].lower() connection.handleRequest(headers_only, name, logo, fmt=self.get_param('fmt')) # /channels/?filter=[filter]&group=[group]&type=m3u elif connection.reqtype == 'channels.m3u' or self.get_param( 'type') == 'm3u': if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.end_headers() return param_group = self.params.get('group') param_filter = self.get_param('filter') if not param_filter: param_filter = 'all' # default filter if param_group: if 'all' in param_group: param_group = None else: tmp = [] for g in param_group: tmp += g.split(',') param_group = tmp translations_list = self.api.translations(param_filter) playlistgen = PlaylistGenerator() 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: continue # filter channels by group name = channel.getAttribute('name') group = TorrentTvApi.CATEGORIES[int(group_id)].decode( 'UTF-8') cid = channel.getAttribute('id') logo = channel.getAttribute('logo') if config.fullpathlogo: logo = P2pproxy.TTVU + logo fields = { 'name': name, 'id': cid, 'url': cid, 'group': group, 'logo': logo } fields['tvgid'] = config.tvgid % fields playlistgen.addItem(fields) P2pproxy.logger.debug('Exporting') header = '#EXTM3U url-tvg="%s" tvg-shift=%d deinterlace=1 m3uautoload=1 cache=1000\n' % ( config.tvgurl, config.tvgshift) exported = playlistgen.exportm3u( hostport=hostport, header=header, fmt=self.get_param('fmt')).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) # /channels/?filter=[filter] else: if headers_only: 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') connection.end_headers() return param_filter = self.get_param('filter') if not param_filter: param_filter = 'all' # default filter translations_list = self.api.translations(param_filter, True) P2pproxy.logger.debug('Exporting') 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') connection.send_header('Content-Length', str(len(translations_list))) connection.end_headers() connection.wfile.write(translations_list) # same as /channels request elif connection.reqtype == 'xbmc.pvr': if len(connection.splittedpath ) == 3 and connection.splittedpath[2] == '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') if headers_only: connection.end_headers() return translations_list = self.api.translations('all', True) connection.send_header('Content-Length', str(len(translations_list))) connection.end_headers() P2pproxy.logger.debug('Exporting') connection.wfile.write(translations_list) # /archive/ branch elif connection.reqtype == 'archive': if len(connection.splittedpath) >= 3 and ( connection.splittedpath[2] == 'dates' or connection.splittedpath[2] == 'dates.m3u'): # /archive/dates.m3u d = date.today() delta = timedelta(days=1) playlistgen = PlaylistGenerator() hostport = connection.headers['Host'] days = int( self.get_param('days')) if 'days' in self.params else 7 suffix = '&suffix=' + self.get_param( 'suffix') 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 = d - delta exported = playlistgen.exportm3u( hostport, empty_header=True, process_url=False, fmt=self.get_param('fmt')).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) return elif len(connection.splittedpath) >= 3 and ( connection.splittedpath[2] == 'playlist' or connection.splittedpath[2] == 'playlist.m3u'): # /archive/playlist.m3u dates = list() if 'date' in self.params: for d in self.params['date']: dates.append( self.parse_date(d).strftime('%d-%m-%Y').replace( '-0', '-')) else: d = date.today() delta = timedelta(days=1) days = int( self.get_param('days')) if 'days' in self.params else 7 for i in range(days): dates.append(d.strftime('%d-%m-%Y').replace('-0', '-')) d = d - delta connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') if headers_only: connection.end_headers() return channels_list = self.api.archive_channels() hostport = connection.headers['Host'] playlistgen = PlaylistGenerator() suffix = '&suffix=' + self.get_param( 'suffix') 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 = P2pproxy.TTVU + 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, empty_header=True, process_url=False, fmt=self.get_param('fmt')).encode('utf-8') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) return # /archive/channels elif len(connection.splittedpath ) == 3 and connection.splittedpath[2] == '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') if headers_only: connection.end_headers() else: archive_channels = self.api.archive_channels(True) P2pproxy.logger.debug('Exporting') connection.send_header('Content-Length', str(len(archive_channels))) connection.end_headers() connection.wfile.write(archive_channels) return # /archive/play?id=[record_id] if len( connection.splittedpath ) == 3 and connection.splittedpath[2].split('?')[0] == 'play': record_id = self.get_param('id') if not record_id: connection.dieWithError(400, 'Bad request') # Bad request return if headers_only: connection.send_response(200) connection.send_header("Content-Type", "video/mpeg") connection.end_headers() return stream_url = None stream_type, stream = self.api.archive_stream_source(record_id) if stream_type == 'torrent': stream_url = re.sub( '^(http.+)$', lambda match: '/url/' + requests.utils.quote( match.group(0), '') + '/stream.mp4', stream) elif stream_type == 'contentid': stream_url = re.sub( '^([0-9a-f]{40})', lambda match: '/content_id/' + requests.utils.quote( match.group(0), '') + '/stream.mp4', stream) connection.path = stream_url connection.splittedpath = stream_url.split('/') connection.reqtype = connection.splittedpath[1].lower() connection.handleRequest(headers_only, fmt=self.get_param('fmt')) # /archive/?type=m3u&date=[param_date]&channel_id=[param_channel] elif self.get_param('type') == 'm3u': d = self.get_date_param() if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.end_headers() return playlistgen = PlaylistGenerator() param_channel = self.get_param('channel_id') d = d.strftime('%d-%m-%Y').replace('-0', '-') if param_channel == '' or not param_channel: channels_list = self.api.archive_channels() for channel in channels_list: channel_id = channel.getAttribute('epg_id') try: records_list = self.api.records(channel_id, d) channel_name = channel.getAttribute('name') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = P2pproxy.TTVU + 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: records_list = self.api.records(param_channel, d) channels_list = self.api.archive_channels() 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 = P2pproxy.TTVU + logo playlistgen.addItem({ 'group': channel_name, 'name': n, 'url': record_id, 'logo': logo, 'tvg': '' }) P2pproxy.logger.debug('Exporting') exported = playlistgen.exportm3u( hostport, empty_header=True, archive=True, fmt=self.get_param('fmt')).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'application/x-mpegurl') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) # /archive/?date=[param_date]&channel_id=[param_channel] else: param_date = self.get_param('date') if not param_date: d = date.today() else: try: param_date = param_date.split('-') d = date(int(param_date[2]), int(param_date[1]), int(param_date[0])) except IndexError: connection.dieWithError(500, 'Date param is not correct!', logging.ERROR) return param_channel = self.get_param('channel_id') if param_channel == '' or not param_channel: connection.dieWithError( 500, 'Got /archive/ request but no channel_id specified!', logging.ERROR) return 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') if headers_only: connection.end_headers() else: records_list = self.api.records(param_channel, d.strftime('%d-%m-%Y'), True) P2pproxy.logger.debug('Exporting') connection.send_header('Content-Length', str(len(records_list))) connection.end_headers() connection.wfile.write(records_list) # Used to generate logomap for the torrenttv plugin elif connection.reqtype == 'logos': translations_list = self.api.translations('all') last = translations_list[-1] connection.send_response(200) connection.send_header('Content-Type', 'text/plain;charset=utf-8') connection.end_headers() connection.wfile.write("logobase = '" + P2pproxy.TTVU + "'\n") connection.wfile.write("logomap = {\n") for channel in translations_list: name = channel.getAttribute('name').encode('utf-8') logo = channel.getAttribute('logo').encode('utf-8') connection.wfile.write(" u'%s': logobase + '%s'" % (name, logo)) if not channel == last: connection.wfile.write(",\n") else: connection.wfile.write("\n") connection.wfile.write("}\n")
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 downloadPlaylist(self): self.playlisttime = int(gevent.time.time()) self.playlist = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) self.channels = {} m = requests.auth.hashlib.md5() try: if self.updatelogos: try: translations_list = TorrentTvApi( p2pconfig.email, p2pconfig.password).translations('all') for channel in translations_list: name = channel.getAttribute('name') if channel.getAttribute('epg_id') not in ('0', '', ' '): self.epg_id[name] = 'ttv%s' % channel.getAttribute( 'id') if not name in self.logomap: self.logomap[ name] = config.logobase + channel.getAttribute( 'logo') self.logger.debug('Logos updated') finally: self.updatelogos = False # p2pproxy plugin not configured headers = {'User-Agent': 'Magic Browser'} with requests.get(config.url, headers=headers, proxies=config.proxies, stream=False, timeout=30) as r: if r.encoding is None: r.encoding = 'utf-8' self.logger.info('TTV playlist %s downloaded' % config.url) pattern = requests.auth.re.compile( r',(?P<name>.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?' ) for match in pattern.finditer(r.text, requests.auth.re.MULTILINE): itemdict = match.groupdict() name = itemdict.get('name') itemdict['logo'] = self.logomap.get( name, 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' ) itemdict['tvgid'] = self.epg_id.get(name, '') url = itemdict['url'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url itemdict['url'] = quote(name.encode('utf-8'), '') + '.ts' self.playlist.addItem(itemdict) m.update(name.encode('utf-8')) self.etag = '"' + m.hexdigest() + '"' self.logger.debug('Requested m3u playlist generated') except requests.exceptions.RequestException: self.logger.error("Can't download TTV playlist!") return False except: self.logger.error(traceback.format_exc()) return False return True
def handle(self, connection, headers_only=False): 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 list(response_headers.items()): connection.send_header(k, v) connection.wfile.write('\r\n') return else: connection.dieWithError(400, 'Bad request') # Bad request return if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'video/mpeg') connection.end_headers() return stream_type, stream, translations_list = TorrentTvApi( config.email, config.password).stream_source(channel_id) 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 = P2pproxy.TTVU + logo break if stream_type not in (b'torrent', b'contentid'): connection.dieWithError( 404, 'Unknown stream type: %s' % stream_type, logging.ERROR) return elif stream_type == b'torrent': connection.path = '/url/%s/stream.mp4' % quote(stream, '') elif stream_type == b'contentid': connection.path = '/content_id/%s/stream.mp4' % stream connection.splittedpath = connection.path.split('/') connection.reqtype = connection.splittedpath[1].lower() connection.handleRequest(headers_only, name, logo, fmt=self.params.get('fmt', [''])[0]) # /channels/?filter=[filter]&group=[group]&type=m3u elif connection.reqtype == 'channels.m3u' or self.params.get( 'type', [''])[0] == 'm3u': if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.end_headers() return param_group = self.params.get('group', [''])[0] if param_group and 'all' in param_group: param_group = None translations_list = TorrentTvApi(config.email, config.password).translations( self.params.get( 'filter', ['all'])[0]) 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: 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 = P2pproxy.TTVU + logo fields = { 'name': name, 'id': cid, 'url': cid, 'group': group, 'logo': logo } if channel.getAttribute('epg_id') != '0': fields['tvgid'] = config.tvgid % fields playlistgen.addItem(fields) P2pproxy.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u( hostport=hostport, header=config.m3uheadertemplate, fmt=self.params.get('fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) # /channels/?filter=[filter] else: if headers_only: 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') connection.end_headers() return translations_list = TorrentTvApi( config.email, config.password).translations( self.params.get('filter', ['all'])[0], True) P2pproxy.logger.debug('Exporting m3u playlist') response_headers = { 'Access-Control-Allow-Origin': '*', 'Connection': 'close', 'Content-Type': 'text/xml;charset=utf-8', 'Content-Length': str(len(translations_list)) } connection.send_response(200) for k, v in list(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') if headers_only: connection.end_headers() return translations_list = TorrentTvApi(config.email, config.password).translations( 'all', True) connection.send_header('Content-Length', str(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] 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, empty_header=True, process_url=False, fmt=self.params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(len(exported))) connection.end_headers() connection.wfile.write(exported) return elif connection.path.endswith( ('playlist', 'playlist.m3u')): # /archive/playlist.m3u dates = list() 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') if headers_only: connection.end_headers() return channels_list = TorrentTvApi( config.email, config.password).archive_channels() hostport = connection.headers['Host'] playlistgen = PlaylistGenerator() suffix = '&suffix=%s' % self.params.get('suffix', [''])[0] 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 = P2pproxy.TTVU + 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, empty_header=True, process_url=False, fmt=self.params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_header('Content-Length', str(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') if headers_only: connection.end_headers() else: archive_channels = TorrentTvApi( config.email, config.password).archive_channels(True) P2pproxy.logger.debug('Exporting m3u playlist') connection.send_header('Content-Length', str(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.dieWithError(400, 'Bad request') # Bad request return if headers_only: connection.send_response(200) connection.send_header("Content-Type", "video/mpeg") connection.end_headers() return stream_type, stream = TorrentTvApi( config.email, config.password).archive_stream_source(record_id) if stream_type not in (b'torrent', b'contentid'): connection.dieWithError( 404, 'Unknown stream type: %s' % stream_type, logging.ERROR) return elif stream_type == b'torrent': connection.path = '/url/%s/stream.mp4' % quote(stream, '') elif stream_type == b'contentid': connection.path = '/content_id/%s/stream.mp4' % stream connection.splittedpath = connection.path.split('/') connection.reqtype = connection.splittedpath[1].lower() connection.handleRequest(headers_only, fmt=self.params.get('fmt', [''])[0]) # /archive/?type=m3u&date=[param_date]&channel_id=[param_channel] elif self.params.get('type', [''])[0] == 'm3u': if headers_only: connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.end_headers() return playlistgen = PlaylistGenerator() param_channel = self.params.get('channel_id', [''])[0] d = self.get_date_param() if not param_channel: channels_list = TorrentTvApi( config.email, config.password).archive_channels() for channel in channels_list: channel_id = channel.getAttribute('epg_id') try: records_list = TorrentTvApi( config.email, config.password).records(channel_id, d) channel_name = channel.getAttribute('name') logo = channel.getAttribute('logo') if logo != '' and config.fullpathlogo: logo = P2pproxy.TTVU + 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: records_list = TorrentTvApi(config.email, config.password).records( param_channel, d) channels_list = TorrentTvApi( config.email, config.password).archive_channels() 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 = P2pproxy.TTVU + logo playlistgen.addItem({ 'group': channel_name, 'name': n, 'url': record_id, 'logo': logo, 'tvg': '' }) P2pproxy.logger.debug('Exporting m3u playlist') exported = playlistgen.exportm3u(hostport, empty_header=True, archive=True, fmt=self.params.get( 'fmt', [''])[0]).encode('utf-8') connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('Content-Length', str(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.dieWithError( 500, 'Got /archive/ request but no channel_id specified!', logging.ERROR) return 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') if headers_only: connection.end_headers() else: records_list = TorrentTvApi(config.email, config.password).records( param_channel, d.strftime('%d-%m-%Y'), True) P2pproxy.logger.debug('Exporting m3u playlist') connection.send_header('Content-Length', str(len(records_list))) connection.end_headers() connection.wfile.write(records_list) # Used to generate logomap for the torrenttv plugin elif connection.reqtype == 'logos': translations_list = TorrentTvApi( config.email, config.password).translations('all') last = translations_list[-1] connection.send_response(200) connection.send_header('Content-Type', 'text/plain;charset=utf-8') connection.end_headers() connection.wfile.write("logobase = '" + P2pproxy.TTVU + "'\n") connection.wfile.write("logomap = {\n") for channel in translations_list: name = channel.getAttribute('name').encode('utf-8') logo = channel.getAttribute('logo').encode('utf-8') connection.wfile.write(" u'%s': logobase + '%s'" % (name, logo)) connection.wfile.write( ",\n") if not channel == last else connection.wfile.write( "\n") connection.wfile.write("}\n")
class Torrenttv(AceProxyPlugin): # ttvplaylist handler is obsolete handlers = ('torrenttv', 'ttvplaylist') def __init__(self, AceConfig, AceProxy): self.logger = logging.getLogger('torrenttv_plugin') self.picons = self.channels = self.playlist = self.etag = None self.playlisttime = gevent.time.time() self.headers = {'User-Agent': 'Magic Browser'} if config.updateevery: gevent.spawn(self.playlistTimedDownloader) def playlistTimedDownloader(self): while 1: self.Playlistparser() gevent.sleep(config.updateevery * 60) 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() self.logger.info('Playlist %s downloaded' % config.url) pattern = requests.auth.re.compile( r',(?P<name>.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?' ) for match in pattern.finditer(r.text, requests.auth.re.MULTILINE): itemdict = match.groupdict() name = itemdict.get('name', '') if not 'logo' in itemdict: itemdict['logo'] = picons.logomap.get(name) self.picons[name] = itemdict['logo'] url = itemdict['url'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive', '.acestream', '.acemedia', '.torrent'))): self.channels[name] = url itemdict['url'] = quote(ensure_str('%s.ts' % name), '') self.playlist.addItem(itemdict) m.update(name.encode('utf-8')) self.etag = '"' + m.hexdigest() + '"' self.logger.debug('torrenttv.m3u playlist generated') self.playlisttime = gevent.time.time() except requests.exceptions.RequestException: self.logger.error("Can't download %s playlist!" % config.url) return False except: self.logger.error(traceback.format_exc()) return False return True def handle(self, connection, headers_only=False): play = False # 30 minutes cache if not self.playlist or (gevent.time.time() - self.playlisttime > 30 * 60): if not self.Playlistparser(): connection.dieWithError() return url = urlparse(connection.path) path = url.path[0:-1] if url.path.endswith('/') else url.path params = parse_qs(connection.query) if path.startswith('/%s/channel/' % connection.reqtype): if not path.endswith('.ts'): connection.dieWithError(404, 'Invalid path: %s' % unquote(path), logging.ERROR) return name = ensure_text(unquote(path[path.rfind('/') + 1:])) url = self.channels.get('.'.join(name.split('.')[:-1])) if url is None: connection.dieWithError(404, 'Unknown channel: ' + name, logging.ERROR) return elif url.startswith('acestream://'): connection.path = '/content_id/%s/%s' % (url.split('/')[2], name) elif url.startswith('infohash://'): connection.path = '/infohash/%s/%s' % (url.split('/')[2], name) elif url.startswith(('http://', 'https://')) and url.endswith( ('.acelive', '.acestream', '.acemedia', '.torrent')): connection.path = '/url/%s/%s' % (quote(url, ''), name) connection.splittedpath = connection.path.split('/') connection.reqtype = connection.splittedpath[1].lower() name = name.split('.')[0] play = True elif self.etag == connection.headers.get('If-None-Match'): self.logger.debug('ETag matches - returning 304') connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: hostport = connection.headers['Host'] path = '' if not self.channels else '/%s/channel' % connection.reqtype add_ts = True if path.endswith('/ts') else False exported = self.playlist.exportm3u(hostport=hostport, path=path, add_ts=add_ts, header=config.m3uheadertemplate, fmt=params.get('fmt', [''])[0]) response_headers = { 'Content-Type': 'audio/mpegurl; charset=utf-8', 'Connection': 'close', 'Content-Length': len(exported), 'Access-Control-Allow-Origin': '*', 'ETag': self.etag } try: h = connection.headers.get('Accept-Encoding').split(',')[0] compress_method = { 'zlib': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS), 'deflate': zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS), 'gzip': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) } exported = compress_method[h].compress( exported) + compress_method[h].flush() response_headers['Content-Length'] = len(exported) response_headers['Content-Encoding'] = h except: pass connection.send_response(200) gevent.joinall([ gevent.spawn(connection.send_header, k, v) for (k, v) in response_headers.items() ]) connection.end_headers() if play: connection.handleRequest(headers_only, name, self.picons.get(name), fmt=params.get('fmt', [''])[0]) elif not headers_only: self.logger.debug('Exporting torrenttv.m3u playlist') connection.wfile.write(exported)
class Torrenttv(AceProxyPlugin): # ttvplaylist handler is obsolete handlers = ( 'torrenttv', 'ttvplaylist', ) def __init__(self, AceConfig, AceStuff): self.logger = logging.getLogger('torrenttv_plugin') self.channels = self.playlist = self.playlisttime = self.etag = self.tvgid = None self.logomap = config.logomap self.epg_id = {k: '' for k in self.logomap} self.updatelogos = p2pconfig.email != 're.place@me' and p2pconfig.password != 'ReplaceMe' if config.updateevery: gevent.spawn(self.playlistTimedDownloader) def playlistTimedDownloader(self): while 1: self.downloadPlaylist() gevent.sleep(config.updateevery * 60) def downloadPlaylist(self): self.playlisttime = int(gevent.time.time()) self.playlist = PlaylistGenerator( m3uchanneltemplate=config.m3uchanneltemplate) self.channels = {} m = hashlib.md5() try: if self.updatelogos: try: translations_list = TorrentTvApi( p2pconfig.email, p2pconfig.password).translations('all') for channel in translations_list: name = channel.getAttribute('name') if channel.getAttribute('epg_id') not in ('0', '', ' '): self.epg_id[name] = 'ttv%s' % channel.getAttribute( 'id') if not name in self.logomap: self.logomap[ name] = config.logobase + channel.getAttribute( 'logo') self.logger.debug("Logos updated") self.updatelogos = False except: self.updatelogos = False # p2pproxy plugin seems not configured headers = {'User-Agent': 'Magic Browser'} with requests.get(config.url, headers=headers, proxies=config.proxies, stream=False, timeout=30) as r: if r.encoding is None: r.encoding = 'utf-8' self.logger.info('TTV playlist %s downloaded' % config.url) pattern = re.compile( r',(?P<name>.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?' ) for match in pattern.finditer(r.text, re.MULTILINE): itemdict = match.groupdict() name = itemdict.get('name') itemdict['logo'] = self.logomap.get( name, 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' ) itemdict['tvgid'] = self.epg_id.get(name, '') url = itemdict['url'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url itemdict['url'] = requests.compat.quote( name.encode('utf-8'), '') + '.ts' self.playlist.addItem(itemdict) m.update(name.encode('utf-8')) self.etag = '"' + m.hexdigest() + '"' self.logger.debug('Requested m3u playlist generated') except requests.exceptions.ConnectionError: self.logger.error("Can't download TTV playlist!") return False except: self.logger.error(traceback.format_exc()) return False return True def handle(self, connection, headers_only=False): play = False # 30 minutes cache if not self.playlist or (int(gevent.time.time()) - self.playlisttime > 30 * 60): self.updatelogos = p2pconfig.email != 're.place@me' and p2pconfig.password != 'ReplaceMe' if not self.downloadPlaylist(): connection.dieWithError() return url = requests.compat.urlparse(connection.path) path = url.path[0:-1] if url.path.endswith('/') else url.path params = parse_qs(connection.query) if path.startswith('/torrenttv/channel/'): if not path.endswith('.ts'): connection.dieWithError( 404, 'Invalid path: %s' % requests.compat.unquote(path), logging.ERROR) return try: name = requests.compat.unquote(path.rsplit( '/', 1)[1][:-3]).decode('utf-8') except AttributeError: name = requests.compat.unquote(path.rsplit('/', 1)[1][:-3]) url = self.channels.get(name, None) if url is None: connection.dieWithError(404, 'Unknown channel: ' + name, logging.ERROR) return elif url.startswith('acestream://'): connection.path = '/content_id/%s/stream.ts' % url.split( '/')[2] elif url.startswith('infohash://'): connection.path = '/infohash/%s/stream.ts' % url.split('/')[2] elif url.startswith(('http://', 'https://')) and url.endswith( ('.acelive', '.acestream', '.acemedia')): connection.path = '/url/%s/stream.ts' % requests.compat.quote( url, '') connection.splittedpath = connection.path.split('/') connection.reqtype = connection.splittedpath[1].lower() play = True elif self.etag == connection.headers.get('If-None-Match'): self.logger.debug('ETag matches - returning 304') connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: self.logger.debug('Exporting m3u playlist') hostport = connection.headers['Host'] path = '' if len(self.channels) == 0 else '/torrenttv/channel' add_ts = True if path.endswith('/ts') else False exported = self.playlist.exportm3u( hostport=hostport, path=path, add_ts=add_ts, header=config.m3uheadertemplate, fmt=params.get('fmt', [''])[0]).encode('utf-8') response_headers = { 'Content-Type': 'audio/mpegurl; charset=utf-8', 'Access-Control-Allow-Origin': '*', 'ETag': self.etag, 'Content-Length': str(len(exported)), 'Connection': 'close' } connection.send_response(200) for k, v in list(response_headers.items()): connection.send_header(k, v) connection.end_headers() if play: connection.handleRequest(headers_only, name, config.logomap.get(name), fmt=params.get('fmt', [''])[0]) elif not headers_only: connection.wfile.write(exported)
class Torrenttv(object): # ttvplaylist handler is obsolete handlers = ('torrenttv', 'ttvplaylist') def __init__(self, AceConfig, AceProxy): self.picons = self.channels = self.playlist = self.etag = None self.playlisttime = gevent.time.time() self.headers = {'User-Agent': 'Magic Browser'} if config.updateevery: schedule(config.updateevery * 60, self.Playlistparser) 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)) logging.error(traceback.format_exc()) return False except: logging.error(traceback.format_exc()); return False return True def handle(self, connection): # 30 minutes cache if not self.playlist or (gevent.time.time() - self.playlisttime > 30 * 60): if not self.Playlistparser(): connection.send_error() connection.ext = query_get(connection.query, 'ext', 'ts') if connection.path.startswith('/{reqtype}/channel/'.format(**connection.__dict__)): if not connection.path.endswith(connection.ext): connection.send_error(404, 'Invalid path: {path}'.format(**connection.__dict__), logging.ERROR) name = ensure_text(unquote(os.path.splitext(os.path.basename(connection.path))[0])) url = self.channels.get(name) if url is None: connection.send_error(404, '[%s]: unknown channel: %s' % (self.__class__.__name__, name), logging.ERROR) connection.__dict__.update({'channelName': name, 'channelIcon': self.picons.get(name), 'path': {'acestream': '/content_id/%s/%s.%s' % (urlparse(url).netloc, name, connection.ext), 'infohash' : '/infohash/%s/%s.%s' % (urlparse(url).netloc, name, connection.ext), 'http' : '/url/%s/%s.%s' % (quote(url,''), name, connection.ext), 'https' : '/url/%s/%s.%s' % (quote(url,''), name, connection.ext), }[urlparse(url).scheme]}) connection.__dict__.update({'splittedpath': connection.path.split('/')}) connection.__dict__.update({'reqtype': connection.splittedpath[1].lower()}) return elif self.etag == connection.headers.get('If-None-Match'): logging.debug('[%s]: ETag matches. Return 304 to [%s]' % (self.__class__.__name__, connection.clientip)) connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: exported = self.playlist.exportm3u( hostport=connection.headers['Host'], path='' if not self.channels else '/{reqtype}/channel'.format(**connection.__dict__), header=config.m3uheadertemplate, query=connection.query ) response_headers = {'Content-Type': 'audio/mpegurl; charset=utf-8', 'Connection': 'close', 'Access-Control-Allow-Origin': '*'} try: h = connection.headers.get('Accept-Encoding').split(',')[0] compress_method = { 'zlib': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS), 'deflate': zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS), 'gzip': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) } exported = compress_method[h].compress(exported) + compress_method[h].flush() response_headers['Content-Encoding'] = h except: pass response_headers['Content-Length'] = len(exported) if connection.request_version == 'HTTP/1.1': response_headers['ETag'] = self.etag connection.send_response(200) gevent.joinall([gevent.spawn(connection.send_header, k, v) for (k,v) in response_headers.items()]) connection.end_headers() connection.wfile.write(exported) logging.debug('[%s]: plugin sent playlist to [%s]' % (self.__class__.__name__, connection.clientip))
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
class Torrentsearch(object): handlers = ('ttv2',) def __init__(self, AceConfig, AceProxy): self.AceConfig = AceConfig self.picons = self.channels = self.playlist = self.etag = self.last_modified = None self.playlisttime = gevent.time.time() self.headers = {'User-Agent': 'Magic Browser'} if config.updateevery: schedule(config.updateevery * 60, self.Playlistparser) 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 def handle(self, connection): # 30 minutes cache if not self.playlist or (gevent.time.time() - self.playlisttime > 30 * 60): if not self.Playlistparser(): logging.info('Parser failed to parse') connection.send_error() connection.ext = query_get(connection.query, 'ext', 'ts') if connection.path.startswith('/{reqtype}/channel/'.format(**connection.__dict__)): if not connection.path.endswith(connection.ext): logging.info('Invalid path') connection.send_error(404, 'Invalid path: {path}'.format(**connection.__dict__), logging.ERROR) name = ensure_text(unquote(os.path.splitext(os.path.basename(connection.path))[0])) url = self.channels.get(name) if url is None: logging.info('Unknown channel') connection.send_error(404, '[%s]: unknown channel: %s' % (self.__class__.__name__, name), logging.ERROR) connection.__dict__.update({'channelName': name, 'channelIcon': self.picons.get(name), 'path': {'acestream': '/content_id/%s/%s.%s' % (urlparse(url).netloc, name, connection.ext), 'infohash' : '/infohash/%s/%s.%s' % (urlparse(url).netloc, name, connection.ext), 'http' : '/url/%s/%s.%s' % (quote(url,''), name, connection.ext), 'https' : '/url/%s/%s.%s' % (quote(url,''), name, connection.ext), }[urlparse(url).scheme]}) connection.__dict__.update({'splittedpath': connection.path.split('/')}) connection.__dict__.update({'reqtype': connection.splittedpath[1].lower()}) return elif self.etag == connection.headers.get('If-None-Match'): logging.debug('[%s]: ETag matches. Return 304 to [%s]' % (self.__class__.__name__, connection.clientip)) connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: host_port = connection.headers['Host'] exported = self.playlist.exportm3u( hostport=host_port, path='' if not self.channels else '/{reqtype}/channel'.format(**connection.__dict__), header=config.m3uheadertemplate.format(get_epg_url(host_port, config, config.tvgurl), config.tvgshift), query=connection.query ) response_headers = {'Content-Type': 'audio/mpegurl; charset=utf-8', 'Connection': 'close', 'Access-Control-Allow-Origin': '*'} try: h = connection.headers.get('Accept-Encoding').split(',')[0] compress_method = { 'zlib': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS), 'deflate': zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS), 'gzip': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) } exported = compress_method[h].compress(exported) + compress_method[h].flush() response_headers['Content-Encoding'] = h except: pass response_headers['Content-Length'] = len(exported) if connection.request_version == 'HTTP/1.1': response_headers['ETag'] = self.etag connection.send_response(200) gevent.joinall([gevent.spawn(connection.send_header, k, v) for (k,v) in response_headers.items()]) connection.end_headers() connection.wfile.write(exported) logging.debug('[%s]: plugin sent playlist to [%s]' % (self.__class__.__name__, connection.clientip))
class Torrenttelik(AceProxyPlugin): handlers = ('torrent-telik',) def __init__(self, AceConfig, AceProxy): self.logger = logging.getLogger('torrenttelik_plugin') self.picons = self.channels = self.playlist = self.etag = self.last_modified = None self.playlisttime = gevent.time.time() self.headers = {'User-Agent': 'Magic Browser'} if config.updateevery: gevent.spawn(self.playlistTimedDownloader) def playlistTimedDownloader(self): while 1: self.Playlistparser() gevent.sleep(config.updateevery * 60) 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() self.logger.info('Playlist %s downloaded' % config.url) try: for channel in playlist['channels']: name = channel['name'] url = 'acestream://{url}'.format(**channel) channel['group'] = channel.pop('cat') if not 'logo' in channel: channel['logo'] = picons.logomap.get(name) self.picons[name] = channel['logo'] if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive', '.acestream', '.acemedia', '.torrent'))): self.channels[name] = url channel['url'] = quote(ensure_str(name),'') self.playlist.addItem(channel) m.update(name.encode('utf-8')) except Exception as e: self.logger.error("Can't parse JSON! %s" % repr(e)) return False self.etag = '"' + m.hexdigest() + '"' self.logger.debug('torrent-telik.m3u playlist generated') self.playlisttime = gevent.time.time() except: self.logger.error("Can't download %s playlist or received json is broken!" % config.url); return False return True def handle(self, connection, headers_only=False): play = False # 30 minutes cache if not self.playlist or (gevent.time.time() - self.playlisttime > 30 * 60): if not self.Playlistparser(): connection.dieWithError(); return url = urlparse(connection.path) path = url.path[0:-1] if url.path.endswith('/') else url.path ext = parse_qs(connection.query).get('ext', ['ts'])[0] if path.startswith('/%s/channel/' % connection.reqtype): if not path.endswith(ext): connection.dieWithError(404, 'Invalid path: %s' % unquote(path), logging.ERROR) return name = ensure_text(unquote(os.path.splitext(os.path.basename(path))[0])) url = self.channels.get(name) if url is None: connection.dieWithError(404, 'Unknown channel: %s' % name, logging.ERROR) return params = {'name': name, 'value': url.split('/')[2], 'ext': ext} if url.startswith('acestream://'): connection.path = u'/content_id/{value}/{name}.{ext}'.format(**params) elif url.startswith('infohash://'): connection.path = u'/infohash/{value}/{name}.{ext}'.format(**params) elif url.startswith(('http://', 'https://')) and url.endswith(('.acelive', '.acestream', '.acemedia', '.torrent')): params.update({'value': quote(url,'')}) connection.path = u'/url/{value}/{name}.{ext}'.format(**params) connection.splittedpath = connection.path.split('/') connection.reqtype = connection.splittedpath[1].lower() play = True elif self.etag == connection.headers.get('If-None-Match'): self.logger.debug('ETag matches - returning 304') connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: hostport = connection.headers['Host'] path = '' if not self.channels else '/%s/channel' % connection.reqtype exported = self.playlist.exportm3u(hostport=hostport, path=path, header=config.m3uheadertemplate, query=connection.query) response_headers = { 'Content-Type': 'audio/mpegurl; charset=utf-8', 'Connection': 'close', 'Content-Length': len(exported), 'Access-Control-Allow-Origin': '*', 'ETag': self.etag } try: h = connection.headers.get('Accept-Encoding').split(',')[0] compress_method = { 'zlib': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS), 'deflate': zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS), 'gzip': zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) } exported = compress_method[h].compress(exported) + compress_method[h].flush() response_headers['Content-Length'] = len(exported) response_headers['Content-Encoding'] = h except: pass connection.send_response(200) gevent.joinall([gevent.spawn(connection.send_header, k, v) for (k,v) in response_headers.items()]) connection.end_headers() if play: connection.handleRequest(headers_only=headers_only, channelName=name, channelIcon=self.picons.get(name)) elif not headers_only: self.logger.debug('Exporting torrent-telik.m3u playlist') connection.wfile.write(exported)
class Torrenttv(AceProxyPlugin): # ttvplaylist handler is obsolete handlers = ('torrenttv', 'ttvplaylist',) def __init__(self, AceConfig, AceStuff): self.logger = logging.getLogger('plugin_torrenttv') self.lock = threading.Lock() self.channels = None self.playlist = None self.playlisttime = None self.etag = None self.logomap = config.logomap self.updatelogos = p2pconfig.email != 're.place@me' and p2pconfig.password != 'ReplaceMe' if config.updateevery: gevent.spawn(self.playlistTimedDownloader) def playlistTimedDownloader(self): while True: time.sleep(10) with self.lock: self.downloadPlaylist() gevent.sleep(config.updateevery * 60) def downloadPlaylist(self): headers = {'User-Agent': 'Magic Browser', 'Accept-Encoding': 'gzip,deflate', 'Connection': 'close'} try: if config.useproxy: origin = requests.get(config.url, headers=headers, proxies=config.proxies, timeout=30).text else: origin = requests.get(config.url, headers=headers, timeout=5).text self.logger.info('TTV playlist ' + config.url + ' downloaded') self.playlisttime = int(time.time()) self.playlist = PlaylistGenerator() self.channels = dict() m = hashlib.md5() pattern = re.compile(r',(?P<name>\S.+) \((?P<group>.+)\)[\r\n]+(?P<url>[^\r\n]+)?') for match in pattern.finditer(origin.encode('UTF-8'), re.MULTILINE): itemdict = match.groupdict() encname = itemdict.get('name') name = encname.decode('UTF-8') logo = self.logomap.get(name) url = itemdict['url'] if logo: itemdict['logo'] = logo if url.startswith(('acestream://', 'infohash://')) \ or (url.startswith(('http://','https://')) and url.endswith(('.acelive','.acestream','.acemedia'))): self.channels[name] = url itemdict['url'] = requests.utils.quote(encname, '') + '.mp4' self.playlist.addItem(itemdict) m.update(encname) self.etag = '"' + m.hexdigest() + '"' except requests.exceptions.ConnectionError: self.logger.error("Can't download TTV playlist!") return False if self.updatelogos: try: api = TorrentTvApi(p2pconfig.email, p2pconfig.password) translations = api.translations('all') logos = dict() for channel in translations: name = channel.getAttribute('name').encode('utf-8') logo = channel.getAttribute('logo').encode('utf-8') logos[name] = config.logobase + logo self.logomap = logos self.logger.debug("Logos updated") self.updatelogos = False except: self.updatelogos = False # p2pproxy plugin seems not configured return True def handle(self, connection, headers_only=False): play = False with self.lock: # 30 minutes cache if not self.playlist or (int(time.time()) - self.playlisttime > 30 * 60): self.updatelogos = p2pconfig.email != 're.place@me' and p2pconfig.password != 'ReplaceMe' if not self.downloadPlaylist(): connection.dieWithError() return url = urlparse(connection.path) path = url.path[0:-1] if url.path.endswith('/') else url.path params = parse_qs(url.query) fmt = params['fmt'][0] if 'fmt' in params else None if path.startswith('/torrenttv/channel/'): if not path.endswith('.mp4'): connection.dieWithError(404, 'Invalid path: ' + path, logging.ERROR) return name = requests.utils.unquote(path[19:-4]).decode('UTF8') url = self.channels.get(name) if not url: connection.dieWithError(404, 'Unknown channel: ' + name, logging.ERROR) return elif url.startswith('acestream://'): connection.path = '/pid/' + url[12:] + '/stream.mp4' connection.splittedpath = connection.path.split('/') connection.reqtype = 'pid' elif url.startswith('infohash://'): connection.path = '/infohash/' + url[11:] + '/stream.mp4' connection.splittedpath = connection.path.split('/') connection.reqtype = 'infohash' elif url.startswith(('http://', 'https://')) and url.endswith(('.torrent', '.acelive','.acestream', '.acemedia')): connection.path = '/torrent/' + requests.utils.quote(url, '') + '/stream.mp4' connection.splittedpath = connection.path.split('/') connection.reqtype = 'torrent' play = True elif self.etag == connection.headers.get('If-None-Match'): self.logger.debug('ETag matches - returning 304') connection.send_response(304) connection.send_header('Connection', 'close') connection.end_headers() return else: hostport = connection.headers['Host'] path = '' if len(self.channels) == 0 else '/torrenttv/channel' add_ts = True if path.endswith('/ts') else False header = '#EXTM3U url-tvg="%s" tvg-shift=%d deinterlace=1 m3uautoload=1 cache=1000\n' % (config.tvgurl, config.tvgshift) exported = self.playlist.exportm3u(hostport, path, add_ts=add_ts, header=header, fmt=fmt) connection.send_response(200) connection.send_header('Content-Type', 'audio/mpegurl; charset=utf-8') connection.send_header('ETag', self.etag) connection.send_header('Content-Length', str(len(exported))) connection.send_header('Connection', 'close') connection.end_headers() if play: connection.handleRequest(headers_only, name, config.logomap.get(name), fmt=fmt) elif not headers_only: connection.wfile.write(exported)