feat: cache failed ffprobe scans with scanner_version and exclude downloading items from scan queue to prevent incomplete metadata

Store failed ffprobe attempts in media_cache with scanner_version/audio_languages/subtitle_languages/external_subtitle_files/video_codec/size/error fields. Add comment explaining mtime-based invalidation triggers automatic retry. Filter out downloading items from radarr/sonarr/missing scan paths using not row.get("downloading") check to prevent scanning incomplete files
This commit is contained in:
2026-08-26 13:52:15 +02:00
parent de0d360a3c
commit 3fb2b34587
+16 -6
View File
@@ -913,8 +913,18 @@ def scan_one(path):
p = Path(path)
if not p.exists(): data = {"error": f"Datei nicht gefunden: {p}"}
else:
try: data = run_ffprobe(str(p)); log.info("Gescannt: %s", p)
except Exception as exc: data = {"error": str(exc)}; log.error("Scanfehler für %s: %s", p, error_summary(exc))
try:
data = run_ffprobe(str(p)); log.info("Gescannt: %s", p)
except Exception as exc:
# Cache failed probes as completed attempts. A changed mtime will
# invalidate this entry automatically and trigger a retry later.
data = {
"scanner_version": SCANNER_VERSION,
"audio_languages": [], "subtitle_languages": [],
"external_subtitle_files": [str(file) for file in external_subtitle_files(str(p))],
"video_codec": "", "size": 0, "error": error_summary(exc),
}
log.error("Scanfehler für %s: %s", p, error_summary(exc))
mtime = p.stat().st_mtime
con = db(); con.execute("INSERT INTO media_cache(path,mtime,data,scanned_at) VALUES(?,?,?,?) ON CONFLICT(path) DO UPDATE SET mtime=excluded.mtime,data=excluded.data,scanned_at=excluded.scanned_at", (str(p), mtime, json.dumps(data), datetime.utcnow().isoformat())); con.commit(); con.close()
return data
@@ -1005,16 +1015,16 @@ def start_scan(source, force=False, rows_snapshot=None, series_snapshot=None):
paths = []
if source == "radarr":
for row in rows_snapshot if rows_snapshot is not None else radarr_rows():
if row["local_path"] != "" and row["pending"]: paths.append(row["local_path"])
if row["local_path"] != "" and row["pending"] and not row.get("downloading"): paths.append(row["local_path"])
elif source == "sonarr":
for group in series_snapshot if series_snapshot is not None else sonarr_groups():
paths.extend(r["local_path"] for r in group["episodes"] if r["local_path"] != "" and r["pending"])
paths.extend(r["local_path"] for r in group["episodes"] if r["local_path"] != "" and r["pending"] and not r.get("downloading"))
else:
for row in rows_snapshot if rows_snapshot is not None else radarr_rows():
if row["local_path"] != "" and is_german_review_candidate(row) and not has_german_track(row): paths.append(row["local_path"])
if row["local_path"] != "" and is_german_review_candidate(row) and not row.get("downloading") and not has_german_track(row): paths.append(row["local_path"])
if SONARR_URL and SONARR_API_KEY:
for group in series_snapshot if series_snapshot is not None else sonarr_groups():
paths.extend(r["local_path"] for r in group["episodes"] if r["local_path"] != "" and is_german_review_candidate(r) and not has_german_track(r))
paths.extend(r["local_path"] for r in group["episodes"] if r["local_path"] != "" and is_german_review_candidate(r) and not r.get("downloading") and not has_german_track(r))
with job_lock: jobs[source]["total"] = len(paths)
futures = [scan_executor.submit(scan_one, path) for path in paths]
for future in as_completed(futures):