Reader shell expects image-parser module. Renamed file to match import expectations.
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
// Comic/Manga Reader - Image-based pages
|
|
// Handles CBZ, comic archives, image directories
|
|
interface ReaderMetadata {
|
|
media_item_id: string;
|
|
title: string;
|
|
author: string;
|
|
cover_image_path: string;
|
|
library_type: "ebook" | "comic" | "manga" | "pdf";
|
|
mime_type: string;
|
|
file_path: string;
|
|
total_pages?: number;
|
|
}
|
|
interface ComicReader {
|
|
type: "comic";
|
|
images: Blob[];
|
|
currentPage: number;
|
|
}
|
|
interface MangaReader {
|
|
type: "manga";
|
|
images: Blob[];
|
|
currentPage: number;
|
|
readingDirection: "rtl" | "vertical";
|
|
}
|
|
// ============================================================
|
|
// Comic Reader Initialization
|
|
// ============================================================
|
|
export async function initializeComicReader(
|
|
metadata: ReaderMetadata,
|
|
): Promise<ComicReader> {
|
|
const response = await fetch(metadata.file_path);
|
|
const archiveBlob = await response.blob();
|
|
// Parse comic archive (CBZ) or image directory
|
|
const images = await parseComicArchive(archiveBlob);
|
|
return {
|
|
type: "comic",
|
|
images,
|
|
currentPage: 1,
|
|
};
|
|
}
|
|
// ============================================================
|
|
// Manga Reader Initialization
|
|
// ============================================================
|
|
export async function initializeMangaReader(
|
|
metadata: ReaderMetadata,
|
|
): Promise<MangaReader> {
|
|
const response = await fetch(metadata.file_path);
|
|
const archiveBlob = await response.blob();
|
|
const images = await parseComicArchive(archiveBlob);
|
|
return {
|
|
type: "manga",
|
|
images,
|
|
currentPage: 1,
|
|
readingDirection: "rtl", // Default for manga
|
|
};
|
|
}
|
|
// ============================================================
|
|
// Comic Archive Parser
|
|
// ============================================================
|
|
async function parseComicArchive(archiveBlob: Blob): Promise<Blob[]> {
|
|
const JSZip = (await import("jszip")).default;
|
|
const zip = await JSZip.loadAsync(archiveBlob);
|
|
const images: Blob[] = [];
|
|
// Get all image files from archive
|
|
const files = Object.keys(zip.files).filter((filename) =>
|
|
filename.match(/\.(jpg|jpeg|png|gif|webp)$/i),
|
|
);
|
|
// Sort files naturally (page-01.jpg, page-02.jpg, etc.)
|
|
files.sort((a, b) => {
|
|
const aName = a.split("/").pop() || a;
|
|
const bName = b.split("/").pop() || b;
|
|
return aName.localeCompare(bName, undefined, { numeric: true });
|
|
});
|
|
// Extract images
|
|
for (const file of files) {
|
|
const fileData = await zip.file(file)?.async("blob");
|
|
if (fileData) {
|
|
images.push(fileData);
|
|
}
|
|
}
|
|
return images;
|
|
}
|