From 98ef133bd97cc78fb51085c7fbdb0d72bb9f22aa Mon Sep 17 00:00:00 2001 From: Aiden Vigue Date: Sun, 20 Jun 2021 18:13:39 -0400 Subject: [PATCH] fix progress --- JellyfinPlayer/ContinueWatchingView.swift | 2 +- JellyfinPlayer/VideoPlayer.swift | 81 +++++++++++++---------- Shared/Extensions/APIExtensions.swift | 8 +-- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/JellyfinPlayer/ContinueWatchingView.swift b/JellyfinPlayer/ContinueWatchingView.swift index 0f4c6c1e..722ed05d 100644 --- a/JellyfinPlayer/ContinueWatchingView.swift +++ b/JellyfinPlayer/ContinueWatchingView.swift @@ -63,7 +63,7 @@ struct ContinueWatchingView: View { Rectangle() .fill(Color(red: 172/255, green: 92/255, blue: 195/255)) .mask(ProgressBar()) - .frame(width: CGFloat(item.userData?.playedPercentage ?? 0 * 3.2), height: 7) + .frame(width: CGFloat((item.userData?.playedPercentage ?? 0) * 3.2), height: 7) .padding(0), alignment: .bottomLeading ) Text(item.seriesName ?? item.name ?? "") diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 67b5a290..62e0e0a8 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -144,7 +144,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe sendProgressReport(eventName: "unpause") } else { sendJellyfinCommand(command: "Seek", options: [ - "position": secondsScrubbedTo + "position": Int(secondsScrubbedTo) ]) } } @@ -253,7 +253,6 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe self.castButton.isEnabled = true self.castButton.setImage(UIImage(named: "CastDisconnected"), for: .normal) playerDestination = .local - startLocalPlaybackEngine() } } @@ -549,56 +548,63 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe self.sendPlayReport() playbackItem = item } - startLocalPlaybackEngine() + startLocalPlaybackEngine(true) }) .store(in: &cancellables) } } - func startLocalPlaybackEngine() { + func startLocalPlaybackEngine(_ fetchCaptions: Bool) { print("Local playback engine starting.") - mediaPlayer = VLCMediaPlayer() - mediaPlayer.delegate = self; - mediaPlayer.drawable = videoContentView; - mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl) mediaPlayer.play() // 1 second = 10,000,000 ticks - + var startTicks: Int64 = 0; if(remotePositionTicks == 0) { print("Using server-reported start time") - let rawStartTicks = manifest.userData?.playbackPositionTicks ?? 0 - - if rawStartTicks != 0 { - let startSeconds = rawStartTicks / 10_000_000 - mediaPlayer.jumpForward(Int32(startSeconds)) - } + startTicks = manifest.userData?.playbackPositionTicks ?? 0 } else { print("Using remote-reported start time") - mediaPlayer.jumpForward(Int32(remotePositionTicks / 10_000_000)) + startTicks = Int64(remotePositionTicks) } - - // Pause and load captions into memory. - mediaPlayer.pause() - - var shouldHaveSubtitleTracks = 0 - subtitleTrackArray.forEach { sub in - if sub.id != -1 && sub.delivery == .external && sub.codec != "subrip" { - shouldHaveSubtitleTracks = shouldHaveSubtitleTracks + 1 - mediaPlayer.addPlaybackSlave(sub.url!, type: .subtitle, enforce: false) + + if startTicks != 0 { + let videoPosition = Double(mediaPlayer.time.intValue / 1000); + let secondsScrubbedTo = startTicks / 10_000_000 + let offset = secondsScrubbedTo - Int64(videoPosition) + print("Seeking to position: \(secondsScrubbedTo)") + if offset > 0 { + mediaPlayer.jumpForward(Int32(offset)) + } else { + mediaPlayer.jumpBackward(Int32(abs(offset))) } } + + if(fetchCaptions) { + // Pause and load captions into memory. + mediaPlayer.pause() + var shouldHaveSubtitleTracks = 1 + subtitleTrackArray.forEach { sub in + if sub.id != -1 && sub.delivery == .external && sub.codec != "subrip" { + shouldHaveSubtitleTracks = shouldHaveSubtitleTracks + 1 + mediaPlayer.addPlaybackSlave(sub.url!, type: .subtitle, enforce: false) + } + } - // Wait for captions to load - delegate?.showLoadingView(self) + // Wait for captions to load + delegate?.showLoadingView(self) - while mediaPlayer.numberOfSubtitlesTracks != shouldHaveSubtitleTracks {} + while mediaPlayer.numberOfSubtitlesTracks != shouldHaveSubtitleTracks { + print("waiting \(String(mediaPlayer.numberOfSubtitlesTracks)) != \(String(shouldHaveSubtitleTracks))") + } - // Select default track & resume playback - mediaPlayer.currentVideoSubTitleIndex = selectedCaptionTrack - mediaPlayer.pause() - mediaPlayer.play() + // Select default track & resume playback + mediaPlayer.currentVideoSubTitleIndex = selectedCaptionTrack + mediaPlayer.pause() + mediaPlayer.play() + } + self.mediaHasStartedPlaying() delegate?.hideLoadingView(self) print("Local engine started.") @@ -619,9 +625,10 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe //MARK: - GCKGenericChannelDelegate extension PlayerViewController: GCKGenericChannelDelegate { @objc func updateRemoteTime() { - paused = false; castButton.setImage(UIImage(named: "CastConnected"), for: .normal) - remotePositionTicks = remotePositionTicks + 2_000_000; //add 0.2 secs every timer evt. + if(!paused) { + remotePositionTicks = remotePositionTicks + 2_000_000; //add 0.2 secs every timer evt. + } if(isSeeking == false) { let remainingTime = (manifest.runTimeTicks! - Int64(remotePositionTicks))/10_000_000 @@ -637,6 +644,7 @@ extension PlayerViewController: GCKGenericChannelDelegate { timeText.text = timeTextStr let playbackProgress = Int64(remotePositionTicks) / manifest.runTimeTicks! + print(playbackProgress) seekSlider.setValue(Float(playbackProgress), animated: true) } } @@ -652,6 +660,7 @@ extension PlayerViewController: GCKGenericChannelDelegate { "position": Int(Float(manifest.runTimeTicks! / 10_000_000) * mediaPlayer.position) ]) } + paused = json["data"]["PlayState"]["IsPaused"].boolValue self.remotePositionTicks = json["data"]["PlayState"]["PositionTicks"].int ?? 0; if(remoteTimeUpdateTimer == nil) { remoteTimeUpdateTimer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(updateRemoteTime), userInfo: nil, repeats: true) @@ -736,7 +745,7 @@ extension PlayerViewController: GCKSessionManagerListener { videoContentView.isHidden = false; remoteTimeUpdateTimer?.invalidate() castButton.setImage(UIImage(named: "CastDisconnected"), for: .normal) - startLocalPlaybackEngine() + startLocalPlaybackEngine(false) } func sessionManager(_ sessionManager: GCKSessionManager, didSuspend session: GCKCastSession, with reason: GCKConnectionSuspendReason) { @@ -745,7 +754,7 @@ extension PlayerViewController: GCKSessionManagerListener { videoContentView.isHidden = false; remoteTimeUpdateTimer?.invalidate() castButton.setImage(UIImage(named: "CastDisconnected"), for: .normal) - startLocalPlaybackEngine() + startLocalPlaybackEngine(false) } } diff --git a/Shared/Extensions/APIExtensions.swift b/Shared/Extensions/APIExtensions.swift index ec2d42b2..ce357d08 100644 --- a/Shared/Extensions/APIExtensions.swift +++ b/Shared/Extensions/APIExtensions.swift @@ -104,13 +104,13 @@ extension BaseItemDto { // MARK: Calculations func getItemRuntime() -> String { - let seconds: Int = Int(self.runTimeTicks ?? 0) / 10_000_000 + let seconds = (self.runTimeTicks ?? 0) / 10_000_000 let hours = (seconds / 3600) let minutes = ((seconds - (hours * 3600)) / 60) if hours != 0 { return "\(hours):\(String(minutes).leftPad(toWidth: 2, withString: "0"))" } else { - return "\(String(minutes).leftPad(toWidth: 2, withString: "0"))m" + return "\(String(minutes))m" } } @@ -119,13 +119,13 @@ extension BaseItemDto { return "" } - let remainingSecs = Int(self.runTimeTicks ?? 0 - (self.userData?.playbackPositionTicks ?? 0)) / 10_000_000 + let remainingSecs = ((self.runTimeTicks ?? 0) - (self.userData?.playbackPositionTicks ?? 0)) / 10_000_000 let proghours = Int(remainingSecs / 3600) let progminutes = Int((Int(remainingSecs) - (proghours * 3600)) / 60) if proghours != 0 { return "\(proghours)h \(String(progminutes).leftPad(toWidth: 2, withString: "0"))m" } else { - return "\(String(progminutes).leftPad(toWidth: 2, withString: "0"))m" + return "\(String(progminutes))m" } } }