从 FFProbe STDERR 打印字符串时输出错误
Mangled output when printing strings from FFProbe STDERR
我正在尝试制作一个简单的函数来环绕 FFProbe,并且可以正确检索大部分数据。
问题是当使用 Windows 命令提示符和 Git Bash for Windows 将字符串实际打印到命令行时,输出看起来很乱顺序。
一些歌曲(特别是文件 Imagine Dragons - Hit Parade_ Best of the Dance Music Charts - Beazz - Lime (Extended Mix).flac
)缺少元数据。我不知道为什么,但是 returns 下面的函数的字典是空的。
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
函数。无论我如何构建要打印的字符串、连接、逗号分隔参数等等,都没有关系。
我首先确定了歌曲的长度,其次是歌曲名称,但两者之间没有 space。由于某种原因,破折号挂在了尽头。根据之前代码中的打印语句,格式应该是 Title - 000
({title} - {length}
) 但输出看起来更像 000Title -
。为什么?
我通过 .
中接受的答案解决了这个问题
我忘记了每行末尾的 return 回车。给出的解决方案如下:
- 在子进程调用中使用
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)
这一切都非常有帮助,但是我使用了这些建议中的 none 个。
我不知道 FFPROBE 提供 JSON 到 STDOUT 的输出,但它确实提供了。执行此操作的代码如下。
#! /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 命令来说已经足够好了。它不是用来证明白痴的,它是在假设程序员不会破坏任何东西的情况下编写的,带有一些漏洞。
我正在尝试制作一个简单的函数来环绕 FFProbe,并且可以正确检索大部分数据。
问题是当使用 Windows 命令提示符和 Git Bash for Windows 将字符串实际打印到命令行时,输出看起来很乱顺序。
一些歌曲(特别是文件 Imagine Dragons - Hit Parade_ Best of the Dance Music Charts - Beazz - Lime (Extended Mix).flac
)缺少元数据。我不知道为什么,但是 returns 下面的函数的字典是空的。
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
函数。无论我如何构建要打印的字符串、连接、逗号分隔参数等等,都没有关系。
我首先确定了歌曲的长度,其次是歌曲名称,但两者之间没有 space。由于某种原因,破折号挂在了尽头。根据之前代码中的打印语句,格式应该是 Title - 000
({title} - {length}
) 但输出看起来更像 000Title -
。为什么?
我通过
我忘记了每行末尾的 return 回车。给出的解决方案如下:
- 在子进程调用中使用
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)
这一切都非常有帮助,但是我使用了这些建议中的 none 个。
我不知道 FFPROBE 提供 JSON 到 STDOUT 的输出,但它确实提供了。执行此操作的代码如下。
#! /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 命令来说已经足够好了。它不是用来证明白痴的,它是在假设程序员不会破坏任何东西的情况下编写的,带有一些漏洞。