Skip to content
This repository was archived by the owner on Feb 2, 2026. It is now read-only.

[FEATURE] Multi-selection of books to shelf - #87#136

Open
Fail-Safe wants to merge 29 commits intogelbphoenix:mainfrom
Fail-Safe:main
Open

[FEATURE] Multi-selection of books to shelf - #87#136
Fail-Safe wants to merge 29 commits intogelbphoenix:mainfrom
Fail-Safe:main

Conversation

@Fail-Safe
Copy link
Contributor

@Fail-Safe Fail-Safe commented Jan 17, 2026

Description

Implements bulk shelf management allowing users to add or remove multiple selected books to/from shelves simultaneously from the Books List table. Addresses the need for efficient shelf management when organizing large book collections.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Performance improvement
  • Documentation update
  • Dependency update
  • Configuration change

Areas Affected

  • Frontend (HTML/CSS/JavaScript)
  • Backend (Python)
  • Database/Storage
  • eBook management
  • OPDS functionality
  • User interface
  • Authentication/Authorization
  • API endpoints
  • Docker configuration
  • Documentation

Changes Made

Backend (cps/shelf.py)

  • Added MAX_BULK_SHELF_SELECTION = 1000 limit to prevent performance issues
  • Implemented validation in bulk_add_to_shelf() and bulk_remove_from_shelf() to enforce limit with i18n error messages

Frontend JavaScript (cps/static/js/table.js)

  • Added i18n infrastructure: btI18n() for key lookups, btFormatNamed() for Python-style named placeholder formatting (%(key)s)
  • Implemented bulk shelf action handlers with granular feedback (added/already present/invalid/removed/not on shelf counts)
  • Enhanced "Select All" with confirmation dialog and truncation handling (shows "Select 1000 of 5000 results?" when truncated)
  • Replaced all hardcoded UI strings with i18n lookups

Frontend JavaScript (cps/static/js/main.js)

  • Extended confirmDialog() to accept optional textOverrides parameter for programmatic dialog text without AJAX call
  • Maintains backward compatibility by falling back to AJAX when no overrides provided

Templates (cps/templates/book_table.html)

  • Added <span id="books-table-i18n"> with data attributes containing all translatable strings
  • Used placeholder tokens (__COUNT__, __SHELF__, etc.) in templates for JavaScript-side replacement
  • Added accessibility labels (aria-label attributes)
  • Included confirmation modal for select-all operations

Documentation (README.md)

  • Added "Bulk shelf management from the Books List (multi-select add/remove)" to features list

Example Usage

// Internationalized message formatting
btFormatNamed(
    btI18n('bulkAdded', 'Added %(count)s to shelf "%(shelf)s".'),
    {count: 5, shelf: 'Favorites'}
)
// Returns: "Added 5 to shelf 'Favorites'."

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

  • Manual testing with eBook files
  • Manual testing with PDF files
  • OPDS client compatibility testing
  • Cross-browser testing (if frontend changes)
  • Mobile/tablet testing (if UI changes)
  • Unit tests
  • Integration tests

Test Configuration

  • Browser(s): Brave/Chrome, Firefox
  • Operating System: Linux
  • Python Version: 3.x
  • eBook formats tested: EPUB
  • Device(s) tested: Desktop (macOS), iPhone 15 Pro (iOS)

Screenshots/Video (if applicable)

N/A - Feature requires live environment interaction

Files/Formats Tested

If this change affects file handling, please list the formats and file types you tested:

  • EPUB files
  • PDF files
  • CBR/CBZ comic files
  • MOBI files
  • Other: ____

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published
  • I have tested the changes with actual eBook or PDF files
  • I have verified OPDS compatibility (if applicable)
  • I have tested on multiple devices/screen sizes (if UI changes)

Additional Notes

  • Limit of 1000 books per bulk operation prevents server overload on large libraries
  • All user-facing strings support internationalization via Flask-Babel
  • Maintains existing shelf permission model (respects public/private shelf access)
  • Status messages provide detailed feedback on partial operations (e.g., "Added 8 to shelf. 2 already on shelf. 1 invalid.")

@github-project-automation github-project-automation bot moved this to Backlog in Autocaliweb Jan 17, 2026
@gelbphoenix gelbphoenix added the enhancement New feature or request label Jan 17, 2026
@gelbphoenix gelbphoenix moved this from Backlog to In progress in Autocaliweb Jan 17, 2026
@gelbphoenix gelbphoenix linked an issue Jan 19, 2026 that may be closed by this pull request
* chore: add ESLint v9 flat config (baseline)

* chore: ignore lockfiles and drop package-lock

* chore: ignore Node lockfiles

* Add functionality for generated shelves and enhance shelf management

- Introduced a new configuration option to generate and link shelves to a Calibre column in the config view.
- Updated the detail, listenmp3, search, and shelf templates to exclude generated shelves from various shelf management actions.
- Enhanced the shelf display logic to differentiate between generated and regular shelves, including tooltips and sorting options for generated shelves.
- Improved the layout and accessibility of shelf links and actions in the navigation and shelf views.

* Enhance configuration for cache directory and update docker-compose comments for CACHE_DIR environment variable.

* Add DB index for fast thumbnail lookups in large libraries

* Implement caching headers for book and series cover responses

* Refactor thumbnail generation to handle duplicates and improve file management

* Fix locale parsing to skip wildcards in accepted languages

* Reorganize imports to satisfy pylint recommendations

* Add runtime debug hooks via SIGUSR1 and SIGUSR2 for live CPU/memory investigations

* Whitespace fixups for improving linter/formatter happiness and affording less noisy future commits

* feat(kobo): Enhance Kobo sync functionality and UI

- Added logging for book sync actions in `kobo_sync_status.py` to track sync reasons.
- Implemented a local-only opt-in shelf for Kobo sync in `render_template.py`, ensuring it exists in hybrid mode.
- Updated shelf creation logic in `shelf.py` to handle reserved shelf names for Kobo sync.
- Improved JavaScript handling for dynamic form controls in `main.js`.
- Added configuration options for Kobo collections sync in `config_edit.html`, allowing users to select sync modes.
- Display generated shelves in the book detail view in `detail.html`.
- Adjusted image loading resolution in `image.html` for better performance.
- Introduced a new database model `KoboTagSyncState` in `ub.py` to manage sync states and settings.
- Enhanced database migration logic to ensure necessary tables and columns exist.
- Updated the book detail rendering logic in `web.py` to include generated shelves.

* refactor: Remove unused import of itsdangerous

* fix: Restore incorrectly removed imports

* fix: Correct an ugly bug in handling of None state in change_archived_books function

* feat(kobo): Add generated shelf sync settings and item limit configuration

* feat: Implement Kobo sync collections mode and related settings

- Added a new user setting for Kobo sync collections mode with options: "all", "selected", and "hybrid".
- Introduced a confirmation modal for changing the Kobo sync mode, triggering a full resync on the next device connection.
- Updated user edit and configuration templates to include new Kobo sync settings.
- Created a new shelf table page with bulk actions for enabling/disabling Kobo sync and deleting selected shelves.
- Implemented JavaScript functionality for managing shelf selections and handling bulk actions.
- Migrated existing Kobo sync settings to new per-user fields in the database.
- Removed deprecated global Kobo sync settings from the configuration template.

* feat(kobo): Enhance Kobo sync functionality with metadata inspection and shelf management

* Fix optional imports for dev/test

* Kobo: improve sync robustness and add store merge toggle

* feat(kobo): enhance remove_synced_book function to support user_id parameter and improve session handling

* Cache writable Calibre DB copy for exports

When the Calibre library DB is read-only, create a writable temp copy of
metadata.db and set CALIBRE_OVERRIDE_DATABASE_PATH to point at it. The
copy is cached (keyed by source mtime+size) and reused for a short TTL
(60s) to avoid repeated copying. Best-effort only; falls back on error.

Also reorganize imports and apply small refactors/cleanup across modules

* Reorganize imports, reformat code, fix Kobo sync

Gate shelf membership updates using tags_last_modified (the
shelf/collection token) to avoid missing newly-allowed books.
For generated shelves, rely on the "not yet synced" branch so
older-but-newly-allowed books are emitted without a full reset.
* chore: add ESLint v9 flat config (baseline)

* Add functionality for generated shelves and enhance shelf management

- Introduced a new configuration option to generate and link shelves to a Calibre column in the config view.
- Updated the detail, listenmp3, search, and shelf templates to exclude generated shelves from various shelf management actions.
- Enhanced the shelf display logic to differentiate between generated and regular shelves, including tooltips and sorting options for generated shelves.
- Improved the layout and accessibility of shelf links and actions in the navigation and shelf views.

* Reorganize imports to satisfy pylint recommendations

* Add runtime debug hooks via SIGUSR1 and SIGUSR2 for live CPU/memory investigations

* feat(kobo): Enhance Kobo sync functionality and UI

- Added logging for book sync actions in `kobo_sync_status.py` to track sync reasons.
- Implemented a local-only opt-in shelf for Kobo sync in `render_template.py`, ensuring it exists in hybrid mode.
- Updated shelf creation logic in `shelf.py` to handle reserved shelf names for Kobo sync.
- Improved JavaScript handling for dynamic form controls in `main.js`.
- Added configuration options for Kobo collections sync in `config_edit.html`, allowing users to select sync modes.
- Display generated shelves in the book detail view in `detail.html`.
- Adjusted image loading resolution in `image.html` for better performance.
- Introduced a new database model `KoboTagSyncState` in `ub.py` to manage sync states and settings.
- Enhanced database migration logic to ensure necessary tables and columns exist.
- Updated the book detail rendering logic in `web.py` to include generated shelves.

* fix: Restore incorrectly removed imports

* feat(kobo): Add generated shelf sync settings and item limit configuration

* feat: Implement Kobo sync collections mode and related settings

- Added a new user setting for Kobo sync collections mode with options: "all", "selected", and "hybrid".
- Introduced a confirmation modal for changing the Kobo sync mode, triggering a full resync on the next device connection.
- Updated user edit and configuration templates to include new Kobo sync settings.
- Created a new shelf table page with bulk actions for enabling/disabling Kobo sync and deleting selected shelves.
- Implemented JavaScript functionality for managing shelf selections and handling bulk actions.
- Migrated existing Kobo sync settings to new per-user fields in the database.
- Removed deprecated global Kobo sync settings from the configuration template.

* Kobo: improve sync robustness and add store merge toggle

* Cache writable Calibre DB copy for exports

When the Calibre library DB is read-only, create a writable temp copy of
metadata.db and set CALIBRE_OVERRIDE_DATABASE_PATH to point at it. The
copy is cached (keyed by source mtime+size) and reused for a short TTL
(60s) to avoid repeated copying. Best-effort only; falls back on error.

Also reorganize imports and apply small refactors/cleanup across modules

* Reorganize imports, reformat code, fix Kobo sync

Gate shelf membership updates using tags_last_modified (the
shelf/collection token) to avoid missing newly-allowed books.
For generated shelves, rely on the "not yet synced" branch so
older-but-newly-allowed books are emitted without a full reset.

* Enhance Kobo Sync functionality and update dependencies

- Added support for retrieving user Kobo collections mode in `books_table` and `list_books` functions.
- Implemented logic to determine if the user is in hybrid mode for Kobo sync and adjusted book entries accordingly.
- Updated `change_profile` to handle Kobo remove behavior settings.
- Removed unnecessary dependency on `python-magic-bin` from `uv.lock`.
- Added `.DS_Store` and cache directories to `.gitignore` files for cleaner repository management.

* feat(docker): update Dockerfile for improved dependency management and cleanup

feat(scripts): add purge_kepubs.py for removing stale KEPUB files from Calibre library

feat(dev): introduce dev-run.sh for automatic restart on code changes
Use COUNT(DISTINCT book.id) for pagination totals with a safe fallback.
load_dependencies now reads .pip_installed for frozen builds and returns
a
simplified runtime list; legacy range checks removed and
dependency_check() returns an empty list to avoid lockfile parsing.
Consolidate frontend infinite-scroll: disable isotope grid, move shelf
init to main.js, add shelf.js stub and enable load-more layout in
templates.
Also apply import reordering and various whitespace/formatting cleanups.
Installer now requires pyproject.toml + uv.lock and prefers uv for
dependency installation. Add --extras / --all-extras / --no-extras flags
to control optional integrations (default = all extras). The installer
no longer falls back to pip-tools/requirements; it fails if uv sync
cannot apply the lock.

Update pyproject.toml and uv.lock: bump Flask-related packages,
Flask-Limiter, flask-wtf; add python-magic-bin for Windows and use a
patched rauth from a git source. Remove legacy requirements/optional
files and adjust CI to watch pyproject.toml and uv.lock instead.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

[FEATURE] Multi-selection of books to shelf

3 participants