# Standardsprachen für die Tonspur ## Kontext Heute gibt es genau eine Einstellung: eine bevorzugte Tonsprache für alles. Sie wird angewandt, indem die **erste** Spur genommen wird, deren Sprachcode passt ([PlayerModel.swift:1374](../../../Flixy/Views/Player/PlayerModel.swift)). Kein Abwägen, keine Ausweichkette, keine Rücksicht darauf, was für eine Spur das ist. Gewünscht ist etwas Abgestuftes: eine allgemeine Sprache, eine je Mediathek, und bei Serien eine **je Serie** — damit die eine auf Englisch läuft und die andere auf Deutsch. Und ein konkreter Ärger, der den ganzen Entwurf bestimmt. ## Der ZDF-Fall Bei manchen ZDF-Serien ist die als **deutsch** ausgezeichnete Spur die **mit Audiodeskription**, und die als **englisch** ausgezeichnete ist in Wahrheit Deutsch ohne Audiodeskription. Daran scheitert jede Lösung, die nur „bevorzuge Deutsch" sagt — sie wählt zuverlässig die falsche. Wer hier ankommen will, muss zwei Dinge können: 1. **Audiodeskription erkennen und meiden.** 2. **Eine einmal getroffene Wahl für die ganze Serie behalten**, auch wenn sie einer Sprache widerspricht. ## Was Jellyfin hergibt — und was nicht Aus `MediaBrowser.Model/Entities/MediaStream.cs` (Stand master): | Feld | da? | |---|---| | `Language` | ja | | `Title` (roh aus der Datei) | ja — **holen wir heute nicht** | | `DisplayTitle` (zusammengesetzt) | ja | | `IsDefault`, `IsForced` | ja | | `IsHearingImpaired` | ja | | `IsOriginal` | ja | | **Audiodeskription** | **nein** | Es gibt **kein Kennzeichen für Audiodeskription**. `IsHearingImpaired` meint Hörschädigung (Untertitel mit Geräuschbeschreibung), nicht Sehschädigung. Die `visual_impaired`-Disposition aus dem Container reicht Jellyfin nicht durch. **Folge:** Audiodeskription ist nur am **Text** zu erkennen. Das ist keine schöne Lösung, aber die einzige — und es heisst, dass sie nachsichtig sein und sich überstimmen lassen muss. Heute dekodieren wir von einer Spur nur `Index, Type, Codec, Language, DisplayTitle, Channels, IsDefault, IsForced` ([JellyfinItem.swift:166](../../../Packages/FlixyKit/Sources/JellyfinKit/JellyfinItem.swift)). `Title`, `IsHearingImpaired` und `IsOriginal` kommen dazu. --- ## Entwurf ### Drei Ebenen, eine Frage ``` Serie → Mediathek → allgemein ``` Jede Ebene kann „wie die Ebene darüber" sagen. Gefragt wird von unten nach oben; die erste Antwort gilt. Bei Filmen gibt es die Serienebene nicht — dort endet es bei der Mediathek, und genau so war es gewünscht. ### Gespeichert wird nicht „eine Sprache", sondern eine Spur Das ist die Kernentscheidung, und sie kommt aus dem ZDF-Fall. Auf der **Serienebene** wird nicht „Deutsch" abgelegt, sondern eine **Signatur** der Spur, die tatsächlich gewählt wurde: ``` TrackSignature { languageCode, normalizedTitle, channels, codec } ``` Eine Kennung („Spur 2") taugt nicht: Folgen derselben Serie haben unterschiedlich sortierte Spuren. Eine Signatur überlebt das, weil sie beschreibt, **wie** die Spur aussieht. Damit ist der ZDF-Fall lösbar: einmal die „englische" Spur wählen, und jede weitere Folge nimmt sie — obwohl der Sprachwunsch Deutsch lautet. Auf **Mediatheks-** und **allgemeiner** Ebene bleibt es bei einer Sprache. Dort wäre eine Signatur sinnlos, weil sie über verschiedene Titel hinweg nichts bedeutet. ### Die Wahl als Punktevergabe Ein reiner Typ in `FlixyPlayback/Decision/AudioTrackChooser.swift` — Spuren und Wunsch hinein, eine Spur heraus. Kein Netz, keine Einstellungen, keine Ansicht. Dieselbe Bauform wie `PlaybackDecider`, `StreamHealth` und `DowngradeRule`, und aus demselben Grund: **eine Regel, die man nicht mit einer Zahlenfolge durchspielen kann, ist nicht zu beurteilen.** | Kriterium | Punkte | |---|---| | passt zur gemerkten Signatur | **+100** | | passt zur gewünschten Sprache | +60 | | steht in der Rangliste | +50 minus Position | | `IsDefault` | +10 | | mehr Kanäle (5.1 vor Stereo) | +1 je Kanal | | sieht nach **Audiodeskription** aus | **−200** | | sieht nach **Kommentarspur** aus | −200 | Gewinnt die höchste Summe; bei Gleichstand die Spur mit der kleineren Nummer, damit dieselbe Datei immer dasselbe ergibt. **Abzug statt Ausschluss**, und das ist Absicht: gibt es eine Sprache *nur* mit Audiodeskription, ist sie immer noch besser als Stille. Ein harter Ausschluss liefe dort ins Leere. Erkannt wird an Wortmarken in `Title` und `DisplayTitle` — `audiodeskription`, `audio description`, `hörfilm`, `descriptive`, freistehendes `ad`; für Kommentare `kommentar`, `commentary`, `director`. Die Liste steht an **einer** Stelle und ist geprüft. ### Die Sprachcodes lügen — und wir fallen darauf herein Vor allem anderen ein Fund, gemessen statt vermutet. So vergleicht die App heute ([PlayerModel.swift:1399](../../../Flixy/Views/Player/PlayerModel.swift)): die ersten zwei Zeichen. ``` deu ~ de → Treffer ger ~ de → KEIN Treffer ← Jellyfin meldet sehr oft „ger" de-DE ~ de → Treffer gsw ~ de → KEIN Treffer ← Schweizerdeutsch, eigene Sprache ``` **`ger` ist die ISO-639-2/B-Form von Deutsch**, und ffmpeg schreibt sie in viele Dateien. Bei solchen Titeln greift die Spracheinstellung heute **überhaupt nicht** — lautlos, ohne dass irgendetwas darauf hindeutet. Gebraucht wird also ein richtiger Vergleich: kleinschreiben, Region abschneiden (`de-DE` → `de`), und die zwanzig Sprachen, die zwei dreibuchstabige Formen haben, über eine Tabelle zusammenführen (`ger`/`deu`, `fre`/`fra`, `dut`/`nld`, `cze`/`ces`, `gre`/`ell` …). **`gsw` bleibt `gsw`.** Schweizerdeutsch ist keine Schreibweise von Deutsch, sondern eine eigene Sprache ohne zweibuchstabigen Code. Es auf `de` abzubilden wäre bequem und falsch — wer Hochdeutsch will, bekäme Schweizerdeutsch untergeschoben. Stattdessen steht es in der Rangliste, und zwar da, wo du es hinstellst. ### Wenn die Wunschsprache fehlt: eine Rangliste Keine Zufallswahl, kein einzelner Ausweichwert, sondern eine **geordnete Liste** — „probier Deutsch, sonst Schweizerdeutsch, sonst Englisch, sonst Französisch". **Nur einmal, für alles.** Sie ist keine dritte Einstellung je Mediathek oder Serie: dort steht der *Wunsch*, die Rangliste ist der Boden darunter und gilt überall gleich. Eine Reihenfolge je Mediathek zu pflegen wäre Arbeit für einen Fall, den es nicht gibt. Sie greift **nur**, wenn der Wunsch bei diesem Titel fehlt. Hast du eine Datei mit nur Deutsch, ist nichts zu entscheiden; hast du eine mit zwölf Sprachen, entscheidet die Liste. Die vollständige Reihenfolge, die immer zu einer Antwort kommt: 1. gemerkte Signatur der Serie 2. Wunschsprache (Serie → Mediathek → allgemein) 3. die Rangliste, von oben nach unten 4. die Spur mit `IsDefault` 5. die erste Spur ohne Audiodeskription 6. die erste Spur Das Punktesystem bildet 1–3 ab; 4–6 sind der Boden darunter. ### Gemerkt wird, was man tut Wählt jemand **während einer Folge** eine andere Tonspur, wird sie als Signatur für diese Serie abgelegt. Ohne Nachfrage — die Frage „für diese Serie merken?" bei jeder Umstellung ist genau die Art Dialog, die man nach dem dritten Mal wegklickt. Sichtbar wird es trotzdem: das Spurenblatt zeigt „Für diese Serie gemerkt" mit einem Weg, es wieder zu löschen. **Eine automatische Handlung, die man nicht sehen kann, ist von einem Fehler nicht zu unterscheiden** — dasselbe Prinzip wie bei der Qualitätsautomatik. Bei Filmen wird nichts gemerkt: ein Film wird einmal gesehen. ### Wo es steht - **Einstellungen → Sprachen**: Tonsprache, die **Rangliste** (ziehbar, mit Hinzufügen und Entfernen), Untertitelsprache, und ein Schalter „Audiodeskription meiden" (an). - **Mediathek → Filter/Einstellungen**: „Tonsprache für diese Mediathek" mit „wie allgemein" als Vorgabe. - **Serie → Detailseite**: „Tonsprache für diese Serie", mit dem gemerkten Wert, falls einer da ist. Abgelegt wird alles **je Gerät** in `UserDefaults` — wie alle anderen Einstellungen auch, und wie besprochen ohne Synchronisierung. --- ## Plex Für **dieses** Stück ist die Antwort einfach: es wird Jellyfin-only gebaut. Die Auswahl steckt im neutralen Teil und würde bei Plex arbeiten, wenn dort jemals dieselben Angaben ankommen — aber geprüft wird sie nur gegen Jellyfin. **PlexKit jetzt zu entfernen, wäre eine eigene Entscheidung**, und keine kleine: gut fünftausend Zeilen, die vollständige Live-TV-Anbindung samt Programmführer und Aufnahmen, der PIN-Anmeldeweg, das Werkzeug `FlixyProbe` und rund achtzig Tests hängen daran. Das ist umkehrbar nur über die Versionsgeschichte. Vorschlag: **nicht jetzt.** Erst soll Jellyfin das können, was du brauchst; erst wenn du Plex tatsächlich abgeschaltet hast, wird ausgebaut. Solange es steht, kostet es nichts ausser dem Verzicht auf neue Plex-Funktionen — und den hast du ohnehin ausgesprochen. --- ## Was ich nicht bauen würde 1. **Keinen Proxy vor Jellyfin.** Ausdrücklich ausgeschlossen, und ich teile das: eine Schicht, die Antworten umschreibt, bricht bei jedem Server-Update anders. 2. **Keinen eigenen Server.** Monate für Anmeldung, Mediathek, Metadaten, Sitzungen — und die Sprachwahl ist davon der kleinste Teil. 3. **Keine Sprache je Genre oder Kategorie.** Du hast es selbst verworfen, und zu Recht: die Frage „welche Sprache für Dokumentationen" hat niemand. 4. **Keine Zufallswahl** als Ausweichfall. Zweimal dieselbe Folge soll zweimal dasselbe ergeben. 5. **Kein Dialog beim Umstellen.** Siehe oben. 6. **Keine Heuristik über den Inhalt** — etwa Tonspuren vergleichen, um Audiodeskription zu erkennen. Das ist Signalverarbeitung auf dem Gerät für einen Fall, den drei Wortmarken erschlagen. ## Wie geprüft wird - **`AudioTrackChooserTests`**: Spurlisten von Hand, darunter der ZDF-Fall wörtlich — deutsche Spur mit Audiodeskription, englisch betitelte deutsche Spur — und die Erwartung, dass nach einmaligem Merken die richtige kommt. - **Sprachcodes**: `ger`/`deu`/`de-DE` müssen alle auf Deutsch passen, `gsw` auf **keines** davon. Genau der Fall, der heute stillschweigend danebengeht. - Rangliste: Wunschsprache fehlt, zweite greift; keine aus der Liste vorhanden; nur Audiodeskription da; gar keine Sprachangabe; eine einzige Spur. - Gleichstand: zweimal dasselbe Ergebnis. - Gegen die **Attrappe** lässt sich eine Datei mit mehreren Spuren melden und die Auswahl im Player ansehen. - An deinem Server: eine ZDF-Folge, einmal die richtige Spur wählen, nächste Folge öffnen. ## Fertig ist es, wenn - Eine ZDF-Folge nach einmaligem Umstellen dauerhaft ohne Audiodeskription läuft. - Eine Serie auf Englisch und eine andere auf Deutsch startet, ohne dass zwischendurch etwas umgestellt wird. - Fehlt die Wunschsprache, greift die Rangliste — nachvollziehbar und jedes Mal gleich. - Eine Datei, die ihre Tonspur `ger` nennt, wird endlich als Deutsch erkannt. - Was die App automatisch gemerkt hat, ist im Spurenblatt zu sehen und zu löschen.