audiobookshelf/artifacts/2026-02-13/consolidate.md

3.6 KiB

Consolidate Book Feature Specification

Overview

The "Consolidate" feature allows users to organize their book library by renaming a book's folder to a standard Author - Book Name format and moving it to the root of the library folder. This helps in flattening nested structures and maintaining a consistent naming convention.

User Interface

Frontend

  • Context menu on Book Card (Library View).
  • Context menu on Book View page.
  • A new option "Consolidate" will be added to the book card's context menu (the "meatball" menu).
  • Visibility:
    • Only available for Books (not Podcasts).
    • Only available if the user has "Update" permissions.
    • Only available if the item is a folder (not a single file).
  • Interaction:
    • Clicking "Consolidate" triggers a confirmation dialog explaining the action.
    • Upon confirmation, the operation is performed.
    • A toast notification indicates success or failure.

Backend Logic

  • Endpoint: POST /api/items/:id/consolidate
  • Controller: LibraryItemController.consolidate
  • Logic:
    1. Retrieve Item: Fetch the library item by ID. Verify it is a book and the user has permissions.
    2. Determine New Name: Construct the folder name using the pattern ${Author} - ${Title}.
      • Author: Primary author name.
      • Title: Book title.
      • Sanitization: Ensure the name is safe for the file system (remove illegal characters).
    3. Determine New Path:
      • Target Library Folder: The root path of the library the item belongs to.
      • New Path: Path.join(LibraryRoot, NewFolderName).
    4. Validation:
      • Check if New Path already exists.
      • If it exists and is the same as the current path, return success (no-op).
      • If it exists and is different, return an error (or handle collision - for now, error).
    5. Execution:
      • Move the directory from Old Path to New Path.
      • Update the path and relPath in the libraryItems table.
      • Update paths of all associated files (audio files, ebook files, cover, etc.) in the database.
      • Update libraryFolderId to the root folder ID (if applicable/tracked).
    6. Cleanup:
      • If the old folder was inside another folder (e.g., Author/Series/Book), check if the parent folders are now empty and delete them if so (similar to how Move or Delete handles it). Note: The existing move logic might handle this or we can reuse handleMoveLibraryItem if we can trick it or modify it.
      • Actually, handleMoveLibraryItem takes a targetFolder. If we pass the library root as targetFolder and rename the directory before/during move?
      • handleMoveLibraryItem assumes itemFolderName is Path.basename(libraryItem.path). It does NOT rename the folder name itself.
      • So we need a custom logic or a modified helper that supports renaming.
  • Response: JSON object indicating success and the updated item.
  • Robustness Improvements:
    • Enhanced handleMoveLibraryItem to detect if the source and destination paths are identical.
    • Skips file move operation if the paths match, preventing "Destination already exists" Errors.
    • Ensures Watcher ignore directories are correctly managed even when paths are identical.

Batch Consolidation

  • Endpoint: POST /api/items/batch/consolidate
  • Controller: LibraryItemController.batchConsolidate
  • Logic: Iterates through selected item IDs and calls the consolidation logic for each.
  • Response: Summary of successful and failed consolidation operations.

Artifacts

  • This specification is saved as artifacts/2026-02-13/consolidate.md.