コード例 #1
0
ファイル: transcode.py プロジェクト: wmcbrine/pytivo
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)
コード例 #2
0
ファイル: transcode.py プロジェクト: thspencer/pyTivo-Taylor
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)
コード例 #3
0
    def send_file(self, handler, path, query):
        seek = int(query.get('Seek', [0])[0])
        duration = int(query.get('Duration', [0])[0])
        always = (handler.container.getboolean('force_ffmpeg')
                  and config.get_bin('ffmpeg'))
        fname = unicode(path, 'utf-8')

        ext = os.path.splitext(fname)[1].lower()
        needs_transcode = ext in TRANSCODE or seek or duration or always

        if not needs_transcode:
            fsize = os.path.getsize(fname)
            handler.send_response(200)
            handler.send_header('Content-Length', fsize)
        else:
            handler.send_response(206)
            handler.send_header('Transfer-Encoding', 'chunked')
        handler.send_header('Content-Type', 'audio/mpeg')
        handler.end_headers()

        if needs_transcode:
            if mswindows:
                fname = fname.encode('cp1252')

            cmd = [config.get_bin('ffmpeg'), '-i', fname, '-vn']
            if ext in ['.mp3', '.mp2']:
                cmd += ['-acodec', 'copy']
            else:
                cmd += ['-ab', '320k', '-ar', '44100']
            cmd += ['-f', 'mp3', '-']
            if seek:
                cmd[-1:] = ['-ss', '%.3f' % (seek / 1000.0), '-']
            if duration:
                cmd[-1:] = ['-t', '%.3f' % (duration / 1000.0), '-']

            ffmpeg = subprocess.Popen(cmd,
                                      bufsize=BLOCKSIZE,
                                      stdout=subprocess.PIPE)
            while True:
                try:
                    block = ffmpeg.stdout.read(BLOCKSIZE)
                    handler.wfile.write('%x\r\n' % len(block))
                    handler.wfile.write(block)
                    handler.wfile.write('\r\n')
                except Exception, msg:
                    handler.server.logger.info(msg)
                    kill(ffmpeg)
                    break

                if not block:
                    break
コード例 #4
0
ファイル: music.py プロジェクト: akolster/pytivo
    def send_file(self, handler, path, query):
        seek = int(query.get('Seek', [0])[0])
        duration = int(query.get('Duration', [0])[0])
        always = (handler.container.getboolean('force_ffmpeg') and
                  config.get_bin('ffmpeg'))
        fname = unicode(path, 'utf-8')

        ext = os.path.splitext(fname)[1].lower()
        needs_transcode = ext in TRANSCODE or seek or duration or always

        if not needs_transcode:
            fsize = os.path.getsize(fname)
            handler.send_response(200)
            handler.send_header('Content-Length', fsize)
        else:
            handler.send_response(206)
            handler.send_header('Transfer-Encoding', 'chunked')
        handler.send_header('Content-Type', 'audio/mpeg')
        handler.end_headers()

        if needs_transcode:
            if mswindows:
                fname = fname.encode('iso8859-1')

            cmd = [config.get_bin('ffmpeg'), '-i', fname, '-vn']
            if ext in ['.mp3', '.mp2']:
                cmd += ['-acodec', 'copy']
            else:
                cmd += ['-ab', '320k', '-ar', '44100']
            cmd += ['-f', 'mp3', '-']
            if seek:
                cmd[-1:] = ['-ss', '%.3f' % (seek / 1000.0), '-']
            if duration:
                cmd[-1:] = ['-t', '%.3f' % (duration / 1000.0), '-']

            ffmpeg = subprocess.Popen(cmd, bufsize=BLOCKSIZE,
                                      stdout=subprocess.PIPE)
            while True:
                try:
                    block = ffmpeg.stdout.read(BLOCKSIZE)
                    handler.wfile.write('%x\r\n' % len(block))
                    handler.wfile.write(block)
                    handler.wfile.write('\r\n')
                except Exception, msg:
                    handler.server.logger.info(msg)
                    kill(ffmpeg)
                    break

                if not block:
                    break
コード例 #5
0
ファイル: transcode.py プロジェクト: Gimpson/pytivo
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)
コード例 #6
0
ファイル: transcode.py プロジェクト: wmcbrine/pytivo
def mp4_remux(inFile, basename, tsn=""):
    outFile = inFile + ".pyTivo-temp"
    newname = basename + ".pyTivo-temp"
    if os.path.exists(outFile):
        return None  # ugh!

    ffmpeg_path = config.get_bin("ffmpeg")
    fname = unicode(inFile, "utf-8")
    oname = unicode(outFile, "utf-8")
    if mswindows:
        fname = fname.encode("cp1252")
        oname = oname.encode("cp1252")

    acodec = select_audiocodec(False, inFile, tsn, "video/mp4")
    settings = select_buffsize(tsn) + ["-c:v", "copy"] + 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), "-f", "mp4"]

    cmd = [ffmpeg_path, "-i", fname] + " ".join(settings).split() + [oname]

    debug("transcoding to tivo model " + tsn[:3] + " using ffmpeg command:")
    debug(" ".join(cmd))

    ffmpeg = subprocess.Popen(cmd)
    debug("remuxing " + inFile + " to " + outFile)
    if ffmpeg.wait():
        debug("error during remuxing")
        os.remove(outFile)
        return None

    return newname
コード例 #7
0
ファイル: transcode.py プロジェクト: wynneth/pytivo
def tivo_compatible(inFile, tsn='', mime=''):
    vInfo = video_info(inFile)

    message = (True, 'all compatible')
    if not config.get_bin('ffmpeg'):
        if mime not in ['video/x-tivo-mpeg', 'video/mpeg', '']:
            message = (False, 'no ffmpeg')
        return message

    while True:
        vmessage = tivo_compatible_video(vInfo, tsn, mime)
        if not vmessage[0]:
            message = vmessage
            break

        amessage = tivo_compatible_audio(vInfo, inFile, tsn, mime)
        if not amessage[0]:
            message = amessage
            break

        cmessage = tivo_compatible_container(vInfo, inFile, mime)
        if not cmessage[0]:
            message = cmessage

        break

    debug('TRANSCODE=%s, %s, %s' % (['YES', 'NO'][message[0]],
                                           message[1], inFile))
    return message
コード例 #8
0
ファイル: transcode.py プロジェクト: lordsutch/pytivo
def detect_h264_level(fname, vstream=0):
    ffprobe_path = config.get_bin('ffprobe')
    if not ffprobe_path:
        return 0

    cmd = [ffprobe_path, '-of', 'flat', '-show_streams', '-i', fname]
    # Windows and other OS buffer 4096 and ffprobe can output more than that.
    out_tmp = tempfile.TemporaryFile()
    ffprobe = subprocess.Popen(cmd, stdout=out_tmp, stderr=subprocess.PIPE,
                               stdin=subprocess.PIPE)

    # wait configured # of seconds: if ffprobe is not back give up
    limit = config.getFFmpegWait()
    if limit:
        for i in xrange(limit * 20):
            time.sleep(.05)
            if not ffprobe.poll() == None:
                break

        if ffprobe.poll() == None:
            kill(ffprobe)
            return 0
    else:
        ffprobe.wait()

    out_tmp.seek(0)
    output = out_tmp.read()
    out_tmp.close()
    debug('ffprobe output=%s' % repr(output))

    match = re.search(r'streams\.stream\.\d+\.level=(\d+)', output)
    if match:
        return int(match.group(1))
    return 0
コード例 #9
0
ファイル: transcode.py プロジェクト: hmblprogrammer/pytivo
def tivo_compatible(inFile, tsn='', mime=''):
    vInfo = video_info(inFile)

    message = (True, 'all compatible')
    if not config.get_bin('ffmpeg'):
        if mime not in ['video/x-tivo-mpeg', 'video/mpeg', '']:
            message = (False, 'no ffmpeg')
        return message

    while True:
        vmessage = tivo_compatible_video(vInfo, tsn, mime)
        if not vmessage[0]:
            message = vmessage
            break

        amessage = tivo_compatible_audio(vInfo, inFile, tsn, mime)
        if not amessage[0]:
            message = amessage
            break

        cmessage = tivo_compatible_container(vInfo, inFile, mime)
        if not cmessage[0]:
            message = cmessage

        break

    debug('TRANSCODE=%s, %s, %s' %
          (['YES', 'NO'][message[0]], message[1], inFile))
    return message
コード例 #10
0
ファイル: transcode.py プロジェクト: wmcbrine/pytivo
def tivo_compatible(inFile, tsn="", mime=""):
    vInfo = video_info(inFile)

    message = (True, "all compatible")
    if not config.get_bin("ffmpeg"):
        if mime not in ["video/x-tivo-mpeg", "video/mpeg", ""]:
            message = (False, "no ffmpeg")
        return message

    while True:
        vmessage = tivo_compatible_video(vInfo, tsn, mime)
        if not vmessage[0]:
            message = vmessage
            break

        amessage = tivo_compatible_audio(vInfo, inFile, tsn, mime)
        if not amessage[0]:
            message = amessage
            break

        cmessage = tivo_compatible_container(vInfo, inFile, mime)
        if not cmessage[0]:
            message = cmessage

        break

    debug("TRANSCODE=%s, %s, %s" % (["YES", "NO"][message[0]], message[1], inFile))
    return message
コード例 #11
0
    def send_file(self, handler, path, query):
        seek = int(query.get('Seek', [0])[0])
        duration = int(query.get('Duration', [0])[0])
        always = (handler.container.get('force_ffmpeg', 'False').lower()
                  == 'true' and config.get_bin('ffmpeg'))
        fname = unicode(path, 'utf-8')

        ext = os.path.splitext(fname)[1].lower()
        needs_transcode = ext in TRANSCODE or seek or duration or always

        handler.send_response(200)
        handler.send_header('Content-Type', 'audio/mpeg')
        if not needs_transcode:
            fsize = os.path.getsize(fname)
            handler.send_header('Content-Length', fsize)
        handler.send_header('Connection', 'close')
        handler.end_headers()

        if needs_transcode:
            if mswindows:
                fname = fname.encode('iso8859-1')

            cmd = [config.get_bin('ffmpeg'), '-i', fname]
            if ext in ['.mp3', '.mp2']:
                cmd += ['-acodec', 'copy']
            else:
                cmd += ['-ab', '320k', '-ar', '44100']
            cmd += ['-f', 'mp3', '-']
            if seek:
                cmd[-1:] = ['-ss', '%.3f' % (seek / 1000.0), '-']
            if duration:
                cmd[-1:] = ['-t', '%.3f' % (duration / 1000.0), '-']

            ffmpeg = subprocess.Popen(cmd,
                                      bufsize=(64 * 1024),
                                      stdout=subprocess.PIPE)
            try:
                shutil.copyfileobj(ffmpeg.stdout, handler.wfile)
            except:
                kill(ffmpeg)
        else:
            f = open(fname, 'rb')
            try:
                shutil.copyfileobj(f, handler.wfile)
            except:
                pass
            f.close()
コード例 #12
0
ファイル: music.py プロジェクト: brimimc/pytivo
    def send_file(self, handler, path, query):
        seek = int(query.get('Seek', [0])[0])
        duration = int(query.get('Duration', [0])[0])
        always = (handler.container.get('force_ffmpeg',
                  'False').lower() == 'true' and config.get_bin('ffmpeg'))
        fname = unicode(path, 'utf-8')

        ext = os.path.splitext(fname)[1].lower()
        needs_transcode = ext in TRANSCODE or seek or duration or always

        handler.send_response(200)
        handler.send_header('Content-Type', 'audio/mpeg')
        if not needs_transcode:
            fsize = os.path.getsize(fname)
            handler.send_header('Content-Length', fsize)
        handler.send_header('Connection', 'close')
        handler.end_headers()

        if needs_transcode:
            if mswindows:
                fname = fname.encode('iso8859-1')

            cmd = [config.get_bin('ffmpeg'), '-i', fname]
            if ext in ['.mp3', '.mp2']:
                cmd += ['-acodec', 'copy']
            else:
                cmd += ['-ab', '320k', '-ar', '44100']
            cmd += ['-f', 'mp3', '-']
            if seek:
                cmd[-1:] = ['-ss', '%.3f' % (seek / 1000.0), '-']
            if duration:
                cmd[-1:] = ['-t', '%.3f' % (duration / 1000.0), '-']

            ffmpeg = subprocess.Popen(cmd, bufsize=(64 * 1024),
                                      stdout=subprocess.PIPE)
            try:
                shutil.copyfileobj(ffmpeg.stdout, handler.wfile)
            except:
                kill(ffmpeg)
        else:
            f = open(fname, 'rb')
            try:
                shutil.copyfileobj(f, handler.wfile)
            except:
                pass
            f.close()
コード例 #13
0
ファイル: update.py プロジェクト: thspencer/pyTivo-Taylor
def do_update_git(pyTivo_dir, latest):
    git_path = config.get_bin('git')
    output, err = None, None

    logger.debug('Git executable path is: %s' % git_path)

    if git_path:
        try:
            # this may not be syncing with GitHub but another remote
            # it depends on the local git repository configuration
            exec_git = subprocess.Popen([git_path, 'pull origin', GIT_BRANCH],
                                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                                        cwd=pyTivo_dir)
            output, err = exec_git.communicate()
            if 'not a git command' in output: # try alternate method if pull origin fails
                exec_git = subprocess.Popen([git_path, 'pull'], stdout=subprocess.PIPE,
                                            stderr=subprocess.STDOUT, cwd=pyTivo_dir)
                output, err = exec_git.communicate()
            logger.debug('Git output:\n%s' % output)
            if err:
                logger.debug('Git error output: %s' % err)
        except OSError, e:
            logger.error('There was an error during Git execution: %s' % e)
            return False

        if not output or err:
            logger.error('Git produced no output')
            return False

        # catch fatal error from Git
        # reason is usually cwd is not a proper git install or is corrupt
        if 'fatal:' in output or err:
            logger.error('Install corrupt or not a git repository:\n%s' % pyTivo_dir)
            return False

        if 'error:' in output or err:
            logger.error('Unable to update existing files')
            return 'no_permission'

        # catch already up-to-date git status
        # if user sees this there may be a bug in the current version detection
        # or are using an out of date remote repository that is out of sync with GitHub.
        if 'Already up-to-date' in output:
            logger.error('Version mismatch. Local git may be fetching ' +
                         'from an outdated remote repository.')
            logger.info('Recommended to use GitHub repository instead from:\n%s' %
                         PACKAGE_URL.split('tarball')[0])
            return False

        # check for successful output at end of git pull.
        # typically will be indication of files changed, insertions, or deletions
        if ('changed' and 'insertions' and 'deletions') in output:
            return True
        else:
            logger.error('Can not determine if Git pull was successful; assuming failure')
            return False
コード例 #14
0
ファイル: tivodownload.py プロジェクト: mlippert/pytivo
    def __init__(self, tivoIP, active_tivos, active_tivos_lock, tivo_open):
        """
        Initialize the TivoDownload with the IP address of the tivo in the
        active tivo list whose queue is to be processed and a function
        to open a tivo download url.
        """
        super().__init__()
        self.tivoIP = tivoIP
        self.active_tivos = active_tivos
        self.active_tivos_lock = active_tivos_lock
        self.tivo_open = tivo_open
        with self.active_tivos_lock:
            self.tivo_tasks = self.active_tivos[tivoIP]

        # prefer tivolibre to tivodecode
        self.decoder_path = config.get_bin('tivolibre')
        self.decoder_is_tivolibre = True
        if not self.decoder_path:
            self.decoder_path = config.get_bin('tivodecode')
            self.decoder_is_tivolibre = False
        self.has_decoder = bool(self.decoder_path)
コード例 #15
0
ファイル: transcode.py プロジェクト: raghu1111/pytivo
def pad_check():
    global pad_style
    if pad_style == UNSET:
        pad_style = OLD_PAD
        filters = tempfile.TemporaryFile()
        cmd = [config.get_bin('ffmpeg'), '-filters']
        ffmpeg = subprocess.Popen(cmd, stdout=filters, stderr=subprocess.PIPE)
        ffmpeg.wait()
        filters.seek(0)
        for line in filters:
            if line.startswith('pad'):
                pad_style = NEW_PAD
                break
        filters.close()
    return pad_style == NEW_PAD
コード例 #16
0
ファイル: transcode.py プロジェクト: wynneth/pytivo
def pad_check():
    global pad_style
    if pad_style == UNSET:
        pad_style = OLD_PAD
        filters = tempfile.TemporaryFile()
        cmd = [config.get_bin('ffmpeg'), '-filters']
        ffmpeg = subprocess.Popen(cmd, stdout=filters, stderr=subprocess.PIPE)
        ffmpeg.wait()
        filters.seek(0)
        for line in filters:
            if line.startswith('pad'):
                pad_style = NEW_PAD
                break
        filters.close()
    return pad_style == NEW_PAD
コード例 #17
0
        def AudioFileFilter(f, filter_type=None):
            ext = os.path.splitext(f)[1].lower()

            if ext in ('.mp3', '.mp2') or (ext in TRANSCODE
                                           and config.get_bin('ffmpeg')):
                return self.AUDIO
            else:
                file_type = False

                if not filter_type or filter_type.split('/')[0] != self.AUDIO:
                    if ext in PLAYLISTS:
                        file_type = self.PLAYLIST
                    elif os.path.isdir(f):
                        file_type = self.DIRECTORY

                return file_type
コード例 #18
0
ファイル: music.py プロジェクト: mlippert/pytivo
        def AudioFileFilter(f, filter_type=None):
            ext = os.path.splitext(f)[1].lower()

            if ext in ('.mp3', '.mp2') or (ext in TRANSCODE and
                                           config.get_bin('ffmpeg')):
                return self.AUDIO
            else:
                file_type = False

                if not filter_type or filter_type.split('/')[0] != self.AUDIO:
                    if ext in PLAYLISTS:
                        file_type = self.PLAYLIST
                    elif os.path.isdir(f):
                        file_type = self.DIRECTORY

                return file_type
コード例 #19
0
def mp4_remux(inFile, basename, tsn='', temp_share_path=''):
    outFile = inFile + '.pyTivo-temp'
    newname = basename + '.pyTivo-temp'

    if temp_share_path:
        newname = os.path.splitext(os.path.split(basename)[1])[0] + '.mp4.pyTivo-temp'
        outFile = os.path.join(temp_share_path, newname)

    if os.path.exists(outFile):
        return None  # ugh!

    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),
            'format': '-f mp4'}

    cmd_string = config.getFFmpegTemplate(tsn) % settings
    cmd = [ffmpeg_path, '-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)
    if ffmpeg.wait():
        debug('error during remuxing')
        os.remove(outFile)
        return None

    return newname
コード例 #20
0
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
コード例 #21
0
ファイル: metadata.py プロジェクト: jtroe/pytivo
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
コード例 #22
0
ファイル: metadata.py プロジェクト: Gimpson/pytivo
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
コード例 #23
0
ファイル: transcode.py プロジェクト: raghu1111/pytivo
def mp4_remux(inFile, basename, tsn=''):
    outFile = inFile + '.pyTivo-temp'
    newname = basename + '.pyTivo-temp'
    if os.path.exists(outFile):
        return None  # ugh!

    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),
        'format': '-f mp4'
    }

    cmd_string = config.getFFmpegTemplate(tsn) % settings
    cmd = [ffmpeg_path, '-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)
    if ffmpeg.wait():
        debug('error during remuxing')
        os.remove(outFile)
        return None

    return newname
コード例 #24
0
ファイル: metadata.py プロジェクト: raghu1111/pytivo
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 (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
    except:
        metadata = {}

    return metadata
コード例 #25
0
ファイル: transcode.py プロジェクト: driver8x/pytivo
def mp4_remux(inFile, basename, tsn='', temp_share_path=''):
    outFile = inFile + '.pyTivo-temp'
    newname = basename + '.pyTivo-temp'

    if temp_share_path:
        newname = os.path.splitext(os.path.split(basename)[1])[0] + '.mp4.pyTivo-temp'
        outFile = os.path.join(temp_share_path, newname)

    if os.path.exists(outFile):
        return None  # ugh!

    ffmpeg_path = config.get_bin('ffmpeg')
    fname = unicode(inFile, 'utf-8')
    oname = unicode(outFile, 'utf-8')
    if mswindows:
        fname = fname.encode('cp1252')
        oname = oname.encode('cp1252')

    acodec = select_audiocodec(False, inFile, tsn, 'video/mp4')
    settings = select_buffsize(tsn) + ['-c:v', 'copy'] + 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),
                 '-f', 'mp4']

    cmd = [ffmpeg_path, '-i', fname] + ' '.join(settings).split() + [oname]

    debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:')
    debug(' '.join(cmd))

    ffmpeg = subprocess.Popen(cmd)
    debug('remuxing ' + inFile + ' to ' + outFile)
    if ffmpeg.wait():
        debug('error during remuxing')
        os.remove(outFile)
        return None

    return newname
コード例 #26
0
ファイル: transcode.py プロジェクト: wynneth/pytivo
def audio_check(inFile, tsn):
    cmd_string = ('-y -vcodec mpeg2video -r 29.97 -b 1000k -acodec copy ' +
                  select_audiolang(inFile, tsn) + ' -t 00:00:01 -f vob -')
    fname = unicode(inFile, 'utf-8')
    if mswindows:
        fname = fname.encode('iso8859-1')
    cmd = [config.get_bin('ffmpeg'), '-i', fname] + cmd_string.split()
    ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    fd, testname = tempfile.mkstemp()
    testfile = os.fdopen(fd, 'wb')
    try:
        shutil.copyfileobj(ffmpeg.stdout, testfile)
    except:
        kill(ffmpeg)
        testfile.close()
        vInfo = None
    else:
        testfile.close()
        vInfo = video_info(testname, False)
    os.remove(testname)
    return vInfo
コード例 #27
0
ファイル: transcode.py プロジェクト: hmblprogrammer/pytivo
def audio_check(inFile, tsn):
    cmd_string = ('-y -c:v mpeg2video -r 29.97 -b:v 1000k -c:a copy ' +
                  select_audiolang(inFile, tsn) + ' -t 00:00:01 -f vob -')
    fname = unicode(inFile, 'utf-8')
    if mswindows:
        fname = fname.encode('cp1252')
    cmd = [config.get_bin('ffmpeg'), '-i', fname] + cmd_string.split()
    ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    fd, testname = tempfile.mkstemp()
    testfile = os.fdopen(fd, 'wb')
    try:
        shutil.copyfileobj(ffmpeg.stdout, testfile)
    except:
        kill(ffmpeg)
        testfile.close()
        vInfo = None
    else:
        testfile.close()
        vInfo = video_info(testname, False)
    os.remove(testname)
    return vInfo
コード例 #28
0
ファイル: transcode.py プロジェクト: wmcbrine/pytivo
def audio_check(inFile, tsn):
    cmd_string = (
        "-y -c:v mpeg2video -r 29.97 -b:v 1000k -c:a copy " + select_audiolang(inFile, tsn) + " -t 00:00:01 -f vob -"
    )
    fname = unicode(inFile, "utf-8")
    if mswindows:
        fname = fname.encode("cp1252")
    cmd = [config.get_bin("ffmpeg"), "-i", fname] + cmd_string.split()
    ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    fd, testname = tempfile.mkstemp()
    testfile = os.fdopen(fd, "wb")
    try:
        shutil.copyfileobj(ffmpeg.stdout, testfile)
    except:
        kill(ffmpeg)
        testfile.close()
        vInfo = None
    else:
        testfile.close()
        vInfo = video_info(testname, False)
    os.remove(testname)
    return vInfo
コード例 #29
0
ファイル: transcode.py プロジェクト: william40/pytivo
def mp4_remux(inFile, basename):
    outFile = inFile + '.pyTivo-temp'
    newname = basename + '.pyTivo-temp'
    if os.path.exists(outFile):
        return None  # ugh!

    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')

    cmd = [ffmpeg_path, '-i', fname, '-vcodec', 'copy', '-acodec',
           'copy', '-f', 'mp4', oname]
    ffmpeg = subprocess.Popen(cmd)
    debug('remuxing ' + inFile + ' to ' + outFile)
    if ffmpeg.wait():
        debug('error during remuxing')
        os.remove(outFile)
        return None

    return newname
コード例 #30
0
ファイル: transcode.py プロジェクト: mlippert/pytivo
def audio_check(inFile, tsn):
    """
    Get the video_info for a test transcode of the desired audio stream
    by transcoding one second of the source file and extracting its info.
    """

    # create an empty temporary file to be written to by ffmpeg
    fd, testname = tempfile.mkstemp()
    os.close(fd)

    cmd = [config.get_bin('ffmpeg'), '-hide_banner', '-nostdin',
           '-i', inFile,
           '-y',
           '-c:v', 'mpeg2video',
           '-r', '29.97',
           '-b:v', '1000k',
           '-c:a', 'copy'
          ] + \
          select_audiolang(inFile, tsn).split() + \
          ['-t', '00:00:01',
           '-f', 'vob',
           testname
          ]

    try:
        ffmpeg = subprocess.run(cmd, timeout=10,
                                stderr=subprocess.PIPE,
                                encoding=locale.getpreferredencoding(),
                                errors='replace')
    except subprocess.TimeoutExpired:
        debug('audio_check: ffmpeg timed out.\nffmpeg reported: {}'.format(ffmpeg.stderr))
        vInfo = None
    else:
        vInfo = video_info(testname, False)

    os.remove(testname)
    return vInfo
コード例 #31
0
ファイル: transcode.py プロジェクト: lordsutch/pytivo
def detect_h264_level(fname, vstream=0):
    ffprobe_path = config.get_bin('ffprobe')
    if not ffprobe_path:
        return 0

    cmd = [ffprobe_path, '-of', 'flat', '-show_streams', '-i', fname]
    # Windows and other OS buffer 4096 and ffprobe can output more than that.
    out_tmp = tempfile.TemporaryFile()
    ffprobe = subprocess.Popen(cmd,
                               stdout=out_tmp,
                               stderr=subprocess.PIPE,
                               stdin=subprocess.PIPE)

    # wait configured # of seconds: if ffprobe is not back give up
    limit = config.getFFmpegWait()
    if limit:
        for i in xrange(limit * 20):
            time.sleep(.05)
            if not ffprobe.poll() == None:
                break

        if ffprobe.poll() == None:
            kill(ffprobe)
            return 0
    else:
        ffprobe.wait()

    out_tmp.seek(0)
    output = out_tmp.read()
    out_tmp.close()
    debug('ffprobe output=%s' % repr(output))

    match = re.search(r'streams\.stream\.\d+\.level=(\d+)', output)
    if match:
        return int(match.group(1))
    return 0
コード例 #32
0
ファイル: transcode.py プロジェクト: mburnsz/pytivo
def mp4_remux(inFile, basename, tsn=''):
    outFile = inFile + '.pyTivo-temp'
    newname = basename + '.pyTivo-temp'
    if os.path.exists(outFile):
        return None  # ugh!

    ffmpeg_path = config.get_bin('ffmpeg')
    fname = unicode(inFile, 'utf-8')
    oname = unicode(outFile, 'utf-8')
    if mswindows:
        fname = fname.encode('cp1252')
        oname = oname.encode('cp1252')

    acodec = select_audiocodec(False, inFile, tsn, 'video/mp4')
    settings = select_buffsize(tsn) + ['-c:v', 'copy'] + 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), '-f', 'mp4'
    ]

    cmd = [ffmpeg_path, '-i', fname] + ' '.join(settings).split() + [oname]

    debug('transcoding to tivo model ' + tsn[:3] + ' using ffmpeg command:')
    debug(' '.join(cmd))

    ffmpeg = subprocess.Popen(cmd)
    debug('remuxing ' + inFile + ' to ' + outFile)
    if ffmpeg.wait():
        debug('error during remuxing')
        os.remove(outFile)
        return None

    return newname
コード例 #33
0
ファイル: transcode.py プロジェクト: raghu1111/pytivo
def transcode(isQuery, inFile, outFile, tsn='', mime='', thead=''):
    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(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('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': []
    }
    if thead:
        ffmpeg_procs[inFile]['blocks'].append(thead)
    reap_process(inFile)
    return resume_transfer(inFile, outFile, 0)
コード例 #34
0
    def get_image_ffmpeg(self, path, width, height, pshape, rot, attrs):
        ffmpeg_path = config.get_bin('ffmpeg')
        if not ffmpeg_path:
            return False, 'FFmpeg not found'

        fname = unicode(path, 'utf-8')
        if sys.platform == 'win32':
            fname = fname.encode('cp1252')

        if attrs and 'size' in attrs:
            result = attrs['size']
        else:
            status, result = self.get_size_ffmpeg(ffmpeg_path, fname)
            if not status:
                return False, result
            if attrs:
                attrs['size'] = result

        if rot in (90, 270):
            oldh, oldw = result
        else:
            oldw, oldh = result

        width, height = self.new_size(oldw, oldh, width, height, pshape)

        if rot == 270:
            filters = 'transpose=1,'
        elif rot == 180:
            filters = 'hflip,vflip,'
        elif rot == 90:
            filters = 'transpose=2,'
        else:
            filters = ''

        filters += 'format=yuvj420p,'

        neww, newh = oldw, oldh
        while (neww / width >= 50) or (newh / height >= 50):
            neww /= 2
            newh /= 2
            filters += 'scale=%d:%d,' % (neww, newh)

        filters += 'scale=%d:%d' % (width, height)

        cmd = [ffmpeg_path, '-i', fname, '-vf', filters, '-f', 'mjpeg', '-']
        jpeg_tmp = tempfile.TemporaryFile()
        ffmpeg = subprocess.Popen(cmd, stdout=jpeg_tmp,
                                  stdin=subprocess.PIPE)

        # wait configured # of seconds: if ffmpeg is not back give up
        limit = config.getFFmpegWait()
        if limit:
            for i in xrange(limit * 20):
                time.sleep(.05)
                if not ffmpeg.poll() == None:
                    break

            if ffmpeg.poll() == None:
                kill(ffmpeg)
                return False, 'FFmpeg timed out'
        else:
            ffmpeg.wait()

        jpeg_tmp.seek(0)
        output = jpeg_tmp.read()
        jpeg_tmp.close()

        if 'JFIF' not in output[:10]:
            output = output[:2] + JFIF_TAG + output[2:]

        return True, output
コード例 #35
0
ファイル: music.py プロジェクト: mlippert/pytivo
    def send_file(self, handler, path, query):
        logger.debug('send_file entered...')
        seek = int(query.get('Seek', [0])[0])
        duration = int(query.get('Duration', [0])[0])
        always = (handler.container.getboolean('force_ffmpeg') and
                  config.get_bin('ffmpeg'))
        fname = path

        ext = os.path.splitext(fname)[1].lower()
        needs_transcode = ext in TRANSCODE or seek or duration or always

        if not needs_transcode:
            fsize = os.path.getsize(fname)
            handler.send_response(200)
            handler.send_header('Content-Length', fsize)
        else:
            # use chunked transfer-encoding to send transcoded data as we get it
            # see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
            handler.send_response(206)
            handler.send_header('Transfer-Encoding', 'chunked')
        handler.send_header('Content-Type', 'audio/mpeg')
        handler.end_headers()

        if needs_transcode:
            cmd = [config.get_bin('ffmpeg'), '-hide_banner', '-nostdin', '-i', fname, '-vn']
            if ext in ['.mp3', '.mp2']:
                cmd += ['-acodec', 'copy']
            else:
                cmd += ['-ab', '320k', '-ar', '44100']
            cmd += ['-f', 'mp3', '-']
            if seek:
                cmd[-1:] = ['-ss', '%.3f' % (seek / 1000.0), '-']
            if duration:
                cmd[-1:] = ['-t', '%.3f' % (duration / 1000.0), '-']

            logger.debug('start process: {}'.format(cmd))
            ffmpeg = subprocess.Popen(cmd, bufsize=BLOCKSIZE,
                                      stdout=subprocess.PIPE)
            while True:
                try:
                    block = ffmpeg.stdout.read(BLOCKSIZE)
                    handler.wfile.write(b'%x\r\n' % len(block))
                    handler.wfile.write(block)
                    handler.wfile.write(b'\r\n')
                except Exception as msg:
                    handler.server.logger.info(msg)
                    kill(ffmpeg)
                    break

                if not block:
                    break
        else:
            f = open(fname, 'rb')
            try:
                shutil.copyfileobj(f, handler.wfile)
            except:
                pass
            f.close()

        try:
            handler.wfile.flush()
        except Exception as msg:
            handler.server.logger.info(msg)
コード例 #36
0
                ts_format = True
                handle = self.tivo_open(url + '&Format=video/x-tivo-mpeg-ts')
            else:
                handle = self.tivo_open(url)
        except Exception, msg:
            status[url]['running'] = False
            status[url]['error'] = str(msg)
            return

        tivo_name = config.tivos[config.tivos_by_ip(tivoIP)].get(
            'name', tivoIP)

        logger.info('[%s] Start getting "%s" from %s' %
                    (time.strftime('%d/%b/%Y %H:%M:%S'), outfile, tivo_name))

        has_tivodecode = bool(config.get_bin('tivodecode'))
        has_tivolibre = bool(config.get_bin('tivolibre'))
        decode = status[url]['decode'] and (has_tivodecode or has_tivolibre)
        if decode:
            fname = outfile
            if mswindows:
                fname = fname.encode('cp1252')

            decoder_path = config.get_bin('tivodecode')
            tcmd = [decoder_path, '-m', mak, '-o', fname, '-']
            if has_tivolibre:
                decoder_path = config.get_bin('tivolibre')
                tcmd = [decoder_path, '-m', mak, '-o', fname]

            tivodecode = subprocess.Popen(tcmd,
                                          stdin=subprocess.PIPE,
コード例 #37
0
ファイル: video.py プロジェクト: thspencer/pyTivo-Taylor
    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)
コード例 #38
0
ファイル: photo.py プロジェクト: WeekdayFiller/pytivo
    def get_image_ffmpeg(self, path, width, height, pshape, rot, attrs):
        ffmpeg_path = config.get_bin('ffmpeg')
        if not ffmpeg_path:
            return False, 'FFmpeg not found'

        fname = unicode(path, 'utf-8')
        if sys.platform == 'win32':
            fname = fname.encode('iso8859-1')

        if attrs and 'size' in attrs:
            result = attrs['size']
        else:
            status, result = self.get_size_ffmpeg(ffmpeg_path, fname)
            if not status:
                return False, result
            if attrs:
                attrs['size'] = result

        if rot in (90, 270):
            oldh, oldw = result
        else:
            oldw, oldh = result

        width, height = self.new_size(oldw, oldh, width, height, pshape)

        if rot == 270:
            filters = 'transpose=1,'
        elif rot == 180:
            filters = 'hflip,vflip,'
        elif rot == 90:
            filters = 'transpose=2,'
        else:
            filters = ''

        filters += 'format=yuvj420p,'

        neww, newh = oldw, oldh
        while (neww / width >= 50) or (newh / height >= 50):
            neww /= 2
            newh /= 2
            filters += 'scale=%d:%d,' % (neww, newh)

        filters += 'scale=%d:%d' % (width, height)

        cmd = [ffmpeg_path, '-i', fname, '-vf', filters, '-f', 'mjpeg', '-']
        jpeg_tmp = tempfile.TemporaryFile()
        ffmpeg = subprocess.Popen(cmd, stdout=jpeg_tmp,
                                  stdin=subprocess.PIPE)

        # wait configured # of seconds: if ffmpeg is not back give up
        limit = config.getFFmpegWait()
        if limit:
            for i in xrange(limit * 20):
                time.sleep(.05)
                if not ffmpeg.poll() == None:
                    break

            if ffmpeg.poll() == None:
                kill(ffmpeg)
                return False, 'FFmpeg timed out'
        else:
            ffmpeg.wait()

        jpeg_tmp.seek(0)
        output = jpeg_tmp.read()
        jpeg_tmp.close()

        if 'JFIF' not in output[:10]:
            output = output[:2] + JFIF_TAG + output[2:]

        return True, output
コード例 #39
0
ファイル: togo.py プロジェクト: wynneth/pytivo
    def NPL(self, handler, query):

        def getint(thing):
            try:
                result = int(thing)
            except:
                result = 0
            return result

        global basic_meta
        shows_per_page = 50 # Change this to alter the number of shows returned
        folder = ''
        FirstAnchor = ''
        has_tivodecode = bool(config.get_bin('tivodecode'))
        useragent = handler.headers.getheader('User-Agent', '')

        if 'TiVo' in query:
            tivoIP = query['TiVo'][0]
            tsn = config.tivos_by_ip(tivoIP)
            tivo_name = config.tivo_names[tsn]
            tivo_mak = config.get_tsn('tivo_mak', tsn)
            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, 'TiVoContainer/Details/TotalItems')
            ItemStart = tag_data(xmldoc, 'TiVoContainer/ItemStart')
            ItemCount = tag_data(xmldoc, 'TiVoContainer/ItemCount')
            title = tag_data(xmldoc, 'TiVoContainer/Details/Title')
            if items:
                FirstAnchor = tag_data(items[0], 'Links/Content/Url')

            data = []
            for item in items:
                entry = {}
                entry['ContentType'] = tag_data(item, 'Details/ContentType')
                for tag in ('CopyProtected', 'UniqueId'):
                    value = tag_data(item, 'Details/' + tag)
                    if value:
                        entry[tag] = value
                if entry['ContentType'] == 'x-tivo-container/folder':
                    entry['Title'] = tag_data(item, 'Details/Title')
                    entry['TotalItems'] = tag_data(item, 'Details/TotalItems')
                    lc = tag_data(item, 'Details/LastCaptureDate')
                    if not lc:
                        lc = tag_data(item, 'Details/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

                    rawsize = entry['SourceSize']
                    entry['SourceSize'] = metadata.human_size(rawsize)

                    dur = getint(entry['Duration']) / 1000
                    entry['Duration'] = ( '%d:%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)
コード例 #40
0
ファイル: togo.py プロジェクト: wynneth/pytivo
            status[url]['error'] = e.code
            logger.error(e.code)
            return
        except urllib2.URLError, e:
            status[url]['running'] = False
            status[url]['error'] = e.reason
            logger.error(e.reason)
            return

        tivo_name = config.tivo_names[config.tivos_by_ip(tivoIP)]

        logger.info('[%s] Start getting "%s" from %s' %
                    (time.strftime('%d/%b/%Y %H:%M:%S'), outfile, tivo_name))

        if status[url]['decode']:
            tivodecode_path = config.get_bin('tivodecode')
            tcmd = [tivodecode_path, '-m', mak, '-o', outfile, '-']
            tivodecode = subprocess.Popen(tcmd, stdin=subprocess.PIPE,
                                          bufsize=(512 * 1024))
            f = tivodecode.stdin
        else:
            f = open(outfile, 'wb')
        length = 0
        start_time = time.time()
        last_interval = start_time
        now = start_time
        try:
            while status[url]['running']:
                output = handle.read(1024000)
                if not output:
                    break
コード例 #41
0
ファイル: video.py プロジェクト: ofBits/pytivo
EXTENSIONS = """.tivo .mpg .avi .wmv .mov .flv .f4v .vob .mp4 .m4v .mkv
.ts .tp .trp .3g2 .3gp .3gp2 .3gpp .amv .asf .avs .bik .bix .box .bsf
.dat .dif .divx .dmb .dpg .dv .dvr-ms .evo .eye .flc .fli .flx .gvi .ivf
.m1v .m21 .m2t .m2ts .m2v .m2p .m4e .mjp .mjpeg .mod .moov .movie .mp21
.mpe .mpeg .mpv .mpv2 .mqv .mts .mvb .nsv .nuv .nut .ogm .qt .rm .rmvb
.rts .scm .smv .ssm .svi .vdo .vfw .vid .viv .vivo .vp6 .vp7 .vro .webm
.wm .wmd .wtv .yuv""".split()

LIKELYTS = """.ts .tp .trp .3g2 .3gp .3gp2 .3gpp .m2t .m2ts .mts .mp4
.m4v .flv .mkv .mov .wtv .dvr-ms .webm""".split()

status = {}  # Global variable to track uploads

use_extensions = True
try:
    assert (config.get_bin('ffmpeg'))
except:
    use_extensions = False


def uniso(iso):
    return time.strptime(iso[:19], '%Y-%m-%dT%H:%M:%S')


def isodt(iso):
    return datetime(*uniso(iso)[:6])


def isogm(iso):
    return int(calendar.timegm(uniso(iso)))
コード例 #42
0
ファイル: transcode.py プロジェクト: hmblprogrammer/pytivo
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)
コード例 #43
0
ファイル: transcode.py プロジェクト: hmblprogrammer/pytivo
def video_info(inFile, cache=True):
    vInfo = dict()
    fname = unicode(inFile, 'utf-8')
    mtime = os.path.getmtime(fname)
    if cache:
        if inFile in info_cache and info_cache[inFile][0] == mtime:
            debug('CACHE HIT! %s' % inFile)
            return info_cache[inFile][1]

    vInfo['Supported'] = True

    ffmpeg_path = config.get_bin('ffmpeg')
    if not ffmpeg_path:
        if os.path.splitext(inFile)[1].lower() not in [
                '.mpg', '.mpeg', '.vob', '.tivo', '.ts'
        ]:
            vInfo['Supported'] = False
        vInfo.update({
            'millisecs': 0,
            'vWidth': 704,
            'vHeight': 480,
            'rawmeta': {}
        })
        if cache:
            info_cache[inFile] = (mtime, vInfo)
        return vInfo

    if mswindows:
        fname = fname.encode('cp1252')
    cmd = [ffmpeg_path, '-i', fname]
    # Windows and other OS buffer 4096 and ffmpeg can output more than that.
    err_tmp = tempfile.TemporaryFile()
    ffmpeg = subprocess.Popen(cmd,
                              stderr=err_tmp,
                              stdout=subprocess.PIPE,
                              stdin=subprocess.PIPE)

    # wait configured # of seconds: if ffmpeg is not back give up
    limit = config.getFFmpegWait()
    if limit:
        for i in xrange(limit * 20):
            time.sleep(.05)
            if not ffmpeg.poll() == None:
                break

        if ffmpeg.poll() == None:
            kill(ffmpeg)
            vInfo['Supported'] = False
            if cache:
                info_cache[inFile] = (mtime, vInfo)
            return vInfo
    else:
        ffmpeg.wait()

    err_tmp.seek(0)
    output = err_tmp.read()
    err_tmp.close()
    debug('ffmpeg output=%s' % output)

    attrs = {
        'container': r'Input #0, ([^,]+),',
        'vCodec': r'Video: ([^, ]+)',  # video codec
        'aKbps': r'.*Audio: .+, (.+) (?:kb/s).*',  # audio bitrate
        'aCodec': r'.*Audio: ([^, ]+)',  # audio codec
        'aFreq': r'.*Audio: .+, (.+) (?:Hz).*',  # audio frequency
        'mapVideo': r'([0-9]+[.:]+[0-9]+).*: Video:.*'
    }  # video mapping

    for attr in attrs:
        rezre = re.compile(attrs[attr])
        x = rezre.search(output)
        if x:
            vInfo[attr] = x.group(1)
        else:
            if attr in ['container', 'vCodec']:
                vInfo[attr] = ''
                vInfo['Supported'] = False
            else:
                vInfo[attr] = None
            debug('failed at ' + attr)

    rezre = re.compile(
        r'.*Audio: .+, (?:(\d+)(?:(?:\.(\d).*)?(?: channels.*)?)|(stereo|mono)),.*'
    )
    x = rezre.search(output)
    if x:
        if x.group(3):
            if x.group(3) == 'stereo':
                vInfo['aCh'] = 2
            elif x.group(3) == 'mono':
                vInfo['aCh'] = 1
        elif x.group(2):
            vInfo['aCh'] = int(x.group(1)) + int(x.group(2))
        elif x.group(1):
            vInfo['aCh'] = int(x.group(1))
        else:
            vInfo['aCh'] = None
            debug('failed at aCh')
    else:
        vInfo['aCh'] = None
        debug('failed at aCh')

    rezre = re.compile(r'.*Video: .+, (\d+)x(\d+)[, ].*')
    x = rezre.search(output)
    if x:
        vInfo['vWidth'] = int(x.group(1))
        vInfo['vHeight'] = int(x.group(2))
    else:
        vInfo['vWidth'] = ''
        vInfo['vHeight'] = ''
        vInfo['Supported'] = False
        debug('failed at vWidth/vHeight')

    rezre = re.compile(r'.*Video: .+, (.+) (?:fps|tb\(r\)|tbr).*')
    x = rezre.search(output)
    if x:
        vInfo['vFps'] = x.group(1)
        if '.' not in vInfo['vFps']:
            vInfo['vFps'] += '.00'

        # Allow override only if it is mpeg2 and frame rate was doubled
        # to 59.94

        if vInfo['vCodec'] == 'mpeg2video' and vInfo['vFps'] != '29.97':
            # First look for the build 7215 version
            rezre = re.compile(r'.*film source: 29.97.*')
            x = rezre.search(output.lower())
            if x:
                debug('film source: 29.97 setting vFps to 29.97')
                vInfo['vFps'] = '29.97'
            else:
                # for build 8047:
                rezre = re.compile(r'.*frame rate differs from container ' +
                                   r'frame rate: 29.97.*')
                debug('Bug in VideoReDo')
                x = rezre.search(output.lower())
                if x:
                    vInfo['vFps'] = '29.97'
    else:
        vInfo['vFps'] = ''
        vInfo['Supported'] = False
        debug('failed at vFps')

    durre = re.compile(r'.*Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+),')
    d = durre.search(output)

    if d:
        vInfo['millisecs'] = (
            (int(d.group(1)) * 3600 + int(d.group(2)) * 60 + int(d.group(3))) *
            1000 + int(d.group(4)) * (10**(3 - len(d.group(4)))))
    else:
        vInfo['millisecs'] = 0

    # get bitrate of source for tivo compatibility test.
    rezre = re.compile(r'.*bitrate: (.+) (?:kb/s).*')
    x = rezre.search(output)
    if x:
        vInfo['kbps'] = x.group(1)
    else:
        # Fallback method of getting video bitrate
        # Sample line:  Stream #0.0[0x1e0]: Video: mpeg2video, yuv420p,
        #               720x480 [PAR 32:27 DAR 16:9], 9800 kb/s, 59.94 tb(r)
        rezre = re.compile(r'.*Stream #0\.0\[.*\]: Video: mpeg2video, ' +
                           r'\S+, \S+ \[.*\], (\d+) (?:kb/s).*')
        x = rezre.search(output)
        if x:
            vInfo['kbps'] = x.group(1)
        else:
            vInfo['kbps'] = None
            debug('failed at kbps')

    # get par.
    rezre = re.compile(r'.*Video: .+PAR ([0-9]+):([0-9]+) DAR [0-9:]+.*')
    x = rezre.search(output)
    if x and x.group(1) != "0" and x.group(2) != "0":
        vInfo['par1'] = x.group(1) + ':' + x.group(2)
        vInfo['par2'] = float(x.group(1)) / float(x.group(2))
    else:
        vInfo['par1'], vInfo['par2'] = None, None

    # get dar.
    rezre = re.compile(r'.*Video: .+DAR ([0-9]+):([0-9]+).*')
    x = rezre.search(output)
    if x and x.group(1) != "0" and x.group(2) != "0":
        vInfo['dar1'] = x.group(1) + ':' + x.group(2)
    else:
        vInfo['dar1'] = None

    # get Audio Stream mapping.
    rezre = re.compile(r'([0-9]+[.:]+[0-9]+)(.*): Audio:(.*)')
    x = rezre.search(output)
    amap = []
    if x:
        for x in rezre.finditer(output):
            amap.append((x.group(1), x.group(2) + x.group(3)))
    else:
        amap.append(('', ''))
        debug('failed at mapAudio')
    vInfo['mapAudio'] = amap

    vInfo['par'] = None

    # get Metadata dump (newer ffmpeg).
    lines = output.split('\n')
    rawmeta = {}
    flag = False

    for line in lines:
        if line.startswith('  Metadata:'):
            flag = True
        else:
            if flag:
                if line.startswith('  Duration:'):
                    flag = False
                else:
                    try:
                        key, value = [x.strip() for x in line.split(':', 1)]
                        try:
                            value = value.decode('utf-8')
                        except:
                            if sys.platform == 'darwin':
                                value = value.decode('macroman')
                            else:
                                value = value.decode('cp1252')
                        rawmeta[key] = [value]
                    except:
                        pass

    vInfo['rawmeta'] = rawmeta

    data = metadata.from_text(inFile)
    for key in data:
        if key.startswith('Override_'):
            vInfo['Supported'] = True
            if key.startswith('Override_mapAudio'):
                audiomap = dict(vInfo['mapAudio'])
                newmap = shlex.split(data[key])
                audiomap.update(zip(newmap[::2], newmap[1::2]))
                vInfo['mapAudio'] = sorted(audiomap.items(),
                                           key=lambda (k, v): (k, v))
            elif key.startswith('Override_millisecs'):
                vInfo[key.replace('Override_', '')] = int(data[key])
            else:
                vInfo[key.replace('Override_', '')] = data[key]

    if cache:
        info_cache[inFile] = (mtime, vInfo)
    debug("; ".join(["%s=%s" % (k, v) for k, v in vInfo.items()]))
    return vInfo
コード例 #44
0
    def NPL(self, handler, query):
        global basic_meta
        shows_per_page = 50  # Change this to alter the number of shows returned
        folder = ''
        has_tivodecode = bool(config.get_bin('tivodecode'))

        if 'TiVo' in query:
            tivoIP = query['TiVo'][0]
            tsn = config.tivos_by_ip(tivoIP)
            tivo_name = config.tivo_names[tsn]
            tivo_mak = config.get_tsn('tivo_mak', tsn)
            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)
コード例 #45
0
ファイル: music.py プロジェクト: akolster/pytivo
    def QueryContainer(self, handler, query):

        def AudioFileFilter(f, filter_type=None):
            ext = os.path.splitext(f)[1].lower()

            if ext in ('.mp3', '.mp2') or (ext in TRANSCODE and
                                           config.get_bin('ffmpeg')):
                return self.AUDIO
            else:
                file_type = False

                if not filter_type or filter_type.split('/')[0] != self.AUDIO:
                    if ext in PLAYLISTS:
                        file_type = self.PLAYLIST
                    elif os.path.isdir(f):
                        file_type = self.DIRECTORY

                return file_type

        def media_data(f):
            if f.name in self.media_data_cache:
                return self.media_data_cache[f.name]

            item = {}
            item['path'] = f.name
            item['part_path'] = f.name.replace(local_base_path, '', 1)
            item['name'] = os.path.basename(f.name)
            item['is_dir'] = f.isdir
            item['is_playlist'] = f.isplay
            item['params'] = 'No'

            if f.title:
                item['Title'] = f.title

            if f.duration > 0:
                item['Duration'] = f.duration

            if f.isdir or f.isplay or '://' in f.name:
                self.media_data_cache[f.name] = item
                return item

            # If the format is: (track #) Song name...
            #artist, album, track = f.name.split(os.path.sep)[-3:]
            #track = os.path.splitext(track)[0]
            #if track[0].isdigit:
            #    track = ' '.join(track.split(' ')[1:])

            #item['SongTitle'] = track
            #item['AlbumTitle'] = album
            #item['ArtistName'] = artist

            ext = os.path.splitext(f.name)[1].lower()
            fname = unicode(f.name, 'utf-8')

            try:
                # If the file is an mp3, let's load the EasyID3 interface
                if ext == '.mp3':
                    audioFile = MP3(fname, ID3=EasyID3)
                else:
                    # Otherwise, let mutagen figure it out
                    audioFile = mutagen.File(fname)

                if audioFile:
                    # Pull the length from the FileType, if present
                    if audioFile.info.length > 0:
                        item['Duration'] = int(audioFile.info.length * 1000)

                    # Grab our other tags, if present
                    def get_tag(tagname, d):
                        for tag in ([tagname] + TAGNAMES[tagname]):
                            try:
                                if tag in d:
                                    value = d[tag][0]
                                    if type(value) not in [str, unicode]:
                                        value = str(value)
                                    return value
                            except:
                                pass
                        return ''

                    artist = get_tag('artist', audioFile)
                    title = get_tag('title', audioFile)
                    if artist == 'Various Artists' and '/' in title:
                        artist, title = [x.strip() for x in title.split('/')]
                    item['ArtistName'] = artist
                    item['SongTitle'] = title
                    item['AlbumTitle'] = get_tag('album', audioFile)
                    item['AlbumYear'] = get_tag('date', audioFile)[:4]
                    item['MusicGenre'] = get_tag('genre', audioFile)
            except Exception, msg:
                print msg

            ffmpeg_path = config.get_bin('ffmpeg')
            if 'Duration' not in item and ffmpeg_path:
                if mswindows:
                    fname = fname.encode('iso8859-1')
                cmd = [ffmpeg_path, '-i', fname]
                ffmpeg = subprocess.Popen(cmd, stderr=subprocess.PIPE,
                                               stdout=subprocess.PIPE, 
                                               stdin=subprocess.PIPE)

                # wait 10 sec if ffmpeg is not back give up
                for i in xrange(200):
                    time.sleep(.05)
                    if not ffmpeg.poll() == None:
                        break

                if ffmpeg.poll() != None:
                    output = ffmpeg.stderr.read()
                    d = durre(output)
                    if d:
                        millisecs = ((int(d.group(1)) * 3600 +
                                      int(d.group(2)) * 60 +
                                      int(d.group(3))) * 1000 +
                                     int(d.group(4)) *
                                     (10 ** (3 - len(d.group(4)))))
                    else:
                        millisecs = 0
                    item['Duration'] = millisecs

            if 'Duration' in item and ffmpeg_path:
                item['params'] = 'Yes'

            self.media_data_cache[f.name] = item
            return item
コード例 #46
0
ファイル: transcode.py プロジェクト: wynneth/pytivo
def video_info(inFile, cache=True):
    vInfo = dict()
    fname = unicode(inFile, 'utf-8')
    mtime = os.stat(fname).st_mtime
    if cache:
        if inFile in info_cache and info_cache[inFile][0] == mtime:
            debug('CACHE HIT! %s' % inFile)
            return info_cache[inFile][1]

    vInfo['Supported'] = True

    ffmpeg_path = config.get_bin('ffmpeg')
    if not ffmpeg_path:
        if os.path.splitext(inFile)[1].lower() not in ['.mpg', '.mpeg',
                                                       '.vob', '.tivo']:
            vInfo['Supported'] = False
        vInfo.update({'millisecs': 0, 'vWidth': 704, 'vHeight': 480,
                      'rawmeta': {}})
        if cache:
            info_cache[inFile] = (mtime, vInfo)
        return vInfo

    if mswindows:
        fname = fname.encode('iso8859-1')
    cmd = [ffmpeg_path, '-i', fname]
    # Windows and other OS buffer 4096 and ffmpeg can output more than that.
    err_tmp = tempfile.TemporaryFile()
    ffmpeg = subprocess.Popen(cmd, stderr=err_tmp, stdout=subprocess.PIPE,
                              stdin=subprocess.PIPE)

    # wait configured # of seconds: if ffmpeg is not back give up
    limit = config.getFFmpegWait()
    if limit:
        for i in xrange(limit * 20):
            time.sleep(.05)
            if not ffmpeg.poll() == None:
                break

        if ffmpeg.poll() == None:
            kill(ffmpeg)
            vInfo['Supported'] = False
            if cache:
                info_cache[inFile] = (mtime, vInfo)
            return vInfo
    else:
        ffmpeg.wait()

    err_tmp.seek(0)
    output = err_tmp.read()
    err_tmp.close()
    debug('ffmpeg output=%s' % output)

    attrs = {'container': r'Input #0, ([^,]+),',
             'vCodec': r'Video: ([^, ]+)',             # video codec
             'aKbps': r'.*Audio: .+, (.+) (?:kb/s).*',     # audio bitrate
             'aCodec': r'.*Audio: ([^, ]+)',             # audio codec
             'aFreq': r'.*Audio: .+, (.+) (?:Hz).*',       # audio frequency
             'mapVideo': r'([0-9]+[.:]+[0-9]+).*: Video:.*'}  # video mapping

    for attr in attrs:
        rezre = re.compile(attrs[attr])
        x = rezre.search(output)
        if x:
            vInfo[attr] = x.group(1)
        else:
            if attr in ['container', 'vCodec']:
                vInfo[attr] = ''
                vInfo['Supported'] = False
            else:
                vInfo[attr] = None
            debug('failed at ' + attr)

    rezre = re.compile(r'.*Audio: .+, (?:(\d+)(?:(?:\.(\d).*)?(?: channels.*)?)|(stereo|mono)),.*')
    x = rezre.search(output)
    if x:
        if x.group(3):
            if x.group(3) == 'stereo':
                vInfo['aCh'] = 2
            elif x.group(3) == 'mono':
                vInfo['aCh'] = 1
        elif x.group(2):
            vInfo['aCh'] = int(x.group(1)) + int(x.group(2))
        elif x.group(1):
            vInfo['aCh'] = int(x.group(1))
        else:
            vInfo['aCh'] = None
            debug('failed at aCh')
    else:
        vInfo['aCh'] = None
        debug('failed at aCh')

    rezre = re.compile(r'.*Video: .+, (\d+)x(\d+)[, ].*')
    x = rezre.search(output)
    if x:
        vInfo['vWidth'] = int(x.group(1))
        vInfo['vHeight'] = int(x.group(2))
    else:
        vInfo['vWidth'] = ''
        vInfo['vHeight'] = ''
        vInfo['Supported'] = False
        debug('failed at vWidth/vHeight')

    rezre = re.compile(r'.*Video: .+, (.+) (?:fps|tb\(r\)|tbr).*')
    x = rezre.search(output)
    if x:
        vInfo['vFps'] = x.group(1)
        if '.' not in vInfo['vFps']:
            vInfo['vFps'] += '.00'

        # Allow override only if it is mpeg2 and frame rate was doubled
        # to 59.94

        if vInfo['vCodec'] == 'mpeg2video' and vInfo['vFps'] != '29.97':
            # First look for the build 7215 version
            rezre = re.compile(r'.*film source: 29.97.*')
            x = rezre.search(output.lower())
            if x:
                debug('film source: 29.97 setting vFps to 29.97')
                vInfo['vFps'] = '29.97'
            else:
                # for build 8047:
                rezre = re.compile(r'.*frame rate differs from container ' +
                                   r'frame rate: 29.97.*')
                debug('Bug in VideoReDo')
                x = rezre.search(output.lower())
                if x:
                    vInfo['vFps'] = '29.97'
    else:
        vInfo['vFps'] = ''
        vInfo['Supported'] = False
        debug('failed at vFps')

    durre = re.compile(r'.*Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+),')
    d = durre.search(output)

    if d:
        vInfo['millisecs'] = ((int(d.group(1)) * 3600 +
                               int(d.group(2)) * 60 +
                               int(d.group(3))) * 1000 +
                              int(d.group(4)) * (10 ** (3 - len(d.group(4)))))
    else:
        vInfo['millisecs'] = 0

    # get bitrate of source for tivo compatibility test.
    rezre = re.compile(r'.*bitrate: (.+) (?:kb/s).*')
    x = rezre.search(output)
    if x:
        vInfo['kbps'] = x.group(1)
    else:
        # Fallback method of getting video bitrate
        # Sample line:  Stream #0.0[0x1e0]: Video: mpeg2video, yuv420p,
        #               720x480 [PAR 32:27 DAR 16:9], 9800 kb/s, 59.94 tb(r)
        rezre = re.compile(r'.*Stream #0\.0\[.*\]: Video: mpeg2video, ' +
                           r'\S+, \S+ \[.*\], (\d+) (?:kb/s).*')
        x = rezre.search(output)
        if x:
            vInfo['kbps'] = x.group(1)
        else:
            vInfo['kbps'] = None
            debug('failed at kbps')

    # get par.
    rezre = re.compile(r'.*Video: .+PAR ([0-9]+):([0-9]+) DAR [0-9:]+.*')
    x = rezre.search(output)
    if x and x.group(1) != "0" and x.group(2) != "0":
        vInfo['par1'] = x.group(1) + ':' + x.group(2)
        vInfo['par2'] = float(x.group(1)) / float(x.group(2))
    else:
        vInfo['par1'], vInfo['par2'] = None, None

    # get dar.
    rezre = re.compile(r'.*Video: .+DAR ([0-9]+):([0-9]+).*')
    x = rezre.search(output)
    if x and x.group(1) != "0" and x.group(2) != "0":
        vInfo['dar1'] = x.group(1) + ':' + x.group(2)
    else:
        vInfo['dar1'] = None

    # get Audio Stream mapping.
    rezre = re.compile(r'([0-9]+[.:]+[0-9]+)(.*): Audio:(.*)')
    x = rezre.search(output)
    amap = []
    if x:
        for x in rezre.finditer(output):
            amap.append((x.group(1), x.group(2) + x.group(3)))
    else:
        amap.append(('', ''))
        debug('failed at mapAudio')
    vInfo['mapAudio'] = amap

    vInfo['par'] = None

    # get Metadata dump (newer ffmpeg).
    lines = output.split('\n')
    rawmeta = {}
    flag = False

    for line in lines:
        if line.startswith('  Metadata:'):
            flag = True
        else:
            if flag:
                if line.startswith('  Duration:'):
                    flag = False
                else:
                    try:
                        key, value = [x.strip() for x in line.split(':', 1)]
                        try:
                            value = value.decode('utf-8')
                        except:
                            if sys.platform == 'darwin':
                                value = value.decode('macroman')
                            else:
                                value = value.decode('iso8859-1')
                        rawmeta[key] = [value]
                    except:
                        pass

    vInfo['rawmeta'] = rawmeta

    data = metadata.from_text(inFile)
    for key in data:
        if key.startswith('Override_'):
            vInfo['Supported'] = True
            if key.startswith('Override_mapAudio'):
                audiomap = dict(vInfo['mapAudio'])
                newmap = shlex.split(data[key])
                audiomap.update(zip(newmap[::2], newmap[1::2]))
                vInfo['mapAudio'] = sorted(audiomap.items(),
                                           key=lambda (k,v): (k,v))
            elif key.startswith('Override_millisecs'):
                vInfo[key.replace('Override_', '')] = int(data[key])
            else:
                vInfo[key.replace('Override_', '')] = data[key]

    if cache:
        info_cache[inFile] = (mtime, vInfo)
    debug("; ".join(["%s=%s" % (k, v) for k, v in vInfo.items()]))
    return vInfo
コード例 #47
0
    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 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)
コード例 #48
0
ファイル: video.py プロジェクト: thspencer/pyTivo-Taylor
HTML_CONTAINER_TEMPLATE_MOBILE = tmpl('container_mob.tmpl')
HTML_CONTAINER_TEMPLATE = tmpl('container_html.tmpl')
XML_CONTAINER_TEMPLATE = tmpl('container_xml.tmpl')
TVBUS_TEMPLATE = tmpl('TvBus.tmpl')

EXTENSIONS = """.tivo .mpg .avi .wmv .mov .flv .f4v .vob .mp4 .m4v .mkv
.ts .tp .trp .3g2 .3gp .3gp2 .3gpp .amv .asf .avs .bik .bix .box .bsf
.dat .dif .divx .dmb .dpg .dv .dvr-ms .evo .eye .flc .fli .flx .gvi .ivf
.m1v .m21 .m2t .m2ts .m2v .m2p .m4e .mjp .mjpeg .mod .moov .movie .mp21
.mpe .mpeg .mpv .mpv2 .mqv .mts .mvb .nsv .nuv .nut .ogm .qt .rm .rmvb
.rts .scm .smv .ssm .svi .vdo .vfw .vid .viv .vivo .vp6 .vp7 .vro .webm
.wm .wmd .wtv .yuv""".split()

use_extensions = True
try:
    assert(config.get_bin('ffmpeg'))
except:
    use_extensions = False

queue = []  # Recordings to push

def uniso(iso):
    return time.strptime(iso[:19], '%Y-%m-%dT%H:%M:%S')

def isodt(iso):
    return datetime(*uniso(iso)[:6])

def isogm(iso):
    return int(calendar.timegm(uniso(iso)))

class Pushable(object):
コード例 #49
0
HTML_CONTAINER_TEMPLATE = tmpl('container_html.tmpl')
XML_CONTAINER_TEMPLATE = tmpl('container_xml.tmpl')
TVBUS_TEMPLATE = tmpl('TvBus.tmpl')

EXTENSIONS = """.tivo .mpg .avi .wmv .mov .flv .f4v .vob .mp4 .m4v .mkv
.ts .tp .trp .3g2 .3gp .3gp2 .3gpp .amv .asf .avs .bik .bix .box .bsf
.dat .dif .divx .dmb .dpg .dv .dvr-ms .evo .eye .flc .fli .flx .gvi .ivf
.m1v .m21 .m2t .m2ts .m2v .m2p .m4e .mjp .mjpeg .mod .moov .movie .mp21
.mpe .mpeg .mpv .mpv2 .mqv .mts .mvb .nsv .nuv .nut .ogm .qt .rm .rmvb
.rts .scm .smv .ssm .svi .vdo .vfw .vid .viv .vivo .vp6 .vp7 .vro .webm
.wm .wmd .wtv .yuv""".split()

use_extensions = True
try:
    assert (config.get_bin('ffmpeg'))
except:
    use_extensions = False

queue = []  # Recordings to push


def uniso(iso):
    return time.strptime(iso[:19], '%Y-%m-%dT%H:%M:%S')


def isodt(iso):
    return datetime(*uniso(iso)[:6])


def isogm(iso):
コード例 #50
0
    def QueryContainer(self, handler, query):
        def AudioFileFilter(f, filter_type=None):
            ext = os.path.splitext(f)[1].lower()

            if ext in ('.mp3', '.mp2') or (ext in TRANSCODE
                                           and config.get_bin('ffmpeg')):
                return self.AUDIO
            else:
                file_type = False

                if not filter_type or filter_type.split('/')[0] != self.AUDIO:
                    if ext in PLAYLISTS:
                        file_type = self.PLAYLIST
                    elif os.path.isdir(f):
                        file_type = self.DIRECTORY

                return file_type

        def media_data(f):
            if f.name in self.media_data_cache:
                return self.media_data_cache[f.name]

            item = {}
            item['path'] = f.name
            item['part_path'] = f.name.replace(local_base_path, '', 1)
            item['name'] = os.path.basename(f.name)
            item['is_dir'] = f.isdir
            item['is_playlist'] = f.isplay
            item['params'] = 'No'

            if f.title:
                item['Title'] = f.title

            if f.duration > 0:
                item['Duration'] = f.duration

            if f.isdir or f.isplay or '://' in f.name:
                self.media_data_cache[f.name] = item
                return item

            # If the format is: (track #) Song name...
            #artist, album, track = f.name.split(os.path.sep)[-3:]
            #track = os.path.splitext(track)[0]
            #if track[0].isdigit:
            #    track = ' '.join(track.split(' ')[1:])

            #item['SongTitle'] = track
            #item['AlbumTitle'] = album
            #item['ArtistName'] = artist

            ext = os.path.splitext(f.name)[1].lower()
            fname = unicode(f.name, 'utf-8')

            try:
                # If the file is an mp3, let's load the EasyID3 interface
                if ext == '.mp3':
                    audioFile = MP3(fname, ID3=EasyID3)
                else:
                    # Otherwise, let mutagen figure it out
                    audioFile = mutagen.File(fname)

                if audioFile:
                    # Pull the length from the FileType, if present
                    if audioFile.info.length > 0:
                        item['Duration'] = int(audioFile.info.length * 1000)

                    # Grab our other tags, if present
                    def get_tag(tagname, d):
                        for tag in ([tagname] + TAGNAMES[tagname]):
                            try:
                                if tag in d:
                                    value = d[tag][0]
                                    if type(value) not in [str, unicode]:
                                        value = str(value)
                                    return value
                            except:
                                pass
                        return ''

                    artist = get_tag('artist', audioFile)
                    title = get_tag('title', audioFile)
                    if artist == 'Various Artists' and '/' in title:
                        artist, title = [x.strip() for x in title.split('/')]
                    item['ArtistName'] = artist
                    item['SongTitle'] = title
                    item['AlbumTitle'] = get_tag('album', audioFile)
                    item['AlbumYear'] = get_tag('date', audioFile)[:4]
                    item['MusicGenre'] = get_tag('genre', audioFile)
            except Exception, msg:
                print msg

            ffmpeg_path = config.get_bin('ffmpeg')
            if 'Duration' not in item and ffmpeg_path:
                if mswindows:
                    fname = fname.encode('iso8859-1')
                cmd = [ffmpeg_path, '-i', fname]
                ffmpeg = subprocess.Popen(cmd,
                                          stderr=subprocess.PIPE,
                                          stdout=subprocess.PIPE,
                                          stdin=subprocess.PIPE)

                # wait 10 sec if ffmpeg is not back give up
                for i in xrange(200):
                    time.sleep(.05)
                    if not ffmpeg.poll() == None:
                        break

                if ffmpeg.poll() != None:
                    output = ffmpeg.stderr.read()
                    d = durre(output)
                    if d:
                        millisecs = (
                            (int(d.group(1)) * 3600 + int(d.group(2)) * 60 +
                             int(d.group(3))) * 1000 + int(d.group(4)) *
                            (10**(3 - len(d.group(4)))))
                    else:
                        millisecs = 0
                    item['Duration'] = millisecs

            if 'Duration' in item and ffmpeg_path:
                item['params'] = 'Yes'

            self.media_data_cache[f.name] = item
            return item
コード例 #51
0
ファイル: music.py プロジェクト: mlippert/pytivo
        def media_data(f):
            if f.name in self.media_data_cache:
                return self.media_data_cache[f.name]

            item = {}
            item['path'] = f.name
            item['part_path'] = f.name.replace(local_base_path, '', 1)
            item['name'] = os.path.basename(f.name)
            item['is_dir'] = f.isdir
            item['is_playlist'] = f.isplay
            item['params'] = 'No'

            if f.title:
                item['Title'] = f.title

            if f.duration > 0:
                item['Duration'] = f.duration

            if f.isdir or f.isplay or '://' in f.name:
                self.media_data_cache[f.name] = item
                return item

            # If the format is: (track #) Song name...
            #artist, album, track = f.name.split(os.path.sep)[-3:]
            #track = os.path.splitext(track)[0]
            #if track[0].isdigit:
            #    track = ' '.join(track.split(' ')[1:])

            #item['SongTitle'] = track
            #item['AlbumTitle'] = album
            #item['ArtistName'] = artist

            ext = os.path.splitext(f.name)[1].lower()
            fname = f.name

            try:
                # If the file is an mp3, let's load the EasyID3 interface
                if ext == '.mp3':
                    audioFile = MP3(fname, ID3=EasyID3)
                else:
                    # Otherwise, let mutagen figure it out
                    audioFile = mutagen.File(fname)

                if audioFile:
                    # Pull the length from the FileType, if present
                    if audioFile.info.length > 0:
                        item['Duration'] = int(audioFile.info.length * 1000)

                    # Grab our other tags, if present
                    def get_tag(tagname, d):
                        for tag in ([tagname] + TAGNAMES[tagname]):
                            try:
                                if tag in d:
                                    value = d[tag][0]
                                    if not isinstance(value, str):
                                        value = str(value)
                                    return value
                            except:
                                pass
                        return ''

                    artist = get_tag('artist', audioFile)
                    title = get_tag('title', audioFile)
                    if artist == 'Various Artists' and '/' in title:
                        artist, title = [x.strip() for x in title.split('/')]
                    item['ArtistName'] = artist
                    item['SongTitle'] = title
                    item['AlbumTitle'] = get_tag('album', audioFile)
                    item['AlbumYear'] = get_tag('date', audioFile)[:4]
                    item['MusicGenre'] = get_tag('genre', audioFile)
            except Exception as msg:
                logger.error(msg)

            ffmpeg_path = config.get_bin('ffmpeg')
            if 'Duration' not in item and ffmpeg_path:
                cmd = [ffmpeg_path, '-hide_banner', '-nostdin', '-i', fname]
                ffmpeg = subprocess.Popen(cmd, stderr=subprocess.PIPE,
                                               stdout=subprocess.PIPE)

                # wait 10 sec if ffmpeg is not back give up
                for i in range(200):
                    time.sleep(.05)
                    if not ffmpeg.poll() == None:
                        break

                if ffmpeg.poll() != None:
                    output = ffmpeg.stderr.read()
                    d = durre(output)
                    if d:
                        millisecs = ((int(d.group(1)) * 3600 +
                                      int(d.group(2)) * 60 +
                                      int(d.group(3))) * 1000 +
                                     int(d.group(4)) *
                                     (10 ** (3 - len(d.group(4)))))
                    else:
                        millisecs = 0
                    item['Duration'] = millisecs

            if 'Duration' in item and ffmpeg_path:
                item['params'] = 'Yes'

            self.media_data_cache[f.name] = item
            return item
コード例 #52
0
ファイル: togo.py プロジェクト: myeh/pytivo
        except Exception, msg:
            status[url]['running'] = False
            status[url]['error'] = str(msg)
            return

        tivo_name = config.tivos[config.tivos_by_ip(tivoIP)].get(
            'name', tivoIP)

        logger.info('[%s] Start getting "%s" from %s' %
                    (time.strftime('%d/%b/%Y %H:%M:%S'), outfile, tivo_name))

        if status[url]['decode']:
            fname = outfile
            if mswindows:
                fname = fname.encode('cp1252')
            tivodecode_path = config.get_bin('tivodecode')
            tcmd = [tivodecode_path, '-m', mak, '-o', fname, '-']
            tivodecode = subprocess.Popen(tcmd,
                                          stdin=subprocess.PIPE,
                                          bufsize=(512 * 1024))
            f = tivodecode.stdin
        else:
            f = open(outfile, 'wb')
        length = 0
        start_time = time.time()
        last_interval = start_time
        now = start_time
        try:
            while status[url]['running']:
                output = handle.read(1024000)
                if not output:
コード例 #53
0
ファイル: togo.py プロジェクト: myeh/pytivo
    def NPL(self, handler, query):
        def getint(thing):
            try:
                result = int(thing)
            except:
                result = 0
            return result

        global basic_meta
        global details_urls
        shows_per_page = 50  # Change this to alter the number of shows returned
        folder = ''
        FirstAnchor = ''
        has_tivodecode = bool(config.get_bin('tivodecode'))

        if 'TiVo' in query:
            tivoIP = query['TiVo'][0]
            tsn = config.tivos_by_ip(tivoIP)
            attrs = config.tivos[tsn]
            tivo_name = attrs.get('name', tivoIP)
            tivo_mak = config.get_tsn('tivo_mak', tsn)

            protocol = attrs.get('protocol', 'https')
            ip_port = '%s:%d' % (tivoIP, attrs.get('port', 443))
            path = attrs.get('path', DEFPATH)
            baseurl = '%s://%s%s' % (protocol, ip_port, path)
            theurl = baseurl
            if 'Folder' in query:
                folder = query['Folder'][0]
                theurl = urlparse.urljoin(theurl, folder)
            theurl += '&ItemCount=%d' % shows_per_page
            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', ip_port, 'tivo',
                                          tivo_mak)
                try:
                    page = self.tivo_open(theurl)
                except IOError, e:
                    handler.redir(UNABLE % (tivoIP, cgi.escape(str(e))), 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, 'TiVoContainer/Details/TotalItems')
            ItemStart = tag_data(xmldoc, 'TiVoContainer/ItemStart')
            ItemCount = tag_data(xmldoc, 'TiVoContainer/ItemCount')
            title = tag_data(xmldoc, 'TiVoContainer/Details/Title')
            if items:
                FirstAnchor = tag_data(items[0], 'Links/Content/Url')

            data = []
            for item in items:
                entry = {}
                for tag in ('CopyProtected', 'ContentType'):
                    value = tag_data(item, 'Details/' + tag)
                    if value:
                        entry[tag] = value
                if entry['ContentType'].startswith('x-tivo-container'):
                    entry['Url'] = tag_data(item, 'Links/Content/Url')
                    entry['Title'] = tag_data(item, 'Details/Title')
                    entry['TotalItems'] = tag_data(item, 'Details/TotalItems')
                    lc = tag_data(item, 'Details/LastCaptureDate')
                    if not lc:
                        lc = tag_data(item, 'Details/LastChangeDate')
                    entry['LastChangeDate'] = time.strftime(
                        '%b %d, %Y', time.localtime(int(lc, 16)))
                else:
                    keys = {
                        'Icon': 'Links/CustomIcon/Url',
                        'Url': 'Links/Content/Url',
                        'Details': 'Links/TiVoVideoDetails/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

                    if 'SourceSize' in entry:
                        rawsize = entry['SourceSize']
                        entry['SourceSize'] = metadata.human_size(rawsize)

                    if 'Duration' in entry:
                        dur = getint(entry['Duration']) / 1000
                        entry['Duration'] = ('%d:%02d:%02d' %
                                             (dur / 3600,
                                              (dur % 3600) / 60, dur % 60))

                    if 'CaptureDate' in entry:
                        entry['CaptureDate'] = time.strftime(
                            '%b %d, %Y',
                            time.localtime(int(entry['CaptureDate'], 16)))

                    url = urlparse.urljoin(baseurl, entry['Url'])
                    entry['Url'] = 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
                        if 'Details' in entry:
                            details_urls[url] = entry['Details']

                data.append(entry)