Skip to content

Instantly share code, notes, and snippets.

@ichux
Created August 1, 2026 06:28
Show Gist options
  • Select an option

  • Save ichux/4f8e89d57d71de18166a538ce3a65636 to your computer and use it in GitHub Desktop.

Select an option

Save ichux/4f8e89d57d71de18166a538ce3a65636 to your computer and use it in GitHub Desktop.
import json
import subprocess
import sys
def get_metadata_ffprobe(file_path):
cmd = [
"ffprobe",
"-hide_banner",
"-v",
"error",
"-print_format",
"json",
"-show_streams",
"-show_format",
file_path,
]
proc = subprocess.run(cmd, capture_output=True, text=True)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or f"ffprobe failed on {file_path}")
return json.loads(proc.stdout)
def format_duration(seconds):
seconds = float(seconds)
h, rem = divmod(seconds, 3600)
m, s = divmod(rem, 60)
if h:
return f"{int(h)}h{int(m)}m{int(s)}s"
if m:
return f"{int(m)}m{int(s)}s"
return f"{int(s)}s"
def summarize(meta):
streams = meta.get("streams", [])
fmt = meta.get("format", {})
video = next((s for s in streams if s.get("codec_type") == "video"), None)
audio = next((s for s in streams if s.get("codec_type") == "audio"), None)
lines = []
duration = fmt.get("duration") or (video or {}).get("duration") or "?"
lines.append(f"file: {fmt.get('filename', '?')}")
lines.append(f"container: {fmt.get('format_name', '?')}")
lines.append(f"duration: {format_duration(duration)}")
if fmt.get("size"):
lines.append(f"size: {int(fmt['size']) / 1024 / 1024:.1f} MiB")
if fmt.get("bit_rate"):
lines.append(f"bit_rate: {int(fmt['bit_rate']) / 1000:.0f} kbps")
if video:
lines.append("")
lines.append("video:")
lines.append(f" codec: {video.get('codec_name')} ({video.get('profile', '?')})")
lines.append(f" size: {video.get('width')}x{video.get('height')}")
lines.append(f" fps: {video.get('avg_frame_rate')}")
if video.get("bit_rate"):
lines.append(f" bit_rate: {int(video['bit_rate']) / 1000:.0f} kbps")
if audio:
lines.append("")
lines.append("audio:")
lines.append(f" codec: {audio.get('codec_name')} ({audio.get('profile', '?')})")
lines.append(f" sample_rate: {audio.get('sample_rate')} Hz")
lines.append(f" channels: {audio.get('channels')} ({audio.get('channel_layout', '?')})")
if audio.get("bit_rate"):
lines.append(f" bit_rate: {int(audio['bit_rate']) / 1000:.0f} kbps")
if not video and not audio:
lines.append("")
lines.append("no video or audio streams found")
return "\n".join(lines)
if __name__ == "__main__":
as_json = "--json" in sys.argv
try:
file_path = next(a for a in sys.argv[1:] if not a.startswith("-"))
except StopIteration:
print("usage: python3 getmeta.py [--json] file.mp4")
sys.exit(1)
try:
meta = get_metadata_ffprobe(file_path)
except (FileNotFoundError, RuntimeError) as err:
print(f"error: {err}")
sys.exit(1)
if as_json:
print(json.dumps(meta, indent=2))
else:
print(summarize(meta))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment