Objective
Add manga (and manhwa/manhua) management to the media-stack — acquisition, serving, and metadata — following the stack’s zero-manual, declarative architecture.
Context
The stack handled TV, movies, and subtitles but nothing for manga. Manga is a separate pipeline from the *arr suite: no Prowlarr / qBittorrent / torrent indexers. Acquisition is extension-based scraping (Mihon/Tachiyomi sources), so it slots in beside the *arr apps rather than into them. Research surveyed the books/comics/manga landscape; manga was done first because it reuses the stack’s existing Flaresolverr for Cloudflare-protected sources.
Approach
Three new services on media-stack-net:
- Suwayomi (
ghcr.io/suwayomi/suwayomi-server:stable) — downloader; downloads chapters as CBZ + ComicInfo.xml into${MEDIA_DIR}/manga. Direct port 4567 (subfolder support unreliable), like Seerr. - Komga (
gotson/komga) — reader/server under the nginx/komgasubpath viaSERVER_SERVLET_CONTEXT_PATH. Handles RTL (manga) and continuous-vertical (manhwa/webtoon). - KOMF (
sndxr/komf) — metadata from AniList/MangaUpdates; internal-only.
scripts/setup-komga.sh bootstraps the Komga admin headlessly via the claim API and declaratively manages the Manga library. scripts/setup-suwayomi.sh registers the extension repo(s) via the GraphQL API. Both are orchestrator-run, self-poll readiness, and are non-fatal so manga never blocks the *arr setup.
Outcome
Shipped and deployed to the live box. Verified fully end-to-end with real content: registered the keiyoushi repo, installed the Comick source, downloaded One Piece ch.1 as a CBZ (52 pages + ComicInfo.xml), and Komga indexed the “One Piece” series. Komga admin auto-claimed (amanschhina@gmail.com); creds in .env.
PRs (all merged): #36 (feature, 5126644), #37 (Suwayomi healthcheck wget→curl), #38 (setup-suwayomi.sh — extension-repo registration), #39 (declarative source installs + KOMF series covers, 892f1b2).
Follow-up (PR #39): made source selection and covers declarative. SUWAYOMI_EXTENSIONS (pkgName list) installs sources via the GraphQL updateExtension mutation, idempotently (default: Comick, MangaDex, Weeb Central). KOMF now uploads real provider posters — the One Piece series shows the MangaUpdates volume cover. Chapter-1 thumbnail stays black: the Comick/ArcaneScans release ships a 556-byte blank page 1 that Komga thumbnails (real content is page 2+); a source artifact, not fixable in config.
Next Actions
- Feature + orchestration + docs + CHANGELOG merged (PR #36)
- Deployed to the live box (
.envcreds set,mstack,docker compose up -d) - Smoke-tested the full path: One Piece ch.1 via Comick → CBZ → Komga indexed
- Merge PR #38 (setup-suwayomi.sh)
- Declarative source installs + KOMF series covers (PR #39, merged + redeployed)
Resources
- Suwayomi-Server · Komga · KOMF
- PRs: https://github.com/achhina/media-stack/pull/36 · /37 · /38
Notes
Durable findings worth keeping:
- Suwayomi vs Komga roles. Suwayomi can also read manga (it streams chapters live from sources and reads downloads), so for a solo browser-only reader it can stand alone. Komga adds value as the library server for owned/downloaded content: multi-user accounts with per-user progress, OPDS for mobile/e-reader apps (Mihon, Paperback, KOReader, Kindle), KOMF metadata/covers, collections/readlists, and offline permanence (sources can delist titles — see MangaDex below). Suwayomi = downloader + source browser; Komga = “Plex for your owned manga.”
- Komga claim API (
GET/POST /api/v1/claimwithX-Komga-Email/X-Komga-Password) creates the initial admin non-interactively. Komga has no way to disable auth (gotson/komga#306 wontfix) and no reverse-proxy header trust (confirmed inSecurityConfiguration.kt— noRequestHeaderAuthenticationFilter), so the *arrX-Auth-Usertrick can’t make it skip login. Mitigation: “Remember me” → 365-day token (rememberMeDurationdefault,KomgaSettingsProvider.kt). - KOMF requires a committed
config/komf/application.yml(crash-loops without one). Komga connection is env-only (KOMF_KOMGA_BASE_URIshadows the ymlbaseUri). - KOMF cover config must nest under
komga:.seriesCovers/overrideExistingCoverslive atkomga.metadataUpdate.default; a top-levelmetadataUpdateblock is silently ignored (metadata still updates, no poster uploaded). Re-cover an existing series viaPOST /komga/match/library/{libraryId}/series/{seriesId}to KOMF (port 8085). KOMF REST paths are under/komga, not/api/metadata. - A scanlator’s blank lead page breaks Komga’s chapter thumbnail. Comick/ArcaneScans One Piece ch.1 ships
001.webpas a 556-byte blank; Komga thumbnails page 1 → black cover. Source artifact, not config;bookCoverswon’t fix it (no per-chapter provider covers). - Suwayomi extension repos are NOT settable via env.
EXTENSION_REPOS/server.extensionReposis ignored at runtime in v2.x (repos are DB-managed); the URL must be the/tree/<branch>form, not rawindex.min.json. Register via the GraphQLsetSettingsAPI — whatsetup-suwayomi.shdoes (PR #38). - MangaDex delisted One Piece (and many licensed titles) — 0 chapters. Comick carries the full series; used it for the smoke test.
jq '.isClaimed // empty'is a trap —//treats booleanfalseas absent, and a missing key makesjq -r .isClaimedprint the string"null"(exit 0). Branch on the boolean explicitly.:latest+ Watchtower is the stack’s real convention; a reviewer’s “everything is pinned” claim was false — verify against the compose, don’t trust it.- AI PR reviews regenerate on every push and ship occasional false “deploy-breaking” claims (e.g. “gotson/komga has no curl” — it does, at
/usr/bin/curl). Verify empirically before acting.
Bulk-downloading a chapter range (Suwayomi GraphQL)
Backfilled One Piece’s Egghead arc onward (ch. 1058–1186, 130 chapters) via the API rather than the UI:
fetchChapters(input:{mangaId})to refresh the source chapter list (Comick returns ~2500 entries — multiple scanlators per chapter number).- Dedupe by integer chapter number, picking one scanlator per number (prefer ArcaneScans/Bato over aggregators like Mangakakalot; aggregators are all that’s available for the most recent chapters). Skipping this downloads 2-3× duplicates.
enqueueChapterDownloads(input:{ids:[Int!]!})with the selected chapter ids.startDownloader(input:{})— the downloader sits STOPPED after enqueue; it must be started explicitly. (input:{}is required even though empty.)- Poll
downloadStatus{ state queue{...} }until the queue drains. - Komga does not auto-index reliably on filesystem events here — trigger
POST /api/v1/libraries/{id}/scan(202), then pollseries/{id}.booksCount.
With AUTO_DOWNLOAD_CHAPTERS on and the title in Suwayomi’s library, future chapters download automatically; only backfills need this manual flow.
Decisions
2026-06-27 — Manga is a separate pipeline, not wired into the *arr stack
Status: decided. Decision: Suwayomi (extension scraping) for acquisition, not Prowlarr/qBittorrent. Rationale: manga sources are scanlation sites, not torrent indexers; the *arr model doesn’t fit. Komga/KOMF serve and enrich.
2026-06-27 — Komga on nginx subpath, Suwayomi on direct port
Status: decided. Decision: Komga at /komga (Spring context-path is reliable); Suwayomi on direct port 4567. Rationale: Suwayomi’s reverse-proxy subfolder support is unreliable — same call as Seerr.
2026-06-27 — Keep :latest, reverted image pinning
Status: decided (reverted a mid-PR change). Decision: komga/komf use :latest. Rationale: matches the *arr services and the stack’s Watchtower auto-update model; pinning would opt them out of it.
Related Projects
Media Stack IaC Declarative Config Evaluation · Persist qBittorrent UPnP Port Mapping in Media Stack · Homelab Services Architecture