diff --git a/client/components/app/Appbar.vue b/client/components/app/Appbar.vue index 6ad9553d..5bff062e 100644 --- a/client/components/app/Appbar.vue +++ b/client/components/app/Appbar.vue @@ -47,8 +47,8 @@

{{ numLibraryItemsSelected }} Selected

- - + + @@ -100,8 +100,8 @@ export default { selectedLibraryItems() { return this.$store.state.selectedLibraryItems }, - userAudiobooks() { - return this.$store.state.user.user.audiobooks || {} + userItemProgress() { + return this.$store.state.user.user.libraryItemProgress || [] }, userCanUpdate() { return this.$store.getters['user/getUserCanUpdate'] @@ -112,11 +112,11 @@ export default { userCanUpload() { return this.$store.getters['user/getUserCanUpload'] }, - selectedIsRead() { - // Find an audiobook that is not read, if none then all audiobooks read - return !this.selectedLibraryItems.find((li) => { - var userAb = this.userAudiobooks[li] - return !userAb || !userAb.isRead + selectedIsFinished() { + // Find an item that is not finished, if none then all items finished + return !this.selectedLibraryItems.find((libraryItemId) => { + var itemProgress = this.userItemProgress.find((lip) => lip.id === libraryItemId) + return !itemProgress || !itemProgress.isFinished }) }, processingBatch() { @@ -153,15 +153,15 @@ export default { }, toggleBatchRead() { this.$store.commit('setProcessingBatch', true) - var newIsRead = !this.selectedIsRead + var newIsFinished = !this.selectedIsFinished var updateProgressPayloads = this.selectedLibraryItems.map((lid) => { return { - audiobookId: lid, - isRead: newIsRead + id: lid, + isFinished: newIsFinished } }) this.$axios - .patch(`/api/me/audiobook/batch/update`, updateProgressPayloads) + .patch(`/api/me/progress/batch/update`, updateProgressPayloads) .then(() => { this.$toast.success('Batch update success!') this.$store.commit('setProcessingBatch', false) diff --git a/client/components/app/BookListRow.vue b/client/components/app/BookListRow.vue index 03f90470..4dbc09a1 100644 --- a/client/components/app/BookListRow.vue +++ b/client/components/app/BookListRow.vue @@ -150,23 +150,6 @@ export default { downloadClick() { this.$store.commit('showEditModalOnTab', { libraryItem: this.book, tab: 'download' }) }, - toggleRead() { - var updatePayload = { - isRead: !this.userIsRead - } - this.isProcessingReadUpdate = true - this.$axios - .$patch(`/api/me/audiobook/${this.libraryItemId}`, updatePayload) - .then(() => { - this.isProcessingReadUpdate = false - this.$toast.success(`"${this.title}" Marked as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) - }) - .catch((error) => { - console.error('Failed', error) - this.isProcessingReadUpdate = false - this.$toast.error(`Failed to mark as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) - }) - }, startStream() { this.$eventBus.$emit('play-item', this.book.id) }, diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue index 676704a7..b479a307 100644 --- a/client/components/cards/LazyBookCard.vue +++ b/client/components/cards/LazyBookCard.vue @@ -301,8 +301,8 @@ export default { moreMenuItems() { var items = [ { - func: 'toggleRead', - text: `Mark as ${this.itemIsFinished ? 'Not Read' : 'Read'}` + func: 'toggleFinished', + text: `Mark as ${this.itemIsFinished ? 'Not Finished' : 'Finished'}` }, { func: 'openCollections', @@ -398,8 +398,7 @@ export default { editClick() { this.$emit('edit', this.audiobook) }, - toggleRead() { - // More menu func + toggleFinished() { var updatePayload = { isFinished: !this.itemIsFinished } @@ -407,15 +406,15 @@ export default { var toast = this.$toast || this.$nuxt.$toast var axios = this.$axios || this.$nuxt.$axios axios - .$patch(`/api/me/audiobook/${this.libraryItemId}`, updatePayload) + .$patch(`/api/me/progress/${this.libraryItemId}`, updatePayload) .then(() => { this.isProcessingReadUpdate = false - toast.success(`"${this.title}" Marked as ${updatePayload.isFinished ? 'Read' : 'Not Read'}`) + toast.success(`Item marked as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) .catch((error) => { console.error('Failed', error) this.isProcessingReadUpdate = false - toast.error(`Failed to mark as ${updatePayload.isFinished ? 'Read' : 'Not Read'}`) + toast.error(`Failed to mark as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) }, itemScanComplete(result) { diff --git a/client/components/tables/collection/BookTableRow.vue b/client/components/tables/collection/BookTableRow.vue index 13b62545..4ed8fe9e 100644 --- a/client/components/tables/collection/BookTableRow.vue +++ b/client/components/tables/collection/BookTableRow.vue @@ -35,8 +35,8 @@
-->
- - + +
@@ -68,12 +68,6 @@ export default { } }, watch: { - userIsRead: { - immediate: true, - handler(newVal) { - this.isRead = newVal - } - }, isDragging: { handler(newVal) { if (newVal) { @@ -113,14 +107,11 @@ export default { showPlayBtn() { return !this.isMissing && !this.isInvalid && !this.isStreaming && this.numTracks }, - userAudiobooks() { - return this.$store.state.user.user ? this.$store.state.user.user.audiobooks || {} : {} + itemProgress() { + return this.$store.getters['user/getUserLibraryItemProgress'](this.book.id) }, - userAudiobook() { - return this.userAudiobooks[this.book.id] || null - }, - userIsRead() { - return this.userAudiobook ? !!this.userAudiobook.isRead : false + userIsFinished() { + return this.itemProgress ? !!this.itemProgress.isFinished : false }, coverWidth() { if (this.bookCoverAspectRatio === 1) return 50 * 1.6 @@ -141,21 +132,21 @@ export default { clickEdit() { this.$emit('edit', this.book) }, - toggleRead() { + toggleFinished() { var updatePayload = { - isRead: !this.isRead + isFinished: !this.userIsFinished } this.isProcessingReadUpdate = true this.$axios - .$patch(`/api/me/audiobook/${this.book.id}`, updatePayload) + .$patch(`/api/me/progress/${this.book.id}`, updatePayload) .then(() => { this.isProcessingReadUpdate = false - this.$toast.success(`"${this.bookTitle}" Marked as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) + this.$toast.success(`Item marked as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) .catch((error) => { console.error('Failed', error) this.isProcessingReadUpdate = false - this.$toast.error(`Failed to mark as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) + this.$toast.error(`Failed to mark as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) }, removeClick() { diff --git a/client/layouts/default.vue b/client/layouts/default.vue index 6e61b366..25a211bb 100644 --- a/client/layouts/default.vue +++ b/client/layouts/default.vue @@ -258,8 +258,9 @@ export default { userStreamUpdate(user) { this.$store.commit('users/updateUser', user) }, - currentUserAudiobookUpdate(payload) { - this.$store.commit('user/updateUserAudiobook', payload) + userItemProgressUpdate(payload) { + console.log('User item progress update', payload) + this.$store.commit('user/updateItemProgress', payload) }, collectionAdded(collection) { this.$store.commit('user/addUpdateCollection', collection) @@ -384,7 +385,7 @@ export default { this.socket.on('user_online', this.userOnline) this.socket.on('user_offline', this.userOffline) this.socket.on('user_stream_update', this.userStreamUpdate) - this.socket.on('current_user_audiobook_update', this.currentUserAudiobookUpdate) + this.socket.on('user_item_progress_updated', this.userItemProgressUpdate) // User Collection Listeners this.socket.on('collection_added', this.collectionAdded) diff --git a/client/pages/config/stats.vue b/client/pages/config/stats.vue index a4f20410..2d05fcfd 100644 --- a/client/pages/config/stats.vue +++ b/client/pages/config/stats.vue @@ -60,7 +60,6 @@ export default { data() { return { listeningStats: null - // libraryStats: null } }, watch: { @@ -103,11 +102,6 @@ export default { }, methods: { async init() { - // this.libraryStats = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/stats`).catch((err) => { - // console.error('Failed to get library stats', err) - // var errorMsg = err.response ? err.response.data || 'Unknown Error' : 'Unknown Error' - // this.$toast.error(`Failed to get library stats: ${errorMsg}`) - // }) this.listeningStats = await this.$axios.$get(`/api/me/listening-stats`).catch((err) => { console.error('Failed to load listening sesions', err) return [] diff --git a/client/pages/item/_id/index.vue b/client/pages/item/_id/index.vue index c99e06ae..2b89670d 100644 --- a/client/pages/item/_id/index.vue +++ b/client/pages/item/_id/index.vue @@ -7,7 +7,7 @@ -
+
@@ -130,8 +130,8 @@ - - + + @@ -173,19 +173,10 @@ export default { }, data() { return { - isRead: false, resettingProgress: false, isProcessingReadUpdate: false } }, - watch: { - userIsRead: { - immediate: true, - handler(newVal) { - this.isRead = newVal - } - } - }, computed: { coverAspectRatio() { return this.$store.getters['getServerSetting']('coverAspectRatio') @@ -298,29 +289,26 @@ export default { description() { return this.mediaMetadata.description || '' }, - userAudiobooks() { - return this.$store.state.user.user ? this.$store.state.user.user.audiobooks || {} : {} - }, - userAudiobook() { - return this.userAudiobooks[this.libraryItemId] || null + userItemProgress() { + return this.$store.getters['user/getUserLibraryItemProgress'](this.libraryItemId) }, userCurrentTime() { - return this.userAudiobook ? this.userAudiobook.currentTime : 0 + return this.userItemProgress ? this.userItemProgress.currentTime : 0 }, - userIsRead() { - return this.userAudiobook ? !!this.userAudiobook.isRead : false + userIsFinished() { + return this.userItemProgress ? !!this.userItemProgress.isFinished : false }, userTimeRemaining() { return this.duration - this.userCurrentTime }, progressPercent() { - return this.userAudiobook ? Math.max(Math.min(1, this.userAudiobook.progress), 0) : 0 + return this.userItemProgress ? Math.max(Math.min(1, this.userItemProgress.progress), 0) : 0 }, userProgressStartedAt() { - return this.userAudiobook ? this.userAudiobook.startedAt : 0 + return this.userItemProgress ? this.userItemProgress.startedAt : 0 }, userProgressFinishedAt() { - return this.userAudiobook ? this.userAudiobook.finishedAt : 0 + return this.userItemProgress ? this.userItemProgress.finishedAt : 0 }, streamLibraryItem() { return this.$store.state.streamLibraryItem @@ -346,21 +334,21 @@ export default { openEbook() { this.$store.commit('showEReader', this.libraryItem) }, - toggleRead() { + toggleFinished() { var updatePayload = { - isRead: !this.isRead + isFinished: !this.userIsFinished } this.isProcessingReadUpdate = true this.$axios - .$patch(`/api/me/audiobook/${this.libraryItemId}`, updatePayload) + .$patch(`/api/me/progress/${this.libraryItemId}`, updatePayload) .then(() => { this.isProcessingReadUpdate = false - this.$toast.success(`"${this.title}" Marked as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) + this.$toast.success(`Item marked as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) .catch((error) => { console.error('Failed', error) this.isProcessingReadUpdate = false - this.$toast.error(`Failed to mark as ${updatePayload.isRead ? 'Read' : 'Not Read'}`) + this.$toast.error(`Failed to mark as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`) }) }, startStream() { @@ -386,7 +374,7 @@ export default { if (confirm(`Are you sure you want to reset your progress?`)) { this.resettingProgress = true this.$axios - .$patch(`/api/me/audiobook/${this.libraryItemId}/reset-progress`) + .$delete(`/api/me/progress/${this.libraryItemId}`) .then(() => { console.log('Progress reset complete') this.$toast.success(`Your progress was reset`) diff --git a/client/store/user.js b/client/store/user.js index a9b141a9..e8b9d700 100644 --- a/client/store/user.js +++ b/client/store/user.js @@ -104,12 +104,18 @@ export const mutations = { localStorage.removeItem('token') } }, - updateUserAudiobook(state, { id, data }) { + updateItemProgress(state, { id, data }) { if (!state.user) return - if (!state.user.audiobooks) { - Vue.set(state.user, 'audiobooks', {}) + if (!data) { + state.user.libraryItemProgress = state.user.libraryItemProgress.filter(lip => lip.id != id) + } else { + var indexOf = state.user.libraryItemProgress.findIndex(lip => lip.id == id) + if (indexOf >= 0) { + state.user.libraryItemProgress.splice(indexOf, 1, data) + } else { + state.user.libraryItemProgress.push(data) + } } - Vue.set(state.user.audiobooks, id, data) }, setSettings(state, settings) { if (!settings) return diff --git a/server/ApiController.js b/server/ApiController.js index ae03bc06..bc70a154 100644 --- a/server/ApiController.js +++ b/server/ApiController.js @@ -131,9 +131,9 @@ class ApiController { // this.router.get('/me/listening-sessions', MeController.getListeningSessions.bind(this)) this.router.get('/me/listening-stats', MeController.getListeningStats.bind(this)) - this.router.patch('/me/audiobook/:id/reset-progress', MeController.resetAudiobookProgress.bind(this)) - this.router.patch('/me/audiobook/:id', MeController.updateAudiobookData.bind(this)) - this.router.patch('/me/audiobook/batch/update', MeController.batchUpdateAudiobookData.bind(this)) + this.router.patch('/me/progress/:id', MeController.createUpdateLibraryItemProgress.bind(this)) + this.router.delete('/me/progress/:id', MeController.removeLibraryItemProgress.bind(this)) + this.router.patch('/me/progress/batch/update', MeController.batchUpdateLibraryItemProgress.bind(this)) this.router.patch('/me/password', MeController.updatePassword.bind(this)) this.router.patch('/me/settings', MeController.updateSettings.bind(this)) @@ -306,35 +306,35 @@ class ApiController { } async syncUserAudiobookData(req, res) { - if (!req.body.data) { - return res.status(403).send('Invalid local user audiobook data') - } + // if (!req.body.data) { + // return res.status(403).send('Invalid local user audiobook data') + // } - var hasUpdates = false + // var hasUpdates = false - // Local user audiobook data use the latest update - req.body.data.forEach((uab) => { - if (!uab || !uab.audiobookId) { - Logger.error('[ApiController] Invalid user audiobook data', uab) - return - } - var audiobook = this.db.audiobooks.find(ab => ab.id === uab.audiobookId) - if (!audiobook) { - Logger.info('[ApiController] syncUserAudiobookData local audiobook data audiobook no longer exists', uab.audiobookId) - return - } - if (req.user.syncLocalUserAudiobookData(uab, audiobook)) { - this.clientEmitter(req.user.id, 'current_user_audiobook_update', { id: uab.audiobookId, data: uab }) - hasUpdates = true - } - }) + // // Local user audiobook data use the latest update + // req.body.data.forEach((uab) => { + // if (!uab || !uab.audiobookId) { + // Logger.error('[ApiController] Invalid user audiobook data', uab) + // return + // } + // var audiobook = this.db.audiobooks.find(ab => ab.id === uab.audiobookId) + // if (!audiobook) { + // Logger.info('[ApiController] syncUserAudiobookData local audiobook data audiobook no longer exists', uab.audiobookId) + // return + // } + // if (req.user.syncLocalUserAudiobookData(uab, audiobook)) { + // this.clientEmitter(req.user.id, 'current_user_audiobook_update', { id: uab.audiobookId, data: uab }) + // hasUpdates = true + // } + // }) - if (hasUpdates) { - await this.db.updateEntity('user', req.user) - } + // if (hasUpdates) { + // await this.db.updateEntity('user', req.user) + // } - var allUserAudiobookData = Object.values(req.user.audiobooksToJSON()) - res.json(allUserAudiobookData) + // var allUserAudiobookData = Object.values(req.user.audiobooksToJSON()) + // res.json(allUserAudiobookData) } // Sync audiobook stream progress @@ -346,16 +346,16 @@ class ApiController { // Sync local downloaded audiobook progress async syncLocal(req, res) { - Logger.debug(`[ApiController] syncLocal for ${req.user.username}`) - var progressPayload = req.body - var audiobookProgress = req.user.updateAudiobookData(progressPayload.audiobookId, progressPayload) - if (audiobookProgress) { - await this.db.updateEntity('user', req.user) - this.clientEmitter(req.user.id, 'current_user_audiobook_update', { - id: progressPayload.audiobookId, - data: audiobookProgress || null - }) - } + // Logger.debug(`[ApiController] syncLocal for ${req.user.username}`) + // var progressPayload = req.body + // var itemProgress = req.user.updateLibraryItemProgress(progressPayload.libraryItemId, progressPayload) + // if (itemProgress) { + // await this.db.updateEntity('user', req.user) + // this.clientEmitter(req.user.id, 'current_user_audiobook_update', { + // id: progressPayload.libraryItemId, + // data: itemProgress || null + // }) + // } res.sendStatus(200) } @@ -384,7 +384,7 @@ class ApiController { // Remove libraryItem from users for (let i = 0; i < this.db.users.length; i++) { var user = this.db.users[i] - var madeUpdates = user.deleteAudiobookData(libraryItem.id) + var madeUpdates = user.removeLibraryItemProgress(libraryItem.id) if (madeUpdates) { await this.db.updateEntity('user', user) } diff --git a/server/Server.js b/server/Server.js index 55aa9e46..40d8e197 100644 --- a/server/Server.js +++ b/server/Server.js @@ -273,7 +273,7 @@ class Server { // socket.on('stream_sync', (syncData) => this.streamManager.streamSync(socket, syncData)) // Used to sync when playing local book on mobile, will be moved to API route - socket.on('progress_update', (payload) => this.audiobookProgressUpdate(socket, payload)) + // socket.on('progress_update', (payload) => this.audiobookProgressUpdate(socket, payload)) // Downloading socket.on('download', (payload) => this.downloadManager.downloadSocketRequest(socket, payload)) @@ -388,7 +388,7 @@ class Server { if (audiobookIdsToRemove.length) { Logger.debug(`[Server] Found ${audiobookIdsToRemove.length} audiobook data to remove from user ${_user.username}`) for (let y = 0; y < audiobookIdsToRemove.length; y++) { - _user.deleteAudiobookData(audiobookIdsToRemove[y]) + _user.removeLibraryItemProgress(audiobookIdsToRemove[y]) } await this.db.updateEntity('user', _user) } @@ -500,89 +500,89 @@ class Server { res.sendStatus(200) } - async audiobookProgressUpdate(socket, progressPayload) { - var client = socket.sheepClient - if (!client || !client.user) { - Logger.error('[Server] audiobookProgressUpdate invalid socket client') - return - } - var audiobookProgress = client.user.updateAudiobookData(progressPayload.audiobookId, progressPayload) - if (audiobookProgress) { - await this.db.updateEntity('user', client.user) - this.clientEmitter(client.user.id, 'current_user_audiobook_update', { - id: progressPayload.audiobookId, - data: audiobookProgress || null - }) - } - } + // async audiobookProgressUpdate(socket, progressPayload) { + // var client = socket.sheepClient + // if (!client || !client.user) { + // Logger.error('[Server] audiobookProgressUpdate invalid socket client') + // return + // } + // var audiobookProgress = client.user.createUpdateLibraryItemProgress(progressPayload.audiobookId, progressPayload) + // if (audiobookProgress) { + // await this.db.updateEntity('user', client.user) + // this.clientEmitter(client.user.id, 'current_user_audiobook_update', { + // id: progressPayload.audiobookId, + // data: audiobookProgress || null + // }) + // } + // } async createBookmark(socket, payload) { - var client = socket.sheepClient - if (!client || !client.user) { - Logger.error('[Server] createBookmark invalid socket client') - return - } - var userAudiobook = client.user.createBookmark(payload) - if (!userAudiobook || userAudiobook.error) { - var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' - socket.emit('show_error_toast', `Failed to create Bookmark: ${failMessage}`) - return - } + // var client = socket.sheepClient + // if (!client || !client.user) { + // Logger.error('[Server] createBookmark invalid socket client') + // return + // } + // var userAudiobook = client.user.createBookmark(payload) + // if (!userAudiobook || userAudiobook.error) { + // var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' + // socket.emit('show_error_toast', `Failed to create Bookmark: ${failMessage}`) + // return + // } - await this.db.updateEntity('user', client.user) + // await this.db.updateEntity('user', client.user) - socket.emit('show_success_toast', `${secondsToTimestamp(payload.time)} Bookmarked`) + // socket.emit('show_success_toast', `${secondsToTimestamp(payload.time)} Bookmarked`) - this.clientEmitter(client.user.id, 'current_user_audiobook_update', { - id: userAudiobook.audiobookId, - data: userAudiobook || null - }) + // this.clientEmitter(client.user.id, 'current_user_audiobook_update', { + // id: userAudiobook.audiobookId, + // data: userAudiobook || null + // }) } async updateBookmark(socket, payload) { - var client = socket.sheepClient - if (!client || !client.user) { - Logger.error('[Server] updateBookmark invalid socket client') - return - } - var userAudiobook = client.user.updateBookmark(payload) - if (!userAudiobook || userAudiobook.error) { - var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' - socket.emit('show_error_toast', `Failed to update Bookmark: ${failMessage}`) - return - } + // var client = socket.sheepClient + // if (!client || !client.user) { + // Logger.error('[Server] updateBookmark invalid socket client') + // return + // } + // var userAudiobook = client.user.updateBookmark(payload) + // if (!userAudiobook || userAudiobook.error) { + // var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' + // socket.emit('show_error_toast', `Failed to update Bookmark: ${failMessage}`) + // return + // } - await this.db.updateEntity('user', client.user) + // await this.db.updateEntity('user', client.user) - socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Updated`) + // socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Updated`) - this.clientEmitter(client.user.id, 'current_user_audiobook_update', { - id: userAudiobook.audiobookId, - data: userAudiobook || null - }) + // this.clientEmitter(client.user.id, 'current_user_audiobook_update', { + // id: userAudiobook.audiobookId, + // data: userAudiobook || null + // }) } async deleteBookmark(socket, payload) { - var client = socket.sheepClient - if (!client || !client.user) { - Logger.error('[Server] deleteBookmark invalid socket client') - return - } - var userAudiobook = client.user.deleteBookmark(payload) - if (!userAudiobook || userAudiobook.error) { - var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' - socket.emit('show_error_toast', `Failed to delete Bookmark: ${failMessage}`) - return - } + // var client = socket.sheepClient + // if (!client || !client.user) { + // Logger.error('[Server] deleteBookmark invalid socket client') + // return + // } + // var userAudiobook = client.user.deleteBookmark(payload) + // if (!userAudiobook || userAudiobook.error) { + // var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error' + // socket.emit('show_error_toast', `Failed to delete Bookmark: ${failMessage}`) + // return + // } - await this.db.updateEntity('user', client.user) + // await this.db.updateEntity('user', client.user) - socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Removed`) + // socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Removed`) - this.clientEmitter(client.user.id, 'current_user_audiobook_update', { - id: userAudiobook.audiobookId, - data: userAudiobook || null - }) + // this.clientEmitter(client.user.id, 'current_user_audiobook_update', { + // id: userAudiobook.audiobookId, + // data: userAudiobook || null + // }) } async authenticateSocket(socket, token) { diff --git a/server/controllers/MeController.js b/server/controllers/MeController.js index fd84d382..e979375f 100644 --- a/server/controllers/MeController.js +++ b/server/controllers/MeController.js @@ -16,31 +16,26 @@ class MeController { res.json(listeningStats) } - // PATCH: api/me/audiobook/:id/reset-progress - async resetAudiobookProgress(req, res) { - var libraryItem = this.db.libraryItems.find(li => li.id === req.params.id) - if (!libraryItem) { - return res.status(404).send('Item not found') + // DELETE: api/me/progress/:id + async removeLibraryItemProgress(req, res) { + var wasRemoved = req.user.removeLibraryItemProgress(req.params.id) + if (!wasRemoved) { + return res.sendStatus(200) } - req.user.resetAudiobookProgress(libraryItem) await this.db.updateEntity('user', req.user) - - var userAudiobookData = req.user.audiobooks[libraryItem.id] - if (userAudiobookData) { - this.clientEmitter(req.user.id, 'current_user_audiobook_update', { id: libraryItem.id, data: userAudiobookData }) - } + this.clientEmitter(req.user.id, 'user_item_progress_updated', { id: libraryItem.id, data: null }) this.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser()) res.sendStatus(200) } - // PATCH: api/me/audiobook/:id - async updateAudiobookData(req, res) { + // PATCH: api/me/progress/:id + async createUpdateLibraryItemProgress(req, res) { var libraryItem = this.db.libraryItems.find(ab => ab.id === req.params.id) if (!libraryItem) { return res.status(404).send('Item not found') } - var wasUpdated = req.user.updateAudiobookData(libraryItem.id, req.body) + var wasUpdated = req.user.createUpdateLibraryItemProgress(libraryItem.id, req.body) if (wasUpdated) { await this.db.updateEntity('user', req.user) this.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser()) @@ -48,19 +43,21 @@ class MeController { res.sendStatus(200) } - // PATCH: api/me/audiobook/batch/update - async batchUpdateAudiobookData(req, res) { - var userAbDataPayloads = req.body - if (!userAbDataPayloads || !userAbDataPayloads.length) { + // PATCH: api/me/progress/batch/update + async batchUpdateLibraryItemProgress(req, res) { + var itemProgressPayloads = req.body + if (!itemProgressPayloads || !itemProgressPayloads.length) { return res.sendStatus(500) } var shouldUpdate = false - userAbDataPayloads.forEach((userAbData) => { - var libraryItem = this.db.libraryItems.find(li => li.id === userAbData.audiobookId) + itemProgressPayloads.forEach((itemProgress) => { + var libraryItem = this.db.libraryItems.find(li => li.id === itemProgress.id) // Make sure this library item exists if (libraryItem) { - var wasUpdated = req.user.updateAudiobookData(libraryItem.id, userAbData) + var wasUpdated = req.user.createUpdateLibraryItemProgress(libraryItem.id, itemProgress) if (wasUpdated) shouldUpdate = true + } else { + Logger.error(`[MeController] batchUpdateLibraryItemProgress: Library Item does not exist ${itemProgress.id}`) } }) diff --git a/server/objects/user/LibraryItemProgress.js b/server/objects/user/LibraryItemProgress.js index f9df5ed4..b57fda81 100644 --- a/server/objects/user/LibraryItemProgress.js +++ b/server/objects/user/LibraryItemProgress.js @@ -5,7 +5,6 @@ class LibraryItemProgress { this.id = null // Same as library item id this.libraryItemId = null - this.totalDuration = null // seconds this.progress = null // 0 to 1 this.currentTime = null // seconds this.isFinished = false @@ -23,7 +22,6 @@ class LibraryItemProgress { return { id: this.id, libraryItemId: this.libraryItemId, - totalDuration: this.totalDuration, progress: this.progress, currentTime: this.currentTime, isFinished: this.isFinished, @@ -36,7 +34,6 @@ class LibraryItemProgress { construct(progress) { this.id = progress.id this.libraryItemId = progress.libraryItemId - this.totalDuration = progress.totalDuration this.progress = progress.progress this.currentTime = progress.currentTime this.isFinished = !!progress.isFinished @@ -46,25 +43,40 @@ class LibraryItemProgress { } updateProgressFromStream(stream) { - this.audiobookId = stream.libraryItemId - this.totalDuration = stream.totalDuration - this.progress = stream.clientProgress - this.currentTime = stream.clientCurrentTime + // this.audiobookId = stream.libraryItemId + // this.totalDuration = stream.totalDuration + // this.progress = stream.clientProgress + // this.currentTime = stream.clientCurrentTime + // this.lastUpdate = Date.now() + + // if (!this.startedAt) { + // this.startedAt = Date.now() + // } + + // // If has < 10 seconds remaining mark as read + // var timeRemaining = this.totalDuration - this.currentTime + // if (timeRemaining < 10) { + // this.isFinished = true + // this.progress = 1 + // this.finishedAt = Date.now() + // } else { + // this.isFinished = false + // this.finishedAt = null + // } + } + + setData(libraryItemId, progress) { + this.id = libraryItemId + this.libraryItemId = libraryItemId + this.progress = Math.min(1, (progress.progress || 0)) + this.currentTime = progress.currentTime || 0 + this.isFinished = !!progress.isFinished || this.progress == 1 this.lastUpdate = Date.now() - - if (!this.startedAt) { - this.startedAt = Date.now() - } - - // If has < 10 seconds remaining mark as read - var timeRemaining = this.totalDuration - this.currentTime - if (timeRemaining < 10) { - this.isFinished = true - this.progress = 1 + this.startedAt = Date.now() + this.finishedAt = null + if (this.isFinished) { this.finishedAt = Date.now() - } else { - this.isFinished = false - this.finishedAt = null + this.progress = 1 } } diff --git a/server/objects/user/User.js b/server/objects/user/User.js index 0b637259..5886935f 100644 --- a/server/objects/user/User.js +++ b/server/objects/user/User.js @@ -204,18 +204,22 @@ class User { // return this.audiobooks[stream.audiobookId] } - updateAudiobookData(audiobookId, updatePayload) { - // if (!this.audiobooks) this.audiobooks = {} - // if (!this.audiobooks[audiobookId]) { - // this.audiobooks[audiobookId] = new UserAudiobookData() - // this.audiobooks[audiobookId].audiobookId = audiobookId - // } - // var wasUpdated = this.audiobooks[audiobookId].update(updatePayload) - // if (wasUpdated) { - // // Logger.debug(`[User] UserAudiobookData was updated ${JSON.stringify(this.audiobooks[audiobookId])}`) - // return this.audiobooks[audiobookId] - // } - // return false + createUpdateLibraryItemProgress(libraryItemId, updatePayload) { + var itemProgress = this.libraryItemProgress.find(li => li.id === libraryItemId) + if (!itemProgress) { + var newItemProgress = new LibraryItemProgress() + newItemProgress.setData(libraryItemId, updatePayload) + this.libraryItemProgress.push(newItemProgress) + return true + } + var wasUpdated = itemProgress.update(updatePayload) + return wasUpdated + } + + removeLibraryItemProgress(libraryItemId) { + if (!this.libraryItemProgress.some(lip => lip.id == libraryItemId)) return false + this.libraryItemProgress = this.libraryItemProgress.filter(lip => lip != libraryItemId) + return true } // Returns Boolean If update was made @@ -244,28 +248,6 @@ class User { return madeUpdates } - resetAudiobookProgress(libraryItem) { - // if (!this.audiobooks || !this.audiobooks[libraryItem.id]) { - // return false - // } - // return this.updateAudiobookData(libraryItem.id, { - // progress: 0, - // currentTime: 0, - // isRead: false, - // lastUpdate: Date.now(), - // startedAt: null, - // finishedAt: null - // }) - } - - deleteAudiobookData(audiobookId) { - // if (!this.audiobooks || !this.audiobooks[audiobookId]) { - // return false - // } - // delete this.audiobooks[audiobookId] - // return true - } - checkCanAccessLibrary(libraryId) { if (this.permissions.accessAllLibraries) return true if (!this.librariesAccessible) return false