From adca700c4a7b3f5d58a15af838ae6681a4ca7ca0 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Mon, 12 Oct 2026 21:52:24 +0200 Subject: [PATCH] Marken suchen, ohne dass jemand danach fragt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eine neue Folge bekommt keine Vorspann-Marke, wenn niemand den Knopf drückt — und niemand drückt ihn, weil man nicht weiss, dass es etwas zu drücken gibt. Der Scan ist der Augenblick, in dem neue Folgen entstehen; jetzt hängt sich der Lauf dort hinten an. Eine Serie nach der anderen, nicht alle zugleich: jede liest von jeder ihrer Folgen ein Stück Ton, und zwanzig gleichzeitig wären zwanzig Leseköpfe auf derselben Platte. Gerechnet wird nur, wo noch nichts steht — beim ersten Mal über einen grossen Bestand dauert das entsprechend, danach findet der Lauf nichts mehr zu tun. Co-Authored-By: Claude Opus 5 --- server/src/Flaro.Api/Markenerkennung.cs | 49 +++++++++++++++++++++++++ server/src/Flaro.Api/ScanCoordinator.cs | 8 ++++ 2 files changed, 57 insertions(+) diff --git a/server/src/Flaro.Api/Markenerkennung.cs b/server/src/Flaro.Api/Markenerkennung.cs index a0c116a..dc92360 100644 --- a/server/src/Flaro.Api/Markenerkennung.cs +++ b/server/src/Flaro.Api/Markenerkennung.cs @@ -84,6 +84,55 @@ public sealed class Markenerkennung( return true; } + /// Nach einem Scan: jede Serie der Mediathek, der noch Marken fehlen. + /// + /// + /// + /// Hier, weil es sonst nie passiert. Eine neue Folge bekommt + /// keine Marke, wenn niemand danach fragt — und niemand fragt, weil man + /// nicht weiss, dass es etwas zu fragen gibt. Der Scan ist der + /// Augenblick, in dem neue Folgen entstehen. + /// + /// + /// Eine nach der anderen, nicht alle zugleich. Jede liest von + /// jeder ihrer Folgen ein Stück Ton; zwanzig Serien gleichzeitig hiesse + /// zwanzig Leseköpfe auf derselben Platte. Beim ersten Mal über einen + /// grossen Bestand dauert das entsprechend — danach findet der Lauf + /// nichts mehr zu tun und ist in Sekunden vorbei. + /// + /// + public async Task NachScanAsync(Guid mediathek, CancellationToken ct = default) + { + using var raum = scopes.CreateScope(); + var db = raum.ServiceProvider.GetRequiredService(); + var leser = raum.ServiceProvider.GetRequiredService(); + + if (!await leser.VorhandenAsync(ct)) return; + + var serien = await db.Series.AsNoTracking() + .Where(x => x.LibraryId == mediathek) + .Select(x => x.Id) + .ToListAsync(ct); + if (serien.Count == 0) return; + + log.LogInformation( + "Suche Vorspann und Abspann in {Anzahl} Serien — das kann dauern.", serien.Count); + + foreach (var serie in serien) + { + if (ct.IsCancellationRequested) return; + if (!_laufend.TryAdd(serie, true)) continue; + try { await LaufenAsync(serie, erneut: false, ct); } + catch (Exception fehler) + { + log.LogWarning(fehler, "Markenerkennung für {Serie} abgebrochen.", serie); + } + finally { _laufend.TryRemove(serie, out _); } + } + + log.LogInformation("Marken für Mediathek {Kennung} durch.", mediathek); + } + private async Task LaufenAsync(Guid serieId, bool erneut, CancellationToken ct) { using var raum = scopes.CreateScope(); diff --git a/server/src/Flaro.Api/ScanCoordinator.cs b/server/src/Flaro.Api/ScanCoordinator.cs index 81b1bd4..ee5c946 100644 --- a/server/src/Flaro.Api/ScanCoordinator.cs +++ b/server/src/Flaro.Api/ScanCoordinator.cs @@ -175,6 +175,14 @@ public sealed class ScanCoordinator( _ = bereich.ServiceProvider.GetRequiredService() .LaufenAsync(Kratzplatzpflege.Anlass.NachDemScan); + // **Und zuletzt die Marken.** Ein Scan ist der Augenblick, in + // dem neue Folgen dazukommen — und eine Folge ohne Vorspann- + // Marke bekommt nie eine, wenn niemand danach fragt. Der Lauf + // hängt sich hinten an und nimmt sich Serie für Serie vor; + // gerechnet wird nur, wo noch nichts steht. + _ = bereich.ServiceProvider.GetRequiredService() + .NachScanAsync(libraryId); + _zustand[libraryId] = _zustand[libraryId] with { Status = "finished",