@prose-reader/streamer 1.276.0 → 1.277.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/archives/printTree.d.ts +1 -0
- package/dist/generators/manifest/hooks/toc.d.ts +10 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +749 -733
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +24 -20
- package/dist/index.umd.cjs.map +1 -1
- package/dist/report.d.ts +2 -7
- package/package.json +3 -3
- package/dist/generators/manifest/hooks/navigationFallback.d.ts +0 -12
- /package/dist/generators/manifest/hooks/{navigationFallback.test.d.ts → toc.test.d.ts} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/report.ts","../src/generators/resources/hooks/calibreFixHook.ts","../src/generators/resources/hooks/cssFixHook.ts","../src/epubs/getArchiveOpfInfo.ts","../src/epubs/getSpineItemFilesFromArchive.ts","../src/utils/uri.ts","../src/parsers/xml.ts","../src/parsers/nav.ts","../src/generators/manifest/hooks/epub/spineItems.ts","../src/generators/manifest/hooks/epub/epub.ts","../src/generators/resources/hooks/defaultHook.ts","../src/generators/resources/hooks/selfClosingTagsFixHook.ts","../src/generators/resources/index.ts","../src/generators/manifest/hooks/apple.ts","../src/parsers/kobo.ts","../src/generators/manifest/hooks/comicInfo.ts","../src/generators/manifest/hooks/default.ts","../src/generators/manifest/hooks/epubOptimizer.ts","../src/generators/manifest/hooks/kobo.ts","../src/utils/sortByTitleComparator.ts","../src/generators/manifest/hooks/navigationFallback.ts","../src/epubs/isArchiveEpub.ts","../src/generators/manifest/hooks/nonEpub.ts","../src/generators/manifest/index.ts","../src/archives/createArchiveFromUrls.ts","../src/archives/createArchiveFromText.ts","../src/archives/createArchiveFromJszip.ts","../src/archives/createArchiveFromLibArchive.ts","../src/archives/createArchiveFromArrayBufferList.ts","../src/configure.ts","../src/archives/archiveLoader.ts","../src/Streamer.ts","../src/ServiceWorkerStreamer.ts"],"sourcesContent":["let enabled = false\n\nexport const Report = {\n enable: (enable: boolean) => {\n enabled = enable\n },\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n log: (...data: any[]) => {\n if (enabled) {\n console.log(`[prose-reader-streamer]`, ...data)\n }\n },\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n debug: (...data: any[]) => {\n if (enabled) {\n console.debug(`[prose-reader-streamer]`, ...data)\n }\n },\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n warn: (...data: any[]) => {\n if (enabled) {\n console.warn(`[prose-reader-streamer]`, ...data)\n }\n },\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n error: (...data: any[]) => {\n console.error(...data)\n },\n}\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nconst hasCalibreCoverMeta = (doc: XmlDocument) => {\n const metaElm = doc\n .descendantWithPath(\"head\")\n ?.childrenNamed(\"meta\")\n .find((node) => node.attr.name === \"calibre:cover\")\n\n return !!(metaElm && metaElm.attr.name === \"calibre:cover\")\n}\n\nconst getBuggyCoverSvg = (doc: XmlDocument) => {\n return doc\n .descendantWithPath(\"body\")\n ?.descendantWithPath(\"div\")\n ?.childrenNamed(\"svg\")\n ?.find(\n (node) =>\n node.attr.width === \"100%\" && node.attr.preserveAspectRatio === \"none\",\n )\n}\n\nconst fixBuggyCover =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.xhtml`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n const opfXmlDoc = new XmlDocument(bodyToParse)\n\n if (hasCalibreCoverMeta(opfXmlDoc)) {\n const buggySvg = getBuggyCoverSvg(opfXmlDoc)\n\n if (buggySvg) {\n delete buggySvg.attr.preserveAspectRatio\n }\n\n return {\n ...resource,\n body: opfXmlDoc?.toString(),\n }\n }\n }\n\n return resource\n }\n\nexport const calibreFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n return fixBuggyCover({ archive, resourcePath })(resource)\n }\n","import type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nexport const cssFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.css`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n /**\n * Fix the potentially invalid writing mode present on some vertical book.\n * This has the benefit of making it compatible with firefox as well.\n */\n const newBody = bodyToParse.replaceAll(\n `-webkit-writing-mode`,\n `writing-mode`,\n )\n\n return {\n ...resource,\n body: newBody,\n }\n }\n\n return resource\n }\n","import type { Archive } from \"../archives/types\"\n\nexport const getArchiveOpfInfo = (archive: Archive) => {\n const filesAsArray = Object.values(archive.records).filter(\n (file) => !file.dir,\n )\n const file = filesAsArray.find((file) => file.uri.endsWith(`.opf`))\n\n return {\n data: file,\n basePath: file?.uri.substring(0, file.uri.lastIndexOf(`/`)) || ``,\n }\n}\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../archives/types\"\nimport { getArchiveOpfInfo } from \"./getArchiveOpfInfo\"\n\nexport const getSpineItemFilesFromArchive = async ({\n archive,\n}: {\n archive: Archive\n}) => {\n const { data: opsFile, basePath: opfBasePath } =\n getArchiveOpfInfo(archive) || {}\n\n const data = await opsFile?.string()\n\n if (!data) return []\n\n const _opfXmlDoc = new XmlDocument(data)\n\n const manifestElm = _opfXmlDoc.childNamed(`manifest`)\n const spineElm = _opfXmlDoc.childNamed(`spine`)\n\n const spineItemIds = spineElm\n ?.childrenNamed(`itemref`)\n .map((item) => item.attr.idref) as string[]\n const manifestItemsFromSpine =\n manifestElm\n ?.childrenNamed(`item`)\n .filter((item) => spineItemIds.includes(item.attr.id || ``)) || []\n\n const archiveSpineItems = archive.records.filter((file) => {\n return manifestItemsFromSpine.find((item) => {\n if (!opfBasePath) return `${item.attr.href}` === file.uri\n return `${opfBasePath}/${item.attr.href}` === file.uri\n })\n })\n\n return archiveSpineItems\n}\n","export const getUriBasename = (uri: string) =>\n uri.substring(uri.lastIndexOf(`/`) + 1) || uri\n\nexport const removeTrailingSlash = (uri: string) =>\n uri.endsWith(\"/\") ? uri.slice(0, -1) : uri\n\nexport const getUriBasePath = (uri: string) => {\n const lastSlashIndex = uri.lastIndexOf(\"/\")\n\n return lastSlashIndex >= 0 ? uri.substring(0, lastSlashIndex) : \"\"\n}\n","import { XmlTextNode } from \"xmldoc\"\n\nimport { XmlElement } from \"xmldoc\"\n\nexport const getXmlElementInnerText = (\n node: XmlElement | undefined,\n): string => {\n if (!node) return \"\"\n\n return node.children\n .map((child) => {\n if (child instanceof XmlTextNode) return child.text\n if (child instanceof XmlElement) return getXmlElementInnerText(child)\n return \"\"\n })\n .join(\"\")\n .trim()\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { urlJoin } from \"@prose-reader/shared\"\nimport { XmlDocument, type XmlElement, type XmlNodeBase } from \"xmldoc\"\nimport { type Archive, getArchiveOpfInfo } from \"..\"\nimport { getUriBasePath } from \"../utils/uri\"\nimport { getXmlElementInnerText } from \"./xml\"\n\ntype Toc = NonNullable<Manifest[`nav`]>[`toc`]\ntype TocItem = NonNullable<Manifest[`nav`]>[`toc`][number]\n\n/**\n * @see https://www.w3.org/TR/epub-33/#sec-nav-def-model\n */\nconst extractNavChapter = (\n li: XmlElement,\n { basePath, baseUrl }: { basePath: string; baseUrl: string },\n) => {\n const chp: TocItem = {\n contents: [],\n path: ``,\n href: ``,\n title: ``,\n }\n\n let contentNode = li.childNamed(`span`) || li.childNamed(`a`)\n\n chp.title =\n (contentNode?.attr.title ||\n contentNode?.val.trim() ||\n getXmlElementInnerText(contentNode)) ??\n ``\n\n let node = contentNode?.name\n\n if (node !== `a`) {\n contentNode = li.descendantWithPath(`${node}.a`)\n if (contentNode) {\n node = contentNode.name.toLowerCase()\n }\n }\n\n if (node === `a` && contentNode?.attr.href) {\n chp.path = urlJoin(basePath, contentNode.attr.href)\n chp.href = urlJoin(baseUrl, basePath, contentNode.attr.href)\n }\n const sublistNode = li.childNamed(`ol`)\n if (sublistNode) {\n const children = sublistNode.childrenNamed(`li`)\n if (children && children.length > 0) {\n chp.contents = children.map((child) =>\n extractNavChapter(child, { basePath, baseUrl }),\n )\n }\n }\n\n return chp\n}\n\nconst buildTOCFromNav = (\n doc: XmlDocument,\n { basePath, baseUrl }: { basePath: string; baseUrl: string },\n) => {\n const toc: Toc = []\n\n let navDataChildren: XmlNodeBase[] | undefined\n\n if (doc.descendantWithPath(`body.nav.ol`)) {\n navDataChildren = doc.descendantWithPath(`body.nav.ol`)?.children\n } else if (doc.descendantWithPath(`body.section.nav.ol`)) {\n navDataChildren = doc.descendantWithPath(`body.section.nav.ol`)?.children\n }\n\n if (navDataChildren && navDataChildren.length > 0) {\n navDataChildren\n .filter((li) => (li as XmlElement).name === `li`)\n .forEach((li) => {\n toc.push(extractNavChapter(li as XmlElement, { basePath, baseUrl }))\n })\n }\n\n return toc\n}\n\nconst parseTocFromNavPath = async (\n opfXmlDoc: XmlDocument,\n archive: Archive,\n { baseUrl }: { opfBasePath: string; baseUrl: string },\n) => {\n // Try to detect if there is a nav item\n const navItem = opfXmlDoc\n .childNamed(`manifest`)\n ?.childrenNamed(`item`)\n .find((child) => child.attr.properties === `nav`)\n\n if (navItem) {\n const tocFile = Object.values(archive.records).find((item) =>\n item.uri.endsWith(navItem.attr.href || ``),\n )\n\n if (tocFile && !tocFile.dir) {\n const doc = new XmlDocument(await tocFile.string())\n\n const tocFileBasePath = getUriBasePath(tocFile.uri)\n\n /**\n * links inside toc.xhtml are relative to the toc.xhtml file,\n * not the opf file anymore\n */\n return buildTOCFromNav(doc, { basePath: tocFileBasePath, baseUrl })\n }\n }\n}\n\nconst mapNcxChapter = (\n point: XmlElement,\n {\n opfBasePath,\n baseUrl,\n prefix,\n }: { opfBasePath: string; baseUrl: string; prefix: string },\n) => {\n const src = point?.childNamed(`${prefix}content`)?.attr.src || ``\n\n const out: TocItem = {\n title:\n point?.descendantWithPath(`${prefix}navLabel.${prefix}text`)?.val || ``,\n path: urlJoin(opfBasePath, src),\n href: urlJoin(baseUrl, opfBasePath, src),\n contents: [],\n }\n const children = point.childrenNamed(`${prefix}navPoint`)\n if (children && children.length > 0) {\n out.contents = children.map((pt) =>\n mapNcxChapter(pt, { opfBasePath, baseUrl, prefix }),\n )\n }\n\n return out\n}\n\nconst buildTOCFromNCX = (\n ncxData: XmlDocument,\n { opfBasePath, baseUrl }: { opfBasePath: string; baseUrl: string },\n) => {\n const toc: NonNullable<Manifest[`nav`]>[`toc`] = []\n\n const rootTagName = ncxData.name\n let prefix = ``\n if (rootTagName.indexOf(`:`) !== -1) {\n prefix = `${rootTagName.split(`:`)[0]}:`\n }\n\n ncxData\n .childNamed(`${prefix}navMap`)\n ?.childrenNamed(`${prefix}navPoint`)\n .forEach((point) => {\n toc.push(mapNcxChapter(point, { opfBasePath, baseUrl, prefix }))\n })\n\n return toc\n}\n\nconst parseTocFromNcx = async ({\n opfData,\n opfBasePath,\n baseUrl,\n archive,\n}: {\n opfData: XmlDocument\n opfBasePath: string\n archive: Archive\n baseUrl: string\n}) => {\n const spine = opfData.childNamed(`spine`)\n const ncxId = spine?.attr.toc\n\n if (ncxId) {\n const ncxItem = opfData\n .childNamed(`manifest`)\n ?.childrenNamed(`item`)\n .find((item) => item.attr.id === ncxId)\n\n if (ncxItem) {\n const ncxPath = `${opfBasePath}${opfBasePath === `` ? `` : `/`}${ncxItem.attr.href}`\n\n const file = Object.values(archive.records).find((item) =>\n item.uri.endsWith(ncxPath),\n )\n\n if (file && !file.dir) {\n const ncxData = new XmlDocument(await file.string())\n\n return buildTOCFromNCX(ncxData, { opfBasePath, baseUrl })\n }\n }\n }\n}\n\nexport const parseToc = async (\n opfXmlDoc: XmlDocument,\n archive: Archive,\n { baseUrl }: { baseUrl: string },\n) => {\n const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {}\n\n const tocFromNcx = await parseTocFromNcx({\n opfData: opfXmlDoc,\n opfBasePath,\n archive,\n baseUrl,\n })\n\n if (tocFromNcx) {\n return tocFromNcx\n }\n\n return await parseTocFromNavPath(opfXmlDoc, archive, {\n opfBasePath,\n baseUrl,\n })\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { XmlElement } from \"xmldoc\"\n\nexport type SpineItemProperties =\n // @see https://www.w3.org/TR/epub/#layout-overrides\n | `rendition:layout-reflowable`\n // @se https://www.w3.org/TR/epub/#layout-overrides\n | `rendition:layout-pre-paginated`\n | `page-spread-left`\n | `page-spread-right`\n\nexport const getSpineItemInfo = (\n itemRefElement: XmlElement,\n): Partial<Manifest[\"spineItems\"][number]> => {\n /**\n * @see https://www.w3.org/TR/epub/#attrdef-properties\n */\n const properties = (itemRefElement.attr.properties?.split(` `) ||\n []) as SpineItemProperties[]\n\n let renditionLayout: Manifest[\"spineItems\"][number][\"renditionLayout\"]\n\n if (\n properties.find((property) => property === `rendition:layout-reflowable`)\n ) {\n renditionLayout = `reflowable`\n }\n\n if (\n properties.find((property) => property === `rendition:layout-pre-paginated`)\n ) {\n renditionLayout = `pre-paginated`\n }\n\n return {\n renditionLayout,\n pageSpreadLeft:\n properties.some((property) => property === `page-spread-left`) ||\n undefined,\n pageSpreadRight:\n properties.some((property) => property === `page-spread-right`) ||\n undefined,\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument, type XmlElement } from \"xmldoc\"\nimport type { Archive } from \"../../../../archives/types\"\nimport { getArchiveOpfInfo } from \"../../../../epubs/getArchiveOpfInfo\"\nimport { getSpineItemFilesFromArchive } from \"../../../../epubs/getSpineItemFilesFromArchive\"\nimport { parseToc } from \"../../../../parsers/nav\"\nimport { Report } from \"../../../../report\"\nimport { getSpineItemInfo } from \"./spineItems\"\n\nconst getItemFromElement = (\n element: XmlElement,\n opfBasePath: string,\n getBaseUrl?: (element: XmlElement) => string,\n) => {\n const href = element.attr.href || ``\n const baseUrl = getBaseUrl?.(element)\n\n return {\n href: opfBasePath\n ? `${baseUrl}${opfBasePath}/${href}`\n : `${baseUrl}${href}`,\n id: element.attr.id || ``,\n mediaType: element.attr[`media-type`],\n }\n}\n\nexport const getItemsFromDoc = (\n doc: XmlDocument,\n archive: Archive,\n getBaseUrl?: (element: XmlElement) => string,\n) => {\n const manifestElm = doc.childNamed(`manifest`)\n const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {}\n\n return (\n manifestElm\n ?.childrenNamed(`item`)\n ?.map((el) => getItemFromElement(el, opfBasePath, getBaseUrl)) || []\n )\n}\n\nexport const epubHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const { data: opsFile, basePath: opfBasePath } =\n getArchiveOpfInfo(archive) || {}\n\n if (!opsFile) {\n return manifest\n }\n\n const data = await opsFile.string()\n\n Report.log(`data`, data)\n\n const opfXmlDoc = new XmlDocument(data)\n\n const toc = (await parseToc(opfXmlDoc, archive, { baseUrl })) || []\n\n const metadataElm = opfXmlDoc.childNamed(`metadata`)\n const manifestElm = opfXmlDoc.childNamed(`manifest`)\n const spineElm = opfXmlDoc.childNamed(`spine`)\n const guideElm = opfXmlDoc.childNamed(`guide`)\n const titleElm = metadataElm?.childNamed(`dc:title`)\n const metaElmChildren = metadataElm?.childrenNamed(`meta`) || []\n const metaElmWithRendition = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:layout`,\n )\n const metaElmWithRenditionFlow = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:flow`,\n )\n const metaElmWithRenditionSpread = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:spread`,\n )\n\n const publisherRenditionLayout = metaElmWithRendition?.val as\n | `reflowable`\n | `pre-paginated`\n | undefined\n const publisherRenditionFlow = metaElmWithRenditionFlow?.val as\n | `scrolled-continuous`\n | `scrolled-doc`\n | `paginated`\n | `auto`\n | undefined\n const renditionSpread = metaElmWithRenditionSpread?.val as\n | `auto`\n | undefined\n\n const title =\n titleElm?.val || archive.records.find(({ dir }) => dir)?.basename || ``\n const pageProgressionDirection = spineElm?.attr[\n `page-progression-direction`\n ] as `ltr` | `rtl` | undefined\n\n const archiveSpineItems = await getSpineItemFilesFromArchive({ archive })\n\n const totalSize = archiveSpineItems.reduce(\n (size, file) => file.size + size,\n 0,\n )\n\n return {\n filename: archive.filename,\n nav: {\n toc,\n },\n renditionLayout: publisherRenditionLayout,\n renditionFlow: publisherRenditionFlow || `auto`,\n renditionSpread,\n title,\n readingDirection: pageProgressionDirection || `ltr`,\n /**\n * @see https://www.w3.org/TR/epub/#sec-itemref-elem\n */\n spineItems:\n spineElm?.childrenNamed(`itemref`).map((itemrefElm, index) => {\n const manifestItem = manifestElm\n ?.childrenNamed(`item`)\n .find((item) => item.attr.id === itemrefElm?.attr.idref)\n const href = manifestItem?.attr.href || ``\n const itemSize =\n archive.records.find((file) => file.uri.endsWith(href))?.size || 0\n\n const hrefBaseUri = baseUrl\n ? baseUrl\n : /^https?:\\/\\//.test(href)\n ? \"\"\n : \"file://\"\n\n const spineItemInfo = getSpineItemInfo(itemrefElm)\n\n return {\n ...spineItemInfo,\n id: manifestItem?.attr.id || ``,\n index,\n href: manifestItem?.attr.href?.startsWith(`https://`)\n ? manifestItem?.attr.href\n : opfBasePath\n ? `${hrefBaseUri}${opfBasePath}/${manifestItem?.attr.href}`\n : `${hrefBaseUri}${manifestItem?.attr.href}`,\n renditionLayout:\n spineItemInfo.renditionLayout ?? publisherRenditionLayout,\n progressionWeight: itemSize / totalSize,\n // size: itemSize\n mediaType: manifestItem?.attr[`media-type`],\n }\n }) || [],\n items: getItemsFromDoc(opfXmlDoc, archive, (element) => {\n const href = element.attr.href || ``\n\n if (/^https?:\\/\\//.test(href)) {\n return \"\"\n }\n\n return baseUrl || \"file://\"\n }),\n guide: guideElm?.childrenNamed(`reference`).map((elm) => {\n return {\n href: elm.attr.href || ``,\n title: elm.attr.title || ``,\n type: elm.attr.type as NonNullable<Manifest[`guide`]>[number][`type`],\n }\n }),\n }\n }\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport { getArchiveOpfInfo } from \"../../../epubs/getArchiveOpfInfo\"\nimport { getItemsFromDoc } from \"../../manifest/hooks/epub/epub\"\nimport type { HookResource } from \"./types\"\n\n/**\n * We are trying to metadata from opf file in epub archive.\n *\n * Otherwise we fallback on what we can know from the archive.\n */\nconst getMetadata = async (archive: Archive, resourcePath: string) => {\n const opfInfo = getArchiveOpfInfo(archive)\n const data = await opfInfo.data?.string()\n\n if (data) {\n const opfXmlDoc = new XmlDocument(data)\n const items = getItemsFromDoc(opfXmlDoc, archive, () => \"\")\n\n // we are comparing opf items relative absolute path in epub archive\n // against resourcePatch (which are absolute path in archive).\n // They should in theory match.\n const foundMediaType = items.find((item) =>\n resourcePath.endsWith(item.href),\n )?.mediaType\n\n if (foundMediaType) {\n return {\n mediaType: items.find((item) => resourcePath.endsWith(item.href))\n ?.mediaType,\n }\n }\n }\n\n return {\n mediaType: getContentTypeFromExtension(resourcePath),\n }\n}\n\nconst getContentTypeFromExtension = (uri: string) => {\n if (uri.endsWith(`.css`)) {\n return `text/css; charset=UTF-8`\n }\n if (uri.endsWith(`.jpg`)) {\n return `image/jpg`\n }\n if (uri.endsWith(`.xhtml`)) {\n return `application/xhtml+xml`\n }\n if (uri.endsWith(`.mp4`)) {\n return `video/mp4`\n }\n if (uri.endsWith(`.svg`)) {\n return `image/svg+xml`\n }\n}\n\nexport const defaultHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (!file || file.dir) return resource\n\n // if (file.stream) {\n // const stream = file.stream()\n\n // console.log(file, stream)\n // stream.on(`data`, data => {\n // console.log(`data`, data)\n // })\n // stream.on(`error`, data => {\n // console.error(`error`, data)\n // })\n // stream.on(`end`, () => {\n // console.log(`end`)\n // })\n\n // }\n\n // const stream = file.stream!()\n\n // const readableStream = new ReadableStream({\n // start(controller) {\n // function push() {\n // stream.on(`data`, data => {\n // controller.enqueue(data)\n // })\n // stream.on(`error`, data => {\n // console.error(`error`, data)\n // })\n // stream.on(`end`, () => {\n // controller.close()\n // })\n\n // stream.resume()\n // }\n\n // push();\n // }\n // })\n\n const metadata = await getMetadata(archive, resourcePath)\n\n return {\n ...resource,\n params: {\n ...resource.params,\n ...(file?.encodingFormat && {\n contentType: file.encodingFormat,\n }),\n ...(metadata.mediaType && {\n contentType: metadata.mediaType,\n }),\n },\n }\n }\n","import type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nconst invalidSelfClosingTags = [\n \"div\",\n \"span\",\n \"p\",\n \"a\",\n \"li\",\n \"ul\",\n \"ol\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"table\",\n \"tr\",\n \"td\",\n \"th\",\n \"thead\",\n \"tbody\",\n \"tfoot\",\n \"section\",\n \"article\",\n \"header\",\n \"footer\",\n \"nav\",\n \"aside\",\n \"main\",\n \"figure\",\n \"figcaption\",\n \"blockquote\",\n \"pre\",\n \"code\",\n \"form\",\n \"textarea\",\n \"select\",\n \"option\",\n \"button\",\n \"label\",\n \"fieldset\",\n \"legend\",\n \"caption\",\n \"dl\",\n \"dt\",\n \"dd\",\n \"iframe\",\n \"video\",\n \"audio\",\n \"canvas\",\n \"script\",\n \"style\",\n]\n\n/**\n * Some books uses xhtml files but also includes wrong self closin tags. This happens\n * a lot with kobo epub which have a lot of self closing <script ... />. This breaks on some\n * browser such as webkit. We use a regex to replace and fix them. There\n * is a first lighter regex which check if any such tag exist in the first place before running\n * the full replace regex empty.\n */\nexport const selfClosingTagsFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.xhtml`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n const tagCheckPattern = new RegExp(\n `<(${invalidSelfClosingTags.join(\"|\")})[\\\\s/>]`,\n \"i\",\n )\n if (!tagCheckPattern.test(bodyToParse)) {\n return resource\n }\n\n const tagPattern = new RegExp(\n `<(${invalidSelfClosingTags.join(\"|\")})(\\\\s[^>]*)?\\\\s*/>`,\n \"gi\",\n )\n\n const fixedBody = bodyToParse.replace(\n tagPattern,\n (_, tagName, attributes = \"\") => {\n // Convert to an opening and closing tag\n return `<${tagName} ${attributes.trim()}></${tagName}>`\n },\n )\n\n return {\n ...resource,\n body: fixedBody,\n }\n }\n\n return resource\n }\n","import type { Archive } from \"../..\"\nimport { Report } from \"../../report\"\nimport { calibreFixHook } from \"./hooks/calibreFixHook\"\nimport { cssFixHook } from \"./hooks/cssFixHook\"\nimport { defaultHook } from \"./hooks/defaultHook\"\nimport { selfClosingTagsFixHook } from \"./hooks/selfClosingTagsFixHook\"\nimport type { HookResource } from \"./hooks/types\"\n\nexport const generateResourceFromArchive = async (\n archive: Archive,\n resourcePath: string,\n) => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (!file || file.dir) {\n throw new Error(`no file found for resourcePath:${resourcePath}`)\n }\n\n const defaultResource: HookResource = {\n params: {},\n }\n\n const hooks = [\n defaultHook({ archive, resourcePath }),\n selfClosingTagsFixHook({ archive, resourcePath }),\n cssFixHook({ archive, resourcePath }),\n calibreFixHook({ archive, resourcePath }),\n ]\n\n try {\n const resource = await hooks.reduce(async (manifest, gen) => {\n return await gen(await manifest)\n }, Promise.resolve(defaultResource))\n\n Report.log(\"Generated resource\", resourcePath, resource)\n\n return {\n ...resource,\n body: resource.body ?? (await file.blob()),\n }\n } catch (e) {\n Report.error(e)\n\n throw e\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const apple =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const infoFile = archive.records.find(\n (file) =>\n file.basename.toLowerCase() === `com.apple.ibooks.display-options.xml`,\n )\n\n if (!infoFile || infoFile.dir) {\n return manifest\n }\n\n const content = await (await infoFile.blob()).text()\n\n try {\n const xmlDoc = new XmlDocument(content)\n const platformElement = xmlDoc.childNamed(`platform`)\n const fixedLayoutOption =\n platformElement\n ?.childrenNamed(\"option\")\n ?.find((option) => option.attr.name === \"fixed-layout\")?.val ||\n \"false\"\n\n return {\n ...manifest,\n renditionLayout:\n fixedLayoutOption === `true`\n ? `pre-paginated`\n : manifest.renditionLayout,\n }\n } catch (e) {\n console.error(\n \"Unable to parse com.apple.ibooks.display-options.xml for content\\n\",\n content,\n )\n console.error(e)\n\n return manifest\n }\n }\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"..\"\n\ntype KoboInformation = {\n renditionLayout?: `reflowable` | `pre-paginated` | undefined\n}\n\nexport const extractKoboInformationFromArchive = async (archive: Archive) => {\n const koboInformation: KoboInformation = {\n renditionLayout: undefined,\n }\n\n await Promise.all(\n archive.records.map(async (file) => {\n if (file.uri.endsWith(`com.kobobooks.display-options.xml`) && !file.dir) {\n const opfXmlDoc = new XmlDocument(await file.string())\n const optionElement = opfXmlDoc\n .childNamed(`platform`)\n ?.childNamed(`option`)\n if (\n optionElement?.attr?.name === `fixed-layout` &&\n optionElement.val === `true`\n ) {\n koboInformation.renditionLayout = `pre-paginated`\n }\n }\n }),\n )\n\n return koboInformation\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\nimport { extractKoboInformationFromArchive } from \"../../../parsers/kobo\"\n\n/**\n * Handle archive which contains ComicInfo.xml. This is a meta file\n * used to define cbz, etc. I believe it comes from some sites or apps.\n */\nexport const comicInfoHook =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const koboInformation = await extractKoboInformationFromArchive(archive)\n\n return {\n ...manifest,\n renditionLayout:\n manifest.renditionLayout ?? koboInformation.renditionLayout,\n }\n }\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const defaultHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (): Promise<Manifest> => {\n const files = Object.values(archive.records).filter((file) => !file.dir)\n\n return {\n filename: archive.filename,\n title:\n archive.records.find(({ dir }) => dir)?.basename.replace(/\\/$/, ``) ||\n archive.filename,\n renditionLayout: undefined,\n renditionSpread: `auto`,\n readingDirection: `ltr`,\n spineItems: files\n .filter((file) => !file.basename.endsWith(`.db`))\n .map((file, index) => {\n const hrefBaseUri = baseUrl\n ? baseUrl\n : /^https?:\\/\\//.test(file.uri)\n ? \"\"\n : \"file://\"\n\n return {\n // some books such as cbz can have same basename inside different sub folder\n // we need to make sure to have unique index\n // /chap01/01.png, /chap02/01.png, etc\n id: `${index}.${file.basename}`,\n index,\n href: encodeURI(`${hrefBaseUri}${file.uri}`),\n renditionLayout: undefined,\n progressionWeight: 1 / files.length,\n pageSpreadLeft: undefined,\n pageSpreadRight: undefined,\n mediaType: file.encodingFormat,\n }\n }),\n items: files.map((file, index) => ({\n id: `${index}.${file.basename}`,\n href: encodeURI(`${baseUrl}${file.uri}`),\n })),\n }\n }\n","import { type Manifest, isXmlBasedMimeType } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport { getSpineItemFilesFromArchive } from \"../../../epubs/getSpineItemFilesFromArchive\"\n\nconst hasDocMetaViewport = (doc: XmlDocument) => {\n const metaElm = doc\n .descendantWithPath(\"head\")\n ?.childrenNamed(\"meta\")\n .find((node) => node.attr.name === \"viewport\")\n\n return !!(metaElm && metaElm.attr.name === \"viewport\")\n}\n\nconst allFilesHaveViewportMeta = (files: Archive[\"records\"]) =>\n files.reduce(async (result, current) => {\n const _result = await result\n\n if (!_result) return false\n\n if (\n !isXmlBasedMimeType({\n mimeType: current.encodingFormat,\n uri: current.uri,\n })\n ) {\n return false\n }\n\n const file = current.dir ? null : await current.string()\n\n if (!file) return false\n\n return hasDocMetaViewport(new XmlDocument(file))\n }, Promise.resolve(true))\n\nexport const epubOptimizerHook =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const bookIsFullReflowable =\n manifest.renditionLayout === \"reflowable\" &&\n manifest.spineItems.every((item) => item.renditionLayout === \"reflowable\")\n\n if (bookIsFullReflowable) {\n const files = await getSpineItemFilesFromArchive({ archive })\n\n const hasAllViewport = await allFilesHaveViewportMeta(files)\n\n if (hasAllViewport) {\n return {\n ...manifest,\n spineItems: manifest.spineItems.map((item) => ({\n ...item,\n renditionLayout: \"pre-paginated\",\n })),\n renditionLayout: \"pre-paginated\",\n }\n }\n }\n\n return manifest\n }\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const kobo =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const comicInfoFile = archive.records.find(\n (file) => file.basename.toLowerCase() === `comicinfo.xml` && !file.dir,\n )\n\n if (!comicInfoFile || comicInfoFile.dir) {\n return manifest\n }\n\n const manifestWithoutComicInfo = {\n ...manifest,\n spineItems: manifest.spineItems\n .filter((item) => !item.id.toLowerCase().endsWith(`comicinfo.xml`))\n .map((item, _, items) => ({\n ...item,\n progressionWeight: 1 / items.length,\n })),\n }\n\n // @todo handle more meta\n const content = await comicInfoFile.string()\n\n try {\n const xmlDoc = new XmlDocument(content)\n\n const mangaVal =\n (xmlDoc.childNamed(`Manga`)?.val as `YesAndRightToLeft`) || `unknown`\n\n return {\n ...manifestWithoutComicInfo,\n readingDirection: mangaVal === `YesAndRightToLeft` ? `rtl` : `ltr`,\n }\n } catch (e) {\n console.error(\"Unable to parse comicinfo.xml for content\\n\", content)\n console.error(e)\n\n return manifestWithoutComicInfo\n }\n }\n","export const sortByTitleComparator = (a: string, b: string) => {\n const alist = a.split(/(\\d+)/)\n const blist = b.split(/(\\d+)/)\n\n for (let i = 0, len = alist.length; i < len; i++) {\n if (alist[i] !== blist[i]) {\n if (alist[i]?.match(/\\d/)) {\n return +(alist[i] || ``) - +(blist[i] || ``)\n }\n return (alist[i] || ``).localeCompare(blist[i] || ``)\n }\n }\n\n return 1\n}\n","import { type Manifest, type TocItem, urlJoin } from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\nimport { sortByTitleComparator } from \"../../../utils/sortByTitleComparator\"\n\n/**\n * In case no navigation was generated prior to this hook, we will try\n * to generate something based on the structure of the archive.\n *\n * We use folders as chapters.\n */\nexport const navigationFallbackHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n if (manifest.nav) return manifest\n\n const filesSortedByAlpha = [...archive.records].sort((a, b) =>\n sortByTitleComparator(a.uri, b.uri),\n )\n\n const filesSortedAlpha = Object.values(filesSortedByAlpha)\n\n const combineWith = (\n toc: TocItem[],\n folder: string,\n subFolders: string[],\n href: string,\n path: string,\n ): TocItem[] => {\n const foundEntry = toc.find((entry) => entry.title === folder)\n const [nextFolderCursor, ...nextSubFolders] = subFolders\n\n if (foundEntry) {\n if (nextFolderCursor) {\n return [\n ...toc.filter((entry) => entry !== foundEntry),\n {\n ...foundEntry,\n contents: [\n ...foundEntry.contents,\n ...combineWith(\n foundEntry.contents,\n nextFolderCursor,\n nextSubFolders,\n href,\n path,\n ),\n ],\n } satisfies TocItem,\n ]\n }\n\n // we have an exact match for current folder\n // try to see if the path is better than previously registered\n const previousRegisteredPathWasLonger =\n foundEntry.path.split(\"/\").length > path.split(\"/\").length\n\n if (previousRegisteredPathWasLonger) {\n return [\n ...toc.filter((entry) => entry !== foundEntry),\n {\n ...foundEntry,\n path,\n href,\n } satisfies TocItem,\n ]\n }\n\n return toc\n }\n\n if (nextFolderCursor) {\n return [\n ...toc,\n {\n contents: combineWith(\n [],\n nextFolderCursor,\n nextSubFolders,\n href,\n path,\n ),\n href,\n path,\n title: folder,\n },\n ]\n }\n\n return [\n ...toc,\n {\n contents: [],\n href,\n path,\n title: folder,\n },\n ]\n }\n\n const toc: NonNullable<Manifest[\"nav\"]>[\"toc\"] = filesSortedAlpha.reduce(\n (acc, file) => {\n if (file.dir) return acc\n\n const parts = file.uri.split(\"/\")\n\n // we have a file that is\n const folders = parts.slice(0, -1)\n const [firstFolder, ...restFolders] = folders\n\n if (firstFolder) {\n const href = urlJoin(baseUrl, encodeURI(file.uri)).replace(/\\/$/, \"\")\n const path = file.uri.replace(/\\/$/, \"\")\n\n return combineWith(acc, firstFolder, restFolders, href, path)\n }\n\n return acc\n },\n [] as NonNullable<Manifest[\"nav\"]>[\"toc\"],\n )\n\n if (toc.length === 0) return manifest\n\n return {\n ...manifest,\n nav: {\n toc,\n },\n }\n }\n","import type { Archive } from \"../archives/types\"\n\nexport const isArchiveEpub = (archive: Archive) => {\n return archive.records.some((file) => file.basename.endsWith(`.opf`))\n}\n","import {\n type Manifest,\n detectMimeTypeFromName,\n parseContentType,\n} from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\nimport { isArchiveEpub } from \"../../../epubs/isArchiveEpub\"\n\n/**\n * If we don't have a regular epub, we have an archive that could be many things.\n * We try to refine the manifest based on the type of content as much as possible.\n */\nexport const nonEpub =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const isEpub = isArchiveEpub(archive)\n\n if (isEpub) return manifest\n\n return {\n ...manifest,\n spineItems: manifest.spineItems.map((spineItem) => {\n const archiveItem = archive.records.find((item) =>\n decodeURI(spineItem.href).endsWith(item.uri),\n )\n\n const mimeType =\n parseContentType(archiveItem?.encodingFormat ?? \"\") ??\n detectMimeTypeFromName(archiveItem?.basename ?? \"\")\n\n return {\n ...spineItem,\n renditionLayout: mimeType?.startsWith(`image/`)\n ? `pre-paginated`\n : spineItem.renditionLayout,\n }\n }),\n }\n }\n","import type { Archive } from \"../../archives/types\"\nimport { Report } from \"../../report\"\nimport { apple } from \"./hooks/apple\"\nimport { comicInfoHook } from \"./hooks/comicInfo\"\nimport { defaultHook } from \"./hooks/default\"\nimport { epubHook } from \"./hooks/epub/epub\"\nimport { epubOptimizerHook } from \"./hooks/epubOptimizer\"\nimport { kobo } from \"./hooks/kobo\"\nimport { navigationFallbackHook } from \"./hooks/navigationFallback\"\nimport { nonEpub } from \"./hooks/nonEpub\"\n\nexport const generateManifestFromArchive = async (\n archive: Archive,\n { baseUrl = `` }: { baseUrl?: string } = {},\n) => {\n const hooks = [\n epubHook({ archive, baseUrl }),\n kobo({ archive, baseUrl }),\n apple({ archive, baseUrl }),\n nonEpub({ archive, baseUrl }),\n epubOptimizerHook({ archive, baseUrl }),\n comicInfoHook({ archive, baseUrl }),\n navigationFallbackHook({ archive, baseUrl }),\n ]\n\n try {\n const baseManifestPromise = defaultHook({ archive, baseUrl })()\n\n const manifest = await hooks.reduce(async (manifest, gen) => {\n return await gen(await manifest)\n }, baseManifestPromise)\n\n Report.log(\"Generated manifest\", manifest)\n\n return manifest\n } catch (e) {\n Report.error(e)\n\n throw e\n }\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\n/**\n * @important\n * Make sure the urls are on the same origin or the cors header is set otherwise\n * the resource cannot be consumed as it is on the web.\n */\nexport const createArchiveFromUrls = async (\n urls: string[],\n options?: { useRenditionFlow: boolean },\n): Promise<Archive> => {\n const opfFileData = `\n <?xml version=\"1.0\" encoding=\"UTF-8\"?><package xmlns=\"http://www.idpf.org/2007/opf\" version=\"2.0\" unique-identifier=\"bookid\">\n <metadata>\n <meta property=\"rendition:layout\">${options?.useRenditionFlow ? `reflowable` : `pre-paginated`}</meta>\n ${options?.useRenditionFlow ? `<meta property=\"rendition:flow\">scrolled-continuous</meta>` : ``}\n </metadata>\n <manifest>\n ${urls\n .map(\n (url) =>\n `<item id=\"${getUriBasename(url)}\" href=\"${url}\" media-type=\"${detectMimeTypeFromName(url)}\"/>`,\n )\n .join(`\\n`)}\n </manifest>\n <spine>\n ${urls.map((url) => `<itemref idref=\"${getUriBasename(url)}\" />`).join(`\\n`)}\n </spine>\n </package>\n `\n\n const filesFromUrl: Archive[`records`] = urls.map((url) => ({\n dir: false,\n basename: getUriBasename(url),\n encodingFormat: detectMimeTypeFromName(url),\n uri: url,\n size: 100 / urls.length,\n blob: async () => {\n const response = await fetch(url)\n\n return response.blob()\n },\n string: async () => ``,\n }))\n\n const opfFile: Archive[`records`][number] = {\n dir: false,\n basename: `content.opf`,\n uri: `content.opf`,\n size: 0,\n blob: async () => new Blob(),\n string: async () => opfFileData,\n }\n\n return {\n filename: ``,\n records: [opfFile, ...filesFromUrl],\n close: () => Promise.resolve(),\n }\n}\n","import { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\n/**\n * Useful to create archive from txt content\n */\nexport const createArchiveFromText = async (\n content: string | Blob,\n {\n mimeType,\n direction,\n }: {\n direction?: `ltr` | `rtl`\n mimeType?: string\n } = { mimeType: \"text/plain\" },\n) => {\n const txtOpfContent = `\n <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" xml:lang=\"ja\" prefix=\"rendition: http://www.idpf.org/vocab/rendition/#\"\n unique-identifier=\"ootuya-id\">\n <metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n xmlns:dcterms=\"http://purl.org/dc/terms/\">\n <meta property=\"rendition:layout\">reflowable</meta>\n </metadata>\n <manifest>\n <item id=\"p01\" href=\"p01.txt\" media-type=\"text/plain\"/>\n </manifest>\n <spine page-progression-direction=\"${direction ?? `ltr`}\">\n <itemref idref=\"p01\" />\n </spine>\n </package>\n `\n\n const archive: Archive = {\n filename: `content.txt`,\n records: [\n {\n dir: false,\n basename: getUriBasename(`generated.opf`),\n uri: `generated.opf`,\n blob: async () => new Blob([txtOpfContent]),\n string: async () => txtOpfContent,\n size: 0,\n },\n {\n dir: false,\n basename: getUriBasename(`p01.txt`),\n uri: `p01.txt`,\n blob: async () => {\n if (typeof content === \"string\") return new Blob([content])\n return content\n },\n string: async () => {\n if (typeof content === \"string\") return content\n return content.text()\n },\n size: typeof content === \"string\" ? content.length : content.size,\n encodingFormat: mimeType,\n },\n ],\n close: () => Promise.resolve(),\n }\n\n return archive\n}\n","import { Report } from \"../report\"\nimport { sortByTitleComparator } from \"../utils/sortByTitleComparator\"\nimport { getUriBasename } from \"../utils/uri\"\nimport type { Archive, StreamResult } from \"./types\"\n\ninterface OutputByType {\n base64: string\n string: string\n text: string\n binarystring: string\n array: number[]\n uint8array: Uint8Array\n arraybuffer: ArrayBuffer\n blob: Blob\n nodebuffer: Buffer\n}\n\ntype OutputType = keyof OutputByType\n\ninterface JSZipObject {\n name: string\n dir: boolean\n date: Date\n comment: string\n unixPermissions: number | string | null\n dosPermissions: number | null\n async<T extends OutputType>(type: T): Promise<OutputByType[T]>\n // nodeStream(type?: `nodebuffer`): NodeJS.ReadableStream;\n internalStream?: (type?: `uint8array`) => StreamResult\n}\n\ninterface JSZip {\n files: { [key: string]: JSZipObject }\n}\n\nexport const createArchiveFromJszip = async (\n jszip: JSZip,\n { orderByAlpha, name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n let files = Object.values(jszip.files)\n\n if (orderByAlpha) {\n files = files.slice().sort((a, b) => sortByTitleComparator(a.name, b.name))\n }\n\n const archive: Archive = {\n filename: name || ``,\n records: files.map((file) => ({\n dir: file.dir,\n basename: getUriBasename(file.name),\n uri: file.name,\n blob: () => file.async(`blob`),\n string: () => file.async(\"string\"),\n ...(file.internalStream && {\n stream: file.internalStream,\n }),\n // this is private API\n // @ts-expect-error\n size: file._data.uncompressedSize,\n })),\n close: () => Promise.resolve(),\n }\n\n Report.log(\"Generated archive\", archive)\n\n return archive\n}\n","/**\n * @see https://github.com/nika-begiashvili/libarchivejs.\n *\n * Does not work in service worker due to usage of web worker.\n */\nimport { Report } from \"../report\"\nimport type { Archive } from \"./types\"\n\ninterface ArchiveReader {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n getFilesArray(): Promise<any[]>\n /**\n * Terminate worker to free up memory\n */\n close(): Promise<void>\n}\n\n/**\n * Represents compressed file before extraction\n */\ninterface CompressedFile {\n /**\n * File name\n */\n get name(): string\n /**\n * File size\n */\n get size(): number\n get lastModified(): number\n /**\n * Extract file from archive\n * @returns {Promise<File>} extracted file\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n extract(): any\n}\n\nexport const createArchiveFromLibArchive = async (\n libArchive: ArchiveReader,\n { name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n const objArray = await libArchive.getFilesArray()\n\n const archive: Archive = {\n close: () => libArchive.close(),\n filename: name ?? ``,\n records: objArray.map((item: { file: CompressedFile; path: string }) => ({\n dir: false,\n basename: item.file.name,\n size: item.file.size,\n uri: `${item.path}${item.file.name}`,\n blob: async () => {\n const file = await (item.file.extract() as Promise<File>)\n\n return file\n },\n string: async () => {\n const file = await (item.file.extract() as Promise<File>)\n\n return file.text()\n },\n })),\n }\n\n Report.log(\"Generated archive\", archive)\n\n return archive\n}\n","import { sortByTitleComparator } from \"../utils/sortByTitleComparator\"\nimport { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\nexport const createArchiveFromArrayBufferList = async (\n list: {\n isDir: boolean\n name: string\n size: number\n data: () => Promise<ArrayBuffer>\n }[],\n { orderByAlpha, name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n let files = list\n\n if (orderByAlpha) {\n files = files.slice().sort((a, b) => sortByTitleComparator(a.name, b.name))\n }\n\n return {\n filename: name || ``,\n records: files.map((file) => ({\n dir: file.isDir,\n basename: getUriBasename(file.name),\n uri: file.name,\n blob: async () => new Blob([await file.data()]),\n string: async () => {\n const data = await file.data()\n return String.fromCharCode.apply(\n null,\n Array.from(new Uint16Array(data)),\n )\n },\n size: file.size,\n })),\n close: () => Promise.resolve(),\n }\n}\n","import { Report } from \"./report\"\n\nexport const configure = ({\n enableReport,\n}: {\n enableReport?: boolean\n} = {}) => {\n Report.enable(!!enableReport)\n}\n","import {\n BehaviorSubject,\n EMPTY,\n NEVER,\n type ObservedValueOf,\n Subject,\n catchError,\n distinctUntilChanged,\n filter,\n first,\n from,\n ignoreElements,\n map,\n merge,\n mergeMap,\n pairwise,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n timer,\n} from \"rxjs\"\nimport { Report } from \"../report\"\nimport type { Archive } from \"./types\"\n\nclass ArchiveEntry {\n state$ = new BehaviorSubject<{\n status: \"idle\" | \"loading\" | \"success\" | \"error\"\n error?: unknown | undefined\n archive?: undefined | Archive\n locks: number\n }>({\n status: `idle`,\n locks: 0,\n })\n\n constructor(private cleanArchiveAfter: number) {}\n\n update(update: Partial<ObservedValueOf<typeof this.state$>>) {\n this.state$.next({ ...this.state$.getValue(), ...update })\n }\n\n get locks$() {\n return this.state$.pipe(map(({ locks }) => locks))\n }\n\n get state() {\n return this.state$.getValue()\n }\n\n get isUnlocked$() {\n return this.locks$.pipe(\n map((locks) => locks <= 0),\n distinctUntilChanged(),\n shareReplay(),\n )\n }\n\n get overTTL$() {\n return this.isUnlocked$.pipe(\n switchMap((isUnlocked) =>\n !isUnlocked\n ? NEVER\n : this.cleanArchiveAfter === Infinity\n ? NEVER\n : timer(this.cleanArchiveAfter),\n ),\n )\n }\n}\n\nexport const createArchiveLoader = ({\n getArchive,\n cleanArchiveAfter = 5 * 60 * 1000, // 5mn\n}: {\n getArchive: (key: string) => Promise<Archive>\n cleanArchiveAfter?: number\n}) => {\n const loadSubject = new Subject<string>()\n const destroySubject = new Subject<void>()\n const purgeSubject = new Subject<void>()\n const archives: Record<string, ArchiveEntry> = {}\n\n const loadArchive$ = loadSubject.pipe(\n mergeMap((key) => {\n const archiveEntry = archives[key]\n\n if (!archiveEntry || archiveEntry.state.status !== \"idle\") return EMPTY\n\n let isClosed = false\n\n const cleanupArchive = (key: string) => {\n Report.debug(`Cleaning up archive with key: ${key}`)\n\n const entry = archives[key]\n\n delete archives[key]\n\n if (!isClosed) {\n entry?.state.archive?.close()\n isClosed = true\n }\n }\n\n archiveEntry.update({\n status: \"loading\",\n })\n\n const locks$ = archiveEntry.locks$\n const isUnlocked$ = archiveEntry.isUnlocked$\n\n const newAccess$ = locks$.pipe(\n pairwise(),\n filter(([prev, curent]) => curent > prev),\n startWith(true),\n )\n\n const archive$ = from(getArchive(key))\n\n return archive$.pipe(\n tap((archive) => {\n archiveEntry.update({\n archive,\n status: \"success\",\n })\n }),\n catchError((error) => {\n cleanupArchive(key)\n\n archiveEntry.update({\n status: \"error\",\n error,\n })\n\n return EMPTY\n }),\n switchMap(() => {\n const readyForPurge$ = newAccess$.pipe(\n switchMap(() => purgeSubject),\n switchMap(() => isUnlocked$),\n filter((isUnlocked) => isUnlocked),\n )\n\n const toCleanup$ = merge(readyForPurge$, archiveEntry.overTTL$)\n\n return toCleanup$.pipe(\n first(),\n tap(() => {\n cleanupArchive(key)\n }),\n )\n }),\n )\n }),\n takeUntil(destroySubject),\n )\n\n const access = (key: string) => {\n let releaseCalled = false\n\n const archiveEntry = archives[key] ?? new ArchiveEntry(cleanArchiveAfter)\n\n archives[key] = archiveEntry\n\n archiveEntry.update({\n locks: archiveEntry.state.locks + 1,\n })\n\n const release = () => {\n if (releaseCalled) return\n\n releaseCalled = true\n\n archiveEntry.update({\n locks: archiveEntry.state.locks - 1,\n })\n }\n\n loadSubject.next(key)\n\n const archive$ = archiveEntry.state$.pipe(\n map(({ archive }) => archive),\n filter((archive) => !!archive),\n )\n\n const error$ = archiveEntry.state$.pipe(\n tap(({ error }) => {\n if (error) {\n throw error\n }\n }),\n ignoreElements(),\n )\n\n return merge(archive$, error$).pipe(\n first(),\n map((archive) => ({ archive, release })),\n catchError((error) => {\n release()\n\n throw error\n }),\n )\n }\n\n /**\n * Will purge immediatly archives as soon as they are released\n */\n const purge = () => {\n purgeSubject.next()\n }\n\n loadArchive$.subscribe()\n\n return {\n access,\n purge,\n _archives: archives,\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n type Observable,\n catchError,\n finalize,\n from,\n lastValueFrom,\n map,\n mergeMap,\n of,\n switchMap,\n} from \"rxjs\"\nimport { createArchiveLoader } from \"./archives/archiveLoader\"\nimport type { Archive } from \"./archives/types\"\nimport { generateManifestFromArchive } from \"./generators/manifest\"\nimport { generateResourceFromArchive } from \"./generators/resources\"\n\ntype OnError = (error: unknown) => Response\ntype OnManifestSuccess = (params: {\n manifest: Manifest\n archive: Archive\n}) => Observable<Manifest> | Promise<Manifest>\n\nexport class Streamer {\n protected epubLoader: ReturnType<typeof createArchiveLoader>\n protected onError: OnError = (error) => {\n console.error(error)\n\n return new Response(String(error), { status: 500 })\n }\n protected onManifestSuccess: OnManifestSuccess\n protected lastAccessedKey: string | undefined\n\n constructor({\n onError,\n onManifestSuccess,\n ...rest\n }: Parameters<typeof createArchiveLoader>[0] & {\n onError?: OnError\n onManifestSuccess?: OnManifestSuccess\n }) {\n this.epubLoader = createArchiveLoader(rest)\n\n this.onManifestSuccess =\n onManifestSuccess ?? (({ manifest }) => Promise.resolve(manifest))\n this.onError = onError ?? this.onError\n }\n\n public prune() {\n this.epubLoader.purge()\n }\n\n public accessArchive(key: string) {\n if (this.lastAccessedKey !== undefined && this.lastAccessedKey !== key) {\n this.epubLoader.purge()\n }\n\n this.lastAccessedKey = key\n\n return this.epubLoader.access(key)\n }\n\n public accessArchiveWithoutLock(key: string) {\n return this.accessArchive(key).pipe(\n map(({ archive, release }) => {\n release()\n\n return archive\n }),\n )\n }\n\n public fetchManifest({ key, baseUrl }: { key: string; baseUrl?: string }) {\n const response$ = this.accessArchive(key).pipe(\n mergeMap(({ archive, release }) => {\n const manifest$ = from(\n generateManifestFromArchive(archive, { baseUrl }),\n )\n\n return manifest$.pipe(\n switchMap((manifest) =>\n from(this.onManifestSuccess({ manifest, archive })),\n ),\n map(\n (manifest) =>\n new Response(JSON.stringify(manifest satisfies Manifest), {\n status: 200,\n }),\n ),\n finalize(() => {\n release()\n }),\n )\n }),\n catchError((error) => {\n return of(this.onError(error))\n }),\n )\n\n return lastValueFrom(response$)\n }\n\n public fetchResource({\n key,\n resourcePath,\n }: {\n key: string\n resourcePath: string\n }) {\n const response$ = this.accessArchive(key).pipe(\n mergeMap(({ archive, release }) => {\n /**\n * We commonly use file:// for manifest without baseUrl. This ensure we\n * have valid URL for the reader while flagging them as local.\n *\n * However, we obviously don't have the file:// prefix on the archive.\n */\n const cleanedResourcePath = resourcePath.replaceAll(`file://`, ``)\n\n const resource$ = from(\n generateResourceFromArchive(archive, cleanedResourcePath),\n )\n\n return resource$.pipe(\n map(\n (resource) =>\n new Response(resource.body, {\n status: 200,\n headers: {\n ...(resource.params.contentType && {\n \"Content-Type\": resource.params.contentType,\n }),\n },\n }),\n ),\n finalize(() => {\n release()\n }),\n )\n }),\n catchError((error) => {\n return of(this.onError(error))\n }),\n )\n\n return lastValueFrom(response$)\n }\n}\n","import { Streamer } from \"./Streamer\"\nimport { removeTrailingSlash } from \"./utils/uri\"\n\ntype ConflictFreeWebWorkerFetchEvent = {\n readonly request: Request\n /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) */\n respondWith(r: Response | PromiseLike<Response>): void\n}\n\nexport class ServiceWorkerStreamer extends Streamer {\n protected getUriInfo: (event: ConflictFreeWebWorkerFetchEvent) =>\n | {\n baseUrl: string\n }\n | undefined\n\n constructor({\n getUriInfo,\n ...rest\n }: ConstructorParameters<typeof Streamer>[0] & {\n getUriInfo: (event: ConflictFreeWebWorkerFetchEvent) =>\n | {\n baseUrl: string\n }\n | undefined\n }) {\n super(rest)\n\n this.getUriInfo = getUriInfo\n this.fetchEventListener = this.fetchEventListener.bind(this)\n }\n\n fetchEventListener(event: ConflictFreeWebWorkerFetchEvent) {\n try {\n const uriInfo = this.getUriInfo(event)\n\n if (!uriInfo) return\n\n const baseUrl = removeTrailingSlash(uriInfo.baseUrl)\n const streamerPath = event.request.url.substring(\n baseUrl.length + `/`.length,\n )\n const [key = ``] = streamerPath.split(\"/\")\n const resourcePath = decodeURIComponent(\n removeTrailingSlash(streamerPath.substring(key.length + `/`.length)),\n )\n\n if (streamerPath.endsWith(`/manifest`)) {\n event.respondWith(\n this.fetchManifest({ key, baseUrl: `${baseUrl}/${key}/` }),\n )\n } else {\n event.respondWith(this.fetchResource({ key, resourcePath }))\n }\n } catch (e) {\n event.respondWith(new Response(String(e), { status: 500 }))\n }\n }\n}\n"],"names":["enabled","Report","enable","data","hasCalibreCoverMeta","doc","metaElm","node","getBuggyCoverSvg","fixBuggyCover","archive","resourcePath","resource","file","bodyToParse","opfXmlDoc","XmlDocument","buggySvg","calibreFixHook","cssFixHook","newBody","getArchiveOpfInfo","getSpineItemFilesFromArchive","opsFile","opfBasePath","_opfXmlDoc","manifestElm","spineItemIds","item","manifestItemsFromSpine","getUriBasename","uri","removeTrailingSlash","getUriBasePath","lastSlashIndex","getXmlElementInnerText","child","XmlTextNode","XmlElement","extractNavChapter","li","basePath","baseUrl","chp","contentNode","urlJoin","sublistNode","children","buildTOCFromNav","toc","navDataChildren","parseTocFromNavPath","navItem","tocFile","tocFileBasePath","mapNcxChapter","point","prefix","src","out","pt","buildTOCFromNCX","ncxData","rootTagName","parseTocFromNcx","opfData","ncxId","ncxItem","ncxPath","parseToc","tocFromNcx","getSpineItemInfo","itemRefElement","properties","renditionLayout","property","getItemFromElement","element","getBaseUrl","href","getItemsFromDoc","el","epubHook","manifest","metadataElm","spineElm","guideElm","titleElm","metaElmChildren","metaElmWithRendition","meta","metaElmWithRenditionFlow","metaElmWithRenditionSpread","publisherRenditionLayout","publisherRenditionFlow","renditionSpread","title","dir","pageProgressionDirection","totalSize","size","itemrefElm","index","manifestItem","itemSize","hrefBaseUri","spineItemInfo","elm","getMetadata","items","getContentTypeFromExtension","defaultHook","metadata","invalidSelfClosingTags","selfClosingTagsFixHook","tagPattern","fixedBody","_","tagName","attributes","generateResourceFromArchive","defaultResource","hooks","gen","e","apple","infoFile","content","fixedLayoutOption","option","extractKoboInformationFromArchive","koboInformation","optionElement","comicInfoHook","files","hasDocMetaViewport","allFilesHaveViewportMeta","result","current","isXmlBasedMimeType","epubOptimizerHook","kobo","comicInfoFile","manifestWithoutComicInfo","mangaVal","sortByTitleComparator","a","b","alist","blist","i","len","navigationFallbackHook","filesSortedByAlpha","filesSortedAlpha","combineWith","folder","subFolders","path","foundEntry","entry","nextFolderCursor","nextSubFolders","acc","folders","firstFolder","restFolders","isArchiveEpub","nonEpub","spineItem","archiveItem","mimeType","parseContentType","detectMimeTypeFromName","generateManifestFromArchive","baseManifestPromise","createArchiveFromUrls","urls","options","opfFileData","url","filesFromUrl","createArchiveFromText","direction","txtOpfContent","createArchiveFromJszip","jszip","orderByAlpha","name","createArchiveFromLibArchive","libArchive","objArray","createArchiveFromArrayBufferList","list","configure","enableReport","ArchiveEntry","cleanArchiveAfter","BehaviorSubject","update","map","locks","distinctUntilChanged","shareReplay","switchMap","isUnlocked","NEVER","timer","createArchiveLoader","getArchive","loadSubject","Subject","destroySubject","purgeSubject","archives","loadArchive$","mergeMap","key","archiveEntry","EMPTY","isClosed","cleanupArchive","locks$","isUnlocked$","newAccess$","pairwise","filter","prev","curent","startWith","from","tap","catchError","error","readyForPurge$","merge","first","takeUntil","access","releaseCalled","release","archive$","error$","ignoreElements","purge","Streamer","onError","onManifestSuccess","rest","response$","finalize","of","lastValueFrom","cleanedResourcePath","ServiceWorkerStreamer","getUriInfo","event","uriInfo","streamerPath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/sortByTitleComparator.ts","../src/utils/uri.ts","../src/archives/createArchiveFromArrayBufferList.ts","../src/report.ts","../src/archives/printTree.ts","../src/archives/createArchiveFromJszip.ts","../src/archives/createArchiveFromLibArchive.ts","../src/archives/createArchiveFromText.ts","../src/archives/createArchiveFromUrls.ts","../src/configure.ts","../src/epubs/getArchiveOpfInfo.ts","../src/generators/manifest/hooks/apple.ts","../src/parsers/kobo.ts","../src/generators/manifest/hooks/comicInfo.ts","../src/generators/manifest/hooks/default.ts","../src/epubs/getSpineItemFilesFromArchive.ts","../src/generators/manifest/hooks/epub/spineItems.ts","../src/generators/manifest/hooks/epub/epub.ts","../src/generators/manifest/hooks/epubOptimizer.ts","../src/generators/manifest/hooks/kobo.ts","../src/epubs/isArchiveEpub.ts","../src/generators/manifest/hooks/nonEpub.ts","../src/parsers/xml.ts","../src/parsers/nav.ts","../src/generators/manifest/hooks/toc.ts","../src/generators/manifest/index.ts","../src/generators/resources/hooks/calibreFixHook.ts","../src/generators/resources/hooks/cssFixHook.ts","../src/generators/resources/hooks/defaultHook.ts","../src/generators/resources/hooks/selfClosingTagsFixHook.ts","../src/generators/resources/index.ts","../src/archives/archiveLoader.ts","../src/Streamer.ts","../src/ServiceWorkerStreamer.ts"],"sourcesContent":["export const sortByTitleComparator = (a: string, b: string) => {\n const alist = a.split(/(\\d+)/)\n const blist = b.split(/(\\d+)/)\n\n for (let i = 0, len = alist.length; i < len; i++) {\n if (alist[i] !== blist[i]) {\n if (alist[i]?.match(/\\d/)) {\n return +(alist[i] || ``) - +(blist[i] || ``)\n }\n return (alist[i] || ``).localeCompare(blist[i] || ``)\n }\n }\n\n return 1\n}\n","export const getUriBasename = (uri: string) =>\n uri.substring(uri.lastIndexOf(`/`) + 1) || uri\n\nexport const removeTrailingSlash = (uri: string) =>\n uri.endsWith(\"/\") ? uri.slice(0, -1) : uri\n\nexport const getUriBasePath = (uri: string) => {\n const lastSlashIndex = uri.lastIndexOf(\"/\")\n\n return lastSlashIndex >= 0 ? uri.substring(0, lastSlashIndex) : \"\"\n}\n","import { sortByTitleComparator } from \"../utils/sortByTitleComparator\"\nimport { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\nexport const createArchiveFromArrayBufferList = async (\n list: {\n isDir: boolean\n name: string\n size: number\n data: () => Promise<ArrayBuffer>\n }[],\n { orderByAlpha, name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n let files = list\n\n if (orderByAlpha) {\n files = files.slice().sort((a, b) => sortByTitleComparator(a.name, b.name))\n }\n\n return {\n filename: name || ``,\n records: files.map((file) => ({\n dir: file.isDir,\n basename: getUriBasename(file.name),\n uri: file.name,\n blob: async () => new Blob([await file.data()]),\n string: async () => {\n const data = await file.data()\n return String.fromCharCode.apply(\n null,\n Array.from(new Uint16Array(data)),\n )\n },\n size: file.size,\n })),\n close: () => Promise.resolve(),\n }\n}\n","import { Report as SharedReport } from \"@prose-reader/shared\"\nimport { name } from \"../package.json\"\n\nexport const Report = SharedReport.namespace(name, false, {\n color: \"#ffae42\",\n})\n","interface TreeNode {\n [key: string]: TreeNode\n}\n\nexport const printTree = (paths: string[]): string => {\n // Split and collect all parts for tree reconstruction\n const tree: TreeNode = {}\n for (const path of paths) {\n const parts = path.split(\"/\")\n let node = tree\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (part === undefined) continue\n if (!node[part]) {\n node[part] = {}\n }\n node = node[part]\n }\n }\n\n // Recursively build the tree string\n const render = (node: TreeNode, indent = \"\"): string => {\n return Object.keys(node)\n .sort()\n .map((key, i, arr) => {\n const isLast = i === arr.length - 1\n const prefix = indent + (isLast ? \"└── \" : \"├── \")\n const nextIndent = indent + (isLast ? \" \" : \"│ \")\n const value = node[key]\n if (value && Object.keys(value).length > 0) {\n return `${prefix}${key}/\\n${render(value, nextIndent)}`\n }\n return `${prefix}${key}`\n })\n .join(\"\\n\")\n }\n\n return render(tree)\n}\n","import { Report } from \"../report\"\nimport { sortByTitleComparator } from \"../utils/sortByTitleComparator\"\nimport { getUriBasename } from \"../utils/uri\"\nimport { printTree } from \"./printTree\"\nimport type { Archive, StreamResult } from \"./types\"\n\ninterface OutputByType {\n base64: string\n string: string\n text: string\n binarystring: string\n array: number[]\n uint8array: Uint8Array\n arraybuffer: ArrayBuffer\n blob: Blob\n nodebuffer: Buffer\n}\n\ntype OutputType = keyof OutputByType\n\ninterface JSZipObject {\n name: string\n dir: boolean\n date: Date\n comment: string\n unixPermissions: number | string | null\n dosPermissions: number | null\n async<T extends OutputType>(type: T): Promise<OutputByType[T]>\n // nodeStream(type?: `nodebuffer`): NodeJS.ReadableStream;\n internalStream?: (type?: `uint8array`) => StreamResult\n}\n\ninterface JSZip {\n files: { [key: string]: JSZipObject }\n}\n\nexport const createArchiveFromJszip = async (\n jszip: JSZip,\n { orderByAlpha, name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n let files = Object.values(jszip.files)\n\n if (orderByAlpha) {\n files = files.slice().sort((a, b) => sortByTitleComparator(a.name, b.name))\n }\n\n const archive: Archive = {\n filename: name || ``,\n records: files.map((file) => ({\n dir: file.dir,\n basename: getUriBasename(file.name),\n uri: file.name,\n blob: () => file.async(`blob`),\n string: () => file.async(\"string\"),\n ...(file.internalStream && {\n stream: file.internalStream,\n }),\n // this is private API\n // @ts-expect-error\n size: file._data.uncompressedSize,\n })),\n close: () => Promise.resolve(),\n }\n\n Report.log(\"Generated archive\", archive)\n\n if (process.env.NODE_ENV === \"development\") {\n if (Report.isEnabled()) {\n const folderStructureStr = printTree(files.map((file) => file.name))\n Report.groupCollapsed(...Report.getGroupArgs(\"Archive folder structure\"))\n Report.log(`\\n${folderStructureStr}`)\n Report.groupEnd()\n }\n }\n\n return archive\n}\n","/**\n * @see https://github.com/nika-begiashvili/libarchivejs.\n *\n * Does not work in service worker due to usage of web worker.\n */\nimport { Report } from \"../report\"\nimport type { Archive } from \"./types\"\n\ninterface ArchiveReader {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n getFilesArray(): Promise<any[]>\n /**\n * Terminate worker to free up memory\n */\n close(): Promise<void>\n}\n\n/**\n * Represents compressed file before extraction\n */\ninterface CompressedFile {\n /**\n * File name\n */\n get name(): string\n /**\n * File size\n */\n get size(): number\n get lastModified(): number\n /**\n * Extract file from archive\n * @returns {Promise<File>} extracted file\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n extract(): any\n}\n\nexport const createArchiveFromLibArchive = async (\n libArchive: ArchiveReader,\n { name }: { orderByAlpha?: boolean; name?: string } = {},\n): Promise<Archive> => {\n const objArray = await libArchive.getFilesArray()\n\n const archive: Archive = {\n close: () => libArchive.close(),\n filename: name ?? ``,\n records: objArray.map((item: { file: CompressedFile; path: string }) => ({\n dir: false,\n basename: item.file.name,\n size: item.file.size,\n uri: `${item.path}${item.file.name}`,\n blob: async () => {\n const file = await (item.file.extract() as Promise<File>)\n\n return file\n },\n string: async () => {\n const file = await (item.file.extract() as Promise<File>)\n\n return file.text()\n },\n })),\n }\n\n Report.log(\"Generated archive\", archive)\n\n return archive\n}\n","import { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\n/**\n * Useful to create archive from txt content\n */\nexport const createArchiveFromText = async (\n content: string | Blob,\n {\n mimeType,\n direction,\n }: {\n direction?: `ltr` | `rtl`\n mimeType?: string\n } = { mimeType: \"text/plain\" },\n) => {\n const txtOpfContent = `\n <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" xml:lang=\"ja\" prefix=\"rendition: http://www.idpf.org/vocab/rendition/#\"\n unique-identifier=\"ootuya-id\">\n <metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n xmlns:dcterms=\"http://purl.org/dc/terms/\">\n <meta property=\"rendition:layout\">reflowable</meta>\n </metadata>\n <manifest>\n <item id=\"p01\" href=\"p01.txt\" media-type=\"text/plain\"/>\n </manifest>\n <spine page-progression-direction=\"${direction ?? `ltr`}\">\n <itemref idref=\"p01\" />\n </spine>\n </package>\n `\n\n const archive: Archive = {\n filename: `content.txt`,\n records: [\n {\n dir: false,\n basename: getUriBasename(`generated.opf`),\n uri: `generated.opf`,\n blob: async () => new Blob([txtOpfContent]),\n string: async () => txtOpfContent,\n size: 0,\n },\n {\n dir: false,\n basename: getUriBasename(`p01.txt`),\n uri: `p01.txt`,\n blob: async () => {\n if (typeof content === \"string\") return new Blob([content])\n return content\n },\n string: async () => {\n if (typeof content === \"string\") return content\n return content.text()\n },\n size: typeof content === \"string\" ? content.length : content.size,\n encodingFormat: mimeType,\n },\n ],\n close: () => Promise.resolve(),\n }\n\n return archive\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { getUriBasename } from \"../utils/uri\"\nimport type { Archive } from \"./types\"\n\n/**\n * @important\n * Make sure the urls are on the same origin or the cors header is set otherwise\n * the resource cannot be consumed as it is on the web.\n */\nexport const createArchiveFromUrls = async (\n urls: string[],\n options?: { useRenditionFlow: boolean },\n): Promise<Archive> => {\n const opfFileData = `\n <?xml version=\"1.0\" encoding=\"UTF-8\"?><package xmlns=\"http://www.idpf.org/2007/opf\" version=\"2.0\" unique-identifier=\"bookid\">\n <metadata>\n <meta property=\"rendition:layout\">${options?.useRenditionFlow ? `reflowable` : `pre-paginated`}</meta>\n ${options?.useRenditionFlow ? `<meta property=\"rendition:flow\">scrolled-continuous</meta>` : ``}\n </metadata>\n <manifest>\n ${urls\n .map(\n (url) =>\n `<item id=\"${getUriBasename(url)}\" href=\"${url}\" media-type=\"${detectMimeTypeFromName(url)}\"/>`,\n )\n .join(`\\n`)}\n </manifest>\n <spine>\n ${urls.map((url) => `<itemref idref=\"${getUriBasename(url)}\" />`).join(`\\n`)}\n </spine>\n </package>\n `\n\n const filesFromUrl: Archive[`records`] = urls.map((url) => ({\n dir: false,\n basename: getUriBasename(url),\n encodingFormat: detectMimeTypeFromName(url),\n uri: url,\n size: 100 / urls.length,\n blob: async () => {\n const response = await fetch(url)\n\n return response.blob()\n },\n string: async () => ``,\n }))\n\n const opfFile: Archive[`records`][number] = {\n dir: false,\n basename: `content.opf`,\n uri: `content.opf`,\n size: 0,\n blob: async () => new Blob(),\n string: async () => opfFileData,\n }\n\n return {\n filename: ``,\n records: [opfFile, ...filesFromUrl],\n close: () => Promise.resolve(),\n }\n}\n","import { Report } from \"./report\"\n\nexport const configure = ({\n enableReport,\n}: {\n enableReport?: boolean\n} = {}) => {\n Report.enable(!!enableReport)\n}\n","import type { Archive } from \"../archives/types\"\n\nexport const getArchiveOpfInfo = (archive: Archive) => {\n const filesAsArray = Object.values(archive.records).filter(\n (file) => !file.dir,\n )\n const file = filesAsArray.find((file) => file.uri.endsWith(`.opf`))\n\n return {\n data: file,\n basePath: file?.uri.substring(0, file.uri.lastIndexOf(`/`)) || ``,\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const apple =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const infoFile = archive.records.find(\n (file) =>\n file.basename.toLowerCase() === `com.apple.ibooks.display-options.xml`,\n )\n\n if (!infoFile || infoFile.dir) {\n return manifest\n }\n\n const content = await (await infoFile.blob()).text()\n\n try {\n const xmlDoc = new XmlDocument(content)\n const platformElement = xmlDoc.childNamed(`platform`)\n const fixedLayoutOption =\n platformElement\n ?.childrenNamed(\"option\")\n ?.find((option) => option.attr.name === \"fixed-layout\")?.val ||\n \"false\"\n\n return {\n ...manifest,\n renditionLayout:\n fixedLayoutOption === `true`\n ? `pre-paginated`\n : manifest.renditionLayout,\n }\n } catch (e) {\n console.error(\n \"Unable to parse com.apple.ibooks.display-options.xml for content\\n\",\n content,\n )\n console.error(e)\n\n return manifest\n }\n }\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"..\"\n\ntype KoboInformation = {\n renditionLayout?: `reflowable` | `pre-paginated` | undefined\n}\n\nexport const extractKoboInformationFromArchive = async (archive: Archive) => {\n const koboInformation: KoboInformation = {\n renditionLayout: undefined,\n }\n\n await Promise.all(\n archive.records.map(async (file) => {\n if (file.uri.endsWith(`com.kobobooks.display-options.xml`) && !file.dir) {\n const opfXmlDoc = new XmlDocument(await file.string())\n const optionElement = opfXmlDoc\n .childNamed(`platform`)\n ?.childNamed(`option`)\n if (\n optionElement?.attr?.name === `fixed-layout` &&\n optionElement.val === `true`\n ) {\n koboInformation.renditionLayout = `pre-paginated`\n }\n }\n }),\n )\n\n return koboInformation\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\nimport { extractKoboInformationFromArchive } from \"../../../parsers/kobo\"\n\n/**\n * Handle archive which contains ComicInfo.xml. This is a meta file\n * used to define cbz, etc. I believe it comes from some sites or apps.\n */\nexport const comicInfoHook =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const koboInformation = await extractKoboInformationFromArchive(archive)\n\n return {\n ...manifest,\n renditionLayout:\n manifest.renditionLayout ?? koboInformation.renditionLayout,\n }\n }\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const defaultHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (): Promise<Manifest> => {\n const files = Object.values(archive.records).filter((file) => !file.dir)\n\n return {\n filename: archive.filename,\n title:\n archive.records.find(({ dir }) => dir)?.basename.replace(/\\/$/, ``) ||\n archive.filename,\n renditionLayout: undefined,\n renditionSpread: `auto`,\n readingDirection: `ltr`,\n spineItems: files\n .filter((file) => !file.basename.endsWith(`.db`))\n .map((file, index) => {\n const hrefBaseUri = baseUrl\n ? baseUrl\n : /^https?:\\/\\//.test(file.uri)\n ? \"\"\n : \"file://\"\n\n return {\n // some books such as cbz can have same basename inside different sub folder\n // we need to make sure to have unique index\n // /chap01/01.png, /chap02/01.png, etc\n id: `${index}.${file.basename}`,\n index,\n href: encodeURI(`${hrefBaseUri}${file.uri}`),\n renditionLayout: undefined,\n progressionWeight: 1 / files.length,\n pageSpreadLeft: undefined,\n pageSpreadRight: undefined,\n mediaType: file.encodingFormat,\n }\n }),\n items: files.map((file, index) => ({\n id: `${index}.${file.basename}`,\n href: encodeURI(`${baseUrl}${file.uri}`),\n })),\n }\n }\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../archives/types\"\nimport { getArchiveOpfInfo } from \"./getArchiveOpfInfo\"\n\nexport const getSpineItemFilesFromArchive = async ({\n archive,\n}: {\n archive: Archive\n}) => {\n const { data: opsFile, basePath: opfBasePath } =\n getArchiveOpfInfo(archive) || {}\n\n const data = await opsFile?.string()\n\n if (!data) return []\n\n const _opfXmlDoc = new XmlDocument(data)\n\n const manifestElm = _opfXmlDoc.childNamed(`manifest`)\n const spineElm = _opfXmlDoc.childNamed(`spine`)\n\n const spineItemIds = spineElm\n ?.childrenNamed(`itemref`)\n .map((item) => item.attr.idref) as string[]\n const manifestItemsFromSpine =\n manifestElm\n ?.childrenNamed(`item`)\n .filter((item) => spineItemIds.includes(item.attr.id || ``)) || []\n\n const archiveSpineItems = archive.records.filter((file) => {\n return manifestItemsFromSpine.find((item) => {\n if (!opfBasePath) return `${item.attr.href}` === file.uri\n return `${opfBasePath}/${item.attr.href}` === file.uri\n })\n })\n\n return archiveSpineItems\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { XmlElement } from \"xmldoc\"\n\nexport type SpineItemProperties =\n // @see https://www.w3.org/TR/epub/#layout-overrides\n | `rendition:layout-reflowable`\n // @se https://www.w3.org/TR/epub/#layout-overrides\n | `rendition:layout-pre-paginated`\n | `page-spread-left`\n | `page-spread-right`\n\nexport const getSpineItemInfo = (\n itemRefElement: XmlElement,\n): Partial<Manifest[\"spineItems\"][number]> => {\n /**\n * @see https://www.w3.org/TR/epub/#attrdef-properties\n */\n const properties = (itemRefElement.attr.properties?.split(` `) ||\n []) as SpineItemProperties[]\n\n let renditionLayout: Manifest[\"spineItems\"][number][\"renditionLayout\"]\n\n if (\n properties.find((property) => property === `rendition:layout-reflowable`)\n ) {\n renditionLayout = `reflowable`\n }\n\n if (\n properties.find((property) => property === `rendition:layout-pre-paginated`)\n ) {\n renditionLayout = `pre-paginated`\n }\n\n return {\n renditionLayout,\n pageSpreadLeft:\n properties.some((property) => property === `page-spread-left`) ||\n undefined,\n pageSpreadRight:\n properties.some((property) => property === `page-spread-right`) ||\n undefined,\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument, type XmlElement } from \"xmldoc\"\nimport type { Archive } from \"../../../../archives/types\"\nimport { getArchiveOpfInfo } from \"../../../../epubs/getArchiveOpfInfo\"\nimport { getSpineItemFilesFromArchive } from \"../../../../epubs/getSpineItemFilesFromArchive\"\nimport { Report } from \"../../../../report\"\nimport { getSpineItemInfo } from \"./spineItems\"\n\nconst getItemFromElement = (\n element: XmlElement,\n opfBasePath: string,\n getBaseUrl?: (element: XmlElement) => string,\n) => {\n const href = element.attr.href || ``\n const baseUrl = getBaseUrl?.(element)\n\n return {\n href: opfBasePath\n ? `${baseUrl}${opfBasePath}/${href}`\n : `${baseUrl}${href}`,\n id: element.attr.id || ``,\n mediaType: element.attr[`media-type`],\n }\n}\n\nexport const getItemsFromDoc = (\n doc: XmlDocument,\n archive: Archive,\n getBaseUrl?: (element: XmlElement) => string,\n) => {\n const manifestElm = doc.childNamed(`manifest`)\n const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {}\n\n return (\n manifestElm\n ?.childrenNamed(`item`)\n ?.map((el) => getItemFromElement(el, opfBasePath, getBaseUrl)) || []\n )\n}\n\nexport const epubHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const { data: opsFile, basePath: opfBasePath } =\n getArchiveOpfInfo(archive) || {}\n\n if (!opsFile) {\n return manifest\n }\n\n const data = await opsFile.string()\n\n Report.groupCollapsed(...Report.getGroupArgs(\"OPF data\"))\n Report.log(`data`, data)\n Report.groupEnd()\n\n const opfXmlDoc = new XmlDocument(data)\n\n const metadataElm = opfXmlDoc.childNamed(`metadata`)\n const manifestElm = opfXmlDoc.childNamed(`manifest`)\n const spineElm = opfXmlDoc.childNamed(`spine`)\n const guideElm = opfXmlDoc.childNamed(`guide`)\n const titleElm = metadataElm?.childNamed(`dc:title`)\n const metaElmChildren = metadataElm?.childrenNamed(`meta`) || []\n const metaElmWithRendition = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:layout`,\n )\n const metaElmWithRenditionFlow = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:flow`,\n )\n const metaElmWithRenditionSpread = metaElmChildren.find(\n (meta) => meta.attr.property === `rendition:spread`,\n )\n\n const publisherRenditionLayout = metaElmWithRendition?.val as\n | `reflowable`\n | `pre-paginated`\n | undefined\n const publisherRenditionFlow = metaElmWithRenditionFlow?.val as\n | `scrolled-continuous`\n | `scrolled-doc`\n | `paginated`\n | `auto`\n | undefined\n const renditionSpread = metaElmWithRenditionSpread?.val as\n | `auto`\n | undefined\n\n const title =\n titleElm?.val || archive.records.find(({ dir }) => dir)?.basename || ``\n const pageProgressionDirection = spineElm?.attr[\n `page-progression-direction`\n ] as `ltr` | `rtl` | undefined\n\n const archiveSpineItems = await getSpineItemFilesFromArchive({ archive })\n\n const totalSize = archiveSpineItems.reduce(\n (size, file) => file.size + size,\n 0,\n )\n\n return {\n filename: archive.filename,\n renditionLayout: publisherRenditionLayout,\n renditionFlow: publisherRenditionFlow || `auto`,\n renditionSpread,\n title,\n readingDirection: pageProgressionDirection || `ltr`,\n /**\n * @see https://www.w3.org/TR/epub/#sec-itemref-elem\n */\n spineItems:\n spineElm?.childrenNamed(`itemref`).map((itemrefElm, index) => {\n const manifestItem = manifestElm\n ?.childrenNamed(`item`)\n .find((item) => item.attr.id === itemrefElm?.attr.idref)\n const href = manifestItem?.attr.href || ``\n const itemSize =\n archive.records.find((file) => file.uri.endsWith(href))?.size || 0\n\n const hrefBaseUri = baseUrl\n ? baseUrl\n : /^https?:\\/\\//.test(href)\n ? \"\"\n : \"file://\"\n\n const spineItemInfo = getSpineItemInfo(itemrefElm)\n\n return {\n ...spineItemInfo,\n id: manifestItem?.attr.id || ``,\n index,\n href: manifestItem?.attr.href?.startsWith(`https://`)\n ? manifestItem?.attr.href\n : opfBasePath\n ? `${hrefBaseUri}${opfBasePath}/${manifestItem?.attr.href}`\n : `${hrefBaseUri}${manifestItem?.attr.href}`,\n renditionLayout:\n spineItemInfo.renditionLayout ?? publisherRenditionLayout,\n progressionWeight: itemSize / totalSize,\n // size: itemSize\n mediaType: manifestItem?.attr[`media-type`],\n }\n }) || [],\n items: getItemsFromDoc(opfXmlDoc, archive, (element) => {\n const href = element.attr.href || ``\n\n if (/^https?:\\/\\//.test(href)) {\n return \"\"\n }\n\n return baseUrl || \"file://\"\n }),\n guide: guideElm?.childrenNamed(`reference`).map((elm) => {\n return {\n href: elm.attr.href || ``,\n title: elm.attr.title || ``,\n type: elm.attr.type as NonNullable<Manifest[`guide`]>[number][`type`],\n }\n }),\n }\n }\n","import { type Manifest, isXmlBasedMimeType } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport { getSpineItemFilesFromArchive } from \"../../../epubs/getSpineItemFilesFromArchive\"\n\nconst hasDocMetaViewport = (doc: XmlDocument) => {\n const metaElm = doc\n .descendantWithPath(\"head\")\n ?.childrenNamed(\"meta\")\n .find((node) => node.attr.name === \"viewport\")\n\n return !!(metaElm && metaElm.attr.name === \"viewport\")\n}\n\nconst allFilesHaveViewportMeta = (files: Archive[\"records\"]) =>\n files.reduce(async (result, current) => {\n const _result = await result\n\n if (!_result) return false\n\n if (\n !isXmlBasedMimeType({\n mimeType: current.encodingFormat,\n uri: current.uri,\n })\n ) {\n return false\n }\n\n const file = current.dir ? null : await current.string()\n\n if (!file) return false\n\n return hasDocMetaViewport(new XmlDocument(file))\n }, Promise.resolve(true))\n\nexport const epubOptimizerHook =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const bookIsFullReflowable =\n manifest.renditionLayout === \"reflowable\" &&\n manifest.spineItems.every((item) => item.renditionLayout === \"reflowable\")\n\n if (bookIsFullReflowable) {\n const files = await getSpineItemFilesFromArchive({ archive })\n\n const hasAllViewport = await allFilesHaveViewportMeta(files)\n\n if (hasAllViewport) {\n return {\n ...manifest,\n spineItems: manifest.spineItems.map((item) => ({\n ...item,\n renditionLayout: \"pre-paginated\",\n })),\n renditionLayout: \"pre-paginated\",\n }\n }\n }\n\n return manifest\n }\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\n\nexport const kobo =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const comicInfoFile = archive.records.find(\n (file) => file.basename.toLowerCase() === `comicinfo.xml` && !file.dir,\n )\n\n if (!comicInfoFile || comicInfoFile.dir) {\n return manifest\n }\n\n const manifestWithoutComicInfo = {\n ...manifest,\n spineItems: manifest.spineItems\n .filter((item) => !item.id.toLowerCase().endsWith(`comicinfo.xml`))\n .map((item, _, items) => ({\n ...item,\n progressionWeight: 1 / items.length,\n })),\n }\n\n // @todo handle more meta\n const content = await comicInfoFile.string()\n\n try {\n const xmlDoc = new XmlDocument(content)\n\n const mangaVal =\n (xmlDoc.childNamed(`Manga`)?.val as `YesAndRightToLeft`) || `unknown`\n\n return {\n ...manifestWithoutComicInfo,\n readingDirection: mangaVal === `YesAndRightToLeft` ? `rtl` : `ltr`,\n }\n } catch (e) {\n console.error(\"Unable to parse comicinfo.xml for content\\n\", content)\n console.error(e)\n\n return manifestWithoutComicInfo\n }\n }\n","import type { Archive } from \"../archives/types\"\n\nexport const isArchiveEpub = (archive: Archive) => {\n return archive.records.some((file) => file.basename.endsWith(`.opf`))\n}\n","import {\n detectMimeTypeFromName,\n type Manifest,\n parseContentType,\n} from \"@prose-reader/shared\"\nimport type { Archive } from \"../../../archives/types\"\nimport { isArchiveEpub } from \"../../../epubs/isArchiveEpub\"\n\n/**\n * If we don't have a regular epub, we have an archive that could be many things.\n * We try to refine the manifest based on the type of content as much as possible.\n */\nexport const nonEpub =\n ({ archive }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n const isEpub = isArchiveEpub(archive)\n\n if (isEpub) return manifest\n\n return {\n ...manifest,\n spineItems: manifest.spineItems.map((spineItem) => {\n const archiveItem = archive.records.find((item) =>\n decodeURI(spineItem.href).endsWith(item.uri),\n )\n\n const mimeType =\n parseContentType(archiveItem?.encodingFormat ?? \"\") ??\n detectMimeTypeFromName(archiveItem?.basename ?? \"\")\n\n return {\n ...spineItem,\n renditionLayout: mimeType?.startsWith(`image/`)\n ? `pre-paginated`\n : spineItem.renditionLayout,\n }\n }),\n }\n }\n","import { XmlTextNode } from \"xmldoc\"\n\nimport { XmlElement } from \"xmldoc\"\n\nexport const getXmlElementInnerText = (\n node: XmlElement | undefined,\n): string => {\n if (!node) return \"\"\n\n return node.children\n .map((child) => {\n if (child instanceof XmlTextNode) return child.text\n if (child instanceof XmlElement) return getXmlElementInnerText(child)\n return \"\"\n })\n .join(\"\")\n .trim()\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { urlJoin } from \"@prose-reader/shared\"\nimport { XmlDocument, type XmlElement, type XmlNodeBase } from \"xmldoc\"\nimport { type Archive, getArchiveOpfInfo } from \"..\"\nimport { getUriBasePath } from \"../utils/uri\"\nimport { getXmlElementInnerText } from \"./xml\"\n\ntype Toc = NonNullable<Manifest[`nav`]>[`toc`]\ntype TocItem = NonNullable<Manifest[`nav`]>[`toc`][number]\n\n/**\n * @see https://www.w3.org/TR/epub-33/#sec-nav-def-model\n */\nconst extractNavChapter = (\n li: XmlElement,\n { basePath, baseUrl }: { basePath: string; baseUrl: string },\n) => {\n const chp: TocItem = {\n contents: [],\n path: ``,\n href: ``,\n title: ``,\n }\n\n let contentNode = li.childNamed(`span`) || li.childNamed(`a`)\n\n chp.title =\n (contentNode?.attr.title ||\n contentNode?.val.trim() ||\n getXmlElementInnerText(contentNode)) ??\n ``\n\n let node = contentNode?.name\n\n if (node !== `a`) {\n contentNode = li.descendantWithPath(`${node}.a`)\n if (contentNode) {\n node = contentNode.name.toLowerCase()\n }\n }\n\n if (node === `a` && contentNode?.attr.href) {\n chp.path = urlJoin(basePath, contentNode.attr.href)\n chp.href = urlJoin(baseUrl, basePath, contentNode.attr.href)\n }\n const sublistNode = li.childNamed(`ol`)\n if (sublistNode) {\n const children = sublistNode.childrenNamed(`li`)\n if (children && children.length > 0) {\n chp.contents = children.map((child) =>\n extractNavChapter(child, { basePath, baseUrl }),\n )\n }\n }\n\n return chp\n}\n\nconst buildTOCFromNav = (\n doc: XmlDocument,\n { basePath, baseUrl }: { basePath: string; baseUrl: string },\n) => {\n const toc: Toc = []\n\n let navDataChildren: XmlNodeBase[] | undefined\n\n if (doc.descendantWithPath(`body.nav.ol`)) {\n navDataChildren = doc.descendantWithPath(`body.nav.ol`)?.children\n } else if (doc.descendantWithPath(`body.section.nav.ol`)) {\n navDataChildren = doc.descendantWithPath(`body.section.nav.ol`)?.children\n }\n\n if (navDataChildren && navDataChildren.length > 0) {\n navDataChildren\n .filter((li) => (li as XmlElement).name === `li`)\n .forEach((li) => {\n toc.push(extractNavChapter(li as XmlElement, { basePath, baseUrl }))\n })\n }\n\n return toc\n}\n\nconst parseTocFromNavPath = async (\n opfXmlDoc: XmlDocument,\n archive: Archive,\n { baseUrl }: { baseUrl: string },\n) => {\n // Try to detect if there is a nav item\n const navItem = opfXmlDoc\n .childNamed(`manifest`)\n ?.childrenNamed(`item`)\n .find((child) => child.attr.properties === `nav`)\n\n if (navItem) {\n const tocFile = Object.values(archive.records).find((item) =>\n item.uri.endsWith(navItem.attr.href || ``),\n )\n\n if (tocFile && !tocFile.dir) {\n const doc = new XmlDocument(await tocFile.string())\n\n const tocFileBasePath = getUriBasePath(tocFile.uri)\n\n /**\n * links inside toc.xhtml are relative to the toc.xhtml file,\n * not the opf file anymore\n */\n return buildTOCFromNav(doc, { basePath: tocFileBasePath, baseUrl })\n }\n }\n}\n\nconst mapNcxChapter = (\n point: XmlElement,\n {\n opfBasePath,\n baseUrl,\n prefix,\n }: { opfBasePath: string; baseUrl: string; prefix: string },\n) => {\n const src = point?.childNamed(`${prefix}content`)?.attr.src || ``\n\n const out: TocItem = {\n title:\n point?.descendantWithPath(`${prefix}navLabel.${prefix}text`)?.val || ``,\n path: urlJoin(opfBasePath, src),\n href: urlJoin(baseUrl, opfBasePath, src),\n contents: [],\n }\n const children = point.childrenNamed(`${prefix}navPoint`)\n if (children && children.length > 0) {\n out.contents = children.map((pt) =>\n mapNcxChapter(pt, { opfBasePath, baseUrl, prefix }),\n )\n }\n\n return out\n}\n\nconst buildTOCFromNCX = (\n ncxData: XmlDocument,\n { opfBasePath, baseUrl }: { opfBasePath: string; baseUrl: string },\n) => {\n const toc: NonNullable<Manifest[`nav`]>[`toc`] = []\n\n const rootTagName = ncxData.name\n let prefix = ``\n if (rootTagName.indexOf(`:`) !== -1) {\n prefix = `${rootTagName.split(`:`)[0]}:`\n }\n\n ncxData\n .childNamed(`${prefix}navMap`)\n ?.childrenNamed(`${prefix}navPoint`)\n .forEach((point) => {\n toc.push(mapNcxChapter(point, { opfBasePath, baseUrl, prefix }))\n })\n\n return toc\n}\n\nconst parseTocFromNcx = async ({\n opfData,\n opfBasePath,\n baseUrl,\n archive,\n}: {\n opfData: XmlDocument\n opfBasePath: string\n archive: Archive\n baseUrl: string\n}) => {\n const spine = opfData.childNamed(`spine`)\n const ncxId = spine?.attr.toc\n\n if (ncxId) {\n const ncxItem = opfData\n .childNamed(`manifest`)\n ?.childrenNamed(`item`)\n .find((item) => item.attr.id === ncxId)\n\n if (ncxItem) {\n const ncxPath = `${opfBasePath}${opfBasePath === `` ? `` : `/`}${ncxItem.attr.href}`\n\n const file = Object.values(archive.records).find((item) =>\n item.uri.endsWith(ncxPath),\n )\n\n if (file && !file.dir) {\n const ncxData = new XmlDocument(await file.string())\n\n return buildTOCFromNCX(ncxData, { opfBasePath, baseUrl })\n }\n }\n }\n}\n\nexport const parseToc = async (\n opfXmlDoc: XmlDocument,\n archive: Archive,\n { baseUrl }: { baseUrl: string },\n) => {\n const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {}\n\n const tocFromNav = await parseTocFromNavPath(opfXmlDoc, archive, {\n baseUrl,\n })\n\n if (tocFromNav) {\n return tocFromNav\n }\n\n const tocFromNcx = await parseTocFromNcx({\n opfData: opfXmlDoc,\n opfBasePath,\n archive,\n baseUrl,\n })\n\n if (tocFromNcx) {\n return tocFromNcx\n }\n}\n","import { type Manifest, urlJoin } from \"@prose-reader/shared\"\nimport { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport { getArchiveOpfInfo } from \"../../../epubs/getArchiveOpfInfo\"\nimport { parseToc } from \"../../../parsers/nav\"\nimport { sortByTitleComparator } from \"../../../utils/sortByTitleComparator\"\n\ntype Toc = NonNullable<Manifest[\"nav\"]>[\"toc\"]\ntype TocItem = NonNullable<Manifest[\"nav\"]>[\"toc\"][number]\n\nconst buildFolderFallbackToc = (\n archive: Archive,\n { baseUrl }: { baseUrl: string },\n): Toc => {\n const filesSortedByAlpha = [...archive.records].sort((a, b) =>\n sortByTitleComparator(a.uri, b.uri),\n )\n\n const combineWith = (\n toc: TocItem[],\n folder: string,\n subFolders: string[],\n href: string,\n path: string,\n ): TocItem[] => {\n const foundEntry = toc.find((entry) => entry.title === folder)\n const [nextFolderCursor, ...nextSubFolders] = subFolders\n\n if (foundEntry) {\n if (nextFolderCursor) {\n return [\n ...toc.filter((entry) => entry !== foundEntry),\n {\n ...foundEntry,\n contents: [\n ...foundEntry.contents,\n ...combineWith(\n foundEntry.contents,\n nextFolderCursor,\n nextSubFolders,\n href,\n path,\n ),\n ],\n } satisfies TocItem,\n ]\n }\n\n const previousRegisteredPathWasLonger =\n foundEntry.path.split(\"/\").length > path.split(\"/\").length\n\n if (previousRegisteredPathWasLonger) {\n return [\n ...toc.filter((entry) => entry !== foundEntry),\n {\n ...foundEntry,\n path,\n href,\n } satisfies TocItem,\n ]\n }\n\n return toc\n }\n\n if (nextFolderCursor) {\n return [\n ...toc,\n {\n contents: combineWith(\n [],\n nextFolderCursor,\n nextSubFolders,\n href,\n path,\n ),\n href,\n path,\n title: folder,\n },\n ]\n }\n\n return [\n ...toc,\n {\n contents: [],\n href,\n path,\n title: folder,\n },\n ]\n }\n\n return filesSortedByAlpha.reduce((acc, file) => {\n if (file.dir) return acc\n\n const folders = file.uri.split(\"/\").slice(0, -1)\n const [firstFolder, ...restFolders] = folders\n\n if (!firstFolder) return acc\n\n const href = urlJoin(baseUrl, encodeURI(file.uri)).replace(/\\/$/, \"\")\n const path = file.uri.replace(/\\/$/, \"\")\n\n return combineWith(acc, firstFolder, restFolders, href, path)\n }, [] as Toc)\n}\n\nconst resolveTocFromArchive = async (\n archive: Archive,\n { baseUrl }: { baseUrl: string },\n): Promise<Toc | undefined> => {\n const { data: opfFile } = getArchiveOpfInfo(archive) || {}\n\n if (opfFile && !opfFile.dir) {\n const opfXmlDoc = new XmlDocument(await opfFile.string())\n const toc = await parseToc(opfXmlDoc, archive, { baseUrl })\n\n // Keep explicit empty TOC for EPUB-like inputs even when there is no nav file.\n return toc || []\n }\n\n const toc = buildFolderFallbackToc(archive, { baseUrl })\n\n if (toc.length === 0) {\n return undefined\n }\n\n return toc\n}\n\n/**\n * Resolve the table of contents from a single entry point.\n * Internally handles EPUB nav, NCX, and folder fallback.\n */\nexport const tocHook =\n ({ archive, baseUrl }: { archive: Archive; baseUrl: string }) =>\n async (manifest: Manifest): Promise<Manifest> => {\n if (manifest.nav) return manifest\n\n const toc = await resolveTocFromArchive(archive, { baseUrl })\n if (!toc) return manifest\n\n return {\n ...manifest,\n nav: {\n toc,\n },\n }\n }\n","import type { Archive } from \"../../archives/types\"\nimport { Report } from \"../../report\"\nimport { apple } from \"./hooks/apple\"\nimport { comicInfoHook } from \"./hooks/comicInfo\"\nimport { defaultHook } from \"./hooks/default\"\nimport { epubHook } from \"./hooks/epub/epub\"\nimport { epubOptimizerHook } from \"./hooks/epubOptimizer\"\nimport { kobo } from \"./hooks/kobo\"\nimport { nonEpub } from \"./hooks/nonEpub\"\nimport { tocHook } from \"./hooks/toc\"\n\nexport const generateManifestFromArchive = async (\n archive: Archive,\n { baseUrl = `` }: { baseUrl?: string } = {},\n) => {\n const hooks = [\n epubHook({ archive, baseUrl }),\n kobo({ archive, baseUrl }),\n apple({ archive, baseUrl }),\n nonEpub({ archive, baseUrl }),\n epubOptimizerHook({ archive, baseUrl }),\n comicInfoHook({ archive, baseUrl }),\n tocHook({ archive, baseUrl }),\n ]\n\n try {\n const baseManifestPromise = defaultHook({ archive, baseUrl })()\n\n const manifest = await hooks.reduce(async (manifest, gen) => {\n return await gen(await manifest)\n }, baseManifestPromise)\n\n Report.log(\"Generated manifest\", manifest)\n\n if (process.env.NODE_ENV === \"development\") {\n if (Report.isEnabled()) {\n const manifestStr = JSON.stringify(manifest, null, 2)\n Report.groupCollapsed(...Report.getGroupArgs(\"Generated manifest\"))\n Report.log(`\\n${manifestStr}`)\n Report.groupEnd()\n }\n }\n\n return manifest\n } catch (e) {\n Report.error(e)\n\n throw e\n }\n}\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nconst hasCalibreCoverMeta = (doc: XmlDocument) => {\n const metaElm = doc\n .descendantWithPath(\"head\")\n ?.childrenNamed(\"meta\")\n .find((node) => node.attr.name === \"calibre:cover\")\n\n return !!(metaElm && metaElm.attr.name === \"calibre:cover\")\n}\n\nconst getBuggyCoverSvg = (doc: XmlDocument) => {\n return doc\n .descendantWithPath(\"body\")\n ?.descendantWithPath(\"div\")\n ?.childrenNamed(\"svg\")\n ?.find(\n (node) =>\n node.attr.width === \"100%\" && node.attr.preserveAspectRatio === \"none\",\n )\n}\n\nconst fixBuggyCover =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.xhtml`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n const opfXmlDoc = new XmlDocument(bodyToParse)\n\n if (hasCalibreCoverMeta(opfXmlDoc)) {\n const buggySvg = getBuggyCoverSvg(opfXmlDoc)\n\n if (buggySvg) {\n delete buggySvg.attr.preserveAspectRatio\n }\n\n return {\n ...resource,\n body: opfXmlDoc?.toString(),\n }\n }\n }\n\n return resource\n }\n\nexport const calibreFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n return fixBuggyCover({ archive, resourcePath })(resource)\n }\n","import type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nexport const cssFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.css`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n /**\n * Fix the potentially invalid writing mode present on some vertical book.\n * This has the benefit of making it compatible with firefox as well.\n */\n const newBody = bodyToParse.replaceAll(\n `-webkit-writing-mode`,\n `writing-mode`,\n )\n\n return {\n ...resource,\n body: newBody,\n }\n }\n\n return resource\n }\n","import { XmlDocument } from \"xmldoc\"\nimport type { Archive } from \"../../../archives/types\"\nimport { getArchiveOpfInfo } from \"../../../epubs/getArchiveOpfInfo\"\nimport { getItemsFromDoc } from \"../../manifest/hooks/epub/epub\"\nimport type { HookResource } from \"./types\"\n\n/**\n * We are trying to metadata from opf file in epub archive.\n *\n * Otherwise we fallback on what we can know from the archive.\n */\nconst getMetadata = async (archive: Archive, resourcePath: string) => {\n const opfInfo = getArchiveOpfInfo(archive)\n const data = await opfInfo.data?.string()\n\n if (data) {\n const opfXmlDoc = new XmlDocument(data)\n const items = getItemsFromDoc(opfXmlDoc, archive, () => \"\")\n\n // we are comparing opf items relative absolute path in epub archive\n // against resourcePatch (which are absolute path in archive).\n // They should in theory match.\n const foundMediaType = items.find((item) =>\n resourcePath.endsWith(item.href),\n )?.mediaType\n\n if (foundMediaType) {\n return {\n mediaType: items.find((item) => resourcePath.endsWith(item.href))\n ?.mediaType,\n }\n }\n }\n\n return {\n mediaType: getContentTypeFromExtension(resourcePath),\n }\n}\n\nconst getContentTypeFromExtension = (uri: string) => {\n if (uri.endsWith(`.css`)) {\n return `text/css; charset=UTF-8`\n }\n if (uri.endsWith(`.jpg`)) {\n return `image/jpg`\n }\n if (uri.endsWith(`.xhtml`)) {\n return `application/xhtml+xml`\n }\n if (uri.endsWith(`.mp4`)) {\n return `video/mp4`\n }\n if (uri.endsWith(`.svg`)) {\n return `image/svg+xml`\n }\n}\n\nexport const defaultHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (!file || file.dir) return resource\n\n // if (file.stream) {\n // const stream = file.stream()\n\n // console.log(file, stream)\n // stream.on(`data`, data => {\n // console.log(`data`, data)\n // })\n // stream.on(`error`, data => {\n // console.error(`error`, data)\n // })\n // stream.on(`end`, () => {\n // console.log(`end`)\n // })\n\n // }\n\n // const stream = file.stream!()\n\n // const readableStream = new ReadableStream({\n // start(controller) {\n // function push() {\n // stream.on(`data`, data => {\n // controller.enqueue(data)\n // })\n // stream.on(`error`, data => {\n // console.error(`error`, data)\n // })\n // stream.on(`end`, () => {\n // controller.close()\n // })\n\n // stream.resume()\n // }\n\n // push();\n // }\n // })\n\n const metadata = await getMetadata(archive, resourcePath)\n\n return {\n ...resource,\n params: {\n ...resource.params,\n ...(file?.encodingFormat && {\n contentType: file.encodingFormat,\n }),\n ...(metadata.mediaType && {\n contentType: metadata.mediaType,\n }),\n },\n }\n }\n","import type { Archive } from \"../../../archives/types\"\nimport type { HookResource } from \"./types\"\n\nconst invalidSelfClosingTags = [\n \"div\",\n \"span\",\n \"p\",\n \"a\",\n \"li\",\n \"ul\",\n \"ol\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"table\",\n \"tr\",\n \"td\",\n \"th\",\n \"thead\",\n \"tbody\",\n \"tfoot\",\n \"section\",\n \"article\",\n \"header\",\n \"footer\",\n \"nav\",\n \"aside\",\n \"main\",\n \"figure\",\n \"figcaption\",\n \"blockquote\",\n \"pre\",\n \"code\",\n \"form\",\n \"textarea\",\n \"select\",\n \"option\",\n \"button\",\n \"label\",\n \"fieldset\",\n \"legend\",\n \"caption\",\n \"dl\",\n \"dt\",\n \"dd\",\n \"iframe\",\n \"video\",\n \"audio\",\n \"canvas\",\n \"script\",\n \"style\",\n]\n\n/**\n * Some books uses xhtml files but also includes wrong self closin tags. This happens\n * a lot with kobo epub which have a lot of self closing <script ... />. This breaks on some\n * browser such as webkit. We use a regex to replace and fix them. There\n * is a first lighter regex which check if any such tag exist in the first place before running\n * the full replace regex empty.\n */\nexport const selfClosingTagsFixHook =\n ({ archive, resourcePath }: { archive: Archive; resourcePath: string }) =>\n async (resource: HookResource): Promise<HookResource> => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (file && !file.dir && file.basename.endsWith(`.xhtml`)) {\n const bodyToParse = resource.body ?? (await file.string())\n\n const tagCheckPattern = new RegExp(\n `<(${invalidSelfClosingTags.join(\"|\")})[\\\\s/>]`,\n \"i\",\n )\n if (!tagCheckPattern.test(bodyToParse)) {\n return resource\n }\n\n const tagPattern = new RegExp(\n `<(${invalidSelfClosingTags.join(\"|\")})(\\\\s[^>]*)?\\\\s*/>`,\n \"gi\",\n )\n\n const fixedBody = bodyToParse.replace(\n tagPattern,\n (_, tagName, attributes = \"\") => {\n // Convert to an opening and closing tag\n return `<${tagName} ${attributes.trim()}></${tagName}>`\n },\n )\n\n return {\n ...resource,\n body: fixedBody,\n }\n }\n\n return resource\n }\n","import type { Archive } from \"../..\"\nimport { Report } from \"../../report\"\nimport { calibreFixHook } from \"./hooks/calibreFixHook\"\nimport { cssFixHook } from \"./hooks/cssFixHook\"\nimport { defaultHook } from \"./hooks/defaultHook\"\nimport { selfClosingTagsFixHook } from \"./hooks/selfClosingTagsFixHook\"\nimport type { HookResource } from \"./hooks/types\"\n\nexport const generateResourceFromArchive = async (\n archive: Archive,\n resourcePath: string,\n) => {\n const file = Object.values(archive.records).find(\n (file) => file.uri === resourcePath && !file.dir,\n )\n\n if (!file || file.dir) {\n throw new Error(`no file found for resourcePath:${resourcePath}`)\n }\n\n const defaultResource: HookResource = {\n params: {},\n }\n\n const hooks = [\n defaultHook({ archive, resourcePath }),\n selfClosingTagsFixHook({ archive, resourcePath }),\n cssFixHook({ archive, resourcePath }),\n calibreFixHook({ archive, resourcePath }),\n ]\n\n try {\n const resource = await hooks.reduce(async (manifest, gen) => {\n return await gen(await manifest)\n }, Promise.resolve(defaultResource))\n\n Report.log(\"Generated resource\", resourcePath, resource)\n\n return {\n ...resource,\n body: resource.body ?? (await file.blob()),\n }\n } catch (e) {\n Report.error(e)\n\n throw e\n }\n}\n","import {\n BehaviorSubject,\n EMPTY,\n NEVER,\n type ObservedValueOf,\n Subject,\n catchError,\n distinctUntilChanged,\n filter,\n first,\n from,\n ignoreElements,\n map,\n merge,\n mergeMap,\n pairwise,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n timer,\n} from \"rxjs\"\nimport { Report } from \"../report\"\nimport type { Archive } from \"./types\"\n\nclass ArchiveEntry {\n state$ = new BehaviorSubject<{\n status: \"idle\" | \"loading\" | \"success\" | \"error\"\n error?: unknown | undefined\n archive?: undefined | Archive\n locks: number\n }>({\n status: `idle`,\n locks: 0,\n })\n\n constructor(private cleanArchiveAfter: number) {}\n\n update(update: Partial<ObservedValueOf<typeof this.state$>>) {\n this.state$.next({ ...this.state$.getValue(), ...update })\n }\n\n get locks$() {\n return this.state$.pipe(map(({ locks }) => locks))\n }\n\n get state() {\n return this.state$.getValue()\n }\n\n get isUnlocked$() {\n return this.locks$.pipe(\n map((locks) => locks <= 0),\n distinctUntilChanged(),\n shareReplay(),\n )\n }\n\n get overTTL$() {\n return this.isUnlocked$.pipe(\n switchMap((isUnlocked) =>\n !isUnlocked\n ? NEVER\n : this.cleanArchiveAfter === Infinity\n ? NEVER\n : timer(this.cleanArchiveAfter),\n ),\n )\n }\n}\n\nexport const createArchiveLoader = ({\n getArchive,\n cleanArchiveAfter = 5 * 60 * 1000, // 5mn\n}: {\n getArchive: (key: string) => Promise<Archive>\n cleanArchiveAfter?: number\n}) => {\n const loadSubject = new Subject<string>()\n const destroySubject = new Subject<void>()\n const purgeSubject = new Subject<void>()\n const archives: Record<string, ArchiveEntry> = {}\n\n const loadArchive$ = loadSubject.pipe(\n mergeMap((key) => {\n const archiveEntry = archives[key]\n\n if (!archiveEntry || archiveEntry.state.status !== \"idle\") return EMPTY\n\n let isClosed = false\n\n const cleanupArchive = (key: string) => {\n Report.debug(`Cleaning up archive with key: ${key}`)\n\n const entry = archives[key]\n\n delete archives[key]\n\n if (!isClosed) {\n entry?.state.archive?.close()\n isClosed = true\n }\n }\n\n archiveEntry.update({\n status: \"loading\",\n })\n\n const locks$ = archiveEntry.locks$\n const isUnlocked$ = archiveEntry.isUnlocked$\n\n const newAccess$ = locks$.pipe(\n pairwise(),\n filter(([prev, curent]) => curent > prev),\n startWith(true),\n )\n\n const archive$ = from(getArchive(key))\n\n return archive$.pipe(\n tap((archive) => {\n archiveEntry.update({\n archive,\n status: \"success\",\n })\n }),\n catchError((error) => {\n cleanupArchive(key)\n\n archiveEntry.update({\n status: \"error\",\n error,\n })\n\n return EMPTY\n }),\n switchMap(() => {\n const readyForPurge$ = newAccess$.pipe(\n switchMap(() => purgeSubject),\n switchMap(() => isUnlocked$),\n filter((isUnlocked) => isUnlocked),\n )\n\n const toCleanup$ = merge(readyForPurge$, archiveEntry.overTTL$)\n\n return toCleanup$.pipe(\n first(),\n tap(() => {\n cleanupArchive(key)\n }),\n )\n }),\n )\n }),\n takeUntil(destroySubject),\n )\n\n const access = (key: string) => {\n let releaseCalled = false\n\n const archiveEntry = archives[key] ?? new ArchiveEntry(cleanArchiveAfter)\n\n archives[key] = archiveEntry\n\n archiveEntry.update({\n locks: archiveEntry.state.locks + 1,\n })\n\n const release = () => {\n if (releaseCalled) return\n\n releaseCalled = true\n\n archiveEntry.update({\n locks: archiveEntry.state.locks - 1,\n })\n }\n\n loadSubject.next(key)\n\n const archive$ = archiveEntry.state$.pipe(\n map(({ archive }) => archive),\n filter((archive) => !!archive),\n )\n\n const error$ = archiveEntry.state$.pipe(\n tap(({ error }) => {\n if (error) {\n throw error\n }\n }),\n ignoreElements(),\n )\n\n return merge(archive$, error$).pipe(\n first(),\n map((archive) => ({ archive, release })),\n catchError((error) => {\n release()\n\n throw error\n }),\n )\n }\n\n /**\n * Will purge immediatly archives as soon as they are released\n */\n const purge = () => {\n purgeSubject.next()\n }\n\n loadArchive$.subscribe()\n\n return {\n access,\n purge,\n _archives: archives,\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n type Observable,\n catchError,\n finalize,\n from,\n lastValueFrom,\n map,\n mergeMap,\n of,\n switchMap,\n} from \"rxjs\"\nimport { createArchiveLoader } from \"./archives/archiveLoader\"\nimport type { Archive } from \"./archives/types\"\nimport { generateManifestFromArchive } from \"./generators/manifest\"\nimport { generateResourceFromArchive } from \"./generators/resources\"\n\ntype OnError = (error: unknown) => Response\ntype OnManifestSuccess = (params: {\n manifest: Manifest\n archive: Archive\n}) => Observable<Manifest> | Promise<Manifest>\n\nexport class Streamer {\n protected epubLoader: ReturnType<typeof createArchiveLoader>\n protected onError: OnError = (error) => {\n console.error(error)\n\n return new Response(String(error), { status: 500 })\n }\n protected onManifestSuccess: OnManifestSuccess\n protected lastAccessedKey: string | undefined\n\n constructor({\n onError,\n onManifestSuccess,\n ...rest\n }: Parameters<typeof createArchiveLoader>[0] & {\n onError?: OnError\n onManifestSuccess?: OnManifestSuccess\n }) {\n this.epubLoader = createArchiveLoader(rest)\n\n this.onManifestSuccess =\n onManifestSuccess ?? (({ manifest }) => Promise.resolve(manifest))\n this.onError = onError ?? this.onError\n }\n\n public prune() {\n this.epubLoader.purge()\n }\n\n public accessArchive(key: string) {\n if (this.lastAccessedKey !== undefined && this.lastAccessedKey !== key) {\n this.epubLoader.purge()\n }\n\n this.lastAccessedKey = key\n\n return this.epubLoader.access(key)\n }\n\n public accessArchiveWithoutLock(key: string) {\n return this.accessArchive(key).pipe(\n map(({ archive, release }) => {\n release()\n\n return archive\n }),\n )\n }\n\n public fetchManifest({ key, baseUrl }: { key: string; baseUrl?: string }) {\n const response$ = this.accessArchive(key).pipe(\n mergeMap(({ archive, release }) => {\n const manifest$ = from(\n generateManifestFromArchive(archive, { baseUrl }),\n )\n\n return manifest$.pipe(\n switchMap((manifest) =>\n from(this.onManifestSuccess({ manifest, archive })),\n ),\n map(\n (manifest) =>\n new Response(JSON.stringify(manifest satisfies Manifest), {\n status: 200,\n }),\n ),\n finalize(() => {\n release()\n }),\n )\n }),\n catchError((error) => {\n return of(this.onError(error))\n }),\n )\n\n return lastValueFrom(response$)\n }\n\n public fetchResource({\n key,\n resourcePath,\n }: {\n key: string\n resourcePath: string\n }) {\n const response$ = this.accessArchive(key).pipe(\n mergeMap(({ archive, release }) => {\n /**\n * We commonly use file:// for manifest without baseUrl. This ensure we\n * have valid URL for the reader while flagging them as local.\n *\n * However, we obviously don't have the file:// prefix on the archive.\n */\n const cleanedResourcePath = resourcePath.replaceAll(`file://`, ``)\n\n const resource$ = from(\n generateResourceFromArchive(archive, cleanedResourcePath),\n )\n\n return resource$.pipe(\n map(\n (resource) =>\n new Response(resource.body, {\n status: 200,\n headers: {\n ...(resource.params.contentType && {\n \"Content-Type\": resource.params.contentType,\n }),\n },\n }),\n ),\n finalize(() => {\n release()\n }),\n )\n }),\n catchError((error) => {\n return of(this.onError(error))\n }),\n )\n\n return lastValueFrom(response$)\n }\n}\n","import { Streamer } from \"./Streamer\"\nimport { removeTrailingSlash } from \"./utils/uri\"\n\ntype ConflictFreeWebWorkerFetchEvent = {\n readonly request: Request\n /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) */\n respondWith(r: Response | PromiseLike<Response>): void\n}\n\nexport class ServiceWorkerStreamer extends Streamer {\n protected getUriInfo: (event: ConflictFreeWebWorkerFetchEvent) =>\n | {\n baseUrl: string\n }\n | undefined\n\n constructor({\n getUriInfo,\n ...rest\n }: ConstructorParameters<typeof Streamer>[0] & {\n getUriInfo: (event: ConflictFreeWebWorkerFetchEvent) =>\n | {\n baseUrl: string\n }\n | undefined\n }) {\n super(rest)\n\n this.getUriInfo = getUriInfo\n this.fetchEventListener = this.fetchEventListener.bind(this)\n }\n\n fetchEventListener(event: ConflictFreeWebWorkerFetchEvent) {\n try {\n const uriInfo = this.getUriInfo(event)\n\n if (!uriInfo) return\n\n const baseUrl = removeTrailingSlash(uriInfo.baseUrl)\n const streamerPath = event.request.url.substring(\n baseUrl.length + `/`.length,\n )\n const [key = ``] = streamerPath.split(\"/\")\n const resourcePath = decodeURIComponent(\n removeTrailingSlash(streamerPath.substring(key.length + `/`.length)),\n )\n\n if (streamerPath.endsWith(`/manifest`)) {\n event.respondWith(\n this.fetchManifest({ key, baseUrl: `${baseUrl}/${key}/` }),\n )\n } else {\n event.respondWith(this.fetchResource({ key, resourcePath }))\n }\n } catch (e) {\n event.respondWith(new Response(String(e), { status: 500 }))\n }\n }\n}\n"],"names":["sortByTitleComparator","a","b","alist","blist","i","len","getUriBasename","uri","removeTrailingSlash","getUriBasePath","lastSlashIndex","createArchiveFromArrayBufferList","list","orderByAlpha","name","files","file","data","Report","SharedReport","printTree","paths","tree","path","parts","node","part","render","indent","key","arr","isLast","prefix","nextIndent","value","createArchiveFromJszip","jszip","archive","folderStructureStr","createArchiveFromLibArchive","libArchive","objArray","item","createArchiveFromText","content","mimeType","direction","txtOpfContent","createArchiveFromUrls","urls","options","opfFileData","url","detectMimeTypeFromName","filesFromUrl","configure","enableReport","getArchiveOpfInfo","apple","manifest","infoFile","fixedLayoutOption","XmlDocument","option","e","extractKoboInformationFromArchive","koboInformation","optionElement","comicInfoHook","defaultHook","baseUrl","dir","index","hrefBaseUri","getSpineItemFilesFromArchive","opsFile","opfBasePath","_opfXmlDoc","manifestElm","spineItemIds","manifestItemsFromSpine","getSpineItemInfo","itemRefElement","properties","renditionLayout","property","getItemFromElement","element","getBaseUrl","href","getItemsFromDoc","doc","el","epubHook","opfXmlDoc","metadataElm","spineElm","guideElm","titleElm","metaElmChildren","metaElmWithRendition","meta","metaElmWithRenditionFlow","metaElmWithRenditionSpread","publisherRenditionLayout","publisherRenditionFlow","renditionSpread","title","pageProgressionDirection","totalSize","size","itemrefElm","manifestItem","itemSize","spineItemInfo","elm","hasDocMetaViewport","metaElm","allFilesHaveViewportMeta","result","current","isXmlBasedMimeType","epubOptimizerHook","kobo","comicInfoFile","manifestWithoutComicInfo","_","items","mangaVal","isArchiveEpub","nonEpub","spineItem","archiveItem","parseContentType","getXmlElementInnerText","child","XmlTextNode","XmlElement","extractNavChapter","li","basePath","chp","contentNode","urlJoin","sublistNode","children","buildTOCFromNav","toc","navDataChildren","parseTocFromNavPath","navItem","tocFile","tocFileBasePath","mapNcxChapter","point","src","out","pt","buildTOCFromNCX","ncxData","rootTagName","parseTocFromNcx","opfData","ncxId","ncxItem","ncxPath","parseToc","tocFromNav","tocFromNcx","buildFolderFallbackToc","filesSortedByAlpha","combineWith","folder","subFolders","foundEntry","entry","nextFolderCursor","nextSubFolders","acc","folders","firstFolder","restFolders","resolveTocFromArchive","opfFile","tocHook","generateManifestFromArchive","hooks","baseManifestPromise","gen","manifestStr","hasCalibreCoverMeta","getBuggyCoverSvg","fixBuggyCover","resourcePath","resource","bodyToParse","buggySvg","calibreFixHook","cssFixHook","newBody","getMetadata","getContentTypeFromExtension","metadata","invalidSelfClosingTags","selfClosingTagsFixHook","tagPattern","fixedBody","tagName","attributes","generateResourceFromArchive","defaultResource","ArchiveEntry","cleanArchiveAfter","BehaviorSubject","update","map","locks","distinctUntilChanged","shareReplay","switchMap","isUnlocked","NEVER","timer","createArchiveLoader","getArchive","loadSubject","Subject","destroySubject","purgeSubject","archives","loadArchive$","mergeMap","archiveEntry","EMPTY","isClosed","cleanupArchive","locks$","isUnlocked$","newAccess$","pairwise","filter","prev","curent","startWith","from","tap","catchError","error","readyForPurge$","merge","first","takeUntil","access","releaseCalled","release","archive$","error$","ignoreElements","purge","Streamer","onError","onManifestSuccess","rest","response$","finalize","of","lastValueFrom","cleanedResourcePath","ServiceWorkerStreamer","getUriInfo","event","uriInfo","streamerPath"],"mappings":"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"}
|