import JSZip from "jszip" const imageExts = new Set([".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp"]) export async function loadPagesFromCbz( url: string, signal?: AbortSignal, ): Promise<{ pages: string[]; pageCount: number }> { const response = await fetch(url, { signal }) if (!response.ok) throw new Error(`Failed to fetch CBZ: ${response.status}`) const blob = await response.blob() const zip = await JSZip.loadAsync(blob) const imageEntries = Object.entries(zip.files) .filter(([name, file]) => { const ext = name.toLowerCase().slice(name.lastIndexOf(".")) return !file.dir && imageExts.has(ext) }) .sort(([a], [b]) => { const numA = parseInt(a.match(/(\d+)/)?.[1] || "0", 10) const numB = parseInt(b.match(/(\d+)/)?.[1] || "0", 10) return numA - numB }) const pageCount = imageEntries.length const pages: string[] = [] for (const [, file] of imageEntries) { const blob = await file.async("blob") pages.push(URL.createObjectURL(blob)) } return { pages, pageCount } } export function revokePageUrls(urls: string[]) { for (const url of urls) { URL.revokeObjectURL(url) } }