Skip to content

About

collection of lil python scripts to ease my sailing life into manga πŸ΄β€β˜ οΈ

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

134 Commits

Folders and files

Repository files navigation

manga_manager

A suite of CLI tools to build a manga library for Kobo e-readers β€” from raw chapter archives to polished .kepub.epub files with full metadata.

Platform: Linux (tested on Linux Mint 22.3 / Debian 13) Β· Python: 3.12+ Β· Package manager: uv


Overview

manga_manager covers the full pipeline from downloaded chapter archives to a Kobo-ready library:

.cbz archives (Tachiyomi, etc.)
        β”‚
        β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  packer β”‚  ──▢  groups chapters into volume dirs, extracts images
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
Volume dir  [Berserk v01/]
        β”‚
        β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ editor β”‚  ──▢  injects metadata (title, author, ISBN, series…) from YAML
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ convertor β”‚  ──▢  converts to .kepub.epub via KindleComicConverter
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
Berserk v01.kepub.epub  β†’  Kobo
Tool Version What it does
packer v0.1.0 Groups .cbz chapter archives into volume directories with extracted chapter subdirs
editor v1.0 Injects / dumps / clears EPUB metadata from YAML files
convertor v1.0 Converts volume directories to .kepub.epub via KCC

Prerequisites

  • Python 3.12+ β€” check with python3 --version
  • uv β€” fast Python package manager

kindlecomicconverter (KCC) is a declared Python dependency and is installed automatically by uv sync β€” no separate installation needed.


Installation

# Clone the repository
git clone https://github.com/burgesQ/manga_manager.git
cd manga_manager

# Install all packages and dev dependencies
uv sync

The three CLIs are now available via uv run:

uv run packer --help
uv run editor --help
uv run convertor --help

Shell completion

Each CLI can emit a completion script via --print-completion {bash,zsh,tcsh} (powered by shtab).

Important β€” completion binds to the command word. The generated script registers completion for packer / editor / convertor. It therefore fires on packer <TAB> but not on uv run packer <TAB> β€” in that form the shell is completing uv's arguments, not the CLI's. Pick one of the two setups below.

Option A β€” use the installed entry points directly (recommended)

uv sync installs the console scripts into .venv/bin/. Activate the venv (or put that dir on PATH) so packer is a real command, then install the completion:

source .venv/bin/activate            # now `packer`, `editor`, `convertor` are on PATH

# zsh β€” drop the script on your fpath, then recompile completions
packer    --print-completion zsh > ~/.zfunc/_packer
editor    --print-completion zsh > ~/.zfunc/_editor
convertor --print-completion zsh > ~/.zfunc/_convertor
# ensure ~/.zfunc is on $fpath before `compinit` in ~/.zshrc:
#   fpath=(~/.zfunc $fpath); autoload -Uz compinit && compinit

# bash
packer --print-completion bash | sudo tee /etc/bash_completion.d/packer >/dev/null

Now packer <TAB> completes. (No uv run prefix β€” the venv is active.)

Option B β€” keep the uv run workflow via wrapper functions

If you prefer not to activate the venv, define wrapper functions named after the CLIs; the #compdef packer completion attaches to the function just as it would to a binary:

# ~/.zshrc
MM=~/repo/manga_manager
packer()    { uv run --project $MM packer    "$@"; }
editor()    { uv run --project $MM editor    "$@"; }
convertor() { uv run --project $MM convertor "$@"; }

Install the completion scripts as in Option A. Now packer <TAB> completes and runs via uv run under the hood. (Typing the literal uv run packer <TAB> still won't complete β€” use the packer function instead.)


Full Workflow Example

Starting from a folder of .cbz chapter files downloaded from Tachiyomi:

~/Downloads/Berserk/
β”œβ”€β”€ Berserk - Chapter 001.cbz
β”œβ”€β”€ Berserk - Chapter 002.cbz
β”œβ”€β”€ ...
└── Berserk - Chapter 012.cbz

Step 1 β€” Pack chapters into a volume

uv run packer \
  --path ~/Downloads/Berserk \
  --serie "Berserk" \
  --volume 1 \
  --chapter-range "1..12"

Result:

~/Downloads/Berserk/
└── Berserk v01/
    β”œβ”€β”€ Berserk - Chapter 001.cbz
    β”œβ”€β”€ Chapter 001/
    β”‚   β”œβ”€β”€ 001.jpg
    β”‚   β”œβ”€β”€ 002.jpg
    β”‚   └── ComicInfo.xml
    β”œβ”€β”€ Berserk - Chapter 002.cbz
    β”œβ”€β”€ Chapter 002/
    ...

Step 2 β€” Convert to Kobo format

uv run convertor ~/Downloads/Berserk

Output: ~/Downloads/Berserk/Berserk v01.kepub.epub β€” ready to copy to your Kobo.

Step 3 β€” Create a metadata file

# berserk.yaml
series: "Berserk"
author: "Kentaro Miura"
publisher: "Dark Horse Comics"
language: "en"

volumes:
  - number: 1
    title: "Black Swordsman"
    isbn: "978-1-56931-900-0"
    date: "2003-08-19"

Step 4 β€” Inject metadata into the EPUB

uv run editor inject ~/Downloads/Berserk berserk.yaml

packer

Groups .cbz chapter archives into a volume directory and extracts each into a Chapter NNN/ subdirectory.

Requirements

Every .cbz must contain a ComicInfo.xml β€” packer validates this before processing. Archives from Tachiyomi include it by default.

Basic usage

uv run packer \
  --path <dir>           \  # folder containing .cbz files
  --serie <name>         \  # series name (used to name the volume dir)
  --volume <N>           \  # volume number
  --chapter-range <range>   # e.g. "1..12" or "1,3,5..8"

Chapter ranges

--chapter-range "1..12"       # chapters 1 to 12 (inclusive)
--chapter-range "1,3,5..8"    # chapters 1, 3, 5, 6, 7, 8
--chapter-range "16"          # single chapter (with extras: 16.1, 16.2…)

Named filename patterns

Packer ships with pre-configured regex patterns for common download sources. Pass --pattern <name> to select one:

Flag Matches Extras Source
default Chapter 001, Ch.001, Ch 1 Chapter 001.5 "read dot net" sites (e.g. readberserk.net, generic)
mangafox Ch.013, Ch 013, Chapter 013 Ch.013.5 MangaFox, Tachiyomi downloads
mangafire Chap 013, Chap.013 Chap 013.5 MangaFire
animeSama Chapitre 013, Chap 013 Chapitre 013.5 animesama.fr (French scans)
weebcentral Unknown_# 327_<hash> Unknown_# 327.1_<hash> WeebCentral

Regex details:

Flag Chapter regex Extra regex
default (?i)chapter[\s._-]*0*(\d+) or (?i)ch[\s._-]*0*(\d+) same with \.(\d+) suffix
mangafox (?i)ch(?:\.|apter)?[\s._-]*0*(\d+) …\.(\d+)
mangafire (?i)chap(?:\.|ter)?[\s._-]*0*(\d+) …\.(\d+)
animeSama (?i)chap(?:\.|itre)?[\s._-]*0*(\d+) …\.(\d+)
weebcentral #\s*0*(\d+) …\.(\d+)
# MangaFox download: "Ch.001 Title.cbz", "Ch.001.5.cbz"
uv run packer --path ./Mashle --serie "Mashle" --volume 1 \
  --chapter-range "1..8" --pattern mangafox

# MangaFire download: "Chap 016.cbz", "Chap 016.1.cbz"
uv run packer --path ./FMA --serie "FMA" --volume 4 \
  --chapter-range "16" --pattern mangafire

# Override with a fully custom regex
uv run packer --path ./Series --serie "Series" --volume 1 \
  --chapter-range "1..10" \
  --chapter-regex "Episode ([0-9]+)" \
  --extra-regex "Episode ([0-9]+)\.([0-9]+)"

Extras (e.g. chapter 16.1, 16.2)

Extra chapters are automatically associated with their parent chapter number and processed in numeric order:

# Processes Chapter 16, then 16.1, then 16.2 in order
uv run packer --path ./FMA --serie "FMA" --volume 4 \
  --chapter-range "16" --pattern mangafire

Batch mode β€” multiple volumes at once

# Inline batch spec
uv run packer --path ./Berserk --serie "Berserk" \
  --batch "v01:1..12-v02:13..24-v03:25..36"

# From a batch file (one entry per line: v01,1..12)
uv run packer --path ./Berserk --serie "Berserk" --batch-file berserk.batch

# Auto-discovery: packer looks for a .batch file in --path automatically

Per-path config file (packer.json)

Place a packer.json in the source directory to set defaults. CLI arguments always override it. By default packer looks for <--path>/packer.json; pass --config PATH to load the config from an explicit location instead (a missing --config file is a hard error, unlike the optional default).

{
  "serie": "Berserk",
  "pattern": "mangafox",
  "nb_worker": 2
}

Cover image

Place a cover.webp in the volume directory before running convertor. It will be injected as the first page in the EPUB.

All options

--path PATH              source directory containing .cbz files
--serie NAME             series name
--volume N               volume number
--chapter-range RANGE    chapter range: "1..12", "1,3,5..8"
--dest PATH              output root (default: same as --path)
--pattern NAME           named pattern: mangafox | mangafire | animeSama | weebcentral
--chapter-regex REGEX    custom regex for main chapters
--extra-regex REGEX      custom regex for extra chapters
--batch SPEC             inline batch: "v01:1..3-v02:4..6"
--batch-file PATH        batch file path
--nb-worker N            parallel workers (default: 1)
--force                  overwrite existing chapter directories
--dry-run                simulate without touching the filesystem
--verbose / --loglevel   control log output

Exit codes

Code Meaning
0 Success
2 CLI / argument error
3 Missing chapter
4 Duplicate chapter match
6 Processing error

editor

Manages EPUB metadata from YAML files. Supports a single .epub file or a directory of EPUBs.

Subcommands

inject β€” write metadata into EPUBs

uv run editor inject <path> <metadata.yaml> [options]

# Examples
uv run editor inject ./Berserk berserk.yaml
uv run editor inject "./Berserk v01.epub" berserk.yaml --force
uv run editor inject ./Berserk berserk.yaml --dry-run --verbose
Option Description
--force Overwrite metadata if it already exists
--dry-run Simulate without writing

dump β€” extract metadata from EPUBs to YAML

uv run editor dump <path> [--output file.yaml]

# Print to stdout
uv run editor dump ./Berserk

# Save to file
uv run editor dump ./Berserk --output current.yaml

clear β€” remove all custom metadata

uv run editor clear <path> [--dry-run]

Metadata YAML format

series: "Berserk"
author: "Kentaro Miura"
publisher: "Dark Horse Comics"
language: "en"                    # BCP 47 code; default: "en-US" if omitted

volumes:
  - number: 1
    title: "Black Swordsman"
    isbn: "978-1-56931-900-0"
    date: "2003-08-19"
  - number: 2
    title: "The Shadow"
    isbn: "978-1-56931-980-2"
    date: "2004-01-01"
    language: "fr"                # per-volume override

Top-level keys:

Key Required Description
series yes Series name β†’ calibre:series
author yes Author name β†’ dc:creator
publisher no Publisher β†’ dc:publisher
language no Default language (BCP 47); falls back to en-US

Per-volume keys:

Key Description
number Volume number β†’ calibre:series_index
title Volume title β†’ dc:title
isbn ISBN β†’ dc:identifier
date Release date (YYYY-MM-DD) β†’ dc:date
language Overrides series-level language for this volume

Supported metadata fields

  • Dublin Core: title, creator, identifier (ISBN), publisher, date, language
  • Calibre custom: series, series_index

See metadatas/ for real-world examples (Mashle, FMA, Boruto, etc.).


convertor

Converts volume directories into .kepub.epub files using KindleComicConverter (KCC).

Basic usage

# Convert all volume directories under a root folder
uv run convertor ./Berserk

# Regenerate even if output already exists
uv run convertor ./Berserk --force-regen

# Dry run
uv run convertor ./Berserk --dry-run --verbose

For each subdirectory under <root>, convertor creates a <VolumeDir>.kepub.epub sibling file.

Berserk/
β”œβ”€β”€ Berserk v01/          ← input dir
β”‚   β”œβ”€β”€ Chapter 001/
β”‚   └── ...
β”œβ”€β”€ Berserk v01.kepub.epub  ← generated output

KCC settings

All settings default to the recommended Kobo Manga profile. Override only what you need:

uv run convertor ./Berserk \
  --profile KoF              # different Kobo model (KoF = Kobo Forma)
  --no-manga-style           # disable right-to-left reading order
  --no-hq                    # disable high-quality mode
  --no-forcecolor            # grayscale output
  --rotation 0               # no page rotation (default: 2 = 90Β° CCW)
  --cropping 1               # safe cropping (default: 2 = aggressive)
Flag Default Description
--profile KoLC KCC device profile (KoLC = Kobo Libra Colour)
--[no-]manga-style on Right-to-left reading direction
--[no-]hq on High-quality mode
--[no-]forcecolor on Force colour output
--rotation 0-3 2 Page rotation: 0=none, 1=90CW, 2=90CCW, 3=180Β°
--cropping 0-2 2 Cropping: 0=off, 1=safe, 2=aggressive

Cover image

If a cover.webp file exists at the root of a volume directory, convertor automatically places it as the first page (Chapter 000/) before invoking KCC, then cleans it up afterwards.

Berserk v01/
β”œβ”€β”€ cover.webp              ← optional: will become the EPUB cover
β”œβ”€β”€ Berserk - Ch.001.cbz
β”œβ”€β”€ Chapter 001/
└── ...

Development

# Install all dependencies (including dev tools)
uv sync

# Run the full test suite
uv run pytest .

# Run tests for a single package
uv run pytest packer -q
uv run pytest editor -q
cd convertor && uv run pytest

# Run with coverage
uv run pytest --cov=packer --cov=convertor --cov=editor --cov-report=html . -q

# Linting & formatting
uv run ruff check .
uv run black --check --diff .
uv run isort --profile black --check-only .

# Type checking
uv run mypy packer/src editor/src convertor/src

# Apply auto-fixes
uv run ruff check --fix .
uv run black .
uv run isort --profile black .

# Coverage HTML report (packer)
make -C packer coverage-html

Project structure

manga_manager/
β”œβ”€β”€ packer/           # .cbz β†’ volume dirs
β”‚   β”œβ”€β”€ src/packer/
β”‚   └── tests/
β”œβ”€β”€ editor/           # EPUB metadata management
β”‚   β”œβ”€β”€ src/editor/
β”‚   └── tests/
β”œβ”€β”€ convertor/        # volume dirs β†’ .kepub.epub
β”‚   β”œβ”€β”€ src/convertor/
β”‚   └── tests/
β”œβ”€β”€ metadatas/        # example YAML metadata files
β”œβ”€β”€ CLAUDE.md         # guidance for Claude Code sessions
β”œβ”€β”€ ROADMAP.md        # backlog and open tasks
└── pyproject.toml    # uv workspace root

Roadmap

See ROADMAP.md for the full backlog. Current open priorities:

  • packer: ComicInfo.xml robustness, --flatten/--keep-structure, concurrency rework
  • editor: Calibre tag/ID injection, Kobo collection support
  • convertor: parallel workers, KCC settings via packer.json
  • CI: multi-Python matrix, reviewdog annotations

About

collection of lil python scripts to ease my sailing life into manga πŸ΄β€β˜ οΈ

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages