Watchdog heisst Watchdog, Engine heisst Engine
Eingedeutschte Fachbegriffe in den Kommentaren — „Wachhund" für Watchdog, „Motor" für Engine. Das liest sich albern und ist unklarer als das Original; niemand sagt Wachhund, wenn er einen Watchdog meint. Acht Stellen berichtigt. Gewöhnliche Sprache bleibt deutsch, der Stil der Kommentare ändert sich nicht. Dazu die Plex-Leiter messbar gemacht: `--leiter` baut dieselbe Anfrage zweimal, mit und ohne `autoAdjustQuality=1`, und zählt die Stufen. Die Zeile steht seit dem Umbau im Code und war nie geprüft — genau die Art ungeprüfter Annahme über Serververhalten, die bei Jellyfin vier Runden gekostet hat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
314c1a3bfc
commit
e324a474fd
@@ -847,7 +847,7 @@ final class PlayerModel {
|
|||||||
|
|
||||||
/// Führt Buch über das Stocken — die **zweite** Uhr.
|
/// Führt Buch über das Stocken — die **zweite** Uhr.
|
||||||
///
|
///
|
||||||
/// Der Wachhund darunter ist ein Totmann: vierzig Sekunden am Stück ohne
|
/// Der Watchdog darunter ist ein Totmann: vierzig Sekunden am Stück ohne
|
||||||
/// Daten, dann Schluss. Er setzt sich bei jedem kurzen Erholen zurück,
|
/// Daten, dann Schluss. Er setzt sich bei jedem kurzen Erholen zurück,
|
||||||
/// und genau das ist sein blinder Fleck: zehn Rückler à dreißig Sekunden
|
/// und genau das ist sein blinder Fleck: zehn Rückler à dreißig Sekunden
|
||||||
/// lösen ihn nie aus, obwohl die halbe Stunde unbrauchbar war.
|
/// lösen ihn nie aus, obwohl die halbe Stunde unbrauchbar war.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Foundation
|
|||||||
/// Der billige Hebel ist `preferredPeakBitRate`: er wirkt ohne Neuaufbau.
|
/// Der billige Hebel ist `preferredPeakBitRate`: er wirkt ohne Neuaufbau.
|
||||||
/// Wenn er nichts ausrichtet — weil die Playlist nur eine Stufe hat oder weil
|
/// Wenn er nichts ausrichtet — weil die Playlist nur eine Stufe hat oder weil
|
||||||
/// schon die unterste läuft —, bleibt nur der Neuaufbau mit kleinerer Bitrate:
|
/// schon die unterste läuft —, bleibt nur der Neuaufbau mit kleinerer Bitrate:
|
||||||
/// Transcoder anhalten, Motor abreißen, neu aushandeln, zurückspringen. Das
|
/// Transcoder anhalten, Engine abreißen, neu aushandeln, zurückspringen. Das
|
||||||
/// sind Sekunden mit schwarzem Bild.
|
/// sind Sekunden mit schwarzem Bild.
|
||||||
///
|
///
|
||||||
/// **Ein Notnagel, keine Regelschleife.** Zu oft ausgelöst erzeugt er genau
|
/// **Ein Notnagel, keine Regelschleife.** Zu oft ausgelöst erzeugt er genau
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public struct PlaybackDecision: Sendable, Equatable {
|
|||||||
switch method {
|
switch method {
|
||||||
case .directPlay(let engine): engine
|
case .directPlay(let engine): engine
|
||||||
// Der Transcoder liefert HLS, und damit ist AVPlayer der richtige
|
// Der Transcoder liefert HLS, und damit ist AVPlayer der richtige
|
||||||
// Motor. **Nicht** aber, wie hier früher stand, „inklusive
|
// Engine. **Nicht** aber, wie hier früher stand, „inklusive
|
||||||
// automatischem Bitratenwechsel": den gibt es nur, wenn die Playlist
|
// automatischem Bitratenwechsel": den gibt es nur, wenn die Playlist
|
||||||
// mehrere Stufen führt, und das muss ausdrücklich bestellt werden.
|
// mehrere Stufen führt, und das muss ausdrücklich bestellt werden.
|
||||||
case .transcode: .avPlayer
|
case .transcode: .avPlayer
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Foundation
|
|||||||
|
|
||||||
/// Buch über das Stocken, mit gleitendem Fenster.
|
/// Buch über das Stocken, mit gleitendem Fenster.
|
||||||
///
|
///
|
||||||
/// **Warum es das gibt.** Der Wachhund im Player kannte nur eine Frage: steht
|
/// **Warum es das gibt.** Der Watchdog im Player kannte nur eine Frage: steht
|
||||||
/// es seit vierzig Sekunden am Stück? Bei jedem kurzen Erholen setzte er sich
|
/// es seit vierzig Sekunden am Stück? Bei jedem kurzen Erholen setzte er sich
|
||||||
/// zurück — zehn Rückler à dreißig Sekunden lösten nichts aus, obwohl die
|
/// zurück — zehn Rückler à dreißig Sekunden lösten nichts aus, obwohl die
|
||||||
/// halbe Stunde unbrauchbar war. Genau dieser Fall ist der, über den geklagt
|
/// halbe Stunde unbrauchbar war. Genau dieser Fall ist der, über den geklagt
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public final class AVPlayerEngine: VideoPlayerEngine {
|
|||||||
teardownObservers()
|
teardownObservers()
|
||||||
state = .loading
|
state = .loading
|
||||||
|
|
||||||
// Die Buchführung gehört zur Quelle, nicht zum Motor: ein neuer Titel
|
// Die Buchführung gehört zur Quelle, nicht zur Engine: ein neuer Titel
|
||||||
// fängt bei null an, sonst schleppte die Zahl den vorigen Film mit.
|
// fängt bei null an, sonst schleppte die Zahl den vorigen Film mit.
|
||||||
variantBitrates = []
|
variantBitrates = []
|
||||||
wantsToPlay = false
|
wantsToPlay = false
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public struct PlaybackSource: Sendable, Equatable {
|
|||||||
/// wackelige Leitung ist es zu wenig: der Systemwert ist auf schnellen
|
/// wackelige Leitung ist es zu wenig: der Systemwert ist auf schnellen
|
||||||
/// Start ausgelegt, nicht darauf, einen Aussetzer zu überstehen.
|
/// Start ausgelegt, nicht darauf, einen Aussetzer zu überstehen.
|
||||||
///
|
///
|
||||||
/// **Wer das entscheidet, muss mehr wissen als der Motor.** Ob es ein
|
/// **Wer das entscheidet, muss mehr wissen als die Engine.** Ob es ein
|
||||||
/// Sender ist, ob die Datei lokal liegt — das weiß der Player, nicht die
|
/// Sender ist, ob die Datei lokal liegt — das weiß der Player, nicht die
|
||||||
/// Engine. Deshalb reist die Zahl mit der Quelle, statt dass die Engine
|
/// Engine. Deshalb reist die Zahl mit der Quelle, statt dass die Engine
|
||||||
/// rät.
|
/// rät.
|
||||||
|
|||||||
@@ -150,6 +150,42 @@ let firstMovie = await { () async -> PlexItem? in
|
|||||||
return try? await server.items(inLibrary: movieLibrary, limit: 1).items.first
|
return try? await server.items(inLibrary: movieLibrary, limit: 1).items.first
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// MARK: - Die Leiter bei Plex
|
||||||
|
|
||||||
|
// Dieselbe Frage wie bei Jellyfin, und aus demselben Grund gestellt: bei Plex
|
||||||
|
// steht `autoAdjustQuality=1` im Code, und ob sein Transcoder daraufhin
|
||||||
|
// mehrere Stufen liefert, war nie geprüft. Eine ungeprüfte Annahme über
|
||||||
|
// Serververhalten hat uns bei Jellyfin vier Runden gekostet.
|
||||||
|
if CommandLine.arguments.contains("--leiter") {
|
||||||
|
guard let movie = firstMovie else {
|
||||||
|
print("Keine Datei zum Prüfen gefunden.")
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
print("Leiter-Probe mit: \(movie.title)\n")
|
||||||
|
|
||||||
|
let ohne = TranscodeRequest(
|
||||||
|
ratingKey: movie.ratingKey,
|
||||||
|
maximumBitrate: 8_000,
|
||||||
|
isLocal: connection.local
|
||||||
|
)
|
||||||
|
let mit = ohne.askingForLadder()
|
||||||
|
|
||||||
|
for (name, anfrage) in [("ohne autoAdjustQuality", ohne), ("mit autoAdjustQuality=1", mit)] {
|
||||||
|
print("=== \(name) ===")
|
||||||
|
guard let url = server.transcodeURL(for: anfrage) else {
|
||||||
|
print(" Keine Adresse zu bauen.\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
print(await prüfePlaylist(url))
|
||||||
|
print()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aufräumen: beide Anfragen haben am Server einen Transcoder angeworfen.
|
||||||
|
await server.stopTranscode(sessionIdentifier: ohne.sessionIdentifier)
|
||||||
|
print("Transcoder angehalten.")
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
if let movie = firstMovie {
|
if let movie = firstMovie {
|
||||||
let request = TranscodeRequest(
|
let request = TranscodeRequest(
|
||||||
ratingKey: movie.ratingKey,
|
ratingKey: movie.ratingKey,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public struct TranscodeRequest: Sendable, Equatable {
|
|||||||
/// Dieselbe Sitzungskennung: es ist **eine** Wiedergabe, und der Server
|
/// Dieselbe Sitzungskennung: es ist **eine** Wiedergabe, und der Server
|
||||||
/// soll sie nicht für zwei halten — sonst bliebe beim Aufräumen ein
|
/// soll sie nicht für zwei halten — sonst bliebe beim Aufräumen ein
|
||||||
/// Transcoder stehen.
|
/// Transcoder stehen.
|
||||||
func askingForLadder() -> TranscodeRequest {
|
public func askingForLadder() -> TranscodeRequest {
|
||||||
TranscodeRequest(
|
TranscodeRequest(
|
||||||
ratingKey: ratingKey,
|
ratingKey: ratingKey,
|
||||||
mediaIndex: mediaIndex,
|
mediaIndex: mediaIndex,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Foundation
|
|||||||
struct StallLedgerTests {
|
struct StallLedgerTests {
|
||||||
/// Der Fall, wegen dem es den Typ gibt.
|
/// Der Fall, wegen dem es den Typ gibt.
|
||||||
///
|
///
|
||||||
/// Zehn Rückler à dreißig Sekunden lösten beim alten Wachhund nichts aus,
|
/// Zehn Rückler à dreißig Sekunden lösten beim alten Watchdog nichts aus,
|
||||||
/// weil er sich bei jedem Erholen zurücksetzte. Hier muss sichtbar
|
/// weil er sich bei jedem Erholen zurücksetzte. Hier muss sichtbar
|
||||||
/// werden, dass die Wiedergabe unbrauchbar ist.
|
/// werden, dass die Wiedergabe unbrauchbar ist.
|
||||||
@Test("Viele kurze Rückler bleiben sichtbar")
|
@Test("Viele kurze Rückler bleiben sichtbar")
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ extension VLCPlayerEngine: VLCMediaPlayerDelegate {
|
|||||||
/// Aufzählung führt nur `opening`, `playing`, `paused`, `stopped` und
|
/// Aufzählung führt nur `opening`, `playing`, `paused`, `stopped` und
|
||||||
/// `error`. Weil diese Methode bisher fehlte, ging der Zustand
|
/// `error`. Weil diese Methode bisher fehlte, ging der Zustand
|
||||||
/// `.buffering` auf dem VLC-Weg **nie** an — und damit löste der
|
/// `.buffering` auf dem VLC-Weg **nie** an — und damit löste der
|
||||||
/// Wachhund im Player dort nie aus. Ein hängender Strom lief stumm ins
|
/// Watchdog im Player dort nie aus. Ein hängender Strom lief stumm ins
|
||||||
/// Nichts, ohne Kreisel, ohne Meldung, ohne Abbruch.
|
/// Nichts, ohne Kreisel, ohne Meldung, ohne Abbruch.
|
||||||
///
|
///
|
||||||
/// Nur aus dem Spielen heraus gewertet. Die Dokumentation sagt, dass vor
|
/// Nur aus dem Spielen heraus gewertet. Die Dokumentation sagt, dass vor
|
||||||
|
|||||||
Reference in New Issue
Block a user