import { fileTypeFromFile } from 'file-type'; import fs from 'node:fs/promises'; import { probeDfont } from './converters/dfont.js'; const OUTPUT_MIME_TYPES = { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', webp: 'image/webp', gif: 'image/gif', tiff: 'image/tiff', avif: 'image/avif', bmp: 'image/bmp', ico: 'image/x-icon', pdf: 'application/pdf', html: 'text/html', txt: 'text/plain', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', md: 'text/markdown', csv: 'text/csv', xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ttf: 'font/ttf', otf: 'font/otf', woff: 'font/woff', epub: 'application/epub+zip', fb2: 'application/x-fictionbook+xml', lrf: 'application/octet-stream', mobi: 'application/x-mobipocket-ebook', pdb: 'application/vnd.palm', rb: 'application/octet-stream', snb: 'application/octet-stream', tcr: 'application/octet-stream', azw3: 'application/vnd.amazon.ebook', }; export async function detectInputMime(filePath) { const result = await fileTypeFromFile(filePath); return result ?? null; } export function outputMimeType(targetFormat) { const mime = OUTPUT_MIME_TYPES[targetFormat]; if (!mime) { throw new Error(`No known MIME type for target format "${targetFormat}"`); } return mime; } const UNDETECTABLE_TEXT_FORMATS = { txt: 'text/plain', html: 'text/html', md: 'text/markdown', csv: 'text/csv', }; const UNDETECTABLE_EBOOK_FORMATS = { fb2: 'application/x-fictionbook+xml', lrf: 'application/octet-stream', pdb: 'application/vnd.palm', rb: 'application/octet-stream', snb: 'application/octet-stream', tcr: 'application/octet-stream', }; function normalizeFormat(format) { if (format === 'jpg') return 'jpeg'; if (format === 'heif') return 'heic'; if (format === 'azw3') return 'mobi'; if (format === 'fb2') return 'xml'; return format; } export async function resolveInputFormat(filePath, declaredFormat) { if (declaredFormat === 'dfont') { const buffer = await fs.readFile(filePath); return probeDfont(buffer) ? { mime: 'application/x-dfont', valid: true } : { mime: null, valid: false }; } const detected = await detectInputMime(filePath); if (!detected) { const fallbackMime = UNDETECTABLE_TEXT_FORMATS[declaredFormat] ?? UNDETECTABLE_EBOOK_FORMATS[declaredFormat]; if (fallbackMime) { return { mime: fallbackMime, valid: true }; } return { mime: null, valid: false }; } const valid = normalizeFormat(detected.ext) === normalizeFormat(declaredFormat); return { mime: detected.mime, valid }; }