// Parser Manager - Routes files to appropriate parsers // Procedural style: Functions, not classes import JSZip from "jszip"; // ============================================================ // Parser Registry // ============================================================ const PARSER_REGISTRY: ParserEntry[] = [ { format: "epub", mimeType: "application/epub+zip", extensions: [".epub"], side: "client", }, { format: "fb2", mimeType: "application/fb2", extensions: [".fb2", ".fb2.zip"], side: "client", }, { format: "txt", mimeType: "text/plain", extensions: [".txt"], side: "client", }, { format: "html", mimeType: "text/html", extensions: [".html", ".htm"], side: "client", }, { format: "mobi", mimeType: "application/x-mobipocket-ebook", extensions: [".mobi", ".azw"], side: "server", }, { format: "azw3", mimeType: "application/vnd.amazon.mobi8-ebook", extensions: [".azw3"], side: "server", }, { format: "docx", mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", extensions: [".docx"], side: "server", }, { format: "rtf", mimeType: "application/rtf", extensions: [".rtf"], side: "server", }, ]; interface ParserEntry { format: string; mimeType: string; extensions: string[]; side: "client" | "server"; } // ============================================================ // Parser Detection // ============================================================ export function detectParserFormat( mimeType: string, extension: string, ): ParserEntry | null { return ( PARSER_REGISTRY.find( (entry) => entry.mimeType === mimeType || entry.extensions.includes(extension.toLowerCase()), ) || null ); } export function requiresServerParsing( mimeType: string, extension: string, ): boolean { const entry = detectParserFormat(mimeType, extension); return entry?.side === "server" || false; } // ============================================================ // Main Parse Function (Router) // ============================================================ export async function parseEbook( file: Blob, mimeType: string, extension: string, ): Promise { const entry = detectParserFormat(mimeType, extension); if (!entry) { throw new Error(`Unsupported ebook format: ${mimeType}, ${extension}`); } if (entry.side === "server") { return parseEbookOnServer(file, entry.format); } else { return parseEbookOnClient(file, entry.format); } } // ============================================================ // Client-Side Parsing // ============================================================ async function parseEbookOnClient( file: Blob, format: string, ): Promise { switch (format) { case "epub": return parseEPUB(file); case "fb2": return parseFB2(file); case "txt": return parseTXT(file); case "html": return parseHTML(file); default: throw new Error(`Client-side parser not implemented for: ${format}`); } } // ============================================================ // Server-Side Parsing (API Call) // ============================================================ async function parseEbookOnServer( file: Blob, format: string, ): Promise { const formData = new FormData(); formData.append("file", file); formData.append("format", format); const response = await fetch("/readers/parse", { method: "POST", body: formData, }); if (!response.ok) { throw new Error(`Server parsing failed: ${response.statusText}`); } return await response.json(); }