diff --git a/README.md b/README.md
index 710b659..7bb4346 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@ Die Container müssen im gemeinsamen Docker-Netzwerk `media-stack_default` errei
## Scans und Performance
-Scans laufen nach dem Laden der Bibliotheksdaten im Hintergrund. Über den Button „Neu scannen“ kann zwischen Radarr, Sonarr und allen Quellen gewählt werden. Die automatische Scan-Häufigkeit wird in den Einstellungen festgelegt.
+Scans laufen nach dem Laden der Bibliotheksdaten im Hintergrund. Über den Button „Neu scannen“ kann zwischen Radarr, Sonarr, allen Quellen und ausschließlich den aktuellen Einträgen der Liste „Ohne Deutsch“ gewählt werden. Die automatische Scan-Häufigkeit wird in den Einstellungen festgelegt.
```env
SCAN_WORKERS=4
diff --git a/app.py b/app.py
index e151b8b..f20a18a 100644
--- a/app.py
+++ b/app.py
@@ -75,7 +75,7 @@ def service_worker():
return response
executor = ThreadPoolExecutor(max_workers=int(os.environ.get("SCAN_WORKERS", "2")))
scan_executor = ThreadPoolExecutor(max_workers=int(os.environ.get("SCAN_WORKERS", "4")))
-jobs = {"radarr": {"state": "idle", "total": 0, "done": 0, "error": None}, "sonarr": {"state": "idle", "total": 0, "done": 0, "error": None}}
+jobs = {"radarr": {"state": "idle", "total": 0, "done": 0, "error": None}, "sonarr": {"state": "idle", "total": 0, "done": 0, "error": None}, "missing": {"state": "idle", "total": 0, "done": 0, "error": None}}
job_lock = threading.Lock()
system_lock = threading.Lock()
previous_cpu = None
@@ -828,9 +828,15 @@ def start_scan(source, force=False):
if source == "radarr":
for row in radarr_rows():
if row["local_path"] != "—" and row["pending"]: paths.append(row["local_path"])
- else:
+ elif source == "sonarr":
for group in sonarr_groups():
paths.extend(r["local_path"] for r in group["episodes"] if r["local_path"] != "—" and r["pending"])
+ else:
+ for row in radarr_rows():
+ if row["local_path"] != "—" and is_german_review_candidate(row) and not has_german_track(row): paths.append(row["local_path"])
+ if SONARR_URL and SONARR_API_KEY:
+ for group in 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))
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):
@@ -888,6 +894,8 @@ def api_rescan():
con = db()
if source in ("radarr", "all"): con.execute("DELETE FROM media_cache WHERE path NOT LIKE ?", (LOCAL_SERIES_PATH.rstrip("/") + "/%",))
if source in ("sonarr", "all"): con.execute("DELETE FROM media_cache WHERE path LIKE ?", (LOCAL_SERIES_PATH.rstrip("/") + "/%",))
+ # The missing-German scan deliberately keeps the cache: it re-processes
+ # only current candidates and leaves the rest of the library untouched.
con.commit(); con.close()
if source == "all":
start_scan("radarr", force=True)
diff --git a/templates/index.html b/templates/index.html
index a3d9115..4470dd0 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -61,7 +61,7 @@ if ('serviceWorker' in navigator) {
@media(max-width:700px){body{font-size:12px;padding-bottom:env(safe-area-inset-bottom)}header{height:auto;min-height:62px;padding:9px 12px;gap:9px;align-items:center}.brand-mark,.brand-mark svg{width:30px;height:30px}.brand-name{font-size:14px}.head-title{font-size:12px}.head-sub{font-size:10px}.actions{gap:4px}.actions button{height:34px;padding:0 8px}.settings-button{font-size:15px}.actions #rescan{font-size:0}.actions #rescan::after{content:'↻';font-size:16px}main{padding:10px 10px 24px}.nav{margin-bottom:10px;padding:4px;overflow-x:auto;scrollbar-width:none}.nav::-webkit-scrollbar{display:none}.nav button{flex:0 0 auto;white-space:nowrap;padding:8px 10px;font-size:11px}.toolbar{grid-template-columns:1fr;gap:7px;padding:8px}.toolbar input,.toolbar select{width:100%;height:38px}.stats{gap:6px}.stat{padding:6px 8px}.tablewrap{overflow-x:auto;border-radius:8px}table{min-width:860px}.dashboard-hero{margin-bottom:10px;padding:18px;border-radius:11px}.dashboard-hero h1{font-size:21px}.dashboard-hero p{font-size:11px;line-height:1.4}.overview-grid{grid-template-columns:1fr 1fr;gap:7px}.overview-card{min-height:84px;padding:12px 10px;gap:8px}.overview-icon{width:32px;height:32px;font-size:18px}.overview-card strong{font-size:18px}.overview-card span:not(.overview-icon){font-size:9px}.overview-card small{font-size:9px}.dashboard-columns{gap:8px}.system-panel,.service-panel{padding:14px;border-radius:10px}.system-meters{gap:12px}.panel-heading{margin-bottom:13px}.panel-heading h2{font-size:14px}.panel-heading p{font-size:10px}.disk-row{grid-template-columns:82px 1fr auto;gap:7px}.disk-values{font-size:10px}.download-hero{padding:18px;margin-bottom:10px}.download-hero h2{font-size:19px}.download-hero p{font-size:11px}.download-stats{grid-template-columns:1fr 1fr;gap:7px}.download-card{min-height:78px;padding:10px;gap:8px}.card-icon{width:30px;height:30px;font-size:17px}.card-label{font-size:9px}.download-card strong{font-size:17px}.download-card small{font-size:9px}.settings-modal{max-height:calc(100dvh - 24px);overflow:auto;padding:18px}.settings-head{margin-bottom:15px}.settings-modal label{margin-top:13px}}
@media(max-width:390px){.brand-name{display:none}.head-sub{display:none}.overview-grid{grid-template-columns:1fr}.dashboard-hero{padding:15px}.download-stats{grid-template-columns:1fr}}
-
MEDIA
Media Max
Audio- und Untertitelspuren aus den Mediendateien
+
MEDIA
Media Max
Audio- und Untertitelspuren aus den Mediendateien
MEDIA MAX
Dashboard
Deine gesamte Medienbibliothek und Systemauslastung auf einen Blick.
Live
▣
Filme{{ rows|length }}Radarr Library
▤
Serien{{ series|length }}Sonarr Shows
⚠
Ohne Deutsch{{ missing_german_movies|length + (missing_german_series|map(attribute='episodes')|map('length')|sum) }}Audio oder Untertitel prüfen
↓
Downloads—SABnzbd wird geladen …
Systemauslastung
Aktuelle Werte aus dem Dashboard-Container
Wird geladen …
CPU—
RAM—
Laufwerke werden geladen …
Dienste
Verbindung und Bibliotheksstatus
R
RadarrFilme & Qualität
Aktiv
S
SonarrSerien & Episoden
{% if sonarr_enabled %}Aktiv{% else %}Nicht konfiguriert{% endif %}