Skip to content

Instantly share code, notes, and snippets.

@hhsprings
Created March 26, 2021 13:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhsprings/3672d2ca575dd49d65cb3cf5d6b7f1ed to your computer and use it in GitHub Desktop.
Save hhsprings/3672d2ca575dd49d65cb3cf5d6b7f1ed to your computer and use it in GitHub Desktop.
nearly equals to "for i in * ; do ffpprobe -hide_banner $i ; done" with a few extra values
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import sys
import subprocess
if hasattr("", "decode"):
_encode = lambda s: s.encode(sys.getfilesystemencoding())
else:
_encode = lambda s: s
def _str(s):
return s.encode(sys.getfilesystemencoding(), errors="xmlcharrefreplace").decode(
sys.getfilesystemencoding())
def _filter_args(*cmd):
"""
do filtering None, and do encoding items to bytes
(in Python 2).
"""
return list(map(_encode, filter(None, *cmd)))
def check_call(*popenargs, **kwargs):
"""
Basically do simply forward args to subprocess#check_call, but this
does two things:
* It does encoding these to bytes in Python 2.
* It does omitting `None` in *cmd.
"""
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
subprocess.check_call(
_filter_args(cmd), **kwargs)
def check_stderroutput(*popenargs, **kwargs):
"""
Unfortunately, ffmpeg and ffprobe throw out the information
we want into the standard error output, and subprocess.check_output
discards the standard error output. This function is obtained by
rewriting subprocess.check_output for standard error output.
And this does two things:
* It does encoding these to bytes in Python 2.
* It does omitting `None` in *cmd.
"""
if 'stderr' in kwargs:
raise ValueError(
'stderr argument not allowed, it will be overridden.')
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
#
process = subprocess.Popen(
_filter_args(cmd),
stderr=subprocess.PIPE,
**kwargs)
stdout_output, stderr_output = process.communicate()
retcode = process.poll()
if retcode:
raise subprocess.CalledProcessError(
retcode, list(cmd), output=stderr_output)
return stderr_output
def _main():
import re
import argparse
ap = argparse.ArgumentParser(
description="""ex.)
globffprobe.py '*.*' --search=' hevc ' --extract 'Duration *: *[\d:.]+'""")
ap.add_argument("pattern", nargs="+")
ap.add_argument("--search")
ap.add_argument("--negate", action="store_true")
ap.add_argument("--extract")
args = ap.parse_args()
from glob import glob
_test = lambda s: not args.negate
_extract = lambda s: s
if args.search:
if not args.negate:
_test = lambda s: re.search(args.search, s)
else:
_test = lambda s: not re.search(args.search, s)
if args.extract:
def _extract(s):
m = re.search(args.extract, s)
if m:
return m.group(0)
return ""
for pat in args.pattern:
for ifn in glob(pat):
cmdl = ["ffprobe", "-hide_banner", ifn]
eout = check_stderroutput(cmdl).decode("utf-8")
if _test(eout):
print("$ " + _str(ifn) + " | " + _str(_extract(eout)))
if __name__ == '__main__':
_main()
@hhsprings
Copy link
Author

ffprobeを、特に Windows の MSYS から unicode だらけファイル名群相手に使おうとすると鬱陶しい、てことに対する一つの処方箋。ArgumentParser に与えている description 内に使用例を入れといたが、それだけでわかる? かと思うんだけど…どうだろか。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment