From efed8717a33ae42be01bbd66ab2305cb43a6f29f Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Sun, 27 Sep 2026 18:30:10 +0200 Subject: [PATCH] =?UTF-8?q?=E2=80=9EAuto"=20gibt=20nicht=20mehr=20auf,=20e?= =?UTF-8?q?s=20versucht=20es=20kleiner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Fehlstart im Zug hat den eigentlichen Mangel gezeigt: die ganze neue Regelung misst **ab dem ersten Bild**. Kommt nie eines, misst sie nichts, greift nichts — und „Auto" hat sich als das erwiesen, was es wörtlich heisst: „nimm, was in den Einstellungen steht". Steht dort „Original", bittet die App über eine Zugverbindung um eine 4K-Datei und wartet vierzig Sekunden auf etwas, das nie kommen kann. Statt aufzugeben geht der Watchdog jetzt eine Sprosse tiefer und baut neu auf — bei Filmen über `restart()`, bei Sendern über den Tuner-Abbau. Gezählt gegen dasselbe Budget wie die Sicherheitsleine, sonst schickt eine tote Leitung die App endlos im Kreis. Scheitert auch das, nennt die Meldung jetzt den Grund und den Weg statt nur „keine Daten mehr": wer ohne Grenze angefragt hat, soll erfahren, dass es daran liegt und wo es sich ändern lässt. Und „Strom" heisst Stream. Zweiunddreissig Stellen, dazu das Gedächtnis ergänzt. Co-Authored-By: Claude Opus 5 --- Flixy/Resources/Localizable.xcstrings | 21 +++++- Flixy/Views/Player/PlayerModel.swift | 71 +++++++++++++++---- .../FlixyPlayback/Decision/StallLedger.swift | 2 +- .../FlixyPlayback/Decision/StreamHealth.swift | 6 +- .../FlixyPlayback/Engine/AVPlayerEngine.swift | 2 +- .../Engine/VideoPlayerEngine.swift | 2 +- .../FlixyKit/Sources/FlixyProbe/Leiter.swift | 4 +- .../JellyfinKit/JellyfinBackend+LiveTV.swift | 2 +- .../JellyfinBackend+Playback.swift | 2 +- .../Sources/JellyfinKit/JellyfinBackend.swift | 2 +- .../Sources/MediaKit/MediaPlayback.swift | 2 +- .../PlexKit/Endpoints/PlexServer+LiveTV.swift | 4 +- .../Sources/PlexKit/PlexBackend.swift | 2 +- .../DowngradeRuleTests.swift | 2 +- .../StreamHealthTests.swift | 2 +- .../Sources/FlixyVLC/VLCPlayerEngine.swift | 4 +- web/README.md | 2 +- 17 files changed, 98 insertions(+), 34 deletions(-) diff --git a/Flixy/Resources/Localizable.xcstrings b/Flixy/Resources/Localizable.xcstrings index 17025d0..c6b3018 100644 --- a/Flixy/Resources/Localizable.xcstrings +++ b/Flixy/Resources/Localizable.xcstrings @@ -3499,7 +3499,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Es kommen keine Daten mehr. Der Strom ist abgerissen." + "value" : "Es kommen keine Daten mehr. Der Stream ist abgerissen." } }, "en" : { @@ -3510,6 +3510,23 @@ } } }, + "player.stalledUnlimited" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Es kommen keine Daten mehr. Die Qualität steht auf „Original\", der Server überträgt also die Datei unverändert — dafür reicht diese Verbindung nicht. Unter Einstellungen → Wiedergabe eine kleinere Stufe wählen." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No more data is arriving. Quality is set to “Original”, so the server sends the file unchanged — this connection cannot carry that. Pick a smaller step under Settings → Playback." + } + } + } + }, "player.stop" : { "localizations" : { "de" : { @@ -3768,7 +3785,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Dieser Strom hat nur eine Stufe — es gibt nichts, worauf der Player ausweichen könnte. Bei Rücklern hilft hier nur eine kleinere Qualität von Hand." + "value" : "Dieser Stream hat nur eine Stufe — es gibt nichts, worauf der Player ausweichen könnte. Bei Rücklern hilft hier nur eine kleinere Qualität von Hand." } }, "en" : { diff --git a/Flixy/Views/Player/PlayerModel.swift b/Flixy/Views/Player/PlayerModel.swift index ed64410..926c82c 100644 --- a/Flixy/Views/Player/PlayerModel.swift +++ b/Flixy/Views/Player/PlayerModel.swift @@ -91,7 +91,7 @@ final class PlayerModel { /// Die eingestellte Stufe in zwei bis fünf Zeichen. /// /// Steht auf dem Knopf im Player. „Automatisch" heißt dabei: was gerade - /// tatsächlich ankommt — bei einem HLS-Strom entscheidet der Player selbst, + /// tatsächlich ankommt — bei einem HLS-Stream entscheidet der Player selbst, /// und ihn danach zu fragen ist ehrlicher, als „Auto" hinzuschreiben und /// die Antwort schuldig zu bleiben. var qualityLabel: String { @@ -177,7 +177,7 @@ final class PlayerModel { /// Wacht darüber, dass aus „lädt" nicht „lädt für immer" wird. @ObservationIgnored private var bufferWatchdog: Task? - /// Wie viel Vorrat bei einem Strom über das Netz angelegt wird. + /// Wie viel Vorrat bei einem Stream über das Netz angelegt wird. /// /// **Nur für Filme und Folgen, nicht für Sender und nicht für Dateien.** /// Ein laufender Sender soll nah am Jetzt bleiben — ein halbminütiger @@ -190,7 +190,7 @@ final class PlayerModel { /// gedrosselten Leitung ermittelt. private static let forwardBuffer: Duration = .seconds(25) - /// Wie oft der Zustand des Stroms geprüft wird. + /// Wie oft der Zustand des Streams geprüft wird. /// /// Einmal je Sekunde: fein genug, dass ein schrumpfender Puffer auffällt, /// bevor er leer ist, und grob genug, dass es nichts kostet. @@ -202,7 +202,7 @@ final class PlayerModel { /// kostet Schärfe, ein falscher nach oben einen Rückler. private static let stepUpCooldown: Duration = .seconds(60) - /// Der Zustand des Stroms, fortlaufend beurteilt. + /// Der Zustand des Streams, fortlaufend beurteilt. @ObservationIgnored private var health = StreamHealth() @ObservationIgnored private var healthTask: Task? /// Wann zuletzt eine Stufe höher gegangen wurde. @@ -357,7 +357,7 @@ final class PlayerModel { // Die zuletzt gewählte Stufe, falls sie gemerkt werden soll. **Vor** // der Entscheidung, nicht danach: hinterher umzustellen hieße, den - // Strom zweimal aufzubauen und den Anfang zweimal zu puffern. + // Stream zweimal aufzubauen und den Anfang zweimal zu puffern. if let stored = settings.rememberedQuality, let restored = PlayerQuality.restored(from: stored, forSourceHeight: media.height) { quality = restored @@ -406,7 +406,7 @@ final class PlayerModel { await restart() } - /// Baut den Strom mit der **aktuell geltenden** Richtlinie neu auf. + /// Baut den Stream mit der **aktuell geltenden** Richtlinie neu auf. /// /// Geteilt zwischen der Wahl von Hand und der Sicherheitsleine — der /// Ablauf ist derselbe, nur der Anlass nicht. Was sich unterscheidet, @@ -549,7 +549,7 @@ final class PlayerModel { diagnostics.note("Engine gestartet") // Weder offline noch live gibt es einen Fortschritt zu melden. if !isOffline, !isLive { startReporting() } - // Den Zustand des Stroms dagegen auch bei Live beobachten: dort + // Den Zustand des Streams dagegen auch bei Live beobachten: dort // hakt es am ehesten, und der billige Hebel kostet nichts. startHealthWatch() } catch { @@ -617,7 +617,7 @@ final class PlayerModel { // MARK: - Die Qualität selbst nachregeln - /// Beobachtet den Strom und passt die Obergrenze an. + /// Beobachtet den Stream und passt die Obergrenze an. /// /// Läuft nur bei „automatisch". Eine ausdrücklich gewählte Stufe ist eine /// Ansage und wird nicht überstimmt — `automatic` ist die Erlaubnis @@ -662,7 +662,7 @@ final class PlayerModel { // MARK: - Die Sicherheitsleine - /// Prüft, ob der Strom neu aufgebaut werden muss — und tut es. + /// Prüft, ob der Stream neu aufgebaut werden muss — und tut es. private func considerTheHardWay( _ condition: StreamCondition, statistics: PlaybackStatistics, @@ -699,7 +699,7 @@ final class PlayerModel { } } - /// Baut den Strom mit kleinerer Bitrate neu auf. + /// Baut den Stream mit kleinerer Bitrate neu auf. private func downgradeTheHardWay(at now: Duration) async { guard let ziel = nextLowerRung() else { hasGivenUp = true @@ -719,6 +719,31 @@ final class PlayerModel { } } + /// Ein zweiter Versuch mit kleinerer Bitrate, bevor aufgegeben wird. + /// + /// Gibt `true` zurück, wenn es einen gab. Zählt gegen dasselbe Budget wie + /// die Sicherheitsleine — sonst könnte eine tote Leitung die App endlos + /// im Kreis schicken. + private func retrySmaller() async -> Bool { + guard quality == .automatic, + downgradesUsed < downgradeBudget, + let ziel = nextLowerRung() + else { return false } + + automaticCeiling = ziel + downgradesUsed += 1 + diagnostics.note("Nichts kam an — neuer Versuch mit höchstens \(ziel) kbit") + + if isLive { + await retuneLive(to: ziel) + } else { + await restart() + } + // Ist der Neuaufbau selbst gescheitert, steht die Meldung schon da. + if case .failed = phase { return false } + return true + } + /// Die nächste Sprosse unterhalb der aktuellen — aus **unserer** Leiter. /// /// Nicht aus der Playlist: die hat in diesem Fall gerade keine, sonst @@ -914,11 +939,33 @@ final class PlayerModel { try? await Task.sleep(for: .seconds(40)) guard !Task.isCancelled, let self, self.isBuffering else { return } - diagnostics.note("Seit 40 s keine Daten — abgebrochen") + diagnostics.note("Seit 40 s keine Daten") + // **Auch das ist ein Beleg**, und ein stärkerer als ein paar + // Rückler: hier kam überhaupt nichts an. Ohne diese Zeile bliebe + // der Hinweis in den Einstellungen aus, weil das Rücklerbuch erst + // ab dem ersten Bild zählt — und das gab es nie. + settings.lastPlaybackStruggled = true + + // **Erst kleiner versuchen, dann aufgeben.** + // + // Hier lag der eigentliche Fehler: die ganze Regelung misst ab + // dem ersten Bild. Kommt nie eines, misst sie nichts, greift + // nichts, und „Auto" hat sich als das erwiesen, was es hiess — + // „nimm, was in den Einstellungen steht". Steht dort „Original", + // bittet die App über eine Zugverbindung um eine 4K-Datei und + // wartet vierzig Sekunden auf etwas, das nie kommen kann. + if await self.retrySmaller() { return } // Den Engine gleich stilllegen: er würde sonst weiter an einem // toten Stream ziehen, und bei Live-TV bliebe der Tuner belegt. silence() - phase = .failed(message: String(localized: "player.stalled")) + // Wer ohne Grenze angefragt hat, bekommt den Grund dazu. „Der + // Stream ist abgerissen" ist wahr und führt nirgendwohin; die + // Einstellung zu nennen ist der Unterschied zwischen einer + // Meldung und einer Hilfe. + let ohneGrenze = quality == .automatic && effectivePolicy.maximumBitrate == nil + phase = .failed(message: String( + localized: ohneGrenze ? "player.stalledUnlimited" : "player.stalled" + )) Task { await self.releaseOnServer() } } } diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift b/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift index 37deacb..5489509 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift +++ b/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift @@ -6,7 +6,7 @@ import Foundation /// 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 /// halbe Stunde unbrauchbar war. Genau dieser Fall ist der, über den geklagt -/// wird: nicht der tote Strom, sondern der, der immer wieder hakt. +/// wird: nicht der tote Stream, sondern der, der immer wieder hakt. /// /// **Warum als eigener Typ.** Keine Uhr, kein AVFoundation, kein Netz — die /// Zeiten kommen von außen herein. Damit lässt sich eine Folge von Rücklern diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift b/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift index df3f4b1..af9955f 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift +++ b/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift @@ -1,6 +1,6 @@ import Foundation -/// Eine Probe vom laufenden Strom. +/// Eine Probe vom laufenden Stream. /// /// Alle Zeiten **seit Beginn dieser Wiedergabe**, nicht als Datum — dasselbe /// wie beim `StallLedger`, und aus demselben Grund: eine Systemuhr, die sich @@ -31,7 +31,7 @@ public struct StreamSample: Sendable, Equatable { } } -/// Wie es dem Strom geht. +/// Wie es dem Stream geht. public enum StreamCondition: Sendable, Equatable { /// Trägt. Es darf wieder eine Stufe höher gehen. case healthy @@ -41,7 +41,7 @@ public enum StreamCondition: Sendable, Equatable { case failing } -/// Beurteilt den Strom aus einer Folge von Proben. +/// Beurteilt den Stream aus einer Folge von Proben. /// /// **Warum als reiner Typ.** Kein AVFoundation, keine Uhr, kein Netz — Proben /// hinein, Urteil heraus. Dieselbe Bauform wie `PlaybackDecider`, und aus diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift b/Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift index 747f8fc..c26f1cc 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift +++ b/Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift @@ -76,7 +76,7 @@ public final class AVPlayerEngine: VideoPlayerEngine { /// /// Aus `playbackStalledNotification` und **nicht** aus dem /// Zugriffsprotokoll: die Meldung kommt bei jeder Quelle, das Protokoll - /// nur bei Strömen über das Netz. Beides zu addieren zählte doppelt. + /// nur bei Streamsn über das Netz. Beides zu addieren zählte doppelt. private var stallCount = 0 /// Aufsummierte Wartezeit. Siehe `noteStall(from:to:)`. private var accumulatedStall: Duration = .zero diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift b/Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift index d8d1fdd..bd3c2bf 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift +++ b/Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift @@ -17,7 +17,7 @@ public struct PlaybackSource: Sendable, Equatable { /// Wie viel Vorrat der Player anlegen soll. /// /// `nil` überlässt es dem System. Das ist für eine Datei auf der Platte - /// richtig und für einen Sender richtig — bei einem Strom über eine + /// richtig und für einen Sender richtig — bei einem Stream über eine /// wackelige Leitung ist es zu wenig: der Systemwert ist auf schnellen /// Start ausgelegt, nicht darauf, einen Aussetzer zu überstehen. /// diff --git a/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift b/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift index 7b2e9ef..bee29b0 100644 --- a/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift +++ b/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift @@ -369,7 +369,7 @@ func erklärungWarumKeineLeiter() { /// **Die Playlist zu bekommen beweist aber noch nichts.** Sie ist Text und /// kostet nichts; die Datenrate steckt in den Schnipseln. Entscheidend ist /// deshalb allein, ob die Schnipsel bei kleinerer Zahl auch kleiner werden — -/// oder ob der Server stur denselben Strom ausliefert, weil die Sitzung schon +/// oder ob der Server stur denselben Stream ausliefert, weil die Sitzung schon /// läuft. Deshalb wird hier gewogen, nicht gezählt. func prüfeSelbstgebauteLeiter(master: URL, kopfzeilen: [String: String]) async { print("") @@ -401,7 +401,7 @@ func prüfeSelbstgebauteLeiter(master: URL, kopfzeilen: [String: String]) async print("") print(" Werden die Schnipsel kleiner, trägt die Idee. Bleiben sie gleich") - print(" gross, rechnet der Server trotz anderer Zahl denselben Strom —") + print(" gross, rechnet der Server trotz anderer Zahl denselben Stream —") print(" dann bringt ein selbstgebautes Menü nichts.") } diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift index 5dc619f..ca39b55 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift +++ b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift @@ -130,7 +130,7 @@ extension JellyfinBackend: LiveTVBackend { } // Kein Transcoder-Weg: dann unverändert. Manche Empfänger liefern - // bereits einen Strom, den das Gerät ohne Umrechnung versteht. + // bereits einen Stream, den das Gerät ohne Umrechnung versteht. if let url = client.url( path: "/Videos/\(channel.id)/stream", query: [ diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift index 7eff6ff..35ebb60 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift +++ b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift @@ -164,7 +164,7 @@ extension JellyfinBackend { URLQueryItem(name: "maxStreamingBitrate", value: String(bitsPerSecond)), // **Kein** `startTimeTicks`. Es gäbe zwei Stellen, die // über den Startpunkt entscheiden: der Server ließe den - // Strom dort beginnen, und der Player spränge anschließend + // Stream dort beginnen, und der Player spränge anschließend // noch einmal um dieselbe Strecke vor — bei einundzwanzig // Minuten Fortschritt landete man bei zweiundvierzig. // Gesprungen wird an genau einer Stelle, und das ist der diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift index a3570b7..83fff09 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift +++ b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift @@ -302,7 +302,7 @@ public struct JellyfinBackend: MediaBackend { /// Eine verkleinerte Fassung zum Herunterladen. /// /// **Fortlaufendes MP4, nicht HLS.** Zum Abspielen liefert Jellyfin eine - /// Abspielliste mit hunderten Schnipseln; das ist für einen Strom richtig + /// Abspielliste mit hunderten Schnipseln; das ist für einen Stream richtig /// und für eine Datei, die auf dem Gerät liegen soll, unbrauchbar. Der /// Endpunkt `/Videos/{id}/stream.mp4` gibt dieselbe Umrechnung als **eine** /// Datei heraus. diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift b/Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift index 5604a95..0d9e657 100644 --- a/Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift +++ b/Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift @@ -46,7 +46,7 @@ public struct TranscodeSettings: Sendable, Equatable { /// Ob der Server eine **Leiter** liefern soll statt einer festen Stufe. /// /// Dann enthält die Playlist mehrere Varianten, und der Player wechselt - /// zwischen ihnen, ohne dass der Strom neu aufgebaut werden muss. Die + /// zwischen ihnen, ohne dass der Stream neu aufgebaut werden muss. Die /// angegebene Bitrate bleibt dabei die **oberste** Sprosse; was darunter /// liegt, erfindet der Server. /// diff --git a/Packages/FlixyKit/Sources/PlexKit/Endpoints/PlexServer+LiveTV.swift b/Packages/FlixyKit/Sources/PlexKit/Endpoints/PlexServer+LiveTV.swift index 3adc640..e15980a 100644 --- a/Packages/FlixyKit/Sources/PlexKit/Endpoints/PlexServer+LiveTV.swift +++ b/Packages/FlixyKit/Sources/PlexKit/Endpoints/PlexServer+LiveTV.swift @@ -1010,7 +1010,7 @@ extension PlexServer { return nil } - /// Baut eine Stromadresse und ruft sie einmal ab. + /// Baut eine Stream-Adresse und ruft sie einmal ab. /// /// Getrennte Methode statt einer Hilfsfunktion in `tune`: eine solche /// Funktion greift über jede Unterbrechung hinweg auf die veränderlichen @@ -1076,7 +1076,7 @@ extension PlexServer { } } - /// Holt eine Stromadresse einmal selbst ab und sagt, was zurückkam. + /// Holt eine Stream-Adresse einmal selbst ab und sagt, was zurückkam. /// /// **Ohne Plex-Kopfzeilen**, weil AVPlayer sie ebenfalls nicht schickt. /// Mit Kopfzeilen zu prüfen hieße, etwas anderes zu prüfen als das, was diff --git a/Packages/FlixyKit/Sources/PlexKit/PlexBackend.swift b/Packages/FlixyKit/Sources/PlexKit/PlexBackend.swift index 94e77bb..edd6243 100644 --- a/Packages/FlixyKit/Sources/PlexKit/PlexBackend.swift +++ b/Packages/FlixyKit/Sources/PlexKit/PlexBackend.swift @@ -179,7 +179,7 @@ public struct PlexBackend: MediaBackend { // Wiedergabe verhindert. Plex' eigene Clients schicken ihn; welche // weitere Angabe sie dabei mitgeben, ist offen. Bis das gemessen ist, // bleibt er draußen: eine Leiter, die es vielleicht gibt, ist keinen - // Strom wert, der sicher nicht läuft. + // Stream wert, der sicher nicht läuft. // // `TranscodeRequest.adaptive` bleibt samt Tests bestehen — das // Gerüst steht, es fehlt die richtige Beschwörungsformel. diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift b/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift index d5672af..bc97701 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift +++ b/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift @@ -73,7 +73,7 @@ struct DowngradeRuleTests { #expect(DowngradeRule.verdict(facts) == .downgrade) } - @Test("Ein gesunder Strom löst nichts aus") + @Test("Ein gesunder Stream löst nichts aus") func healthyNeverTriggers() { #expect(DowngradeRule.verdict(notlage(condition: .healthy)) == .notBadEnough) } diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift b/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift index 297e6e3..ff14b3d 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift +++ b/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift @@ -2,7 +2,7 @@ import Testing import Foundation @testable import FlixyPlayback -@Suite("Zustand des Stroms") +@Suite("Zustand des Streams") struct StreamHealthTests { /// Baut eine Folge von Proben im Sekundentakt. private func lauf( diff --git a/Packages/FlixyVLC/Sources/FlixyVLC/VLCPlayerEngine.swift b/Packages/FlixyVLC/Sources/FlixyVLC/VLCPlayerEngine.swift index ef6199b..3e81891 100644 --- a/Packages/FlixyVLC/Sources/FlixyVLC/VLCPlayerEngine.swift +++ b/Packages/FlixyVLC/Sources/FlixyVLC/VLCPlayerEngine.swift @@ -21,7 +21,7 @@ public final class VLCPlayerEngine: NSObject, VideoPlayerEngine { private let player = VLCMediaPlayer() - /// Was VLC über den laufenden Strom weiß. + /// Was VLC über den laufenden Stream weiß. /// /// Bisher meldete dieser Weg gar nichts: die Standardimplementierung gibt /// `nil` zurück, und die Bitratenanzeige blieb bei VLC dauerhaft leer. @@ -227,7 +227,7 @@ extension VLCPlayerEngine: VLCMediaPlayerDelegate { /// Aufzählung führt nur `opening`, `playing`, `paused`, `stopped` und /// `error`. Weil diese Methode bisher fehlte, ging der Zustand /// `.buffering` auf dem VLC-Weg **nie** an — und damit löste der - /// Watchdog im Player dort nie aus. Ein hängender Strom lief stumm ins + /// Watchdog im Player dort nie aus. Ein hängender Stream lief stumm ins /// Nichts, ohne Kreisel, ohne Meldung, ohne Abbruch. /// /// Nur aus dem Spielen heraus gewertet. Die Dokumentation sagt, dass vor diff --git a/web/README.md b/web/README.md index 6e60d31..4a4a2ab 100644 --- a/web/README.md +++ b/web/README.md @@ -19,7 +19,7 @@ davon, wie gut das Frontend geschrieben ist: - **Herkunft.** Anfragen laufen über `/api` und damit über dieselbe Adresse wie die Seite. Kein CORS, auch nicht beim Streamen. - **Klartext und Verschlüsselung.** Läuft der Medienserver über `http` und die - Seite über `https`, blockiert der Browser den Strom. Dagegen kann keine Zeile + Seite über `https`, blockiert der Browser den Stream. Dagegen kann keine Zeile im Frontend etwas tun — ein Server davor schon. Nebenbei bleibt der Zugangsschlüssel beim Server, statt im Browser zu liegen.