This commit is contained in:
nose
2025-12-23 16:36:39 -08:00
parent 16316bb3fd
commit 8bf04c6b71
25 changed files with 3165 additions and 234 deletions

View File

@@ -3,7 +3,12 @@ from __future__ import annotations
import json
import hashlib
import ffmpeg
import subprocess
import shutil
try:
import ffmpeg # type: ignore
except Exception:
ffmpeg = None # type: ignore
import base64
import logging
import time
@@ -130,10 +135,45 @@ def create_tags_sidecar(file_path: Path, tags: set) -> None:
def ffprobe(file_path: str) -> dict:
probe = ffmpeg.probe(file_path)
metadata = {}
"""Probe a media file and return a metadata dictionary.
# Format-level info
This function prefers the python `ffmpeg` module (ffmpeg-python) when available.
If that is not present, it will attempt to call the external `ffprobe` binary if found
on PATH. If neither is available or probing fails, an empty dict is returned.
"""
probe = None
# Try python ffmpeg module first
if ffmpeg is not None:
try:
probe = ffmpeg.probe(file_path)
except Exception as exc: # pragma: no cover - environment dependent
_format_logger.debug("ffmpeg.probe failed: %s", exc)
probe = None
# Fall back to external ffprobe if available
if probe is None:
ffprobe_cmd = shutil.which("ffprobe")
if ffprobe_cmd:
try:
proc = subprocess.run(
[ffprobe_cmd, "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", str(file_path)],
check=True,
capture_output=True,
text=True,
)
probe = json.loads(proc.stdout)
except Exception as exc: # pragma: no cover - environment dependent
_format_logger.debug("External ffprobe failed: %s", exc)
probe = None
else:
_format_logger.debug("No ffmpeg Python module and no ffprobe binary found")
return {}
if not isinstance(probe, dict):
return {}
metadata = {}
fmt = probe.get("format", {})
metadata["duration"] = float(fmt.get("duration", 0)) if "duration" in fmt else None
metadata["size"] = int(fmt.get("size", 0)) if "size" in fmt else None