mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Fix:Clean user data on server start removing invalid media progress items
This commit is contained in:
		
							parent
							
								
									9ee6eaade9
								
							
						
					
					
						commit
						ac30a971c5
					
				| @ -187,6 +187,11 @@ export default { | |||||||
|           this.$toast.error('Failed to start scan') |           this.$toast.error('Failed to start scan') | ||||||
|         }) |         }) | ||||||
|     }, |     }, | ||||||
|  |     userUpdated(user) { | ||||||
|  |       if (user.seriesHideFromContinueListening && user.seriesHideFromContinueListening.length) { | ||||||
|  |         this.removeAllSeriesFromContinueSeries(user.seriesHideFromContinueListening) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     libraryItemAdded(libraryItem) { |     libraryItemAdded(libraryItem) { | ||||||
|       console.log('libraryItem added', libraryItem) |       console.log('libraryItem added', libraryItem) | ||||||
|       // TODO: Check if libraryItem would be on this shelf |       // TODO: Check if libraryItem would be on this shelf | ||||||
| @ -244,23 +249,16 @@ export default { | |||||||
|         this.libraryItemUpdated(li) |         this.libraryItemUpdated(li) | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|     seriesUpdated(series) { |     removeAllSeriesFromContinueSeries(seriesIds) { | ||||||
|       if (series.hideFromHome) { |  | ||||||
|       this.shelves.forEach((shelf) => { |       this.shelves.forEach((shelf) => { | ||||||
|         if (shelf.type == 'book' && shelf.id == 'continue-series') { |         if (shelf.type == 'book' && shelf.id == 'continue-series') { | ||||||
|           // Filter out series books from continue series shelf |           // Filter out series books from continue series shelf | ||||||
|           shelf.entities = shelf.entities.filter((ent) => { |           shelf.entities = shelf.entities.filter((ent) => { | ||||||
|               if (ent.media.metadata.series && ent.media.metadata.series.id == series.id) return false |             if (ent.media.metadata.series && seriesIds.includes(ent.media.metadata.series.id)) return false | ||||||
|             return true |             return true | ||||||
|           }) |           }) | ||||||
|           } else if (shelf.type == 'series') { |  | ||||||
|             // Filter out series from series shelf |  | ||||||
|             shelf.entities = shelf.entities.filter((ent) => { |  | ||||||
|               return ent.id != series.id |  | ||||||
|             }) |  | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       } |  | ||||||
|     }, |     }, | ||||||
|     authorUpdated(author) { |     authorUpdated(author) { | ||||||
|       this.shelves.forEach((shelf) => { |       this.shelves.forEach((shelf) => { | ||||||
| @ -288,7 +286,7 @@ export default { | |||||||
|       this.$store.commit('user/addSettingsListener', { id: 'bookshelf', meth: this.settingsUpdated }) |       this.$store.commit('user/addSettingsListener', { id: 'bookshelf', meth: this.settingsUpdated }) | ||||||
| 
 | 
 | ||||||
|       if (this.$root.socket) { |       if (this.$root.socket) { | ||||||
|         this.$root.socket.on('series_updated', this.seriesUpdated) |         this.$root.socket.on('user_updated', this.userUpdated) | ||||||
|         this.$root.socket.on('author_updated', this.authorUpdated) |         this.$root.socket.on('author_updated', this.authorUpdated) | ||||||
|         this.$root.socket.on('author_removed', this.authorRemoved) |         this.$root.socket.on('author_removed', this.authorRemoved) | ||||||
|         this.$root.socket.on('item_updated', this.libraryItemUpdated) |         this.$root.socket.on('item_updated', this.libraryItemUpdated) | ||||||
| @ -304,7 +302,7 @@ export default { | |||||||
|       this.$store.commit('user/removeSettingsListener', 'bookshelf') |       this.$store.commit('user/removeSettingsListener', 'bookshelf') | ||||||
| 
 | 
 | ||||||
|       if (this.$root.socket) { |       if (this.$root.socket) { | ||||||
|         this.$root.socket.off('series_updated', this.seriesUpdated) |         this.$root.socket.off('user_updated', this.userUpdated) | ||||||
|         this.$root.socket.off('author_updated', this.authorUpdated) |         this.$root.socket.off('author_updated', this.authorUpdated) | ||||||
|         this.$root.socket.off('author_removed', this.authorRemoved) |         this.$root.socket.off('author_removed', this.authorRemoved) | ||||||
|         this.$root.socket.off('item_updated', this.libraryItemUpdated) |         this.$root.socket.off('item_updated', this.libraryItemUpdated) | ||||||
|  | |||||||
| @ -28,7 +28,6 @@ | |||||||
|             <span class="font-mono">{{ numShowing }}</span> |             <span class="font-mono">{{ numShowing }}</span> | ||||||
|           </div> |           </div> | ||||||
|           <div class="flex-grow" /> |           <div class="flex-grow" /> | ||||||
|           <ui-btn v-if="seriesHideFromHome" :loading="processingSeriesHideFromHome" color="primary" small class="mr-2" @click="showSeriesOnHome">Show on Home</ui-btn> |  | ||||||
|           <ui-btn color="primary" small :loading="processingSeries" class="flex items-center" @click="markSeriesFinished"> |           <ui-btn color="primary" small :loading="processingSeries" class="flex items-center" @click="markSeriesFinished"> | ||||||
|             <div class="h-5 w-5"> |             <div class="h-5 w-5"> | ||||||
|               <svg v-if="isSeriesFinished" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(63, 181, 68)"> |               <svg v-if="isSeriesFinished" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(63, 181, 68)"> | ||||||
| @ -95,8 +94,7 @@ export default { | |||||||
|       keywordTimeout: null, |       keywordTimeout: null, | ||||||
|       processingSeries: false, |       processingSeries: false, | ||||||
|       processingIssues: false, |       processingIssues: false, | ||||||
|       processingAuthors: false, |       processingAuthors: false | ||||||
|       processingSeriesHideFromHome: false |  | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
| @ -152,9 +150,6 @@ export default { | |||||||
|     seriesName() { |     seriesName() { | ||||||
|       return this.selectedSeries ? this.selectedSeries.name : null |       return this.selectedSeries ? this.selectedSeries.name : null | ||||||
|     }, |     }, | ||||||
|     seriesHideFromHome() { |  | ||||||
|       return this.selectedSeries ? this.selectedSeries.hideFromHome : null |  | ||||||
|     }, |  | ||||||
|     seriesProgress() { |     seriesProgress() { | ||||||
|       return this.selectedSeries ? this.selectedSeries.progress : null |       return this.selectedSeries ? this.selectedSeries.progress : null | ||||||
|     }, |     }, | ||||||
| @ -176,23 +171,6 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     async showSeriesOnHome() { |  | ||||||
|       this.processingSeriesHideFromHome = true |  | ||||||
|       const seriesId = this.selectedSeries.id |  | ||||||
|       this.$axios |  | ||||||
|         .$patch(`/api/series/${seriesId}`, { hideFromHome: false }) |  | ||||||
|         .then((data) => { |  | ||||||
|           console.log('Updated series', data) |  | ||||||
|           this.$toast.success('Series updated successfully') |  | ||||||
|         }) |  | ||||||
|         .catch((error) => { |  | ||||||
|           console.error('Failed to update series', error) |  | ||||||
|           this.$toast.error('Failed to update series') |  | ||||||
|         }) |  | ||||||
|         .finally(() => { |  | ||||||
|           this.processingSeriesHideFromHome = false |  | ||||||
|         }) |  | ||||||
|     }, |  | ||||||
|     async matchAllAuthors() { |     async matchAllAuthors() { | ||||||
|       this.processingAuthors = true |       this.processingAuthors = true | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -411,10 +411,10 @@ export default { | |||||||
|           text: 'Re-Scan' |           text: 'Re-Scan' | ||||||
|         }) |         }) | ||||||
|       } |       } | ||||||
|       if (this.userIsAdminOrUp && this.series && this.bookMount) { |       if (this.series && this.bookMount) { | ||||||
|         items.push({ |         items.push({ | ||||||
|           func: 'hideSeriesFromHome', |           func: 'hideSeriesFromContinueListening', | ||||||
|           text: 'Hide Series from Home' |           text: 'Hide Series from Continue Series' | ||||||
|         }) |         }) | ||||||
|       } |       } | ||||||
|       return items |       return items | ||||||
| @ -595,17 +595,17 @@ export default { | |||||||
|       // More menu func |       // More menu func | ||||||
|       this.store.commit('showEditModalOnTab', { libraryItem: this.libraryItem, tab: 'match' }) |       this.store.commit('showEditModalOnTab', { libraryItem: this.libraryItem, tab: 'match' }) | ||||||
|     }, |     }, | ||||||
|     hideSeriesFromHome() { |     hideSeriesFromContinueListening() { | ||||||
|       const axios = this.$axios || this.$nuxt.$axios |       const axios = this.$axios || this.$nuxt.$axios | ||||||
|       this.processing = true |       this.processing = true | ||||||
|       axios |       axios | ||||||
|         .$patch(`/api/series/${this.series.id}`, { hideFromHome: true }) |         .$post(`/api/me/series/${this.series.id}/hide`) | ||||||
|         .then((data) => { |         .then((data) => { | ||||||
|           console.log('Series updated', data) |           console.log('User updated', data) | ||||||
|         }) |         }) | ||||||
|         .catch((error) => { |         .catch((error) => { | ||||||
|           console.error('Failed to hide series from home', error) |           console.error('Failed to hide series from home', error) | ||||||
|           this.$toast.error('Failed to update series') |           this.$toast.error('Failed to update user') | ||||||
|         }) |         }) | ||||||
|         .finally(() => { |         .finally(() => { | ||||||
|           this.processing = false |           this.processing = false | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ class Server { | |||||||
|       await this.auth.initTokenSecret() |       await this.auth.initTokenSecret() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await this.checkUserMediaProgress() // Remove invalid user item progress
 |     await this.cleanUserData() // Remove invalid user item progress
 | ||||||
|     await this.purgeMetadata() // Remove metadata folders without library item
 |     await this.purgeMetadata() // Remove metadata folders without library item
 | ||||||
|     await this.playbackSessionManager.removeInvalidSessions() |     await this.playbackSessionManager.removeInvalidSessions() | ||||||
|     await this.cacheManager.ensureCachePaths() |     await this.cacheManager.ensureCachePaths() | ||||||
| @ -368,23 +368,39 @@ class Server { | |||||||
|     return purged |     return purged | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Remove user media progress entries that dont have a library item
 |   // Remove user media progress with items that no longer exist & remove seriesHideFrom that no longer exist
 | ||||||
|   // TODO: Check podcast episode exists still
 |   async cleanUserData() { | ||||||
|   async checkUserMediaProgress() { |  | ||||||
|     for (let i = 0; i < this.db.users.length; i++) { |     for (let i = 0; i < this.db.users.length; i++) { | ||||||
|       var _user = this.db.users[i] |       var _user = this.db.users[i] | ||||||
|       if (_user.mediaProgress) { |       var hasUpdated = false | ||||||
|         var itemProgressIdsToRemove = _user.mediaProgress.map(lip => lip.id).filter(lipId => !this.db.libraryItems.find(_li => _li.id == lipId)) |       if (_user.mediaProgress.length) { | ||||||
|         if (itemProgressIdsToRemove.length) { |         const lengthBefore = _user.mediaProgress.length | ||||||
|           Logger.debug(`[Server] Found ${itemProgressIdsToRemove.length} media progress data to remove from user ${_user.username}`) |         _user.mediaProgress = _user.mediaProgress.filter(mp => { | ||||||
|           for (const lipId of itemProgressIdsToRemove) { |           const libraryItem = this.db.libraryItems.find(li => li.id === mp.libraryItemId) | ||||||
|             _user.removeMediaProgress(lipId) |           if (!libraryItem) return false | ||||||
|  |           if (mp.episodeId && (libraryItem.mediaType !== 'podcast' || !libraryItem.media.checkHasEpisode(mp.episodeId))) return false // Episode not found
 | ||||||
|  |           return true | ||||||
|  |         }) | ||||||
|  | 
 | ||||||
|  |         if (lengthBefore > _user.mediaProgress.length) { | ||||||
|  |           Logger.debug(`[Server] Removing ${_user.mediaProgress.length - lengthBefore} media progress data from user ${_user.username}`) | ||||||
|  |           hasUpdated = true | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|  |       if (_user.seriesHideFromContinueListening.length) { | ||||||
|  |         _user.seriesHideFromContinueListening = _user.seriesHideFromContinueListening.filter(seriesId => { | ||||||
|  |           if (!this.db.series.some(se => se.id === seriesId)) { // Series removed
 | ||||||
|  |             hasUpdated = true | ||||||
|  |             return false | ||||||
|  |           } | ||||||
|  |           return true | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |       if (hasUpdated) { | ||||||
|         await this.db.updateEntity('user', _user) |         await this.db.updateEntity('user', _user) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   // First time login rate limit is hit
 |   // First time login rate limit is hit
 | ||||||
|   loginLimitReached(req, res, options) { |   loginLimitReached(req, res, options) { | ||||||
|  | |||||||
| @ -276,5 +276,21 @@ class MeController { | |||||||
|       libraryItems: itemsInProgress |       libraryItems: itemsInProgress | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   // GET: api/me/series/:id/hide
 | ||||||
|  |   async hideSeriesFromContinueListening(req, res) { | ||||||
|  |     const series = this.db.series.find(se => se.id === req.params.id) | ||||||
|  |     if (!series) { | ||||||
|  |       Logger.error(`[MeController] hideSeriesFromContinueListening: Series ${req.params.id} not found`) | ||||||
|  |       return res.sendStatus(404) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const hasUpdated = req.user.addSeriesToHideFromContinueListening(req.params.id) | ||||||
|  |     if (hasUpdated) { | ||||||
|  |       await this.db.updateEntity('user', req.user) | ||||||
|  |       this.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser()) | ||||||
|  |     } | ||||||
|  |     res.json(req.user.toJSONForBrowser()) | ||||||
|  |   } | ||||||
| } | } | ||||||
| module.exports = new MeController() | module.exports = new MeController() | ||||||
| @ -5,7 +5,6 @@ class Series { | |||||||
|     this.id = null |     this.id = null | ||||||
|     this.name = null |     this.name = null | ||||||
|     this.description = null |     this.description = null | ||||||
|     this.hideFromHome = false |  | ||||||
|     this.addedAt = null |     this.addedAt = null | ||||||
|     this.updatedAt = null |     this.updatedAt = null | ||||||
| 
 | 
 | ||||||
| @ -18,7 +17,6 @@ class Series { | |||||||
|     this.id = series.id |     this.id = series.id | ||||||
|     this.name = series.name |     this.name = series.name | ||||||
|     this.description = series.description || null |     this.description = series.description || null | ||||||
|     this.hideFromHome = !!series.hideFromHome |  | ||||||
|     this.addedAt = series.addedAt |     this.addedAt = series.addedAt | ||||||
|     this.updatedAt = series.updatedAt |     this.updatedAt = series.updatedAt | ||||||
|   } |   } | ||||||
| @ -28,7 +26,6 @@ class Series { | |||||||
|       id: this.id, |       id: this.id, | ||||||
|       name: this.name, |       name: this.name, | ||||||
|       description: this.description, |       description: this.description, | ||||||
|       hideFromHome: this.hideFromHome, |  | ||||||
|       addedAt: this.addedAt, |       addedAt: this.addedAt, | ||||||
|       updatedAt: this.updatedAt |       updatedAt: this.updatedAt | ||||||
|     } |     } | ||||||
| @ -46,14 +43,13 @@ class Series { | |||||||
|     this.id = getId('ser') |     this.id = getId('ser') | ||||||
|     this.name = data.name |     this.name = data.name | ||||||
|     this.description = data.description || null |     this.description = data.description || null | ||||||
|     this.hideFromHome = !!data.hideFromHome |  | ||||||
|     this.addedAt = Date.now() |     this.addedAt = Date.now() | ||||||
|     this.updatedAt = Date.now() |     this.updatedAt = Date.now() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   update(series) { |   update(series) { | ||||||
|     if (!series) return false |     if (!series) return false | ||||||
|     const keysToUpdate = ['name', 'description', 'hideFromHome'] |     const keysToUpdate = ['name', 'description'] | ||||||
|     var hasUpdated = false |     var hasUpdated = false | ||||||
|     for (const key of keysToUpdate) { |     for (const key of keysToUpdate) { | ||||||
|       if (series[key] !== undefined && series[key] !== this[key]) { |       if (series[key] !== undefined && series[key] !== this[key]) { | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ class User { | |||||||
|     this.createdAt = null |     this.createdAt = null | ||||||
| 
 | 
 | ||||||
|     this.mediaProgress = [] |     this.mediaProgress = [] | ||||||
|  |     this.seriesHideFromContinueListening = [] // Series IDs that should not show on home page continue listening
 | ||||||
|     this.bookmarks = [] |     this.bookmarks = [] | ||||||
| 
 | 
 | ||||||
|     this.settings = {} |     this.settings = {} | ||||||
| @ -92,6 +93,7 @@ class User { | |||||||
|       type: this.type, |       type: this.type, | ||||||
|       token: this.token, |       token: this.token, | ||||||
|       mediaProgress: this.mediaProgress ? this.mediaProgress.map(li => li.toJSON()) : [], |       mediaProgress: this.mediaProgress ? this.mediaProgress.map(li => li.toJSON()) : [], | ||||||
|  |       seriesHideFromContinueListening: [...this.seriesHideFromContinueListening], | ||||||
|       bookmarks: this.bookmarks ? this.bookmarks.map(b => b.toJSON()) : [], |       bookmarks: this.bookmarks ? this.bookmarks.map(b => b.toJSON()) : [], | ||||||
|       isActive: this.isActive, |       isActive: this.isActive, | ||||||
|       isLocked: this.isLocked, |       isLocked: this.isLocked, | ||||||
| @ -111,6 +113,7 @@ class User { | |||||||
|       type: this.type, |       type: this.type, | ||||||
|       token: this.token, |       token: this.token, | ||||||
|       mediaProgress: this.mediaProgress ? this.mediaProgress.map(li => li.toJSON()) : [], |       mediaProgress: this.mediaProgress ? this.mediaProgress.map(li => li.toJSON()) : [], | ||||||
|  |       seriesHideFromContinueListening: [...this.seriesHideFromContinueListening], | ||||||
|       bookmarks: this.bookmarks ? this.bookmarks.map(b => b.toJSON()) : [], |       bookmarks: this.bookmarks ? this.bookmarks.map(b => b.toJSON()) : [], | ||||||
|       isActive: this.isActive, |       isActive: this.isActive, | ||||||
|       isLocked: this.isLocked, |       isLocked: this.isLocked, | ||||||
| @ -161,6 +164,9 @@ class User { | |||||||
|       this.bookmarks = user.bookmarks.filter(bm => typeof bm.libraryItemId == 'string').map(bm => new AudioBookmark(bm)) |       this.bookmarks = user.bookmarks.filter(bm => typeof bm.libraryItemId == 'string').map(bm => new AudioBookmark(bm)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     this.seriesHideFromContinueListening = [] | ||||||
|  |     if (user.seriesHideFromContinueListening) this.seriesHideFromContinueListening = [...user.seriesHideFromContinueListening] | ||||||
|  | 
 | ||||||
|     this.isActive = (user.isActive === undefined || user.type === 'root') ? true : !!user.isActive |     this.isActive = (user.isActive === undefined || user.type === 'root') ? true : !!user.isActive | ||||||
|     this.isLocked = user.type === 'root' ? false : !!user.isLocked |     this.isLocked = user.type === 'root' ? false : !!user.isLocked | ||||||
|     this.lastSeen = user.lastSeen || null |     this.lastSeen = user.lastSeen || null | ||||||
| @ -196,6 +202,13 @@ class User { | |||||||
|       } |       } | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|  |     if (payload.seriesHideFromContinueListening && Array.isArray(payload.seriesHideFromContinueListening)) { | ||||||
|  |       if (this.seriesHideFromContinueListening.join(',') !== payload.seriesHideFromContinueListening.join(',')) { | ||||||
|  |         hasUpdates = true | ||||||
|  |         this.seriesHideFromContinueListening = [...payload.seriesHideFromContinueListening] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // And update permissions
 |     // And update permissions
 | ||||||
|     if (payload.permissions) { |     if (payload.permissions) { | ||||||
|       for (const key in payload.permissions) { |       for (const key in payload.permissions) { | ||||||
| @ -297,7 +310,13 @@ class User { | |||||||
|     return wasUpdated |     return wasUpdated | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   removeMediaProgress(libraryItemId) { |   removeMediaProgress(id) { | ||||||
|  |     if (!this.mediaProgress.some(mp => mp.id === id)) return false | ||||||
|  |     this.mediaProgress = this.mediaProgress.filter(mp => mp.id !== id) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   removeMediaProgressForLibraryItem(libraryItemId) { | ||||||
|     if (!this.mediaProgress.some(lip => lip.libraryItemId == libraryItemId)) return false |     if (!this.mediaProgress.some(lip => lip.libraryItemId == libraryItemId)) return false | ||||||
|     this.mediaProgress = this.mediaProgress.filter(lip => lip.libraryItemId != libraryItemId) |     this.mediaProgress = this.mediaProgress.filter(lip => lip.libraryItemId != libraryItemId) | ||||||
|     return true |     return true | ||||||
| @ -378,5 +397,15 @@ class User { | |||||||
|   removeBookmark(libraryItemId, time) { |   removeBookmark(libraryItemId, time) { | ||||||
|     this.bookmarks = this.bookmarks.filter(bm => (bm.libraryItemId !== libraryItemId || bm.time !== time)) |     this.bookmarks = this.bookmarks.filter(bm => (bm.libraryItemId !== libraryItemId || bm.time !== time)) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   checkShouldHideSeriesFromContinueListening(seriesId) { | ||||||
|  |     return this.seriesHideFromContinueListening.includes(seriesId) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addSeriesToHideFromContinueListening(seriesId) { | ||||||
|  |     if (this.seriesHideFromContinueListening.includes(seriesId)) return false | ||||||
|  |     this.seriesHideFromContinueListening.push(seriesId) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
| } | } | ||||||
| module.exports = User | module.exports = User | ||||||
| @ -150,6 +150,7 @@ class ApiRouter { | |||||||
|     this.router.patch('/me/settings', MeController.updateSettings.bind(this)) |     this.router.patch('/me/settings', MeController.updateSettings.bind(this)) | ||||||
|     this.router.post('/me/sync-local-progress', MeController.syncLocalMediaProgress.bind(this)) |     this.router.post('/me/sync-local-progress', MeController.syncLocalMediaProgress.bind(this)) | ||||||
|     this.router.get('/me/items-in-progress', MeController.getAllLibraryItemsInProgress.bind(this)) |     this.router.get('/me/items-in-progress', MeController.getAllLibraryItemsInProgress.bind(this)) | ||||||
|  |     this.router.post('/me/series/:id/hide', MeController.hideSeriesFromContinueListening.bind(this)) | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     // Backup Routes
 |     // Backup Routes
 | ||||||
| @ -304,7 +305,7 @@ class ApiRouter { | |||||||
|     // Remove libraryItem from users
 |     // Remove libraryItem from users
 | ||||||
|     for (let i = 0; i < this.db.users.length; i++) { |     for (let i = 0; i < this.db.users.length; i++) { | ||||||
|       var user = this.db.users[i] |       var user = this.db.users[i] | ||||||
|       var madeUpdates = user.removeMediaProgress(libraryItem.id) |       var madeUpdates = user.removeMediaProgressForLibraryItem(libraryItem.id) | ||||||
|       if (madeUpdates) { |       if (madeUpdates) { | ||||||
|         await this.db.updateEntity('user', user) |         await this.db.updateEntity('user', user) | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -415,13 +415,16 @@ module.exports = { | |||||||
|             const libraryItemJson = libraryItem.toJSONMinified() |             const libraryItemJson = libraryItem.toJSONMinified() | ||||||
|             libraryItemJson.seriesSequence = librarySeries.sequence |             libraryItemJson.seriesSequence = librarySeries.sequence | ||||||
| 
 | 
 | ||||||
|  |             const hideFromContinueListening = user.checkShouldHideSeriesFromContinueListening(librarySeries.id) | ||||||
|  | 
 | ||||||
|             if (!seriesMap[librarySeries.id]) { |             if (!seriesMap[librarySeries.id]) { | ||||||
|               const seriesObj = allSeries.find(se => se.id === librarySeries.id) |               const seriesObj = allSeries.find(se => se.id === librarySeries.id) | ||||||
|               if (seriesObj && !seriesObj.hideFromHome) { |               if (seriesObj) { | ||||||
|                 var series = { |                 var series = { | ||||||
|                   ...seriesObj.toJSON(), |                   ...seriesObj.toJSON(), | ||||||
|                   books: [libraryItemJson], |                   books: [libraryItemJson], | ||||||
|                   inProgress: bookInProgress, |                   inProgress: bookInProgress, | ||||||
|  |                   hideFromContinueListening, | ||||||
|                   bookInProgressLastUpdate: bookInProgress ? mediaProgress.lastUpdate : null, |                   bookInProgressLastUpdate: bookInProgress ? mediaProgress.lastUpdate : null, | ||||||
|                   firstBookUnread: bookInProgress ? null : libraryItemJson |                   firstBookUnread: bookInProgress ? null : libraryItemJson | ||||||
|                 } |                 } | ||||||
| @ -555,7 +558,7 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|     // For Continue Series - Find next book in series for series that are in progress
 |     // For Continue Series - Find next book in series for series that are in progress
 | ||||||
|     for (const seriesId in seriesMap) { |     for (const seriesId in seriesMap) { | ||||||
|       if (seriesMap[seriesId].inProgress) { |       if (seriesMap[seriesId].inProgress && !seriesMap[seriesId].hideFromContinueListening) { | ||||||
|         seriesMap[seriesId].books = naturalSort(seriesMap[seriesId].books).asc(li => li.seriesSequence) |         seriesMap[seriesId].books = naturalSort(seriesMap[seriesId].books).asc(li => li.seriesSequence) | ||||||
| 
 | 
 | ||||||
|         // NEW implementation takes the first book unread with the smallest series sequence
 |         // NEW implementation takes the first book unread with the smallest series sequence
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user