mirror of
https://github.com/MrSleeps/jellyfin-scene-search.git
synced 2026-11-15 22:41:28 +00:00
43 lines
1.2 KiB
Python
43 lines
1.2 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
def require_ffmpeg() -> None:
|
|
missing = [name for name in ("ffmpeg", "ffprobe") if shutil.which(name) is None]
|
|
if missing:
|
|
raise RuntimeError(f"Missing required executable(s): {', '.join(missing)}")
|
|
|
|
|
|
def sha256_file(path: Path, chunk_size: int = 4 * 1024 * 1024) -> str:
|
|
digest = hashlib.sha256()
|
|
with path.open("rb") as fh:
|
|
while chunk := fh.read(chunk_size):
|
|
digest.update(chunk)
|
|
return digest.hexdigest()
|
|
|
|
|
|
def media_id_for(path: Path, content_sha256: str) -> str:
|
|
return hashlib.sha256(f"file:{content_sha256}".encode()).hexdigest()[:32]
|
|
|
|
|
|
def extract_frames(path: Path, out_dir: Path, interval_seconds: float) -> list[Path]:
|
|
require_ffmpeg()
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
for old in out_dir.glob("frame_*.jpg"):
|
|
old.unlink()
|
|
|
|
output = out_dir / "frame_%06d.jpg"
|
|
cmd = [
|
|
"ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
|
|
"-i", str(path),
|
|
"-vf", f"fps=1/{interval_seconds}",
|
|
"-q:v", "3",
|
|
str(output),
|
|
]
|
|
subprocess.run(cmd, check=True)
|
|
return sorted(out_dir.glob("frame_*.jpg"))
|