Fix LibraryItem and Media file update logic for library scans

This commit is contained in:
mikiher 2024-03-19 19:28:26 +02:00
parent 88f9533b37
commit 9511122bae
3 changed files with 89 additions and 10 deletions

View File

@ -20,6 +20,7 @@ const LibraryScan = require("./LibraryScan")
const OpfFileScanner = require('./OpfFileScanner')
const NfoFileScanner = require('./NfoFileScanner')
const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
const EBookFile = require("../objects/files/EBookFile")
/**
* Metadata for books pulled from files
@ -84,7 +85,7 @@ class BookScanner {
// Update audio files that were modified
if (libraryItemData.audioLibraryFilesModified.length) {
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified)
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified.map(lf => lf.new))
media.audioFiles = media.audioFiles.map((audioFileObj) => {
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === audioFileObj.metadata.path)
if (!matchedScannedAudioFile) {
@ -138,11 +139,25 @@ class BookScanner {
}
// Check if cover was removed
if (media.coverPath && !libraryItemData.imageLibraryFiles.some(lf => lf.metadata.path === media.coverPath) && !(await fsExtra.pathExists(media.coverPath))) {
if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some(lf => lf.metadata.path === media.coverPath) && !(await fsExtra.pathExists(media.coverPath))) {
media.coverPath = null
hasMediaChanges = true
}
// Update cover if it was modified
if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) {
let coverMatch = libraryItemData.imageLibraryFilesModified.find(iFile => iFile.old.metadata.path === media.coverPath)
if (coverMatch) {
const coverPath = coverMatch.new.metadata.path
if (coverPath !== media.coverPath) {
libraryScan.addLog(LogLevel.DEBUG, `Updating book cover "${media.coverPath}" => "${coverPath}" for book "${media.title}"`)
media.coverPath = coverPath
media.changed('coverPath', true)
hasMediaChanges = true
}
}
}
// Check if cover is not set and image files were found
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
// Prefer using a cover image with the name "cover" otherwise use the first image
@ -157,6 +172,19 @@ class BookScanner {
hasMediaChanges = true
}
// Update ebook if it was modified
if (media.ebookFile && libraryItemData.ebookLibraryFilesModified.length) {
let ebookMatch = libraryItemData.ebookLibraryFilesModified.find(eFile => eFile.old.metadata.path === media.ebookFile.metadata.path)
if (ebookMatch) {
const ebookFile = new EBookFile(ebookMatch.new)
ebookFile.ebookFormat = ebookFile.metadata.ext.slice(1).toLowerCase()
libraryScan.addLog(LogLevel.DEBUG, `Updating book ebook file "${media.ebookFile.metadata.path}" => "${ebookFile.metadata.path}" for book "${media.title}"`)
media.ebookFile = ebookFile.toJSON()
media.changed('ebookFile', true)
hasMediaChanges = true
}
}
// Check if ebook is not set and ebooks were found
if (!media.ebookFile && !librarySettings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
// Prefer to use an epub ebook then fallback to the first ebook found

View File

@ -4,6 +4,12 @@ const LibraryItem = require('../models/LibraryItem')
const globals = require('../utils/globals')
class LibraryItemScanData {
/**
* @typedef LibraryFileModifiedObject
* @property {LibraryItem.LibraryFileObject} old
* @property {LibraryItem.LibraryFileObject} new
*/
constructor(data) {
/** @type {string} */
this.libraryFolderId = data.libraryFolderId
@ -39,7 +45,7 @@ class LibraryItemScanData {
this.libraryFilesRemoved = []
/** @type {LibraryItem.LibraryFileObject[]} */
this.libraryFilesAdded = []
/** @type {LibraryItem.LibraryFileObject[]} */
/** @type {LibraryFileModifiedObject[]} */
this.libraryFilesModified = []
}
@ -77,9 +83,9 @@ class LibraryItemScanData {
return (this.audioLibraryFilesRemoved.length + this.audioLibraryFilesAdded.length + this.audioLibraryFilesModified.length) > 0
}
/** @type {LibraryItem.LibraryFileObject[]} */
/** @type {LibraryFileModifiedObject[]} */
get audioLibraryFilesModified() {
return this.libraryFilesModified.filter(lf => globals.SupportedAudioTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
return this.libraryFilesModified.filter(lf => globals.SupportedAudioTypes.includes(lf.old.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
@ -97,12 +103,42 @@ class LibraryItemScanData {
return this.libraryFiles.filter(lf => globals.SupportedAudioTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryFileModifiedObject[]} */
get imageLibraryFilesModified() {
return this.libraryFilesModified.filter(lf => globals.SupportedImageTypes.includes(lf.old.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get imageLibraryFilesRemoved() {
return this.libraryFilesRemoved.filter(lf => globals.SupportedImageTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get imageLibraryFilesAdded() {
return this.libraryFilesAdded.filter(lf => globals.SupportedImageTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get imageLibraryFiles() {
return this.libraryFiles.filter(lf => globals.SupportedImageTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {import('../objects/files/LibraryFile')[]} */
/** @type {LibraryFileModifiedObject[]} */
get ebookLibraryFilesModified() {
return this.libraryFilesModified.filter(lf => globals.SupportedEbookTypes.includes(lf.old.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get ebookLibraryFilesRemoved() {
return this.libraryFilesRemoved.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get ebookLibraryFilesAdded() {
return this.libraryFilesAdded.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
/** @type {LibraryItem.LibraryFileObject[]} */
get ebookLibraryFiles() {
return this.libraryFiles.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
}
@ -153,7 +189,7 @@ class LibraryItemScanData {
existingLibraryItem[key] = this[key]
this.hasChanges = true
if (key === 'relPath') {
if (key === 'relPath' || key === 'path') {
this.hasPathChange = true
}
}
@ -202,8 +238,9 @@ class LibraryItemScanData {
this.hasChanges = true
} else {
libraryFilesAdded = libraryFilesAdded.filter(lf => lf !== matchingLibraryFile)
let existingLibraryFileBefore = structuredClone(existingLibraryFile)
if (this.compareUpdateLibraryFile(existingLibraryItem.path, existingLibraryFile, matchingLibraryFile, libraryScan)) {
this.libraryFilesModified.push(existingLibraryFile)
this.libraryFilesModified.push({old: existingLibraryFileBefore, new: existingLibraryFile})
this.hasChanges = true
}
}

View File

@ -71,7 +71,7 @@ class PodcastScanner {
// Update audio files that were modified
if (libraryItemData.audioLibraryFilesModified.length) {
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified)
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified.map(lf => lf.new))
for (const podcastEpisode of existingPodcastEpisodes) {
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === podcastEpisode.audioFile.metadata.path)
@ -132,11 +132,25 @@ class PodcastScanner {
let hasMediaChanges = false
// Check if cover was removed
if (media.coverPath && !libraryItemData.imageLibraryFiles.some(lf => lf.metadata.path === media.coverPath)) {
if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some(lf => lf.metadata.path === media.coverPath)) {
media.coverPath = null
hasMediaChanges = true
}
// Update cover if it was modified
if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) {
let coverMatch = libraryItemData.imageLibraryFilesModified.find(iFile => iFile.old.metadata.path === media.coverPath)
if (coverMatch) {
const coverPath = coverMatch.new.metadata.path
if (coverPath !== media.coverPath) {
libraryScan.addLog(LogLevel.DEBUG, `Updating podcast cover "${media.coverPath}" => "${coverPath}" for podcast "${media.title}"`)
media.coverPath = coverPath
media.changed('coverPath', true)
hasMediaChanges = true
}
}
}
// Check if cover is not set and image files were found
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
// Prefer using a cover image with the name "cover" otherwise use the first image