- Adds `uv`, `ruff`, `pyright`, `vulture` and `pytest-xdist`
- Move project, lockfile, docker build etc to uv
- Align python tooling on 3.14
- Huge bulk of ruff linter fixes applied. Still in progress but all the
core types are now enforced
- Update CI and test helpers
- Clean up a few uses of config options that may miss the env variable
if this is set
- Add enhanced retry availability utilising the DB to persist download
errors / retries across restarts, request failures, and pass Prowlarr
detail through the download task to maintain retry data.
- Strip back entrypoint permissions for less intensive chown operations.
Fixes#796
- Added a path for rootless permissions in the entrypoint script
- Routed prowlarr searches through torznab for seedtime info
- Added additional request flow for download permissions
- Adds a combined search option in the search bar selector
- Choose both a book and audiobook file in a two-step release modal, and
download both simultaneously from a single search result.
- Works for requests. Request both a book+audiobook at once, or works
seamlessly with request policies that differ between book + audiobook
(E.g. automatically download the ebook portion, while the audiobook gets
sent as a request)
- Hidden for users who have book or audiobooks blocked.
Closes#611
Closes#515
## Summary
This adds a new `audible` metadata provider backed by the Audimeta API.
The provider supports:
- Audible/Audimeta metadata lookup without authentication
- region selection (`us`, `ca`, `uk`, `au`, `fr`, `de`, `jp`, `it`,
`in`, `es`, `br`)
- ASIN book lookup
- ISBN lookup with fallback search
- series suggestions and series-order browsing
- richer audiobook metadata such as narrators, runtime, rating,
subtitle, cover, publisher, and series info
- configurable Audimeta base URL, timeout, cache usage, default sort,
and unreleased filtering
## Notes
A few Audimeta-specific integration details were needed:
- send a meaningful `User-Agent`, otherwise Audimeta rejects requests
with `403`
- send the `cache` parameter in the format Audimeta expects
- use `keywords` for general search instead of `query`, which gave
poor/irrelevant results for title-style
searches
## Validation
Tested locally with:
- `python -m py_compile shelfmark/metadata_providers/audible.py`
- `python -m pytest tests/metadata/test_audible.py -v`
- `python -m pytest
tests/metadata/test_metadata_provider_capabilities.py -v`
Also verified manually in a Podman test container:
- searching for `Discount Dan` returns Audible title `B0DXLXRNGG`
- book details and series metadata load correctly
## Scope
This PR intentionally keeps the change localized to the provider layer
and docs:
- new Audible provider
- provider registration
- provider docs
- generated environment variable docs
- Added full Hardcover reading status types into the list selector
- Split reading status entries from dedicated lists
- Added option to disable the automatic removal of books when downloaded
from a Hardcover list
- Fixed browser download not firing when the completed state was
triggered in specific cases
- Updated frontend CSS to Tailwind v4
- Reverted socket IO origin restriction
- Fixed search queries not persisting after auth redirect
- Move advanced search options to left UI selector
- Unlock IRC source to be used for audiobook content_type
- Tweaked security settings env var syncing to be prioritised
- Fix AA "all languages" query generation
- Added language-free AA query as second fallback in case of no results
- Testing moving SeleniumBase scratch files to /tmp via symlink
- Added enhanced logging for activity dismissals and other events
- Removed iFrame restrictions
- Adds full interaction with Hardcover lists, including adding and
removing from lists + want to read status
- List selection exposed in search results, details modal and release
modal
- Added automatic list dropdown when selecting "list" search
- Added auto-removal of books from a list when downloading from that
specific list page
- Changed search selector to hover-activated
- Restructured search field options into the left-hand selector.
Includes dynamic options for each provider.
- Moved Hardcover list and manual search mode into the left hand
selector
- Added search mode and metadata provider into the search options area
- Added new Hardcover series API query and live series suggestions
- Added live Hardcover author and title suggestions
- Added canonical per-user visibility of requests and downloads via new
activity view table. Users get fully independent activity and history
views, while admins still see all.
- Replaces janky frontend + backend combination
Two-phase download history: downloads are now recorded in the DB at
queue time (not just at terminal time), eliminating the need to
reconstruct metadata in the terminal hook and removing the
`_is_graduated_request_download()` request-scan mess
- Much simpler handling of downloads in the activity sidebar, and
improved storage, persistence and UI behavior.
- Replace `ActivityService` with direct storage on
`DownloadHistoryService` and `download_requests` and removes the
activity_log/activity_dismissals tables
- Simplify no-auth mode by removing the fake user row pattern, handled
internally
- Add local download fallback so history entries can still serve files
after tasks leave the queue
- Downloads, requests and history are now entirely persistent between
updates / restarts, and correctly tied to each user.
- Refactored user and request code to avoid any database conflicts
- Fix threading behavior with custom script execution
- Harden the no_auth activity user filtering
- Add a hint to add local admin if none is created
- Added secret key to persist login states across updates / restarts
- Added the manual retry option for failed downloads
- Added the ability to retry failed post-processing using existing
downloaded file
- Added admin-visible "Download as" selector, admin chooses a user to
download on-behalf of - inherits their output preferences.
- Added search mode and default metadata provider / release source
options to User Preferences and My Account settings.
- Added sort by format option in release results
- Added {OriginalName} renaming field option, to retain the exact
downloaded filename
- Frontend dependency updates - fixes rollup vulnerability from this
week
Closes#662#656#649#562
- Added migration for builtin auth users who used dev builds during
multi-user development
- Display apprise errors in logging
- Fix user provisioning in reverse proxy auth setups
- Refactor scoring and release modal utils
Various fixes from the last couple days:
- Add manual approval option for book/audiobook requests (#651)
- Add flagged HTTP headers
- Add filesystem fallback - copy + delete when hardlink/move fails
across filesystems (#647)
- Dependency updates
- Tweak frontend test config (simplified tsconfig for tests)
- Fix overlapping sort scoring in release modal - duplicate scoring keys
caused incorrect release ordering (#654 )
- Fix stale search session after download - search state was not
refreshed when returning from a download (#659)
- Fix multi-format release filtering - releases with multiple formats
were incorrectly excluded by the format filter (#658)
- Fix config persistence when action button is used - clicking "Test
connection" reset unsaved settings (#657)
- Fix request grid text positioning in admin request policy panel
- Fix rTorrent path discovery (#653)
- Fix `/login` API check (#650)
- Add certificate validation setting
- Fix some OIDC providers not linking emails to local users
- Reintroduce sort by peers option for prowlarr results
- Fix "All languages" search query reverting to default language
- Fix download/request dismissal with multiple admin users
- Fix download / request behavior on details modal
- Added two env vars for OIDC login:
- HIDE_LOCAL_AUTH - Remove the "password" option on login page when OIDC
enabled
- OIDC_AUTO_REDIRECT - Immediately launch OIDC provider page
- Improved UX for initial OIDC setup, including creating a local admin
user
- Added callback URL label to OIDC setup page
- Fix Qbittorrent save path bug
- Add admin config for self-settings options visibility. Remove delivery
preferences or notifications from the view.
- Add option to use Booklore's Bookdrop API destination instead of a
specific library
- Add download path options for all torrent clients
- Migrate download client handling from /prowlarr to /download. Moves
all torrent/usenet handling to app-level and gives ABB this
functionality.
- ABB Scraper now uses shared HTTP infrastructure instead of raw
requests, adding retry and proxy support
- Added author, age and bitrate info to ABB search results
- Added "best match" sorting option for releases
- Added size and bitrate sorting options for ABB
- Removed bundled default ABB hostname, must be configured by the user
- Added URL normalisation for ABB hostname
- Rearranged settings UI, moved download clients to its own section.
- More tests
## Summary
Adds AudiobookBay as a web-scraping release source for audiobook
torrents. Once enabled, a new tab shows up in the Find Releases modal.
## What's New
- **AudiobookBay source** – Search AudiobookBay for audiobook torrents
from the Shelfmark UI
- **Torrent downloads** – Extract magnet links from detail pages and add
them to the configured torrent client
- **Audiobook-only** – Source is limited to audiobooks
- **Download clients:** Currently uses the torrent client configured
under **Prowlarr > Download Clients**.
- Audiobook-specific categories (e.g. `QBITTORRENT_CATEGORY_AUDIOBOOK`)
are applied when set.
- **Settings → AudiobookBay**:
- Enable toggle
- Hostname
- Max pages to search (default 5)
- Rate limit delay in seconds (default 1)
## How It Works
1. User searches for an audiobook; AudiobookBay is queried if enabled.
2. Results show title, language, format, and size
3. User selects a release; the handler fetches the detail page and
extracts the magnet link.
4. Magnet link is sent to the configured torrent client.
## Testing
- Unit tests for source, handler, scraper, and utils
- Mocked HTTP requests and torrent client calls
- Coverage for search, relevance filtering, language mapping, size
parsing, and download flow
### Screenshots
<img width="600" alt="image"
src="https://github.com/user-attachments/assets/2e10a259-5c35-4065-980d-b59a1c961c9f"
/>
- Add request retry in the case of a download failure, admins will be prompted to attach a new file to the request
- Add admin-level "add to requests" button in the release modal
- Added notification support via Apprise dependency
- Notifications can be configured globally or per user, with full
customization of events and notification type.
- Added expanded ActivityCard for increased detail of each request, file
info, and managing the attached file.
- Enhanced tests
- Refactored activity backend for full user-level management, using the
db file
- Revamped the activity sidebar UX and categorisation
- Added download history and user filtering
- Added User Preferences modal, giving limited configuration for
non-admins - replaces the "restrict settings" config option.
- Many many bug fixes
- Many many new tests
- Adds a comprehensive multi-user request system to the existing
download flow
- Request configuration is policy based. Configure global settings for
content type, or narrow down policy for specific sources (E.g. allow
direct downloads, set prowlarr to request only, block IRC completely,
etc).
- Global policy configuration and per-user overrides for tailored
configs
- Replaced downloads sidebar with ActivitySidebar, combining active
downloads with requests. Admin management of user requests is done here,
and admins have view of downloads from all users. Sidebar can now be
pinned.
- Request either a standard book or a specific release. Release-requests
are used if you permit one source differently than the other. On
book-level requests, admins pick the specific file to be attached to the
fulfilled request.
- Users can request books with a note
This is WIP so some features are still not complete (notifications, more
automatic release selection, among others).
- Moved backend OIDC functionality to external library Authlib to help
maintainability
- Separated User settings UI into individual components, allowing for
standard settings UI decorator components to be used.
- Added full support for reverse proxy and CWA users alongside local and
OIDC
- Added mapping and syncing functionality for OIDC, CWA and reverse
proxy users
- Added per-user settings into the app-wide config system. Each config
can be declared as user-overrideable, and app-wide functionality can now
receive user-specific options via standard config calls.
- Added per-user audiobook destination config
- Updated login modal UI for simplified login, plus custom labels for
OIDC login
- Added user visibility in header dropdown
- Unified "restrict settings to admin" to use app-wide user roles.
Closes#552
## Summary
Adds OIDC authentication and multi-user support to Shelfmark. Users can
now be managed individually with per-user download settings, while
maintaining full backwards compatibility with existing auth modes
(no-auth, builtin, proxy, CWA).
### Authentication
- **OIDC login** with PKCE, auto-discovery, group-based admin mapping
- **Password fallback** when OIDC is enabled (prevents admin lockout)
- **Auto-provisioning** of OIDC users (configurable on/off)
- **Email-based linking** of pre-created users to OIDC accounts
- **Lockout prevention** — requires a local admin before OIDC can be
enabled
### User Management
- **SQLite user database** (`users.db`) with admin CRUD API
- **Users management tab** in settings UI (admin-only)
- **Settings restricted to admins** in multi-user modes (builtin/OIDC) —
non-admin users cannot access settings
- Create, edit, and delete users with role assignment (admin/user)
- Password management for builtin auth users
- OIDC users shown with provider badge (password fields hidden)
- Per-user configurable settings:
- **Download destination** — custom folder path per user
- **BookLore library & path** — dropdown select, each user's books go to
their own library
- **Email recipients** — per-user email delivery targets
- **`{User}` template variable** — use in destination paths (e.g.,
`/books/{User}/`)
- Settings override model: per-user values override globals, empty/unset
falls back to global defaults
### Download Scoping
- **Per-user download visibility** — non-admins only see their own
downloads
- **Username display** in downloads sidebar (shows who requested each
download)
- **WebSocket room-based filtering** — admins see all, users see only
their own
- **Download progress scoping** — progress events routed to correct user
rooms
### BookLore Integration
- **Dynamic dropdown selects** for library/path (replaces text inputs)
- **Per-user library/path overrides** via user settings
- **Options cache refresh** after Test Connection
### Security
- SQL injection prevention (column whitelist on user updates)
- Generic OIDC error messages (no internal detail leakage)
- Admin self-deletion and last-local-admin deletion guards
- OIDC role overwrite fix (only updates role when admin_group is
configured)
## Migration
**No migration script needed.** The `users.db` is created automatically
on first startup. Existing builtin auth users are auto-migrated to the
database on their first login. All other auth modes (no-auth, proxy,
CWA) continue working unchanged.
## Test Plan
- [x] All 519 tests passing, 0 failures
- [ ] Test no-auth mode: settings accessible, downloads work without
login
- [ ] Test builtin auth: legacy credentials auto-migrate on login, new
users can be created
- [ ] Test OIDC auth: login flow, callback, auto-provisioning,
group-based admin
- [ ] Test CWA auth: unchanged behavior
- [ ] Test proxy auth: unchanged behavior
- [ ] Test per-user downloads: non-admin sees only own downloads
- [ ] Test BookLore dropdowns: library/path selection, per-user
overrides
- [ ] Test Docker build: no Dockerfile changes needed
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add new booklore API file formats
- Renamed cookie for better login persistence with reverse proxy
- Updated fs.py to try hardlink before atomic move from tmp dir
- Fix transmission URL parsing
- Fix scenario where file processing of huge files starves the
healthcheck
- Large enhancements to custom scripting, including passing JSON
download info, more consistent activation across output types,
decoupling from staging behavior, and added full documentation.
- Refreshed available AA URLs
- Fixed potential redirect from AA itself causing mirror cache errors
- Added fully customizable mirror list in UI
- Segmented rotation behavior to Auto mode only
Fixes#588