mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-03 00:06:46 +01:00
Fix LibraryItem and Media file update logic for library scans
This commit is contained in:
parent
88f9533b37
commit
9511122bae
@ -20,6 +20,7 @@ const LibraryScan = require("./LibraryScan")
|
|||||||
const OpfFileScanner = require('./OpfFileScanner')
|
const OpfFileScanner = require('./OpfFileScanner')
|
||||||
const NfoFileScanner = require('./NfoFileScanner')
|
const NfoFileScanner = require('./NfoFileScanner')
|
||||||
const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
|
const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
|
||||||
|
const EBookFile = require("../objects/files/EBookFile")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata for books pulled from files
|
* Metadata for books pulled from files
|
||||||
@ -84,7 +85,7 @@ class BookScanner {
|
|||||||
|
|
||||||
// Update audio files that were modified
|
// Update audio files that were modified
|
||||||
if (libraryItemData.audioLibraryFilesModified.length) {
|
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) => {
|
media.audioFiles = media.audioFiles.map((audioFileObj) => {
|
||||||
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === audioFileObj.metadata.path)
|
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === audioFileObj.metadata.path)
|
||||||
if (!matchedScannedAudioFile) {
|
if (!matchedScannedAudioFile) {
|
||||||
@ -138,11 +139,25 @@ class BookScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if cover was removed
|
// 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
|
media.coverPath = null
|
||||||
hasMediaChanges = true
|
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
|
// Check if cover is not set and image files were found
|
||||||
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
||||||
// Prefer using a cover image with the name "cover" otherwise use the first image
|
// Prefer using a cover image with the name "cover" otherwise use the first image
|
||||||
@ -157,6 +172,19 @@ class BookScanner {
|
|||||||
hasMediaChanges = true
|
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
|
// Check if ebook is not set and ebooks were found
|
||||||
if (!media.ebookFile && !librarySettings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
|
if (!media.ebookFile && !librarySettings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
|
||||||
// Prefer to use an epub ebook then fallback to the first ebook found
|
// Prefer to use an epub ebook then fallback to the first ebook found
|
||||||
|
@ -4,6 +4,12 @@ const LibraryItem = require('../models/LibraryItem')
|
|||||||
const globals = require('../utils/globals')
|
const globals = require('../utils/globals')
|
||||||
|
|
||||||
class LibraryItemScanData {
|
class LibraryItemScanData {
|
||||||
|
/**
|
||||||
|
* @typedef LibraryFileModifiedObject
|
||||||
|
* @property {LibraryItem.LibraryFileObject} old
|
||||||
|
* @property {LibraryItem.LibraryFileObject} new
|
||||||
|
*/
|
||||||
|
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
this.libraryFolderId = data.libraryFolderId
|
this.libraryFolderId = data.libraryFolderId
|
||||||
@ -39,7 +45,7 @@ class LibraryItemScanData {
|
|||||||
this.libraryFilesRemoved = []
|
this.libraryFilesRemoved = []
|
||||||
/** @type {LibraryItem.LibraryFileObject[]} */
|
/** @type {LibraryItem.LibraryFileObject[]} */
|
||||||
this.libraryFilesAdded = []
|
this.libraryFilesAdded = []
|
||||||
/** @type {LibraryItem.LibraryFileObject[]} */
|
/** @type {LibraryFileModifiedObject[]} */
|
||||||
this.libraryFilesModified = []
|
this.libraryFilesModified = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,9 +83,9 @@ class LibraryItemScanData {
|
|||||||
return (this.audioLibraryFilesRemoved.length + this.audioLibraryFilesAdded.length + this.audioLibraryFilesModified.length) > 0
|
return (this.audioLibraryFilesRemoved.length + this.audioLibraryFilesAdded.length + this.audioLibraryFilesModified.length) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {LibraryItem.LibraryFileObject[]} */
|
/** @type {LibraryFileModifiedObject[]} */
|
||||||
get audioLibraryFilesModified() {
|
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[]} */
|
/** @type {LibraryItem.LibraryFileObject[]} */
|
||||||
@ -97,12 +103,42 @@ class LibraryItemScanData {
|
|||||||
return this.libraryFiles.filter(lf => globals.SupportedAudioTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
|
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[]} */
|
/** @type {LibraryItem.LibraryFileObject[]} */
|
||||||
get imageLibraryFiles() {
|
get imageLibraryFiles() {
|
||||||
return this.libraryFiles.filter(lf => globals.SupportedImageTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
|
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() {
|
get ebookLibraryFiles() {
|
||||||
return this.libraryFiles.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
|
return this.libraryFiles.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
|
||||||
}
|
}
|
||||||
@ -153,7 +189,7 @@ class LibraryItemScanData {
|
|||||||
existingLibraryItem[key] = this[key]
|
existingLibraryItem[key] = this[key]
|
||||||
this.hasChanges = true
|
this.hasChanges = true
|
||||||
|
|
||||||
if (key === 'relPath') {
|
if (key === 'relPath' || key === 'path') {
|
||||||
this.hasPathChange = true
|
this.hasPathChange = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,8 +238,9 @@ class LibraryItemScanData {
|
|||||||
this.hasChanges = true
|
this.hasChanges = true
|
||||||
} else {
|
} else {
|
||||||
libraryFilesAdded = libraryFilesAdded.filter(lf => lf !== matchingLibraryFile)
|
libraryFilesAdded = libraryFilesAdded.filter(lf => lf !== matchingLibraryFile)
|
||||||
|
let existingLibraryFileBefore = structuredClone(existingLibraryFile)
|
||||||
if (this.compareUpdateLibraryFile(existingLibraryItem.path, existingLibraryFile, matchingLibraryFile, libraryScan)) {
|
if (this.compareUpdateLibraryFile(existingLibraryItem.path, existingLibraryFile, matchingLibraryFile, libraryScan)) {
|
||||||
this.libraryFilesModified.push(existingLibraryFile)
|
this.libraryFilesModified.push({old: existingLibraryFileBefore, new: existingLibraryFile})
|
||||||
this.hasChanges = true
|
this.hasChanges = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ class PodcastScanner {
|
|||||||
|
|
||||||
// Update audio files that were modified
|
// Update audio files that were modified
|
||||||
if (libraryItemData.audioLibraryFilesModified.length) {
|
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) {
|
for (const podcastEpisode of existingPodcastEpisodes) {
|
||||||
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === podcastEpisode.audioFile.metadata.path)
|
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === podcastEpisode.audioFile.metadata.path)
|
||||||
@ -132,11 +132,25 @@ class PodcastScanner {
|
|||||||
let hasMediaChanges = false
|
let hasMediaChanges = false
|
||||||
|
|
||||||
// Check if cover was removed
|
// 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
|
media.coverPath = null
|
||||||
hasMediaChanges = true
|
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
|
// Check if cover is not set and image files were found
|
||||||
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
||||||
// Prefer using a cover image with the name "cover" otherwise use the first image
|
// Prefer using a cover image with the name "cover" otherwise use the first image
|
||||||
|
Loading…
Reference in New Issue
Block a user