const Path = require('path') const fsExtra = require('../libs/fsExtra') const { readTextFile } = require('../utils/fileUtils') const { LogLevel } = require('../utils/constants') const abmetadataGenerator = require('../utils/generators/abmetadataGenerator') class AbsMetadataFileScanner { constructor() { } /** * Check for metadata.json or metadata.abs file and set book metadata * * @param {import('./LibraryScan')} libraryScan * @param {import('./LibraryItemScanData')} libraryItemData * @param {Object} bookMetadata * @param {string} [existingLibraryItemId] */ async scanBookMetadataFile(libraryScan, libraryItemData, bookMetadata, existingLibraryItemId = null) { const metadataLibraryFile = libraryItemData.metadataJsonLibraryFile || libraryItemData.metadataAbsLibraryFile let metadataText = metadataLibraryFile ? await readTextFile(metadataLibraryFile.metadata.path) : null let metadataFilePath = metadataLibraryFile?.metadata.path let metadataFileFormat = libraryItemData.metadataJsonLibraryFile ? 'json' : 'abs' // When metadata file is not stored with library item then check in the /metadata/items folder for it if (!metadataText && existingLibraryItemId) { let metadataPath = Path.join(global.MetadataPath, 'items', existingLibraryItemId) let altFormat = global.ServerSettings.metadataFileFormat === 'json' ? 'abs' : 'json' // First check the metadata format set in server settings, fallback to the alternate metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`) metadataFileFormat = global.ServerSettings.metadataFileFormat if (await fsExtra.pathExists(metadataFilePath)) { metadataText = await readTextFile(metadataFilePath) } else if (await fsExtra.pathExists(Path.join(metadataPath, `metadata.${altFormat}`))) { metadataFilePath = Path.join(metadataPath, `metadata.${altFormat}`) metadataFileFormat = altFormat metadataText = await readTextFile(metadataFilePath) } } if (metadataText) { libraryScan.addLog(LogLevel.INFO, `Found metadata file "${metadataFilePath}" - preferring`) let abMetadata = null if (metadataFileFormat === 'json') { abMetadata = abmetadataGenerator.parseJson(metadataText) } else { abMetadata = abmetadataGenerator.parse(metadataText, 'book') } if (abMetadata) { if (abMetadata.tags?.length) { bookMetadata.tags = abMetadata.tags } if (abMetadata.chapters?.length) { bookMetadata.chapters = abMetadata.chapters } for (const key in abMetadata.metadata) { if (abMetadata.metadata[key] === undefined || abMetadata.metadata[key] === null) continue bookMetadata[key] = abMetadata.metadata[key] } } } } /** * Check for metadata.json or metadata.abs file and set podcast metadata * * @param {import('./LibraryScan')} libraryScan * @param {import('./LibraryItemScanData')} libraryItemData * @param {Object} podcastMetadata * @param {string} [existingLibraryItemId] */ async scanPodcastMetadataFile(libraryScan, libraryItemData, podcastMetadata, existingLibraryItemId = null) { const metadataLibraryFile = libraryItemData.metadataJsonLibraryFile || libraryItemData.metadataAbsLibraryFile let metadataText = metadataLibraryFile ? await readTextFile(metadataLibraryFile.metadata.path) : null let metadataFilePath = metadataLibraryFile?.metadata.path let metadataFileFormat = libraryItemData.metadataJsonLibraryFile ? 'json' : 'abs' // When metadata file is not stored with library item then check in the /metadata/items folder for it if (!metadataText && existingLibraryItemId) { let metadataPath = Path.join(global.MetadataPath, 'items', existingLibraryItemId) let altFormat = global.ServerSettings.metadataFileFormat === 'json' ? 'abs' : 'json' // First check the metadata format set in server settings, fallback to the alternate metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`) metadataFileFormat = global.ServerSettings.metadataFileFormat if (await fsExtra.pathExists(metadataFilePath)) { metadataText = await readTextFile(metadataFilePath) } else if (await fsExtra.pathExists(Path.join(metadataPath, `metadata.${altFormat}`))) { metadataFilePath = Path.join(metadataPath, `metadata.${altFormat}`) metadataFileFormat = altFormat metadataText = await readTextFile(metadataFilePath) } } if (metadataText) { libraryScan.addLog(LogLevel.INFO, `Found metadata file "${metadataFilePath}" - preferring`) let abMetadata = null if (metadataFileFormat === 'json') { abMetadata = abmetadataGenerator.parseJson(metadataText) } else { abMetadata = abmetadataGenerator.parse(metadataText, 'podcast') } if (abMetadata) { if (abMetadata.tags?.length) { podcastMetadata.tags = abMetadata.tags } for (const key in abMetadata.metadata) { if (abMetadata.metadata[key] === undefined) continue // TODO: New podcast model changed some keys, need to update the abmetadataGenerator let newModelKey = key if (key === 'feedUrl') newModelKey = 'feedURL' else if (key === 'imageUrl') newModelKey = 'imageURL' else if (key === 'itunesPageUrl') newModelKey = 'itunesPageURL' else if (key === 'type') newModelKey = 'podcastType' podcastMetadata[newModelKey] = abMetadata.metadata[key] } } } } } module.exports = new AbsMetadataFileScanner()