def infopage(self) -> None: t = INFO_PAGE_TCLASS() t.admin = "" if get_server("tivo_mak", "") and get_server("togo_path", ""): t.togo = "<br>Pull from TiVos:<br>" else: t.togo = "" for section, settings in 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 pytivo.config.TIVOS: if tsn and "address" in pytivo.config.TIVOS[tsn]: t.togo += ( '<a href="/TiVoConnect?' + "Command=NPL&Container=" + quote(section) + "&TiVo=" + pytivo.config.TIVOS[tsn]["address"] + '">' + pytivo.config.TIVOS[tsn]["name"] + "</a><br>" ) self.send_html(str(t))
def transcode(inFile: str, outFile: BinaryIO, tsn: str = "", mime: str = "", thead: bytes = b"") -> int: settings = transcode_settings(isQuery=False, inFile=inFile, tsn=tsn, mime=mime) ffmpeg_path = get_bin("ffmpeg") if ffmpeg_path is None: LOGGER.error("No ffmpeg binary found") return 0 if inFile[-5:].lower() == ".tivo": tivodecode_path = get_bin("tivodecode") if tivodecode_path is None: LOGGER.error("No tivodecode binary found.") return 0 tivo_mak = get_server("tivo_mak", "") if tivo_mak == "": LOGGER.error("No valid tivo_mak found.") return 0 tcmd = [tivodecode_path, "-m", tivo_mak, inFile] 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", inFile] + settings ffmpeg = subprocess.Popen(cmd, bufsize=(512 * 1024), stdout=subprocess.PIPE) if cmd: LOGGER.debug("transcoding to tivo model " + tsn[:3] + " using ffmpeg command:") LOGGER.debug(" ".join(cmd)) FFMPEG_PROCS[inFile] = FfmpegProcess(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 from_tivo(full_path: str) -> Dict[str, str]: tdcat_path = get_bin("tdcat") tivo_mak = 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) except: metadata = {} return metadata
def tsn_from_service_info(info: zeroconf.ServiceInfo) -> Optional[str]: tsn = info.properties.get(b"TSN") if get_server("togo_all", ""): tsn = info.properties.get(b"tsn", tsn) if tsn is None: return None if isinstance(tsn, bytes): tsn_str = tsn.decode("utf-8") else: tsn_str = str(tsn) return tsn_str
def ToGo(self, handler: "TivoHTTPHandler", query: Query) -> None: togo_path = get_server("togo_path", "") for name, data in getShares(): if togo_path == name: togo_path = str(data.get("path")) if togo_path: tivoIP = query["TiVo"][0] tsn = tivos_by_ip(tivoIP) tivo_mak = get_tsn("tivo_mak", tsn) urls = query.get("Url", []) decode = "decode" in query save = "save" in query ts_format = "ts_format" in query for theurl in urls: STATUS[theurl] = { "running": False, "error": "", "rate": "", "queued": True, "size": 0, "finished": False, "decode": decode, "save": save, "ts_format": ts_format, } 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)
result = int(thing) except: result = 0 return result AUTH_HANDLER = urllib.request.HTTPPasswordMgrWithDefaultRealm() cj = http.cookiejar.CookieJar() cj.set_cookie(null_cookie("sid", "ADEADDA7EDEBAC1E")) TIVO_OPENER = urllib.request.build_opener( urllib.request.HTTPCookieProcessor(cj), urllib.request.HTTPBasicAuthHandler(AUTH_HANDLER), urllib.request.HTTPDigestAuthHandler(AUTH_HANDLER), ) tsn = get_server("togo_tsn", "") if tsn: TIVO_OPENER.addheaders.append(("TSN", tsn)) class ToGo(Plugin): CONTENT_TYPE = "text/html" def tivo_open(self, url: str) -> BinaryIO: # 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
def send_file(self, handler: "TivoHTTPHandler", path: str, query: Query) -> None: mime = "video/x-tivo-mpeg" tsn = handler.headers.get("tsn", "") try: assert tsn tivo_name = pytivo.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 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(get_bin("tivodecode") and get_server("tivo_mak", "")) else: valid = True if valid and offset: valid = (compatible and offset < os.path.getsize(path)) or ( not compatible and 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) thead = b"" if faking: thead = self.tivo_header(tsn, path, mime) if compatible: size = os.path.getsize(path) + len(thead) handler.send_response(200) handler.send_header("Content-Length", str(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)) start = time.time() count = 0 if valid: if compatible: if faking and not offset: handler.wfile.write(thead) LOGGER.debug('"%s" is tivo compatible' % path) f = open(path, "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 as msg: LOGGER.info(msg) f.close() else: LOGGER.debug('"%s" is not tivo compatible' % path) if offset: count = resume_transfer(path, handler.wfile, offset) else: count = transcode(path, handler.wfile, tsn, mime, thead) try: if not compatible: handler.wfile.write(b"0\r\n\r\n") handler.wfile.flush() except Exception as msg: LOGGER.info(msg) mega_elapsed = (time.time() - start) * 1024 * 1024 if mega_elapsed < 1: mega_elapsed = 1 rate = count * 8.0 / mega_elapsed LOGGER.info( '[%s] Done sending "%s" to %s, %d bytes, %.2f Mb/s' % (time.strftime("%d/%b/%Y %H:%M:%S"), path, tivo_name, count, rate))