mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			109 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const Path = require('path')
 | |
| const globals = require('../globals')
 | |
| const fs = require('../../libs/fsExtra')
 | |
| const Logger = require('../../Logger')
 | |
| const Archive = require('../../libs/libarchive/archive')
 | |
| const { xmlToJSON } = require('../index')
 | |
| const parseComicInfoMetadata = require('./parseComicInfoMetadata')
 | |
| 
 | |
| /**
 | |
|  * 
 | |
|  * @param {string} filepath 
 | |
|  * @returns {Promise<Buffer>}
 | |
|  */
 | |
| async function getComicFileBuffer(filepath) {
 | |
|   if (!await fs.pathExists(filepath)) {
 | |
|     Logger.error(`Comic path does not exist "${filepath}"`)
 | |
|     return null
 | |
|   }
 | |
|   try {
 | |
|     return fs.readFile(filepath)
 | |
|   } catch (error) {
 | |
|     Logger.error(`Failed to read comic at "${filepath}"`, error)
 | |
|     return null
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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) {
 | |
|   const comicFileBuffer = await getComicFileBuffer(comicPath)
 | |
|   if (!comicFileBuffer) return null
 | |
| 
 | |
|   const archive = await Archive.open(comicFileBuffer)
 | |
|   const fileEntry = await archive.extractSingleFile(comicImageFilepath)
 | |
| 
 | |
|   if (!fileEntry?.fileData) {
 | |
|     Logger.error(`[parseComicMetadata] Invalid file entry data for comicPath "${comicPath}"/${comicImageFilepath}`)
 | |
|     return false
 | |
|   }
 | |
| 
 | |
|   try {
 | |
|     await fs.writeFile(outputCoverPath, fileEntry.fileData)
 | |
|     return true
 | |
|   } catch (error) {
 | |
|     Logger.error(`[parseComicMetadata] Failed to extract image from comicPath "${comicPath}"`, error)
 | |
|     return false
 | |
|   }
 | |
| }
 | |
| 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(`Parsing metadata from comic at "${comicPath}"`)
 | |
| 
 | |
|   const comicFileBuffer = await getComicFileBuffer(comicPath)
 | |
|   if (!comicFileBuffer) return null
 | |
| 
 | |
|   const archive = await Archive.open(comicFileBuffer)
 | |
| 
 | |
|   const fileObjects = await archive.getFilesArray()
 | |
| 
 | |
|   fileObjects.sort((a, b) => {
 | |
|     return a.file.name.localeCompare(b.file.name, undefined, {
 | |
|       numeric: true,
 | |
|       sensitivity: 'base'
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   let metadata = null
 | |
|   const comicInfo = fileObjects.find(fo => fo.file.name === 'ComicInfo.xml')
 | |
|   if (comicInfo) {
 | |
|     const comicInfoEntry = await comicInfo.file.extract()
 | |
|     if (comicInfoEntry?.fileData) {
 | |
|       const comicInfoStr = new TextDecoder().decode(comicInfoEntry.fileData)
 | |
|       const comicInfoJson = await xmlToJSON(comicInfoStr)
 | |
|       if (comicInfoJson) {
 | |
|         metadata = parseComicInfoMetadata.parse(comicInfoJson)
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const payload = {
 | |
|     path: comicPath,
 | |
|     ebookFormat: ebookFile.ebookFormat,
 | |
|     metadata
 | |
|   }
 | |
| 
 | |
|   const firstImage = fileObjects.find(fo => globals.SupportedImageTypes.includes(Path.extname(fo.file.name).toLowerCase().slice(1)))
 | |
|   if (firstImage?.file?._path) {
 | |
|     payload.ebookCoverPath = firstImage.file._path
 | |
|   } else {
 | |
|     Logger.warn(`Cover image not found in comic at "${comicPath}"`)
 | |
|   }
 | |
| 
 | |
|   return payload
 | |
| }
 | |
| module.exports.parse = parse |