Repository navigation
feat(lumen): caching, admin request tools, saved settings and branding uploads - #596
Conversation
Lumen asked SeerrNG again for everything on every visit: going back to Discover repeated all its calls, including one detail lookup per title in "New on <server>". Besides being slow (SeerrNG's first lookup of a title can take seconds), every call counts against SeerrNG's per-account rate limit, so quick browsing could hit 429s. - apiCache.ts: answers younger than 3 minutes are reused without asking; older ones (up to a day) show at once while a new answer loads. Saved per account in localStorage so a reopened app starts from what it last showed; signing out or switching account drops it. - Any request or other change (POST/PUT/DELETE, another narrator) marks everything stale, so nothing keeps showing a title as not requested. Requests, quota, sign-in and public settings are always re-checked. - useApi, the Discover rows, "New on <server>" (the finished row is saved too) and list pages use it. A failed refresh keeps the saved answer up. - Books, Audiobooks, Movies and Series show placeholder posters while the first page loads, so a slow answer doesn't look like an empty page. Checked in the SeerrNG Android app (emulator, Android 16): Movies and Back, and a full close and reopen, ask SeerrNG for none of Discover's rows again; Back still behaves.
…ttings Tester feedback: - Requests gets an Everyone tab for admins and request managers: every waiting request first, then the newest, each with who asked, and Approve / Decline on waiting ones. The tab shows how many are waiting. - The request sheet and the Advanced options get "Request as" for people SeerrNG lets choose the requester (Admin, or Manage Users together with Manage Requests). - Title pages show the posters' corner glyph on their poster: the check when it's in the library, the clock when requested. - "Lumen settings for everyone" can be saved from the admin page. A small nginx script (njs, already in the image) checks with SeerrNG that the person is an admin, then writes lumen-config.json into a mounted /lumen-data folder. Without that folder the page keeps the download.
With a big download queue, the request that was actually downloading could be far down the history, past the newest requests Lumen lists, so the Requests page showed only queued titles at 0%. Both Requests lists now also pull in every request whose download has started (from SeerrNG's in-progress requests); the Everyone tab puts them right after the ones waiting for approval, furthest along first. Radarr and Sonarr report everything in the download client's queue as "downloading". Requests and posters now say Queued while none of it is here yet.
Admins and request managers get SeerrNG's request actions in Lumen: - Change (waiting requests, and failed movie or series requests): a sheet with server, quality, folder, who the request is for and, for a series, its seasons, starting from what the request has now. A waiting request is then approved or just saved; a failed one is saved and tried again. - Retry on failed requests. - Remove on any request, confirmed by a second click on the same button (no browser pop-up). The Back-closes-the-sheet handling moves into useBackCloses so both sheets share it.
With the /lumen-data folder mounted, "Lumen settings for everyone" gets an Upload button next to the logo and the tab icon. The image is checked (PNG, JPEG, WebP, SVG or ICO by its first bytes, up to 2 MB, SeerrNG admins only), kept in /lumen-data/branding under a new name each time so no browser shows an old copy, and its address is saved for everyone straight away. Other unsaved changes on the page stay unsaved. Older uploads of the same kind are deleted. /branding/ now serves uploads first, then a branding folder mounted into the app, with a CSP that lets nothing there run scripts. The save script also avoids syntax njs doesn't support (spread, for...of); the image's proxy tests caught it.
Tester feedback (Tatsu, ncbudd/lumen#4): - branding.logoShape frames the custom logo: "rounded" (default), "circle", or "raw" (the file as it is: transparent, uncropped, as wide as it is up to 160px). The admin settings page picks it, with a live preview. The logo CSS now beats the play mark's own rules, which gave a custom logo the accent square on the sign-in card. - mediaServerName replaces Plex / Jellyfin / Emby in every label, filter and the sign-in page (up to 40 characters). Set on the admin page; empty keeps the real name.
The Everyone tab listed waiting requests, started downloads and only the 20 newest requests, so a big library (hundreds of requests) showed a small slice. It now has SeerrNG's own filters with their counts (All, Waiting, Downloading, Failed, Available) and a Show more button that loads 20 more at a time (in SeerrNG pages of up to 100). All still puts waiting requests and started downloads first; Downloading puts started ones first.
|
Merged with contributor ancestry preserved in a03a2a04a, pushed to main and the GitLab mirror. This is not yet a new stable release. Reviewed the nginx/njs writes and authentication, SVG serving protections, client account/cache boundaries, request permissions and controls. I patched three verified defects before merging:
Evidence: 327 browser cases passed, with 13 viewport-specific skips; 8 matching baseline visual cases; final retry/sign-out checks passed across desktop, phone and tablet. The final native suite passes 27 cases, including an actual built nginx container that checks anonymous/non-admin denial, invalid/oversized config, persistent config readback, upload validation, SVG CSP/sandbox/nosniff and preservation of the current logo. Failed baselines are retained. Tests use isolated fixtures, not household requests. Detailed review and limits. Root release qualification is still pending. |
Lumen: caching, admin request tools, saved settings and branding
Seven commits on top of main (f7bc03b), consolidated from tester feedback collected in ncbudd/lumen (mirror PR ncbudd/lumen#2).
1. Keep recent answers instead of asking SeerrNG every time
Discover's second visit makes 1 call instead of 23.
2. Requests from everyone, Request as, library badge, saved settings
userId./auth/methat the person is an admin. It then writeslumen-config.jsoninto a mounted/lumen-datafolder.lumen-config.json./lumen-datais deliberately not created in the image, so settings are never written into a container that an update would replace.3. Show downloads that have started, and call 0% ones Queued
filter=processing(up to two pages, kept only when progress is above 0).downloading, so anything at 0% now says Queued, on request rows and on posters.4. Change, Retry and Remove on the Everyone tab
PUT /request/:id). A waiting request is then approved or just saved; a failed one is saved and retried.POST /request/:id/retry).DELETE /request/:id), confirmed by a second click on the same button rather than a browser pop-up.useBackCloses, so both sheets share it.5. Upload the logo and tab icon
/lumen-datamounted, the admin settings page has Upload buttons (PUT /lumen/branding/logo|icon, admins only)./lumen-data/brandingunder a new name each time, so no browser shows an old copy, and earlier uploads of the same kind are deleted./branding/serves uploads first, then a mounted branding folder. It has a CSP that lets nothing there run scripts, including an SVG opened on its own.6. Logo shape and a custom media server name
branding.logoShape:rounded(default),circle, orraw. Raw is the file as it is: transparent, uncropped, and as wide as it is, up to 160px. It's picked on the admin page with a live preview.mediaServerNamereplaces Plex / Jellyfin / Emby in every label, filter and the sign-in page (up to 40 characters). Leaving it empty keeps the real name.7. Everyone shows every request: filters and Show more
/request/count: All, Waiting, Downloading, Failed and Available.Compose files and
docs/using-seerr/lumen.mdcover/lumen-data(mkdir lumen-data && sudo chown 101:101 lumen-data), uploads,logoShapeandmediaServerName.Testing
tsc --noEmit, build, and unit tests: 22 passed, including the real-image proxy tests. These caught two njs syntax limits (spread andfor...of) before anything shipped.nginxwith the template mounted).