Skip to content

About

Manga reader plugin for hoardodile.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@hoardodile/plugin-manga

Manga reader content plugin: chapter directory, scroll and paged modes, two-page spreads, fit and zoom, per-page comments and reading-position restore. Chrome follows the host theme (light/dark, palette, fonts, icon style) via the design system; the reading canvas is a media surface (black by default, theme canvas optional). Supports page-folder resources (subdirectories become chapters) and single-file comic archives — CBZ/zip, CBR/rar, CB7/7z, CBT/tar, EPUB — whose pages are materialized on first preview via the host's extractArchive.

Importing a chapter book

Two equivalent ways to get a multi-chapter book into hoardodile:

  • One archive: upload a single CBZ/CBR/CB7/CBT (chapter subdirectories inside the archive become chapters), or an EPUB with image pages. Non-zip formats list/extract through the bundled 7-Zip binary, so uploads of rar/7z/tar need that optional package installed.
  • A whole book folder: importLocal is non-recursive per direct item, but a directory item is packed recursively — put the whole book folder (with 第1话/-style chapter subdirectories) into the import source, or browse to its parent in the folder importer and import it: it lands as ONE resource whose nested chapter paths the reader groups into chapters.

Dev loop

This plugin is developed entirely through the plugin toolchain — no hoardodile server, no web app:

pnpm build          # bundle manifest + client + server hooks into dist/
pnpm dev            # watch-build and serve the workbench (http://127.0.0.1:5199)
pnpm detect:smoke   # run detect against testdata/pages through the real sandbox
pnpm test           # vitest

pnpm dev captures the server-side hook results (detect, sourceMeta, searchMeta, listFiles, coverLocal) from the real worker sandbox and feeds them to the workbench, so the iframe receives the same context the app would push. It serves the flat page volume (testdata/pages via --data); point it at testdata/cbz or testdata/book to work on the archive / folder paths. Individual hooks can also be run or benchmarked directly:

pnpm exec hoardodile plugin run listFiles testdata/pages --plugin-dir dist
pnpm exec hoardodile plugin run listFiles testdata/cbz --plugin-dir dist
pnpm exec hoardodile plugin bench listFiles testdata/pages --plugin-dir dist

Archive hooks materialize into a scratch cache under the OS temp dir during plugin run/dev, mirroring the server's local/cache layout.

testdata/

Committed fixture volumes under a single testdata/ root, regenerated by pnpm testdata. Every volume is a flat directory — a resource holds either a page folder or a single archive, never both:

  • testdata/pages/ — a synthetic volume of ten generated pages, 1.png … 10.png. The filenames are deliberately unpadded so lexicographic and natural ordering disagree — the reader must show them in page order. Each page carries one marker bar per page number, so the current page is readable at a glance.
  • testdata/cbz/ — a two-chapter DEFLATE CBZ (第1话/ and 第2话/, five pages each, page numbers restarting per chapter) carrying the side-car junk real CBZs ship with (ComicInfo.xml, Thumbs.db) — listFiles must skip those and keep only image pages.
  • testdata/cbz-stored/ — the same book re-packed with STORED entries, covering the uncompressed boundary of the container codec.
  • testdata/cbz-nasty/ — deep nesting, a ~90-char directory name and #/spaces/parens in page names.
  • testdata/book/ — the same book as a folder (chapter subdirectories), standing in for the folder-import path.

Real-world samples live in testdata-real/ (git-ignored; not committed): small public-domain comics and EPUBs downloaded from the Internet Archive, exercised during development.

pnpm testdata:real   # fetch/verify samples, then run the hook suite

Sizes are resolved dynamically from the archive.org metadata API, so a source file that changed size is re-fetched instead of failing a stale size check. On proxy-only networks the fetch needs Node's proxy support: NODE_USE_ENV_PROXY=1 pnpm testdata:real (or set it in the shell).

The comic sample is deliberately a jp2-based archive.org scan (Single Page Processed JP2 ZIP): it reproduces the real-world case where the card cover renders but the reader pages are blank — jp2/tiff/heic are not browser-decodable, archive pages are listed as originals, and the host's transcode pipeline covers the first page (cover) but the reader serves the raw extracted bytes. Archive cards also show their page-count and width/height badges now that the archive sourceMeta probes the first pages through the virtual path.

Verification drives the plugin hooks straight through @hoardodile/host createPluginResourceAPI (the same path the format integration tests use) rather than hoardodile plugin run: plugin run/dev load the plugin into the sandbox without its manifest, so the sandbox denies the container permission and every archive hook is rejected — an upstream @hoardodile/cli limitation.

Known container limits: password-protected (encrypted) zip entries are rejected with a clear error, and ZIP64 archives (>4 GiB / >65535 entries) fall back to the yauzl parser without a dedicated fixture.

The fixture volumes hold resource content and nothing else: detect rejects a page folder that mixes in non-image files, so a stray README there would make the plugin stop matching its own fixture.

Architecture

  • src/core/ — framework-agnostic domain logic, fully unit-tested: source-shape classification (format.ts), chapter grouping and order (chapters.ts), the linear book model and navigation (book.ts), the versioned reading position and per-chapter progress (position.ts), and page-record building from container listings / extraction manifests (records.ts).
  • src/main.ts — thin server hooks over the logic: detect, sourceMeta, searchMeta, coverLocal, listFiles, imageHashes. Archive pages are addressed as virtual paths (book.cbz!第1话/001.png) for probing/hashing/covers; full materialization happens only in listFiles, i.e. on first preview (with the host's per-entry progress surfaced by the reader).
  • src/render/ — thin React adapters: the book hook (useMangaBook), chapter+page position (useMangaReaderState), first-materialization progress (useExtractProgress), the chapter directory drawer (ChapterList), and the scroll/paged views.

SDK packages

@hoardodile/* dependencies resolve from the npm registry (^0.1.9): pnpm install pulls the published SDK directly — no tarballs, no pnpm-workspace.yaml overrides.

Licensing

  • The plugin is MIT licensed (see LICENSE).
  • Committed fixtures under testdata/ are synthetic (regenerated by pnpm testdata). Real-world samples fetched by pnpm testdata:real are public-domain works from the Internet Archive / Project Gutenberg and live only in the gitignored testdata-real/ directory.

Requirements

  • hoardodile ≥ 0.1.9 — the built-in plugin marketplace (Settings → Marketplace) and the batched asset-download API (download([…])) when the manifest declares "download": true. The marketplace's Readme and Release notes tabs and release readme assets are read by newer builds; older builds still list and install the plugin normally.
  • "minAppVersion" in manifest.json declares the lowest hoardodile release this plugin runs on. Hosts below it refuse to install or update the plugin (the marketplace gates the install/update entries and zip uploads are blocked with an explanation), so bump it only when the plugin really needs a newer app. Omit it for plugins that support every release.
  • This plugin's version is independent of the hoardodile release version; bump it on user-visible changes.
  • Dev loop: Node ≥ 24, pnpm 11.

Deploying

Publish to the marketplace with one command:

# 1. Add the repository address to your registry repo's registry.json:
#    { "version": 1, "plugins": ["https://github.com/<owner>/<repo>"] }

# 2. One-click release — release-it bumps the version in package.json AND
#    manifest.json, writes CHANGELOG.md from Conventional Commits, commits,
#    tags `v<version>` and pushes. The tag-triggered `.github/workflows/
#    release.yml` then builds, packages (`release/<id>-<version>.zip` +
#    `.sha256`) and publishes the GitHub release. No local `gh` CLI or token.
pnpm release <version>

On main, with a clean working tree. The tag must match the manifest version (v<manifest.version>) — the workflow fails otherwise. Then paste the registry repo address once in Settings → Marketplace. The app reads the registry, each plugin's manifest and its latest release — names, versions, permissions and release notes come straight from GitHub, so the list never needs editing again. The zip asset is <id>-<version>.zip (produced by hoardodile plugin package); before the first release the plugin shows up with a "no release" state.

Prefer pushing a tag manually (no release-it)? It still works — the workflow does the same build/package/publish:

git tag v<version> && git push origin v<version>

Local installs (zip upload in Settings → Plugins) still work for private packages.

Publishing a readme

The marketplace detail view shows a per-release Readme tab. Ship the readme markdown in the readme/ folder as a bare README.md fallback, plus one README.<locale>.md file per extra language (e.g. readme/README.md, readme/README.zh.md) — release.yml uploads the whole folder alongside the zip, so each release carries its own readme and every version shows independent notes. README.md is the fallback the app shows for any language without a specific file, so English normally lives there and you do not need a README.en.md. Use the app's supported language codes for the extra files (zh, ja, de, es) — a region-coded name like README.zh-CN.md only matches a UI language resolved to that exact code, so README.zh.md is what Chinese users see.

pnpm readme:check (run by release.yml before publishing) gates this: it fails the release if readme/ is absent-and-required, is not flat, ships no README.md / README.<locale>.md, or references an image by a nested/missing path.

The app resolves the readme for the user's UI language (exact locale → base language → the README.md fallback); the release body always shows in the Release notes tab.

About

Manga reader plugin for hoardodile.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages