„Scratch disk" wörtlich zu übersetzen ist derselbe Fehler wie „Wachhund"
für Watchdog und „Keks" für Cookie. Und „Marke" ist kein Fachbegriff für
das, was gemeint ist: Jellyfin nennt diese Abschnitte Media Segments, und
das ist auch das Wort, in dem sich darüber reden lässt.
Kratzplatz* → Transcode* (was es ist, steht in FLARO_TRANSCODE)
Marke, Marken → Segment, Segmente
Markenerkennung → Segmenterkennung
Markenart/-suche → Segmentart/-suche
Tonabdruck → Fingerprint (Chromaprint nennt es so)
Tonabgleich → Fingerprintabgleich
Schlüsselbild → Keyframe
Bildabtaster → Frameabtaster
Gewöhnliches Deutsch bleibt gewöhnliches Deutsch: Wartung, Freigabe,
Meldung, Abspann, Vorspann. Das war nie das Problem.
**Was sich nicht ändert, und zwar mit Absicht.** Die drei
Einstellungsschlüssel `wartung.kratzplatz.paket.*` bleiben, wie sie sind —
sie stehen in der Datenbank, und ein neuer Name hiesse, dass die Werte
des Nutzers stillschweigend auf die Vorgabe zurückfallen. Dasselbe für
die Endpunktpfade `/marken`: sie sind nicht sichtbar, und ein Umbenennen
wäre Diff ohne Gewinn.
**Die Migration ist von Hand geschrieben.** `dotnet ef` hat ein Gerüst
erzeugt, das beide Tabellen löscht und neu anlegt — es sieht eine
verschwundene und eine neue Tabelle, nicht eine umbenannte. Damit wäre
jedes erkannte Segment und jeder Vermerk „hier wurde schon gesucht" weg
gewesen. `RenameTable` und `RenameIndex` tun dasselbe, ohne eine Zeile
anzufassen; nachgemessen an einer echten SQLite-Datei: Zeilen vorher 1
und 1, nachher 1 und 1, Inhalt unverändert.
Nachgezogen: in `bilder.ts` und `main.ts` heisst „marke" ein Häkchen und
das Logo — die blieben unberührt. Und „Segment" ist sächlich, was eine
Blindersetzung nicht weiss: „eine Segment" stand danach an vierzehn
Stellen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.1 KiB
C#
86 lines
3.1 KiB
C#
using Flaro.Media;
|
|
|
|
namespace Flaro.Media.Tests;
|
|
|
|
/// <summary>Die Ausgabe von <c>fpcalc -raw</c> lesen.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// <b>Ohne das Programm selbst.</b> Ob Chromaprint rechnen kann, ist nicht
|
|
/// unsere Frage; ob wir seine Ausgabe richtig verstehen, schon. Die Zahlen
|
|
/// kommen mit Vorzeichen, gemeint sind die Bitmuster — wer das verwechselt,
|
|
/// bekommt einen Fingerprint, der nie zu einem zweiten passt.
|
|
/// </remarks>
|
|
public class FingerprintleserTests
|
|
{
|
|
[Test]
|
|
public void Die_Zahlen_werden_als_Bitmuster_gelesen()
|
|
{
|
|
var fingerprint = Fingerprintleser.Lesen("DURATION=120\nFINGERPRINT=1,-1,2147483647,-2147483648\n");
|
|
|
|
Assert.That(fingerprint, Is.EqualTo(new uint[] { 1u, 0xFFFFFFFFu, 0x7FFFFFFFu, 0x80000000u }));
|
|
}
|
|
|
|
[Test]
|
|
public void Ohne_Fingerprintzeile_kommt_nichts()
|
|
{
|
|
Assert.That(Fingerprintleser.Lesen("DURATION=120\n"), Is.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void Eine_leere_Zeile_ergibt_keinen_Fingerprint()
|
|
{
|
|
Assert.That(Fingerprintleser.Lesen("FINGERPRINT=\n"), Is.Empty);
|
|
}
|
|
|
|
/// <summary>Eine Zeitscheibe ist rund 124 Millisekunden.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// Daran hängt jede Zeitangabe, die aus einem Fingerprint entsteht. Stimmt
|
|
/// die Zahl nicht, liegt jedes Segment um denselben Faktor daneben — und
|
|
/// das sähe aus wie ein Fehler in der Erkennung.
|
|
/// </remarks>
|
|
[Test]
|
|
public void Eine_Zeitscheibe_dauert_124_Millisekunden()
|
|
{
|
|
Assert.That(Fingerprintleser.SekundenJeFingerprint, Is.EqualTo(0.1238).Within(0.0005));
|
|
}
|
|
}
|
|
|
|
/// <summary>Was fpcalc wirklich kann — nachgemessen, nicht angenommen.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// <b>Der Anlass ist ein Fehler, der im Betrieb stand.</b> Hier wurde
|
|
/// <c>-ts 0</c> übergeben, in der Annahme, das sei ein Startpunkt. Es ist
|
|
/// ein Schalter („gib Zeitstempel aus"), und die Null las fpcalc als
|
|
/// zweiten Dateinamen: Code 2, „No such file or directory" — über Dateien,
|
|
/// die da waren. Einen Startpunkt gibt es bei fpcalc nicht.
|
|
///
|
|
/// Gemessen am Binärprogramm aus dem Abbild, an einer Datei von 2700
|
|
/// Sekunden: <c>-length 0</c> ergibt 21 786 Werte, also 0,1239 Sekunden je
|
|
/// Wert; <c>-length 120</c> bricht nach 948 Werten ab.
|
|
/// </remarks>
|
|
public class FingerprintRateTests
|
|
{
|
|
[Test]
|
|
public void Die_Rate_stimmt_mit_der_Messung_ueberein()
|
|
{
|
|
// 21 786 Werte für 2700 Sekunden.
|
|
var gemessen = 2700.0 / 21786;
|
|
Assert.That(Math.Abs(gemessen - Fingerprintleser.SekundenJeFingerprint), Is.LessThan(0.0005));
|
|
}
|
|
|
|
/// <summary>Eine Stunde Fingerprint passt in eine überschaubare Reihe.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// Damit niemand auf die Idee kommt, den Fingerprint einer ganzen Folge für
|
|
/// zu gross zu halten und wieder in Ausschnitten zu lesen: eine Stunde
|
|
/// sind knapp 29 000 Werte, also 116 Kilobyte.
|
|
/// </remarks>
|
|
[Test]
|
|
public void Eine_Stunde_sind_rund_29000_Werte()
|
|
{
|
|
var werte = (int)(3600 / Fingerprintleser.SekundenJeFingerprint);
|
|
Assert.That(werte, Is.InRange(28500, 29500));
|
|
}
|
|
}
|