diff --git a/client/components/modals/item/tabs/Details.vue b/client/components/modals/item/tabs/Details.vue
index 2088407d..4680cd30 100644
--- a/client/components/modals/item/tabs/Details.vue
+++ b/client/components/modals/item/tabs/Details.vue
@@ -12,11 +12,11 @@
-
+
Quick Match
-
+
Re-Scan
diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js
index 9a886cce..250b6f6d 100644
--- a/server/scanner/Scanner.js
+++ b/server/scanner/Scanner.js
@@ -10,6 +10,7 @@ const { ScanResult, LogLevel } = require('../utils/constants')
const MediaFileScanner = require('./MediaFileScanner')
const BookFinder = require('../finders/BookFinder')
+const PodcastFinder = require('../finders/PodcastFinder')
const LibraryItem = require('../objects/LibraryItem')
const LibraryScan = require('./LibraryScan')
const ScanOptions = require('./ScanOptions')
@@ -33,6 +34,7 @@ class Scanner {
this.scanningFilesChanged = false
this.bookFinder = new BookFinder()
+ this.podcastFinder = new PodcastFinder()
}
isLibraryScanning(libraryId) {
@@ -672,16 +674,6 @@ class Scanner {
var provider = options.provider || 'google'
var searchTitle = options.title || libraryItem.media.metadata.title
var searchAuthor = options.author || libraryItem.media.metadata.authorName
- var searchISBN = options.isbn || libraryItem.media.metadata.isbn
- var searchASIN = options.asin || libraryItem.media.metadata.asin
-
- var results = await this.bookFinder.search(provider, searchTitle, searchAuthor, searchISBN, searchASIN)
- if (!results.length) {
- return {
- warning: `No ${provider} match found`
- }
- }
- var matchData = results[0]
// Set to override existing metadata if scannerPreferMatchedMetadata setting is true
if (this.db.serverSettings.scannerPreferMatchedMetadata) {
@@ -689,18 +681,110 @@ class Scanner {
options.overrideDetails = true
}
- // Update cover if not set OR overrideCover flag
+ var updatePayload = {}
var hasUpdated = false
- if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) {
- Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`)
- var coverResult = await this.coverManager.downloadCoverFromUrl(libraryItem, matchData.cover)
- if (!coverResult || coverResult.error || !coverResult.cover) {
- Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
- } else {
+
+ if (libraryItem.mediaType === 'book') {
+ var searchISBN = options.isbn || libraryItem.media.metadata.isbn
+ var searchASIN = options.asin || libraryItem.media.metadata.asin
+
+ var results = await this.bookFinder.search(provider, searchTitle, searchAuthor, searchISBN, searchASIN)
+ if (!results.length) {
+ return {
+ warning: `No ${provider} match found`
+ }
+ }
+ var matchData = results[0]
+
+ // Update cover if not set OR overrideCover flag
+ if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) {
+ Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`)
+ var coverResult = await this.coverManager.downloadCoverFromUrl(libraryItem, matchData.cover)
+ if (!coverResult || coverResult.error || !coverResult.cover) {
+ Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
+ } else {
+ hasUpdated = true
+ }
+ }
+
+ updatePayload = await this.quickMatchBookBuildUpdatePayload(libraryItem, matchData, options)
+ } else { // Podcast quick match
+ var results = await this.podcastFinder.search(searchTitle)
+ if (!results.length) {
+ return {
+ warning: `No ${provider} match found`
+ }
+ }
+ var matchData = results[0]
+
+ // Update cover if not set OR overrideCover flag
+ if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) {
+ Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`)
+ var coverResult = await this.coverManager.downloadCoverFromUrl(libraryItem, matchData.cover)
+ if (!coverResult || coverResult.error || !coverResult.cover) {
+ Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
+ } else {
+ hasUpdated = true
+ }
+ }
+
+ updatePayload = this.quickMatchPodcastBuildUpdatePayload(libraryItem, matchData, options)
+ }
+
+ if (Object.keys(updatePayload).length) {
+ Logger.debug('[Scanner] Updating details', updatePayload)
+ if (libraryItem.media.update(updatePayload)) {
hasUpdated = true
}
}
+ if (hasUpdated) {
+ await this.db.updateLibraryItem(libraryItem)
+ this.emitter('item_updated', libraryItem.toJSONExpanded())
+ }
+
+ return {
+ updated: hasUpdated,
+ libraryItem: libraryItem.toJSONExpanded()
+ }
+ }
+
+ quickMatchPodcastBuildUpdatePayload(libraryItem, matchData, options) {
+ const updatePayload = {}
+ updatePayload.metadata = {}
+
+ const matchDataTransformed = {
+ title: matchData.title || null,
+ author: matchData.artistName || null,
+ genres: matchData.genres || [],
+ itunesId: matchData.id || null,
+ itunesPageUrl: matchData.pageUrl || null,
+ itunesArtistId: matchData.artistId || null,
+ releaseDate: matchData.releaseDate || null,
+ imageUrl: matchData.cover || null,
+ description: matchData.descriptionPlain || null
+ }
+
+ for (const key in matchDataTransformed) {
+ if (matchDataTransformed[key]) {
+ if (key === 'genres') {
+ if ((!libraryItem.media.metadata.genres || options.overrideDetails)) {
+ updatePayload.metadata[key] = matchDataTransformed[key].split(',').map(v => v.trim()).filter(v => !!v)
+ }
+ } else if (!libraryItem.media.metadata[key] || options.overrideDetails) {
+ updatePayload.metadata[key] = matchDataTransformed[key]
+ }
+ }
+ }
+
+ if (!Object.keys(updatePayload.metadata).length) {
+ delete updatePayload.metadata
+ }
+
+ return updatePayload
+ }
+
+ async quickMatchBookBuildUpdatePayload(libraryItem, matchData, options) {
// Update media metadata if not set OR overrideDetails flag
const detailKeysToUpdate = ['title', 'subtitle', 'description', 'narrator', 'publisher', 'publishedYear', 'genres', 'tags', 'language', 'explicit', 'asin', 'isbn']
const updatePayload = {}
@@ -763,22 +847,11 @@ class Scanner {
updatePayload.metadata.series = seriesPayload
}
- if (Object.keys(updatePayload).length) {
- Logger.debug('[Scanner] Updating details', updatePayload)
- if (libraryItem.media.update(updatePayload)) {
- hasUpdated = true
- }
+ if (!Object.keys(updatePayload.metadata).length) {
+ delete updatePayload.metadata
}
- if (hasUpdated) {
- await this.db.updateLibraryItem(libraryItem)
- this.emitter('item_updated', libraryItem.toJSONExpanded())
- }
-
- return {
- updated: hasUpdated,
- libraryItem: libraryItem.toJSONExpanded()
- }
+ return updatePayload
}
async matchLibraryItems(library) {