Skip to main content

Organize downloaded audiobooks into Audiobookshelf library layout

Project description

abs-organize

CLI to place downloaded audiobooks into an Audiobookshelf library layout from embedded tags (and optional folder-name guesses). Copy is the default; use --move to clear the inbox after a successful run.

Layout: {library}/{Author}/[{Series}/]{TitleFolder}/

Requirements: Python 3.11+

Quick start

pip install abs-organize

# One-off (no config file)
abs-organize ~/Downloads/book.m4b --library ~/Audiobooks --dry-run
abs-organize ~/Downloads/book.m4b --library ~/Audiobooks

# With config (see Configuration)
abs-organize ~/Downloads/inbox/MyBook.m4b

Install

From PyPI (recommended):

pip install abs-organize

From a clone:

pip install -e .

For development and tests, see Development.

Usage

abs-organize INPUT [options]

INPUT — one audio file (.mp3, .m4b, .m4a, .flac, .ogg) or a folder of tracks.

Option Purpose
--library PATH Library root for this run (overrides config and env)
--profile NAME Named [libraries.*] profile (default profile when omitted)
--dry-run Show library, destination, and planned ops; no writes
--move Move into the library instead of copy (rename on same FS)
--replace Delete existing destination title folder, then organize
--allow-guess Guess author/title from folder or file name when tags are missing
--batch Organize every detected book under INPUT (multi-book inbox)
--continue-on-error With --batch, keep going after a failure (apply runs only)
--json Success payload on stdout (scripting)
-v, --verbose Path sanitization details on stderr

Metadata overrides (single-book runs): --author, --title, --year, --series, --sequence, --narrator. With --batch, --series, --narrator, and --year may gap-fill empty fields per book; --author, --title, and --sequence are rejected.

Preview, copy, and move

abs-organize ~/Downloads/inbox/SomeBook --dry-run --library ~/Audiobooks
abs-organize ~/Downloads/inbox/SomeBook --library ~/Audiobooks
abs-organize ~/Downloads/inbox/SomeBook --library ~/Audiobooks --move

--dry-run uses the same validation as a real run and prints warnings to stderr, but does not create library paths or transfer files.

Batch inbox

If INPUT contains multiple book roots (e.g. several .m4b siblings), a plain run fails with a candidate list. Use --batch to organize all detected books:

abs-organize ~/Downloads/inbox --batch --library ~/Audiobooks --dry-run
abs-organize ~/Downloads/inbox --batch --library ~/Audiobooks --move

Dry-run always reports every book. On apply, batch stops at the first failure unless --continue-on-error is set.

Discovery (summary): each .m4b/.m4a sibling is its own book; .mp3/.flac/.ogg siblings in one folder are one book; Disc/CD/Disk subfolders roll up to one book at the parent.

Metadata and guessing

Tags are read with Mutagen:

Folder segment Tags
Author albumartist or artist
Title folder album or title (+ optional subtitle via config)
Series grouping; sequence/year/narrator from tags, movement atoms (.m4b/.m4a), or OPF when present

When album or title ends with a trailing narrator clause — (read by …), (narrated by …), or (performed by …) (or the same phrases in square brackets) — that clause is removed from the title folder name. The extracted name becomes narrator only if the composer tag is empty; if composer is set, it wins for the {Narrator} segment and the suffix is still stripped from the title.

Missing author or title tags exit with an error unless --allow-guess is set. Guesses use patterns such as Author - Title or Author - Title (YYYY) on the book folder or file stem; stderr marks them (confidence: low). CLI overrides always win.

Example (series layout):

{library}/Terry Goodkind/Sword of Truth/Vol 1 - 1994 - Wizards First Rule {Sam Tsoutsouvas}/book.m4b

Sidecars (desc.txt, reader.txt, cover images) are copied when present.

Configuration

File: ~/.config/abs-organize/config.toml

include_subtitle_in_folder = false

[libraries.default]
path = "/Users/you/Audiobooks"

[libraries.fiction]
path = "/Users/you/Audiobooks/Fiction"
  • [libraries.default] is required when you omit --library.
  • include_subtitle_in_folder — append - {subtitle} to the title folder name.

Library path precedence

Priority Source
1 --library PATH
2 ABS_ORGANIZE_LIBRARY (only when --profile is omitted)
3 [libraries.{profile}].path when --profile NAME is set
4 [libraries.default].path

Scripting (--json)

On success, stdout is JSON; errors stay on stderr (plain text). Warnings are in the JSON payload, not duplicated on stderr.

Single book:

{
  "destination": "/Users/you/Audiobooks/Jane Author/Book Title/",
  "files": ["book.mp3"],
  "warnings": []
}

Batch:

{
  "books": [
    {
      "source": "/inbox/Book A/",
      "ok": true,
      "destination": "/Audiobooks/Author/Title/",
      "files": ["book.m4b"],
      "warnings": []
    }
  ],
  "summary": { "ok": 1, "failed": 0 }
}

Unknown top-level keys may be added later; ignore fields you do not need.

Exit codes

Code Meaning
0 Success
1 User or metadata error (missing tags, invalid paths, config/profile errors)
2 I/O error (copy, move, or filesystem failure)

Batch: 0 only if every book succeeded; partial failure uses 1 or 2 if any book hit I/O errors.

Development

Release policy: see docs/RELEASE.md.

CI: GitHub Actions runs pytest on every push and pull request (.github/workflows/ci.yml). Require the CI status check to pass before merging to main (Settings → Branches → Branch protection rules).

Path Role
src/abs_organize/cli.py Argument parsing and entry point
src/abs_organize/organize.py Single-book copy/move pipeline
src/abs_organize/batch.py Multi-book inbox orchestration
src/abs_organize/discovery.py Book-root detection
src/abs_organize/metadata.py Tag read, validation, overrides
src/abs_organize/naming.py ABS-style path segments
tests/ Pytest suite (test_data/ for fixtures)
pip install -e ".[dev]"
pytest
abs-organize --help

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

abs_organize-0.1.1.tar.gz (40.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

abs_organize-0.1.1-py3-none-any.whl (28.5 kB view details)

Uploaded Python 3

File details

Details for the file abs_organize-0.1.1.tar.gz.

File metadata

  • Download URL: abs_organize-0.1.1.tar.gz
  • Upload date:
  • Size: 40.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for abs_organize-0.1.1.tar.gz
Algorithm Hash digest
SHA256 13c1754852b63b40e0e6d9792ed8449d084c4227ca1c99433e9752a615800d6f
MD5 cd208b0a4ac7e2d464da607b2769befb
BLAKE2b-256 ec608d19d9bbfb467985729836dc23f261ec2c6410f75ba9c1054312ca35c1a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for abs_organize-0.1.1.tar.gz:

Publisher: release.yml on trevordavies095/abs-organize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file abs_organize-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: abs_organize-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 28.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for abs_organize-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f3c7d470afbb9a0c60970480e91b908fc1839b150554db3d6f14b043815b6aa2
MD5 f991f5f30b319b30a53f7dbd16984ca4
BLAKE2b-256 34d9e3a85b2b6d887d706346da8d40d54ab0a12a579d472423ebfaeb29dd573f

See more details on using hashes here.

Provenance

The following attestation bundles were made for abs_organize-0.1.1-py3-none-any.whl:

Publisher: release.yml on trevordavies095/abs-organize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page