From 5657cd9e4becbba500c864196c705e066c2052c8 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Sat, 10 Oct 2026 21:01:35 +0200 Subject: [PATCH] =?UTF-8?q?Der=20Sprung=20ging=20ins=20Leere,=20und=20die?= =?UTF-8?q?=20Pr=C3=BCfung=20dagegen=20griff=20nie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nach vorn ziehen, Regler springt zurück. Im Pausieren nicht — dort wuchs die Abspielliste weiter und holte die Stelle irgendwann ein. Der Spieler sollte einen Sprung ausserhalb des Stroms daran erkennen, dass er hinter dessen Ende liegt. Das Ende stand in `streamEnd`, und das wird gesetzt, wenn der Player eine Dauer meldet — was er bei einer wachsenden Liste nie tut. `streamEnd` blieb also nichts, jeder Sprung galt als innerhalb, AVPlayer bekam ein Ziel ohne Schnipsel und verwarf es. Gefragt wird jetzt der Vorrat: so weit, wie Daten da sind, springt der Spieler selbst; darüber hinaus wird der Strom neu gebaut. Weiss niemand, wie weit es reicht, wird ebenfalls neu gebaut — ein neuer Strom dauert ein paar Sekunden, ein Sprung, der nichts tut, ist kaputt. Entschieden wird vor dem Aufräumen: `seek` verwirft den Vorrat, und genau an dem hängt die Antwort. Co-Authored-By: Claude Opus 5 --- Flaro/Views/Player/PlayerModel.swift | 36 +++++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Flaro/Views/Player/PlayerModel.swift b/Flaro/Views/Player/PlayerModel.swift index aa8d8d7..b46327b 100644 --- a/Flaro/Views/Player/PlayerModel.swift +++ b/Flaro/Views/Player/PlayerModel.swift @@ -1549,6 +1549,10 @@ final class PlayerModel { // Der Sprung **ist** angekommen, in dem Moment, in dem man ihn // auslöst. Alles Weitere ist Warten auf Daten, und dafür gibt es den // Kreisel. + // **Vor dem Aufräumen entscheiden.** Die Antwort hängt daran, wie + // weit der Vorrat reicht — und der wird gleich verworfen. + let neuerStrom = ausserhalbDesStroms(time) + currentTime = time seekTarget = time // Der Vorrat von vorhin gilt für die alte Stelle. Ihn stehen zu lassen @@ -1566,7 +1570,7 @@ final class PlayerModel { // der Spieler bliebe mit einem Kreisel stehen. Also wird der Strom // neu aufgebaut — `restart` steigt bei `currentTime` wieder ein, und // das ist genau die Stelle, die eben gesetzt wurde. - if ausserhalbDesStroms(time) { + if neuerStrom { Task { await restart() } return } @@ -1580,18 +1584,32 @@ final class PlayerModel { /// neue Sitzung zu starten hiesse, Sekunden zu warten, um fünf Sekunden /// zurückzugehen. private func ausserhalbDesStroms(_ time: Duration) -> Bool { - // Ein Strom ohne Vorlauf und ohne bekanntes Ende ist eine ganze - // Datei: dort springt der Spieler überall hin. - if streamOffset == .zero, streamEnd == nil { return false } + // **Eine Datei mit bekannter Länge: überallhin.** `streamEnd` steht + // nur, wenn der Player eine Dauer ermitteln konnte, und das kann er + // genau dann, wenn das Ganze schon dasteht — eine Mediendatei oder + // eine fertige Abspielliste. + if streamEnd != nil, streamOffset == .zero { return false } + // Vor dem Anfang des Stroms gibt es in ihm nichts. if time < streamOffset { return true } - // **Eine halbe Sekunde Nachsicht.** Das Ende der Liste und das Ende - // des Erzeugten gehen um ein Stück auseinander; genau an der Kante - // einen neuen Strom zu bauen wäre Aufwand für nichts. - if let ende = streamEnd, time > ende + .milliseconds(500) { return true } + // **Eine wachsende Liste reicht so weit, wie Daten da sind.** + // + // Hier stand ein Vergleich mit `streamEnd`, und der ging nie auf: + // bei einer wachsenden Liste bleibt die Dauer unbestimmt, also ist + // `streamEnd` nichts, und jeder Sprung galt als innerhalb. AVPlayer + // bekam ein Ziel, zu dem es keine Schnipsel gibt, verwarf es, und + // der Regler sprang zurück — beim Ziehen sichtbar, im Pausieren + // nicht, weil die Liste dort weiterwuchs und ihn irgendwann einholte. + // + // **Weiss niemand, wie weit es reicht, wird neu gebaut.** Ein neuer + // Strom dauert ein paar Sekunden; ein Sprung, der nichts tut, ist + // kaputt. + guard let bis = bufferedUntil else { return true } - return false + // Eine halbe Sekunde Nachsicht an der Kante: dort einen neuen Strom + // zu bauen wäre Aufwand für nichts. + return time > bis + .milliseconds(500) } /// Springt relativ zur aktuellen Stelle — für die ±10-Sekunden-Knöpfe.