Zwölf Sekunden für eine Hülle um nichts

Die Messung sagt es deutlich:

    20:15:53  Umpacken    — Schlüsselbildsuche 2348 ms, Vorbereitung 2394 ms.
    20:16:05  Umkodieren  — Schlüsselbildsuche 0 ms, Vorbereitung 0 ms.
    20:16:08  erstes Stück nach 2750 ms.

Fünfzehn Sekunden, und zwölf davon liegen zwischen zwei Bestellungen für
denselben Film. Der erste Strom wurde angelegt und dann nie abgeholt —
keine Medienliste, kein Stück, kein ffmpeg-Fehler. Danach gab die App auf
und bestellte neu, diesmal mit Umkodieren, und das lief nach knapp drei
Sekunden.

Dazwischen lag die Hauptliste. Es gibt sie allein wegen der
Untertitelspuren, und bei diesem Film waren die noch gar nicht aus der
Datei gezogen — sie war also leer bis auf einen Verweis auf die
Medienliste. Eine Hülle um nichts, und keine umsonst: ohne `CODECS` muss
ein Spieler sie erst aufmachen, um zu sehen, was darin liegt.

Jetzt gibt es sie nur, wenn wenigstens eine Spur abholbar ist. Sonst
bekommt die App die Medienliste unmittelbar — denselben Weg wie der
Browser, der nie gestolpert ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-10 20:20:16 +02:00
co-authored by Claude Opus 5
parent a6b3217d6e
commit 19ec17da19
2 changed files with 37 additions and 14 deletions
@@ -118,7 +118,7 @@ public static class StreamEndpoints
erzwingen: anfrage.Transcode,
tonversatz: Math.Clamp(anfrage.AudioOffsetMs, -5000, 5000) / 1000.0);
return Results.Ok(await Auskunft(db, sitzung));
return Results.Ok(await Auskunft(db, vorrat, sitzung));
}
catch (InvalidOperationException fehler)
{
@@ -511,17 +511,35 @@ public static class StreamEndpoints
new HashSet<string>(anfrage.AudioCodecs, StringComparer.OrdinalIgnoreCase));
}
private static async Task<StreamResponse> Auskunft(FlaroContext db, Stromsitzung sitzung)
private static async Task<StreamResponse> Auskunft(
FlaroContext db, Untertitelvorrat vorrat, Stromsitzung sitzung)
{
var spuren = await db.MediaStreams.AsNoTracking()
.Where(s => s.MediaFileId == sitzung.DateiId)
.OrderBy(s => s.Index)
.ToListAsync();
// **Die Hauptliste nur, wenn etwas drinsteht.**
//
// Sie gibt es allein wegen der Untertitelspuren; ohne sie ist sie
// eine Hülle um die Medienliste. Und eine Hülle ist nicht umsonst:
// eine Hauptliste ohne `CODECS` muss der Spieler erst aufmachen, um
// zu sehen, was darin liegt. Gemessen an einem Film, dessen Spuren
// noch nicht herausgezogen waren: zwölf Sekunden vergingen, ohne dass
// die Medienliste auch nur abgeholt wurde, dann gab die App auf und
// bestellte neu.
var datei = await db.MediaFiles.AsNoTracking()
.FirstOrDefaultAsync(f => f.Id == sitzung.DateiId);
var hatText = datei is not null && spuren
.Where(x => x.Kind == MediaStreamKind.Subtitle)
.Where(x => x.Codec is null || !Untertitelvorrat.IstBild(x.Codec))
.Any(x => vorrat.Liegtvor(datei.Id, datei.ModifiedAt, x.Index));
return new StreamResponse(
SessionId: sitzung.Kennung,
Url: $"/api/v1/stream/{sitzung.Kennung}/index.m3u8",
MasterUrl: $"/api/v1/stream/{sitzung.Kennung}/master.m3u8",
MasterUrl: hatText ? $"/api/v1/stream/{sitzung.Kennung}/master.m3u8" : null,
Method: sitzung.Art switch
{
Stromart.Direkt => "direct",