Kratzplatz, Markenerkennung, Tonabdruck — erfundene Wörter für Fachbegriffe

„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>
This commit is contained in:
Scarriffle
2026-10-16 16:26:57 +02:00
co-authored by Claude Opus 5
parent 32f592b83e
commit ed13d5fa43
73 changed files with 2137 additions and 694 deletions
@@ -0,0 +1,56 @@
using Flaro.Core.Media;
namespace Flaro.Core.Tests;
/// <summary>Der Abgleich an echten Chromaprint-Abdrücken.</summary>
///
/// <remarks>
/// <b>Bisher nur mit erfundenen Zahlen geprüft.</b> Die sagen, ob die Suche
/// rechnet; sie sagen nicht, ob die Schwellen zu echtem Material passen.
/// Genau dazwischen kann alles liegen: zwei Aufnahmen desselben Stücks sind
/// nie bitgleich, und wie unähnlich sie sind, weiss man erst, wenn man es
/// misst.
///
/// Die beiden Abdrücke liegen als Prüfdaten daneben: zwei Tonspuren mit
/// demselben dreissigsekündigen Stück an verschiedenen Stellen und in
/// verschiedener Bitrate, durch <c>fpcalc</c> gedreht. Zwanzig Kilobyte
/// Text — der Preis dafür, dass diese Zusage nicht bloss behauptet ist.
/// </remarks>
public class EchteFingerprintsTests
{
private const double JeFingerprint = 4096.0 / 3.0 / 11025.0;
private static IReadOnlyList<uint>? Lesen(string name)
{
var pfad = Path.Combine(TestContext.CurrentContext.TestDirectory, "Fingerprints", name);
if (!File.Exists(pfad)) return null;
return File.ReadAllText(pfad)
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Select(t => unchecked((uint)long.Parse(t)))
.ToList();
}
[Test]
public void Dasselbe_Stueck_wird_in_zwei_Aufnahmen_gefunden()
{
var a = Lesen("folgeA.txt");
var b = Lesen("folgeB.txt");
if (a is null || b is null) Assert.Ignore("Keine Abdrücke zum Prüfen da.");
var treffer = Fingerprintabgleich.Finden(a, b, JeFingerprint);
TestContext.Out.WriteLine($"A {a.Count} Werte, B {b.Count} Werte");
TestContext.Out.WriteLine(treffer is null
? "NICHTS GEFUNDEN"
: $"A {treffer.AVon:0.0}–{treffer.ABis:0.0} s, B {treffer.BVon:0.0}–{treffer.BBis:0.0} s");
Assert.That(treffer, Is.Not.Null, "das Stück steckt in beiden");
Assert.Multiple(() =>
{
Assert.That(treffer!.AVon, Is.EqualTo(20).Within(3));
Assert.That(treffer.BVon, Is.EqualTo(75).Within(3));
Assert.That(treffer.Laenge, Is.EqualTo(30).Within(4));
});
}
}