mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-22 00:07:52 +01:00
Update:Quick match all for library to use task instead of toast, remove scan socket events
This commit is contained in:
parent
50215dab9a
commit
49403771c9
@ -12,7 +12,7 @@
|
||||
<p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p>
|
||||
<p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p>
|
||||
</div>
|
||||
<ui-btn v-if="userIsAdminOrUp && !isFinished && action === 'library-scan' && !cancelingScan" color="primary" :padding-y="1" :padding-x="1" class="text-xs w-16 max-w-16 truncate mr-1" @click.stop="cancelScan">{{ this.$strings.ButtonCancel }}</ui-btn>
|
||||
<ui-btn v-if="userIsAdminOrUp && !isFinished && isLibraryScan && !cancelingScan" color="primary" :padding-y="1" :padding-x="1" class="text-xs w-16 max-w-16 truncate mr-1" @click.stop="cancelScan">{{ this.$strings.ButtonCancel }}</ui-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -81,6 +81,9 @@ export default {
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
isLibraryScan() {
|
||||
return this.action === 'library-scan' || this.action === 'library-match-all'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -11,8 +11,8 @@
|
||||
<ui-btn v-if="userIsAdminOrUp" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">{{ $strings.ButtonQuickMatch }}</ui-btn>
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-tooltip :disabled="!!libraryScan" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4">
|
||||
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="!!libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn>
|
||||
<ui-tooltip :disabled="isLibraryScanning" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4">
|
||||
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="isLibraryScanning" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn>
|
||||
</ui-tooltip>
|
||||
|
||||
<div class="flex-grow" />
|
||||
@ -80,9 +80,9 @@ export default {
|
||||
libraryProvider() {
|
||||
return this.$store.getters['libraries/getLibraryProvider'](this.libraryId) || 'google'
|
||||
},
|
||||
libraryScan() {
|
||||
isLibraryScanning() {
|
||||
if (!this.libraryId) return null
|
||||
return this.$store.getters['scanners/getLibraryScan'](this.libraryId)
|
||||
return !!this.$store.getters['tasks/getRunningLibraryScanTask'](this.libraryId)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -42,13 +42,10 @@ export default {
|
||||
return this.$store.getters['libraries/getCurrentLibrary']
|
||||
},
|
||||
currentLibraryId() {
|
||||
return this.currentLibrary ? this.currentLibrary.id : null
|
||||
return this.currentLibrary?.id || null
|
||||
},
|
||||
libraries() {
|
||||
return this.$store.getters['libraries/getSortedLibraries']()
|
||||
},
|
||||
libraryScans() {
|
||||
return this.$store.state.scanners.libraryScans
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -212,54 +212,6 @@ export default {
|
||||
this.libraryItemAdded(ab)
|
||||
})
|
||||
},
|
||||
scanComplete(data) {
|
||||
console.log('Scan complete received', data)
|
||||
|
||||
let message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" complete!`
|
||||
let toastType = 'success'
|
||||
if (data.error) {
|
||||
message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" finished with error:\n${data.error}`
|
||||
toastType = 'error'
|
||||
} else if (data.results) {
|
||||
var scanResultMsgs = []
|
||||
var results = data.results
|
||||
if (results.added) scanResultMsgs.push(`${results.added} added`)
|
||||
if (results.updated) scanResultMsgs.push(`${results.updated} updated`)
|
||||
if (results.removed) scanResultMsgs.push(`${results.removed} removed`)
|
||||
if (results.missing) scanResultMsgs.push(`${results.missing} missing`)
|
||||
if (!scanResultMsgs.length) message += '\nEverything was up to date'
|
||||
else message += '\n' + scanResultMsgs.join('\n')
|
||||
} else {
|
||||
message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" was canceled`
|
||||
}
|
||||
|
||||
var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
|
||||
if (existingScan && !isNaN(existingScan.toastId)) {
|
||||
this.$toast.update(existingScan.toastId, { content: message, options: { timeout: 5000, type: toastType, closeButton: false, onClose: () => null } }, true)
|
||||
} else {
|
||||
this.$toast[toastType](message, { timeout: 5000 })
|
||||
}
|
||||
|
||||
this.$store.commit('scanners/remove', data)
|
||||
},
|
||||
onScanToastCancel(id) {
|
||||
this.$root.socket.emit('cancel_scan', id)
|
||||
},
|
||||
scanStart(data) {
|
||||
data.toastId = this.$toast(`${data.type === 'match' ? 'Matching' : 'Scanning'} "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, onClose: () => this.onScanToastCancel(data.id) })
|
||||
this.$store.commit('scanners/addUpdate', data)
|
||||
},
|
||||
scanProgress(data) {
|
||||
var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
|
||||
if (existingScan && !isNaN(existingScan.toastId)) {
|
||||
data.toastId = existingScan.toastId
|
||||
this.$toast.update(existingScan.toastId, { content: `Scanning "${existingScan.name}"... ${data.progress.progress || 0}%`, options: { timeout: false } }, true)
|
||||
} else {
|
||||
data.toastId = this.$toast(`Scanning "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, onClose: () => this.onScanToastCancel(data.id) })
|
||||
}
|
||||
|
||||
this.$store.commit('scanners/addUpdate', data)
|
||||
},
|
||||
taskStarted(task) {
|
||||
console.log('Task started', task)
|
||||
this.$store.commit('tasks/addUpdateTask', task)
|
||||
@ -442,11 +394,6 @@ export default {
|
||||
this.socket.on('playlist_updated', this.playlistUpdated)
|
||||
this.socket.on('playlist_removed', this.playlistRemoved)
|
||||
|
||||
// Scan Listeners
|
||||
this.socket.on('scan_start', this.scanStart)
|
||||
this.socket.on('scan_complete', this.scanComplete)
|
||||
this.socket.on('scan_progress', this.scanProgress)
|
||||
|
||||
// Task Listeners
|
||||
this.socket.on('task_started', this.taskStarted)
|
||||
this.socket.on('task_finished', this.taskFinished)
|
||||
|
@ -1,5 +1,4 @@
|
||||
export const state = () => ({
|
||||
libraryScans: [],
|
||||
providers: [
|
||||
{
|
||||
text: 'Google Books',
|
||||
@ -72,26 +71,8 @@ export const state = () => ({
|
||||
]
|
||||
})
|
||||
|
||||
export const getters = {
|
||||
getLibraryScan: state => id => {
|
||||
return state.libraryScans.find(ls => ls.id === id)
|
||||
}
|
||||
}
|
||||
export const getters = {}
|
||||
|
||||
export const actions = {
|
||||
export const actions = {}
|
||||
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
addUpdate(state, data) {
|
||||
const index = state.libraryScans.findIndex(lib => lib.id === data.id)
|
||||
if (index >= 0) {
|
||||
state.libraryScans.splice(index, 1, data)
|
||||
} else {
|
||||
state.libraryScans.push(data)
|
||||
}
|
||||
},
|
||||
remove(state, data) {
|
||||
state.libraryScans = state.libraryScans.filter(scan => scan.id !== data.id)
|
||||
}
|
||||
}
|
||||
export const mutations = {}
|
@ -9,7 +9,8 @@ export const getters = {
|
||||
return state.tasks.filter(t => t.data?.libraryItemId === libraryItemId)
|
||||
},
|
||||
getRunningLibraryScanTask: (state) => (libraryId) => {
|
||||
return state.tasks.find(t => t.data?.libraryId === libraryId && !t.isFinished)
|
||||
const libraryScanActions = ['library-scan', 'library-match-all']
|
||||
return state.tasks.find(t => libraryScanActions.includes(t.action) && t.data?.libraryId === libraryId && !t.isFinished)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,6 +775,13 @@ class LibraryController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* GET: /api/libraries/:id/matchall
|
||||
* Quick match all library items. Book libraries only.
|
||||
*
|
||||
* @param {import('express').Request} req
|
||||
* @param {import('express').Response} res
|
||||
*/
|
||||
async matchAll(req, res) {
|
||||
if (!req.user.isAdminOrUp) {
|
||||
Logger.error(`[LibraryController] Non-root user attempted to match library items`, req.user)
|
||||
|
@ -69,7 +69,7 @@ class LibraryItem extends Model {
|
||||
*
|
||||
* @param {number} offset
|
||||
* @param {number} limit
|
||||
* @returns {Promise<Model<LibraryItem>[]>} LibraryItem
|
||||
* @returns {Promise<LibraryItem[]>} LibraryItem
|
||||
*/
|
||||
static getLibraryItemsIncrement(offset, limit, where = null) {
|
||||
return this.findAll({
|
||||
|
@ -12,6 +12,7 @@ const Author = require('../objects/entities/Author')
|
||||
const Series = require('../objects/entities/Series')
|
||||
const LibraryScanner = require('./LibraryScanner')
|
||||
const CoverManager = require('../managers/CoverManager')
|
||||
const TaskManager = require('../managers/TaskManager')
|
||||
|
||||
class Scanner {
|
||||
constructor() { }
|
||||
@ -280,6 +281,14 @@ class Scanner {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick match library items
|
||||
*
|
||||
* @param {import('../objects/Library')} library
|
||||
* @param {import('../objects/LibraryItem')[]} libraryItems
|
||||
* @param {LibraryScan} libraryScan
|
||||
* @returns {Promise<boolean>} false if scan canceled
|
||||
*/
|
||||
async matchLibraryItemsChunk(library, libraryItems, libraryScan) {
|
||||
for (let i = 0; i < libraryItems.length; i++) {
|
||||
const libraryItem = libraryItems[i]
|
||||
@ -313,6 +322,11 @@ class Scanner {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick match all library items for library
|
||||
*
|
||||
* @param {import('../objects/Library')} library
|
||||
*/
|
||||
async matchLibraryItems(library) {
|
||||
if (library.mediaType === 'podcast') {
|
||||
Logger.error(`[Scanner] matchLibraryItems: Match all not supported for podcasts yet`)
|
||||
@ -330,11 +344,14 @@ class Scanner {
|
||||
const libraryScan = new LibraryScan()
|
||||
libraryScan.setData(library, 'match')
|
||||
LibraryScanner.librariesScanning.push(libraryScan.getScanEmitData)
|
||||
SocketAuthority.emitter('scan_start', libraryScan.getScanEmitData)
|
||||
|
||||
const taskData = {
|
||||
libraryId: library.id
|
||||
}
|
||||
const task = TaskManager.createAndAddTask('library-match-all', `Matching books in "${library.name}"`, null, true, taskData)
|
||||
Logger.info(`[Scanner] matchLibraryItems: Starting library match scan ${libraryScan.id} for ${libraryScan.libraryName}`)
|
||||
|
||||
let hasMoreChunks = true
|
||||
let isCanceled = false
|
||||
while (hasMoreChunks) {
|
||||
const libraryItems = await Database.libraryItemModel.getLibraryItemsIncrement(offset, limit, { libraryId: library.id })
|
||||
if (!libraryItems.length) {
|
||||
@ -347,6 +364,7 @@ class Scanner {
|
||||
|
||||
const shouldContinue = await this.matchLibraryItemsChunk(library, oldLibraryItems, libraryScan)
|
||||
if (!shouldContinue) {
|
||||
isCanceled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -354,13 +372,15 @@ class Scanner {
|
||||
if (offset === 0) {
|
||||
Logger.error(`[Scanner] matchLibraryItems: Library has no items ${library.id}`)
|
||||
libraryScan.setComplete('Library has no items')
|
||||
task.setFailed(libraryScan.error)
|
||||
} else {
|
||||
libraryScan.setComplete()
|
||||
task.setFinished(isCanceled ? 'Canceled' : libraryScan.scanResultsString)
|
||||
}
|
||||
|
||||
delete LibraryScanner.cancelLibraryScan[libraryScan.libraryId]
|
||||
LibraryScanner.librariesScanning = LibraryScanner.librariesScanning.filter(ls => ls.id !== library.id)
|
||||
SocketAuthority.emitter('scan_complete', libraryScan.getScanEmitData)
|
||||
TaskManager.taskFinished(task)
|
||||
}
|
||||
}
|
||||
module.exports = new Scanner()
|
||||
|
Loading…
Reference in New Issue
Block a user