@@ -133,7 +133,7 @@
import { Capacitor } from '@capacitor/core'
import { AbsAudioPlayer } from '@/plugins/capacitor'
import { Dialog } from '@capacitor/dialog'
-import { FastAverageColor } from 'fast-average-color'
+import { getAverageColorFromCoverUrl } from '@/utils/coverAverageColor'
import WrappingMarquee from '@/assets/WrappingMarquee.js'
import jumpLabelMixin from '@/mixins/jumpLabel'
@@ -176,6 +176,7 @@ export default {
lockUi: false
},
isLoading: false,
+ isCheckingServerProgress: false,
isDraggingCursor: false,
draggingTouchStartX: 0,
draggingTouchStartTime: 0,
@@ -289,6 +290,9 @@ export default {
return 190 * heightScale
}
},
+ showLoadingState() {
+ return this.isLoading || this.isCheckingServerProgress
+ },
showCastBtn() {
return this.$store.state.isCastAvailable
},
@@ -427,17 +431,14 @@ export default {
},
async coverImageLoaded(fullCoverUrl) {
if (!fullCoverUrl) return
-
- const fac = new FastAverageColor()
- fac
- .getColorAsync(fullCoverUrl)
- .then((color) => {
- this.coverRgb = color.rgba
- this.coverBgIsLight = color.isLight
- })
- .catch((e) => {
- console.log(e)
- })
+ const avg = await getAverageColorFromCoverUrl(this, fullCoverUrl)
+ if (!avg) {
+ this.coverRgb = 'rgb(55, 56, 56)'
+ this.coverBgIsLight = false
+ } else {
+ this.coverRgb = avg.rgba
+ this.coverBgIsLight = avg.isLight
+ }
},
clickTitleAndAuthor() {
if (!this.showFullscreen) return
@@ -480,13 +481,13 @@ export default {
},
async jumpNextChapter() {
await this.$hapticsImpact()
- if (this.isLoading) return
+ if (this.showLoadingState) return
if (!this.nextChapter) return
this.seek(this.nextChapter.start)
},
async jumpChapterStart() {
await this.$hapticsImpact()
- if (this.isLoading) return
+ if (this.showLoadingState) return
if (!this.currentChapter) {
return this.restart()
}
@@ -516,12 +517,12 @@ export default {
},
async jumpBackwards() {
await this.$hapticsImpact()
- if (this.isLoading) return
+ if (this.showLoadingState) return
AbsAudioPlayer.seekBackward({ value: this.jumpBackwardsTime })
},
async jumpForward() {
await this.$hapticsImpact()
- if (this.isLoading) return
+ if (this.showLoadingState) return
AbsAudioPlayer.seekForward({ value: this.jumpForwardTime })
},
setStreamReady() {
@@ -625,7 +626,7 @@ export default {
}
},
seek(time) {
- if (this.isLoading) return
+ if (this.showLoadingState) return
if (this.seekLoading) {
console.error('Already seek loading', this.seekedTime)
return
@@ -634,7 +635,8 @@ export default {
this.seekedTime = time
this.seekLoading = true
- AbsAudioPlayer.seek({ value: Math.floor(time) })
+ // Pass fractional seconds so seeks to non-integer chapter starts don't truncate
+ AbsAudioPlayer.seek({ value: time })
if (this.$refs.playedTrack) {
const perc = time / this.totalDuration
@@ -657,11 +659,14 @@ export default {
},
async playPauseClick() {
await this.$hapticsImpact()
- if (this.isLoading) return
+ if (this.showLoadingState) return
this.isPlaying = !!((await AbsAudioPlayer.playPause()) || {}).playing
this.isEnded = false
},
+ setIsCheckingServerProgress(value) {
+ this.isCheckingServerProgress = !!value
+ },
play() {
AbsAudioPlayer.playPlayer()
this.startPlayInterval()
diff --git a/components/app/AudioPlayerContainer.vue b/components/app/AudioPlayerContainer.vue
index 1040e61b..f9f84047 100644
--- a/components/app/AudioPlayerContainer.vue
+++ b/components/app/AudioPlayerContainer.vue
@@ -48,6 +48,9 @@ export default {
},
isIos() {
return this.$platform === 'ios'
+ },
+ currentPlaybackSession() {
+ return this.$store.state.currentPlaybackSession
}
},
methods: {
@@ -226,7 +229,7 @@ export default {
console.log('Already streaming item', startTime)
if (startTime !== undefined && startTime !== null) {
// seek to start time
- AbsAudioPlayer.seek({ value: Math.floor(startTime) })
+ AbsAudioPlayer.seek({ value: startTime })
} else if (this.$refs.audioPlayer) {
this.$refs.audioPlayer.play()
}
@@ -304,48 +307,129 @@ export default {
this.$refs.audioPlayer?.seek(currentTime)
},
/**
- * When device gains focus then refresh the timestamps in the audio player
+ * Fetch the current user's media progress from the server for a given library item / episode.
+ * Returns the server media progress object, or null if the request fails, times out, or the
+ * response doesn't match the requested library item.
+ *
+ * The audio player's loading state is shown while the request is in flight so the user
+ * doesn't tap play before we have a chance to update the timestamps. The request timeout
+ * is 7 seconds so a slow/unresponsive server doesn't block the user for long.
*/
- deviceFocused(hasFocus) {
- if (!this.$store.state.currentPlaybackSession) return
+ async getServerMediaProgressForCurrentSession() {
+ if (!this.$store.state.user.user || !this.$store.state.networkConnected) return null
+ const libraryItemId = this.currentPlaybackSession?.libraryItemId
+ const episodeId = this.currentPlaybackSession?.episodeId
+ if (!libraryItemId) return null
- if (hasFocus) {
+ if (this.$refs.audioPlayer?.isCheckingServerProgress) {
+ console.log('[AudioPlayerContainer] getServerMediaProgressForCurrentSession: already checking server progress')
+ return null
+ }
+
+ const url = episodeId ? `/api/me/progress/${libraryItemId}/${episodeId}` : `/api/me/progress/${libraryItemId}`
+
+ this.$refs.audioPlayer?.setIsCheckingServerProgress(true)
+ try {
+ const data = await this.$nativeHttp.get(url, { connectTimeout: 7000, readTimeout: 7000 })
+ if (!data || data.libraryItemId !== libraryItemId) return null
+ return data
+ } catch (error) {
+ console.error('[AudioPlayerContainer] Failed to get server media progress', error)
+ return null
+ } finally {
+ this.$refs.audioPlayer?.setIsCheckingServerProgress(false)
+ }
+ },
+ getLocalMediaProgressForCurrentSession() {
+ if (!this.currentPlaybackSession) return null
+ return this.$store.getters['globals/getLocalMediaProgressById'](this.currentPlaybackSession.localLibraryItem?.id, this.currentPlaybackSession.localEpisodeId)
+ },
+ /**
+ * Sync the server media progress with the local media progress
+ */
+ async syncServerMediaProgressWithLocalMediaProgress(localMediaProgressId, serverMediaProgress) {
+ try {
+ const newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress({
+ localMediaProgressId,
+ mediaProgress: serverMediaProgress
+ })
+ if (newLocalMediaProgress?.id) {
+ this.$store.commit('globals/updateLocalMediaProgress', newLocalMediaProgress)
+ }
+ } catch (error) {
+ console.error('[AudioPlayerContainer] Failed to sync server progress with local media progress', error)
+ }
+ },
+ /**
+ * Check if the server media progress is more recent than the local media progress and sync if so
+ */
+ async checkSyncServerProgressWithLocalProgress(localMediaProgress) {
+ if (!localMediaProgress) return
+ console.log('[AudioPlayerContainer] checkSyncServerProgressWithLocalProgress: checking server media progress for local media item open in player')
+ const serverMediaProgress = await this.getServerMediaProgressForCurrentSession()
+ if (!serverMediaProgress?.lastUpdate || serverMediaProgress.lastUpdate <= localMediaProgress.lastUpdate) return
+
+ console.log('[AudioPlayerContainer] checkSyncServerProgressWithLocalProgress: server progress is more recent than local progress. Server current time:', serverMediaProgress.currentTime, 'vs local', localMediaProgress.currentTime, `(server lastUpdate=${serverMediaProgress.lastUpdate} > local lastUpdate=${localMediaProgress.lastUpdate})`)
+ if (!this.$refs.audioPlayer?.isPlaying && serverMediaProgress.currentTime !== localMediaProgress.currentTime) {
+ // Use seek() so the native audio player's current session is updated
+ this.$refs.audioPlayer.seek(serverMediaProgress.currentTime)
+ }
+
+ await this.syncServerMediaProgressWithLocalMediaProgress(localMediaProgress.id, serverMediaProgress)
+ },
+ /**
+ * When socket is reconnected after a delay, if a local media item is open in the player (paused)
+ * we fetch the server media progress and sync it if it is more recent than the local progress
+ *
+ * If there is no socket connection we may have missed external progress updates
+ */
+ async socketReconnected() {
+ if (!this.currentPlaybackSession) return
+ // dont update timestamps if player is playing
+ if (this.$refs.audioPlayer?.isPlaying) return
+
+ if (this.$refs.audioPlayer.isLocalPlayMethod) {
+ const localMediaProgress = this.getLocalMediaProgressForCurrentSession()
+ if (!localMediaProgress) {
+ console.error('[AudioPlayerContainer] socket reconnected: Local media progress not found')
+ return
+ }
+
+ await this.checkSyncServerProgressWithLocalProgress(localMediaProgress)
+ }
+ },
+ /**
+ * When device re-gains focus then refresh the timestamps in the audio player
+ * if local item is open then fetch the server media progress and update if more recent
+ */
+ async deviceFocused(hasFocus) {
+ if (!this.currentPlaybackSession || !hasFocus) return
+ // dont update timestamps if player is playing
+ if (this.$refs.audioPlayer?.isPlaying) return
+
+ if (this.$refs.audioPlayer.isLocalPlayMethod) {
+ const localMediaProgress = this.getLocalMediaProgressForCurrentSession()
+ if (!localMediaProgress) {
+ console.error('[AudioPlayerContainer] device visibility: Local media progress not found')
+ return
+ }
+
+ console.log('[AudioPlayerContainer] device visibility: found local media progress', localMediaProgress.currentTime, 'last time in player is', this.currentTime)
+ this.$refs.audioPlayer.currentTime = localMediaProgress.currentTime
+ this.$refs.audioPlayer.timeupdate()
+
+ await this.checkSyncServerProgressWithLocalProgress(localMediaProgress)
+ } else {
+ // server item so fetch server media progress and update player time
+ console.log('[AudioPlayerContainer] device visibility: checking server media progress for server media item open in player')
+ const data = await this.getServerMediaProgressForCurrentSession()
+ if (!data) return
if (!this.$refs.audioPlayer?.isPlaying) {
- const playbackSession = this.$store.state.currentPlaybackSession
- if (this.$refs.audioPlayer.isLocalPlayMethod) {
- const localLibraryItemId = playbackSession.localLibraryItem?.id
- const localEpisodeId = playbackSession.localEpisodeId
- if (!localLibraryItemId) {
- console.error('[AudioPlayerContainer] device visibility: no local library item for session', JSON.stringify(playbackSession))
- return
- }
- const localMediaProgress = this.$store.state.globals.localMediaProgress.find((mp) => {
- if (localEpisodeId) return mp.localEpisodeId === localEpisodeId
- return mp.localLibraryItemId === localLibraryItemId
- })
- if (localMediaProgress) {
- console.log('[AudioPlayerContainer] device visibility: found local media progress', localMediaProgress.currentTime, 'last time in player is', this.currentTime)
- this.$refs.audioPlayer.currentTime = localMediaProgress.currentTime
- this.$refs.audioPlayer.timeupdate()
- } else {
- console.error('[AudioPlayerContainer] device visibility: Local media progress not found')
- }
- } else {
- const libraryItemId = playbackSession.libraryItemId
- const episodeId = playbackSession.episodeId
- const url = episodeId ? `/api/me/progress/${libraryItemId}/${episodeId}` : `/api/me/progress/${libraryItemId}`
- this.$nativeHttp
- .get(url)
- .then((data) => {
- if (!this.$refs.audioPlayer?.isPlaying && data.libraryItemId === libraryItemId) {
- console.log('[AudioPlayerContainer] device visibility: got server media progress', data.currentTime, 'last time in player is', this.currentTime)
- this.$refs.audioPlayer.currentTime = data.currentTime
- this.$refs.audioPlayer.timeupdate()
- }
- })
- .catch((error) => {
- console.error('[AudioPlayerContainer] device visibility: Failed to get progress', error)
- })
+ console.log('[AudioPlayerContainer] device visibility: got server media progress', data.currentTime, 'last time in player is', this.currentTime)
+ // Only seek if the difference is greater than 1 second
+ if (Math.abs(data.currentTime - this.currentTime) > 1) {
+ // Use seek() so the native audio player's current session is updated
+ this.$refs.audioPlayer.seek(data.currentTime)
}
}
}
@@ -368,6 +452,7 @@ export default {
this.$eventBus.$on('user-settings', this.settingsUpdated)
this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate)
this.$eventBus.$on('device-focus-update', this.deviceFocused)
+ this.$eventBus.$on('socket-reconnected', this.socketReconnected)
},
beforeDestroy() {
this.onLocalMediaProgressUpdateListener?.remove()
@@ -383,6 +468,7 @@ export default {
this.$eventBus.$off('user-settings', this.settingsUpdated)
this.$eventBus.$off('playback-time-update', this.playbackTimeUpdate)
this.$eventBus.$off('device-focus-update', this.deviceFocused)
+ this.$eventBus.$off('socket-reconnected', this.socketReconnected)
}
}
diff --git a/components/connection/ServerConnectForm.vue b/components/connection/ServerConnectForm.vue
index e4abd33b..24105626 100644
--- a/components/connection/ServerConnectForm.vue
+++ b/components/connection/ServerConnectForm.vue
@@ -484,7 +484,7 @@ export default {
const { value } = await Dialog.confirm({
title: this.$strings.HeaderConfirm,
- message: this.$strings.MessageConfirmDeleteServerConfig,
+ message: this.$strings.MessageConfirmDeleteServerConfig
})
if (value) {
this.processing = true
@@ -843,7 +843,7 @@ export default {
async setUserAndConnection({ user, userDefaultLibraryId, serverSettings, ereaderDevices }) {
if (!user) return
- console.log('Successfully logged in', JSON.stringify(user))
+ console.log('Successfully logged in: ' + user.username)
this.$store.commit('setServerSettings', serverSettings)
this.$store.commit('libraries/setEReaderDevices', ereaderDevices)
diff --git a/components/widgets/DownloadProgressIndicator.vue b/components/widgets/DownloadProgressIndicator.vue
index 8e389c7d..be1d502c 100644
--- a/components/widgets/DownloadProgressIndicator.vue
+++ b/components/widgets/DownloadProgressIndicator.vue
@@ -12,7 +12,8 @@ export default {
return {
downloadItemListener: null,
completeListener: null,
- itemPartUpdateListener: null
+ itemPartUpdateListener: null,
+ queueChangedListener: null
}
},
computed: {
@@ -76,17 +77,22 @@ export default {
},
onDownloadItemPartUpdate(itemPart) {
this.$store.commit('globals/updateDownloadItemPart', itemPart)
+ },
+ onQueueChanged(data) {
+ if (!data.hasWork) this.$store.commit('globals/clearItemDownloads')
}
},
async mounted() {
this.downloadItemListener = await AbsDownloader.addListener('onDownloadItem', (data) => this.onDownloadItem(data))
this.itemPartUpdateListener = await AbsDownloader.addListener('onDownloadItemPartUpdate', (data) => this.onDownloadItemPartUpdate(data))
+ this.queueChangedListener = await AbsDownloader.addListener('onQueueChanged', (data) => this.onQueueChanged(data))
this.completeListener = await AbsDownloader.addListener('onItemDownloadComplete', (data) => this.onItemDownloadComplete(data))
},
beforeDestroy() {
this.downloadItemListener?.remove()
this.completeListener?.remove()
this.itemPartUpdateListener?.remove()
+ this.queueChangedListener?.remove()
}
}
\ No newline at end of file
diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj
index 61eb36df..ad63bbaf 100644
--- a/ios/App/App.xcodeproj/project.pbxproj
+++ b/ios/App/App.xcodeproj/project.pbxproj
@@ -740,12 +740,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 0.11.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -764,12 +764,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 0.11.0;
+ MARKETING_VERSION = 0.13.0;
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock
index 1fc0fd35..fdd46c56 100644
--- a/ios/App/Podfile.lock
+++ b/ios/App/Podfile.lock
@@ -25,11 +25,11 @@ PODS:
- Capacitor
- CordovaPlugins (6.2.1):
- CapacitorCordova
- - Realm (10.54.4):
- - Realm/Headers (= 10.54.4)
- - Realm/Headers (10.54.4)
- - RealmSwift (10.54.4):
- - Realm (= 10.54.4)
+ - Realm (10.54.6):
+ - Realm/Headers (= 10.54.6)
+ - Realm/Headers (10.54.6)
+ - RealmSwift (10.54.6):
+ - Realm (= 10.54.6)
- WebnativellcCapacitorFilesharer (7.0.4):
- Capacitor
@@ -89,22 +89,22 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
- Capacitor: 106e7a4205f4618d582b886a975657c61179138d
- CapacitorApp: d63334c052278caf5d81585d80b21905c6f93f39
- CapacitorBrowser: 081852cf532acf77b9d2953f3a88fe5b9711fb06
- CapacitorClipboard: b98aead5dc7ec595547fc2c5d75bacd2ae3338bc
- CapacitorCommunityKeepAwake: 00dfd8fa3cca0df003c9a3e2cd7bee678aeec68b
- CapacitorCommunityVolumeButtons: 8a0443a202ed659688d85f4d44d66f42f62f2b56
+ Capacitor: 03bc7cbdde6a629a8b910a9d7d78c3cc7ed09ea7
+ CapacitorApp: febecbb9582cb353aed037e18ec765141f880fe9
+ CapacitorBrowser: 6299776d496e968505464884d565992faa20444a
+ CapacitorClipboard: 70bfdb42b877b320a6e511ab94fa7a6a55d57ecb
+ CapacitorCommunityKeepAwake: ae762ce29b53147d28cfcaae5273cd1db0c38fc4
+ CapacitorCommunityVolumeButtons: 1b84f7abf29cd9476cef9e8979b2854a64d2eed5
CapacitorCordova: 5967b9ba03915ef1d585469d6e31f31dc49be96f
- CapacitorDialog: 9b934329026b2b0ffa56939bb06df3c67541a2ab
- CapacitorHaptics: 70e47470fa1a6bd6338cd102552e3846b7f9a1b3
- CapacitorNetwork: 07ec4c69c1bb696f41c23e00d31bda1bbb221bba
- CapacitorPreferences: cbf154e5e5519b7f5ab33817a334dda1e98387f9
- CapacitorStatusBar: 275cbf2f4dfc00388f519ef80c7ec22edda342c9
- CordovaPlugins: 5a72a85b45469e68556bb172409f1b6d57b27236
- Realm: 8b5cda39a41f17a1734da2f39c6004eb8745587a
- RealmSwift: 0b4f808fed6898f1f6c26f501f740efd80dff0b4
- WebnativellcCapacitorFilesharer: 10b111373d4dc49608935600dcbcc14605258c73
+ CapacitorDialog: 0e09f242f6c3f5e82e4dc76b20f2a056be57a579
+ CapacitorHaptics: 1f1e17041f435d8ead9ff2a34edd592c6aa6a8d6
+ CapacitorNetwork: 15cb4385f0913a8ceb5e9a4d7af1ec554bdb8de8
+ CapacitorPreferences: 6c98117d4d7508034a4af9db64d6b26fc75d7b94
+ CapacitorStatusBar: 6e7af040d8fc4dd655999819625cae9c2d74c36f
+ CordovaPlugins: 2ecbba09775516c41764dbf78ade612427311b7e
+ Realm: b1b3bc68162fa242132eb7eefbf91d7c40f36a85
+ RealmSwift: 456cfd82a4f23dff8e3456980999331ab69bbf3e
+ WebnativellcCapacitorFilesharer: e3a5930240633db3335040251d66aac6762ff111
PODFILE CHECKSUM: 498821c0cfa2508609567fa95d7244c01cbef538
diff --git a/layouts/default.vue b/layouts/default.vue
index aa621721..f7ea3885 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -24,6 +24,7 @@ export default {
inittingLibraries: false,
hasMounted: false,
disconnectTime: 0,
+ socketDisconnectedTime: 0,
timeLostFocus: 0,
currentLang: null
}
@@ -44,7 +45,7 @@ export default {
} else {
var timeSinceDisconnect = Date.now() - this.disconnectTime
if (timeSinceDisconnect > 5000) {
- console.log('Time since disconnect was', timeSinceDisconnect, 'sync with server')
+ console.log('[default] Time since disconnect was', timeSinceDisconnect, 'sync with server')
setTimeout(() => {
this.syncLocalSessions(false)
}, 4000)
@@ -55,6 +56,28 @@ export default {
this.disconnectTime = Date.now()
}
}
+ },
+ socketConnected: {
+ handler(newVal, oldVal) {
+ if (!this.hasMounted) {
+ // watcher runs before mount, handling libraries/connection should be handled in mount
+ return
+ }
+ if (newVal) {
+ // if we havent been receiving socket events then external progress updates may have been missed
+ const timeSinceDisconnect = Date.now() - this.socketDisconnectedTime
+ if (timeSinceDisconnect > 30000 && this.isPlayerOpen) {
+ console.log('[default] socket reconnected after ' + timeSinceDisconnect + 'ms and player is open, triggering server media progress sync')
+ // used for triggering a server media progress sync if local media item is open in player
+ this.$eventBus.$emit('socket-reconnected')
+ } else {
+ console.log('[default] socket reconnected after ' + timeSinceDisconnect + 'ms')
+ }
+ } else {
+ console.log('[default] socket disconnected')
+ this.socketDisconnectedTime = Date.now()
+ }
+ }
}
},
computed: {
@@ -67,6 +90,9 @@ export default {
networkConnected() {
return this.$store.state.networkConnected
},
+ socketConnected() {
+ return this.$store.state.socketConnected
+ },
user() {
return this.$store.state.user.user
},
@@ -218,9 +244,9 @@ export default {
AbsLogger.info({ tag: 'default', message: 'Calling syncLocalSessions' })
const response = await this.$db.syncLocalSessionsWithServer(isFirstSync)
if (response?.error) {
- console.error('[default] Failed to sync local sessions', response.error)
+ await AbsLogger.error({ tag: 'default', message: `syncLocalSessions: Failed to sync local sessions: ${response.error}` })
} else {
- console.log('[default] Successfully synced local sessions')
+ await AbsLogger.info({ tag: 'default', message: 'syncLocalSessions: Successfully synced local sessions' })
// Reload local media progresses
await this.$store.dispatch('globals/loadLocalMediaProgress')
}
@@ -233,11 +259,13 @@ export default {
async userMediaProgressUpdated(payload) {
const prog = payload.data // MediaProgress
await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: Received updated media progress for current user from socket event. Media item id ${payload.id}` })
+ const mediaProgressId = payload.id
+ const itemLabel = `${prog.libraryItemId}${prog.episodeId ? ` episodeId: ${prog.episodeId}` : ''}`
// Check if this media item is currently open in the player, paused, and this progress update is coming from a different session
const isMediaOpenInPlayer = this.$store.getters['getIsMediaStreaming'](prog.libraryItemId, prog.episodeId)
if (isMediaOpenInPlayer && this.$store.getters['getCurrentPlaybackSessionId'] !== payload.sessionId && !this.$store.state.playerIsPlaying) {
- await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: Item is currently open in player, paused and this progress update is coming from a different session. Updating playback time to ${payload.data.currentTime}` })
+ await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: Updating paused player playback time to ${payload.data.currentTime} (${itemLabel}, mediaProgressId: ${mediaProgressId})` })
this.$eventBus.$emit('playback-time-update', payload.data.currentTime)
}
@@ -248,17 +276,17 @@ export default {
// Progress update is more recent then local progress
if (localProg && localProg.lastUpdate < prog.lastUpdate) {
if (localProg.currentTime == prog.currentTime && localProg.isFinished == prog.isFinished) {
- await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: server lastUpdate is more recent but progress is up-to-date (libraryItemId: ${prog.libraryItemId}${prog.episodeId ? ` episodeId: ${prog.episodeId}` : ''})` })
+ await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: server lastUpdate is more recent but progress is up-to-date (${itemLabel}, mediaProgressId: ${mediaProgressId}, server lastUpdate=${prog.lastUpdate} > local lastUpdate=${localProg.lastUpdate})` })
return
}
// Server progress is more up-to-date
- await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: syncing progress from server with local item for "${prog.libraryItemId}" ${prog.episodeId ? `episode ${prog.episodeId}` : ''} | server lastUpdate=${prog.lastUpdate} > local lastUpdate=${localProg.lastUpdate}` })
- const payload = {
+ await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: Syncing server progress to local (${itemLabel}, mediaProgressId: ${mediaProgressId}, server lastUpdate=${prog.lastUpdate} > local lastUpdate=${localProg.lastUpdate})` })
+ const syncPayload = {
localMediaProgressId: localProg.id,
mediaProgress: prog
}
- newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(payload)
+ newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(syncPayload)
} else if (!localProg) {
// Check if local library item exists
// local media progress may not exist yet if it hasn't been played
@@ -270,20 +298,20 @@ export default {
const localEpisode = lliEpisodes.find((ep) => ep.serverEpisodeId === prog.episodeId)
if (localEpisode) {
// Add new local media progress
- const payload = {
+ const syncPayload = {
localLibraryItemId: localLibraryItem.id,
localEpisodeId: localEpisode.id,
mediaProgress: prog
}
- newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(payload)
+ newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(syncPayload)
}
} else {
// Add new local media progress
- const payload = {
+ const syncPayload = {
localLibraryItemId: localLibraryItem.id,
mediaProgress: prog
}
- newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(payload)
+ newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(syncPayload)
}
} else {
console.log(`[default] userMediaProgressUpdate no local media progress or lli found for this server item ${prog.id}`)
@@ -291,7 +319,7 @@ export default {
}
if (newLocalMediaProgress?.id) {
- await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: local media progress updated for ${newLocalMediaProgress.id}` })
+ await AbsLogger.info({ tag: 'default', message: `userMediaProgressUpdate: Local media progress updated (${itemLabel}, localId: ${newLocalMediaProgress.id})` })
this.$store.commit('globals/updateLocalMediaProgress', newLocalMediaProgress)
}
},
diff --git a/package-lock.json b/package-lock.json
index 2a3385a9..adf34e43 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "audiobookshelf-app",
- "version": "0.12.0-beta",
+ "version": "0.13.0-beta",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "audiobookshelf-app",
- "version": "0.12.0-beta",
+ "version": "0.13.0-beta",
"dependencies": {
"@capacitor-community/keep-awake": "^7.0.0",
"@capacitor-community/volume-buttons": "^7.0.0",
diff --git a/package.json b/package.json
index 4e4777e2..386f4da2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-app",
- "version": "0.12.0-beta",
+ "version": "0.13.0-beta",
"author": "advplyr",
"scripts": {
"dev": "nuxt --hostname 0.0.0.0 --port 1337",
diff --git a/pages/item/_id/index.vue b/pages/item/_id/index.vue
index 4966eecf..3cec7392 100644
--- a/pages/item/_id/index.vue
+++ b/pages/item/_id/index.vue
@@ -13,7 +13,7 @@