Add:Library route quick match all books

This commit is contained in:
advplyr 2022-02-15 16:36:22 -06:00
parent 088969e1fe
commit c953c3dee0
4 changed files with 87 additions and 52 deletions

View File

@ -181,8 +181,8 @@ export default {
this.quickMatching = true this.quickMatching = true
var matchOptions = { var matchOptions = {
provider: this.libraryProvider, provider: this.libraryProvider,
title: details.title, title: this.details.title,
author: details.author !== this.book.author ? details.author : null author: this.details.author !== this.book.author ? this.details.author : null
} }
this.$axios this.$axios
.$post(`/api/books/${this.audiobookId}/match`, matchOptions) .$post(`/api/books/${this.audiobookId}/match`, matchOptions)

View File

@ -59,6 +59,7 @@ class ApiController {
this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this)) this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this))
this.router.get('/libraries/:id/stats', LibraryController.middleware.bind(this), LibraryController.stats.bind(this)) this.router.get('/libraries/:id/stats', LibraryController.middleware.bind(this), LibraryController.stats.bind(this))
this.router.get('/libraries/:id/authors', LibraryController.middleware.bind(this), LibraryController.getAuthors.bind(this)) this.router.get('/libraries/:id/authors', LibraryController.middleware.bind(this), LibraryController.getAuthors.bind(this))
this.router.post('/libraries/:id/matchbooks', LibraryController.middleware.bind(this), LibraryController.matchBooks.bind(this))
this.router.post('/libraries/order', LibraryController.reorder.bind(this)) this.router.post('/libraries/order', LibraryController.reorder.bind(this))
// TEMP: Support old syntax for mobile app // TEMP: Support old syntax for mobile app
@ -516,5 +517,57 @@ class ApiController {
await this.cacheManager.purgeAll() await this.cacheManager.purgeAll()
res.sendStatus(200) res.sendStatus(200)
} }
async quickMatchBook(audiobook, options = {}) {
var provider = options.provider || 'google'
var searchTitle = options.title || audiobook.book._title
var searchAuthor = options.author || audiobook.book._author
var results = await this.bookFinder.search(provider, searchTitle, searchAuthor)
if (!results.length) {
return {
warning: `No ${provider} match found`
}
}
var matchData = results[0]
// Update cover if not set OR overrideCover flag
var hasUpdated = false
if (matchData.cover && (!audiobook.book.cover || options.overrideCover)) {
Logger.debug(`[BookController] Updating cover "${matchData.cover}"`)
var coverResult = await this.coverController.downloadCoverFromUrl(audiobook, matchData.cover)
if (!coverResult || coverResult.error || !coverResult.cover) {
Logger.warn(`[BookController] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
} else {
hasUpdated = true
}
}
// Update book details if not set OR overrideDetails flag
const detailKeysToUpdate = ['title', 'subtitle', 'author', 'narrator', 'publisher', 'publishYear', 'series', 'volumeNumber', 'asin', 'isbn']
const updatePayload = {}
for (const key in matchData) {
if (matchData[key] && detailKeysToUpdate.includes(key) && (!audiobook.book[key] || options.overrideDetails)) {
updatePayload[key] = matchData[key]
}
}
if (Object.keys(updatePayload).length) {
Logger.debug('[BookController] Updating details', updatePayload)
if (audiobook.update({ book: updatePayload })) {
hasUpdated = true
}
}
if (hasUpdated) {
await this.db.updateEntity('audiobook', audiobook)
this.emitter('audiobook_updated', audiobook.toJSONExpanded())
}
return {
updated: hasUpdated,
audiobook: audiobook.toJSONExpanded()
}
}
} }
module.exports = ApiController module.exports = ApiController

View File

@ -272,55 +272,8 @@ class BookController {
} }
var options = req.body || {} var options = req.body || {}
var provider = options.provider || 'google' var matchResult = await this.quickMatchBook(audiobook, options)
var searchTitle = options.title || audiobook.book._title res.json(matchResult)
var searchAuthor = options.author || audiobook.book._author
var results = await this.bookFinder.search(provider, searchTitle, searchAuthor)
if (!results.length) {
return res.json({
warning: `No ${provider} match found`
})
}
var matchData = results[0]
// Update cover if not set OR overrideCover flag
var hasUpdated = false
if (matchData.cover && (!audiobook.book.cover || options.overrideCover)) {
Logger.debug(`[BookController] Updating cover "${matchData.cover}"`)
var coverResult = await this.coverController.downloadCoverFromUrl(audiobook, matchData.cover)
if (!coverResult || coverResult.error || !coverResult.cover) {
Logger.warn(`[BookController] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
} else {
hasUpdated = true
}
}
// Update book details if not set OR overrideDetails flag
const detailKeysToUpdate = ['title', 'subtitle', 'author', 'narrator', 'publisher', 'publishYear', 'series', 'volumeNumber', 'asin', 'isbn']
const updatePayload = {}
for (const key in matchData) {
if (matchData[key] && detailKeysToUpdate.includes(key) && (!audiobook.book[key] || options.overrideDetails)) {
updatePayload[key] = matchData[key]
}
}
if (Object.keys(updatePayload).length) {
Logger.debug('[BookController] Updating details', updatePayload)
if (audiobook.update({ book: updatePayload })) {
hasUpdated = true
}
}
if (hasUpdated) {
await this.db.updateEntity('audiobook', audiobook)
this.emitter('audiobook_updated', audiobook.toJSONExpanded())
}
res.json({
updated: hasUpdated,
audiobook: audiobook.toJSONExpanded()
})
} }
} }
module.exports = new BookController() module.exports = new BookController()

View File

@ -334,7 +334,7 @@ class LibraryController {
async reorder(req, res) { async reorder(req, res) {
if (!req.user.isRoot) { if (!req.user.isRoot) {
Logger.error('[ApiController] ReorderLibraries invalid user', req.user) Logger.error('[ApiController] ReorderLibraries invalid user', req.user)
return res.sendStatus(401) return res.sendStatus(403)
} }
var orderdata = req.body var orderdata = req.body
@ -470,6 +470,35 @@ class LibraryController {
res.json(Object.values(authors)) res.json(Object.values(authors))
} }
async matchBooks(req, res) {
if (!req.user.isRoot) {
Logger.error(`[LibraryController] Non-root user attempted to match library books`, req.user)
return res.sendStatus(403)
}
res.sendStatus(200)
const provider = req.library.provider || 'google'
var audiobooksInLibrary = this.db.audiobooks.filter(ab => ab.libraryId === req.library.id)
const resultPayload = {
library: library.toJSON(),
total: audiobooksInLibrary.length,
updated: 0
}
for (let i = 0; i < audiobooksInLibrary.length; i++) {
var audiobook = audiobooksInLibrary[i]
Logger.debug(`[LibraryController] matchBooks quick matching "${audiobook.title}" (${i + 1} of ${audiobooksInLibrary.length})`)
var result = await this.quickMatchBook(audiobook, { provider })
if (result.warning) {
Logger.warn(`[LibraryController] matchBooks warning ${result.warning} for audiobook "${audiobook.title}"`)
} else if (result.updated) {
resultPayload.updated++
}
}
this.clientEmitter(req.usr.id, 'library-match-results', resultPayload)
}
middleware(req, res, next) { middleware(req, res, next) {
var librariesAccessible = req.user.librariesAccessible || [] var librariesAccessible = req.user.librariesAccessible || []
if (librariesAccessible && librariesAccessible.length && !librariesAccessible.includes(req.params.id)) { if (librariesAccessible && librariesAccessible.length && !librariesAccessible.includes(req.params.id)) {