No description
  • Rust 90.8%
  • CSS 8.5%
  • Just 0.4%
  • Dockerfile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-31 12:52:26 +02:00
src ui: switch to datastar 2026-08-31 12:52:26 +02:00
.dockerignore add dockerfile + deploy 2026-08-01 12:38:00 +02:00
.gitignore add maud 2026-07-31 11:07:03 +02:00
AGENTS.md rework fscache 2026-07-31 22:21:37 +02:00
build.rs ui: switch to datastar 2026-08-31 12:52:26 +02:00
Cargo.lock ui: switch to datastar 2026-08-31 12:52:26 +02:00
Cargo.toml ui: switch to datastar 2026-08-31 12:52:26 +02:00
data.db separate pending page and use db cache properly 2026-07-31 13:32:50 +02:00
Dockerfile add dockerfile + deploy 2026-08-01 12:38:00 +02:00
justfile add dockerfile + deploy 2026-08-01 12:38:00 +02:00
README.md ui: switch to datastar 2026-08-31 12:52:26 +02:00

manga-mover

Organizes single-file manga archives (.cbz, .zip, etc.) from a source directory tree into a sorted destination directory. Filenames are matched against hardcoded regex patterns to extract metadata (chapter, episode, volume, title). State is tracked in SQLite. Uses axum + maud + datastar for a server-rendered web UI.

Setup

Requires Rust 1.93+.

just build

Configuration

Create a TOML config file:

source = "/path/to/unsorted"
dest = "/path/to/sorted"
db = "/path/to/manga-mover.db"

# Optional: background scan interval in seconds (default 300, 0 to disable)
scan_interval_secs = 300

# Optional: auto-move files during background scans (default false = dry-run only)
auto_move = false

Set MANGA_MOVER_CONFIG to the config path, or place it at /config.toml.

export MANGA_MOVER_CONFIG=./config.toml
cargo run

Usage

Open http://127.0.0.1:3000 in a browser.

Workflow

  1. Import a manga from /ui/untracked — pick a detected source subdirectory, give it a name and destination subdirectory.
  2. Edit manga metadata on the detail page (/ui/mangas/:id) — adjust the name, source/dest paths, or toggle volume numbering.
  3. Sort at /ui/mangas/:id/sort (per-manga) or /ui/sort (global) — preview what would be moved, then confirm.
  4. Use Refresh on /ui to recompute stats without waiting for the background scanner.

Filename patterns

Patterns are hardcoded in src/logic/source_pattern.rs. They use regex to extract metadata from filenames. Examples of supported filename formats:

  • Episode 42.cbz
  • (S2) Ep. 69 - Servant of the Aesir (ch. 151).cbz
  • Chapter 1.cbz
  • WebToon_Chapter 3_ Using My Clone (1).cbz
  • Vol. 3 Ch. 25.cbz
  • Manga_v1_ch01.cbz

If a file doesn't match any pattern, it is flagged as unsortable in the UI.

Dest naming convention

Destination filenames follow a fixed convention based on the manga's with_volumes setting:

  • Without volumes (default): {name} {chapter}.cbz — e.g. Berserk 314.cbz
  • With volumes: {name} v{volume} {chapter}.cbz — e.g. Berserk v3 25.cbz

If the pattern extracts a title, it is appended: {name} {chapter} {title}.cbz.

Season tracking

Manga entries track a current_season (default 1). Season markers in source filenames can trigger season changes:

  • set — sets the season to a specific value
  • increment — increments the season by 1

Files are processed in alphabetical order, so season markers should sort before the chapters they affect.

Anomaly categories

Each file in a manga's source or dest directory is classified:

Category Meaning
sorted Already moved to dest and matches expected naming
unsorted In source, matched a pattern, pending move
unsortable In source, didn't match any pattern
dest-anomaly In dest, doesn't match expected naming convention
duplicate Multiple files in source match to the same dest path

Development

just run      # build CSS and run with local test config
just test     # run tests
just clippy   # run clippy lints
just check    # build CSS + clippy + tests (pre-commit gate)
just build    # release build
just css      # rebuild min.css from src/ui/css/*.css