Phase 2: Transcoding, adaptive Bitrate, Spuren, Marker, Sync

Der Decider brauchte keine Änderung — nur eine andere Richtlinie.
Genau dafür war er gebaut.

Transcoding
- TranscodeRequest baut die Parameter für /video/:/transcode/universal.
  directStream=1 lässt Plex nur umpacken, wenn der Bildcodec passt,
  statt pauschal neu zu kodieren.
- Vor dem Start wird der Server gefragt (decision); sagt er nein, steht
  der Grund im Klartext da statt eines schwarzen Bildes.
- Beim Verlassen wird der Transcoder angehalten. Ohne dieses Signal
  rechnet der Server minutenlang für niemanden weiter.
- Die adaptive Bitrate kommt mit HLS: AVPlayer wechselt sie selbst.

Qualitätseinstellungen
- Getrennt für WLAN und Mobilfunk, fünf spürbare Stufen.
  Voreinstellung: zuhause Original, unterwegs 4 Mbit.
- NetworkConditions erkennt Mobilfunk über isExpensive — das deckt auch
  den Hotspot ab, der technisch WLAN ist und trotzdem Volumen kostet.

Spuren und Marken
- Ton- und Untertitelwahl im Player, bevorzugte Sprache in den
  Einstellungen, nachsichtiger Sprachvergleich (de/deu/ger/de-DE).
- Intro- und Abspann-Marken mit Überspringen-Knopf, optional
  automatisch. Bereits übersprungene Marken werden gemerkt, sonst käme
  man nach einem Rücksprung nie ins Intro zurück.
- Nächste Folge inkl. Staffelwechsel; Specials in Staffel 0 werden
  nicht vorgezogen.

Fortschritt
- Alle zehn Sekunden an den Server, plus Schlussmeldung beim Verlassen.
  Erst die nimmt den Titel aus „wird gerade abgespielt" heraus.
- markWatched/markUnwatched/rate/refreshLibrary stehen bereit.

86 Tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-09-11 17:24:17 +02:00
co-authored by Claude Opus 5
parent d0a84f35de
commit 55bcfe2fbf
13 changed files with 1512 additions and 53 deletions
+337
View File
@@ -1839,6 +1839,343 @@
}
}
}
},
"player.tracks": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Ton und Untertitel"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Audio and subtitles"
}
}
}
},
"player.audioTracks": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Tonspur"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Audio"
}
}
}
},
"player.subtitleTracks": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Untertitel"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Subtitles"
}
}
}
},
"player.subtitlesOff": {
"comment": "Eintrag, der die Untertitel abschaltet",
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Aus"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Off"
}
}
}
},
"player.skipIntro": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Intro überspringen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Skip intro"
}
}
}
},
"player.skipCredits": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Abspann überspringen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Skip credits"
}
}
}
},
"player.nextEpisode": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Nächste Folge"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Next episode"
}
}
}
},
"player.transcodeRefused": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Der Server hat die Wiedergabe abgelehnt."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "The server refused playback."
}
}
}
},
"settings.quality": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Qualität"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Quality"
}
}
}
},
"settings.qualityWifi": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Im WLAN"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "On Wi-Fi"
}
}
}
},
"settings.qualityCellular": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Über Mobilfunk"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "On cellular"
}
}
}
},
"settings.qualityExplanation": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Wird eine Datei größer als die eingestellte Grenze, rechnet der Server sie unterwegs herunter und passt die Bitrate laufend an die Verbindung an."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "If a file exceeds the limit, the server transcodes it on the fly and adapts the bitrate to your connection."
}
}
}
},
"settings.playback": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Wiedergabe"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Playback"
}
}
}
},
"settings.autoSkipIntro": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Intro automatisch überspringen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Skip intros automatically"
}
}
}
},
"settings.autoSkipCredits": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Abspann automatisch überspringen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Skip credits automatically"
}
}
}
},
"settings.autoPlayNext": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Nächste Folge automatisch"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Play next episode automatically"
}
}
}
},
"quality.original": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Original"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Original"
}
}
}
},
"quality.high": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Hoch (12 Mbit/s)"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "High (12 Mbps)"
}
}
}
},
"quality.medium": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Mittel (8 Mbit/s)"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Medium (8 Mbps)"
}
}
}
},
"quality.low": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Niedrig (4 Mbit/s)"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Low (4 Mbps)"
}
}
}
},
"quality.minimal": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Sparsam (2 Mbit/s)"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Data saver (2 Mbps)"
}
}
}
}
},
"version": "1.1"