diff --git a/Model/Player/PlayerModel.swift b/Model/Player/PlayerModel.swift index 7514709a..a8f433d1 100644 --- a/Model/Player/PlayerModel.swift +++ b/Model/Player/PlayerModel.swift @@ -281,8 +281,12 @@ final class PlayerModel: ObservableObject { } func upgradeToStream(_ stream: Stream, force: Bool = false) { + guard let video = currentVideo else { + return + } + if !self.stream.isNil, force || self.stream != stream { - playStream(stream, of: currentVideo!, preservingTime: true, upgrading: true) + playStream(stream, of: video, preservingTime: true, upgrading: true) } } diff --git a/Model/Watch.swift b/Model/Watch.swift index bad21ab0..45c456cc 100644 --- a/Model/Watch.swift +++ b/Model/Watch.swift @@ -1,10 +1,12 @@ import CoreData +import CoreMedia import Defaults import Foundation @objc(Watch) final class Watch: NSManagedObject, Identifiable { @Default(.watchedThreshold) private var watchedThreshold + @Default(.saveHistory) private var saveHistory } extension Watch { @@ -45,4 +47,15 @@ extension Watch { formatter.unitsStyle = .full return formatter.localizedString(for: watchedAt, relativeTo: Date()) } + + var timeToRestart: CMTime? { + finished ? nil : saveHistory ? .secondsInDefaultTimescale(stoppedAt) : nil + } + + var video: Video { + Video( + videoID: videoID, title: "", author: "", + length: 0, published: "", views: -1, channel: Channel(id: "", name: "") + ) + } } diff --git a/Shared/Player/Controls/PlayerControls.swift b/Shared/Player/Controls/PlayerControls.swift index 38d400f8..4d0b9a2a 100644 --- a/Shared/Player/Controls/PlayerControls.swift +++ b/Shared/Player/Controls/PlayerControls.swift @@ -272,6 +272,9 @@ struct PlayerControls: View { var mediumButtonsBar: some View { HStack { #if !os(tvOS) + restartVideoButton + .padding(.trailing, 15) + button("Seek Backward", systemImage: "gobackward.10", size: 30, cornerRadius: 5) { player.backend.seek(relative: .secondsInDefaultTimescale(-10)) } @@ -314,12 +317,28 @@ struct PlayerControls: View { .keyboardShortcut("l", modifiers: []) .keyboardShortcut(KeyEquivalent.rightArrow, modifiers: []) #endif + + advanceToNextItemButton + .padding(.leading, 15) #endif } .font(.system(size: 20)) .padding(.horizontal, 4) } + private var restartVideoButton: some View { + button("Restart video", systemImage: "backward.end.fill", size: 30, cornerRadius: 5) { + player.backend.seek(to: 0.0) + } + } + + private var advanceToNextItemButton: some View { + button("Next", systemImage: "forward.fill", size: 30, cornerRadius: 5) { + player.advanceToNextItem() + } + .disabled(player.queue.isEmpty) + } + var bottomBar: some View { HStack { Text(model.playbackTime) diff --git a/Shared/Views/VideoContextMenuView.swift b/Shared/Views/VideoContextMenuView.swift index d8b84387..6338fc27 100644 --- a/Shared/Views/VideoContextMenuView.swift +++ b/Shared/Views/VideoContextMenuView.swift @@ -141,16 +141,8 @@ struct VideoContextMenuView: View { Button { player.controls.startPiP(startImmediately: false) - var time: CMTime? - if saveHistory, - let stoppedAt = watch?.stoppedAt, - !watch!.finished - { - time = .secondsInDefaultTimescale(stoppedAt) - } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - player.play(video, at: time, showingPlayer: false) + player.play(video, at: watch?.timeToRestart, showingPlayer: false) } } label: { Label("Play in PiP", systemImage: "pip")