diff --git a/Sora/MediaUtils/CustomPlayer/CustomPlayer.swift b/Sora/MediaUtils/CustomPlayer/CustomPlayer.swift index f5b1053..623cb50 100644 --- a/Sora/MediaUtils/CustomPlayer/CustomPlayer.swift +++ b/Sora/MediaUtils/CustomPlayer/CustomPlayer.swift @@ -77,6 +77,13 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele } return UserDefaults.standard.bool(forKey: "pipButtonVisible") } + + private var isAutoplayEnabled: Bool { + if UserDefaults.standard.object(forKey: "autoplayNext") == nil { + return true + } + return UserDefaults.standard.bool(forKey: "autoplayNext") + } private var pipController: AVPictureInPictureController? private var pipButton: UIButton! @@ -402,6 +409,13 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele twoFingerTapGesture.numberOfTouchesRequired = 2 twoFingerTapGesture.delegate = self view.addGestureRecognizer(twoFingerTapGesture) + + NotificationCenter.default.addObserver( + self, + selector: #selector(handlePlaybackEnded), + name: .AVPlayerItemDidPlayToEndTime, + object: player.currentItem + ) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -466,6 +480,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele timeUpdateTimer.invalidate() } + NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil) NotificationCenter.default.removeObserver(self) UIDevice.current.isBatteryMonitoringEnabled = false @@ -2997,6 +3012,19 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele batteryLabel?.text = "N/A" } } + + @objc private func handlePlaybackEnded() { + guard isAutoplayEnabled else { return } + + Logger.shared.log("Playback ended, autoplay enabled - starting next episode", type: "Debug") + + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in + self?.player.pause() + self?.dismiss(animated: true) { [weak self] in + self?.onWatchNext() + } + } + } } class GradientOverlayButton: UIButton { diff --git a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewPlayer.swift b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewPlayer.swift index ccbca67..f34e5a3 100644 --- a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewPlayer.swift +++ b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewPlayer.swift @@ -205,6 +205,7 @@ struct SettingsViewPlayer: View { @AppStorage("doubleTapSeekEnabled") private var doubleTapSeekEnabled: Bool = false @AppStorage("skipIntroOutroVisible") private var skipIntroOutroVisible: Bool = true @AppStorage("pipButtonVisible") private var pipButtonVisible: Bool = true + @AppStorage("autoplayNext") private var autoplayNext: Bool = true @AppStorage("videoQualityWiFi") private var wifiQuality: String = VideoQualityPreference.defaultWiFiPreference.rawValue @AppStorage("videoQualityCellular") private var cellularQuality: String = VideoQualityPreference.defaultCellularPreference.rawValue @@ -247,6 +248,13 @@ struct SettingsViewPlayer: View { showDivider: true ) + SettingsToggleRow( + icon: "play.circle.fill", + title: NSLocalizedString("Autoplay Next", comment: ""), + isOn: $autoplayNext, + showDivider: true + ) + SettingsPickerRow( icon: "timer", title: NSLocalizedString("Completion Percentage", comment: ""),