我正在尝试创建一个简单的函数来包装FFProbe ,并且可以正确检索大部分数据。
问题是当使用Windows命令提示符和Git Bash for Windows实际打印字符串到命令行时,输出会出现损坏且无序。
某些歌曲(特别是文件Imagine Dragons - Hit Parade_ Best of the Dance Music Charts\80 - 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)
我不明白为什么输出(可以有效地从正则表达式模式中检索字符串,但是打印时输出格式奇怪)只有在使用python的print
函数打印到控制台时才会出现混乱。无论我如何构建字符串以打印,连接,逗号分隔的参数,无论如何。
我最后以歌曲的长度结束,歌曲名称第二,但两者之间没有空格。由于某种原因,破折号悬而未决。基于之前代码中的print语句,格式应为Title - 000
({title} - {length}
),但输出看起来更像000Title -
。为什么呢?
答案 0 :(得分:0)
我通过related question中接受的答案解决了这个问题。
我忘记了每一行末尾的回程车。给出的解决方案如下:
universal_newlines=True
。
stderr = Popen(("ffprobe", file_path), shell=True, stderr=PIPE, universal_newlines=True).communicate()[1]
从stderr
剥离该行周围的空白。
*.communicate()[1].decode().rstrip()
在最后删除所有空格。*.communicate()[1].decode().strip()
剥离周围的所有空间。*.communicate()[1].decode()[:-2]
删除最后两个字符。以正则表达式模式吞咽\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()
。这不是完美的,但它对于简单的shell命令来说已经足够了。它没有被证明是白痴证明,它是用一些漏洞写的,假设程序员不会破坏任何东西。