Add FFmpeg-based video integrity check

This commit is contained in:
2026-07-11 11:32:07 +02:00
parent 97a39709e8
commit 4c4180f28c
8 changed files with 422 additions and 4 deletions
+45 -1
View File
@@ -6,7 +6,8 @@ from .file import File
from .tag_manager import TagManager
from .pool_index import PoolIndex
from .utils import list_files
from typing import Iterable
from .integrity import check_video_integrity, ffmpeg_available, IntegrityResult
from typing import Callable, Iterable
from src.core.config import (
load_global_config, save_global_config, DEFAULT_TAG_SCHEMA
)
@@ -226,6 +227,49 @@ class FileManager:
"disk_count": len(disk_keys),
}
def scan_video_integrity(
self,
files: list[File],
deep: bool = True,
on_progress: Callable[[int, int, File], None] | None = None,
should_cancel: Callable[[], bool] | None = None,
) -> dict:
"""Check a list of movies for corrupted/unreadable video data.
Runs :func:`check_video_integrity` on each file (deep = full ffmpeg
decode, otherwise a quick ffprobe probe). ``on_progress(done, total,
file)`` is called after each file and ``should_cancel()`` is polled
before each — so a GUI can show progress and stop between files.
Returns a dict with:
ok — False if ffmpeg/ffprobe isn't available (with 'error')
problems — IntegrityResult list for files that failed (bad or
unable-to-check), in scan order
checked — how many files were actually processed
cancelled — True if the scan stopped early
"""
if not ffmpeg_available(deep):
tool = "ffmpeg" if deep else "ffprobe"
return {"ok": False, "error": f"{tool} není k dispozici (nainstaluj FFmpeg).",
"problems": [], "checked": 0, "cancelled": False}
problems: list[IntegrityResult] = []
total = len(files)
checked = 0
cancelled = False
for i, f in enumerate(files, 1):
if should_cancel is not None and should_cancel():
cancelled = True
break
result = check_video_integrity(f.file_path, deep=deep)
checked += 1
if not result.ok:
problems.append(result)
if on_progress is not None:
on_progress(i, total, f)
return {"ok": True, "problems": problems, "checked": checked,
"cancelled": cancelled}
def statistics(self) -> dict:
"""Aggregate stats over the loaded pool movies for the stats view.