Merge branch 'master' into download-page

This commit is contained in:
advplyr
2022-08-21 15:56:20 -05:00
12 changed files with 160 additions and 58 deletions
@@ -37,9 +37,9 @@ data class DeviceSettings(
} }
@get:JsonIgnore @get:JsonIgnore
val jumpBackwardsTimeMs get() = jumpBackwardsTime * 1000L val jumpBackwardsTimeMs get() = (jumpBackwardsTime ?: default().jumpBackwardsTime) * 1000L
@get:JsonIgnore @get:JsonIgnore
val jumpForwardTimeMs get() = jumpForwardTime * 1000L val jumpForwardTimeMs get() = (jumpForwardTime ?: default().jumpBackwardsTime) * 1000L
} }
data class DeviceData( data class DeviceData(
@@ -7,10 +7,8 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import com.audiobookshelf.app.R
import com.audiobookshelf.app.data.LibraryItemWrapper import com.audiobookshelf.app.data.LibraryItemWrapper
import com.audiobookshelf.app.data.PodcastEpisode import com.audiobookshelf.app.data.PodcastEpisode
import java.util.* import java.util.*
@@ -21,7 +19,6 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
private var mediaButtonClickCount: Int = 0 private var mediaButtonClickCount: Int = 0
var mediaButtonClickTimeout: Long = 1000 //ms var mediaButtonClickTimeout: Long = 1000 //ms
var seekAmount: Long = 20000 //ms
override fun onPrepare() { override fun onPrepare() {
Log.d(tag, "ON PREPARE MEDIA SESSION COMPAT") Log.d(tag, "ON PREPARE MEDIA SESSION COMPAT")
@@ -75,19 +72,19 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
} }
override fun onSkipToPrevious() { override fun onSkipToPrevious() {
playerNotificationService.seekBackward(seekAmount) playerNotificationService.skipToPrevious()
} }
override fun onSkipToNext() { override fun onSkipToNext() {
playerNotificationService.seekForward(seekAmount) playerNotificationService.skipToNext()
} }
override fun onFastForward() { override fun onFastForward() {
playerNotificationService.seekForward(seekAmount) playerNotificationService.jumpForward()
} }
override fun onRewind() { override fun onRewind() {
playerNotificationService.seekForward(seekAmount) playerNotificationService.jumpBackward()
} }
override fun onSeekTo(pos: Long) { override fun onSeekTo(pos: Long) {
@@ -179,10 +176,10 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
handleMediaButtonClickCount() handleMediaButtonClickCount()
} }
KeyEvent.KEYCODE_MEDIA_NEXT -> { KeyEvent.KEYCODE_MEDIA_NEXT -> {
playerNotificationService.seekForward(seekAmount) playerNotificationService.jumpForward()
} }
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> { KeyEvent.KEYCODE_MEDIA_PREVIOUS -> {
playerNotificationService.seekBackward(seekAmount) playerNotificationService.jumpBackward()
} }
KeyEvent.KEYCODE_MEDIA_STOP -> { KeyEvent.KEYCODE_MEDIA_STOP -> {
playerNotificationService.closePlayback() playerNotificationService.closePlayback()
@@ -226,22 +223,22 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
super.handleMessage(msg) super.handleMessage(msg)
if (2 == msg.what) { if (2 == msg.what) {
playerNotificationService.seekBackward(seekAmount) playerNotificationService.jumpBackward()
playerNotificationService.play() playerNotificationService.play()
} }
else if (msg.what >= 3) { else if (msg.what >= 3) {
playerNotificationService.seekForward(seekAmount) playerNotificationService.jumpForward()
playerNotificationService.play() playerNotificationService.play()
} }
} }
} }
// Example Using a custom action in android auto override fun onCustomAction(action: String?, extras: Bundle?) {
// override fun onCustomAction(action: String?, extras: Bundle?) { super.onCustomAction(action, extras)
// super.onCustomAction(action, extras)
// when (action) {
// if ("com.audiobookshelf.app.PLAYBACK_RATE" == action) { CUSTOM_ACTION_JUMP_FORWARD -> onFastForward()
// CUSTOM_ACTION_JUMP_BACKWARD -> onRewind()
// } }
// } }
} }
@@ -0,0 +1,4 @@
package com.audiobookshelf.app.player
const val CUSTOM_ACTION_JUMP_FORWARD = "com.audiobookshelf.customAction.jump_forward";
const val CUSTOM_ACTION_JUMP_BACKWARD = "com.audiobookshelf.customAction.jump_backward";
@@ -20,7 +20,6 @@ import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.media.MediaBrowserServiceCompat import androidx.media.MediaBrowserServiceCompat
import androidx.media.utils.MediaConstants import androidx.media.utils.MediaConstants
import com.audiobookshelf.app.BuildConfig import com.audiobookshelf.app.BuildConfig
@@ -30,9 +29,11 @@ import com.audiobookshelf.app.data.DeviceInfo
import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.device.DeviceManager
import com.audiobookshelf.app.media.MediaManager import com.audiobookshelf.app.media.MediaManager
import com.audiobookshelf.app.server.ApiHandler import com.audiobookshelf.app.server.ApiHandler
import com.fasterxml.jackson.annotation.JsonIgnore
import com.google.android.exoplayer2.* import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector.CustomActionProvider
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
import com.google.android.exoplayer2.source.MediaSource import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource
@@ -42,6 +43,7 @@ import com.google.android.exoplayer2.upstream.*
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
const val SLEEP_TIMER_WAKE_UP_EXPIRATION = 120000L // 2m const val SLEEP_TIMER_WAKE_UP_EXPIRATION = 120000L // 2m
class PlayerNotificationService : MediaBrowserServiceCompat() { class PlayerNotificationService : MediaBrowserServiceCompat() {
@@ -294,17 +296,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
mediaSessionConnector.setQueueNavigator(queueNavigator) mediaSessionConnector.setQueueNavigator(queueNavigator)
mediaSessionConnector.setPlaybackPreparer(MediaSessionPlaybackPreparer(this)) mediaSessionConnector.setPlaybackPreparer(MediaSessionPlaybackPreparer(this))
// Example adding custom action with icon in android auto mediaSessionConnector.setCustomActionProviders(
// mediaSessionConnector.setCustomActionProviders(object : MediaSessionConnector.CustomActionProvider { JumpForwardCustomActionProvider(),
// override fun onCustomAction(player: Player, action: String, extras: Bundle?) { JumpBackwardCustomActionProvider(),
// } )
// override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? {
// var icon = R.drawable.exo_icon_rewind
// return PlaybackStateCompat.CustomAction.Builder(
// "com.audiobookshelf.app.PLAYBACK_RATE", "Playback Rate", icon)
// .build()
// }
// })
mediaSession.setCallback(MediaSessionCallback(this)) mediaSession.setCallback(MediaSessionCallback(this))
@@ -320,13 +315,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
1000 * 20 // 20s playback rebuffer 1000 * 20 // 20s playback rebuffer
).build() ).build()
val seekBackTime = DeviceManager.deviceData.deviceSettings?.jumpBackwardsTimeMs ?: 10000
val seekForwardTime = DeviceManager.deviceData.deviceSettings?.jumpForwardTimeMs ?: 10000
mPlayer = ExoPlayer.Builder(this) mPlayer = ExoPlayer.Builder(this)
.setLoadControl(customLoadControl) .setLoadControl(customLoadControl)
.setSeekBackIncrementMs(seekBackTime) .setSeekBackIncrementMs(deviceSettings.jumpBackwardsTimeMs)
.setSeekForwardIncrementMs(seekForwardTime) .setSeekForwardIncrementMs(deviceSettings.jumpForwardTimeMs)
.build() .build()
mPlayer.setHandleAudioBecomingNoisy(true) mPlayer.setHandleAudioBecomingNoisy(true)
mPlayer.addListener(PlayerListener(this)) mPlayer.addListener(PlayerListener(this))
@@ -701,6 +693,22 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
} }
fun skipToPrevious() {
currentPlayer.seekToPrevious()
}
fun skipToNext() {
currentPlayer.seekToNext()
}
fun jumpForward() {
seekForward(deviceSettings.jumpForwardTimeMs)
}
fun jumpBackward() {
seekBackward(deviceSettings.jumpBackwardsTimeMs)
}
fun seekForward(amount: Long) { fun seekForward(amount: Long) {
seekPlayer(getCurrentTime() + amount) seekPlayer(getCurrentTime() + amount)
} }
@@ -757,6 +765,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
return DeviceInfo(Build.MANUFACTURER, Build.MODEL, Build.BRAND, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME) return DeviceInfo(Build.MANUFACTURER, Build.MODEL, Build.BRAND, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
} }
@get:JsonIgnore
val deviceSettings get() = DeviceManager.deviceData.deviceSettings ?: DeviceSettings.default()
fun getPlayItemRequestPayload(forceTranscode:Boolean):PlayItemRequestPayload { fun getPlayItemRequestPayload(forceTranscode:Boolean):PlayItemRequestPayload {
return PlayItemRequestPayload(getMediaPlayer(), !forceTranscode, forceTranscode, getDeviceInfo()) return PlayItemRequestPayload(getMediaPlayer(), !forceTranscode, forceTranscode, getDeviceInfo())
} }
@@ -966,5 +977,39 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
clientEventEmitter?.onNetworkMeteredChanged(unmetered) clientEventEmitter?.onNetworkMeteredChanged(unmetered)
} }
} }
inner class JumpBackwardCustomActionProvider : CustomActionProvider {
override fun onCustomAction(player: Player, action: String, extras: Bundle?) {
/*
This does not appear to ever get called. Instead, MediaSessionCallback.onCustomAction() is
responsible to reacting to a custom action.
*/
}
override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? {
return PlaybackStateCompat.CustomAction.Builder(
CUSTOM_ACTION_JUMP_BACKWARD,
getContext().getString(R.string.action_jump_backward),
R.drawable.exo_icon_rewind
).build()
}
}
inner class JumpForwardCustomActionProvider : CustomActionProvider {
override fun onCustomAction(player: Player, action: String, extras: Bundle?) {
/*
This does not appear to ever get called. Instead, MediaSessionCallback.onCustomAction() is
responsible to reacting to a custom action.
*/
}
override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? {
return PlaybackStateCompat.CustomAction.Builder(
CUSTOM_ACTION_JUMP_FORWARD,
getContext().getString(R.string.action_jump_forward),
R.drawable.exo_icon_fastforward
).build()
}
}
} }
@@ -6,4 +6,6 @@
<string name="custom_url_scheme">com.audiobookshelf.app</string> <string name="custom_url_scheme">com.audiobookshelf.app</string>
<string name="add_widget">Add widget</string> <string name="add_widget">Add widget</string>
<string name="app_widget_description">Simple widget for audiobookshelf playback</string> <string name="app_widget_description">Simple widget for audiobookshelf playback</string>
<string name="action_jump_forward">Jump Forward</string>
<string name="action_jump_backward">Jump Backward</string>
</resources> </resources>
+2 -2
View File
@@ -8,8 +8,8 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.google.gms:google-services:4.3.5' classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.android.tools.build:gradle:7.2.0-beta04' classpath 'com.android.tools.build:gradle:7.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
+37 -5
View File
@@ -6,9 +6,26 @@
</div> </div>
</template> </template>
<div class="w-full h-full overflow-hidden absolute top-0 left-0 flex items-center justify-center" @click="show = false"> <div
class="w-full h-full overflow-hidden absolute top-0 left-0 flex items-center justify-center"
@click="
show = false
manualTimerModal = false
"
>
<div class="w-full overflow-x-hidden overflow-y-auto bg-primary rounded-lg border border-white border-opacity-20" style="max-height: 75%" @click.stop> <div class="w-full overflow-x-hidden overflow-y-auto bg-primary rounded-lg border border-white border-opacity-20" style="max-height: 75%" @click.stop>
<ul v-if="!sleepTimerRunning" class="h-full w-full" role="listbox" aria-labelledby="listbox-label"> <div v-if="manualTimerModal" class="p-4">
<div class="flex mb-4" @click="manualTimerModal = false">
<span class="material-icons text-3xl">arrow_back</span>
</div>
<div class="flex my-2 justify-between">
<ui-btn @click="decreaseManualTimeout" class="w-9 h-9" :padding-x="0" small style="max-width: 36px"><span class="material-icons">remove</span></ui-btn>
<p class="text-2xl font-mono text-center">{{ manualTimeoutMin }} min</p>
<ui-btn @click="increaseManualTimeout" class="w-9 h-9" :padding-x="0" small style="max-width: 36px"><span class="material-icons">add</span></ui-btn>
</div>
<ui-btn @click="clickedOption(manualTimeoutMin)" class="w-full">Set Timer</ui-btn>
</div>
<ul v-else-if="!sleepTimerRunning" class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
<template v-for="timeout in timeouts"> <template v-for="timeout in timeouts">
<li :key="timeout" class="text-gray-50 select-none relative py-4 cursor-pointer hover:bg-black-400" role="option" @click="clickedOption(timeout)"> <li :key="timeout" class="text-gray-50 select-none relative py-4 cursor-pointer hover:bg-black-400" role="option" @click="clickedOption(timeout)">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
@@ -21,8 +38,13 @@
<span class="font-normal block truncate text-lg text-center">End of Chapter</span> <span class="font-normal block truncate text-lg text-center">End of Chapter</span>
</div> </div>
</li> </li>
<li class="text-gray-50 select-none relative py-4 cursor-pointer hover:bg-black-400" role="option" @click="manualTimerModal = true">
<div class="flex items-center justify-center">
<span class="font-normal block truncate text-lg text-center">Manual sleep timer</span>
</div>
</li>
</ul> </ul>
<div v-else class="px-2 py-4"> <div v-else class="p-4">
<div class="flex my-2 justify-between"> <div class="flex my-2 justify-between">
<ui-btn @click="decreaseSleepTime" class="w-9 h-9" :padding-x="0" small style="max-width: 36px"><span class="material-icons">remove</span></ui-btn> <ui-btn @click="decreaseSleepTime" class="w-9 h-9" :padding-x="0" small style="max-width: 36px"><span class="material-icons">remove</span></ui-btn>
<p class="text-2xl font-mono text-center">{{ timeRemainingPretty }}</p> <p class="text-2xl font-mono text-center">{{ timeRemainingPretty }}</p>
@@ -45,7 +67,10 @@ export default {
currentEndOfChapterTime: Number currentEndOfChapterTime: Number
}, },
data() { data() {
return {} return {
manualTimerModal: null,
manualTimeoutMin: 1
}
}, },
computed: { computed: {
show: { show: {
@@ -57,7 +82,7 @@ export default {
} }
}, },
timeouts() { timeouts() {
return [1, 5, 10, 15, 30, 45, 60, 90] return [5, 10, 15, 30, 45, 60, 90]
}, },
timeRemainingPretty() { timeRemainingPretty() {
return this.$secondsToTimestamp(this.currentTime) return this.$secondsToTimestamp(this.currentTime)
@@ -71,6 +96,7 @@ export default {
clickedOption(timeoutMin) { clickedOption(timeoutMin) {
var timeout = timeoutMin * 1000 * 60 var timeout = timeoutMin * 1000 * 60
this.show = false this.show = false
this.manualTimerModal = false
this.$nextTick(() => this.$emit('change', { time: timeout, isChapterTime: false })) this.$nextTick(() => this.$emit('change', { time: timeout, isChapterTime: false }))
}, },
cancelSleepTimer() { cancelSleepTimer() {
@@ -82,6 +108,12 @@ export default {
}, },
decreaseSleepTime() { decreaseSleepTime() {
this.$emit('decrease') this.$emit('decrease')
},
increaseManualTimeout() {
this.manualTimeoutMin++
},
decreaseManualTimeout() {
if (this.manualTimeoutMin > 1) this.manualTimeoutMin--
} }
}, },
mounted() {} mounted() {}
+1 -1
View File
@@ -38,7 +38,7 @@ public class AbsAudioPlayer: CAPPlugin {
do { do {
// Fetch the most recent active session // Fetch the most recent active session
let activeSession = try await Realm().objects(PlaybackSession.self).where({ $0.isActiveSession == true }).last let activeSession = try await Realm().objects(PlaybackSession.self).where({ $0.isActiveSession == true }).last?.freeze()
if let activeSession = activeSession { if let activeSession = activeSession {
await PlayerProgress.syncFromServer() await PlayerProgress.syncFromServer()
try self.startPlaybackSession(activeSession, playWhenReady: false, playbackRate: PlayerSettings.main().playbackRate) try self.startPlaybackSession(activeSession, playWhenReady: false, playbackRate: PlayerSettings.main().playbackRate)
+6 -6
View File
@@ -9,12 +9,12 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' pod 'CapacitorApp', :path => '..\..\node_modules\@capacitor\app'
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog' pod 'CapacitorDialog', :path => '..\..\node_modules\@capacitor\dialog'
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' pod 'CapacitorHaptics', :path => '..\..\node_modules\@capacitor\haptics'
pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network' pod 'CapacitorNetwork', :path => '..\..\node_modules\@capacitor\network'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' pod 'CapacitorStatusBar', :path => '..\..\node_modules\@capacitor\status-bar'
pod 'CapacitorStorage', :path => '../../node_modules/@capacitor/storage' pod 'CapacitorStorage', :path => '..\..\node_modules\@capacitor\storage'
end end
target 'App' do target 'App' do
@@ -155,8 +155,13 @@ extension LocalMediaProgress {
static func fetchOrCreateLocalMediaProgress(localMediaProgressId: String?, localLibraryItemId: String?, localEpisodeId: String?) -> LocalMediaProgress? { static func fetchOrCreateLocalMediaProgress(localMediaProgressId: String?, localLibraryItemId: String?, localEpisodeId: String?) -> LocalMediaProgress? {
if let localMediaProgressId = localMediaProgressId { if let localMediaProgressId = localMediaProgressId {
return Database.shared.getLocalMediaProgress(localMediaProgressId: localMediaProgressId) // Check if it existing in the database, if not, we need to create it
} else if let localLibraryItemId = localLibraryItemId { if let progress = Database.shared.getLocalMediaProgress(localMediaProgressId: localMediaProgressId) {
return progress
}
}
if let localLibraryItemId = localLibraryItemId {
guard let localLibraryItem = Database.shared.getLocalLibraryItem(localLibraryItemId: localLibraryItemId) else { return nil } guard let localLibraryItem = Database.shared.getLocalLibraryItem(localLibraryItemId: localLibraryItemId) else { return nil }
let episode = localLibraryItem.getPodcastEpisode(episodeId: localEpisodeId) let episode = localLibraryItem.getPodcastEpisode(episodeId: localEpisodeId)
return LocalMediaProgress(localLibraryItem: localLibraryItem, episode: episode) return LocalMediaProgress(localLibraryItem: localLibraryItem, episode: episode)
+4
View File
@@ -167,6 +167,8 @@ class AudioPlayer: NSObject {
// MARK: - Methods // MARK: - Methods
public func play(allowSeekBack: Bool = false) { public func play(allowSeekBack: Bool = false) {
guard self.isInitialized() else { return }
if allowSeekBack { if allowSeekBack {
let diffrence = Date.timeIntervalSinceReferenceDate - lastPlayTime let diffrence = Date.timeIntervalSinceReferenceDate - lastPlayTime
var time: Int? var time: Int?
@@ -202,6 +204,8 @@ class AudioPlayer: NSObject {
} }
public func pause() { public func pause() {
guard self.isInitialized() else { return }
self.audioPlayer.pause() self.audioPlayer.pause()
self.status = 0 self.status = 0
self.rate = 0.0 self.rate = 0.0
+17 -4
View File
@@ -76,16 +76,25 @@ class PlayerProgress {
} }
private static func updateLocalSessionFromServerMediaProgress() async { private static func updateLocalSessionFromServerMediaProgress() async {
NSLog("checkCurrentSessionProgress: Checking if local media progress was updated on server") NSLog("updateLocalSessionFromServerMediaProgress: Checking if local media progress was updated on server")
guard let session = PlayerHandler.getPlaybackSession()?.freeze() else { return } guard let session = try! await Realm().objects(PlaybackSession.self).last(where: { $0.isActiveSession == true })?.freeze() else {
NSLog("updateLocalSessionFromServerMediaProgress: Failed to get session")
return
}
// Fetch the current progress // Fetch the current progress
let progress = await ApiClient.getMediaProgress(libraryItemId: session.libraryItemId!, episodeId: session.episodeId) let progress = await ApiClient.getMediaProgress(libraryItemId: session.libraryItemId!, episodeId: session.episodeId)
guard let progress = progress else { return } guard let progress = progress else {
NSLog("updateLocalSessionFromServerMediaProgress: No progress object")
return
}
// Determine which session is newer // Determine which session is newer
let serverLastUpdate = progress.lastUpdate let serverLastUpdate = progress.lastUpdate
guard let localLastUpdate = session.updatedAt else { return } guard let localLastUpdate = session.updatedAt else {
NSLog("updateLocalSessionFromServerMediaProgress: No local session updatedAt")
return
}
let serverCurrentTime = progress.currentTime let serverCurrentTime = progress.currentTime
let localCurrentTime = session.currentTime let localCurrentTime = session.currentTime
@@ -94,12 +103,16 @@ class PlayerProgress {
// Update the session, if needed // Update the session, if needed
if serverIsNewerThanLocal && currentTimeIsDifferent { if serverIsNewerThanLocal && currentTimeIsDifferent {
NSLog("updateLocalSessionFromServerMediaProgress: Server has newer time than local serverLastUpdate=\(serverLastUpdate) localLastUpdate=\(localLastUpdate)")
guard let session = session.thaw() else { return } guard let session = session.thaw() else { return }
session.update { session.update {
session.currentTime = serverCurrentTime session.currentTime = serverCurrentTime
session.updatedAt = serverLastUpdate session.updatedAt = serverLastUpdate
} }
NSLog("updateLocalSessionFromServerMediaProgress: Updated session currentTime newCurrentTime=\(serverCurrentTime) previousCurrentTime=\(localCurrentTime)")
PlayerHandler.seek(amount: session.currentTime) PlayerHandler.seek(amount: session.currentTime)
} else {
NSLog("updateLocalSessionFromServerMediaProgress: Local session does not need updating; local has latest progress")
} }
} }