New data model fix scan for creating series/authors and mapping ebooks

This commit is contained in:
advplyr 2022-03-13 13:47:36 -05:00
parent ea9ec13845
commit 6597fca576
7 changed files with 134 additions and 50 deletions

View File

@ -3,7 +3,7 @@ const Logger = require('../Logger')
const LibraryFile = require('./files/LibraryFile') const LibraryFile = require('./files/LibraryFile')
const Book = require('./entities/Book') const Book = require('./entities/Book')
const Podcast = require('./entities/Podcast') const Podcast = require('./entities/Podcast')
const { areEquivalent, copyValue } = require('../utils/index') const { areEquivalent, copyValue, getId } = require('../utils/index')
class LibraryItem { class LibraryItem {
constructor(libraryItem = null) { constructor(libraryItem = null) {
@ -149,6 +149,7 @@ class LibraryItem {
// Data comes from scandir library item data // Data comes from scandir library item data
setData(libraryMediaType, payload) { setData(libraryMediaType, payload) {
this.id = getId('li')
if (libraryMediaType === 'podcast') { if (libraryMediaType === 'podcast') {
this.mediaType = 'podcast' this.mediaType = 'podcast'
this.media = new Podcast() this.media = new Podcast()
@ -319,7 +320,6 @@ class LibraryItem {
dataFound.libraryFiles.forEach((lf) => { dataFound.libraryFiles.forEach((lf) => {
var fileFoundCheck = this.checkFileFound(lf, true) var fileFoundCheck = this.checkFileFound(lf, true)
console.log('Check library file', fileFoundCheck, lf.metadata.filename)
if (fileFoundCheck === null) { if (fileFoundCheck === null) {
newLibraryFiles.push(lf) newLibraryFiles.push(lf)
} else if (fileFoundCheck) { } else if (fileFoundCheck) {
@ -381,21 +381,47 @@ class LibraryItem {
} }
} }
findLibraryFileWithIno(inode) {
return this.libraryFiles.find(lf => lf.ino === inode)
}
// Set metadata from files // Set metadata from files
async syncFiles(preferOpfMetadata) { async syncFiles(preferOpfMetadata) {
var hasUpdated = false
if (this.mediaType === 'book') {
// Add/update ebook files (ebooks that were removed are removed in checkScanData)
this.libraryFiles.forEach((lf) => {
if (lf.fileType === 'ebook') {
var existingFile = this.media.findFileWithInode(lf.ino)
if (!existingFile) {
this.media.addEbookFile(lf)
hasUpdated = true
} else if (existingFile.ebookFormat) {
if (existingFile.updateFromLibraryFile(lf)) {// EBookFile.js
hasUpdated = true
}
}
}
})
}
// Set cover image if not set
var imageFiles = this.libraryFiles.filter(lf => lf.fileType === 'image') var imageFiles = this.libraryFiles.filter(lf => lf.fileType === 'image')
console.log('image files', imageFiles.length, 'has cover', this.media.coverPath)
if (imageFiles.length && !this.media.coverPath) { if (imageFiles.length && !this.media.coverPath) {
this.media.coverPath = imageFiles[0].metadata.path this.media.coverPath = imageFiles[0].metadata.path
Logger.debug('[LibraryItem] Set media cover path', this.media.coverPath) Logger.debug('[LibraryItem] Set media cover path', this.media.coverPath)
hasUpdated = true
} }
// Parse metadata files
var textMetadataFiles = this.libraryFiles.filter(lf => lf.fileType === 'metadata' || lf.fileType === 'text') var textMetadataFiles = this.libraryFiles.filter(lf => lf.fileType === 'metadata' || lf.fileType === 'text')
if (!textMetadataFiles.length) { if (textMetadataFiles.length) {
return false if (await this.media.syncMetadataFiles(textMetadataFiles, preferOpfMetadata)) {
hasUpdated = true
}
} }
var hasUpdated = await this.media.syncMetadataFiles(textMetadataFiles, preferOpfMetadata)
if (hasUpdated) { if (hasUpdated) {
this.updatedAt = Date.now() this.updatedAt = Date.now()
} }

View File

@ -341,5 +341,11 @@ class Book {
} }
return payload return payload
} }
addEbookFile(libraryFile) {
var newEbook = new EBookFile()
newEbook.setData(libraryFile)
this.ebookFiles.push(newEbook)
}
} }
module.exports = Book module.exports = Book

View File

@ -30,5 +30,28 @@ class EBookFile {
updatedAt: this.updatedAt updatedAt: this.updatedAt
} }
} }
setData(libraryFile) {
this.ino = libraryFile.ino
this.metadata = libraryFile.metadata.clone()
this.ebookFormat = libraryFile.metadata.format
this.addedAt = Date.now()
this.updatedAt = Date.now()
}
updateFromLibraryFile(libraryFile) {
var hasUpdated = false
if (this.metadata.update(libraryFile.metadata)) {
hasUpdated = true
}
if (this.ebookFormat !== libraryFile.metadata.format) {
this.ebookFormat = libraryFile.metadata.format
hasUpdated = true
}
return hasUpdated
}
} }
module.exports = EBookFile module.exports = EBookFile

View File

@ -247,7 +247,7 @@ class BookMetadata {
parseAuthorsTag(authorsTag) { parseAuthorsTag(authorsTag) {
var parsed = parseNameString(authorsTag) var parsed = parseNameString(authorsTag)
if (!parsed) return [] if (!parsed) return []
return parsed.map((au) => { return (parsed.names || []).map((au) => {
return { return {
id: `new-${Math.floor(Math.random() * 1000000)}`, id: `new-${Math.floor(Math.random() * 1000000)}`,
name: au name: au

View File

@ -185,7 +185,7 @@ class AudioFileScanner {
var totalAudioFilesToInclude = audioScanResult.audioFiles.length var totalAudioFilesToInclude = audioScanResult.audioFiles.length
var newAudioFiles = audioScanResult.audioFiles.filter(af => { var newAudioFiles = audioScanResult.audioFiles.filter(af => {
return !libraryItem.libraryFiles.find(lf => lf.ino === af.ino) return !libraryItem.media.findFileWithInode(af.ino)
}) })
// Adding audio files to book media // Adding audio files to book media

View File

@ -354,6 +354,9 @@ class Scanner {
} }
} }
// Temp authors & series are inserted - create them if found
await this.createNewAuthorsAndSeries(libraryItem)
if (!libraryItem.media.hasMediaFiles) { // Library item is invalid if (!libraryItem.media.hasMediaFiles) { // Library item is invalid
libraryItem.setInvalid() libraryItem.setInvalid()
hasUpdated = true hasUpdated = true
@ -407,11 +410,20 @@ class Scanner {
libraryItem.media.updateLastCoverSearch(updatedCover) libraryItem.media.updateLastCoverSearch(updatedCover)
} }
// Temp authors & series are inserted - create them if found
await this.createNewAuthorsAndSeries(libraryItem)
}
return libraryItem
}
async createNewAuthorsAndSeries(libraryItem) {
// Create or match all new authors and series // Create or match all new authors and series
if (libraryItem.media.metadata.authors.some(au => au.id.startsWith('new'))) { if (libraryItem.media.metadata.authors.some(au => au.id.startsWith('new'))) {
var newAuthors = [] var newAuthors = []
libraryItem.media.metadata.authors = libraryItem.media.metadata.authors.map((tempMinAuthor) => { libraryItem.media.metadata.authors = libraryItem.media.metadata.authors.map((tempMinAuthor) => {
var _author = this.db.authors.find(au => au.checkNameEquals(tempMinAuthor.name)) var _author = this.db.authors.find(au => au.checkNameEquals(tempMinAuthor.name))
if (!_author) _author = newAuthors.find(au => au.checkNameEquals(tempMinAuthor.name)) // Check new unsaved authors
if (!_author) { if (!_author) {
_author = new Author() _author = new Author()
_author.setData(tempMinAuthor) _author.setData(tempMinAuthor)
@ -431,6 +443,7 @@ class Scanner {
var newSeries = [] var newSeries = []
libraryItem.media.metadata.series = libraryItem.media.metadata.series.map((tempMinSeries) => { libraryItem.media.metadata.series = libraryItem.media.metadata.series.map((tempMinSeries) => {
var _series = this.db.series.find(se => se.checkNameEquals(tempMinSeries.name)) var _series = this.db.series.find(se => se.checkNameEquals(tempMinSeries.name))
if (!_series) _series = newSeries.find(se => se.checkNameEquals(tempMinSeries.name)) // Check new unsaved series
if (!_series) { if (!_series) {
_series = new Series() _series = new Series()
_series.setData(tempMinSeries) _series.setData(tempMinSeries)
@ -449,9 +462,6 @@ class Scanner {
} }
} }
return libraryItem
}
getFileUpdatesGrouped(fileUpdates) { getFileUpdatesGrouped(fileUpdates) {
var folderGroups = {} var folderGroups = {}
fileUpdates.forEach((file) => { fileUpdates.forEach((file) => {
@ -529,7 +539,6 @@ class Scanner {
// Check if book dir group is already an item // Check if book dir group is already an item
var existingLibraryItem = this.db.libraryItems.find(li => fullPath.startsWith(li.path)) var existingLibraryItem = this.db.libraryItems.find(li => fullPath.startsWith(li.path))
if (existingLibraryItem) { if (existingLibraryItem) {
// Is the item exactly - check if was deleted // Is the item exactly - check if was deleted
if (existingLibraryItem.path === fullPath) { if (existingLibraryItem.path === fullPath) {
var exists = await fs.pathExists(fullPath) var exists = await fs.pathExists(fullPath)

View File

@ -18,7 +18,9 @@ const FileMetadata = require('../objects/metadata/FileMetadata')
const AudioMetaTags = require('../objects/metadata/AudioMetaTags') const AudioMetaTags = require('../objects/metadata/AudioMetaTags')
var authorsToAdd = [] var authorsToAdd = []
var existingDbAuthors = []
var seriesToAdd = [] var seriesToAdd = []
var existingDbSeries = []
// Load old audiobooks // Load old audiobooks
async function loadAudiobooks() { async function loadAudiobooks() {
@ -41,6 +43,10 @@ function makeAuthorsFromOldAb(authorsList) {
if (existingAuthor) { if (existingAuthor) {
return existingAuthor.toJSONMinimal() return existingAuthor.toJSONMinimal()
} }
var existingDbAuthor = existingDbAuthors.find(a => a.name.toLowerCase() === authorName.toLowerCase())
if (existingDbAuthor) {
return existingDbAuthor.toJSONMinimal()
}
var newAuthor = new Author() var newAuthor = new Author()
newAuthor.setData({ name: authorName }) newAuthor.setData({ name: authorName })
@ -55,6 +61,10 @@ function makeSeriesFromOldAb({ series, volumeNumber }) {
if (existingSeries) { if (existingSeries) {
return [existingSeries.toJSONMinimal(volumeNumber)] return [existingSeries.toJSONMinimal(volumeNumber)]
} }
var existingDbSeriesItem = existingDbSeries.find(s => s.name.toLowerCase() === series.toLowerCase())
if (existingDbSeriesItem) {
return [existingDbSeriesItem.toJSONMinimal(volumeNumber)]
}
var newSeries = new Series() var newSeries = new Series()
newSeries.setData({ name: series }) newSeries.setData({ name: series })
seriesToAdd.push(newSeries) seriesToAdd.push(newSeries)
@ -190,6 +200,13 @@ async function migrateDb(db) {
return return
} }
if (db.authors && db.authors.length) {
existingDbAuthors = db.authors
}
if (db.series && db.series.length) {
existingDbSeries = db.series
}
var libraryItems = audiobooks.map((ab) => makeLibraryItemFromOldAb(ab)) var libraryItems = audiobooks.map((ab) => makeLibraryItemFromOldAb(ab))
Logger.info(`>>> ${libraryItems.length} Library Items made`) Logger.info(`>>> ${libraryItems.length} Library Items made`)
@ -202,7 +219,10 @@ async function migrateDb(db) {
Logger.info(`>>> ${seriesToAdd.length} Series made`) Logger.info(`>>> ${seriesToAdd.length} Series made`)
await db.insertEntities('series', seriesToAdd) await db.insertEntities('series', seriesToAdd)
} }
existingDbSeries = []
existingDbAuthors = []
authorsToAdd = []
seriesToAdd = []
Logger.info(`==== DB Migration Complete ====`) Logger.info(`==== DB Migration Complete ====`)
} }
module.exports = migrateDb module.exports = migrateDb