405 lines
16 KiB
Markdown
405 lines
16 KiB
Markdown
|
|
# 04 — Theming and Users
|
||
|
|
|
||
|
|
Status: applied 2026-05-08 against `https://tv.s8n.ru` (Jellyfin 10.10.3 on nullstone).
|
||
|
|
Scope: visual theme, server-side branding, multi-user UX prep, SyncPlay,
|
||
|
|
maintenance/revert. LAN-only constraints preserved (no public-facing changes).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Theme decision: ElegantFin
|
||
|
|
|
||
|
|
### Candidates surveyed
|
||
|
|
|
||
|
|
| Theme | Type | Maintenance (May 2026) | Notes |
|
||
|
|
|---|---|---|---|
|
||
|
|
| Jellyfin built-in CSS variables | first-party | n/a | Minimal. Recolour only, no layout polish. |
|
||
|
|
| **ElegantFin** (lscambo13) | community CSS | **active — v25.12.31 (Dec 2025)**, tested 10.11.5 | Jellyseerr-inspired. Single-import, jsDelivr-hosted. |
|
||
|
|
| Ultrachromic (CTalvio) | community CSS | "selectively maintained, project is old" | Three presets (mono / kaleido / nova). Risk of breaking on newer JF. |
|
||
|
|
| JellyFlix (prayag17) | community CSS | **development halted** per repo notice | Most Netflix-look-alike but stale. |
|
||
|
|
| DarkFlix (DevilsDesigns) | community CSS, fork of JellyFlix | sporadic | Inherits JellyFlix risk. |
|
||
|
|
| Theme Park (Jellyfin pack) | multi-app CSS | active | dracula/nord/hotline/plex variants. Less Netflix, more "skin pack". |
|
||
|
|
| Jellyfin-Vue | full alt web client | active | Replaces the entire web UI. Out of scope: violates "theme via CSS only" constraint and forces an image swap. |
|
||
|
|
| Finetwo / JellyfinNetflixWeb | fork-style replacement | varies | Same constraint violation. |
|
||
|
|
|
||
|
|
### Why ElegantFin
|
||
|
|
|
||
|
|
1. **Most recent activity by far** — v25.12.31 released 31 Dec 2025; tested
|
||
|
|
on Jellyfin 10.11.5 which means it'll keep working as we upgrade past
|
||
|
|
our current 10.10.3.
|
||
|
|
2. **Single `@import` line** — zero ops overhead. CDN-hosted on jsDelivr
|
||
|
|
with `cache-control: public, max-age=604800`. No assets to host
|
||
|
|
ourselves. Revert = clear one field.
|
||
|
|
3. **Jellyseerr-inspired** — modern dark UI with rounded cards, hero
|
||
|
|
backdrops, smooth hover, condensed sidebar. Closer to "premium
|
||
|
|
streaming" feel than Netflix's red-and-black, and ages better.
|
||
|
|
4. **Doesn't touch the upstream image** — we stay on `jellyfin/jellyfin:10.10.3`.
|
||
|
|
5. **Compatible with multi-user setup** — applies server-wide via
|
||
|
|
`Branding.CustomCss`, every user inherits.
|
||
|
|
6. **Not the JellyWatch 2026 darling** (that was JellyFlix) but JellyFlix
|
||
|
|
is explicitly halted. ElegantFin is the safer, longer-lived pick.
|
||
|
|
|
||
|
|
### What it looks like
|
||
|
|
|
||
|
|
- Inter typeface throughout (loaded from Google Fonts inside the CSS).
|
||
|
|
- Dark-only colour scheme (`color-scheme: dark`), primary background
|
||
|
|
`#111827`, secondary `#1d2635` (Tailwind slate territory).
|
||
|
|
- Backdrop hero on item pages with darker bottom-gradient overlay.
|
||
|
|
- Rounded cards (~10px radius), subtle shadow, hover lift.
|
||
|
|
- "ElegantFin v25.12.31" tag in the footer (visible to users — fine for us).
|
||
|
|
- Login screen restyled into a centred card on a blurred backdrop.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. How it was applied
|
||
|
|
|
||
|
|
### Branding API (already done 2026-05-08)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
TOKEN=*redacted*
|
||
|
|
|
||
|
|
cat > /tmp/branding.json <<'EOF'
|
||
|
|
{
|
||
|
|
"LoginDisclaimer": "Welcome to tv.s8n.ru — LAN-only. Be kind, rewind.",
|
||
|
|
"CustomCss": "/* ElegantFin v25.12.31 — Jellyseerr-inspired Netflix-y theme */\n@import url(\"https://cdn.jsdelivr.net/gh/lscambo13/ElegantFin@main/Theme/ElegantFin-jellyfin-theme-build-latest-minified.css\");\n",
|
||
|
|
"SplashscreenEnabled": true
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
|
||
|
|
curl -sS -X POST \
|
||
|
|
-H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
--data-binary @/tmp/branding.json \
|
||
|
|
https://tv.s8n.ru/System/Configuration/branding
|
||
|
|
# expect: HTTP 204
|
||
|
|
```
|
||
|
|
|
||
|
|
### Verification
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -sS -H "X-Emby-Token: $TOKEN" \
|
||
|
|
https://tv.s8n.ru/System/Configuration/branding | python3 -m json.tool
|
||
|
|
# Should include the @import line and the disclaimer text.
|
||
|
|
|
||
|
|
# Public branding endpoint the SPA reads at runtime — confirms anonymous
|
||
|
|
# clients (i.e. the browser before login) will see the theme:
|
||
|
|
curl -sS https://tv.s8n.ru/Branding/Configuration | python3 -m json.tool
|
||
|
|
```
|
||
|
|
|
||
|
|
`/` returns Jellyfin's SPA shell; the theme CSS is fetched **at runtime**
|
||
|
|
by the JS bundle from `/Branding/Configuration`, not inlined into
|
||
|
|
`index.html`. So `curl /` won't grep-match. The valid JSON at
|
||
|
|
`/Branding/Configuration` is the API-level confirmation. Final check is a
|
||
|
|
hard browser reload (cache-bust) on `https://tv.s8n.ru` from the LAN.
|
||
|
|
|
||
|
|
### Cache clear
|
||
|
|
|
||
|
|
Jellyfin web caches aggressively in browsers. After applying:
|
||
|
|
|
||
|
|
- Users: hard reload (Ctrl-Shift-R / Cmd-Shift-R) once.
|
||
|
|
- Server: no restart needed; CustomCss change is live on next page load.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Server-side branding state (as of 2026-05-08)
|
||
|
|
|
||
|
|
| Field | Value |
|
||
|
|
|---|---|
|
||
|
|
| `LoginDisclaimer` | "Welcome to tv.s8n.ru — LAN-only. Be kind, rewind." |
|
||
|
|
| `CustomCss` | `@import` of ElegantFin v25.12.31 from jsDelivr (autoupdating off `@main`) |
|
||
|
|
| `SplashscreenEnabled` | `true` |
|
||
|
|
|
||
|
|
`SplashscreenEnabled: true` makes Jellyfin auto-pick a backdrop from the
|
||
|
|
library and serve it at `/Branding/Splashscreen`. The web client doesn't
|
||
|
|
itself surface this; mobile/TV clients do. Harmless to leave on.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Multi-user UX prep
|
||
|
|
|
||
|
|
### 4a. Library inventory
|
||
|
|
|
||
|
|
| Library | Type | ItemId |
|
||
|
|
|---|---|---|
|
||
|
|
| Movies | movies | `f137a2dd21bbc1b99aa5c0f6bf02a805` |
|
||
|
|
| TV Shows | tvshows | `767bffe4f11c93ef34b805451a696a4e` |
|
||
|
|
| Playlists | playlists | `1071671e7bffa0532e930debee501d2e` |
|
||
|
|
|
||
|
|
### 4b. Existing users
|
||
|
|
|
||
|
|
| Name | UserId | Admin? |
|
||
|
|
|---|---|---|
|
||
|
|
| s8n | `2be0f0d3fe3a45dc9298138a15a01925` | yes |
|
||
|
|
|
||
|
|
### 4c. Creating a new user (UI)
|
||
|
|
|
||
|
|
1. Dashboard → Users → "+ Add User".
|
||
|
|
2. Username + initial password. Tick "User can manage server" OFF.
|
||
|
|
3. After creation, click the user → tabs:
|
||
|
|
- **Profile**: language, audio default, subtitle default. Set per
|
||
|
|
user; doesn't have to match server defaults.
|
||
|
|
- **Library Access**: untick "Enable access to all libraries", tick
|
||
|
|
only the libraries this user should see.
|
||
|
|
- **Parental Control**: max rating, blocked tags, access schedule.
|
||
|
|
- **Password**: set / reset.
|
||
|
|
|
||
|
|
### 4d. Creating a new user (API) — playbook
|
||
|
|
|
||
|
|
> **Do not run this without explicit user request.** Documented for the
|
||
|
|
> friend account that will exist later.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
TOKEN=*redacted*
|
||
|
|
TVSHOWS_ID=767bffe4f11c93ef34b805451a696a4e
|
||
|
|
|
||
|
|
# 1. Create the user (auth header REQUIRED — admin token).
|
||
|
|
NEW_USER=$(curl -sS -X POST \
|
||
|
|
-H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"Name":"friend","Password":"<initial-password>"}' \
|
||
|
|
https://tv.s8n.ru/Users/New)
|
||
|
|
echo "$NEW_USER" | python3 -m json.tool
|
||
|
|
NEW_ID=$(echo "$NEW_USER" | python3 -c "import sys,json; print(json.load(sys.stdin)['Id'])")
|
||
|
|
echo "NEW_ID=$NEW_ID"
|
||
|
|
|
||
|
|
# 2. Tighten the policy: TV-only, non-admin, can change own prefs,
|
||
|
|
# no content deletion, SyncPlay enabled (so we can co-watch).
|
||
|
|
cat > /tmp/policy.json <<EOF
|
||
|
|
{
|
||
|
|
"IsAdministrator": false,
|
||
|
|
"IsHidden": false,
|
||
|
|
"IsDisabled": false,
|
||
|
|
"EnableContentDeletion": false,
|
||
|
|
"EnableUserPreferenceAccess": true,
|
||
|
|
"EnableRemoteAccess": true,
|
||
|
|
"EnableSharedDeviceControl": false,
|
||
|
|
"EnableLiveTvAccess": false,
|
||
|
|
"EnableLiveTvManagement": false,
|
||
|
|
"EnableMediaPlayback": true,
|
||
|
|
"EnableAudioPlaybackTranscoding": true,
|
||
|
|
"EnableVideoPlaybackTranscoding": true,
|
||
|
|
"EnablePlaybackRemuxing": true,
|
||
|
|
"EnableAllFolders": false,
|
||
|
|
"EnabledFolders": ["$TVSHOWS_ID"],
|
||
|
|
"EnableAllChannels": false,
|
||
|
|
"EnabledChannels": [],
|
||
|
|
"EnableAllDevices": true,
|
||
|
|
"BlockedTags": [],
|
||
|
|
"BlockedMediaFolders": [],
|
||
|
|
"MaxParentalRating": null,
|
||
|
|
"AccessSchedules": [],
|
||
|
|
"SyncPlayAccess": "CreateAndJoinGroups",
|
||
|
|
"InvalidLoginAttemptCount": 0,
|
||
|
|
"LoginAttemptsBeforeLockout": 5,
|
||
|
|
"MaxActiveSessions": 0
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
|
||
|
|
curl -sS -X POST \
|
||
|
|
-H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
--data-binary @/tmp/policy.json \
|
||
|
|
"https://tv.s8n.ru/Users/$NEW_ID/Policy"
|
||
|
|
# expect: HTTP 204
|
||
|
|
|
||
|
|
# 3. Verify
|
||
|
|
curl -sS -H "X-Emby-Token: $TOKEN" \
|
||
|
|
"https://tv.s8n.ru/Users/$NEW_ID" | python3 -m json.tool
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4e. Policy field cheat-sheet
|
||
|
|
|
||
|
|
| Field | What it does | Recommended for `friend` |
|
||
|
|
|---|---|---|
|
||
|
|
| `IsAdministrator` | Full server admin | **false** |
|
||
|
|
| `EnableContentDeletion` | Can delete media items via UI | **false** |
|
||
|
|
| `EnableUserPreferenceAccess` | Change own profile/audio/sub prefs | **true** |
|
||
|
|
| `EnableAllFolders` | Master switch for library ACL | **false** |
|
||
|
|
| `EnabledFolders` | Whitelist of CollectionFolder Ids | `[TVShows]` (only) |
|
||
|
|
| `BlockedTags` | Skip items tagged with these | optional; e.g. `["adult","unrated"]` |
|
||
|
|
| `MaxParentalRating` | Hide above this rating | `null` for friend (adult). Set `15` for a kid. |
|
||
|
|
| `AccessSchedules` | Day-of-week + time windows | `[]` (no restriction) |
|
||
|
|
| `SyncPlayAccess` | `CreateAndJoinGroups` / `JoinGroups` / `None` | `CreateAndJoinGroups` |
|
||
|
|
| `MaxActiveSessions` | Concurrent sessions cap; 0 = unlimited | `2` if you want to throttle |
|
||
|
|
| `LoginAttemptsBeforeLockout` | Brute-force protection | `5` |
|
||
|
|
| `EnableLiveTvAccess` / `Management` | Live TV / DVR | **false** (we don't run it) |
|
||
|
|
|
||
|
|
### 4f. Password reset flow
|
||
|
|
|
||
|
|
The friend forgot their password. Two routes:
|
||
|
|
|
||
|
|
- **Self-serve (only if SMTP is configured — we don't currently)**: login
|
||
|
|
page → "Forgot Password". Jellyfin emits a PIN file at
|
||
|
|
`/config/data/passwordreset-*.json` valid 30 minutes. Without SMTP, the
|
||
|
|
admin reads the PIN out of the container and gives it to the friend.
|
||
|
|
- **Admin reset (what we'll do)**:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -sS -X POST \
|
||
|
|
-H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"NewPw":"<new-password>","ResetPassword":false}' \
|
||
|
|
"https://tv.s8n.ru/Users/$USER_ID/Password"
|
||
|
|
```
|
||
|
|
|
||
|
|
To clear the password entirely (forces friend to set one on next login):
|
||
|
|
same call with `"ResetPassword": true` and no `NewPw`.
|
||
|
|
|
||
|
|
### 4g. Easy Pin / quick login
|
||
|
|
|
||
|
|
Jellyfin's built-in equivalent is **Quick Connect**:
|
||
|
|
|
||
|
|
- Dashboard → General → "Allow Quick Connect" (server-wide toggle).
|
||
|
|
- Friend opens a Jellyfin client (TV app, mobile), taps "Quick Connect" →
|
||
|
|
6-digit code.
|
||
|
|
- They enter the code in any already-logged-in browser session under
|
||
|
|
Settings → Quick Connect → Authorize.
|
||
|
|
|
||
|
|
Casual-friendly and avoids them typing passwords on a TV remote. **We
|
||
|
|
have not enabled it yet** — flip on when friend account is created.
|
||
|
|
|
||
|
|
### 4h. Per-user defaults (profile UI)
|
||
|
|
|
||
|
|
Set on each user's profile page (or via `/Users/{id}/Configuration` API):
|
||
|
|
|
||
|
|
- `AudioLanguagePreference`: `eng`
|
||
|
|
- `SubtitleLanguagePreference`: `eng`
|
||
|
|
- `SubtitleMode`: `Smart` (only show when audio differs) or `Always`.
|
||
|
|
- `PlayDefaultAudioTrack`: true.
|
||
|
|
- Display language: pick on first login.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Watching together / continue-watching
|
||
|
|
|
||
|
|
### 5a. Resume / Next Up / Up Next — how Jellyfin builds them
|
||
|
|
|
||
|
|
- **Continue Watching** ("Resume" row): items where `UserData.PlaybackPositionTicks > 0`
|
||
|
|
and not yet `Played: true`. Threshold for "watched" is server-side
|
||
|
|
~90% by default. Per-user.
|
||
|
|
- **Next Up**: for series the user has started, Jellyfin walks the
|
||
|
|
next unwatched episode in season/episode order. Configurable in
|
||
|
|
Dashboard → Display → Next Up (max age, rewatching toggle).
|
||
|
|
- **Up Next** (the in-player auto-advance card): client-side feature in
|
||
|
|
the web/mobile players, fed by the same Next Up logic.
|
||
|
|
|
||
|
|
No action needed — these light up automatically once a user has played
|
||
|
|
something. Futurama is loaded, so as soon as anyone plays an episode,
|
||
|
|
the homepage gets populated.
|
||
|
|
|
||
|
|
### 5b. SyncPlay (synchronised group playback)
|
||
|
|
|
||
|
|
Server-side: nothing to enable, ships on. Per-user permission lives in
|
||
|
|
`Policy.SyncPlayAccess`:
|
||
|
|
|
||
|
|
| Value | Meaning |
|
||
|
|
|---|---|
|
||
|
|
| `CreateAndJoinGroups` | Can start a SyncPlay group + invite | (s8n + recommended for friend) |
|
||
|
|
| `JoinGroups` | Can only join existing groups | useful for kid accounts |
|
||
|
|
| `None` | Disabled | — |
|
||
|
|
|
||
|
|
Verified current state: `s8n.SyncPlayAccess = CreateAndJoinGroups` ✓.
|
||
|
|
|
||
|
|
**How to use**:
|
||
|
|
|
||
|
|
1. s8n opens a series episode and starts playing.
|
||
|
|
2. Player overlay → top-right people-icon ("SyncPlay") → "Create group".
|
||
|
|
3. Friend logs in (any device — same `tv.s8n.ru`), opens the same item
|
||
|
|
or the SyncPlay menu → "Join {s8n}'s group".
|
||
|
|
4. Anyone in the group's play/pause/seek is mirrored within ~1 second.
|
||
|
|
5. Voice chat is up to you — Jellyfin doesn't bundle one (Matrix room
|
||
|
|
on `txt.s8n.ru` works fine; or just a phone call).
|
||
|
|
|
||
|
|
Caveat: SyncPlay uses WebSockets. Our reverse proxy (`traefik`) handles
|
||
|
|
WS by default, no changes needed.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Maintenance
|
||
|
|
|
||
|
|
### 6a. Updating the theme
|
||
|
|
|
||
|
|
ElegantFin's `@import` URL pins to `@main` on jsDelivr — meaning new
|
||
|
|
upstream commits propagate after jsDelivr's cache TTL (12h s-maxage,
|
||
|
|
7d max-age). To pull immediately:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Force refresh by pinning to a specific tag, then back to main:
|
||
|
|
curl -sS -X POST -H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"CustomCss": "@import url(\"https://cdn.jsdelivr.net/gh/lscambo13/ElegantFin@v25.12.31/Theme/ElegantFin-jellyfin-theme-build-latest-minified.css\");", "LoginDisclaimer": "Welcome to tv.s8n.ru — LAN-only. Be kind, rewind.", "SplashscreenEnabled": true}' \
|
||
|
|
https://tv.s8n.ru/System/Configuration/branding
|
||
|
|
```
|
||
|
|
|
||
|
|
Or just ask each user to hard-reload — their browser cache is the
|
||
|
|
common bottleneck, not jsDelivr.
|
||
|
|
|
||
|
|
When upgrading Jellyfin (e.g. 10.10.3 → 10.11.x), check
|
||
|
|
[the ElegantFin release notes](https://github.com/lscambo13/ElegantFin/releases)
|
||
|
|
first. The current theme is tagged tested-against 10.11.5, so we're
|
||
|
|
forward-compatible through that.
|
||
|
|
|
||
|
|
### 6b. Reverting
|
||
|
|
|
||
|
|
Empty out the CustomCss field via API:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -sS -X POST -H "X-Emby-Token: $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"CustomCss": "", "LoginDisclaimer": "", "SplashscreenEnabled": false}' \
|
||
|
|
https://tv.s8n.ru/System/Configuration/branding
|
||
|
|
```
|
||
|
|
|
||
|
|
Or in the UI: Dashboard → General → clear "Custom CSS code" → Save.
|
||
|
|
Hard-reload browsers. Vanilla Jellyfin returns instantly.
|
||
|
|
|
||
|
|
### 6c. Pinning a known-good revision
|
||
|
|
|
||
|
|
If `@main` ships a regression, switch the URL to a specific release tag
|
||
|
|
(e.g. `@v25.12.31`). Tags are in the GitHub releases page. jsDelivr
|
||
|
|
serves `@<tag>` immutably and forever.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. First-30-minutes UX checklist (new user)
|
||
|
|
|
||
|
|
When the friend gets their account, walk them through this **once**:
|
||
|
|
|
||
|
|
1. **Login** → see the LAN-only disclaimer; that's the right server.
|
||
|
|
2. **Profile picture** → set one (just helps SyncPlay group UX).
|
||
|
|
3. **Display preferences** (top-right user icon → Display):
|
||
|
|
- Theme: keep "Dark" (ElegantFin is dark-only, light theme will look
|
||
|
|
half-applied). Don't switch.
|
||
|
|
- Landing screen: Home.
|
||
|
|
4. **Playback preferences**:
|
||
|
|
- Default audio language: `English`.
|
||
|
|
- Default subtitle language: `English`.
|
||
|
|
- Subtitle mode: `Smart` (auto-show on foreign audio).
|
||
|
|
- "Play next episode automatically": on (this is what enables Up Next).
|
||
|
|
5. **Quality** — first-time playback test on Futurama:
|
||
|
|
- Pick S01E01, play. Click the gear → quality. If it stutters on
|
||
|
|
1080p, drop to 720p; transcoder is CPU-only on nullstone today
|
||
|
|
(GTX 1660 Ti driver still broken — see `README.md`).
|
||
|
|
- Once confirmed playing, that quality is remembered per device.
|
||
|
|
6. **SyncPlay test**: friend in one tab, s8n in another, friend joins
|
||
|
|
s8n's group, confirm play/pause syncs. (Drops the "do you have it
|
||
|
|
running" question forever.)
|
||
|
|
7. **Mobile/TV**: install Jellyfin app, server URL `https://tv.s8n.ru`
|
||
|
|
(must be on LAN or Tailscale), Quick Connect or password.
|
||
|
|
8. **Bookmarks/RSS**: there isn't one — Jellyfin's "Latest" row is the
|
||
|
|
substitute. Friend can favourite shows (heart icon) to pin.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Open items / future work
|
||
|
|
|
||
|
|
- [ ] Enable Quick Connect when friend account is created (Dashboard →
|
||
|
|
General → Quick Connect).
|
||
|
|
- [ ] Configure SMTP for self-serve password reset (currently admin-only).
|
||
|
|
- [ ] Replace `@main` pin with `@v25.12.31` if we hit upstream churn.
|
||
|
|
- [ ] Add a 2nd library (movies are mounted but the server may have an
|
||
|
|
empty Movies folder — confirm with friend's first ask).
|
||
|
|
- [ ] After GPU driver fix on nullstone, NVENC transcode → 1080p HEVC
|
||
|
|
will stop being CPU-bound; revisit per-user quality defaults.
|
||
|
|
- [ ] Optional: tweak `--elegantFinFooterText` CSS var to drop the
|
||
|
|
ElegantFin version label from the footer (cosmetic).
|