Spider-Man ist nicht 720p, er ist breit
Die Auflösung wurde allein aus der Höhe gebildet. Ein Kinoformat von 2.39:1 liegt als 1920×800 vor — nach der Höhe gerechnet kam „720p" heraus, und das stand so in der Oberfläche. Jetzt zählt die grössere von Breite und Höhe; Hochformat kippt damit nicht, und 4K-Breitbild heisst nicht mehr 1440p. Die Detailansicht hat zwei Leserschaften, und bisher bekamen beide dasselbe. Wer schauen will, sieht jetzt Laufzeit, Auflösung und die Sprachen — jede einmal, statt „Englisch · Englisch · Englisch · Englisch · Deutsch". Wer die Mediathek betreut, sieht darunter Dateiformat, Grösse und den Ordner. Der Ordner verrät eine falsche Zuordnung in einer Sekunde: steht über der Beschreibung „Hanni & Nanni 3" und der Ordner heisst „Hanni und Nanni", ist die Sache klar. Er kommt nur für Administratoren überhaupt vom Server — versteckt im Client wäre er weiterhin auslesbar. Ein geplanter Titel war unsichtbar. Das ist die Hälfte, die nichts bringt: dass er kommt, ist der Sinn des Planens. Er steht jetzt mit „Verfügbar ab …" in der Mediathek, und die Datei geht trotzdem nicht heraus — Download wie Strom lehnen bis zum Termin ab, auch für Administratoren. Wer vorziehen will, hat „Jetzt veröffentlichen"; eine Hintertür für eine Rolle wäre eine Regel, die manchmal gilt. Was ein Auffrischen geändert hat, steht jetzt unter „Zu prüfen" — in einer eigenen Gruppe mit „Zur Kenntnis" statt „Veröffentlichen". Diese Titel sind sichtbar; es gibt nichts freizugeben, nur etwas abzuhaken. Und das Protokoll sagt endlich, wo es knallt. „InvalidOperationException: Nullable object must have a value." ohne eine einzige Zeile Herkunft ist für niemanden eine Diagnose — weder für den Betreiber noch für mich. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f44779c899
commit
255eb7c2f0
@@ -25,11 +25,13 @@ public static class DeliveryEndpoints
|
||||
// durch bis zum SPA-Rückfall und bekäme die Webseite mit Status 200.
|
||||
// Genau das ist passiert: der Spieler bekam HTML statt Video.
|
||||
app.MapMethods("/api/v1/files/{id:guid}/download", ["GET", "HEAD"], async (
|
||||
Guid id, FlaroContext db, PackageCoordinator packer) =>
|
||||
Guid id, FlaroContext db, PackageCoordinator packer, TimeProvider uhr) =>
|
||||
{
|
||||
var gefunden = await Laden(db, id);
|
||||
if (gefunden is not var (datei, plan)) return Results.NotFound();
|
||||
|
||||
if (await FreiAb(db, datei, uhr.GetUtcNow()) is { } nochNicht) return NochNicht(nochNicht);
|
||||
|
||||
// Passt schon alles, geht die Datei unverändert hinaus — mit
|
||||
// Längenangabe und Bereichsanfragen, also mit Fortschritt und
|
||||
// Fortsetzen.
|
||||
@@ -70,6 +72,41 @@ public static class DeliveryEndpoints
|
||||
}).RequireAuthorization();
|
||||
}
|
||||
|
||||
/// <summary>Ab wann diese Datei herausgehen darf — <c>null</c> heisst: sofort.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Hier und nicht im Sichtbarkeitsfilter.</b> Ein geplanter Titel steht
|
||||
/// mit „Verfügbar ab …" in der Mediathek — das ist der Sinn des Planens.
|
||||
/// Sichtbar heisst aber nicht abspielbar: ohne diese Prüfung liesse sich
|
||||
/// die Datei trotzdem herunterladen, und die Angabe wäre eine Zierde.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Für alle, auch für Administratoren.</b> Wer die Freigabe vorziehen
|
||||
/// will, hat dafür den Knopf „Jetzt veröffentlichen" — eine Hintertür für
|
||||
/// eine Rolle wäre eine Regel, die manchmal gilt.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal static async Task<DateTimeOffset?> FreiAb(
|
||||
FlaroContext db, MediaFile datei, DateTimeOffset jetzt)
|
||||
{
|
||||
DateTimeOffset? wann = datei.MovieId is { } film
|
||||
? await db.Movies.AsNoTracking().Where(m => m.Id == film)
|
||||
.Select(m => m.PublishAt).FirstOrDefaultAsync()
|
||||
: datei.EpisodeId is { } folge
|
||||
? await db.Episodes.AsNoTracking().Where(f => f.Id == folge)
|
||||
.Select(f => f.PublishAt).FirstOrDefaultAsync()
|
||||
: null;
|
||||
|
||||
return wann is { } termin && termin > jetzt ? termin : null;
|
||||
}
|
||||
|
||||
/// <summary>Der Satz, der statt der Datei kommt.</summary>
|
||||
internal static IResult NochNicht(DateTimeOffset wann) =>
|
||||
Results.Problem(
|
||||
$"Dieser Titel ist ab {wann.ToLocalTime():dd.MM.yyyy, HH:mm} Uhr verfügbar.",
|
||||
statusCode: StatusCodes.Status403Forbidden);
|
||||
|
||||
private static async Task<(MediaFile Datei, DeliveryPlan Plan)?> Laden(FlaroContext db, Guid id)
|
||||
{
|
||||
var datei = await db.MediaFiles.AsNoTracking().FirstOrDefaultAsync(f => f.Id == id);
|
||||
|
||||
Reference in New Issue
Block a user