Komga Enhanced — A manga media server with integrated downloading, automatic chapter tracking, multi-source metadata, scrobbling, and hardened CBZ data-safety.
Built on Komga — extends the excellent upstream media server with manga downloading, automation, multi-tracker sync, and reliability features.
| Image | Description |
|---|---|
08shiro80/komga:latest |
Stable release |
08shiro80/komga-private:latest |
Testing branch — may contain unstable or experimental changes |
Docker:
docker run -d \
--name komga \
--network bridge \
-p 25600:25600 \
-v /path/to/config:/config \
-v /path/to/manga:/manga \
08shiro80/komga:latest
Docker Compose:
services:
komga:
image: 08shiro80/komga:latest
container_name: komga
network_mode: bridge
ports:
- "25600:25600"
volumes:
- ./config:/config
- /path/to/manga:/manga
restart: unless-stopped
docker compose up -d
Open http://localhost:25600, create an admin account, and add a library. See Installation for JAR, build-from-source, and gallery-dl options.
This fork transforms Komga from a pure media server into a complete manga management solution:
| Problem | Solution |
|---|---|
| Manually downloading manga | Automatic downloads via gallery-dl — supports MangaDex and many other manga/image sites |
| Losing track of downloaded chapters | Chapter URL tracking — DB + filesystem checks prevent duplicates |
| Re-downloading after crashes | Crash recovery — auto-resumes interrupted downloads on startup |
| Title changes cause re-downloads | UUID folder names — MangaDex UUID as folder name, immune to title changes |
| Folder renames break series | Series survives folder rename — detects same series via MangaDex UUID, preserves progress and metadata |
| Unwanted chapters keep re-downloading | Chapter blacklist — permanent + auto-detection of same-group duplicates and dead-link redirects |
| Syncing MangaDex subscriptions | MangaDex Subscription Sync — auto-downloads from your followed manga feed |
| Source upload uses wrong chapter number | Add-Chapter-Download — paste a chapter URL with custom filename + number override |
| Cloudflare blocks the source site | FlareSolverr integration — transparent challenge-bypass for non-MangaDex sources |
| Missing metadata | MangaDex, AniList, Kitsu & Metron plugins for rich metadata |
| Manual metadata-match per series | Auto Metadata Match — title-similarity scoring across providers on scan |
| Tracker progress out of sync | Manga Scrobbler — AniList / MyAnimeList / Kitsu / MangaDex on book completion |
| Western comics need their own tracker | Comic Scrobbler — Metron |
| Migrating from Tachiyomi/Mihon | Backup import extracts your MangaDex follows |
| No guest browsing for family | Guest/Kiosk mode — read-only browsing without login, per-library access control |
| Long vertical webtoon pages | Page splitting like TachiyomiSY |
| Corrupt CBZ after an interrupted write | CbzSafeWriter — every CBZ-mutating path writes through a single hardened pipeline with multi-stage verify + atomic rollback |
| Silent CBZ corruption goes unnoticed | Media Integrity Verify / Repair / Rescan — byte-wise scan, zip -FF-based repair, persistent ERROR-flag in the UI |
| Long-running maintenance hidden | Background-job indicator in the nav-bar — Verify / Repair / Split-All / Re-inject all visible from anywhere |
| No server logs in UI | Web-based log viewer — real-time SSE, persistent log-level, dual Debug/Info toggle |
| One-off DB/CBZ maintenance | Settings → Fixes page — GUI-triggered re-inject of ComicInfo.xml across a library |
| Bland default theme | 7 color themes — AMOLED, Nord, Dracula, Solarized, Green, Red + Default |
New Download triggers a one-time download only — it does not add the URL to your follow list.
Grouped by area. Every section here is implemented and shipped; nothing aspirational.
Download manga from MangaDex and other manga/image sites via gallery-dl-komga (a fork of gallery-dl with Komga-specific enhancements):
Any manga/image URL supported by gallery-dl works — not just MangaDex. Simply paste the URL in the WebUI to start a download.
Automatically sync new chapters from your MangaDex subscription feed — completely independent from the follow.txt system:
mangadex-subscription plugin in Settings → Pluginsclient_id, client_secret, username, and passwordHow it works:
GET /user/follows/manga for newly followed manga → queues full downloadGET /user/follows/manga/feed?publishAtSince=... for new chapters of existing manga, with a 30-min look-back window so chapters whose feed-indexing lagged the sync boundary still landDefault Language)Configuration (via Plugin Manager UI):
| Setting | Default | Description |
|---|---|---|
client_id |
— | MangaDex API Client ID |
client_secret |
— | MangaDex API Client Secret |
username |
— | MangaDex username |
password |
— | MangaDex password |
sync_interval_minutes |
30 | How often to check for new chapters |
No app restart needed — the syncer automatically restarts when you save config or toggle the plugin.
Automatically check for new chapters from your favorite manga:
follow.txt file in your library root# Example follow.txt
https://mangadex.org/title/a1c7c817-4e59-43b7-9365-09c5f56e5eb1
https://mangadex.org/title/32d76d19-8a05-4db0-9fc2-e0b0648fe9d0
https://mangahere.cc/manga/one_piece/
https://manhuaplus.com/manga/magic-emperor/
https://hdoujin.me/12345
For series whose source uploads arrive as one-off chapters that don’t fit the rest of the series naming, the Add Chapter Download… entry in the 3-dot menu of a series opens a dialog with two modes:
Filename, Chapter #, Volume, Chapter Title. With overrides on, the downloaded CBZ is renamed and <Number> / <Volume> / <Title> are upserted into ComicInfo so it sorts correctly in the series.chapter>=50,chapter<=80), runs gallery-dl with the filter expression. Standard naming applies.Skip if file exists compares DB chapter numbers (BookMetadata.numberSort), not filenames — filenames vary too much per source. The destination is taken from the series the menu was triggered on, so an Add-Chapter-Download into an existing UUID folder never creates a parallel manga folder.
Cloudflare-protected manga sites (mgeko.cc, mangaclash.com, deatte5.com, tritinia.org, manhwatop.com, …) cannot be fetched by gallery-dl’s requests session — the server returns the Cloudflare challenge HTML.
The companion gallery-dl-komga fork supports an external FlareSolverr endpoint that solves the challenge in headless Chrome and returns the cookies + User-Agent that solved it. Per-host cookies + UA are cached on disk for 20 minutes — subsequent runs go direct without re-invoking FlareSolverr. The challenge round-trip only fires on a Cloudflare HTML response or a cold cache; JSON-API endpoints (api.mangadex.org) stay on the direct path.
Set flaresolverr_url (e.g. http://192.168.1.10:8191/v1) in Plugin Manager → gallery-dl Downloader. Leave blank to disable.
A prominent search card sits at the top of Downloads. Pick a target library once from the dropdown, then for each result you get two buttons:
follow.txt, the button is “Follow” and appends the MangaDex URL to the selected library. If it’s already in any library’s follow.txt, the button is “Following” (success-coloured) and a second click removes the line from whichever library contains it.Advanced filters (collapsible panel) — multi-select for:
includedTags[])excludedTags[]) — useful for permanently hiding things you never want to seeOnly titles with downloadable chapters (toggle) — MangaDex’ built-in hasAvailableChapters=true is too generous (it counts external-link chapters and 0-page placeholders as “available”, e.g. Solo Leveling still shows up even though every English chapter just links to webnovel.com). With this toggle on the UI does one extra /manga/{id}/feed call per result and only keeps titles where at least one chapter has externalUrl == null AND pages > 0 in your preferred language (read from gallery-dl Downloader default_language). Each result is cached server-side for 24h.
Cost: 1 extra MangaDex API call per result when the toggle is on (cached). 20 results = ~20 extra calls = a few seconds of throttling on first run, then free until cache expires. Toggle off = zero extra cost.
With no title and at least one filter set, the button switches to Browse and queries MangaDex sorted by followedCount desc — popular-first browse when you can’t decide what to read next.
Pagination — 24 results per page, classic page selector below the grid. MangaDex caps offset + limit ≤ 10000, so the page count tops out at 417 pages with the default page size.
Tag catalog cached 7 days in your browser — the tag dropdown is filled from GET /api/v1/plugins/mangadex-metadata/tags on first use, then served from localStorage for a week (MangaDex updates its tags only a few times a year). No tag fetch on every page load.
Persistent defaults — a Save as default button writes the current filter combination to your Komga account (user client-setting komga.fork.mangadexsearch.defaults), so defaults follow you across browsers and devices (a previously saved per-browser localStorage value is migrated automatically). On the next visit the panel pre-fills with those values, so you can set a permanent tag blacklist once and forget about it. Clear all resets the current selection without touching the saved default.
Already-followed titles are marked — on page load the search card pre-fetches every library’s follow.txt, extracts the MangaDex UUIDs, and uses that set to flip every result’s Follow button to “Following” state. No special filter; just an honest two-state toggle.
API rate-limit note: every search and browse call goes through
MangaDexMetadataPlugintoapi.mangadex.organd counts against MangaDex’s global rate limit (~5 req/sec). Heavy use of the panel — especially Browse — will throttle (HTTP 429) for a few seconds, same as the rest of the fork’s MangaDex traffic.
Import your manga library from Tachiyomi or Mihon:
.tachibk (Mihon/forks) and .proto.gz (Tachiyomi) formatsfollow.txtPermanently prevent unwanted chapters from being re-downloaded:
Three automatic blacklist paths keep the queue self-cleaning:
externalUrl != null && pages == 0 (J-Novel-style redirects to a publisher site) are blacklisted on detection — they can’t be downloaded anywayAll three log at WARN so the operator can review and remove individual entries via the series blacklist dialog if needed.
Never download the same chapter twice:
Important:
Import chapter URLsis enabled by default and required for the downloader, follow list, and subscription sync to detect already-downloaded chapters. Disable it in Library → Edit → Metadata for libraries that don’t use the download system — otherwise library scans will be significantly slower.
Rich metadata from multiple sources:
MangaDex Metadata Plugin:
AniList Metadata Plugin:
Kitsu Metadata Plugin (ships as a default external plugin — see Custom Plugins):
Metron Metadata Plugin (disabled by default — comic metadata):
Komf-style automatic provider matching for new series on scan:
anilist,mangadex,kitsu by default)0.85)web_url plus multi-source tracker_links into series.json, so MylarSeriesProvider produces one WebLink per matched sitePOST /api/v1/automatch/libraries/{id}Plugin Manager → Auto Metadata Match with a GUI (drag-free ordered provider list + library multi-select) instead of raw CSV; does not appear in the per-series Search Online Databases dialog (it runs as a background processor, not a manual search provider)MetadataProviderPlugin becomes selectable in the provider priorityPush read progress to external trackers when a book is marked completed:
Manga Scrobbler — AniList / MyAnimeList / Kitsu / MangaDex:
SeriesMetadata.links (anilist.co, myanimelist.net, kitsu.app, mangadex.org), or via manual JSON mappingssync_user_id) and per-library exclusion (exclude_library_ids)Comic Scrobbler — Metron:
metron.cloud/issue/… and metron.cloud/series/… linksBoth scrobblers persist last-known progress and status per (series, tracker) in a sync_state table so duplicate submissions are skipped after restarts.
gallery-dl Downloader is the single source of truth for MangaDex authentication. Set mangadex_username / mangadex_password / mangadex_client_id / mangadex_client_secret once on that plugin and MangaDex Subscription Sync + Manga Scrobbler read from it automatically (their own equivalent fields stay empty and only act as per-plugin overrides). The Subscription Sync’s default_language is already read this way today (in MangaDexSubscriptionSyncer.checkFeed), and the credential reads follow the same pattern.
Resolution order for each MangaDex field:
gallery-dl Downloader (mangadex_*)MangaDex Subscription Sync (client_id/client_secret/username/password) — second fallback for the scrobbler onlyBeyond the built-in plugins, the fork can load external plugin JARs at runtime — drop them into <config-dir>/plugins/ or upload via Plugin Manager → Install Plugin (file or URL). Built-in plugins stay compiled in and cannot be uninstalled; only external plugins are removable.
Docker: the plugins folder lives at
/config/plugins, which is already inside the mounted/configvolume — no extra volume mount is needed. Drop JARs there (or upload via the UI) and they persist across container restarts. The bundled default plugins (e.g. Kitsu) are auto-installed there on first start.
MetadataProviderPlugin (search + metadata, shows up in Search Online Databases and Auto Metadata Match) and NotifierPlugin (receives DOWNLOAD_COMPLETED / DOWNLOAD_FAILED events — webhook, Discord, …)SpiOnlyClassLoader whose parent whitelists only the SPI (org.gotson.komga.infrastructure.plugin.api.*), JDK (java.*/javax.*), Kotlin runtime (kotlin.*/kotlinx.*) and Jackson (com.fasterxml.jackson.*). A plugin attempting import org.gotson.komga.domain.… or Spring gets ClassNotFoundException("Plugin denied access to '…' — class-loader isolation. …"). Bundle anything else you need (OkHttp, JDBC driver, …) into your plugin JAR. Load failures never crash the server.plugins/plugin-template, edit one Kotlin file, run ./gradlew build, install the JAR. Full guide: PLUGINS.mdSecurity model — class-loader isolation, NOT a sandbox. The whitelist above blocks compile-time/runtime imports of Komga internals so a plugin can’t reach into the host through the SPI’s back door. It does not restrict filesystem (
java.io.File), network (java.net.http) or reflection (java.lang.reflect) — those are intentionally allowed because plugins call external APIs. An installed external JAR runs arbitrary code with the same OS rights as the Komga process. The install endpoint is admin-only — only install plugins you trust. See PLUGINS.md → Security model for the full statement of limits.
Split long vertical webtoon pages into readable segments:
CbzSafeWriter (see Reliability)Read-only browsing without login — perfect for family or shared setups:
7 predefined theme presets in Account → UI Settings:
Choose how new manga folders are named:
uuid (default) — uses MangaDex UUID like 0c6fe779-...title — uses manga title like Roman ClubOverride the gallery-dl directory template per-install via the Plugin Manager → gallery-dl Downloader → Chapter Naming Template field. Blank keeps each site’s default. Common fields: {chapter}, {chapter_minor}, {volume}, {title}, {group}, {lang}.
ChapterMatcher accepts three prefix shapes in the resulting filename for post-download CBZ matching and resume detection: c<num> (gallery-dl default — e.g. c001), ch. <num> (e.g. ch. 1), or Chapter <num> / Chapter_<num> (e.g. Chapter 1, Chapter_001). Letter suffixes (5.5a, 5.5b — MangaDex convention for split releases of the same decimal chapter) are preserved across both extraction and matching. Pick any template that produces one of these three prefixes; the rest of the filename is yours.
The fork puts the same level of care into not-corrupting-your-library as it does into the user-visible features. Many of these are silent in normal operation — you only notice them when something would have gone wrong.
Six paths can mutate a CBZ on disk (PageSplitter, BookPageEditor.removeHashedPages / deletePages, ComicInfoGenerator.writeInjected / injectComicInfoWithRetry, DownloadExecutor.patchComicInfo). All six route through one utility that guarantees:
.bak.<uuid> only after the new bytes are verified on disk; the backup move + atomic rename are the only window where the file isn’t readable. At 150-chapter Split-All on a 50-200 MB-per-chapter library this saves ~15-30 GB of disk traffic per run versus a copy-based approach..bak is moved back over target; rollback failure leaves .bak on disk and a fatal-level log line gives its path so the user can restore manually.The lambda signature is (OutputStream) -> Unit so callers can wrap the stream in either java.util.zip.ZipOutputStream or Apache commons-compress ZipArchiveOutputStream — same writer, both ZIP APIs.
Settings → Maintenance → Verify ZIP integrity runs a byte-wise check over every .cbz / .zip in the library:
Media.Status.ERROR with a Corrupt CBZ: <message> comment, surface in the analysis filter, and survive container restart (count comes from mediaRepository.countByStatus(ERROR) when no scan is running)Repair flagged runs zip -FF <src> --out <tmp> per ERROR-book. Fully recovered → Files.move overwrites + status flips to OUTDATED for re-analyze. Partial → comment updated, status stays ERROR.Rescan flagged byte-wise re-verifies each ERROR-book and only emits taskEmitter.analyzeBook for those that pass. Use after a Repair-Partial or after fixing files externally.The task-count indicator in the nav-bar now reflects custom long-running actions too — Split-All, Verify Integrity, Repair, Re-inject ComicInfo, library imports. The tooltip lists active job names. You can navigate away from the originating page without losing visibility.
Default SQLite was tuned for embedded single-user use. The fork picks values that match a multi-tab Komga UI against a library DB measured in hundreds of MB:
busy-timeout: 30s (both DBs) — the JDBC driver waits transparently instead of bubbling SQLITE_BUSY to the task layersynchronous: NORMAL (both DBs) — fsync only at WAL-checkpoint boundaries, 3-5× faster on bulk writes; no corruption risk under WAL, ~1 s commits may be lost on power-cutcache_size: 2000 (main DB only — tasks-db is small) — 8 MB per connection (default is 2 MB) holds the working set of the dominant indexes/settings/server → Task threads (upstream historically capped to 1 from pre-WAL days). Resizes live without restart.SQLITE_BUSY retry-loop in TaskHandler — 5 attempts with linear backoff (500 ms → 2.5 s) catches the edge case where a write enters busy state right at the 30 s ceilingTwo scheduled jobs run daily and prune log/event tables to keep the SQLite file lean:
PLUGIN_LOG — entries older than 7 days are deleted (was unbounded; observed 119k+ rows on installs without retention)HISTORICAL_EVENT + HISTORICAL_EVENT_PROPERTIES — pruned together (the schema has no ON DELETE CASCADE, so the DAO deletes properties first then events)Note on file size: SQLite does not shrink
database.sqlitewhen rows are deleted — freed pages are reused for future writes but the file stays the same size on disk (it just stops growing). To actually reclaim space, runVACUUM;against the database (e.g.sqlite3 database.sqlite "VACUUM;") — this works while Komga is running but holds a brief exclusive lock. Retention prevents unbounded growth; VACUUM is the one-time reclaim.
New chapters are automatically scanned after a download completes (scanDeep=false — filesystem walk only, cheap):
newlyDownloaded > 0 (resume runs that found nothing already on disk are skipped)GUI-triggered one-time maintenance actions under Settings → Fixes. Cards are versioned and removed once obsolete. The card list is built dynamically from FixRegistry — adding a new fix is one block of Kotlin + one backend endpoint, no frontend change.
ComicInfo.xml + series.json for every CBZ in the selected library from MangaDex metadata. Enable Force to overwrite existing ComicInfo (useful when MangaDex metadata changed). CBZs from non-MangaDex sources are skipped even under Force — the re-inject reads the existing <Web> tag and refuses to overwrite mangabuddy / cubari / Mihon-export ComicInfo with MangaDex metadata. Image entries are written with STORED to skip re-deflating already-compressed data (~3-5× faster sweep).Admin-only log viewer in Settings → Logs:
The fork pins org.gotson.komga: WARN as the baseline log level — state-altering events (auto-blacklist, stale-recovery, repair-skip, etc.) are emitted at WARN so they survive the default install. Routine flow stays at INFO/DEBUG and only surfaces when you flip the toggle.
pip install https://github.com/08shiro80/gallery-dl-komga/archive/refs/heads/master.tar.gz)See Quick Start for Docker and Docker Compose commands. The Docker image already contains gallery-dl-komga, kepubify, and zip (for the Repair path); no extra setup needed.
gallery-dl-komga is installed via pip inside the Docker image. The fork keeps the upstream version string (1.32.1), so a plain -U will not pull in new commits — pip sees an unchanged version and reuses its cached wheel, and GitHub caches the branch tarball for a few minutes. Force a clean reinstall:
docker exec -u 0 komga pip3 install --break-system-packages --no-cache-dir --force-reinstall \
https://github.com/08shiro80/gallery-dl-komga/archive/refs/heads/master.tar.gz
To pin an exact commit — immutable, and it bypasses the branch-tarball cache entirely — use its SHA instead of refs/heads/master:
docker exec -u 0 komga pip3 install --break-system-packages --no-cache-dir --force-reinstall \
https://github.com/08shiro80/gallery-dl-komga/archive/<commit-sha>.tar.gz
gallery-dl runs as a subprocess per download, so no Komga restart is needed — the next download uses the updated version.
java -jar komga.jar
Install gallery-dl-komga (the fork, see Requirements) — the download/ComicInfo features rely on the fork’s
komgapostprocessor, not upstream PyPIgallery-dl. Point the gallery-dl Downloader plugin’sgallery_dl_pathat a local checkout if needed.
Full metadata in ComicInfo.xml and series.json (title, authors, genres, cover art, publish dates, scanlation group, etc.) is only guaranteed when downloading from MangaDex or when using the MangaDex/AniList metadata plugins. Other sites supported by gallery-dl will download chapters correctly, but metadata may be incomplete or missing.
# Build frontend
cd komga-webui && npm install && npm run build && cd ..
# Build backend with frontend
./gradlew prepareThymeLeaf :komga:bootJar
# Run
java -jar komga/build/libs/komga-*.jar
Create ~/.config/gallery-dl/config.json:
{
"extractor": {
"mangadex": {
"lang": ["en"],
"chapter-filter": "lang == 'en'"
}
}
}
To use a local gallery-dl-komga checkout (e.g. for latest extractors), set gallery_dl_path in the plugin config to the directory containing the gallery_dl package. This sets PYTHONPATH so python -m gallery_dl loads from your local source.
If you have a FlareSolverr instance for Cloudflare-protected sites, set its URL in Plugin Manager → gallery-dl Downloader → flaresolverr_url (e.g. http://192.168.1.10:8191/v1). Blank disables the feature.
Configure via application properties:
komga:
download:
follow-check-interval: 24h
The fork stores its database migrations in a separate history table (flyway_fork_history), completely independent from the official Komga migration history (flyway_schema_history):
| Feature | Original | This Fork |
|---|---|---|
| Media Server | Yes | Yes |
| Manga Downloads | No | Yes |
| Automatic Chapter Tracking | No | Yes |
| MangaDex Subscription Sync | No | Yes |
| Follow List Automation | No | Yes |
| Add-Chapter-Download per series | No | Yes |
| Cloudflare Bypass (FlareSolverr) | No | Yes |
| Chapter Blacklist + Auto-blacklist | No | Yes |
| Series survives folder rename | No | Yes |
| Auto-scan after download | No | Yes |
| Configurable folder naming | No | Yes (UUID/title) |
| Configurable chapter naming | No | Yes (3 prefixes) |
| Guest/Kiosk Mode | No | Yes |
| Web Log Viewer (persistent level) | No | Yes |
| Color Themes | No | 7 presets |
| Tachiyomi Import | No | Yes |
| Page Splitting | No | Yes |
| AniList, Kitsu & Metron Metadata | No | Yes |
| Auto Metadata Match (Komf-style) | No | Yes |
| Tracker Sync (AniList / MAL / Kitsu / MangaDex / Metron) | No | Yes |
| Settings → Fixes (one-off maintenance) | No | Yes |
| Media Integrity Verify / Repair / Rescan | No | Yes |
| Hardened CBZ writer (atomic + verified) | No | Yes |
| Background-job indicator in nav-bar | No | Yes |
| Real-time Progress | No | Yes (SSE) |
See CONTRIBUTING.md for details.
komga postprocessor for in-process ComicInfo.xml injectionMangaDexMetadataPlugin to keep the rate-limiter and content-rating config in play)