Files
Flaro/server/tests/Flaro.Core.Tests/VorschauplanTests.cs
T
ScarriffleandClaude Opus 5 68abd71074 Ein Bild, wo bisher nur eine Zahl stand
Wer zur Zeitleiste greift, sieht jetzt das Standbild der Stelle — im Web
beim Überfahren, in der App beim Ziehen.

**Erzeugt wird beim Abspielen, nicht auf Vorrat.** Ein Lauf über 453
Filme und 4213 Folgen wäre ein Abend ffmpeg und mehrere Gigabyte für
Titel, die niemand anfasst. Startet jemand einen Titel, stellt sich die
Datei hinten an; bis zum ersten Griff zur Leiste ist der Lauf durch.
Gemessen an einer erzeugten Datei: 191 ms für 250 Sekunden Film, ein
Zweistünder liegt damit bei etwa fünf Sekunden.

**Ein ffmpeg-Aufruf, nicht siebenhundert.** `fps=1/10,scale=320:-2,
tile=10x10` macht aus einem Durchlauf fertige Blätter zu hundert
Kacheln. Bezahlbar ist das durch `-skip_frame nokey` — dieselbe
Abkürzung wie beim Abtasten der Abspannhelligkeit: nur Keyframes
dekodieren. Dass die Vorschau dadurch um zwei Sekunden danebenliegen
kann, sieht niemand.

**Der Spieler lädt ein Blatt und verschiebt danach nur den Ausschnitt.**
Beim Fahren über die Leiste wird kein einziger Abruf mehr fällig. Die
Rechnung Sekunde → Kachel steht an drei Stellen — Server, Web, App —
und deshalb auch dreimal dieselbe; weicht eine ab, hält man die Vorschau
für ein unscharfes Bild statt für einen Fehler. Neun Prüfungen decken
die Ränder ab: Sekunde null, letzte Kachel eines Blattes, erste des
nächsten, und hinter dem Ende.

**Die Kachelmasse werden gemessen, nicht gerechnet.** `scale=320:-2`
hält das Seitenverhältnis, ein Breitbildfilm ergibt also flachere
Kacheln. Geraten wäre jede Kachel um ein paar Bildpunkte verschoben.

Aufgeräumt wird mit dem Transcode-Cache: der Namensanfang trägt Kennung
und Änderungszeit der Mediendatei, verwaiste Blätter sind daran ohne
Tabelle erkennbar. Der Ordner taucht unter „Speicher" auf.

**Und die Pfeiltasten spulen wieder.** Hatte die Zeitleiste den Fokus,
überliess der Spieler die Pfeile dem Browser — der verschiebt `value`
und löst `input` aus, aber `change` kommt bei Tastatureingabe nicht
verlässlich, also wurde nie gesprungen. Die Ausnahme fällt weg; Pfeil
heisst überall ±10 Sekunden. Nativ wären es ohnehin 100 Millisekunden
gewesen, weil `step` auf 0,1 steht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-16 17:05:55 +02:00

102 lines
3.2 KiB
C#

using Flaro.Core.Media;
namespace Flaro.Core.Tests;
/// <summary>Welche Kachel eine Stelle zeigt.</summary>
///
/// <remarks>
/// <b>Die Rechnung steht hier, weil beide Spieler sie brauchen.</b> Web und
/// App verschieben denselben Ausschnitt; zweimal formuliert driftet er
/// auseinander, und eine verschobene Vorschau sieht man nicht sofort — man
/// hält sie für ein ungenaues Bild.
/// </remarks>
public class VorschauplanTests
{
/// <summary>Hundert Kacheln je Blatt, alle zehn Sekunden eine.</summary>
private static readonly Vorschauplan Plan = new(
Intervall: 10, Spalten: 10, Zeilen: 10,
KachelBreite: 320, KachelHoehe: 180, Blaetter: 3);
[Test]
public void Der_Anfang_ist_die_erste_Kachel()
{
Assert.That(Plan.Kachel(0), Is.EqualTo(new Vorschaukachel(0, 0, 0)));
}
/// <summary>Innerhalb eines Intervalls gilt dieselbe Kachel.</summary>
[Test]
public void Neun_Sekunden_sind_noch_die_erste()
{
Assert.That(Plan.Kachel(9.9), Is.EqualTo(new Vorschaukachel(0, 0, 0)));
}
[Test]
public void Zehn_Sekunden_sind_die_zweite()
{
Assert.That(Plan.Kachel(10), Is.EqualTo(new Vorschaukachel(0, 1, 0)));
}
/// <summary>Nach zehn Kacheln beginnt die zweite Zeile, nicht das zweite Blatt.</summary>
[Test]
public void Die_elfte_Kachel_steht_eine_Zeile_tiefer()
{
Assert.That(Plan.Kachel(100), Is.EqualTo(new Vorschaukachel(0, 0, 1)));
}
/// <summary>Die Ränder eines Blattes — dort verrechnet man sich.</summary>
[Test]
public void Der_Blattwechsel_liegt_richtig()
{
Assert.Multiple(() =>
{
// Kachel 99: letzte Spalte, letzte Zeile, erstes Blatt.
Assert.That(Plan.Kachel(990), Is.EqualTo(new Vorschaukachel(0, 9, 9)));
// Kachel 100: erste Spalte, erste Zeile, zweites Blatt.
Assert.That(Plan.Kachel(1000), Is.EqualTo(new Vorschaukachel(1, 0, 0)));
});
}
/// <summary>Hinter dem letzten Bild bleibt das letzte Bild stehen.</summary>
///
/// <remarks>
/// Das Raster endet, wo ffmpeg aufgehört hat. Eine Sekunde darüber
/// hinaus — bei ungenauer Laufzeit durchaus möglich — soll die
/// Vorschau nicht verschwinden.
/// </remarks>
[Test]
public void Hinter_dem_Ende_gilt_die_letzte_Kachel()
{
Assert.That(Plan.Kachel(99_999), Is.EqualTo(new Vorschaukachel(2, 9, 9)));
}
/// <summary>Eine negative Stelle gibt es nicht, und sie stürzt auch nicht ab.</summary>
[Test]
public void Vor_dem_Anfang_gilt_die_erste_Kachel()
{
Assert.That(Plan.Kachel(-30), Is.EqualTo(new Vorschaukachel(0, 0, 0)));
}
/// <summary>Ohne Blätter gibt es nichts zu zeigen.</summary>
[Test]
public void Ein_leerer_Plan_liefert_nichts()
{
var leer = Plan with { Blaetter = 0 };
Assert.Multiple(() =>
{
Assert.That(leer.Kachel(42), Is.Null);
Assert.That((Plan with { Intervall = 0 }).Kachel(42), Is.Null);
});
}
[Test]
public void Die_Zahlen_haengen_zusammen()
{
Assert.Multiple(() =>
{
Assert.That(Plan.ProBlatt, Is.EqualTo(100));
Assert.That(Plan.Kacheln, Is.EqualTo(300));
});
}
}