mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Add:Batch select audiobook play button, item page mobile screen size cleanup
This commit is contained in:
		
							parent
							
								
									8931702f1b
								
							
						
					
					
						commit
						7485cf1a26
					
				| @ -26,7 +26,7 @@ | ||||
|   -webkit-font-smoothing: antialiased; | ||||
| } | ||||
| 
 | ||||
| .material-icons:not(.text-xs):not(.text-sm):not(.text-md):not(.text-base):not(.text-lg):not(.text-xl):not(.text-2xl):not(.text-3xl):not(.text-4xl):not(.text-5xl):not(.text-6xl):not(.text-7xl):not(.text-8xl) { | ||||
| .material-icons:not([class*="text-"]) { | ||||
|   font-size: 1.5rem; | ||||
| } | ||||
| 
 | ||||
| @ -44,11 +44,10 @@ | ||||
|   -webkit-font-smoothing: antialiased; | ||||
| } | ||||
| 
 | ||||
| .material-icons-outlined:not(.text-xs):not(.text-sm):not(.text-md):not(.text-base):not(.text-lg):not(.text-xl):not(.text-2xl):not(.text-3xl):not(.text-4xl):not(.text-5xl):not(.text-6xl):not(.text-7xl):not(.text-8xl) { | ||||
| .material-icons-outlined:not([class*="text-"]) { | ||||
|   font-size: 1.5rem; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: 'Gentium Book Basic'; | ||||
|   font-style: normal; | ||||
|  | ||||
| @ -46,8 +46,12 @@ | ||||
|         </nuxt-link> | ||||
|       </div> | ||||
|       <div v-show="numLibraryItemsSelected" class="absolute top-0 left-0 w-full h-full px-4 bg-primary flex items-center"> | ||||
|         <h1 class="text-2xl px-4">{{ $getString('MessageItemsSelected', [numLibraryItemsSelected]) }}</h1> | ||||
|         <h1 class="text-lg md:text-2xl px-4">{{ $getString('MessageItemsSelected', [numLibraryItemsSelected]) }}</h1> | ||||
|         <div class="flex-grow" /> | ||||
|         <ui-btn v-if="!isPodcastLibrary" color="success" :padding-x="4" small class="flex items-center h-9 mr-2" @click="playSelectedItems"> | ||||
|           <span class="material-icons -ml-2 pr-1 text-white">play_arrow</span> | ||||
|           {{ $strings.ButtonPlay }} | ||||
|         </ui-btn> | ||||
|         <ui-tooltip v-if="userIsAdminOrUp && !isPodcastLibrary" :text="$strings.ButtonQuickMatch" direction="bottom"> | ||||
|           <ui-icon-btn :disabled="processingBatch" icon="auto_awesome" @click="batchAutoMatchClick" class="mx-1.5" /> | ||||
|         </ui-tooltip> | ||||
| @ -59,14 +63,14 @@ | ||||
|         </ui-tooltip> | ||||
|         <template v-if="userCanUpdate && numLibraryItemsSelected < 50"> | ||||
|           <ui-tooltip text="Edit" direction="bottom"> | ||||
|             <ui-icon-btn v-show="!processingBatchDelete" icon="edit" bg-color="warning" class="mx-1.5" @click="batchEditClick" /> | ||||
|             <ui-icon-btn :disabled="processingBatch" icon="edit" bg-color="warning" class="mx-1.5" @click="batchEditClick" /> | ||||
|           </ui-tooltip> | ||||
|         </template> | ||||
|         <ui-tooltip v-if="userCanDelete" :text="$strings.ButtonRemove" direction="bottom"> | ||||
|           <ui-icon-btn :disabled="processingBatchDelete" icon="delete" bg-color="error" class="mx-1.5" @click="batchDeleteClick" /> | ||||
|           <ui-icon-btn :disabled="processingBatch" icon="delete" bg-color="error" class="mx-1.5" @click="batchDeleteClick" /> | ||||
|         </ui-tooltip> | ||||
|         <ui-tooltip :text="$strings.LabelDeselectAll" direction="bottom"> | ||||
|           <span class="material-icons text-4xl px-4 hover:text-gray-100 cursor-pointer" :class="processingBatchDelete ? 'text-gray-400' : ''" @click="cancelSelectionMode">close</span> | ||||
|           <span class="material-icons text-4xl px-4 hover:text-gray-100 cursor-pointer" :class="processingBatch ? 'text-gray-400' : ''" @click="cancelSelectionMode">close</span> | ||||
|         </ui-tooltip> | ||||
|       </div> | ||||
|     </div> | ||||
| @ -77,9 +81,7 @@ | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       processingBatchDelete: false, | ||||
|       totalEntities: 0, | ||||
|       isAllSelected: false | ||||
|       totalEntities: 0 | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
| @ -149,11 +151,47 @@ export default { | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     cancelSelectionMode() { | ||||
|       if (this.processingBatchDelete) return | ||||
|     async playSelectedItems() { | ||||
|       this.$store.commit('setProcessingBatch', true) | ||||
| 
 | ||||
|       var libraryItems = await this.$axios.$post(`/api/items/batch/get`, { libraryItemIds: this.selectedLibraryItems }).catch((error) => { | ||||
|         var errorMsg = error.response.data || 'Failed to get items' | ||||
|         console.error(errorMsg, error) | ||||
|         this.$toast.error(errorMsg) | ||||
|         return [] | ||||
|       }) | ||||
| 
 | ||||
|       if (!libraryItems.length) { | ||||
|         this.$store.commit('setProcessingBatch', false) | ||||
|         return | ||||
|       } | ||||
| 
 | ||||
|       const queueItems = [] | ||||
|       libraryItems.forEach((item) => { | ||||
|         queueItems.push({ | ||||
|           libraryItemId: item.id, | ||||
|           libraryId: item.libraryId, | ||||
|           episodeId: null, | ||||
|           title: item.media.metadata.title, | ||||
|           subtitle: item.media.metadata.authors.map((au) => au.name).join(', '), | ||||
|           caption: '', | ||||
|           duration: item.media.duration || null, | ||||
|           coverPath: item.media.coverPath || null | ||||
|         }) | ||||
|       }) | ||||
| 
 | ||||
|       this.$eventBus.$emit('play-item', { | ||||
|         libraryItemId: queueItems[0].libraryItemId, | ||||
|         queueItems | ||||
|       }) | ||||
|       this.$store.commit('setProcessingBatch', false) | ||||
|       this.$store.commit('setSelectedLibraryItems', []) | ||||
|       this.$eventBus.$emit('bookshelf_clear_selection') | ||||
|     }, | ||||
|     cancelSelectionMode() { | ||||
|       if (this.processingBatch) return | ||||
|       this.$store.commit('setSelectedLibraryItems', []) | ||||
|       this.$eventBus.$emit('bookshelf_clear_selection') | ||||
|       this.isAllSelected = false | ||||
|     }, | ||||
|     toggleBatchRead() { | ||||
|       this.$store.commit('setProcessingBatch', true) | ||||
| @ -183,7 +221,6 @@ export default { | ||||
|       var audiobookText = this.numLibraryItemsSelected > 1 ? `these ${this.numLibraryItemsSelected} items` : 'this item' | ||||
|       var confirmMsg = `Are you sure you want to remove ${audiobookText}?\n\n*Does not delete your files, only removes the items from Audiobookshelf` | ||||
|       if (confirm(confirmMsg)) { | ||||
|         this.processingBatchDelete = true | ||||
|         this.$store.commit('setProcessingBatch', true) | ||||
|         this.$axios | ||||
|           .$post(`/api/items/batch/delete`, { | ||||
| @ -191,7 +228,6 @@ export default { | ||||
|           }) | ||||
|           .then(() => { | ||||
|             this.$toast.success('Batch delete success!') | ||||
|             this.processingBatchDelete = false | ||||
|             this.$store.commit('setProcessingBatch', false) | ||||
|             this.$store.commit('setSelectedLibraryItems', []) | ||||
|             this.$eventBus.$emit('bookshelf_clear_selection') | ||||
| @ -199,7 +235,6 @@ export default { | ||||
|           .catch((error) => { | ||||
|             this.$toast.error('Batch delete failed') | ||||
|             console.error('Failed to batch delete', error) | ||||
|             this.processingBatchDelete = false | ||||
|             this.$store.commit('setProcessingBatch', false) | ||||
|           }) | ||||
|       } | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|         <controls-volume-control ref="volumeControl" v-model="volume" @input="setVolume" class="mx-2 hidden md:block" /> | ||||
| 
 | ||||
|         <div class="cursor-pointer text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showSleepTimer')"> | ||||
|           <span v-if="!sleepTimerSet" class="material-icons text-2xl sm:text-2.5xl">snooze</span> | ||||
|           <span v-if="!sleepTimerSet" class="material-icons text-2xl">snooze</span> | ||||
|           <div v-else class="flex items-center"> | ||||
|             <span class="material-icons text-lg text-warning">snooze</span> | ||||
|             <p class="text-xl text-warning font-mono font-semibold text-center px-0.5 pb-0.5" style="min-width: 30px">{{ sleepTimerRemainingString }}</p> | ||||
| @ -15,15 +15,15 @@ | ||||
|         </div> | ||||
| 
 | ||||
|         <div v-if="!isPodcast" class="cursor-pointer text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showBookmarks')"> | ||||
|           <span class="material-icons text-2xl sm:text-2.5xl">{{ bookmarks.length ? 'bookmarks' : 'bookmark_border' }}</span> | ||||
|           <span class="material-icons text-2xl">{{ bookmarks.length ? 'bookmarks' : 'bookmark_border' }}</span> | ||||
|         </div> | ||||
| 
 | ||||
|         <div v-if="chapters.length" class="cursor-pointer text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="showChapters"> | ||||
|           <span class="material-icons text-2xl sm:text-3xl">format_list_bulleted</span> | ||||
|           <span class="material-icons text-2xl">format_list_bulleted</span> | ||||
|         </div> | ||||
| 
 | ||||
|         <button v-if="playerQueueItems.length" class="outline-none text-gray-300 mx-1 lg:mx-2 hover:text-white" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showPlayerQueueItems')"> | ||||
|           <span class="material-icons text-2xl sm:text-3xl">queue_music</span> | ||||
|           <span class="material-icons text-2.5xl sm:text-3xl">queue_music</span> | ||||
|         </button> | ||||
| 
 | ||||
|         <ui-tooltip v-if="chapters.length" direction="top" :text="useChapterTrack ? $strings.LabelUseFullTrack : $strings.LabelUseChapterTrack"> | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| 
 | ||||
|               <template v-if="!isVideo"> | ||||
|                 <p v-if="isPodcast" class="mb-2 mt-0.5 text-gray-200 text-lg md:text-xl">by {{ podcastAuthor || 'Unknown' }}</p> | ||||
|                 <p v-else-if="authors.length" class="mb-2 mt-0.5 text-gray-200 text-lg md:text-xl"> | ||||
|                 <p v-else-if="authors.length" class="mb-2 mt-0.5 text-gray-200 text-lg md:text-xl max-w-[calc(100vw-2rem)] overflow-hidden overflow-ellipsis"> | ||||
|                   by <nuxt-link v-for="(author, index) in authors" :key="index" :to="`/author/${author.id}`" class="hover:underline">{{ author.name }}<span v-if="index < authors.length - 1">, </span></nuxt-link> | ||||
|                 </p> | ||||
|                 <p v-else class="mb-2 mt-0.5 text-gray-200 text-xl">by Unknown</p> | ||||
| @ -44,7 +44,7 @@ | ||||
|                 <div class="w-32"> | ||||
|                   <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNarrators }}</span> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                 <div class="max-w-[calc(100vw-10rem)] overflow-hidden overflow-ellipsis"> | ||||
|                   <template v-for="(narrator, index) in narrators"> | ||||
|                     <nuxt-link :key="narrator" :to="`/library/${libraryId}/bookshelf?filter=narrators.${$encode(narrator)}`" class="hover:underline">{{ narrator }}</nuxt-link | ||||
|                     ><span :key="index" v-if="index < narrators.length - 1">, </span> | ||||
| @ -63,7 +63,7 @@ | ||||
|                 <div class="w-32"> | ||||
|                   <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelGenres }}</span> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                 <div class="max-w-[calc(100vw-10rem)] overflow-hidden overflow-ellipsis"> | ||||
|                   <template v-for="(genre, index) in genres"> | ||||
|                     <nuxt-link :key="genre" :to="`/library/${libraryId}/bookshelf?filter=genres.${$encode(genre)}`" class="hover:underline">{{ genre }}</nuxt-link | ||||
|                     ><span :key="index" v-if="index < genres.length - 1">, </span> | ||||
|  | ||||
| @ -301,7 +301,11 @@ class LibraryItemController { | ||||
|     if (!libraryItemIds.length) { | ||||
|       return res.status(403).send('Invalid payload') | ||||
|     } | ||||
|     var libraryItems = this.db.libraryItems.filter(li => libraryItemIds.includes(li.id)).map((li) => li.toJSONExpanded()) | ||||
|     var libraryItems = [] | ||||
|     libraryItemIds.forEach((lid) => { | ||||
|       const li = this.db.libraryItems.find(_li => _li.id === lid) | ||||
|       if (li) libraryItems.push(li.toJSONExpanded()) | ||||
|     }) | ||||
|     res.json(libraryItems) | ||||
|   } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user