Dashboard-Disc-Karte: Auto-Pre-Scan beim Einlegen — man SIEHT was drinliegt
Ampel / ampel (push) Successful in 41s
Ampel / ampel (push) Successful in 41s
Commander-Befund: Disc wurde erkannt, aber das UI verriet nicht WAS.
- Watcher stoesst beim Einlegen (und beim Start mit bereits eingelegter
Disc) automatisch den Pre-Scan an, Ergebnis landet im DISC_CACHE und
im Log ("Disc erkannt: Titel (Jahr) [typ, Confidence]")
- GET /devices liefert das disc-Feld mit Titel/Jahr/Typ/Confidence/Poster
- UI: prominente Karte "Im Laufwerk erkannt" mit Poster (TMDB relativ
oder OMDb absolut), Beschreibung und Rippen-Start (Ziel-Dialog)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+38
-2
@@ -63,8 +63,34 @@ async def startup_event():
|
||||
asyncio.create_task(disc_watcher())
|
||||
|
||||
|
||||
# Auto-Pre-Scan-Ergebnisse je Laufwerk: das Dashboard zeigt damit sofort,
|
||||
# WAS im Laufwerk liegt (Titel/Jahr/Poster), ohne dass jemand klicken muss.
|
||||
DISC_CACHE: Dict[str, Dict] = {}
|
||||
|
||||
|
||||
async def _auto_prescan(pfad: str):
|
||||
"""Identifiziert die eingelegte Disc im Hintergrund und cached das Ergebnis."""
|
||||
if DISC_CACHE.get(pfad, {}).get("_laeuft"):
|
||||
return
|
||||
DISC_CACHE[pfad] = {"_laeuft": True, "title": "Wird erkannt…"}
|
||||
try:
|
||||
prescan = PreScan()
|
||||
ergebnis = await asyncio.to_thread(prescan.scan, pfad)
|
||||
DISC_CACHE[pfad] = ergebnis.to_dict()
|
||||
db.add_log(
|
||||
"info", "watcher",
|
||||
f"Disc erkannt: {ergebnis.title}"
|
||||
+ (f" ({ergebnis.year})" if ergebnis.year else "")
|
||||
+ f" [{ergebnis.disc_type}, Confidence {ergebnis.confidence:.0%}] auf {pfad}",
|
||||
)
|
||||
except Exception as e:
|
||||
DISC_CACHE.pop(pfad, None)
|
||||
print(f"Auto-Pre-Scan {pfad}: {e}")
|
||||
|
||||
|
||||
async def disc_watcher():
|
||||
"""Disc-Wache: pollt die Laufwerke und protokolliert Einwurf/Auswurf.
|
||||
"""Disc-Wache: pollt die Laufwerke, protokolliert Einwurf/Auswurf und
|
||||
stößt beim Einlegen automatisch den Pre-Scan an (Dashboard-Disc-Karte).
|
||||
|
||||
Ersetzt den nie gebauten udev-Daemon aus dem KONZEPT: udev funktioniert im
|
||||
Container nicht sinnvoll (kein udevd) — ein 3-Sekunden-Poll per ioctl ist
|
||||
@@ -79,11 +105,17 @@ async def disc_watcher():
|
||||
except OSError:
|
||||
continue
|
||||
vorher = bekannt.get(pfad)
|
||||
if vorher is not None and status != vorher:
|
||||
if vorher is None:
|
||||
# Erststart: liegt schon eine Disc drin, direkt erkennen
|
||||
if status == CDS_DISC_OK:
|
||||
asyncio.create_task(_auto_prescan(pfad))
|
||||
elif status != vorher:
|
||||
if status == CDS_DISC_OK:
|
||||
db.add_log("info", "watcher", f"Disc eingelegt: {pfad}")
|
||||
asyncio.create_task(_auto_prescan(pfad))
|
||||
elif status in (CDS_NO_DISC, CDS_TRAY_OPEN) and vorher == CDS_DISC_OK:
|
||||
db.add_log("info", "watcher", f"Disc entfernt: {pfad}")
|
||||
DISC_CACHE.pop(pfad, None)
|
||||
bekannt[pfad] = status
|
||||
except Exception as e:
|
||||
print(f"Disc-Wache: {e}")
|
||||
@@ -147,6 +179,7 @@ class Device(BaseModel):
|
||||
status: str
|
||||
model: Optional[str] = None
|
||||
serial: Optional[str] = None
|
||||
disc: Optional[Dict] = None # Auto-Pre-Scan-Ergebnis (Titel/Jahr/Poster)
|
||||
|
||||
|
||||
def _job_row_to_model(zeile: dict) -> Job:
|
||||
@@ -323,6 +356,9 @@ async def get_devices():
|
||||
geraete = []
|
||||
for pfad in device_discovery.list_optical_devices():
|
||||
info = await asyncio.to_thread(device_discovery.device_info, pfad)
|
||||
disc = DISC_CACHE.get(pfad)
|
||||
if disc and not disc.get("_laeuft"):
|
||||
info["disc"] = disc
|
||||
geraete.append(Device(**info))
|
||||
return geraete
|
||||
|
||||
|
||||
Reference in New Issue
Block a user