Files
bookhoard/web/src/reader/parser-manager.ts
T
john-okeefe d3d84a8318 Implement core reader TypeScript modules for shell and UI management
- reader-shell.ts: Main initialization, Alpine.js integration, media type detection
- progress-indicator.ts: Reading progress tracking and display components
- settings-manager.ts: User settings persistence and retrieval
- panel-dock-system.ts: Dockable panel management with drag/drop and collapse
- parser-manager.ts: Parser selection and format detection system

These core modules provide the foundation for all reader types with
shared functionality for progress tracking, settings management, and
the flexible panel docking system.
2026-04-03 22:29:20 -04:00

161 lines
3.7 KiB
TypeScript

// 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<EbookCIF> {
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<EbookCIF> {
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<EbookCIF> {
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();
}