mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-08 00:08:14 +01:00
Update new library scanner to check for cover images and ebooks
This commit is contained in:
parent
2c8448d147
commit
f8f94f2a6d
@ -25,8 +25,11 @@ class Database {
|
||||
// Cached library filter data
|
||||
this.libraryFilterData = {}
|
||||
|
||||
/** @type {import('./objects/settings/ServerSettings')} */
|
||||
this.serverSettings = null
|
||||
/** @type {import('./objects/settings/NotificationSettings')} */
|
||||
this.notificationSettings = null
|
||||
/** @type {import('./objects/settings/EmailSettings')} */
|
||||
this.emailSettings = null
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,16 @@ class LibraryItemScanData {
|
||||
return this.libraryFiles.filter(lf => globals.SupportedAudioTypes.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 {LibraryItem.LibraryFileObject[]} */
|
||||
get ebookLibraryFiles() {
|
||||
return this.libraryFiles.filter(lf => globals.SupportedEbookTypes.includes(lf.metadata.ext?.slice(1).toLowerCase() || ''))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {LibraryItem} existingLibraryItem
|
||||
@ -124,7 +134,7 @@ class LibraryItemScanData {
|
||||
}
|
||||
|
||||
if (!matchingLibraryFile) { // Library file removed
|
||||
libraryScan.addLog(LogLevel.INFO, `Library file "${existingLibraryFile.metadata.path}" was removed from library item "${existingLibraryItem.path}"`)
|
||||
libraryScan.addLog(LogLevel.INFO, `Library file "${existingLibraryFile.metadata.path}" was removed from library item "${existingLibraryItem.relPath}"`)
|
||||
this.libraryFilesRemoved.push(existingLibraryFile)
|
||||
existingLibraryItem.libraryFiles = existingLibraryItem.libraryFiles.filter(lf => lf !== existingLibraryFile)
|
||||
this.hasChanges = true
|
||||
@ -141,7 +151,11 @@ class LibraryItemScanData {
|
||||
if (libraryFilesAdded.length) {
|
||||
this.hasChanges = true
|
||||
for (const libraryFile of libraryFilesAdded) {
|
||||
libraryScan.addLog(LogLevel.INFO, `New library file found with path "${libraryFile.metadata.path}" for library item "${existingLibraryItem.path}"`)
|
||||
libraryScan.addLog(LogLevel.INFO, `New library file found with path "${libraryFile.metadata.path}" for library item "${existingLibraryItem.relPath}"`)
|
||||
if (libraryFile.isEBookFile) {
|
||||
// Set all new ebook files as supplementary
|
||||
libraryFile.isSupplementary = true
|
||||
}
|
||||
existingLibraryItem.libraryFiles.push(libraryFile.toJSON())
|
||||
}
|
||||
}
|
||||
@ -155,14 +169,15 @@ class LibraryItemScanData {
|
||||
existingLibraryItem.lastScan = Date.now()
|
||||
existingLibraryItem.lastScanVersion = packageJson.version
|
||||
|
||||
libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.path}" changed: [${existingLibraryItem.changed()?.join(',') || ''}]`)
|
||||
libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" changed: [${existingLibraryItem.changed()?.join(',') || ''}]`)
|
||||
libraryScan.resultsUpdated++
|
||||
|
||||
if (this.hasLibraryFileChanges) {
|
||||
existingLibraryItem.changed('libraryFiles', true)
|
||||
}
|
||||
await existingLibraryItem.save()
|
||||
} else {
|
||||
libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.path}" is up-to-date`)
|
||||
libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" is up-to-date`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,5 +234,20 @@ class LibraryItemScanData {
|
||||
// Fallback to check inode value
|
||||
return this.audioLibraryFilesRemoved.some(af => af.ino === existingAudioFile.ino)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if existing ebook file on Book was removed
|
||||
* @param {import('../models/Book').EBookFileObject} ebookFile
|
||||
* @returns {boolean} true if ebook file was removed
|
||||
*/
|
||||
checkEbookFileRemoved(ebookFile) {
|
||||
if (!this.ebookLibraryFiles.length) return true
|
||||
|
||||
if (this.ebookLibraryFiles.some(lf => lf.metadata.path === ebookFile.metadata.path)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !this.ebookLibraryFiles.some(lf => lf.ino === ebookFile.ino)
|
||||
}
|
||||
}
|
||||
module.exports = LibraryItemScanData
|
@ -13,6 +13,7 @@ class LibraryScan {
|
||||
constructor() {
|
||||
this.id = null
|
||||
this.type = null
|
||||
/** @type {import('../objects/Library')} */
|
||||
this.library = null
|
||||
this.verbose = false
|
||||
|
||||
@ -117,7 +118,7 @@ class LibraryScan {
|
||||
}
|
||||
|
||||
if (this.verbose) {
|
||||
Logger.debug(`[LibraryScan] "${this.libraryName}":`, args)
|
||||
Logger.debug(`[LibraryScan] "${this.libraryName}":`, ...args)
|
||||
}
|
||||
this.logs.push(logObj)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ const fs = require('../libs/fsExtra')
|
||||
const fileUtils = require('../utils/fileUtils')
|
||||
const scanUtils = require('../utils/scandir')
|
||||
const { ScanResult, LogLevel } = require('../utils/constants')
|
||||
const globals = require('../utils/globals')
|
||||
const AudioFileScanner = require('./AudioFileScanner')
|
||||
const ScanOptions = require('./ScanOptions')
|
||||
const LibraryScan = require('./LibraryScan')
|
||||
@ -128,11 +129,13 @@ class LibraryScanner {
|
||||
libraryScan.addLog(LogLevel.INFO, `Library item "${existingLibraryItem.relPath}" folder exists but has no episodes`)
|
||||
} else {
|
||||
libraryScan.addLog(LogLevel.WARN, `Library Item "${existingLibraryItem.path}" (inode: ${existingLibraryItem.ino}) is missing`)
|
||||
libraryScan.resultsMissing++
|
||||
if (!existingLibraryItem.isMissing) {
|
||||
libraryItemIdsMissing.push(existingLibraryItem.id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
libraryItemDataFound = libraryItemDataFound.filter(lidf => lidf !== libraryItemData)
|
||||
await libraryItemData.checkLibraryItemData(existingLibraryItem, libraryScan)
|
||||
if (libraryItemData.hasLibraryFileChanges || libraryItemData.hasPathChange) {
|
||||
await this.rescanLibraryItem(existingLibraryItem, libraryItemData, libraryScan)
|
||||
@ -153,6 +156,11 @@ class LibraryScanner {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Add new library items
|
||||
if (libraryItemDataFound.length) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,7 +238,6 @@ class LibraryScanner {
|
||||
* @param {LibraryScan} libraryScan
|
||||
*/
|
||||
async rescanLibraryItem(existingLibraryItem, libraryItemData, libraryScan) {
|
||||
|
||||
if (existingLibraryItem.mediaType === 'book') {
|
||||
/** @type {Book} */
|
||||
const media = await existingLibraryItem.getMedia({
|
||||
@ -309,10 +316,77 @@ class LibraryScanner {
|
||||
media.changed('audioFiles', true)
|
||||
}
|
||||
|
||||
// Check if cover was removed
|
||||
if (media.coverPath && !libraryItemData.imageLibraryFiles.some(lf => lf.metadata.path === media.coverPath)) {
|
||||
media.coverPath = null
|
||||
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
|
||||
const coverMatch = libraryItemData.imageLibraryFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
||||
media.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
|
||||
hasMediaChanges = true
|
||||
}
|
||||
|
||||
// Check if ebook was removed
|
||||
if (media.ebookFile && (libraryScan.library.settings.audiobooksOnly || libraryItemData.checkEbookFileRemoved(media.ebookFile))) {
|
||||
media.ebookFile = null
|
||||
hasMediaChanges = true
|
||||
}
|
||||
|
||||
// Check if ebook is not set and ebooks were found
|
||||
if (!media.ebookFile && !libraryScan.library.settings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
|
||||
// Prefer to use an epub ebook then fallback to the first ebook found
|
||||
let ebookLibraryFile = libraryItemData.ebookLibraryFiles.find(lf => lf.metadata.ext.slice(1).toLowerCase() === 'epub')
|
||||
if (!ebookLibraryFile) ebookLibraryFile = libraryItemData.ebookLibraryFiles[0]
|
||||
// Ebook file is the same as library file except for additional `ebookFormat`
|
||||
ebookLibraryFile.ebookFormat = ebookLibraryFile.metadata.ext.slice(1).toLowerCase()
|
||||
media.ebookFile = ebookLibraryFile
|
||||
media.changed('ebookFile', true)
|
||||
hasMediaChanges = true
|
||||
}
|
||||
|
||||
// Check/update the isSupplementary flag on libraryFiles for the LibraryItem
|
||||
let libraryItemUpdated = false
|
||||
for (const libraryFile of existingLibraryItem.libraryFiles) {
|
||||
if (globals.SupportedEbookTypes.includes(libraryFile.metadata.ext.slice(1).toLowerCase())) {
|
||||
if (media.ebookFile && libraryFile.ino === media.ebookFile.ino) {
|
||||
if (libraryFile.isSupplementary !== false) {
|
||||
libraryFile.isSupplementary = false
|
||||
libraryItemUpdated = true
|
||||
}
|
||||
} else if (libraryFile.isSupplementary !== true) {
|
||||
libraryFile.isSupplementary = true
|
||||
libraryItemUpdated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (libraryItemUpdated) {
|
||||
existingLibraryItem.changed('libraryFiles', true)
|
||||
await existingLibraryItem.save()
|
||||
}
|
||||
|
||||
// TODO: Update chapters & metadata
|
||||
|
||||
if (hasMediaChanges) {
|
||||
await media.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {LibraryItemScanData} libraryItemData
|
||||
* @param {LibraryScan} libraryScan
|
||||
*/
|
||||
async scanNewLibraryItem(libraryItemData, libraryScan) {
|
||||
|
||||
if (libraryScan.libraryMediaType === 'book') {
|
||||
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(libraryScan.libraryMediaType, libraryItemData, libraryItemData.audioLibraryFiles)
|
||||
// TODO: Create new book
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = LibraryScanner
|
Loading…
Reference in New Issue
Block a user