Repository navigation
feat: narrator, series and bitrate columns for MyAnonamouse results - #1390
Merged
Merged
Conversation
Prowlarr's MyAnonamouse indexer drops the narrator and series MAM returns, and Torznab has no field for them. With a MAM session ID (PROWLARR_MAM_ID, settable in the Prowlarr settings or as an env var) Shelfmark reruns the Prowlarr query against MAM's JSON search API and matches torrents back by ID, filling extra.narrator, extra.series and extra.bitrate (parsed from the uploader's tags). Lookups are cached for an hour, stay inside the Prowlarr search budget, and never fail the search. New Search Mode toggles SHOW_SERIES_COLUMN, SHOW_NARRATOR_COLUMN and SHOW_BITRATE_COLUMN (user-overridable) control the columns. Columns can now declare a setting_key and content_types, applied by apply_column_visibility() in /api/releases; narrator and bitrate are audiobook-only. AudiobookBay's bitrate column follows the same toggle, and a Torznab bitrate attribute from other indexers is used when present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MAM locks each session to one IP or ASN, so reusing Prowlarr's session often 403s from Shelfmark. Say so in the MAM Session ID setting, the generated env docs, and a new docs/myanonamouse-enrichment.md guide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ides Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thank you ! |
calibrain
added a commit
that referenced
this pull request
Sep 26, 2026
#1399) Follow-up to #1390. - The origin came from each result's infoUrl, matched by a regex that did not check the host, and the mam_id cookie had no domain. Any Prowlarr indexer returning a URL like https://evil.example?myanonamouse.net/t/1 sent the session ID to evil.example. Requests now always go to https://www.myanonamouse.net (Prowlarr's only MAM URL), with the cookie as a header and redirects off. Only results from Prowlarr's MyAnonamouse indexer are looked up, and their URLs must be on myanonamouse.net. - The lookup searched every category and read one page, so for common titles most of Prowlarr's results were missed (a "Dune" audiobook search: 56 audiobooks on the first 100 of 328 matches). It now reruns Prowlarr's exact search: the same query clean-up, the MAM main categories behind the Torznab categories searched (13/15/16 for audiobooks, 14 for e-books, all once expanded), and the MAM indexer's own search type, search-in options and languages. Further pages are read while IDs are missing, page 1 of every title first, at most 4 requests per search. - Failed requests back off for 1, 2, 4 ... up to 30 minutes. The 10th consecutive failure stops enrichment until Test MAM Session passes, the session ID changes, or Shelfmark restarts. - The detail cache prunes expired entries instead of growing for as long as Shelfmark runs.
doonga
pushed a commit
to greyrock-labs/home-ops
that referenced
this pull request
Sep 26, 2026
…v1.4.0) (#283) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/calibrain/shelfmark](https://github.com/calibrain/shelfmark) | minor | `v1.3.15` → `v1.4.0` | --- ### Release Notes <details> <summary>calibrain/shelfmark (ghcr.io/calibrain/shelfmark)</summary> ### [`v1.4.0`](https://github.com/calibrain/shelfmark/releases/tag/v1.4.0) [Compare Source](calibrain/shelfmark@v1.3.15...v1.4.0) ##### What's Changed - build(deps): bump the python-deps group with 2 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1302](calibrain/shelfmark#1302) - fix: keep polling queued Real-Debrid torrents by [@​mvanhorn](https://github.com/mvanhorn) in [#​1303](calibrain/shelfmark#1303) - fix(bypass): keep Anna's Archive's aa\_ddg\_check so clearance replays by [@​jfmlima](https://github.com/jfmlima) in [#​1305](calibrain/shelfmark#1305) - fix(postprocess): attach unmatched chaptered audio files to existing book group ([#​1176](calibrain/shelfmark#1176)) by [@​amasen02](https://github.com/amasen02) in [#​1309](calibrain/shelfmark#1309) - build(deps): bump the gh-actions group with 3 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1310](calibrain/shelfmark#1310) - build(deps): bump the npm-deps group in /src/frontend with 4 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1308](calibrain/shelfmark#1308) - build(deps): bump python from `cae66f2` to `cad9a2c` by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1307](calibrain/shelfmark#1307) - build(deps): bump the docker-base-image-digests group with 2 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1306](calibrain/shelfmark#1306) - Deep-link Search By mode via URL hash by [@​nfvelten](https://github.com/nfvelten) in [#​1311](calibrain/shelfmark#1311) - build(deps): bump the python-deps group across 1 directory with 4 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1327](calibrain/shelfmark#1327) - Keep default filters out of the URL hash by [@​nfvelten](https://github.com/nfvelten) in [#​1314](calibrain/shelfmark#1314) - feat(download): add Blackhole torrent handoff by [@​atirna](https://github.com/atirna) in [#​1312](calibrain/shelfmark#1312) - feat(naming): add {FirstAuthor} template token by [@​viniciuspx](https://github.com/viniciuspx) in [#​1322](calibrain/shelfmark#1322) - fix: share rotating log file handlers by [@​eikopf](https://github.com/eikopf) in [#​1316](calibrain/shelfmark#1316) - fix(prowlarr): skip indexers in Prowlarr failure back-off by [@​jfmlima](https://github.com/jfmlima) in [#​1324](calibrain/shelfmark#1324) - fix: prevent Anna's Archive download countdown resets by preserving browser sessions by [@​broglea](https://github.com/broglea) in [#​1325](calibrain/shelfmark#1325) - build(deps): bump the docker-base-image-digests group with 2 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1328](calibrain/shelfmark#1328) - build(deps-dev): bump the npm-deps group in /src/frontend with 4 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1329](calibrain/shelfmark#1329) - build(deps-dev): bump vitest from 4.1.11 to 5.0.0 in /src/frontend by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1330](calibrain/shelfmark#1330) - fix(irc): search by surname, and rank the answer by author ([#​1331](calibrain/shelfmark#1331)) by [@​Kukkerem](https://github.com/Kukkerem) in [#​1332](calibrain/shelfmark#1332) - fix(irc): rank a surname-only result as partial, not wrong ([#​1332](calibrain/shelfmark#1332)) by [@​calibrain](https://github.com/calibrain) in [#​1334](calibrain/shelfmark#1334) - feat(sources): add Libgen as a direct catalogue search source by [@​klaidliadon](https://github.com/klaidliadon) in [#​1326](calibrain/shelfmark#1326) - refactor: make direct download provider-driven by [@​TomJansen](https://github.com/TomJansen) in [#​1337](calibrain/shelfmark#1337) - fix(sources): restore Direct Download search errors and language matches by [@​calibrain](https://github.com/calibrain) in [#​1339](calibrain/shelfmark#1339) - fix(sources): send a Referer when fetching libgen ads.php pages by [@​klaidliadon](https://github.com/klaidliadon) in [#​1340](calibrain/shelfmark#1340) - Feature: Add Download counts to search result displays and Download sidebar by [@​RoninTech](https://github.com/RoninTech) in [#​1336](calibrain/shelfmark#1336) - Extract archives when zip/rar are enabled as supported formats by [@​funkypenguin](https://github.com/funkypenguin) in [#​1343](calibrain/shelfmark#1343) - fix(download): complete consumed Blackhole handoffs by [@​atirna](https://github.com/atirna) in [#​1345](calibrain/shelfmark#1345) - Add configurable word separator for naming templates by [@​viniciuspx](https://github.com/viniciuspx) in [#​1333](calibrain/shelfmark#1333) - build(deps): bump the python-deps group across 1 directory with 5 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1344](calibrain/shelfmark#1344) - fix: unbreak main and follow up on the Blackhole handoff review by [@​calibrain](https://github.com/calibrain) in [#​1346](calibrain/shelfmark#1346) - build(deps): bump python-socketio from 5.16.4 to 5.17.0 in the python-deps group by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1347](calibrain/shelfmark#1347) - Added the ability to sort direct search results by Most downloads by [@​RoninTech](https://github.com/RoninTech) in [#​1351](calibrain/shelfmark#1351) - feat: Add TorBox client support and settings integration by [@​marcelorodrigo](https://github.com/marcelorodrigo) in [#​1342](calibrain/shelfmark#1342) - refactor: extract the per-source release search out of /api/releases by [@​splitsec2](https://github.com/splitsec2) in [#​1355](calibrain/shelfmark#1355) - build(deps): bump the docker-base-image-digests group with 2 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1348](calibrain/shelfmark#1348) - build(deps): bump the npm-deps group in /src/frontend with 9 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1349](calibrain/shelfmark#1349) - build(deps): bump the gh-actions group with 6 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1350](calibrain/shelfmark#1350) - feat(auth): provision proxy users as non-admin once an admin exists by [@​splitsec2](https://github.com/splitsec2) in [#​1356](calibrain/shelfmark#1356) - fix(users): apply user updates only after the payload validates by [@​splitsec2](https://github.com/splitsec2) in [#​1360](calibrain/shelfmark#1360) - fix(download): default is\_admin to False in the request policy guard by [@​splitsec2](https://github.com/splitsec2) in [#​1358](calibrain/shelfmark#1358) - fix(oidc): reject backslash paths in the return\_to sanitizer by [@​splitsec2](https://github.com/splitsec2) in [#​1359](calibrain/shelfmark#1359) - fix(queue): don't stamp CANCELLED over a finished download by [@​splitsec2](https://github.com/splitsec2) in [#​1361](calibrain/shelfmark#1361) - fix(download): check task ownership before serving queued files by [@​splitsec2](https://github.com/splitsec2) in [#​1357](calibrain/shelfmark#1357) - Feature: Show the AA search result stats by [@​RoninTech](https://github.com/RoninTech) in [#​1362](calibrain/shelfmark#1362) - fix(requests): reject non-object items in the batch endpoint by [@​splitsec2](https://github.com/splitsec2) in [#​1369](calibrain/shelfmark#1369) - fix(http): keep the host of a protocol-relative download link by [@​splitsec2](https://github.com/splitsec2) in [#​1368](calibrain/shelfmark#1368) - fix(googlebooks): page by the capped size, not the raw limit by [@​splitsec2](https://github.com/splitsec2) in [#​1370](calibrain/shelfmark#1370) - fix(deluge): send seeding ratio limit under Deluge's own keys by [@​splitsec2](https://github.com/splitsec2) in [#​1367](calibrain/shelfmark#1367) - feat(auth): static API\_KEY (env) accepted as Bearer or X-Api-Key, cookie or key by [@​gavinmcfall](https://github.com/gavinmcfall) in [#​1366](calibrain/shelfmark#1366) - fix(auth): rename the API\_KEY env var to SHELFMARK\_API\_KEY by [@​calibrain](https://github.com/calibrain) in [#​1374](calibrain/shelfmark#1374) - fix: bypass recordings, welib wrong-md5 links, footer build sha ([#​1364](calibrain/shelfmark#1364)) by [@​calibrain](https://github.com/calibrain) in [#​1373](calibrain/shelfmark#1373) - build(deps): bump the python-deps group with 4 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1375](calibrain/shelfmark#1375) - ci: debounce dev image builds instead of building nightly by [@​calibrain](https://github.com/calibrain) in [#​1376](calibrain/shelfmark#1376) - fix(download): stream a completed book instead of buffering it in RAM - lowering memory needs significantly by [@​splitsec2](https://github.com/splitsec2) in [#​1378](calibrain/shelfmark#1378) - perf(docker): keep the heavy build layers cacheable across builds - save 11minutes per build by [@​splitsec2](https://github.com/splitsec2) in [#​1379](calibrain/shelfmark#1379) - test(auth): stop proxy provisioning tests depending on run order by [@​splitsec2](https://github.com/splitsec2) in [#​1381](calibrain/shelfmark#1381) - feat(search): add a configurable default content type by [@​splitsec2](https://github.com/splitsec2) in [#​1371](calibrain/shelfmark#1371) - feat(library): mark search results already in a Calibre library by [@​splitsec2](https://github.com/splitsec2) in [#​1377](calibrain/shelfmark#1377) - Default to english when no lang is slected by [@​calibrain](https://github.com/calibrain) in [#​1396](calibrain/shelfmark#1396) - fix(auth): fail closed when auth prerequisites are missing ([#​1387](calibrain/shelfmark#1387)) by [@​calibrain](https://github.com/calibrain) in [#​1397](calibrain/shelfmark#1397) - build(deps): bump the gh-actions group with 4 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1395](calibrain/shelfmark#1395) - fix(audiobookbay): reuse the resolved magnet when retrying ([#​1388](calibrain/shelfmark#1388)) by [@​calibrain](https://github.com/calibrain) in [#​1398](calibrain/shelfmark#1398) - build(deps): bump the npm-deps group in /src/frontend with 7 updates by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1394](calibrain/shelfmark#1394) - build(deps): bump seleniumbase from 4.54.9 to 4.54.10 in the python-deps group by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1382](calibrain/shelfmark#1382) - feat: narrator, series and bitrate columns for MyAnonamouse results by [@​adman234](https://github.com/adman234) in [#​1390](calibrain/shelfmark#1390) - build(deps): bump astral-sh/uv from 0.12.16 to 0.12.19 in the docker-base-image-digests group across 1 directory by [@​dependabot](https://github.com/dependabot)\[bot] in [#​1392](calibrain/shelfmark#1392) - fix(mam): keep the session ID on MAM and rerun Prowlarr's exact search by [@​calibrain](https://github.com/calibrain) in [#​1399](calibrain/shelfmark#1399) - fix(ui): contain the result count added in [#​1362](calibrain/shelfmark#1362) by [@​calibrain](https://github.com/calibrain) in [#​1363](calibrain/shelfmark#1363) ##### New Contributors - [@​amasen02](https://github.com/amasen02) made their first contribution in [#​1309](calibrain/shelfmark#1309) - [@​atirna](https://github.com/atirna) made their first contribution in [#​1312](calibrain/shelfmark#1312) - [@​viniciuspx](https://github.com/viniciuspx) made their first contribution in [#​1322](calibrain/shelfmark#1322) - [@​eikopf](https://github.com/eikopf) made their first contribution in [#​1316](calibrain/shelfmark#1316) - [@​broglea](https://github.com/broglea) made their first contribution in [#​1325](calibrain/shelfmark#1325) - [@​klaidliadon](https://github.com/klaidliadon) made their first contribution in [#​1326](calibrain/shelfmark#1326) - [@​TomJansen](https://github.com/TomJansen) made their first contribution in [#​1337](calibrain/shelfmark#1337) - [@​RoninTech](https://github.com/RoninTech) made their first contribution in [#​1336](calibrain/shelfmark#1336) - [@​marcelorodrigo](https://github.com/marcelorodrigo) made their first contribution in [#​1342](calibrain/shelfmark#1342) - [@​splitsec2](https://github.com/splitsec2) made their first contribution in [#​1355](calibrain/shelfmark#1355) - [@​gavinmcfall](https://github.com/gavinmcfall) made their first contribution in [#​1366](calibrain/shelfmark#1366) **Full Changelog**: <calibrain/shelfmark@v1.3.15...v1.4.0> </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMDUuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjEwNS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.greyrock.io/todd/home-ops/pulls/283
|
Can this now be used to add a {Narrator} text field to the download path? I am trying to get audiobooks to download to “/{Author}/{Title} {{Narrator}}/{Title}” so that I can have multiple versions of the same book without having to manually rename folders each time. |
Contributor
Author
Good idea, I've created a new PR for this change. |
calibrain
pushed a commit
that referenced
this pull request
Oct 3, 2026
…#1407) ## Human-Written explanation: Following up on previous PR to use MAM ID to get nararrator and series to show up in search, this PR will allow the series and nararrator fields to be added to the path when saving an audiobook. I have tested my ghcr.io image on my instance and it seemed to work properly. All the text below is written by Claude. # feat(naming): {Narrator} placeholder and MyAnonamouse series fallback Follow-up to #1390 and #1399. Related to #605 and #934 (narrator support). ## Problem Several narrations of the same audiobook currently land in the same folder, because nothing in the path template tells them apart. Keeping more than one version means renaming folders by hand after every download. Since #1390, MyAnonamouse results carry the release's narrator and series in `extra`, but the naming templates can't use them: there is no `{Narrator}` placeholder, and `{Series}` / `{SeriesPosition}` only come from the metadata provider. ## Changes - **`{Narrator}` placeholder** (`core/naming.py`, `download/postprocess/transfer.py`, `core/models.py`): `DownloadTask` gains `narrator`, read from `narrator` or `extra.narrator` when a release is queued, and kept in the restart-safe retry payload. It's available in audiobook templates like any other placeholder, including prefix/suffix blocks such as `{ - Narrator}`. - **Audiobookshelf folder style**: Audiobookshelf reads the narrator from folder names like `Title {Narrator}`. The template `{Title} {{Narrator}}` already matches as `{` + `{Narrator}`; the parser now also drops the closing brace when the narrator is empty, so the folder is `Title` rather than `Title }`. - **No stray spaces around `/`**: an empty placeholder at the start or end of a folder name no longer leaves a space there (e.g. `Title /Title`). This applies to all templates. - **Series fallback** (`release_sources/prowlarr/mam.py`, `source.py`, `download/orchestrator.py`): MAM enrichment also stores the first series' name and number as `extra.series_name` / `extra.series_position`, which queueing already falls back to when the metadata provider has no series. The provider's series still wins. A release-level series number is only used when it names the same series as the provider, so a provider series is never paired with the number of a different MAM series (an omnibus, for example). - **Settings and preview** (`config/settings.py`, `namingTemplatePreview.ts`): the audiobook template descriptions list `{Narrator}` and explain `{{Narrator}}`. The settings page preview mirrors the parser changes and offers `{Narrator}` under "Insert variable" for audiobook templates only. - **Docs**: regenerated `environment-variables.md`. This also picked up the Library Check settings, which weren't in the generated docs yet; happy to drop that part to keep the diff focused. ## Example Audiobook Path Template `{Author}/{Title} {{Narrator}}/{Title}`: | Narrator | Result | |----------|--------| | Samuel Roukin | `Christopher Ruocchio/Empire of Silence {Samuel Roukin}/Empire of Silence.m4b` | | none | `Christopher Ruocchio/Empire of Silence/Empire of Silence.m4b` | ## Testing - `tests/core/test_narrator_template_variable.py` (new, 16 tests): `{{Narrator}}` with and without a value, the `{ {Narrator}}` prefix form, prefix/suffix blocks, sanitizing, `build_library_path`, task metadata, retry payload round trip, MAM series name/number parsing (including a `1-3` range having no number), and queueing (narrator from `extra`, series fallback, no cross-series number, blank narrator). - `namingTemplatePreview.test.ts`: the same `{{Narrator}}` cases for the preview. - Updated `test_generate_env_docs.py` for the new template description. - Full `pytest -m "not integration and not e2e"` compared with an upstream `main` worktree on the same machine: no new failures (the remaining ones are Windows-only on both). - `ruff check`, `ruff format --check`, `basedpyright` (0 errors) and `vulture` on touched files; frontend `tsc --noEmit`, `oxlint`, `oxfmt --check`, `vitest` (218 passed). - Checked the settings page locally: the audiobook preview renders `... {Simon Vance}.mp3` and `{Narrator}` is listed for audiobook templates only. No behavior change for existing templates, apart from spaces next to `/` being trimmed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: narrator, series and bitrate columns for MyAnonamouse results
Addresses #605 and #934 (narrator in the release list).
Problem
Both requests were closed because the narrator isn't in Torznab results, which is correct. Prowlarr's MyAnonamouse indexer reads
author_infobut drops thenarrator_infoandseries_infoMAM returns next to it, and neither Prowlarr'sReleaseInfonor the Torznab output has a field for them. Shelfmark's size tooltip already looks for anarratorTorznab attribute, but nothing ever sends one.When a book has several narrations, choosing one means going back and forth between Shelfmark and the tracker.
Approach
Optional, opt-in enrichment using the user's own MAM session (
mam_id), the same approach AudioBookRequest's MAM indexer uses:…myanonamouse.net/t/<id>are collected./tor/js/loadSearchJSONbasic.php, normally one request, at most 3), and matches torrents back to Prowlarr's results by torrent ID. The MAM origin is taken from the result URL, so a custom Prowlarr MAM base URL is respected, and the cookie is only ever sent to*.myanonamouse.net.extra.narrator,extra.series(The Sun Eater #1) andextra.bitrate/extra.bitrate_value. MAM has no bitrate field, so it's parsed from the uploader's free-text tags (64 kbps) and some releases won't have one.Lookups are cached per torrent for an hour, respect the existing Prowlarr search deadline, go through the configured proxy (
get_proxies), and never fail the search: a 403, timeout or bad JSON is logged and the list renders without the extra details.Changes
release_sources/prowlarr/mam.py(new): small MAM client (search, andget_usernamefor the test button),narrator_info/series_info/ tags parsing, cached best-effortlookup_torrent_details(). A 403 includes MAM's reply and a note about the IP/ASN lock.release_sources/prowlarr/source.py: enrichment after the result loop. Series, Narrator and Bitrate columns only when a MAM ID is configured, since otherwise they would be empty for every row. A Torznabbitrateattribute from other indexers is also mapped toextra.bitrate.release_sources/prowlarr/settings.py: "MyAnonamouse Enrichment" section withPROWLARR_MAM_ID(password field, env-overridable like every setting) and a Test MAM Session button.release_sources/__init__.py:ColumnSchemagains optionalsetting_keyandcontent_types. The newapply_column_visibility()drops gated columns and their grid tracks. Neither field is serialized.main.py:/api/releasesappliesapply_column_visibility()with the request's content type and the user's effective settings.config/settings.py/users_settings.py: Search Mode › "Release List Columns" withSHOW_SERIES_COLUMN,SHOW_NARRATOR_COLUMNandSHOW_BITRATE_COLUMN, all default on and user-overridable. Narrator and bitrate are audiobook-only, series shows for both. AudiobookBay's existing bitrate column now follows the bitrate toggle.·separators; the size tooltip no longer lists Bitrate twice.docs/myanonamouse-enrichment.md(linked from the index), and a regeneratedenvironment-variables.md. The regeneration also picked up a few pre-existing drifts frommain(the Libgen section,AA_DEFAULT_SORTdefault, a duplicateBOOK_LANGUAGErow). I can drop those if you'd rather keep this diff focused.MyAnonamouse locks each session to one IP or ASN. Reusing the session Prowlarr (or a seedbox script) uses will often 403. A separate MAM session for Shelfmark will likely be needed when Shelfmark reaches MAM from a different IP (another host, a VPN container, or a proxy in Shelfmark's Network settings), or when the existing session is ASN-locked to another network. The setting's description, the error message and the new doc all say so.
Testing
tests/prowlarr/test_mam_enrichment.py(new, 19 tests): parsing (narrator dedupe, multiple series, missing numbers, malformed JSON, tag bitrate), lookup (stops once all IDs are found, cache, 403 and connection errors return empty, expired deadline skips the request), only MAM releases enriched, Torznab bitrate mapping, column config with and without a MAM ID for audiobook and ebook, toggles, grid-track removal, and gates not serialized.tests/core/test_admin_users_api.py: the curated search-preference key list now includes the three toggles.pytest -m "not integration and not e2e"compared with an upstreammainworktree on the same machine: no new failures. The remaining ~115 failures on both are Windows-only (tor/entrypoint shell tests, path separators).ruff check/ruff format --check/basedpyright(0 errors) /vultureon touched files; frontendtsc --noEmit,oxlint,oxfmt --check,vitest(201 passed).No behavior change unless
PROWLARR_MAM_IDis set, apart from the bitrate toggle on AudiobookBay (default on, same as today).🤖 Generated with Claude Code