从ffprobe stderr打印字符串时,将输出弄乱



我正在尝试制作一个简单的功能来包裹FFProbe ,并且大多数数据都可以正确检索。

问题是,使用Windows命令提示符和Windows的Git Bash实际将字符串实际打印到命令行时,输出出现乱和订单。

一些歌曲(特别是文件Imagine Dragons - Hit Parade_ Best of the Dance Music Charts80 - Beazz - Lime (Extended Mix).flac(缺少元数据。我不知道为什么,但是词典以下功能返回的函数为空。

ffprobe将其结果输出到stderr,可以将其输送到subprocess.PIPE,解码和解析。我选择了解析位的正则罚款。

这是下面我代码的纤细版本,因为输出查看GitHub Gist。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from glob import glob
from re import findall, MULTILINE
from subprocess import Popen, PIPE

def glob_from(path, ext):
    """Return glob from a directory."""
    working_dir = os.getcwd()
    os.chdir(path)
    file_paths = glob("**/*." + ext)
    os.chdir(working_dir)
    return file_paths

def media_metadata(file_path):
    """Use FFPROBE to get information about a media file."""
    stderr = Popen(("ffprobe", file_path), shell=True, stderr=PIPE).communicate()[1].decode()
    metadata = {}
    for match in findall(r"(w+)s+:s(.+)$", stderr, MULTILINE):
        metadata[match[0].lower()] = match[1]
    return metadata

if __name__ == "__main__":
    base = "C:/Users/spike/Music/Deezloader"
    for file in glob_from(base, "flac"):
        meta = media_metadata(os.path.join(base, file))
        title_length = meta.get("title", file) + " - " + meta.get("length", "000")
        print(title_length)

输出要点输出RAW

我不明白为什么只有在使用Python的print函数打印到控制台时,输出(有效地从正则表达式检索到弦乐(才会出现混乱。我如何构建字符串以打印,串联,逗号限制的参数,无论如何都无关紧要。

我最终以歌曲的长度和歌曲名称第二,但两者之间没有空间。由于某种原因,仪表板悬而未决。基于以前的代码中的打印语句,格式应为Title - 000({title} - {length}(,但输出看起来更像000Title -。为什么?

我通过我相关问题中接受的答案解决了这一点。

我忘记了每条线末端的返回马车。提供的解决方案如下:

  1. 在子过程呼叫中使用universal_newlines=True
    • stderr = Popen(("ffprobe", file_path), shell=True, stderr=PIPE, universal_newlines=True).communicate()[1]
  2. stderr剥离围绕线的空格。

    • *.communicate()[1].decode().rstrip()最终剥离所有空格。
    • *.communicate()[1].decode().strip()剥离所有Wightspace。
    • *.communicate()[1].decode()[:-2]删除最后两个字符。
  3. 吞咽 r在正则模式中。

    • findall(r"(w+)s+:s(.+)r$", stderr, MULTILINE)

这都非常有用,但是我没有使用这些建议。

我不知道FFProbe为Stdout提供JSON输出,但确实如此。代码下面的代码。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from json import loads
from subprocess import check_output, DEVNULL, PIPE

def arg_builder(args, kwargs, defaults={}):
    """Build arguments from `args` and `kwargs` in a shell-lexical manner."""
    for key, val in defaults.items():
        kwargs[key] = kwargs.get(key, val)
    args = list(args)
    for arg, val in kwargs.items():
        if isinstance(val, bool):
            if val:
                args.append("-" + arg)
        else:
            args.extend(("-" + arg, val))
    return args

def run_ffprobe(file_path, *args, **kwargs):
    """Use FFPROBE to get information about a media file."""
    return loads(check_output(("ffprobe", arg_builder(args, kwargs, defaults={"show_format": True}),
                               "-of", "json", file_path), shell=True, stderr=DEVNULL))

您可能还可以从arg_builder()中获得一些用途。它不是完美的,但对于简单的外壳命令来说已经足够了。这不是白痴的证据,它是用几个孔编写的,假设程序员不会破坏任何东西。

最新更新