Updates to metadata file format changing, use chapters from metadata file

This commit is contained in:
advplyr 2023-05-16 18:58:01 -05:00
parent 81d4ac3ed2
commit 3c406c12b4
6 changed files with 93 additions and 23 deletions

View File

@ -45,7 +45,7 @@
</div>
<div class="w-44 mb-2">
<ui-dropdown v-model="newServerSettings.metadataFileFormat" small :items="metadataFileFormats" label="Metadata File Format" @input="(val) => updateSettingsKey('metadataFileFormat', val)" :disabled="updatingServerSettings" />
<ui-dropdown v-model="newServerSettings.metadataFileFormat" small :items="metadataFileFormats" label="Metadata File Format" @input="updateMetadataFileFormat" :disabled="updatingServerSettings" />
</div>
<div class="pt-4">
@ -355,6 +355,10 @@ export default {
updateServerLanguage(val) {
this.updateSettingsKey('language', val)
},
updateMetadataFileFormat(val) {
if (this.serverSettings.metadataFileFormat === val) return
this.updateSettingsKey('metadataFileFormat', val)
},
updateSettingsKey(key, val) {
this.updateServerSettings({
[key]: val
@ -364,8 +368,7 @@ export default {
this.updatingServerSettings = true
this.$store
.dispatch('updateServerSettings', payload)
.then((success) => {
console.log('Updated Server Settings', success)
.then(() => {
this.updatingServerSettings = false
this.$toast.success('Server settings updated')

View File

@ -9,6 +9,7 @@ const Podcast = require('./mediaTypes/Podcast')
const Video = require('./mediaTypes/Video')
const Music = require('./mediaTypes/Music')
const { areEquivalent, copyValue, getId, cleanStringForSearch } = require('../utils/index')
const { filePathToPOSIX } = require('../utils/fileUtils')
class LibraryItem {
constructor(libraryItem = null) {
@ -368,7 +369,7 @@ class LibraryItem {
const fileFoundCheck = this.checkFileFound(lf, true)
if (fileFoundCheck === null) {
newLibraryFiles.push(lf)
} else if (fileFoundCheck && lf.metadata.format !== 'abs') { // Ignore abs file updates
} else if (fileFoundCheck && lf.metadata.format !== 'abs' && lf.metadata.filename !== 'metadata.json') { // Ignore abs file updates
hasUpdated = true
existingLibraryFiles.push(lf)
} else {
@ -502,17 +503,26 @@ class LibraryItem {
const metadataFileFormat = global.ServerSettings.metadataFileFormat
const metadataFilePath = Path.join(metadataPath, `metadata.${metadataFileFormat}`)
if (metadataFileFormat === 'json') {
// Remove metadata.abs if it exists
if (await fs.pathExists(Path.join(metadataPath, `metadata.abs`))) {
Logger.debug(`[LibraryItem] Removing metadata.abs for item "${this.media.metadata.title}"`)
await fs.remove(Path.join(metadataPath, `metadata.abs`))
this.libraryFiles = this.libraryFiles.filter(lf => lf.metadata.path !== filePathToPOSIX(Path.join(metadataPath, `metadata.abs`)))
}
return fs.writeFile(metadataFilePath, JSON.stringify(this.media.toJSONForMetadataFile(), null, 2)).then(() => {
return fs.writeFile(metadataFilePath, JSON.stringify(this.media.toJSONForMetadataFile(), null, 2)).then(async () => {
this.isSavingMetadata = false
// Add metadata.json to libraryFiles array if it is new
if (global.ServerSettings.storeMetadataWithItem && !this.libraryFiles.some(lf => lf.metadata.path === filePathToPOSIX(metadataFilePath))) {
const newLibraryFile = new LibraryFile()
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.json`)
this.libraryFiles.push(newLibraryFile)
}
return true
}).catch((error) => {
this.isSavingMetadata = false
Logger.error(`[LibraryItem] Failed to save json file at "${metadataFilePath}"`, error)
return false
})
@ -521,12 +531,22 @@ class LibraryItem {
if (await fs.pathExists(Path.join(metadataPath, `metadata.json`))) {
Logger.debug(`[LibraryItem] Removing metadata.json for item "${this.media.metadata.title}"`)
await fs.remove(Path.join(metadataPath, `metadata.json`))
this.libraryFiles = this.libraryFiles.filter(lf => lf.metadata.path !== filePathToPOSIX(Path.join(metadataPath, `metadata.json`)))
}
return abmetadataGenerator.generate(this, metadataFilePath).then((success) => {
return abmetadataGenerator.generate(this, metadataFilePath).then(async (success) => {
this.isSavingMetadata = false
if (!success) Logger.error(`[LibraryItem] Failed saving abmetadata to "${metadataFilePath}"`)
else Logger.debug(`[LibraryItem] Success saving abmetadata to "${metadataFilePath}"`)
else {
// Add metadata.abs to libraryFiles array if it is new
if (global.ServerSettings.storeMetadataWithItem && !this.libraryFiles.some(lf => lf.metadata.path === filePathToPOSIX(metadataFilePath))) {
const newLibraryFile = new LibraryFile()
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.abs`)
this.libraryFiles.push(newLibraryFile)
}
Logger.debug(`[LibraryItem] Success saving abmetadata to "${metadataFilePath}"`)
}
return success
})
}

View File

@ -1,5 +1,5 @@
const Path = require('path')
const { getFileTimestampsWithIno } = require('../../utils/fileUtils')
const { getFileTimestampsWithIno, filePathToPOSIX } = require('../../utils/fileUtils')
const globals = require('../../utils/globals')
const FileMetadata = require('../metadata/FileMetadata')
@ -59,8 +59,8 @@ class LibraryFile {
var fileMetadata = new FileMetadata()
fileMetadata.setData(fileTsData)
fileMetadata.filename = Path.basename(relPath)
fileMetadata.path = path
fileMetadata.relPath = relPath
fileMetadata.path = filePathToPOSIX(path)
fileMetadata.relPath = filePathToPOSIX(relPath)
fileMetadata.ext = Path.extname(relPath)
this.ino = fileTsData.ino
this.metadata = fileMetadata

View File

@ -237,7 +237,7 @@ class Book {
// Look for desc.txt, reader.txt, metadata.abs and opf file then update details if found
async syncMetadataFiles(textMetadataFiles, opfMetadataOverrideDetails) {
let metadataUpdatePayload = {}
let tagsUpdated = false
let hasUpdated = false
const descTxt = textMetadataFiles.find(lf => lf.metadata.filename === 'desc.txt')
if (descTxt) {
@ -256,18 +256,25 @@ class Book {
}
}
const metadataAbs = textMetadataFiles.find(lf => lf.metadata.filename === 'metadata.abs' || lf.metadata.filename === 'metadata.json')
if (metadataAbs) {
const isJSON = metadataAbs.metadata.filename === 'metadata.json'
Logger.debug(`[Book] Found ${metadataAbs.metadata.filename} file for "${this.metadata.title}"`)
const metadataText = await readTextFile(metadataAbs.metadata.path)
const abmetadataUpdates = abmetadataGenerator.parseAndCheckForUpdates(metadataText, this, 'book', isJSON)
const metadataIsJSON = global.ServerSettings.metadataFileFormat === 'json'
const metadataAbs = textMetadataFiles.find(lf => lf.metadata.filename === 'metadata.abs')
const metadataJson = textMetadataFiles.find(lf => lf.metadata.filename === 'metadata.json')
const metadataFile = metadataIsJSON ? metadataJson : metadataAbs
if (metadataFile) {
Logger.debug(`[Book] Found ${metadataFile.metadata.filename} file for "${this.metadata.title}"`)
const metadataText = await readTextFile(metadataFile.metadata.path)
const abmetadataUpdates = abmetadataGenerator.parseAndCheckForUpdates(metadataText, this, 'book', metadataIsJSON)
if (abmetadataUpdates && Object.keys(abmetadataUpdates).length) {
Logger.debug(`[Book] "${this.metadata.title}" changes found in metadata.abs file`, abmetadataUpdates)
if (abmetadataUpdates.tags) { // Set media tags if updated
this.tags = abmetadataUpdates.tags
tagsUpdated = true
hasUpdated = true
}
if (abmetadataUpdates.chapters) { // Set chapters if updated
this.chapters = abmetadataUpdates.chapters
hasUpdated = true
}
if (abmetadataUpdates.metadata) {
metadataUpdatePayload = {
@ -276,6 +283,9 @@ class Book {
}
}
}
} else if (metadataAbs || metadataJson) { // Has different metadata file format so mark as updated
Logger.debug(`[Book] Found different format metadata file ${(metadataAbs || metadataJson).metadata.filename}, expecting .${global.ServerSettings.metadataFileFormat} for "${this.metadata.title}"`)
hasUpdated = true
}
const metadataOpf = textMetadataFiles.find(lf => lf.isOPFFile || lf.metadata.filename === 'metadata.xml')
@ -289,7 +299,7 @@ class Book {
if (key === 'tags') { // Add tags only if tags are empty
if (opfMetadata.tags.length && (!this.tags.length || opfMetadataOverrideDetails)) {
this.tags = opfMetadata.tags
tagsUpdated = true
hasUpdated = true
}
} else if (key === 'genres') { // Add genres only if genres are empty
if (opfMetadata.genres.length && (!this.metadata.genres.length || opfMetadataOverrideDetails)) {
@ -321,9 +331,9 @@ class Book {
}
if (Object.keys(metadataUpdatePayload).length) {
return this.metadata.update(metadataUpdatePayload) || tagsUpdated
return this.metadata.update(metadataUpdatePayload) || hasUpdated
}
return tagsUpdated
return hasUpdated
}
searchQuery(query) {

View File

@ -111,8 +111,8 @@ class Scanner {
}
if (hasUpdated) {
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
await this.db.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
return ScanResult.UPDATED
}
return ScanResult.UPTODATE

View File

@ -3,6 +3,7 @@ const filePerms = require('./filePerms')
const package = require('../../package.json')
const Logger = require('../Logger')
const { getId } = require('./index')
const areEquivalent = require('../utils/areEquivalent')
const CurrentAbMetadataVersion = 2
@ -424,6 +425,33 @@ function parseJsonMetadataText(text) {
}
}
function cleanChaptersArray(chaptersArray, mediaTitle) {
const chapters = []
let index = 0
for (const chap of chaptersArray) {
if (chap.start === null || isNaN(chap.start)) {
Logger.error(`[abmetadataGenerator] Invalid chapter start time ${chap.start} for "${mediaTitle}" metadata file`)
return null
}
if (chap.end === null || isNaN(chap.end)) {
Logger.error(`[abmetadataGenerator] Invalid chapter end time ${chap.end} for "${mediaTitle}" metadata file`)
return null
}
if (!chap.title || typeof chap.title !== 'string') {
Logger.error(`[abmetadataGenerator] Invalid chapter title ${chap.title} for "${mediaTitle}" metadata file`)
return null
}
chapters.push({
id: index++,
start: chap.start,
end: chap.end,
title: chap.title
})
}
return chapters
}
// Input text from abmetadata file and return object of media changes
// only returns object of changes. empty object means no changes
function parseAndCheckForUpdates(text, media, mediaType, isJSON) {
@ -477,6 +505,15 @@ function parseAndCheckForUpdates(text, media, mediaType, isJSON) {
}
}
if (abmetadataData.chapters && mediaType === 'book') {
const abmetadataChaptersCleaned = cleanChaptersArray(abmetadataData.chapters)
if (abmetadataChaptersCleaned) {
if (!areEquivalent(abmetadataChaptersCleaned, media.chapters)) {
updatePayload.chapters = abmetadataChaptersCleaned
}
}
}
if (Object.keys(metadataUpdatePayload).length) {
updatePayload.metadata = metadataUpdatePayload
}