mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-03-04 15:09:44 +00:00
Implement Ctrl+A Select All and Batch Reset functionality
This commit is contained in:
parent
23034e6672
commit
f7506e84d3
9 changed files with 266 additions and 3 deletions
|
|
@ -186,6 +186,11 @@ export default {
|
|||
action: 'rescan'
|
||||
})
|
||||
|
||||
options.push({
|
||||
text: 'Reset Metadata',
|
||||
action: 'reset-metadata'
|
||||
})
|
||||
|
||||
// The limit of 50 is introduced because of the URL length. Each id has 36 chars, so 36 * 40 = 1440
|
||||
// + 40 , separators = 1480 chars + base path 280 chars = 1760 chars. This keeps the URL under 2000 chars even with longer domains
|
||||
if (this.selectedMediaItems.length <= 40) {
|
||||
|
|
@ -261,6 +266,8 @@ export default {
|
|||
this.batchMerge()
|
||||
} else if (action === 'consolidate') {
|
||||
this.batchConsolidate()
|
||||
} else if (action === 'reset-metadata') {
|
||||
this.batchResetMetadata()
|
||||
}
|
||||
},
|
||||
batchConsolidate() {
|
||||
|
|
@ -294,6 +301,34 @@ export default {
|
|||
}
|
||||
this.$store.commit('globals/setConfirmPrompt', payload)
|
||||
},
|
||||
batchResetMetadata() {
|
||||
const payload = {
|
||||
message: `Are you sure you want to reset metadata for ${this.numMediaItemsSelected} items? This will remove metadata files and re-scan the items from files.`,
|
||||
callback: (confirmed) => {
|
||||
if (confirmed) {
|
||||
this.$store.commit('setProcessingBatch', true)
|
||||
this.$axios
|
||||
.$post('/api/items/batch/reset-metadata', {
|
||||
libraryItemIds: this.selectedMediaItems.map((i) => i.id)
|
||||
})
|
||||
.then(() => {
|
||||
this.$toast.success('Batch reset metadata successful')
|
||||
this.cancelSelectionMode()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Batch reset metadata failed', error)
|
||||
const errorMsg = error.response?.data || 'Batch reset metadata failed'
|
||||
this.$toast.error(errorMsg)
|
||||
})
|
||||
.finally(() => {
|
||||
this.$store.commit('setProcessingBatch', false)
|
||||
})
|
||||
}
|
||||
},
|
||||
type: 'yesNo'
|
||||
}
|
||||
this.$store.commit('globals/setConfirmPrompt', payload)
|
||||
},
|
||||
batchMerge() {
|
||||
const payload = {
|
||||
message: this.$strings.MessageConfirmBatchMerge,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ export default {
|
|||
lastTimestamp: 0,
|
||||
postScrollTimeout: null,
|
||||
currFirstEntityIndex: -1,
|
||||
currLastEntityIndex: -1
|
||||
currLastEntityIndex: -1,
|
||||
isSelectAll: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -246,17 +247,48 @@ export default {
|
|||
}
|
||||
},
|
||||
clearSelectedEntities() {
|
||||
this.isSelectAll = false
|
||||
this.updateBookSelectionMode(false)
|
||||
this.isSelectionMode = false
|
||||
},
|
||||
selectAll() {
|
||||
if (this.entityName !== 'items' && this.entityName !== 'series-books' && this.entityName !== 'collections' && this.entityName !== 'playlists') {
|
||||
return
|
||||
}
|
||||
|
||||
this.isSelectAll = true
|
||||
this.isSelectionMode = true
|
||||
|
||||
const itemsToSelect = []
|
||||
this.entities.forEach((entity) => {
|
||||
if (entity && !entity.collapsedSeries) {
|
||||
const mediaItem = {
|
||||
id: entity.id,
|
||||
libraryId: entity.libraryId,
|
||||
mediaType: entity.mediaType,
|
||||
hasTracks: entity.mediaType === 'podcast' || entity.media.audioFile || entity.media.numTracks || (entity.media.tracks && entity.media.tracks.length)
|
||||
}
|
||||
itemsToSelect.push(mediaItem)
|
||||
}
|
||||
})
|
||||
|
||||
if (itemsToSelect.length) {
|
||||
this.$store.commit('globals/addBatchMediaItemsSelected', itemsToSelect)
|
||||
}
|
||||
|
||||
this.updateBookSelectionMode(true)
|
||||
},
|
||||
selectEntity(entity, shiftKey) {
|
||||
if (this.entityName === 'items' || this.entityName === 'series-books') {
|
||||
const indexOf = this.entities.findIndex((ent) => ent && ent.id === entity.id)
|
||||
const lastLastItemIndexSelected = this.lastItemIndexSelected
|
||||
if (!this.selectedMediaItems.some((i) => i.id === entity.id)) {
|
||||
const alreadySelected = this.selectedMediaItems.some((i) => i.id === entity.id)
|
||||
|
||||
if (!alreadySelected) {
|
||||
this.lastItemIndexSelected = indexOf
|
||||
} else {
|
||||
this.lastItemIndexSelected = -1
|
||||
this.isSelectAll = false // Deselecting an item turns off "Select All" mode
|
||||
}
|
||||
|
||||
if (shiftKey && lastLastItemIndexSelected >= 0) {
|
||||
|
|
@ -322,7 +354,11 @@ export default {
|
|||
updateBookSelectionMode(isSelectionMode) {
|
||||
for (const key in this.entityComponentRefs) {
|
||||
if (this.entityIndexesMounted.includes(Number(key))) {
|
||||
this.entityComponentRefs[key].setSelectionMode(isSelectionMode)
|
||||
const component = this.entityComponentRefs[key]
|
||||
component.setSelectionMode(isSelectionMode)
|
||||
if (isSelectionMode && this.isSelectAll) {
|
||||
component.selected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isSelectionMode) {
|
||||
|
|
@ -780,8 +816,19 @@ export default {
|
|||
windowResize() {
|
||||
this.executeRebuild()
|
||||
},
|
||||
handleKeyDown(e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
|
||||
// Only trigger if no input/textarea is focused
|
||||
if (['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
this.selectAll()
|
||||
}
|
||||
},
|
||||
initListeners() {
|
||||
window.addEventListener('resize', this.windowResize)
|
||||
window.addEventListener('keydown', this.handleKeyDown)
|
||||
|
||||
this.$nextTick(() => {
|
||||
var bookshelf = document.getElementById('bookshelf')
|
||||
|
|
@ -817,6 +864,7 @@ export default {
|
|||
},
|
||||
removeListeners() {
|
||||
window.removeEventListener('resize', this.windowResize)
|
||||
window.removeEventListener('keydown', this.handleKeyDown)
|
||||
var bookshelf = document.getElementById('bookshelf')
|
||||
if (bookshelf) {
|
||||
bookshelf.removeEventListener('scroll', this.scroll)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue