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.