def ToGo(self, handler, query): tivo_mak = config.get_server('tivo_mak') togo_path = config.get_server('togo_path') for name, data in config.getShares(): if togo_path == name: togo_path = data.get('path') if tivo_mak and togo_path: tivoIP = query['TiVo'][0] urls = query.get('Url', []) decode = 'decode' in query save = 'save' in query for theurl in urls: status[theurl] = {'running': False, 'error': '', 'rate': '', 'queued': True, 'size': 0, 'finished': False, 'decode': decode, 'save': save} if tivoIP in queue: queue[tivoIP].append(theurl) else: queue[tivoIP] = [theurl] thread.start_new_thread(ToGo.process_queue, (self, tivoIP, tivo_mak, togo_path)) logger.info('[%s] Queued "%s" for transfer to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), unquote(theurl), togo_path)) urlstring = '<br>'.join([unquote(x) for x in urls]) message = TRANS_QUEUE % (urlstring, togo_path) else: message = MISSING handler.redir(message, 5)
def infopage(self): t = Template(file=os.path.join(SCRIPTDIR, 'templates', 'info_page.tmpl'), filter=EncodeUnicode) t.admin = '' if config.get_server('tivo_mak') and config.get_server('togo_path'): t.togo = '<br>Pull from TiVos:<br>' else: t.togo = '' for section, settings in config.getShares(): plugin_type = settings.get('type') if plugin_type == 'settings': t.admin += ('<a href="/TiVoConnect?Command=Settings&' + 'Container=' + quote(section) + '">Settings</a><br>') elif plugin_type == 'togo' and t.togo: for tsn in config.tivos: if tsn and 'address' in config.tivos[tsn]: t.togo += ('<a href="/TiVoConnect?' + 'Command=NPL&Container=' + quote(section) + '&TiVo=' + config.tivos[tsn]['address'] + '">' + config.tivos[tsn]['name'] + '</a><br>') self.send_html(str(t))
def test(motor_record='XF:31IDA-OP{Tbl-Ax:X1}Mtr'): config.setup_logging([__name__, 'pypvserver.motor']) server = config.get_server() mrec = EpicsMotor(motor_record) # give the motor time to connect time.sleep(1.0) logger.info('--> PV Positioner, using put completion and a DONE pv') # PV positioner, put completion, done pv pos = PVPositioner(mrec.field_pv('VAL'), readback=mrec.field_pv('RBV'), done=mrec.field_pv('MOVN'), done_val=0, stop=mrec.field_pv('STOP'), stop_val=1, put_complete=True, limits=(-2, 2), ) ppv_motor = PypvMotor('m1', pos, server=server) print(ppv_motor.severity) record_name = ppv_motor.full_pvname for i in range(2): epics.caput(record_name, i, wait=True) print(pos.position) return ppv_motor
def startXMPP(self): m = mind.getMind() xmpp_info = m.getXMPPLoginInfo() jid=xmpp.protocol.JID(xmpp_info['username'] + '/pyTivo') cl=xmpp.Client( server=xmpp_info['server'], port=xmpp_info['port'], debug=[], ) self.__logger.debug('Connecting to %s:%s' % (xmpp_info['server'], xmpp_info['port'])) cl.connect() cl.RegisterHandler('message', self.processMessage) self.__logger.debug('Loging in as %s/pyTivo' % xmpp_info['username']) cl.auth(user=jid.getNode(), password=config.get_server('tivo_password'), resource='pyTivo') cl.sendInitPresence(requestRoster=0) for user_name in xmpp_info['presence_list']: self.__logger.debug('Sending presence to %s' % user_name) jid = xmpp.protocol.JID(user_name) cl.sendPresence(jid) t = threading.Thread(target=self.processXMPP, args=(cl,)) t.setDaemon(True) t.start()
def push_one_file(self, f): file_info = VideoDetails() file_info['valid'] = transcode.supported_format(f['path']) temp_share = config.get_server('temp_share', '') temp_share_path = '' if temp_share: for name, data in config.getShares(): if temp_share == name: temp_share_path = data.get('path') mime = 'video/mpeg' if config.isHDtivo(f['tsn']): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(f['path'], f['tsn'], m)[0]: mime = m break if (mime == 'video/mpeg' and transcode.mp4_remuxable(f['path'], f['tsn'])): new_path = transcode.mp4_remux(f['path'], f['name'], f['tsn'], temp_share_path) if new_path: mime = 'video/mp4' f['name'] = new_path if temp_share_path: ip = config.get_ip() port = config.getPort() container = quote(temp_share) + '/' f['url'] = 'http://%s:%s/%s' % (ip, port, container) if file_info['valid']: file_info.update(self.metadata_full(f['path'], f['tsn'], mime)) url = f['url'] + quote(f['name']) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(f['tsn']) m.pushVideo( tsn = f['tsn'], url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except Exception, msg: logger.error(msg)
def infopage(self): useragent = self.headers.getheader('User-Agent', '') if useragent.lower().find('mobile') > 0: t = Template(file=os.path.join(SCRIPTDIR, 'templates', 'info_page_mob.tmpl'), filter=EncodeUnicode) else: t = Template(file=os.path.join(SCRIPTDIR, 'templates', 'info_page.tmpl'), filter=EncodeUnicode) t.admin = '' if config.get_server('tivo_mak') and config.get_server('togo_path'): t.togo = '<br>Pull from TiVos:<br>' else: t.togo = '' if (config.get_server('tivo_username') and config.get_server('tivo_password')): t.shares = '<br>Push from video shares:<br>' else: t.shares = '' for section, settings in config.getShares(): plugin_type = settings.get('type') if plugin_type == 'settings': t.admin += ('<a href="/TiVoConnect?Command=Settings&' + 'Container=' + quote(section) + '">Settings</a><br>') elif plugin_type == 'togo' and t.togo: for tsn in config.tivos: if tsn: t.togo += ('<a href="/TiVoConnect?' + 'Command=NPL&Container=' + quote(section) + '&TiVo=' + config.tivos[tsn] + '">' + escape(config.tivo_names[tsn]) + '</a><br>') elif plugin_type and t.shares: plugin = GetPlugin(plugin_type) if hasattr(plugin, 'Push'): t.shares += ('<a href="/TiVoConnect?Command=' + 'QueryContainer&Container=' + quote(section) + '&Format=text/html">' + section + '</a><br>') self.send_html(str(t))
def transcode(isQuery, inFile, outFile, tsn="", mime="", thead=""): vcodec = select_videocodec(inFile, tsn, mime) settings = select_buffsize(tsn) + vcodec if not vcodec[1] == "copy": settings += ( select_videobr(inFile, tsn) + select_maxvideobr(tsn) + select_videofps(inFile, tsn) + select_aspect(inFile, tsn) ) acodec = select_audiocodec(isQuery, inFile, tsn) settings += acodec if not acodec[1] == "copy": settings += select_audiobr(tsn) + select_audiofr(inFile, tsn) + select_audioch(inFile, tsn) settings += [select_audiolang(inFile, tsn), select_ffmpegprams(tsn)] settings += select_format(tsn, mime) settings = " ".join(settings).split() if isQuery: return settings ffmpeg_path = config.get_bin("ffmpeg") fname = unicode(inFile, "utf-8") if mswindows: fname = fname.encode("cp1252") if inFile[-5:].lower() == ".tivo": tivodecode_path = config.get_bin("tivodecode") tivo_mak = config.get_server("tivo_mak") tcmd = [tivodecode_path, "-m", tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = "" ffmpeg = tivodecode else: cmd = [ffmpeg_path, "-i", "-"] + settings ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, "-i", fname] + settings ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug("transcoding to tivo model " + tsn[:3] + " using ffmpeg command:") debug(" ".join(cmd)) ffmpeg_procs[inFile] = {"process": ffmpeg, "start": 0, "end": 0, "last_read": time.time(), "blocks": []} if thead: ffmpeg_procs[inFile]["blocks"].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)
def transcode(isQuery, inFile, outFile, tsn='', mime='', thead=''): settings = {'video_codec': select_videocodec(inFile, tsn, mime), 'video_br': select_videobr(inFile, tsn), 'video_fps': select_videofps(inFile, tsn), 'max_video_br': select_maxvideobr(tsn), 'buff_size': select_buffsize(tsn), 'aspect_ratio': ' '.join(select_aspect(inFile, tsn)), 'audio_br': select_audiobr(tsn), 'audio_fr': select_audiofr(inFile, tsn), 'audio_ch': select_audioch(inFile, tsn), 'audio_codec': select_audiocodec(isQuery, inFile, tsn), 'audio_lang': select_audiolang(inFile, tsn), 'ffmpeg_pram': select_ffmpegprams(tsn), 'ffmpeg_threads': select_ffmpegthreads(), 'format': select_format(tsn, mime)} if isQuery: return settings ffmpeg_path = config.get_bin('ffmpeg') cmd_string = config.getFFmpegTemplate(tsn) % settings fname = unicode(inFile, 'utf-8') if mswindows: fname = fname.encode('iso8859-1') if inFile[-5:].lower() == '.tivo': tivodecode_path = config.get_bin('tivodecode') tivo_mak = config.get_server('tivo_mak') tcmd = [tivodecode_path, '-m', tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = '' ffmpeg = tivodecode else: cmd = [ffmpeg_path] + select_ffmpegthreads().split() + ['-i', '-'] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path] + select_ffmpegthreads().split() + ['-i', fname] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg_procs[inFile] = {'process': ffmpeg, 'start': 0, 'end': 0, 'last_read': time.time(), 'blocks': []} if thead: ffmpeg_procs[inFile]['blocks'].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)
def infopage(self): self.send_response(200) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() t = Template(file=os.path.join(SCRIPTDIR, 'templates', 'info_page.tmpl'), filter=EncodeUnicode) t.admin = '' if config.get_server('tivo_mak') and config.get_server('togo_path'): t.togo = '<br>Pull from TiVos:<br>' else: t.togo = '' if (config.get_server('tivo_username') and config.get_server('tivo_password')): t.shares = '<br>Push from video shares:<br>' else: t.shares = '' for section, settings in config.getShares(): plugin_type = settings.get('type') if plugin_type == 'settings': t.admin += ('<a href="/TiVoConnect?Command=Settings&' + 'Container=' + quote(section) + '">Web Configuration</a><br>') elif plugin_type == 'togo' and t.togo: for tsn in config.tivos: if tsn: t.togo += ('<a href="/TiVoConnect?' + 'Command=NPL&Container=' + quote(section) + '&TiVo=' + config.tivos[tsn] + '">' + escape(config.tivo_names[tsn]) + '</a><br>') elif plugin_type == 'video' and t.shares: t.shares += ('<a href="TiVoConnect?Command=' + 'QueryContainer&Container=' + quote(section) + '&Format=text/html">' + section + '</a><br>') self.wfile.write(t)
def send_packet(self, packet): debug('send packet:%s to for request:%d ...' % (packet, self._request)) business = get_server(self._request) if business: if business in BUSINESS_MAP: conn = BUSINESS_MAP[business] conn.send(packet) else: warning('business server %s is not avalible' % business) pass else: warning('unsupported request: %d' % self._request) self.read_header()
def Push(self, handler, query): try: tsn = query['tsn'][0] except: logger.error('Push requires a TiVo Service Number') handler.send_error(404) return if not tsn in config.tivos: for key, value in config.tivos.items(): if value.get('name') == tsn: tsn = key break try: tivo_name = config.tivos[tsn]['name'] except: tivo_name = tsn container = quote(query['Container'][0].split('/')[0]) ip = config.get_ip(tsn) port = config.getPort() baseurl = 'http://%s:%s/%s' % (ip, port, container) if config.getIsExternal(tsn): exturl = config.get_server('externalurl') if exturl: if not exturl.endswith('/'): exturl += '/' baseurl = exturl + container else: ip = self.readip() baseurl = 'http://%s:%s/%s' % (ip, port, container) path = self.get_local_base_path(handler, query) files = query.get('File', []) for f in files: file_path = os.path.normpath(path + '/' + f) queue.append({'path': file_path, 'name': f, 'tsn': tsn, 'url': baseurl}) if len(queue) == 1: thread.start_new_thread(Video.process_queue, (self,)) logger.info('[%s] Queued "%s" for Push to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), unicode(file_path, 'utf-8'), tivo_name)) files = [unicode(f, 'utf-8') for f in files] handler.redir(PUSHED % (tivo_name, '<br>'.join(files)), 5)
def transcode(isQuery, inFile, outFile, tsn=""): settings = { "video_codec": select_videocodec(inFile, tsn), "video_br": select_videobr(inFile, tsn), "video_fps": select_videofps(inFile, tsn), "max_video_br": select_maxvideobr(tsn), "buff_size": select_buffsize(tsn), "aspect_ratio": " ".join(select_aspect(inFile, tsn)), "audio_br": select_audiobr(tsn), "audio_fr": select_audiofr(inFile, tsn), "audio_ch": select_audioch(tsn), "audio_codec": select_audiocodec(isQuery, inFile, tsn), "audio_lang": select_audiolang(inFile, tsn), "ffmpeg_pram": select_ffmpegprams(tsn), "format": select_format(tsn), } if isQuery: return settings ffmpeg_path = config.get_bin("ffmpeg") cmd_string = config.getFFmpegTemplate(tsn) % settings fname = unicode(inFile, "utf-8") if mswindows: fname = fname.encode("iso8859-1") if inFile[-5:].lower() == ".tivo": tivodecode_path = config.get_bin("tivodecode") tivo_mak = config.get_server("tivo_mak") tcmd = [tivodecode_path, "-m", tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = "" ffmpeg = tivodecode else: cmd = [ffmpeg_path, "-i", "-"] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, "-i", fname] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug("transcoding to tivo model " + tsn[:3] + " using ffmpeg command:") debug(" ".join(cmd)) ffmpeg_procs[inFile] = {"process": ffmpeg, "start": 0, "end": 0, "last_read": time.time(), "blocks": []} reap_process(inFile) return transfer_blocks(inFile, outFile)
def read_body(self, body): logging.debug('read body(%s) from %s' % (body, self._addr_str)) self._body = body business = get_server(self._request) BusinessConnection.clients_lock.acquire() if business in BusinessConnection.clients: logging.debug('forward request to %s' % business) conn = BusinessConnection.clients[business].pop() BusinessConnection.clients[business].add(conn) conn.send(self._header + self._body, self._type, self._address[0]) else: logging.debug('no %s business server is avaliable' % business) BusinessConnection.clients_lock.release() self._stream.read_bytes(Connection.header_length, self.read_header)
def from_tivo(full_path): if full_path in tivo_cache: return tivo_cache[full_path] tdcat_path = config.get_bin('tdcat') tivo_mak = config.get_server('tivo_mak') if tdcat_path and tivo_mak: fname = unicode(full_path, 'utf-8') if mswindows: fname = fname.encode('iso8859-1') tcmd = [tdcat_path, '-m', tivo_mak, '-2', fname] tdcat = subprocess.Popen(tcmd, stdout=subprocess.PIPE) metadata = from_details(tdcat.stdout) tivo_cache[full_path] = metadata else: metadata = {} return metadata
def from_tivo(full_path): if full_path in tivo_cache: return tivo_cache[full_path] tdcat_path = config.get_bin("tdcat") tivo_mak = config.get_server("tivo_mak") try: assert tivo_mak if tdcat_path: details = _tdcat_bin(tdcat_path, full_path, tivo_mak) else: details = _tdcat_py(full_path, tivo_mak) metadata = from_details(details) tivo_cache[full_path] = metadata except: metadata = {} return metadata
def test(): config.setup_logging([__name__, 'pypvserver.pv']) server = config.get_server() logger.info('Creating PV "pv1", a floating-point type') python_pv = PyPV('pv1', 123.0, server=server) # full_pvname includes the server prefix pvname = python_pv.full_pvname logger.info('... which is %s including the server prefix', pvname) signal = epics.PV(pvname) signal.add_callback(updated) time.sleep(0.1) for value in range(10): logger.info('Updating the value on the server-side to: %s', value) python_pv.value = value time.sleep(0.05) logger.info('Done')
def infopage(self): t = Template(file=os.path.join(SCRIPTDIR, 'templates', 'info_page.tmpl')) t.version = PYTIVO_VERSION t.admin = '' if config.get_server('tivo_mak') and config.get_togo('path'): t.togo = '<br>Pull from TiVos:<br>' else: t.togo = '' for section, settings in config.getShares(): plugin_type = settings.get('type') if plugin_type == 'settings': t.admin += ('<a href="/TiVoConnect?Command=Settings&Container={}">Settings</a><br>' .format(quote(section))) elif plugin_type == 'togo' and t.togo: for tsn in config.tivos: if tsn and 'address' in config.tivos[tsn]: t.togo += ('<a href="/TiVoConnect?Command=NPL&Container={}&TiVo={}">{}</a><br>' .format(quote(section), config.tivos[tsn]['address'], config.tivos[tsn]['name'])) self.send_html(str(t))
def Push(self, handler, query): tsn = query["tsn"][0] for key in config.tivo_names: if config.tivo_names[key] == tsn: tsn = key break tivo_name = config.tivo_names.get(tsn, tsn) container = quote(query["Container"][0].split("/")[0]) ip = config.get_ip(tsn) port = config.getPort() baseurl = "http://%s:%s/%s" % (ip, port, container) if config.getIsExternal(tsn): exturl = config.get_server("externalurl") if exturl: if not exturl.endswith("/"): exturl += "/" baseurl = exturl + container else: ip = self.readip() baseurl = "http://%s:%s/%s" % (ip, port, container) path = self.get_local_base_path(handler, query) files = query.get("File", []) for f in files: file_path = path + os.path.normpath(f) queue.append({"path": file_path, "name": f, "tsn": tsn, "url": baseurl}) if len(queue) == 1: thread.start_new_thread(Video.process_queue, (self,)) logger.info( '[%s] Queued "%s" for Push to %s' % (time.strftime("%d/%b/%Y %H:%M:%S"), unicode(file_path, "utf-8"), tivo_name) ) files = [unicode(f, "utf-8") for f in files] handler.redir(PUSHED % (tivo_name, "<br>".join(files)), 5)
def Push(self, handler, query): tsn = query['tsn'][0] for key in config.tivo_names: if config.tivo_names[key] == tsn: tsn = key break tivo_name = config.tivo_names.get(tsn, tsn) container = quote(query['Container'][0].split('/')[0]) ip = config.get_ip(tsn) port = config.getPort() baseurl = 'http://%s:%s/%s' % (ip, port, container) if config.getIsExternal(tsn): exturl = config.get_server('externalurl') if exturl: if not exturl.endswith('/'): exturl += '/' baseurl = exturl + container else: ip = self.readip() baseurl = 'http://%s:%s/%s' % (ip, port, container) path = self.get_local_base_path(handler, query) files = query.get('File', []) for f in files: file_path = path + os.path.normpath(f) queue.append({'path': file_path, 'name': f, 'tsn': tsn, 'url': baseurl}) if len(queue) == 1: thread.start_new_thread(Video.process_queue, (self,)) logger.info('[%s] Queued "%s" for Push to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), unicode(file_path, 'utf-8'), tivo_name)) files = [unicode(f, 'utf-8') for f in files] handler.redir(PUSHED % (tivo_name, '<br>'.join(files)), 5)
def on_close(ws): print("closed") logging.debug("closed") def on_open(ws): channels = conf.get_channels() for i in range(0, len(channels)): subscribe(ws, channels[i]["id"], channels[i]["password"]) def subscribe(ws, channel, password): if (password == ""): msg = '{"subscribe":{"channelId":\"' + channel + '\"}}' else: msg = '{"subscribe":{"channelId":\"' + channel + '\", "password":\"' + password + '\"}}' print(msg) logging.debug(msg) ws.send(msg) if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp(conf.get_server() + "/websocket", on_message=on_message, on_error=on_error, on_close=on_close) ws.on_open = on_open ws.run_forever()
def send_file(self, handler, path, query): mime = 'video/x-tivo-mpeg' tsn = handler.headers.getheader('tsn', '') try: assert (tsn) tivo_name = config.tivos[tsn].get('name', tsn) except: tivo_name = handler.address_string() is_tivo_file = (path[-5:].lower() == '.tivo') if 'Format' in query: mime = query['Format'][0] needs_tivodecode = (is_tivo_file and mime == 'video/mpeg') compatible = (not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.getheader('Range')[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool( config.get_bin('tivodecode') and config.get_server('tivo_mak')) else: valid = True if valid and offset: valid = ((compatible and offset < os.path.getsize(path)) or (not compatible and transcode.is_resumable(path, offset))) #faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = (mime == 'video/x-tivo-mpeg' and not (is_tivo_file and compatible)) fname = unicode(path, 'utf-8') thead = '' if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.path.getsize(fname) + len(thead) handler.send_response(200) handler.send_header('Content-Length', size - offset) handler.send_header( 'Content-Range', 'bytes %d-%d/%d' % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header('Transfer-Encoding', 'chunked') handler.send_header('Content-Type', mime) handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, 'rb') try: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)
details_urls = {} # URLs for extended data, indexed by main URL def null_cookie(name, value): return cookielib.Cookie(0, name, value, None, False, '', False, False, '', False, False, None, False, None, None, None) auth_handler = urllib2.HTTPPasswordMgrWithDefaultRealm() cj = cookielib.CookieJar() cj.set_cookie(null_cookie('sid', 'ADEADDA7EDEBAC1E')) tivo_opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), urllib2.HTTPBasicAuthHandler(auth_handler), urllib2.HTTPDigestAuthHandler(auth_handler)) tsn = config.get_server('togo_tsn') if tsn: tivo_opener.addheaders.append(('TSN', tsn)) class ToGo(Plugin): CONTENT_TYPE = 'text/html' def tivo_open(self, url): # Loop just in case we get a server busy message while True: try: # Open the URL using our authentication/cookie opener return tivo_opener.open(url) # Do a retry if the TiVo responds that the server is busy
from config import get_server from jim_protocol import create_response import json s = get_server() print("Server started") client, addr = s.accept() print("Client connected: ", client, addr) presence = json.loads(client.recv(1024).decode("utf-8")) client.send(json.dumps(create_response(presence)).encode("utf-8")) while True: print("Waiting data") data = json.loads(client.recv(1024).decode("utf-8")) print("Data received") if "exit" not in data: print(data) else: client.close() s.close() print("Exit") break
def send_file(self, handler, path, query): mime = "video/x-tivo-mpeg" tsn = handler.headers.getheader("tsn", "") tivo_name = config.tivo_names.get(tsn, tsn) is_tivo_file = path[-5:].lower() == ".tivo" if "Format" in query: mime = query["Format"][0] needs_tivodecode = is_tivo_file and mime == "video/mpeg" compatible = not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0] try: # "bytes=XXX-" offset = int(handler.headers.getheader("Range")[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool(config.get_bin("tivodecode") and config.get_server("tivo_mak")) else: valid = True if valid and offset: valid = (compatible and offset < os.stat(path).st_size) or ( not compatible and transcode.is_resumable(path, offset) ) # faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = mime == "video/x-tivo-mpeg" and not (is_tivo_file and compatible) fname = unicode(path, "utf-8") thead = "" if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.stat(fname).st_size + len(thead) handler.send_response(200) handler.send_header("Content-Length", size - offset) handler.send_header("Content-Range", "bytes %d-%d/%d" % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header("Transfer-Encoding", "chunked") handler.send_header("Content-Type", mime) handler.send_header("Connection", "close") handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime("%d/%b/%Y %H:%M:%S"), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, "rb") try: if mime == "video/mp4": count = qtfaststart.process(f, handler.wfile, offset) else: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)
def NPL(self, handler, query): global basic_meta shows_per_page = 50 # Change this to alter the number of shows returned cname = query['Container'][0].split('/')[0] folder = '' tivo_mak = config.get_server('tivo_mak') has_tivodecode = bool(config.get_bin('tivodecode')) if 'TiVo' in query: tivoIP = query['TiVo'][0] tivos_by_ip = dict([(value, key) for key, value in config.tivos.items()]) tivo_name = config.tivo_names[tivos_by_ip[tivoIP]] theurl = ('https://' + tivoIP + '/TiVoConnect?Command=QueryContainer&ItemCount=' + str(shows_per_page) + '&Container=/NowPlaying') if 'Folder' in query: folder += query['Folder'][0] theurl += '/' + folder if 'AnchorItem' in query: theurl += '&AnchorItem=' + quote(query['AnchorItem'][0]) if 'AnchorOffset' in query: theurl += '&AnchorOffset=' + query['AnchorOffset'][0] if (theurl not in tivo_cache or (time.time() - tivo_cache[theurl]['thepage_time']) >= 60): # if page is not cached or old then retreive it auth_handler.add_password('TiVo DVR', tivoIP, 'tivo', tivo_mak) try: page = self.tivo_open(theurl) except IOError, e: handler.redir(UNABLE % tivoIP, 10) return tivo_cache[theurl] = {'thepage': minidom.parse(page), 'thepage_time': time.time()} page.close() xmldoc = tivo_cache[theurl]['thepage'] items = xmldoc.getElementsByTagName('Item') TotalItems = tag_data(xmldoc, 'Details/TotalItems') ItemStart = tag_data(xmldoc, 'ItemStart') ItemCount = tag_data(xmldoc, 'ItemCount') FirstAnchor = tag_data(items[0], 'Links/Content/Url') data = [] for item in items: entry = {} entry['ContentType'] = tag_data(item, 'ContentType') for tag in ('CopyProtected', 'UniqueId'): value = tag_data(item, tag) if value: entry[tag] = value if entry['ContentType'] == 'x-tivo-container/folder': entry['Title'] = tag_data(item, 'Title') entry['TotalItems'] = tag_data(item, 'TotalItems') lc = tag_data(item, 'LastCaptureDate') if not lc: lc = tag_data(item, 'LastChangeDate') entry['LastChangeDate'] = time.strftime('%b %d, %Y', time.localtime(int(lc, 16))) else: keys = {'Icon': 'Links/CustomIcon/Url', 'Url': 'Links/Content/Url', 'SourceSize': 'Details/SourceSize', 'Duration': 'Details/Duration', 'CaptureDate': 'Details/CaptureDate'} for key in keys: value = tag_data(item, keys[key]) if value: entry[key] = value entry['SourceSize'] = ( '%.3f GB' % (float(entry['SourceSize']) / (1024 ** 3)) ) dur = int(entry['Duration']) / 1000 entry['Duration'] = ( '%02d:%02d:%02d' % (dur / 3600, (dur % 3600) / 60, dur % 60) ) entry['CaptureDate'] = time.strftime('%b %d, %Y', time.localtime(int(entry['CaptureDate'], 16))) url = entry['Url'] if url in basic_meta: entry.update(basic_meta[url]) else: basic_data = metadata.from_container(item) entry.update(basic_data) basic_meta[url] = basic_data data.append(entry)
def check_for_blacklist(ctx): if ctx.guild is not None: server = config.get_server(ctx.guild.id) return not ctx.channel.id in server['blacklist'] else: return True
def transcode(isQuery, inFile, outFile, tsn='', mime='', thead=''): vcodec = select_videocodec(inFile, tsn, mime) settings = select_buffsize(tsn) + vcodec if not vcodec[1] == 'copy': settings += (select_videobr(inFile, tsn) + select_maxvideobr(tsn) + select_videofps(inFile, tsn) + select_aspect(inFile, tsn)) acodec = select_audiocodec(isQuery, inFile, tsn) settings += acodec if not acodec[1] == 'copy': settings += (select_audiobr(tsn) + select_audiofr(inFile, tsn) + select_audioch(inFile, tsn)) settings += [select_audiolang(inFile, tsn), select_ffmpegprams(tsn)] settings += select_format(tsn, mime) settings = ' '.join(settings).split() if isQuery: return settings ffmpeg_path = config.get_bin('ffmpeg') fname = unicode(inFile, 'utf-8') if mswindows: fname = fname.encode('cp1252') if inFile[-5:].lower() == '.tivo': tivodecode_path = config.get_bin('tivodecode') tivo_mak = config.get_server('tivo_mak') tcmd = [tivodecode_path, '-m', tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = '' ffmpeg = tivodecode else: cmd = [ffmpeg_path, '-i', '-'] + settings ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, '-i', fname] + settings ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg_procs[inFile] = {'process': ffmpeg, 'start': 0, 'end': 0, 'last_read': time.time(), 'blocks': []} if thead: ffmpeg_procs[inFile]['blocks'].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)
def mp4_remux(inFile, basename, tsn='', temp_share_path=''): temp_add = config.get_server('temp_add', '') unique_id = '' if temp_add: unique_id = '_' + config.get_random() outFile = inFile + unique_id + '.pyTivo-temp' newname = basename + unique_id + '.pyTivo-temp' if temp_share_path: newname = os.path.splitext(os.path.split(basename)[1])[0] + unique_id + '.mp4.pyTivo-temp' outFile = os.path.join(temp_share_path, newname) if os.path.exists(outFile): debug('File already exists. Performing full transcode instead') return None ffmpeg_path = config.get_bin('ffmpeg') fname = unicode(inFile, 'utf-8') oname = unicode(outFile, 'utf-8') if mswindows: fname = fname.encode('iso8859-1') oname = oname.encode('iso8859-1') settings = {'video_codec': '-vcodec copy', 'video_br': select_videobr(inFile, tsn), 'video_fps': select_videofps(inFile, tsn), 'max_video_br': select_maxvideobr(tsn), 'buff_size': select_buffsize(tsn), 'aspect_ratio': ' '.join(select_aspect(inFile, tsn)), 'audio_br': select_audiobr(tsn), 'audio_fr': select_audiofr(inFile, tsn), 'audio_ch': select_audioch(inFile, tsn), 'audio_codec': select_audiocodec(False, inFile, tsn, 'video/mp4'), 'audio_lang': select_audiolang(inFile, tsn), 'ffmpeg_pram': select_ffmpegprams(tsn), 'ffmpeg_threads': select_ffmpegthreads(), 'format': '-f mp4'} cmd_string = config.getFFmpegTemplate(tsn) % settings cmd = [ffmpeg_path] + select_ffmpegthreads().split() + ['-i', fname] + cmd_string.split() + [oname] debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg = subprocess.Popen(cmd) debug('remuxing ' + inFile + ' to ' + outFile) # attempt to overcome certain FFmpeg audio timestamp errors # by forcing the audio stream to be transcoded # works more reliably with versions of FFmpeg >= 0.11.x # large amounts of warnings during mux are expected # also bypasses ac3 stream copy regression in FFmpeg # error: 'codec frame size is not set' # 02/20/2012 - lavc ver >= 54.x.x # commit 16e54ac7255d47e70ba9ba60d5ce5d0a0e44b223 if ffmpeg.wait() == 1 and 'acodec copy' in settings['audio_codec']: debug('FFmpeg error, attempting to transcode audio as workaround') settings['audio_codec'] = '-acodec ac3' # don't use -copyts cmd_string = config.getFFmpegTemplate(tsn) % settings cmd = [ffmpeg_path] + select_ffmpegthreads().split() + ['-y', '-i', fname] + cmd_string.split() + [oname] debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg = subprocess.Popen(cmd) if ffmpeg.wait(): try: os.remove(outFile) debug('FFmpeg error, temp file has been removed: ' + outFile) except: logger.error('FFmpeg returned a fatal error, ' + 'check debug log and configuration settings') pass return None return newname
def send_file(self, handler, path, query): mime = 'video/x-tivo-mpeg' tsn = handler.headers.getheader('tsn', '') tivo_name = config.tivo_names.get(tsn, tsn) is_tivo_file = (path[-5:].lower() == '.tivo') if 'Format' in query: mime = query['Format'][0] needs_tivodecode = (is_tivo_file and mime == 'video/mpeg') compatible = (not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.getheader('Range')[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool(config.get_bin('tivodecode') and config.get_server('tivo_mak')) else: valid = True if valid and offset: valid = ((compatible and offset < os.stat(path).st_size) or (not compatible and transcode.is_resumable(path, offset))) #faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = (mime == 'video/x-tivo-mpeg' and not (is_tivo_file and compatible)) fname = unicode(path, 'utf-8') thead = '' if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.stat(fname).st_size + len(thead) handler.send_response(200) handler.send_header('Content-Length', size - offset) handler.send_header('Content-Range', 'bytes %d-%d/%d' % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header('Transfer-Encoding', 'chunked') handler.send_header('Content-Type', mime) handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), fname, tivo_name)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) logger.debug('"%s" is tivo compatible' % fname) f = open(fname, 'rb') try: if mime == 'video/mp4': count = qtfaststart.process(f, handler.wfile, offset) else: if offset: offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) except Exception, msg: logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % fname) if offset: count = transcode.resume_transfer(path, handler.wfile, offset) else: count = transcode.transcode(False, path, handler.wfile, tsn, mime, thead)
def send_file(self, handler, path, query): global status self.cleanup_status() # Keep status object from getting too big mime = 'video/x-tivo-mpeg' tsn = handler.headers.get('tsn', '') try: assert(tsn) tivo_name = config.tivos[tsn].get('name', tsn) except: tivo_name = handler.address_string() if not tivo_name in status: status[tivo_name] = {} is_tivo_file = False tivo_header_size = 0 is_tivo_ts = False try: with open(path, 'rb') as f: tivo_header = f.read(16) if tivo_header[0:4] == b'TiVo': is_tivo_file = True tivo_header_size = struct.unpack_from('>L', tivo_header, 10)[0] if (tivo_header[7] & 0x20 != 0): is_tivo_ts = True except: pass tivo_mak = config.get_tsn('tivo_mak', tsn) has_tivolibre = bool(config.get_bin('tivolibre')) has_tivodecode = bool(config.get_bin('tivodecode')) use_tivolibre = False if has_tivolibre and bool(config.get_server('tivolibre_upload', True)): use_tivolibre = True if 'Format' in query: mime = query['Format'][0] needs_tivodecode = (((is_tivo_file and is_tivo_ts) or (is_tivo_file and not has_tivolibre)) and mime == 'video/mpeg') compatible = (not needs_tivodecode and transcode.tivo_compatible(path, tsn, mime)[0]) try: # "bytes=XXX-" offset = int(handler.headers.get('Range')[6:-1]) except: offset = 0 if needs_tivodecode: valid = bool((has_tivodecode or has_tivolibre) and tivo_mak) else: valid = True if valid and offset: valid = ((compatible and offset < os.path.getsize(path)) or (not compatible and transcode.is_resumable(path, offset))) if status[tivo_name][path]: # Don't let the TiVo loop over and over in the same spot valid = (offset != status[tivo_name][path]['offset']) status[tivo_name][path]['error'] = 'Repeat offset call' #faking = (mime in ['video/x-tivo-mpeg-ts', 'video/x-tivo-mpeg'] and faking = (mime == 'video/x-tivo-mpeg' and not (is_tivo_file and compatible)) thead = '' if faking: thead = self.tivo_header(tsn, path, mime) size = os.path.getsize(path) + len(thead) if compatible: handler.send_response(200) handler.send_header('Content-Length', size - offset) handler.send_header('Content-Range', 'bytes %d-%d/%d' % (offset, size - offset - 1, size)) else: handler.send_response(206) handler.send_header('Transfer-Encoding', 'chunked') handler.send_header('Content-Type', mime) handler.end_headers() logger.info('[%s] Start sending "%s" to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), path, tivo_name)) if valid: start_time = time.time() last_interval = start_time now = start_time count = 0 output = 0 if path in status[tivo_name]: status[tivo_name][path]['active'] = True status[tivo_name][path]['offset'] = offset else: status[tivo_name][path] = {'active': True, 'decrypting': False, 'transcoding': False, 'offset': offset, 'start': start_time, 'end': start_time, 'rate': 0, 'size': size, 'output': 0, 'error': '', } if compatible: logger.debug('"%s" is tivo compatible' % path) f = open(path, 'rb') tivolibre = None if not offset: if faking: handler.wfile.write(thead) count += len(thead) output += len(thead) elif tivo_header_size > 0: block = f.read(tivo_header_size) handler.wfile.write(block) count += len(block) output += len(block) try: if is_tivo_file and use_tivolibre: status[tivo_name][path]['decrypting'] = True f.close() tivolibre_path = config.get_bin('tivolibre') tcmd = [tivolibre_path, '-m', tivo_mak, '-i', path] tivolibre = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) f = tivolibre.stdout if offset: if tivolibre: raise Exception('tivolibre does not support offset') offset -= len(thead) f.seek(offset) while True: block = f.read(512 * 1024) if not block: break handler.wfile.write(block) count += len(block) output += len(block) now = time.time() elapsed = now - last_interval if elapsed >= 1: status[tivo_name][path]['rate'] = (count * 8.0) / elapsed status[tivo_name][path]['output'] += count count = 0 last_interval = now if tivolibre: tivolibre.wait() except Exception as msg: status[tivo_name][path]['error'] = str(msg) if tivolibre: tivolibre.kill() tivolibre.wait() logger.info(msg) f.close() else: logger.debug('"%s" is not tivo compatible' % path) status[tivo_name][path]['transcoding'] = True if offset: count = transcode.resume_transfer(path, handler.wfile, offset, status[tivo_name][path]) else: count = transcode.transcode(False, path, handler.wfile, status[tivo_name][path], is_tivo_file, tsn, mime, thead) end_time = time.time() elapsed = end_time - status[tivo_name][path]['start'] rate = count * 8.0 / elapsed # bits / sec status[tivo_name][path]['active'] = False status[tivo_name][path]['end'] = end_time status[tivo_name][path]['rate'] = rate logger.info('[{timestamp:%d/%b/%Y %H:%M:%S}] Done sending "{fname}" to {tivo_name}, ' '{mbps[0]:.2f} {mbps[1]}B/s ({num_bytes[0]:.3f} {num_bytes[1]}Bytes / {seconds:.0f} s)' .format(timestamp=datetime.fromtimestamp(end_time), fname=path, tivo_name=tivo_name, num_bytes=prefix_bin_qty(count), mbps=prefix_bin_qty(rate / 8), seconds=elapsed)) else: logger.info('Invalid file "{}" requested by {}'.format(path, tivo_name)) try: if not compatible: handler.wfile.write(b'0\r\n\r\n') handler.wfile.flush() except Exception as msg: logger.exception('Exception writing an empty response for an incompatible file')
def Push(self, handler, query): tsn = query['tsn'][0] for key in config.tivo_names: if config.tivo_names[key] == tsn: tsn = key break tivo_name = config.tivo_names.get(tsn, tsn) container = quote(query['Container'][0].split('/')[0]) ip = config.get_ip() port = config.getPort() baseurl = 'http://%s:%s' % (ip, port) if config.getIsExternal(tsn): exturl = config.get_server('externalurl') if exturl: baseurl = exturl else: ip = self.readip() baseurl = 'http://%s:%s' % (ip, port) path = self.get_local_base_path(handler, query) files = query.get('File', []) for f in files: file_path = path + os.path.normpath(f) file_info = VideoDetails() file_info['valid'] = transcode.supported_format(file_path) mime = 'video/mpeg' if config.isHDtivo(tsn): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(file_path, tsn, m)[0]: mime = m break if file_info['valid']: file_info.update(self.metadata_full(file_path, tsn, mime)) url = baseurl + '/%s%s' % (container, quote(f)) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(tsn) m.pushVideo( tsn = tsn, url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except Exception, e: handler.send_response(500) handler.end_headers() handler.wfile.write('%s\n\n%s' % (e, traceback.format_exc() )) raise logger.info('[%s] Queued "%s" for Push to %s' % (time.strftime('%d/%b/%Y %H:%M:%S'), unicode(file_path, 'utf-8'), tivo_name))
def transcode(isQuery, inFile, outFile, status=None, isTivoFile=False, tsn='', mime='', thead=''): vcodec = select_videocodec(inFile, tsn, mime) settings = select_buffsize(tsn) + vcodec if not vcodec[1] == 'copy': settings += (select_videobr(inFile, tsn) + select_maxvideobr(tsn) + select_videofps(inFile, tsn) + select_aspect(inFile, tsn)) acodec = select_audiocodec(isQuery, inFile, tsn) settings += acodec if not acodec[1] == 'copy': settings += (select_audiobr(tsn) + select_audiofr(inFile, tsn) + select_audioch(inFile, tsn)) settings += [select_audiolang(inFile, tsn), select_ffmpegprams(tsn)] settings += select_format(tsn, mime) settings = ' '.join(settings).split() if isQuery: return settings ffmpeg_path = config.get_bin('ffmpeg') fname = inFile if isTivoFile: if status: status['decrypting'] = True tivo_mak = config.get_server('tivo_mak') tivolibre_path = config.get_bin('tivolibre') # prefer tivolibre to tivodecode if tivolibre_path: decode_cmd = [tivolibre_path, '-m', tivo_mak, '-i', fname] else: tivodecode_path = config.get_bin('tivodecode') if not tivodecode_path: raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 'tivodecode executable') decode_cmd = [tivodecode_path, '-m', tivo_mak, fname] tivodecode = subprocess.Popen(decode_cmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = '' ffmpeg = tivodecode else: cmd = [ffmpeg_path, '-hide_banner', '-i', '-'] + settings ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, '-hide_banner', '-i', fname] + settings ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if cmd: debug('transcoding to tivo model {} using ffmpeg command:'.format(tsn[:3])) debug(' '.join(cmd)) ffmpeg_procs[inFile] = {'process': ffmpeg, 'start': 0, 'end': 0, 'last_read': time.time(), 'blocks': []} if thead: ffmpeg_procs[inFile]['blocks'].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)
queue = {} # Recordings to download -- list per TiVo basic_meta = {} # Data from NPL, parsed, indexed by progam URL details_urls = {} # URLs for extended data, indexed by main URL def null_cookie(name, value): return cookielib.Cookie(0, name, value, None, False, '', False, False, '', False, False, None, False, None, None, None) auth_handler = urllib2.HTTPPasswordMgrWithDefaultRealm() cj = cookielib.CookieJar() cj.set_cookie(null_cookie('sid', 'ADEADDA7EDEBAC1E')) tivo_opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), urllib2.HTTPBasicAuthHandler(auth_handler), urllib2.HTTPDigestAuthHandler(auth_handler)) tsn = config.get_server('togo_tsn') if tsn: tivo_opener.addheaders.append(('TSN', tsn)) class ToGo(Plugin): CONTENT_TYPE = 'text/html' def tivo_open(self, url): # Loop just in case we get a server busy message while True: try: # Open the URL using our authentication/cookie opener return tivo_opener.open(url) # Do a retry if the TiVo responds that the server is busy except urllib2.HTTPError, e:
def transcode(isQuery, inFile, outFile, tsn='', mime='', thead=''): vcodec = select_videocodec(inFile, tsn, mime) settings = select_buffsize(tsn) + vcodec if not vcodec[1] == 'copy': settings += (select_videobr(inFile, tsn) + select_maxvideobr(tsn) + select_videofps(inFile, tsn) + select_aspect(inFile, tsn)) acodec = select_audiocodec(isQuery, inFile, tsn) settings += acodec if not acodec[1] == 'copy': settings += (select_audiobr(tsn) + select_audiofr(inFile, tsn) + select_audioch(inFile, tsn)) settings += [select_audiolang(inFile, tsn), select_ffmpegprams(tsn)] settings += select_format(tsn, mime) settings = ' '.join(settings).split() if isQuery: return settings ffmpeg_path = config.get_bin('ffmpeg') fname = unicode(inFile, 'utf-8') if mswindows: fname = fname.encode('cp1252') if inFile[-5:].lower() == '.tivo': tivodecode_path = config.get_bin('tivodecode') tivo_mak = config.get_server('tivo_mak') tcmd = [tivodecode_path, '-m', tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = '' ffmpeg = tivodecode else: cmd = [ffmpeg_path, '-i', '-'] + settings ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, '-i', fname] + settings ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg_procs[inFile] = { 'process': ffmpeg, 'start': 0, 'end': 0, 'last_read': time.time(), 'blocks': [] } if thead: ffmpeg_procs[inFile]['blocks'].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)
def select_videofilter(inFile): vInfo = video_info(inFile) #legacy subtitle support to be removed subtitles = vInfo.get('subtitles') if subtitles: return ['-vf', subtitles] embed = config.get_server('embedded_subs', 'Off') subfile = vInfo.get('subFile') if not subfile: if embed == 'On' or (embed == 'OnlyForced' and vInfo.get('forcedSub') != None): subfile = inFile logger.info("subfile: {0}".format(subfile)) #first select a subFile in the metadata.txt file #then select the subFile with the same filename as the video file (video file: video.mpg, subFile: video.mpg.srt) if subfile and os.path.exists(os.path.join(os.path.split(inFile)[0], subfile)): subfile = os.path.join(os.path.split(inFile)[0], subfile) elif os.path.exists(os.path.join(os.path.split(inFile)[0], os.path.basename(inFile) + '.srt')): subfile = os.path.join(os.path.split(inFile)[0], os.path.basename(inFile) + '.srt') elif os.path.exists(os.path.join(os.path.split(inFile)[0], os.path.basename(inFile) + '.ass')): subfile = os.path.join(os.path.split(inFile)[0], os.path.basename(inFile) + '.ass') elif subfile == 'self': subfile = inFile elif not subfile or not os.path.exists(subfile): subfile = '' if subfile: sInfo = vInfo if subfile != inFile: sInfo = video_info(subfile) logger.info('sInfo: %s' % sInfo) subType = sInfo.get('subType') forcedsub = sInfo.get('forcedSub') logger.info("subType: {0}{1}".format(subType, '' if forcedsub == None else ' (forced)')) #escape ffmpeg special characters #subfile_escape = re.sub(r"'", r"\\\\\\'", subfile_escape) #can't seem to escape ' character subfile_escape = re.sub(r'([\\\[\]\:@;,])', r'\\\1', subfile) # Use "subStream" tag to determine which subtitle stream to use textSubStream = '' picSubStream = '' subStream = vInfo.get('subStream', forcedsub) if subStream != None and re.match(r'^[0-9]+$', str(subStream)): logger.info("subStream: {0}".format(subStream)) textSubStream = ":si={0}".format(subStream) picSubStream = ":{0}".format(subStream) vfilter = [] if re.search(r'ass|ssa', subType) and subfile != inFile: vfilter = ['-vf', "ass=\\'{0}\\'".format(subfile_escape)] elif re.search(r'ass|ssa|subrip|srt|sup|sami|text|microdvd|subviewer|stl|jaco|mpl|pjs|vplayer|eia|webvtt', subType): # jacosub can also include gfx? vfilter = ['-vf', "subtitles=\\'{0}\\'{1}".format(subfile_escape, textSubStream)] elif re.search(r'pgs|vob|dvdsub|dvd_subtitle', subType): vfilter = ['-filter_complex', "[0:v][0:s{0}]overlay".format(picSubStream)] if vfilter: logger.info('video filter: %s' % vfilter) return vfilter return False
def push_one_file(self, f): file_info = VideoDetails() file_info['valid'] = transcode.supported_format(f['path']) temp_share = config.get_server('temp_share', '') temp_share_path = '' remux_path = os.path.dirname(f['path']) if temp_share: for name, data in config.getShares(): if temp_share == name: temp_share_path = data.get('path') remux_path = temp_share_path mime = 'video/mpeg' if config.isHDtivo(f['tsn']): for m in ['video/mp4', 'video/bif']: if transcode.tivo_compatible(f['path'], f['tsn'], m)[0]: mime = m break if (mime == 'video/mpeg' and transcode.mp4_remuxable(f['path'], f['tsn'])): if config.get_freeSpace(remux_path, f['path']): new_path = transcode.mp4_remux(f['path'], f['name'], f['tsn'], temp_share_path) if new_path: mime = 'video/mp4' f['name'] = new_path if temp_share_path: ip = config.get_ip() port = config.getPort() container = quote(temp_share) + '/' f['url'] = 'http://%s:%s/%s' % (ip, port, container) else: logger.warning('Not enough disk space to perform remux, ' + 'transcoding instead.') if file_info['valid']: file_info.update(self.metadata_full(f['path'], f['tsn'], mime)) url = f['url'] + quote(f['name']) title = file_info['seriesTitle'] if not title: title = file_info['title'] source = file_info['seriesId'] if not source: source = title subtitle = file_info['episodeTitle'] try: m = mind.getMind(f['tsn']) m.pushVideo( tsn = f['tsn'], url = url, description = file_info['description'], duration = file_info['duration'] / 1000, size = file_info['size'], title = title, subtitle = subtitle, source = source, mime = mime, tvrating = file_info['tvRating']) except ValueError, msg: if 'usernamePasswordError' in msg: if f['name'].endswith('.pyTivo-temp'): fname = os.path.join(remux_path, os.path.basename(f['name'])) fname = unicode(fname, 'utf-8') os.remove(fname) logger.debug(fname + ' has been removed')
def transcode(isQuery, inFile, outFile, tsn='', mime='', thead=''): settings = { 'video_codec': select_videocodec(inFile, tsn, mime), 'video_br': select_videobr(inFile, tsn), 'video_fps': select_videofps(inFile, tsn), 'max_video_br': select_maxvideobr(tsn), 'buff_size': select_buffsize(tsn), 'aspect_ratio': ' '.join(select_aspect(inFile, tsn)), 'audio_br': select_audiobr(tsn), 'audio_fr': select_audiofr(inFile, tsn), 'audio_ch': select_audioch(inFile, tsn), 'audio_codec': select_audiocodec(isQuery, inFile, tsn), 'audio_lang': select_audiolang(inFile, tsn), 'ffmpeg_pram': select_ffmpegprams(tsn), 'format': select_format(tsn, mime) } if isQuery: return settings ffmpeg_path = config.get_bin('ffmpeg') cmd_string = config.getFFmpegTemplate(tsn) % settings fname = unicode(inFile, 'utf-8') if mswindows: fname = fname.encode('cp1252') if inFile[-5:].lower() == '.tivo': tivodecode_path = config.get_bin('tivodecode') tivo_mak = config.get_server('tivo_mak') tcmd = [tivodecode_path, '-m', tivo_mak, fname] tivodecode = subprocess.Popen(tcmd, stdout=subprocess.PIPE, bufsize=(512 * 1024)) if tivo_compatible(inFile, tsn)[0]: cmd = '' ffmpeg = tivodecode else: cmd = [ffmpeg_path, '-i', '-'] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, stdin=tivodecode.stdout, stdout=subprocess.PIPE, bufsize=(512 * 1024)) else: cmd = [ffmpeg_path, '-i', fname] + cmd_string.split() ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:') debug(' '.join(cmd)) ffmpeg_procs[inFile] = { 'process': ffmpeg, 'start': 0, 'end': 0, 'last_read': time.time(), 'blocks': [] } if thead: ffmpeg_procs[inFile]['blocks'].append(thead) reap_process(inFile) return resume_transfer(inFile, outFile, 0)