| docs/superpowers | ||
| examples | ||
| tests | ||
| .gitignore | ||
| auto_download.py | ||
| build_kometa.py | ||
| build_metadata.py | ||
| conftest.py | ||
| download_muhn_pace.py | ||
| dub_official.json | ||
| find_missing.py | ||
| fix_library.py | ||
| LICENSE | ||
| manual_match.py | ||
| one-pace-combined.json | ||
| one-pace.yml | ||
| one_pace_mover.py | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| write_nfo.py | ||
🏴☠️ DubPacerr
Build and maintain an English‑dub One Pace library in Plex — automatically.
One Pace fixes the pacing of One Piece, but watching it dubbed means stitching together official dual‑audio releases and the fan‑made Muhn Pace dub edits, with metadata split across two projects that each miss what the other has. DubPacerr does the whole pipeline: merges the metadata (real titles + plot summary and manga/anime coverage, sub and dub), downloads what you're missing (official dual‑audio via qBittorrent, Muhn Pace dub fills via Pixeldrain), files episodes by content hash keeping only English audio, and decorates Plex through Kometa.
Named in the spirit of OnePacerr — but dub-first.
TL;DR — what it does
- 🧩 Merges two metadata sources into one (
one-pace-combined.json):ladyisatis/one-pace-metadata→ official episode titles, plot summaries, and the file‑matching hashes (incl. the Muhn Pace dub map).chase-roohms/kometa-configs→ season posters, logo, theme, saga grouping, and manga/anime coverage.
- 📝 Builds a Kometa metadata file (
one-pace.yml) so Plex shows the merged titles + "narrative + Covers anime/manga" summaries + posters. - 📦 Names & files your episodes (
one_pace_mover.py) — matches downloads (official by filename CRC, dub by content hash) and moves them toSeason NN/One Pace - SxxEyy - Title.ext. No OnePaceOrganizer needed (though it's a great tool — this just gives you one combined source and full control). - 🤖 Runs on autopilot — a cron wrapper moves new episodes as they download and refreshes Plex + Kometa.
Just want the pretty metadata in Plex and nothing else? Skip straight to Quick start: Kometa only. You only need one file.
Quick start A — Kometa only (just metadata)
If your One Pace files are already named SxxEyy and you just want Plex to look great:
- Grab
one-pace.ymlfrom this repo (or regenerate it — see below). - Drop it into your Kometa config folder (next to
config.yml). - In
config.yml, under the library that holds your One Pace show, add:metadata_files: - file: /config/one-pace.yml - Run Kometa:
docker exec kometa python3 kometa.py --run --metadata-only --run-libraries "YourLibraryName"
That's it — titles, summaries (with manga/anime coverage), season posters, logo and theme get applied to your "One Pace" show.
…or pull the metadata straight from this repo (no download)
The generated one-pace.yml is hosted here, so you can point Kometa at it by URL and never download or regenerate anything:
metadata_files:
- url: https://git.ourserver.party/xenarathon/DubPacerr/raw/branch/main/one-pace.yml
It's refreshed as the upstream projects add episodes, so your library stays current automatically.
What is Kometa, and do I need it?
Kometa (formerly Plex Meta Manager) is a tool that applies metadata, posters and collections to Plex from simple YAML files. It's the cleanest way to give a personal media show like One Pace proper episode titles and art, because Plex's normal "agents" don't know what One Pace is. You run it in Docker; it talks to your Plex and applies whatever the YAML says. Metadata it applies lives in Plex's database, so it survives file changes and you can re‑apply any time.
Quick start B — full pipeline (also auto‑file your episodes)
This adds the file mover, which takes freshly downloaded One Pace + Muhn Pace files and drops them into your library, correctly named.
# 1. (optional) regenerate the combined source + Kometa file from upstream
python3 build_metadata.py # -> one-pace-combined.json
python3 build_kometa.py # -> one-pace.yml
# 2. dry-run the mover to SEE what it would do (moves nothing)
python3 one_pace_mover.py \
--metadata one-pace-combined.json \
--src "/path/to/downloads/One Pace" \
--src "/path/to/downloads/One Pace Dub (Muhn Pace)" \
--library "/path/to/Plex/Anime/One Pace" \
--dry-run
# 3. drop --dry-run to actually move them
Then wire it to cron with the example in examples/ so new episodes file themselves. See Personalize it for the exact things to change.
Requirements
- Python 3.11+ (3.13+ recommended). The mover uses only the standard library;
build_metadata.py/build_kometa.pyneedpyyaml(pip install -r requirements.txt). - For Plex metadata: a working Kometa install pointed at your Plex.
- For the mover: your downloads and your Plex library should be on the same filesystem if you want instant moves (a cross‑filesystem move still works, it just copies+deletes).
- Running as root may be required if your downloaded files are owned by another user (e.g. your download client's user) — see the note in the cron example.
How the combine works
Both upstream projects number episodes the same way (Season = arc, both derived from the official One Pace Episode Guide), so we merge on (season, episode). For each episode slot we take the best of both:
| Field | Comes from |
|---|---|
| Episode title | ladyisatis (official) → Muhn Pace → chase‑roohms (whichever exists first) |
| Plot narrative | ladyisatis |
| Coverage ("Covers anime episode(s) / manga chapter(s)") | ladyisatis structured fields, formatted chase‑roohms‑style |
| Season poster / background / logo / theme / saga | chase‑roohms |
| File‑matching hashes (official + dub) | ladyisatis |
The episode summary ends up as the narrative plus the coverage lines:
The keepers of Shift Station, Kokoro and her granddaughter Chimney, point the
Straw Hats in the direction of the metropolitan Water Seven...
Covers anime episode(s): 228 - 230
Covers manga chapter(s): 322 - 324
Why the dub "just works" too
Muhn Pace episodes are English‑dub edits built on top of the One Pace cuts — same episodes, different audio. ladyisatis ships an other_edits/muhn_pace table that maps each dub file (by content hash) to its canonical One Pace (season, episode) — even resolving the messy spots where the dub's own file numbering drifts (e.g. parts of Wano). So a dub file lands in the same slot as its subbed counterpart and inherits that slot's title, summary and art automatically.
How the mover matches files (no OnePaceOrganizer needed)
- Official One Pace releases carry a CRC32 in the filename, e.g.
...[B4592974].mkv→ instant lookup, no hashing. - Muhn Pace dub files have no CRC in the name → the mover reads the file and computes its CRC32 + blake2s, then looks it up in the combined source.
Matched files are moved to Season NN/One Pace - SxxEyy - Title.ext. The mover never overwrites, skips half‑downloaded files, caches hashes so re‑runs are fast, and uses a lock so cron runs never overlap.
Personalize it
Everything is parameterized — here's the short list of what you change:
- Paths — in your copy of
examples/run-mover.sh: your media root, your download folder(s), and your PlexOne Pacelibrary folder. - Plex library name / section — in Kometa's
config.yml(the library name) and, if you use the cron wrapper, the Plex section number it refreshes. - (optional) Title style —
TITLE_PRECEDENCEnear the top ofbuild_metadata.py. Default["ladyisatis", "muhn_pace", "chase"]gives clean official titles; put"chase"first if you prefer the more descriptive ones. - (optional) Posters — the artwork URLs come from chase‑roohms' asset repo (the "NeonVariant" set). Swap them in
one-pace.ymlif you like a different look.
Keeping metadata when you transcode (e.g. Tdarr)
Kometa metadata lives in Plex's database, keyed by season/episode — so it survives transcoding and you can re‑apply any time. But run the mover before you transcode the dub files: the mover identifies dub files by their content hash, and transcoding changes that hash. Order: download → mover → transcode → (re‑run Kometa).
Scripts
| Script | What it does |
|---|---|
build_metadata.py |
Fetches both upstreams (by URL, or --ladyisatis/--chase local paths) and writes one-pace-combined.json — the single source of truth. |
build_kometa.py |
Turns one-pace-combined.json into one-pace.yml for Kometa. |
one_pace_mover.py |
Matches episodes and places them in your library (default hardlink — keeps the download for seeding and uses no extra space; --link-mode move|copy|symlink to change). --dry-run to preview. |
fix_library.py |
Tidy an existing library: rename bare/mis-named files (e.g. One Pace S14E05.mkv) to canonical, and report duplicate episodes. Read-only by default; --apply to rename. |
find_missing.py |
Audit vs the metadata: list missing episodes, unmatched downloads, and (--verify) library files whose CRC32 is outdated. Read-only. |
auto_download.py |
Find missing official episodes on the One Pace release RSS feed and queue them in qBittorrent (matched exactly by CRC32). Report-only without --add. |
download_muhn_pace.py |
Download the missing Muhn Pace dub files from the Pixeldrain mirrors (skips what you already have, by size). Supports your own Pixeldrain API key for paid full-speed downloads. |
manual_match.py |
For files with no known release hash (e.g. dub releases not yet indexed upstream): list them with their arc/season + episode titles and emit a starter overrides.json to feed one_pace_mover.py --overrides. |
examples/run-mover.sh |
Example cron wrapper: move new episodes, then refresh Plex + run Kometa. |
Re‑run build_metadata.py whenever the upstream projects add episodes (new arcs, new dub releases). It pulls fresh each time.
Automated downloading (OnePacerr-style)
Inspired by OnePacerr, auto_download.py closes the loop on the official side:
- Works out which canonical episodes you're missing (metadata vs library).
- Pulls the One Pace release RSS feed (each item's magnet filename carries the CRC32).
- Matches missing episodes to releases by CRC32 — exact, no fuzzy title guessing.
- Sends the magnets to qBittorrent under a category, skipping anything already there.
python3 auto_download.py \
--metadata one-pace-combined.json --library "/path/to/One Pace" \
--qbit-host http://127.0.0.1:8080 --qbit-user USER --qbit-pass PASS \
--category onepace # report only; add --add to actually queue
The mover + Kometa then file and decorate whatever qBittorrent finishes — fully hands-off. Dub-only gaps (Muhn Pace) aren't on this feed; those come from the dub sources.
Toggles
--prefer-extended— when both a standard and an "Extended Cut" release exist, grab the extended one.--include-specials— include the April-Fools / specials season (0) in the missing list (off by default; the mover still files specials it finds).find_missing.py --verify— hash your existing files and flag any whose CRC32 doesn't match the expected release, so you can re-grab outdated copies.
Building a dub-only (English) collection
The One Pace RSS/metadata has no English-audio flag, so dub-only works in two layers:
auto_download.py --dub-only dub_official.json— only queues episodes that have an official English dub, perdub_official.json(derived from the dub watch guide; edit it as One Pace dubs more arcs). Episodes the guide fills from Muhn Pace are skipped here and come from the dub sources instead.one_pace_mover.py --require-audio eng— at filing,ffprobechecks each file's audio tracks and skips anything explicitly non-English (untagged/unknown audio is kept — fail-open). Dual-audio (jpn,eng) and dub (eng) files pass; sub-only (jpn) is rejected. Requiresffprobe, so run the mover from an ffmpeg-capable image.download_muhn_pace.py— grabs the Muhn Pace dub fills (the arcs One Pace hasn't dual-audio'd) from the Pixeldrain mirrors, fetching only what you're missing.
# bring your own Pixeldrain API key for paid full-speed downloads (free works, just throttled)
PIXELDRAIN_API_KEY=... python3 download_muhn_pace.py \
--dest "/path/to/downloads/One Pace Dub (Muhn Pace)" \
--library "/path/to/Plex/One Pace" # so already-filed episodes aren't re-downloaded
Manually matching files with no known hash
Some releases (often newer dub batches) aren't in the upstream metadata yet, so they can't be hash-matched. To file them with the correct title/summary anyway:
# 1. generate a starter map (lists each unmatched file + its arc/season + episode titles)
python3 manual_match.py --metadata one-pace-combined.json --src "/path/to/downloads/..."
# 2. edit overrides.template.json, filling in the episode numbers (S35E60, ...)
# 3. file them, inheriting that slot's metadata
python3 one_pace_mover.py --metadata one-pace-combined.json --overrides overrides.template.json ...
NFO metadata (Jellyfin / Plex .nfo agent)
Kometa decorates Plex. If you also run Jellyfin (or prefer Plex's local
XBMCnfoTVImporter agent), write_nfo.py writes portable Kodi-flavor NFO sidecars into the
library from the same one-pace-combined.json:
tvshow.nfoat the library root (title, plot, studio, genre, poster/logo/fanart URLs)season.nfoin eachSeason NN/(season number + title)One Pace - SxxEyy - Title.nfonext to each episode (title, season/episode, plot, aired, runtime)
Matching is by the SxxEyy in each filename, not by content hash — so episodes already
re-encoded to AV1 (or any other codec/remux) are covered.
Backfill an existing library once:
python3 write_nfo.py --library "/path/to/Plex/Anime/One Pace"
Add --dry-run to preview. Re-runs are idempotent (overwrite/refresh).
Keep it current: the mover writes each episode's NFO as it files new downloads (pass
--no-write-nfo to disable). A daily write_nfo.py sweep (see examples/crontab.example)
refreshes show/season/episode NFOs and backfills newly-AV1'd files.
Plex: enable the XBMCnfoTVImporter agent on the One Pace library to read these. Jellyfin: reads NFO by default — no config needed.
Automating with cron
See examples/crontab.example. The gist: run run-mover.sh every 15 minutes — it files any newly‑downloaded episodes and, only when something actually moved, refreshes your Plex library and triggers a Kometa metadata run. Idle runs do nothing.
Roadmap
- GUI version (planned, future branch) — a friendly interface for less technical users to point at their folders and Plex and click "go," instead of editing scripts and cron.
- Pass to rename existing library files in place + flag duplicates — see
fix_library.py.
Thanks / Credits
This tool only stitches together other people's hard work:
- The One Pace Team — the recut project itself, and the Episode Guide all this metadata comes from.
- ladyisatis/one-pace-metadata — episode titles, summaries, and the file‑matching + dub hash tables.
- chase-roohms/kometa-configs — the Kometa metadata, posters, logo and theme.
- Muhny (D Goat) — Muhn Pace, the English‑dub edits, and the dub watch guide community.
- eltharynd/OnePacerr — the RSS→qBittorrent auto-download approach and library-gap workflow that inspired
auto_download.pyandfind_missing.py.
License
GPL-3.0 — see LICENSE. This repo contains no One Pace video or copyrighted material, only metadata pointers and tooling.
🤖 Disclaimer: this project was built with the help of Claude (Opus 4.8), Anthropic's AI assistant.