Beispiel #1
0
    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&amp;'
                    + "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&amp;Container="
                            + quote(section)
                            + "&amp;TiVo="
                            + pytivo.config.TIVOS[tsn]["address"]
                            + '">'
                            + pytivo.config.TIVOS[tsn]["name"]
                            + "</a><br>"
                        )

        self.send_html(str(t))
Beispiel #2
0
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)
Beispiel #3
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
Beispiel #4
0
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
Beispiel #5
0
 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)
Beispiel #6
0
        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
Beispiel #7
0
    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))