Skip to content

CLI

The CLI (Command Line Interface) provides direct, scriptable access to all audiobook organization features for automation and batch processing.

The CLI is designed for:

  • Automation - Scripts, cron jobs, scheduled tasks
  • Batch processing - Process multiple directories
  • CI/CD integration - Automated workflows
  • Docker containers - Isolated execution environments
  • Power users - Direct control without interactive prompts

Best for: Automation, scripts, batch processing, CI/CD pipelines, users who prefer direct command execution

Not ideal for: First-time users, exploring metadata, trial-and-error configuration (use GUI or TUI instead)


Terminal window
# macOS/Linux via Homebrew
brew tap jeeftor/tap
brew install audiobook-organizer
# Debian/Ubuntu
sudo apt install audiobook-organizer
# RedHat/Fedora
sudo yum install audiobook-organizer
# Alpine
sudo apk add audiobook-organizer
# Go install
go install github.com/jeeftor/audiobook-organizer@latest
# Docker
docker pull jeffsui/audiobook-organizer:latest

See also: INSTALLATION.md for detailed platform-specific instructions


Generate local command-line documentation captures from the repository root. The output files are local-only and ignored by git:

Terminal window
make docs-cli-captures

The workflow builds the CLI binary, copies committed LibriVox sample media from testdata/mp3flat/ into generated sample data under output/docs-cli-sample/, runs representative non-interactive commands, renders terminal-style static PNG captures with Playwright, and writes them under output/docs-visuals/cli/.

Current capture names are help, organize-dry-run, metadata-inspect, and rename-preview. Regenerate one or more specific captures with:

Terminal window
ABO_DOCS_CLI_CAPTURES=help,metadata-inspect make docs-cli-captures

If Playwright-managed Chromium is not installed, run:

Terminal window
cd web && npm run install:browsers

Generate animated CLI GIFs with VHS:

Terminal window
make docs-cli-gifs

Current GIF capture names are organize-run, metadata-inspect, and rename-preview. The organize run GIF stages fresh sample files, executes a real non-dry-run organize command, and lists the organized output files. Regenerate one or more specific GIFs with:

Terminal window
ABO_DOCS_CLI_GIFS=organize-run,rename-preview make docs-cli-gifs

You can also point the PNG workflow at an existing Chrome or Chrome Headless Shell binary with ABO_DOCS_BROWSER_EXECUTABLE_PATH=/path/to/chrome make docs-cli-captures. Static PNG captures require cwebp and generate WebP companions. Animated GIF captures are optimized with gifsicle -O3 when gifsicle is available; set ABO_DOCS_GIF_OPTIMIZE=0 to skip that pass. The aggregate make docs-visuals target includes web UI screenshots, static CLI PNG captures, and animated CLI GIF captures, and CI uploads the generated files as docs visual artifacts.


Terminal window
# Organize in place (input = output)
audiobook-organizer --dir=/path/to/audiobooks
# Organize to separate output directory
audiobook-organizer --dir=/source --out=/organized
# Preview changes without moving files
audiobook-organizer --dir=/source --out=/organized --dry-run
# Verbose output
audiobook-organizer --dir=/source --out=/organized --verbose
Terminal window
# Rename with default template
audiobook-organizer rename --dir=/path/to/audiobooks
# Rename with custom template
audiobook-organizer rename --dir=/path --template="{author} - {series} {series_number} - {title}"
# Preview renames
audiobook-organizer rename --dir=/path --dry-run
# Use Last, First author format
audiobook-organizer rename --dir=/path --author-format=last-first
Terminal window
# Undo previous organization (reads .abook-org.log)
audiobook-organizer --dir=/path --undo
# Undo previous rename
audiobook-organizer rename --dir=/path --undo

FlagAliasesDescription
--dir--inputInput directory containing audiobooks (required)
FlagAliasesDefaultDescription
--out--outputSame as --dirOutput directory for organized files
--config-~/.audiobook-organizer.yamlConfig file path
--dry-run-falsePreview changes without executing
--verbose-vfalseShow detailed progress
--prompt-falseReview and confirm each book move
--undo-falseRestore files to original locations
--remove-empty-falseRemove empty directories
--replace_space-(none)Character to replace spaces
--use-embedded-metadata-falseExtract metadata from audio files
--flat-falseProcess files individually (auto-enables --use-embedded-metadata)
--skip-errors-falseSkip files with missing/invalid metadata instead of stopping
--layout-author-series-titleDirectory structure pattern
--layout-template-(none)Custom directory layout template that overrides --layout
--author-fields-authorsComma-separated fields to try for author
--series-field-seriesField to use as series
--title-field-titleField to use as title
--track-field-trackField to use for track number
--disc-field-discField to use for disc number (e.g., disc, discnumber, disk, tpos)

Seven directory structure patterns:

Terminal window
# Standard (default): Author/Series/Title/
--layout=author-series-title
# Numbered series: Author/Series/#1 - Title/
--layout=author-series-title-number
# Series-focused: Author/Series/ (multi-file books in series folder)
--layout=author-series
# No series: Author/Title/
--layout=author-title
# Flat per author: Author/
--layout=author-only
# Series without author: Series/Title/
--layout=series-title
# Series without author, numbered: Series/#1 - Title/
--layout=series-title-number

See also: LAYOUTS.md for detailed layout comparison

Basic organization:

Terminal window
audiobook-organizer --dir=/media/audiobooks

Organize to separate directory:

Terminal window
audiobook-organizer \
--dir=/media/unorganized \
--out=/media/organized

Preview changes first:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--dry-run \
--verbose

Use embedded metadata (MP3/M4B files):

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--use-embedded-metadata

Flat mode for single-file audiobooks:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--flat

Custom layout:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--layout=author-title

Custom layout template:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--layout-template="{author}/{series}/{series-count} - {title} ({narrator})"

Show the available layout template fields and syntax:

Terminal window
audiobook-organizer layout-template

Replace spaces with underscores:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--replace_space=_

Interactive prompt mode:

Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--prompt

FlagDescription
--dirDirectory containing audiobooks (required)
FlagDefaultDescription
--template{author} - {series} {series_number} - {title}Filename template with placeholders
--author-formatfirst-lastAuthor name format: first-last, last-first, preserve
--recursivetrueRecursively process subdirectories
--preserve-pathtrueOnly rename filename, keep directory structure
--promptfalsePrompt before renaming each file
--strictfalseError on missing template fields
--undofalseUndo previous rename operations
--dry-runfalsePreview renames without executing
--author-fieldsauthorsComma-separated fields to try for author
--title-fieldtitleField to use as title
--series-fieldseriesField to use as series
--track-fieldtrackField to use for track number
--disc-fielddiscField to use for disc number (e.g., disc, discnumber, tpos)

Available placeholders for --template:

FieldDescriptionExample
{author}First author (formatted per --author-format)Brandon Sanderson
{authors}All authors (comma-separated)Brandon Sanderson, Dan Wells
{title}Book titleThe Final Empire
{series}Series name (without number)Mistborn
{series_number}Series number only1
{track}Track number (zero-padded)01
{album}Album fieldMistborn Era 1
{year}Publication year2006
{narrator}Narrator (if available)Michael Kramer

Rename with custom template:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{author} - {track} - {title}"

Use Last, First author format:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{author} - {title}" \
--author-format=last-first

Include series information:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{series} {series_number} - {track} - {title}"

Preview renames first:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{author} - {title}" \
--dry-run

With field mapping:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{author} - {title}" \
--author-fields="narrators,authors" \
--title-field="album"

Interactive prompt mode:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--template="{author} - {title}" \
--prompt

Undo previous renames:

Terminal window
audiobook-organizer rename \
--dir=/media/audiobooks \
--undo

For files with non-standard metadata structures (especially MP3 files), use field mapping flags to specify which fields contain author, title, series, etc.

Comma-separated list of fields to try in priority order:

Terminal window
--author-fields="authors,narrators,album_artist,artist"

How it works:

  1. Try first field (authors)
  2. If empty, try next field (narrators)
  3. Continue until a non-empty field is found
  4. Use first non-empty value

Common configurations:

Terminal window
# For Audiobookshelf metadata
--author-fields="authors"
# For standard MP3s
--author-fields="artist,album_artist"
# For audiobooks with narrator as artist
--author-fields="narrators,artist,album_artist,authors"

Single field to use for book title:

Terminal window
--title-field="album" # Use album tag as title
--title-field="title" # Use title tag (default)

Common use cases:

  • MP3 files where album contains book title: --title-field="album"
  • Standard metadata: --title-field="title"

Single field to use for series information:

Terminal window
--series-field="series" # Use series tag (default)
--series-field="album" # Use album tag as series

Single field to use for track numbers:

Terminal window
--track-field="track" # Use track tag (default)
--track-field="track_number" # Alternative field name
Terminal window
audiobook-organizer \
--dir=/media/audiobooks \
--use-embedded-metadata \
--author-fields="narrators,album_artist,artist" \
--title-field="album" \
--series-field="series" \
--track-field="track" \
--layout=author-series-title

See also: METADATA.md for detailed field mapping guide


All flags can be set via environment variables with either AO_ or AUDIOBOOK_ORGANIZER_ prefix:

Terminal window
# Input directory (any of these work)
export AO_DIR="/path/to/audiobooks"
export AO_INPUT="/path/to/audiobooks"
export AUDIOBOOK_ORGANIZER_DIR="/path/to/audiobooks"
export AUDIOBOOK_ORGANIZER_INPUT="/path/to/audiobooks"
# Output directory (any of these work)
export AO_OUT="/path/to/output"
export AO_OUTPUT="/path/to/output"
export AUDIOBOOK_ORGANIZER_OUT="/path/to/output"
export AUDIOBOOK_ORGANIZER_OUTPUT="/path/to/output"
Terminal window
# Short prefix (AO_)
export AO_REPLACE_SPACE="_"
export AO_VERBOSE=true
export AO_REMOVE_EMPTY=true
export AO_USE_EMBEDDED_METADATA=true
export AO_LAYOUT="author-series-title"
export AO_AUTHOR_FIELDS="authors,narrators,album_artist,artist"
export AO_SERIES_FIELD="series"
export AO_TITLE_FIELD="album,title"
export AO_TRACK_FIELD="track,track_number"
# Long prefix (AUDIOBOOK_ORGANIZER_)
export AUDIOBOOK_ORGANIZER_REPLACE_SPACE="_"
export AUDIOBOOK_ORGANIZER_VERBOSE=true
export AUDIOBOOK_ORGANIZER_REMOVE_EMPTY=true
export AUDIOBOOK_ORGANIZER_USE_EMBEDDED_METADATA=true
export AUDIOBOOK_ORGANIZER_LAYOUT="author-series-title"
export AUDIOBOOK_ORGANIZER_AUTHOR_FIELDS="authors,narrators,album_artist,artist"

Precedence: CLI flags > Environment variables > Config file > Defaults

See also: CONFIGURATION.md for complete configuration guide


Run the CLI in a Docker container for isolated execution:

Terminal window
# Process current directory
docker run -v $(pwd):/books \
jeffsui/audiobook-organizer --dir=/books
# Process specific directory
docker run -v /path/to/audiobooks:/books \
jeffsui/audiobook-organizer --dir=/books
Terminal window
# Mount source (read-only) and destination directories
docker run \
-v /path/to/source:/input:ro \
-v /path/to/destination:/output \
jeffsui/audiobook-organizer --dir=/input --out=/output
Terminal window
# Use -it for interactive mode
docker run -it \
-v /path/to/source:/input:ro \
-v /path/to/destination:/output \
jeffsui/audiobook-organizer --dir=/input --out=/output --prompt
Terminal window
# Preview changes without moving files
docker run \
-v /path/to/source:/input:ro \
-v /path/to/destination:/output \
jeffsui/audiobook-organizer --dir=/input --out=/output --dry-run --verbose
Terminal window
# Mount config file
docker run \
-v $(pwd)/.audiobook-organizer.yaml:/config.yaml:ro \
-v /path/to/books:/books \
jeffsui/audiobook-organizer --dir=/books --config=/config.yaml
Terminal window
# Pass environment variables
docker run \
-e AO_LAYOUT=author-title \
-e AO_VERBOSE=true \
-v /path/to/books:/books \
jeffsui/audiobook-organizer --dir=/books
version: '3.8'
services:
audiobook-organizer:
image: jeffsui/audiobook-organizer:latest
volumes:
- /path/to/source:/input:ro
- /path/to/destination:/output
- ./config.yaml:/config.yaml:ro
environment:
- AO_LAYOUT=author-series-title
- AO_VERBOSE=true
command: --dir=/input --out=/output --config=/config.yaml
  • :ro suffix - Mount volume as read-only (recommended for source)
  • Container paths - Must match --dir and --out parameters
  • Log files - Written to output directory (.abook-org.log)
  • Multiple mounts - Can mount multiple directories
  • Same directory - Source and destination can be the same

#!/bin/bash
# Process multiple audiobook directories
DIRS=(
"/media/audiobooks/sci-fi"
"/media/audiobooks/fantasy"
"/media/audiobooks/non-fiction"
)
for dir in "${DIRS[@]}"; do
echo "Processing: $dir"
audiobook-organizer \
--dir="$dir" \
--layout=author-series-title \
--verbose
done
Terminal window
# Add to crontab: crontab -e
# Run every night at 2 AM
0 2 * * * /usr/local/bin/audiobook-organizer \
--dir=/media/audiobooks \
--out=/media/organized \
--remove-empty \
>> /var/log/audiobook-organizer.log 2>&1
name: Organize Audiobooks
on:
push:
paths:
- 'audiobooks/**'
jobs:
organize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install audiobook-organizer
run: |
wget https://github.com/jeeftor/audiobook-organizer/releases/latest/download/audiobook-organizer_Linux_x86_64.tar.gz
tar xzf audiobook-organizer_Linux_x86_64.tar.gz
chmod +x audiobook-organizer
- name: Organize audiobooks
run: |
./audiobook-organizer \
--dir=./audiobooks \
--out=./organized \
--verbose
- name: Upload organized files
uses: actions/upload-artifact@v3
with:
name: organized-audiobooks
path: organized/
#!/usr/bin/env python3
import subprocess
import json
def organize_audiobooks(input_dir, output_dir, layout="author-series-title", dry_run=False):
"""Organize audiobooks using CLI"""
cmd = [
"audiobook-organizer",
f"--dir={input_dir}",
f"--out={output_dir}",
f"--layout={layout}",
"--verbose"
]
if dry_run:
cmd.append("--dry-run")
result = subprocess.run(cmd, capture_output=True, text=True)
return {
"success": result.returncode == 0,
"stdout": result.stdout,
"stderr": result.stderr
}
# Usage
result = organize_audiobooks(
input_dir="/media/audiobooks",
output_dir="/media/organized",
dry_run=True
)
print(json.dumps(result, indent=2))
Terminal window
# Organize audiobooks on Windows
param(
[string]$InputDir = "C:\Audiobooks",
[string]$OutputDir = "C:\Organized",
[string]$Layout = "author-series-title"
)
Write-Host "Organizing audiobooks from $InputDir to $OutputDir"
& audiobook-organizer `
--dir=$InputDir `
--out=$OutputDir `
--layout=$Layout `
--verbose
if ($LASTEXITCODE -eq 0) {
Write-Host "Organization complete!" -ForegroundColor Green
} else {
Write-Host "Organization failed!" -ForegroundColor Red
exit $LASTEXITCODE
}

Flat Mode (--flat):

  • Processes each file independently based on its metadata
  • Files grouped only if they have identical metadata
  • Auto-enables --use-embedded-metadata
  • Good for: Single-file audiobooks, mixed collections
Terminal window
audiobook-organizer --dir=/books --flat

Skipping bad files (--skip-errors):

Use with --flat when your collection has mixed metadata quality. Files with missing or invalid metadata (e.g., no author tag) are skipped with a warning instead of stopping the entire run. Files with good metadata are still organized.

Terminal window
audiobook-organizer \
--dir=/books \
--flat \
--skip-errors \
--dry-run

Non-Flat Mode (default):

  • All files in a directory treated as one book
  • Shared metadata per directory
  • Good for: Multi-file audiobooks, pre-organized collections
Terminal window
audiobook-organizer --dir=/books

See also: METADATA.md for detailed comparison

metadata.json files (default):

Terminal window
audiobook-organizer --dir=/books

Embedded metadata (EPUB, MP3, M4B):

Terminal window
audiobook-organizer --dir=/books --use-embedded-metadata

Hybrid mode (automatic):

  • When metadata.json exists alongside audio files
  • Book-level metadata from JSON
  • Track-level metadata from audio files
  • No special flag needed

See also: METADATA.md for metadata extraction guide

All operations are logged to .abook-org.log in the output directory:

Terminal window
# Undo organization
audiobook-organizer --dir=/source --out=/dest --undo
# Undo rename
audiobook-organizer rename --dir=/books --undo

Log file format: JSON with source/target paths for each operation

Limitations:

  • Only works if log file exists
  • Can’t undo if files were manually modified after organization
  • Undo reverses operations in reverse order

The CLI includes commands for integrating with Audiobookshelf (ABS), a self-hosted audiobook and podcast server.

ABS integration provides:

  • Metadata scanning - Compare local files against ABS library metadata
  • ABS metadata organization - Reorganize already-indexed ABS items using ABS as the metadata source
  • Library scanning - Trigger ABS library scans after file operations
  • Real-time events - WebSocket connection for scan status monitoring
  • Custom headers - Support for Cloudflare Access and other proxy authentication

Compare local files against ABS library to identify organization needs:

Terminal window
# SQLite + API mode (auto path discovery from ABS database)
audiobook-organizer abs scan \
--abs-sqlite=/var/lib/audiobookshelf/config/abs.sqlite \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--dir=/mnt/audiobooks
# API-only mode (manual path mapping)
audiobook-organizer abs scan \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--abs-path-map="/audiobooks:/mnt/audiobooks" \
--dir=/mnt/audiobooks
# Show all items (not just mismatches)
audiobook-organizer abs scan --all
# Verify local file existence
audiobook-organizer abs scan --check-files

Output:

  • ✓ Files in correct location
  • 🚚 Files need to be moved
  • ✗ Files missing from disk

Organize items that Audiobookshelf already indexed. ABS supplies the metadata and path mapping, then Audiobook Organizer reuses the normal organizer move, dry-run, undo, layout, logging, and prompt behavior.

Terminal window
# Preview moves without changing files
audiobook-organizer abs organize \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--abs-library=Audiobooks \
--abs-path-map="/audiobooks:/mnt/audiobooks" \
--dir=/mnt/audiobooks \
--layout=author-title \
--dry-run
# Move files in place using ABS metadata
audiobook-organizer abs organize \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--abs-library=Audiobooks \
--abs-path-map="/audiobooks:/mnt/audiobooks" \
--dir=/mnt/audiobooks \
--layout=author-title
# Move files with a custom layout template
audiobook-organizer abs organize \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--abs-library=Audiobooks \
--abs-path-map="/audiobooks:/mnt/audiobooks" \
--dir=/mnt/audiobooks \
--layout-template="{author}/{series}/{series-count} - {title}"
# Undo the previous ABS metadata organization run
audiobook-organizer abs organize --dir=/mnt/audiobooks --undo

After non-dry-run moves, run abs scan-trigger for the touched ABS library so Audiobookshelf can mark old paths missing, discover the organized paths, and then clean up missing rows through your normal ABS workflow.

Trigger ABS to rescan a library (useful after moving files):

Terminal window
# Trigger scan for default library
audiobook-organizer abs scan-trigger \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG...
# Trigger scan for specific library
audiobook-organizer abs scan-trigger \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG... \
--abs-library=lib_abc123

abs websocket-test - Test WebSocket Connection

Section titled “abs websocket-test - Test WebSocket Connection”

Listen for real-time ABS scan events:

Terminal window
audiobook-organizer abs websocket-test \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG...

Output shows scan start/complete events with counts of added/updated/missing items.

Verify path discovery is working correctly:

Terminal window
audiobook-organizer abs test-paths \
--abs-sqlite=/var/lib/audiobookshelf/config/abs.sqlite \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG...

For ABS instances protected by Cloudflare Access or other proxies:

Terminal window
# Create headers file
cat > ~/.abs_headers << 'EOF'
CF-Access-Client-Id=xxxxxxxxxxxxxxxxxxxxxx
CF-Access-Client-Secret=yyyyyyyyyyyyyyyyyy
EOF
# Use with any ABS command
audiobook-organizer abs scan \
--abs-url=https://abs.example.com \
--abs-token=eyJhbG... \
--header-file=~/.abs_headers \
--dir=/mnt/audiobooks
Terminal window
audiobook-organizer abs scan \
--abs-url=https://abs.example.com \
--abs-token=eyJhbG... \
--header "CF-Access-Client-Id=xxx" \
--header "CF-Access-Client-Secret=yyy" \
--dir=/mnt/audiobooks
Terminal window
audiobook-organizer abs scan \
--header-file=~/.abs_headers \
--header "X-Extra-Header=special" \
--abs-url=https://abs.example.com \
--abs-token=eyJhbG...
FlagDescription
--abs-urlABS API base URL (e.g., http://localhost:13378)
--abs-tokenABS API token (from Settings > Users > API Token)
--abs-libraryLibrary ID or name (default: auto-select)
--abs-sqlitePath to abs.sqlite for auto path discovery
--abs-path-mapManual path mapping abs:local format
--header-fileFile with custom headers (KEY=VALUE format)
--headerCustom header inline (can be used multiple times)
--allShow all items, not just mismatches (scan command)
--check-filesVerify local files exist (scan command)
--abs-all-librariesScan or organize all libraries with explicit path mappings
  1. Open ABS web interface
  2. Go to Settings → Users
  3. Click your user
  4. Copy API Token

If ABS runs in Docker, copy the SQLite file:

Terminal window
# Copy from container
docker cp abs_container:/config/abs.sqlite /tmp/abs.sqlite
# Use with scan
audiobook-organizer abs scan \
--abs-sqlite=/tmp/abs.sqlite \
--abs-url=http://localhost:13378 \
--abs-token=eyJhbG...

Solutions:

  • Verify directory contains supported formats (MP3, M4B, EPUB, metadata.json)
  • Try --use-embedded-metadata if no metadata.json files
  • Use --flat for single-file audiobooks
  • Check file permissions

Solutions:

  • Use --skip-errors with --flat to skip files with bad metadata and organize the rest
  • Use --author-fields to specify correct metadata fields
  • Check file tags with metadata viewer: audiobook-organizer metadata-tui --dir=/path
  • Verify audio files aren’t corrupted
  • See METADATA.md for field mapping guide

Solutions:

  • Ensure write access to output directory
  • Run with appropriate user permissions
  • Check directory ownership: ls -la
  • On Windows, run as Administrator if needed

Symptoms: “path too long” errors on Windows

Solutions:

Solutions:

  • Review field mapping: use audiobook-organizer metadata-tui --dir=/path
  • Adjust --layout option
  • Check --author-fields, --title-field, --series-field values
  • Use --verbose for detailed logging

CodeMeaning
0Success
1General error
2Invalid arguments
3File system error
4Metadata extraction error

Use in scripts:

Terminal window
audiobook-organizer --dir=/books
if [ $? -eq 0 ]; then
echo "Success"
else
echo "Failed with exit code $?"
fi

Audiobookshelf Integration:


When reporting CLI issues, please include:

  • Operating system and version
  • CLI version (audiobook-organizer version)
  • Complete command with all flags
  • Error output (use --verbose)
  • Sample directory structure (if relevant)