mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-10-06 09:34:39 +01:00
feat(search): let each user pick their own default book languages (#1255)
## Why `BOOK_LANGUAGE` is a per-reader property, not a per-instance one. On a shared install one household member searches in German while another wants English and German — today whoever changes the setting changes it for everyone, and the only escape is re-picking languages in the filter on every single search. The per-user override machinery already carries `SEARCH_MODE`, the metadata providers and the default release sources, so the language default mostly had to opt into it. ## What changed **The field.** `BOOK_LANGUAGE` becomes `user_overridable` and moves from the **General** tab to **Search Mode**, next to the other user-overridable search defaults (per [review](https://github.com/calibrain/shelfmark/pull/1255#issuecomment-5391189094) — the first version had the Search section span two tabs, this one doesn't). Admins set it per user in the user editor, users set it in **My Account → Search Preferences**, and the Search Mode tab carries the usual "N users override this" summary. **No migration for the move.** `general` and `search_mode` both persist into `settings.json`, and a field's value is resolved through `load_config_file(tab)` for the tab it's declared on — so an install that already stores `BOOK_LANGUAGE` keeps its value. Checked against a `settings.json` written while the field still lived on General: the stored value resolves unchanged, a fresh install still gets `["en"]`, and `BOOK_LANGUAGE` in the environment still overrides both. **The two places the default is read.** - `/api/config` seeds the frontend's language filter, so it now resolves `BOOK_LANGUAGE` for the session user. - `build_release_search_plan` falls back to the default whenever a request carries no language filter — which is exactly what the filter's "Default" option sends. It takes an optional `user_id`, passed by `/api/releases` from the session and by the Prowlarr retry path from `task.user_id`, so a retry re-searches in the languages of whoever queued the download. **Validation.** Overrides go through `normalize_language()`, so `"German"`, `"ger"` and `"de"` all store as `de`, and an unknown language is rejected with a message naming it instead of being silently searched for. An empty list stays an empty list (a deliberate "no default filter"), `null` clears the override as everywhere else, and ENV still wins: with `BOOK_LANGUAGE` set in the environment the field reports `fromEnv` and overrides are ignored. **Scope.** Only the language default becomes overridable. The two format lists left behind under "Default Search Filters" stay admin-only — they describe what the library and its post-processing accept, not what a reader wants to read. There's a test pinning that. ## Verification - 2681 unit tests pass (2670 before, 11 added) - `ruff check`, `ruff format`, `basedpyright` over backend and tests, and `vulture` all clean; frontend lint, format, typecheck and 126 unit tests clean - `docs/environment-variables.md` regenerated via `scripts/generate_env_docs.py` (the `BOOK_LANGUAGE` row follows the field into the Search Mode section) - Manually against a two-user instance with builtin auth (first round, before the tab move): with user A on German and user B on English+German, `/api/config` returns each reader their own `default_language` and an unfiltered `/api/releases` plans the matching languages; an admin can set and read the same override for another user; clearing it falls back to the global value; a stray `"klingon"` is rejected; and `BOOK_LANGUAGE` in the environment overrides both users with the field marked `fromEnv` - After the tab move I re-ran the suites above plus the stored-value/fresh-install/ENV check described under "No migration for the move"; the behaviour it exercises is what the move could have broken Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: CaliBrain <calibrain@l4n.xyz>
This commit is contained in:
co-authored by
Claude Opus 5
CaliBrain
parent
a5595cf9f1
commit
463ef49ac3
@@ -298,15 +298,6 @@ Audiobook formats to include in search results. ZIP/RAR archives are extracted a
|
||||
- **Type:** string (comma-separated)
|
||||
- **Default:** `m4b,mp3,m4a,mp4,flac,ogg,wma,aac,wav,opus,zip,rar`
|
||||
|
||||
#### `BOOK_LANGUAGE`
|
||||
|
||||
**Default Book Languages**
|
||||
|
||||
Default language filter for searches.
|
||||
|
||||
- **Type:** string (comma-separated)
|
||||
- **Default:** `en`
|
||||
|
||||
</details>
|
||||
|
||||
## Search Mode
|
||||
@@ -314,6 +305,7 @@ Default language filter for searches.
|
||||
| Variable | Description | Type | Default |
|
||||
|----------|-------------|------|---------|
|
||||
| `SEARCH_MODE` | How you want to search for and download books. | string (choice) | `universal` |
|
||||
| `BOOK_LANGUAGE` | Default language filter for searches. Users can override this for their own account. | string (comma-separated) | `en` |
|
||||
| `AA_DEFAULT_SORT` | Default sort order for search results. | string (choice) | `relevance` |
|
||||
| `SHOW_RELEASE_SOURCE_LINKS` | Show clickable release-source links in release and details modals. Metadata provider links stay enabled. | boolean | `true` |
|
||||
| `SHOW_COMBINED_SELECTOR` | Show the option to search for and download both a book and audiobook together. | boolean | `true` |
|
||||
@@ -337,6 +329,15 @@ How you want to search for and download books.
|
||||
- **Default:** `universal`
|
||||
- **Options:** `direct` (Direct), `universal` (Universal)
|
||||
|
||||
#### `BOOK_LANGUAGE`
|
||||
|
||||
**Default Book Languages**
|
||||
|
||||
Default language filter for searches. Users can override this for their own account.
|
||||
|
||||
- **Type:** string (comma-separated)
|
||||
- **Default:** `en`
|
||||
|
||||
#### `AA_DEFAULT_SORT`
|
||||
|
||||
**Default Sort Order**
|
||||
@@ -749,6 +750,7 @@ Automatically open the downloads sidebar when a new download is queued.
|
||||
Automatically download completed files to your browser for the selected content types.
|
||||
|
||||
- **Type:** string (comma-separated)
|
||||
|
||||
- **Default:** _empty list_
|
||||
|
||||
#### `MAX_CONCURRENT_DOWNLOADS`
|
||||
|
||||
@@ -30,7 +30,7 @@ Requires mounting your Calibre-Web `app.db` to `/auth/app.db`.
|
||||
|
||||
Admins can configure per-user settings by editing a user in the user management panel. Non-admin users can also edit their own settings through **My Account** (accessible from the user menu). Admins control which sections are visible in My Account via the **Visible Self-Settings Sections** option.
|
||||
|
||||
There are three categories of per-user settings:
|
||||
There are four categories of per-user settings:
|
||||
|
||||
### Delivery Preferences
|
||||
|
||||
@@ -42,6 +42,15 @@ Override where a user's downloads are sent. Options depend on the global output
|
||||
- **BookLore library/path** — Per-user BookLore target (when using BookLore output mode)
|
||||
- **Email recipient** — Per-user email address (when using Email output mode)
|
||||
|
||||
### Search Preferences
|
||||
|
||||
Override how a user searches, on top of the global search defaults:
|
||||
|
||||
- **Search mode** — Direct or Universal for this user
|
||||
- **Default book languages** — The languages a user's searches fall back to when they don't pick one themselves. Useful for a shared instance where readers want different languages.
|
||||
- **Metadata providers** — Book, audiobook, and combined-mode provider for this user
|
||||
- **Default release sources** — The release tab opened first for books and audiobooks
|
||||
|
||||
### Notifications
|
||||
|
||||
Users can configure personal notification routes, separate from the global notification settings. Each route targets a URL (e.g. an Apprise-compatible endpoint) and can be scoped to specific event types or all events.
|
||||
|
||||
Reference in New Issue
Block a user