audiobookshelf/server/utils/parsers/parseComicMetadata.js
2024-09-18 14:26:10 -05:00

92 lines
2.9 KiB
JavaScript

const Path = require('path')
const Logger = require('../../Logger')
const parseComicInfoMetadata = require('./parseComicInfoMetadata')
const globals = require('../globals')
const { xmlToJSON } = require('../index')
const { createComicBookExtractor } = require('../comicBookExtractors.js')
/**
* Extract cover image from comic return true if success
*
* @param {string} comicPath
* @param {string} comicImageFilepath
* @param {string} outputCoverPath
* @returns {Promise<boolean>}
*/
async function extractCoverImage(comicPath, comicImageFilepath, outputCoverPath) {
let archive = null
try {
archive = createComicBookExtractor(comicPath)
await archive.open()
return await archive.extractToFile(comicImageFilepath, outputCoverPath)
} catch (error) {
Logger.error(`[parseComicMetadata] Failed to extract image "${comicImageFilepath}" from comicPath "${comicPath}" into "${outputCoverPath}"`, error)
return false
} finally {
// Ensure we free the memory
archive?.close()
}
}
module.exports.extractCoverImage = extractCoverImage
/**
* Parse metadata from comic
*
* @param {import('../../models/Book').EBookFileObject} ebookFile
* @returns {Promise<import('./parseEbookMetadata').EBookFileScanData>}
*/
async function parse(ebookFile) {
const comicPath = ebookFile.metadata.path
Logger.debug(`[parseComicMetadata] Parsing comic metadata at "${comicPath}"`)
let archive = null
try {
archive = createComicBookExtractor(comicPath)
await archive.open()
const filePaths = await archive.getFilePaths()
// Sort the file paths in a natural order to get the first image
filePaths.sort((a, b) => {
return a.localeCompare(b, undefined, {
numeric: true,
sensitivity: 'base'
})
})
let metadata = null
const comicInfoPath = filePaths.find((filePath) => filePath === 'ComicInfo.xml')
if (comicInfoPath) {
const comicInfoData = await archive.extractToBuffer(comicInfoPath)
if (comicInfoData) {
const comicInfoStr = new TextDecoder().decode(comicInfoData)
const comicInfoJson = await xmlToJSON(comicInfoStr)
if (comicInfoJson) {
metadata = parseComicInfoMetadata.parse(comicInfoJson)
}
}
}
const payload = {
path: comicPath,
ebookFormat: ebookFile.ebookFormat,
metadata
}
const firstImagePath = filePaths.find((filePath) => globals.SupportedImageTypes.includes(Path.extname(filePath).toLowerCase().slice(1)))
if (firstImagePath) {
payload.ebookCoverPath = firstImagePath
} else {
Logger.warn(`[parseComicMetadata] Cover image not found in comic at "${comicPath}"`)
}
return payload
} catch (error) {
Logger.error(`[parseComicMetadata] Failed to parse comic metadata at "${comicPath}"`, error)
return null
} finally {
// Ensure we free the memory
archive?.close()
}
}
module.exports.parse = parse