Пример #1
0
Файл: tvh.py Проект: ccdale/tvh
def deleteRecording(uuid):
    try:
        data = {"uuid": uuid}
        sendToTVH("dvr/entry/remove", data)
    except Exception as e:
        fname = sys._getframe().f_code.co_name
        errorNotify(fname, e)
Пример #2
0
def getStreamType(finfo, stype="video"):
    try:
        for stream in finfo["streams"]:
            if "codec_type" in stream and stream["codec_type"] == stype:
                return stream
        return None
    except Exception as e:
        errorNotify("getStreamType", e)
Пример #3
0
def makeCmd(tracks, fqfn, ofn):
    try:
        cmdstub, mapcmd, ascmd = makeStub(tracks, fqfn)
        convcmd = ["-c:v", "libx265", "-crf", "28"]
        cmd = cmdstub + mapcmd + convcmd + ascmd + [ofn]
        msg = "SD Command:"
        for thing in cmd:
            msg += " " + thing
        return (cmd, msg)
    except Exception as e:
        errorNotify("makeCmd", e)
Пример #4
0
def makeStub(tracks, fqfn):
    try:
        cmdstub = ["nice", "-n", "19", "ffmpeg", "-i", fqfn]
        mapcmd = ["-map", f"0:{tracks[0]}", "-map", f"0:{tracks[1]}"]
        ascmd = ["-acodec", "copy"]
        withsubs = True if tracks[2] > 0 else False
        if withsubs:
            mapcmd += ["-map", f"0:{tracks[2]}"]
            ascmd += ["-scodec", "copy"]
        return (cmdstub, mapcmd, ascmd)
    except Exception as e:
        errorNotify("makeStub", e)
Пример #5
0
def fileDuration(finfo):
    try:
        dur = 0
        sdur = ""
        stream = getStreamType(finfo, "video")
        if stream is not None and "duration" in stream:
            xtmp = stream["duration"].split(".")
            dur = int(xtmp[0])
            sdur = UT.hms(dur)
        return (dur, sdur)
    except Exception as e:
        errorNotify("fileDuration", e)
Пример #6
0
def hasSubtitles(finfo):
    try:
        ret = False
        try:
            stream = getStreamType(finfo, stype="subtitle")
            if stream is not None:
                ret = True
        except Exception as e:
            errorNotify("hasSubtitles", e)
        return ret
    except Exception as e:
        errorNotify("hasSubtitles", e)
Пример #7
0
Файл: tvh.py Проект: ccdale/tvh
def channelPrograms(channel="BBC Four HD"):
    """
    return a time sorted dict of programs for the named channel

    each event looks like:
    {
      'eventId': 5050806,
      'episodeId': 5050807,
      'serieslinkId': 91157,
      'serieslinkUri': 'ddprogid:///usr/bin/tv_grab_zz_sdjson/SH000191120000',
      'channelName': 'BBC Four HD',
      'channelUuid': '2f6501b00ef0982c8fc3aa67b0229ecc',
      'channelNumber': '106',
      'channelIcon': 'https://s3.amazonaws.com/schedulesdirect/assets/stationLogos/s83282_h3_aa.png',
      'start': 1567936800,
      'stop': 1567965480,
      'title': 'SIGN OFF',
      'description': 'Sign off.',
      'summary': 'Sign off.', # optional
      'nextEventId': 5050808,
    }
    """
    try:
        # chans = channels()
        # now = int(time.time())
        # xfilter = [ { "field": "name", "type": "string", "value": channel, "comparison": "eq", } ]
        # xfilter = [
        #     {"field": "stop", "type": "numeric", "value": str(now), "comparison": "gt"},
        #     {
        #         "field": "start",
        #         "type": "numeric",
        #         "value": str(now + (3600 * 24)),
        #         "comparison": "lt",
        #     },
        # ]
        # if chans is not None:
        # for chan in chans:
        # if chan["name"] == channel:
        # data = {"filter": xfilter}
        data = {"limit": "999"}
        j = sendToTVH("epg/events/grid", data)
        print(str(j["totalCount"]) + " programs")
        mindur, minprog = UT.displayProgramList(j["entries"], 24, channel)
        print("min duration: {}".format(mindur))
        print("{}".format(minprog))
        # break
        # else:
        # print("chans is none")
    except Exception as e:
        fname = sys._getframe().f_code.co_name
        errorNotify(fname, e)
Пример #8
0
def checkRemoveOutputFile(ofn):
    try:
        if FUT.fileExists(ofn):
            size = FUT.fileSize(ofn)
            if size > 0:
                msg = f"Destination file '{ofn}' exists: {FUT.sizeof_fmt(size)}, not converting"
                log.info(msg)
                raise ConvertFailure(msg)
            else:
                msg = "Deleting existing zero length destination file '{ofn}'"
                log.info(msg)
                os.remove(ofn)
    except Exception as e:
        errorNotify("checkRemoveOutputFile", e)
Пример #9
0
def canConvert(finfo):
    try:
        ret = False
        try:
            stream = getStreamType(finfo, "video")
            if stream is not None:
                if stream["codec_name"] == "mpeg2video":
                    ret = 1
                elif stream["codec_name"] == "h264":
                    ret = 2
        except Exception as e:
            errorNotify("canConvert", e)
        return ret
    except Exception as e:
        errorNotify("canConvert", e)
Пример #10
0
def makeHDCmd(tracks, fqfn, ofn):
    try:
        cmdstub, mapcmd, ascmd = makeStub(tracks, fqfn)
        # convcmd = ["-c:v", "libx265", "-preset", "ultrafast", "-x265-params"]
        # convcmd.append(
        #     "crf=22:qcomp=0.8:aq-mode=1:aq_strength=1.0:qg-size=16:psy-rd=0.7:psy-rdoq=5.0:rdoq-level=1:merange=44"
        # )
        convcmd = ["-vcodec", "copy"]
        cmd = cmdstub + mapcmd + convcmd + ascmd + [ofn]
        msg = "HD Command:"
        for thing in cmd:
            msg += " " + thing
        return (cmd, msg)
    except Exception as e:
        errorNotify("makeHDCmd", e)
Пример #11
0
Файл: tvh.py Проект: ccdale/tvh
def channels():
    """
    return a sorted list of enabled channels
    """
    try:
        sents = None
        data = {"limit": 200}
        j = sendToTVH("channel/grid", data)
        if "entries" in j:
            sents = sorted(j["entries"],
                           key=itemgetter("number"),
                           reverse=False)
    except Exception as e:
        fname = sys._getframe().f_code.co_name
        errorNotify(fname, e)
    finally:
        return sents
Пример #12
0
def trackIndexes(finfo):
    try:
        vtrack = atrack = strack = -1
        try:
            for stream in finfo["streams"]:
                if "codec_type" in stream:
                    if stream["codec_type"] == "video":
                        vtrack = stream["index"]
                    elif stream["codec_type"] == "audio":
                        if int(stream["channels"]) > 1:
                            atrack = stream["index"]
                    elif stream["codec_type"] == "subtitle":
                        strack = stream["index"]
        except Exception as e:
            errorNotify("trackIndexes", e)
        return (vtrack, atrack, strack)
    except Exception as e:
        errorNotify("trackIndexes", e)
Пример #13
0
def processProc(proc, regex, duration, outq):
    """
    looking for the output lines from ffmpeg that look like

    frame=   71 fps=0.0 q=-0.0 size=       3kB time=00:00:03.43 bitrate=   7.7kbits/s speed=6.86x

    frame=34458 fps= 35 q=-0.0 size= 1031676kB time=00:22:59.64 bitrate=6125.9kbits/s speed= 1.4x

    using the python regex extensions to name the groups
    (see https://docs.python.org/3/howto/regex.html#non-capturing-and-named-groups)

    The regular expression is now in the convert function so that it is
    only compiled once.
    """
    global olines
    try:
        pc = 0
        sthen = stleft = ssize = ""
        for line in iter(proc.stdout.readline, ""):
            # print(line)
            # canoutput = False
            m = regex.match(line)
            if m is not None:
                xdict = m.groupdict()
                if "time" in xdict:
                    now = int(time.time())
                    # print("getting tsecs")
                    tsecs = UT.secondsFromHMS(xdict["time"])
                    # print("getting pc")
                    pc = int((tsecs * 100) / duration)
                    if "speed" in xdict:
                        tleft = int((duration - tsecs) / float(xdict["speed"]))
                        stleft = UT.hms(tleft)
                        then = now + tleft
                        dtts = datetime.datetime.fromtimestamp(then)
                        sthen = dtts.strftime("%H:%M:%S")
                    if "size" in xdict:
                        tsz = xdict["size"].split("k")
                        ssize = FUT.sizeof_fmt(int(int(tsz[0]) * 1000))
            else:
                olines.append(line)
            outq.put(f"Complete: {pc}% {ssize} ETA: {sthen} ({stleft})")
    except Exception as e:
        errorNotify("processProc", e)
Пример #14
0
def convert(fqfn):
    rc = 1
    try:
        finfo = fileInfo(fqfn)
        rstr = r"frame=\s*(?P<frame>[0-9]+)\s+"
        rstr += r"fps=\s*(?P<fps>[0-9.]+)\s+.*"
        rstr += r"size=\s*(?P<size>[0-9kmgB]+)\s+"
        rstr += r"time=(?P<time>[0-9:.]+)\s+"
        rstr += r"bitrate=\s*(?P<bitrate>[0-9.]+[km]bits/s)\s+"
        rstr += r"speed=\s*(?P<speed>[0-9.]+)x"
        regex = re.compile(rstr)
        if finfo is not None and canConvert(finfo):
            cconv = canConvert(finfo)
            if cconv == 1:
                tracks = trackIndexes(finfo)
                withsubs = True if tracks[2] > 0 else False
                fn, fext = os.path.splitext(fqfn)
                ofn = fn + ".mkv"
                checkRemoveOutputFile(ofn)
                if cconv == 1:
                    cmd, msg = makeCmd(tracks, fqfn, ofn)
                    sizecheck = True
                else:
                    cmd, msg = makeHDCmd(tracks, fqfn, ofn)
                    sizecheck = False
                log.info(msg)
                xmsg = ", with subtitles," if withsubs else ""
                msg = f"Converting{xmsg} '{fqfn}' to '{ofn}'"
                log.info(msg)
                dur, sdur = fileDuration(finfo)
                log.info(f"file duration: {sdur}")
                rc = runThreadConvert(cmd, fqfn, ofn, dur, regex)
                tidy(rc, fqfn, ofn, sizecheck=sizecheck)
            elif cconv == 2:
                msg = f"Not converting HD stream {fqfn}"
                log.warning(msg)
        else:
            msg = f"Cannot convert {fqfn}"
            log.error(msg)
            raise ConvertFailure(msg)
    except Exception as e:
        errorNotify("convert", e)
    return rc
Пример #15
0
def runThreadConvert(cmd, fqfn, ofn, duration, regex):
    global gpid
    try:
        print("")
        proc = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
        )
        gpid = proc.pid
        outq = queue.Queue()
        t = threading.Thread(target=processProc,
                             args=(proc, regex, duration, outq))
        # wait a bit before processing output
        time.sleep(10)
        # start the thread to read and process output from ffmpeg
        t.start()
        try:
            print("")
            while True:
                try:
                    line = outq.get(block=False)
                    # log.info(line)
                    print(f"\r{line:>56}", end="")
                except queue.Empty:
                    time.sleep(10)
                if proc.poll() is not None:
                    print("")
                    break
        finally:
            rc = proc.returncode
            # wait for ffmpeg to finish producing output
            t.join()
            return rc
    except Exception as e:
        errorNotify("runThreadConvert", e)
Пример #16
0
def fileInfo(fqfn):
    try:
        finfo = None
        try:
            if FUT.fileExists(fqfn):
                cmd = [
                    "ffprobe",
                    "-loglevel",
                    "quiet",
                    "-of",
                    "json",
                    "-show_streams",
                    fqfn,
                ]
                proc = subprocess.run(cmd, capture_output=True)
                if proc.returncode == 0:
                    xstr = proc.stdout.decode("utf-8")
                    # print(xstr)
                    finfo = json.loads(xstr)
        except Exception as e:
            errorNotify("fileInfo", e)
        return finfo
    except Exception as e:
        errorNotify("fileInfo", e)
Пример #17
0
Файл: tvh.py Проект: ccdale/tvh
def finishedRecordings():
    """
    grid_finished returns a dict

    single program looks like:
    {
        'uuid': 'a64b50c335f01c0df1a49f11a0f8d3f4',
        'enabled': True,
        'start': 1576749600,
        'start_extra': 0,
        'start_real': 1576749570,
        'stop': 1576751400,
        'stop_extra': 0,
        'stop_real': 1576752300,
        'duration': 2700,
        'channel': 'c5827940c7ae3d76ea80df053112dc9c',
        'channel_icon': '',
        'channelname': 'BBC ONE HD',
        'title': {'eng': 'Homes Under the Hammer'},
        'disp_title': 'Homes Under the Hammer',
        'subtitle': {'eng': 'A house with a stream but close to a railway line in Handsacre in Staffordshire and a large three-storey property in Plymouth are sold under the hammer. [S] [HD]'},
        'disp_subtitle': 'A house with a stream but close to a railway line in Handsacre in Staffordshire and a large three-storey property in Plymouth are sold under the hammer. [S] [HD]',
        'description': {'eng': 'A house with a stream but close to a railway line in Handsacre in Staffordshire and a large three-storey property in Plymouth are sold under the hammer. [S] [HD]'},
        'disp_description': 'A house with a stream but close to a railway line in Handsacre in Staffordshire and a large three-storey property in Plymouth are sold under the hammer. [S] [HD]',
        'pri': 2,
        'retention': 0,
        'removal': 0,
        'playposition': 0,
        'playcount': 0,
        'config_name': 'ee86fd19903e87679e5fdfe243966ad0',
        'owner': 'chris',
        'creator': 'chris',
        'filename': '/home/hts/Railway/Homes-Under-the-Hammer.ts',
        'directory': 'Railway',
        'errorcode': 0,
        'errors': 0,
        'data_errors': 0,
        'dvb_eid': 0,
        'noresched': True,
        'norerecord': False,
        'fileremoved': 0,
        'autorec': '0dee37cd9707da051618045a73c9aa43',
        'autorec_caption': 'railway',
        'timerec': '',
        'timerec_caption': '',
        'parent': '',
        'child': '',
        'content_type': 2,
        'broadcast': 0,
        'url': 'dvrfile/a64b50c335f01c0df1a49f11a0f8d3f4',
        'filesize': 1045284324,
        'status': 'Completed OK',
        'sched_status': 'completed',
        'duplicate': 0,
        'comment': 'Auto recording: railway'
    }
    """
    entries = None
    total = 0
    try:
        data = {"limit": 100}
        j = sendToTVH("dvr/entry/grid_finished", data)
        if "entries" in j:
            entries = j["entries"]
        if "total" in j:
            total = int(j["total"])
    except Exception as e:
        fname = sys._getframe().f_code.co_name
        errorNotify(fname, e)
    finally:
        return (total, entries)