Extension & Client Architecture
How the Browser Importer and the Mihon extension are built, and the server routes they use.
1. Browser Importer
The importer (extensions/xianscan-importer) is a Manifest V3 extension written in TypeScript and bundled with esbuild. build.js produces two packages:
dist/for Chromium browsers, with a background service worker.dist-firefox/for Firefox, with a background script and the add-on idimporter@xianscan.local.
Page scanner (src/content/scanner.ts) collects images in four passes:
<img>elements, reading lazy-load attributes (data-src,data-original,data-lazy-src,data-urland similar), thensrcset,currentSrcandsrc.- CSS
background-imageon page containers. - When fewer than 3 images are in the page, image URLs found in embedded JSON state scripts.
- For virtual-scrolling readers, a MutationObserver remembers every image URL that appears, and matches them to empty page placeholders.
Downloads go through the background script. If a site refuses, the image is fetched from inside the open tab (with the page's cookies), and as a last resort drawn from the page onto a canvas. The access token is only added by the background script and never exposed to web pages.
cd extensions/xianscan-importer
yarn install
yarn build # dist/ and dist-firefox/
yarn package # the .zip and .xpi release files
2. Mihon Extension
The Mihon extension (extensions/xianscan-mihon, package eu.kanade.tachiyomi.extension.all.xianscan) targets extension library 1.6 and Android 6+. It sends the access token in an X-XianScan-Token header, only to the configured server, and shows a readable message on 401.
| Endpoint | Purpose |
|---|---|
GET /api/mihon/library?page=N&status=&genre= | Books, most recently updated first, 50 per page, archived books excluded |
GET /api/mihon/search?q=&page=N&status=&genre= | Same list, filtered by title, author or artist |
GET /api/mihon/genres | { genres: string[] } |
GET /api/mihon/manga/<id> | Book details and cover URL |
GET /api/mihon/manga/<id>/chapters | Chapter list (chapter number is the position in the book) |
GET /api/mihon/chapters/<id>/pages | Page image URLs (/api/pages/<id>/file, translated output or the original) |
GET /api/covers/<id>/file?w=512 | Cover image |
cd extensions/xianscan-mihon
# Debug APK (JDK 21, Android SDK platform 34, build-tools 34.0.0)
./gradlew :app:assembleDebug
# Release APK. Without signing.properties or the SIGNING_* variables it is signed
# with the debug key, and cannot update over the repository version.
./gradlew :app:assembleRelease
# Check that the APK bundles no Kotlin stdlib or host library (needs dexdump)
bash scripts/verify-apk.sh
Gradle names the APK tachiyomi-all.xianscan-v<version>-<buildType>.apk. Every dependency is compileOnly, because the host app provides Kotlin and all libraries.