3.3 KiB
Recursive Library Structure Fixer Specification
Date: 2026-02-11 Status: Implemented
Overview
This document specifies the behavior of the Python utility (scripts/reorganize_library.py) designed to crawl and reorganize deeply nested audiobook library structures into a flat, Audiobookshelf (ABS) compatible format.
Problem Statement
The ABS scanner performs optimally with shallow hierarchies. Deeply nested structures (e.g., Author / Series / Book / files) cause metadata misclassification (Author/Series shifting) and inefficiency. Additionally, "Collection" folders often contain single intro files that cause the scanner to swallow all sub-books into one item.
Migration Strategy: Top-Level Flattening
The script reorganizes the library so that every book occupies a single folder directly under the library root.
1. Primary Naming Pattern
The target structure is:
LibraryRoot / {CleanAuthor} - {BookPathSegments} / {Files}
Refined Naming Logic:
- Author Cleaning: The first folder segment is treated as the Author. Common suffixes are stripped to avoid clutter:
" Collection"," Anthology"," Series"," Books"," Works"," Complete"
- Redundancy Check: If the rest of the path (the "Book" part) already starts with the Author's name (case-insensitive), the Author prefix is not added again.
- Deduplication: Adjacent identical segments in the final name are merged (e.g.,
Book - BookbecomesBook).
2. Detection Logic (Leaf Node Identification)
A directory is identified as a "Book Folder" if:
- It contains audio files (
.mp3,.m4b, etc.) AND has no subdirectories. - It contains audio files AND subdirectories, but has more than 1 audio file.
- Reason: Prevents "Collection" folders with a single
intro.mp3from being treated as books, allowing the script to traverse deeper to find the actual books. - Exception: If subdirectories are named
CD 1,Disc 1, etc., it is treated as a book regardless of file count.
- Reason: Prevents "Collection" folders with a single
- It contains only
CD/Discsubdirectories (even if no audio files are in the root).
3. Transformation Examples
| Source Path (Relative to Root) | Target Folder Name | Reason |
|---|---|---|
Stephen Baxter Collection / Manifold / Origin |
Stephen Baxter - Manifold - Origin |
"Collection" stripped; "Manifold" preserved. |
Abbie Rushton / Unspeakable |
Abbie Rushton - Unspeakable |
Standard Author - Title. |
Dungeon Crawler Carl / Book 1 Dungeon Crawler Carl |
Dungeon Crawler Carl - Book 1 |
Deduplication of "Dungeon Crawler Carl". |
Fiction / Author / Book |
Fiction - Author - Book |
"Fiction" treated as Author context if deeper than 2 levels. |
Python Script Interface
Location
scripts/reorganize_library.py
Usage
python3 scripts/reorganize_library.py /path/to/library [options]
Arguments
path: Root directory of the library to scan.--dry-run: (Recommended) Print all planned moves without executing them.--verbose: Enable debug logging (shows every folder checked and why it was accepted/rejected).
Technical Constraints
- Atomic Moves: Uses
shutil.movefor safety. - Conflict Handling: Skips the move if a folder with the target name already exists.
- Cleanup: Automatically removes empty parent directories after moving their contents.