mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-01 19:07:02 -04:00 
			
		
		
		
	Add:Random library sorting option for libraries and series #3166
- Fixed author sort and match button not showing
This commit is contained in:
		
							parent
							
								
									82f136ba79
								
							
						
					
					
						commit
						43d6c6678f
					
				| @ -84,11 +84,6 @@ | ||||
| 
 | ||||
|         <ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" /> | ||||
|       </template> | ||||
|       <!-- home page --> | ||||
|       <template v-else-if="isHome"> | ||||
|         <div class="flex-grow" /> | ||||
|         <ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" /> | ||||
|       </template> | ||||
|       <!-- search page --> | ||||
|       <template v-else-if="page === 'search'"> | ||||
|         <div class="flex-grow" /> | ||||
| @ -99,10 +94,15 @@ | ||||
|       <!-- authors page --> | ||||
|       <template v-else-if="page === 'authors'"> | ||||
|         <div class="flex-grow" /> | ||||
|         <ui-btn v-if="userCanUpdate && authors && authors.length && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn> | ||||
|         <ui-btn v-if="userCanUpdate && authors?.length && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn> | ||||
| 
 | ||||
|         <!-- author sort select --> | ||||
|         <controls-sort-select v-if="authors && authors.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" /> | ||||
|         <controls-sort-select v-if="authors?.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" /> | ||||
|       </template> | ||||
|       <!-- home page --> | ||||
|       <template v-else-if="isHome"> | ||||
|         <div class="flex-grow" /> | ||||
|         <ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" /> | ||||
|       </template> | ||||
|     </div> | ||||
|   </div> | ||||
| @ -187,6 +187,10 @@ export default { | ||||
|         { | ||||
|           text: this.$strings.LabelTotalDuration, | ||||
|           value: 'totalDuration' | ||||
|         }, | ||||
|         { | ||||
|           text: this.$strings.LabelRandomly, | ||||
|           value: 'random' | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|  | ||||
| @ -88,6 +88,10 @@ export default { | ||||
|         { | ||||
|           text: this.$strings.LabelFileModified, | ||||
|           value: 'mtimeMs' | ||||
|         }, | ||||
|         { | ||||
|           text: this.$strings.LabelRandomly, | ||||
|           value: 'random' | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
| @ -128,6 +132,10 @@ export default { | ||||
|         { | ||||
|           text: this.$strings.LabelFileModified, | ||||
|           value: 'mtimeMs' | ||||
|         }, | ||||
|         { | ||||
|           text: this.$strings.LabelRandomly, | ||||
|           value: 'random' | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
| @ -215,4 +223,4 @@ export default { | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| </script> | ||||
|  | ||||
| @ -455,6 +455,7 @@ | ||||
|   "LabelRSSFeedPreventIndexing": "Prevent Indexing", | ||||
|   "LabelRSSFeedSlug": "RSS Feed Slug", | ||||
|   "LabelRSSFeedURL": "RSS Feed URL", | ||||
|   "LabelRandomly": "Randomly", | ||||
|   "LabelReAddSeriesToContinueListening": "Re-add series to Continue Listening", | ||||
|   "LabelRead": "Read", | ||||
|   "LabelReadAgain": "Read Again", | ||||
|  | ||||
| @ -2,7 +2,6 @@ const Sequelize = require('sequelize') | ||||
| const Database = require('../../Database') | ||||
| const Logger = require('../../Logger') | ||||
| const authorFilters = require('./authorFilters') | ||||
| const { asciiOnlyToLowerCase } = require('../index') | ||||
| 
 | ||||
| const ShareManager = require('../../managers/ShareManager') | ||||
| 
 | ||||
| @ -274,6 +273,8 @@ module.exports = { | ||||
|       return [[Sequelize.literal(`CAST(\`series.bookSeries.sequence\` AS FLOAT) ${nullDir}`)]] | ||||
|     } else if (sortBy === 'progress') { | ||||
|       return [[Sequelize.literal('mediaProgresses.updatedAt'), dir]] | ||||
|     } else if (sortBy === 'random') { | ||||
|       return [Database.sequelize.random()] | ||||
|     } | ||||
|     return [] | ||||
|   }, | ||||
|  | ||||
| @ -89,6 +89,8 @@ module.exports = { | ||||
|       } | ||||
|     } else if (sortBy === 'media.numTracks') { | ||||
|       return [['numEpisodes', dir]] | ||||
|     } else if (sortBy === 'random') { | ||||
|       return [Database.sequelize.random()] | ||||
|     } | ||||
|     return [] | ||||
|   }, | ||||
|  | ||||
| @ -10,15 +10,15 @@ module.exports = { | ||||
| 
 | ||||
|   /** | ||||
|    * Get series filtered and sorted | ||||
|    *  | ||||
|    * @param {import('../../objects/Library')} library  | ||||
|    * @param {import('../../objects/user/User')} user  | ||||
|    * @param {string} filterBy  | ||||
|    * @param {string} sortBy  | ||||
|    * @param {boolean} sortDesc  | ||||
|    * @param {string[]} include  | ||||
|    * @param {number} limit  | ||||
|    * @param {number} offset  | ||||
|    * | ||||
|    * @param {import('../../objects/Library')} library | ||||
|    * @param {import('../../objects/user/User')} user | ||||
|    * @param {string} filterBy | ||||
|    * @param {string} sortBy | ||||
|    * @param {boolean} sortDesc | ||||
|    * @param {string[]} include | ||||
|    * @param {number} limit | ||||
|    * @param {number} offset | ||||
|    * @returns {Promise<{ series:object[], count:number }>} | ||||
|    */ | ||||
|   async getFilteredSeries(library, user, filterBy, sortBy, sortDesc, include, limit, offset) { | ||||
| @ -26,7 +26,7 @@ module.exports = { | ||||
|     let filterGroup = null | ||||
|     if (filterBy) { | ||||
|       const searchGroups = ['genres', 'tags', 'authors', 'progress', 'narrators', 'publishers', 'languages'] | ||||
|       const group = searchGroups.find(_group => filterBy.startsWith(_group + '.')) | ||||
|       const group = searchGroups.find((_group) => filterBy.startsWith(_group + '.')) | ||||
|       filterGroup = group || filterBy | ||||
|       filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null | ||||
|     } | ||||
| @ -49,9 +49,11 @@ module.exports = { | ||||
|     // Handle library setting to hide single book series
 | ||||
|     // TODO: Merge with existing query
 | ||||
|     if (library.settings.hideSingleBookSeries) { | ||||
|       seriesWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), { | ||||
|         [Sequelize.Op.gt]: 1 | ||||
|       })) | ||||
|       seriesWhere.push( | ||||
|         Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), { | ||||
|           [Sequelize.Op.gt]: 1 | ||||
|         }) | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     // Handle filters
 | ||||
| @ -101,9 +103,11 @@ module.exports = { | ||||
|     } | ||||
| 
 | ||||
|     if (attrQuery) { | ||||
|       seriesWhere.push(Sequelize.where(Sequelize.literal(`(${attrQuery})`), { | ||||
|         [Sequelize.Op.gt]: 0 | ||||
|       })) | ||||
|       seriesWhere.push( | ||||
|         Sequelize.where(Sequelize.literal(`(${attrQuery})`), { | ||||
|           [Sequelize.Op.gt]: 0 | ||||
|         }) | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     const order = [] | ||||
| @ -133,6 +137,8 @@ module.exports = { | ||||
|     } else if (sortBy === 'lastBookUpdated') { | ||||
|       seriesAttributes.include.push([Sequelize.literal('(SELECT MAX(b.updatedAt) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'mostRecentBookUpdated']) | ||||
|       order.push(['mostRecentBookUpdated', dir]) | ||||
|     } else if (sortBy === 'random') { | ||||
|       order.push(Database.sequelize.random()) | ||||
|     } | ||||
| 
 | ||||
|     const { rows: series, count } = await Database.seriesModel.findAndCountAll({ | ||||
| @ -184,7 +190,7 @@ module.exports = { | ||||
|           sensitivity: 'base' | ||||
|         }) | ||||
|       }) | ||||
|       oldSeries.books = s.bookSeries.map(bs => { | ||||
|       oldSeries.books = s.bookSeries.map((bs) => { | ||||
|         const libraryItem = bs.book.libraryItem.toJSON() | ||||
|         delete bs.book.libraryItem | ||||
|         libraryItem.media = bs.book | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user