Marken suchen, ohne dass jemand danach fragt
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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1d70be0f99
commit
adca700c4a
@@ -84,6 +84,55 @@ public sealed class Markenerkennung(
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Nach einem Scan: jede Serie der Mediathek, der noch Marken fehlen.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Hier, weil es sonst nie passiert.</b> 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.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Eine nach der anderen, nicht alle zugleich.</b> 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.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public async Task NachScanAsync(Guid mediathek, CancellationToken ct = default)
|
||||
{
|
||||
using var raum = scopes.CreateScope();
|
||||
var db = raum.ServiceProvider.GetRequiredService<FlaroContext>();
|
||||
var leser = raum.ServiceProvider.GetRequiredService<Tonabdruckleser>();
|
||||
|
||||
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();
|
||||
|
||||
@@ -175,6 +175,14 @@ public sealed class ScanCoordinator(
|
||||
_ = bereich.ServiceProvider.GetRequiredService<Kratzplatzpflege>()
|
||||
.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<Markenerkennung>()
|
||||
.NachScanAsync(libraryId);
|
||||
|
||||
_zustand[libraryId] = _zustand[libraryId] with
|
||||
{
|
||||
Status = "finished",
|
||||
|
||||
Reference in New Issue
Block a user