Gefunden und gleich wieder weggeworfen
**Stream, nicht Strom.** Mein Fehler, und die Regel kenne ich: Fachbegriffe bleiben englisch. Betroffen war eine Meldung im Spieler und vier Zeilen im Tagesprotokoll. **Der Abspann fiel durch die eigene Schranke.** `Hoechstlaenge` von fünf Minuten galt für Vorspann und Abspann gleichermassen. Fünf Minuten sind für einen Abspann aber keine Obergrenze, sondern die Regel — eine deutsche Serienproduktion listet Sprecher, Synchronregie und Studio hinterher, und sechs Minuten kommen vor. Der Tonabgleich fand das Stück, und die Zeile darunter warf es weg. Von aussen sah das aus wie „nichts gefunden". Der Abspann darf jetzt so lang sein wie sein Suchfenster; weiter reicht eine Marke ohnehin nie. **Vermutung, nicht Messung** — das Stück steht auf einem Server, an den ich nicht komme. Deshalb dasselbe Commit: **Man kann jetzt nachsehen.** Neben jeder Folge steht für Verwalter, was die Erkennung gefunden hat: „Vorspann + Abspann", „Vorspann" oder „keine Marken". Ob eine Marke fehlt oder bloss nicht angezeigt wird, war von aussen nicht zu unterscheiden — und beides hat eine andere Ursache. Die Angabe kostet nichts: sie steht längst in der Antwort des Servers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a360bed02b
commit
74643b8242
@@ -64,6 +64,21 @@ public sealed class Markenerkennung(
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public const double Hoechstlaenge = 5 * 60;
|
public const double Hoechstlaenge = 5 * 60;
|
||||||
|
|
||||||
|
/// <summary>Dasselbe für den Abspann — und deutlich grosszügiger.</summary>
|
||||||
|
///
|
||||||
|
/// <remarks>
|
||||||
|
/// <b>Fünf Minuten sind für einen Abspann keine Obergrenze, sondern
|
||||||
|
/// die Regel.</b> Eine deutsche Serienproduktion listet Sprecher,
|
||||||
|
/// Synchronregie und Studio hinterher; sechs Minuten kommen vor. Mit
|
||||||
|
/// derselben Schranke wie beim Vorspann wurde der Fund gemacht und
|
||||||
|
/// gleich wieder weggeworfen — gefunden, verworfen, und am Ende stand
|
||||||
|
/// kein Knopf da, obwohl die Erkennung gearbeitet hatte.
|
||||||
|
///
|
||||||
|
/// Weiter als das Suchfenster kann eine Marke ohnehin nicht reichen;
|
||||||
|
/// mehr als dieses Fenster zu erlauben hiesse nichts zu erlauben.
|
||||||
|
/// </remarks>
|
||||||
|
public const double Hoechstabspann = Abspannfenster;
|
||||||
|
|
||||||
/// <summary>Welche Staffeln gerade abgetastet werden.</summary>
|
/// <summary>Welche Staffeln gerade abgetastet werden.</summary>
|
||||||
private readonly ConcurrentDictionary<Guid, bool> _laufend = new();
|
private readonly ConcurrentDictionary<Guid, bool> _laufend = new();
|
||||||
|
|
||||||
@@ -325,9 +340,11 @@ public sealed class Markenerkennung(
|
|||||||
// vermerken hiesse, ihn beim nächsten Scan zu wiederholen.
|
// vermerken hiesse, ihn beim nächsten Scan zu wiederholen.
|
||||||
await VermerkenAsync(db, serieId, staffel.Key, art, geordnet.Count, ct);
|
await VermerkenAsync(db, serieId, staffel.Key, art, geordnet.Count, ct);
|
||||||
|
|
||||||
|
var grenze = art == Markenart.Intro ? Hoechstlaenge : Hoechstabspann;
|
||||||
|
|
||||||
foreach (var (folgenId, stelle) in treffer)
|
foreach (var (folgenId, stelle) in treffer)
|
||||||
{
|
{
|
||||||
if (stelle.Bis - stelle.Von > Hoechstlaenge) continue;
|
if (stelle.Bis - stelle.Von > grenze) continue;
|
||||||
|
|
||||||
// **Die Zeiten liegen im Fenster, nicht in der Folge.**
|
// **Die Zeiten liegen im Fenster, nicht in der Folge.**
|
||||||
// Beim Abspann fängt das Fenster zehn Minuten vor dem
|
// Beim Abspann fängt das Fenster zehn Minuten vor dem
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public sealed class Streamkoordinator(
|
|||||||
if (eintrag.Sitzung.Gesehen > grenze) continue;
|
if (eintrag.Sitzung.Gesehen > grenze) continue;
|
||||||
if (!_sitzungen.TryRemove(kennung, out var weg)) continue;
|
if (!_sitzungen.TryRemove(kennung, out var weg)) continue;
|
||||||
|
|
||||||
log.LogInformation("Strom {Kennung} wurde seit {Geduld} nicht abgeholt — beendet.",
|
log.LogInformation("Stream {Kennung} wurde seit {Geduld} nicht abgeholt — beendet.",
|
||||||
kennung, Geduld);
|
kennung, Geduld);
|
||||||
Abraeumen(weg);
|
Abraeumen(weg);
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ public sealed class Streamkoordinator(
|
|||||||
// eine Spur.
|
// eine Spur.
|
||||||
if (text.Trim() is { Length: > 0 } warnungen)
|
if (text.Trim() is { Length: > 0 } warnungen)
|
||||||
{
|
{
|
||||||
log.LogWarning("Strom {Kennung}: ffmpeg meldet {Warnungen}",
|
log.LogWarning("Stream {Kennung}: ffmpeg meldet {Warnungen}",
|
||||||
sitzung.Kennung, warnungen);
|
sitzung.Kennung, warnungen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +434,7 @@ public sealed class Streamkoordinator(
|
|||||||
}
|
}
|
||||||
catch (IOException fehler)
|
catch (IOException fehler)
|
||||||
{
|
{
|
||||||
log.LogWarning(fehler, "Der Ordner zu Strom {Kennung} blieb liegen.", eintrag.Sitzung.Kennung);
|
log.LogWarning(fehler, "Der Ordner zu Stream {Kennung} blieb liegen.", eintrag.Sitzung.Kennung);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +458,7 @@ public sealed class Streamkoordinator(
|
|||||||
try { Directory.Delete(Wurzel, recursive: true); }
|
try { Directory.Delete(Wurzel, recursive: true); }
|
||||||
catch (IOException fehler)
|
catch (IOException fehler)
|
||||||
{
|
{
|
||||||
log.LogDebug(fehler, "Der Stromordner {Pfad} liess sich nicht leeren.", Wurzel);
|
log.LogDebug(fehler, "Der Streamordner {Pfad} liess sich nicht leeren.", Wurzel);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1284,7 +1284,7 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
|
|
||||||
function hlsfehler(art: string, arten: { NETWORK_ERROR: string; MEDIA_ERROR: string }): string {
|
function hlsfehler(art: string, arten: { NETWORK_ERROR: string; MEDIA_ERROR: string }): string {
|
||||||
if (art === arten.NETWORK_ERROR) {
|
if (art === arten.NETWORK_ERROR) {
|
||||||
return 'Der Strom ist abgerissen. Entweder war die Verbindung weg, '
|
return 'Der Stream ist abgerissen. Entweder war die Verbindung weg, '
|
||||||
+ 'oder der Server hat die Sitzung aufgeräumt — fang die Wiedergabe neu an.';
|
+ 'oder der Server hat die Sitzung aufgeräumt — fang die Wiedergabe neu an.';
|
||||||
}
|
}
|
||||||
if (art === arten.MEDIA_ERROR) {
|
if (art === arten.MEDIA_ERROR) {
|
||||||
|
|||||||
@@ -1085,6 +1085,20 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem
|
|||||||
/** Und wie sie heisst — für die Zeile über dem Spieler. */
|
/** Und wie sie heisst — für die Zeile über dem Spieler. */
|
||||||
let serienname: string | undefined;
|
let serienname: string | undefined;
|
||||||
|
|
||||||
|
/** Was die Erkennung bei dieser Folge gefunden hat — nur für Verwalter.
|
||||||
|
*
|
||||||
|
* **Ohne das bleibt „es kommt kein Knopf" eine Vermutung.** Ob die Marke
|
||||||
|
* gar nicht gefunden wurde oder bloss nicht angezeigt wird, ist von
|
||||||
|
* aussen nicht zu unterscheiden — und beides hat eine andere Ursache.
|
||||||
|
* Einmal nachsehen zu können erspart eine Runde Raten. */
|
||||||
|
function markenwort(marken: Folge['markers']): string {
|
||||||
|
if (!istAdmin()) return '';
|
||||||
|
if (!marken || marken.length === 0) return 'keine Marken';
|
||||||
|
return marken
|
||||||
|
.map(m => m.kind === 'intro' ? 'Vorspann' : 'Abspann')
|
||||||
|
.join(' + ');
|
||||||
|
}
|
||||||
|
|
||||||
function folgenblock(folge: Folge): HTMLElement {
|
function folgenblock(folge: Folge): HTMLElement {
|
||||||
const block = document.createElement('div');
|
const block = document.createElement('div');
|
||||||
block.className = 'einstellung';
|
block.className = 'einstellung';
|
||||||
@@ -1095,9 +1109,11 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem
|
|||||||
: folge.state && folge.state.positionSeconds > 0
|
: folge.state && folge.state.positionSeconds > 0
|
||||||
? `noch ${Math.round(((folge.state.runtimeSeconds ?? 0) - folge.state.positionSeconds) / 60)} Min`
|
? `noch ${Math.round(((folge.state.runtimeSeconds ?? 0) - folge.state.positionSeconds) / 60)} Min`
|
||||||
: '';
|
: '';
|
||||||
|
const marken = markenwort(folge.markers);
|
||||||
|
const daneben = [nebenbei, marken].filter(Boolean).join(' · ');
|
||||||
zeile.innerHTML =
|
zeile.innerHTML =
|
||||||
`<strong>${String(folge.episode).padStart(2, '0')} · ${esc(folge.title ?? 'Ohne Titel')}</strong>`
|
`<strong>${String(folge.episode).padStart(2, '0')} · ${esc(folge.title ?? 'Ohne Titel')}</strong>`
|
||||||
+ (nebenbei ? `<span class="winzig">${esc(nebenbei)}</span>` : '');
|
+ (daneben ? `<span class="winzig">${esc(daneben)}</span>` : '');
|
||||||
|
|
||||||
const wie = `S${folge.season} · F${folge.episode}`
|
const wie = `S${folge.season} · F${folge.episode}`
|
||||||
+ (folge.title ? ` — ${folge.title}` : '');
|
+ (folge.title ? ` — ${folge.title}` : '');
|
||||||
|
|||||||
Reference in New Issue
Block a user