Commit graph

44 commits

Author SHA1 Message Date
s8n
d0e7af3099 doc 28 INC7-final: CSS overlay covering <video> was actual cause
Agent 6 applied SW-pin fix and marked verified via element state
(currentTime advancing, videoWidth=1920, readyState=4). Headless pixel
histogram still showed darkPct=100% — element decoded fine but CSS
overlay covered it.

Real cause: branding.xml BLACK-PASS paints .libraryPage with
#000 !important. Jellyfin OSD page renders <div id=videoOsdPage
class=libraryPage>; class match -> opaque black div above <video>.

Fix: extend transparent-scope using :has(.htmlVideoPlayer) +
#videoOsdPage selector. Post-fix darkPct=9.8% (was 100%), MNS S1E4
video frame visually paints.

Removed INC6 clear-cache-only middleware (no longer needed, was
burning HTTP cache every visit).

bin/apply-26-incident-fixes.sh extended with INC7 patch (idempotent
re-apply if branding.xml ever drifts back).

Lesson: video-element state alone is insufficient verification.
Always sample pixel histogram + canvas drawImage on the painted
viewport.
2026-05-09 03:04:41 +01:00
s8n
de670bcb13 doc 28: record commit hash + nullstone backup path for INC7 fix 2026-05-09 02:50:21 +01:00
s8n
917d21b3be doc 28 + INC7: fix prod black-screen via SW cache pin
Five sibling agents converged on root cause:
jellyfin-asset-immutable Traefik router (priority 90) was matching
/web/serviceworker.js (Jellyfin PWA's actual SW filename), pinning it
with Cache-Control: public, max-age=31536000, immutable. The
priority-100 jellyfin-html-nocache router only excluded the literal
path /web/sw.js, missing serviceworker.js.

Stale SWs from earlier ARRFLIX iterations intercepted /Videos/* and
/web/* fetch events, returning cached/empty bytes. Result:
MediaSource appendBuffer got bad data -> black <video>. INC6's
Clear-Site-Data: "cache" couldn't fix it (per MDN spec, "cache"
excludes SW registrations; "storage" would have worked).

Fix: added jellyfin-sw-nocache router at priority 250 in
/opt/docker/traefik/config/dynamic.yml on nullstone, forcing
cache-no-store@file on /web/serviceworker.js + /web/sw.js. Hot-reload
via Traefik file provider, no docker restart.

Verified at the wire (curl -I /web/serviceworker.js now returns
no-cache, no-store, must-revalidate; main.jellyfin.bundle.js still
immutable as intended) and via headless Chromium probe of MNS S1E4
(33s of currentTime advance, readyState 4, videoWidth 1920x1080,
no errors, both s8n admin and guest user).

bin/prod-vs-dev-compare.py also lands as a one-shot diff helper used
during the investigation.
2026-05-09 02:50:00 +01:00
s8n
f0a2ac6450 doc 27: status snapshot 2026-05-09 visual
Visual status board: symptoms killed (8/8), roadmap (done /
pending / high / medium / deferred / strategic), library codec
matrix, repo file tree, next-click. Point-in-time after doc-26
incident closed. For ongoing roadmap see ROADMAP.md.
2026-05-09 02:23:53 +01:00
s8n
e1720e3cb5 doc 26 INC6: Clear-Site-Data cache-only for shim deploy
INC5 fmp4-disable shim required browser hard-reload to fire. Owner's
MNS S1E4 re-test still black-screened because cached index.html ran
old shim + fmp4-HLS bug recurred. Add Traefik response header
'Clear-Site-Data: "cache"' on /web/index.html. Cache-only is safe
(no cookie/storage wipe -> auth + localStorage preserved). One fresh
visit refetches index.html with new shim. Remove middleware after
owner confirms working, otherwise every revisit re-flushes cache.
2026-05-09 02:10:52 +01:00
s8n
9ca55ccf67 doc 26: add INC5 scrollbar grey-strip subsection
Symptom + root cause + fix + lesson for the scrollbar grey strip at
very bottom of page. Patch already in bin/apply-26-incident-fixes.sh
and live in branding.xml on prod from earlier commit; this is the
documentation subsection that was missing dedicated coverage.
2026-05-09 02:05:16 +01:00
s8n
1ee698b592 doc 26: case CLOSED — final state + 8 forbidden patterns
All 8 owner-reported symptoms resolved across 5 iterations (INC1-5):

INC1 — index.html drift revert + :has() transparent-scope + Cineplex
       Abspielen override + encoding.xml HLS 499 fix
INC2 — pin .backdropContainer position:fixed (persistent backdrop)
INC3 — extend transparent-scope through detail-page sub-sections
INC4 — .emby-scroller transparent (kill black band behind carousels) +
       EnableTonemapping=false + 20Mbps RemoteClientBitrateLimit cap +
       headless-test-v2.py (admin+guest+click-play+bg-sweep)
INC5 — AV1 source re-encode (MNS S1E2/E4/E5 to H.264/AAC) +
       enableHlsFmp4=false localStorage shim +
       ::-webkit-scrollbar styled to ARRFLIX palette

Verification: headless playwright on Chrome + Firefox UA confirms MNS
S1E4 plays 1920x1080 readyState=4 currentTime advancing. Owner
double-confirmed solved.

Doc 26 final state section + 18-item forbidden-pattern checklist added
for future operators.
2026-05-09 02:03:39 +01:00
s8n
733a6df96c doc 26 INC5: disable fMP4-HLS client-side + AV1 force-transcode
Two parallel fixes for MNS S1E4 black-video bug. Belt+braces.

INC5 fmp4-disable (this agent):
- Add localStorage.setItem('enableHlsFmp4', 'false') shim to
  web-overrides/index.html (idempotent, marker INC5 fmp4=false 2026-05-09)
- Forces TS segments instead of fMP4 for all HLS transcodes,
  works around upstream black-video bug with HEVC+fMP4
  (jellyfin-webos#126, jellyfin#16612)
- Browser localStorage verified false via headless playwright;
  server confirmed emitting -hls_segment_type fmp4 before fix
- Repo + deployed file md5 match: 5b212d7d60b8a2b910a2f47dd0470a09

INC5 AV1 force-transcode (parallel agent):
- Re-encoded MNS S1E1-5 AV1->H.264 in container; PlaybackInfo
  now returns DirectStream/DirectPlay=true on S1E4
- Doc additions covering the AV1 work included here since
  same file (already authored by parallel agent, not yet committed)
2026-05-09 01:58:45 +01:00
s8n
6288c57781 doc 26 INC4: black band + 4K HDR slow transcode + v2 test + methodology audit
Two regressions slipped through INC1-3:

INC4a -- BLACK BAND behind every detail-page carousel
  Pre-existing 2026-05-08 home-page rule painted .emby-scroller {bg:#000
  !important} UNSCOPED. Hits every carousel inside .itemDetailPage incl
  admin-only More from Season N, More Like This. INC1-3 transparent-scope
  list missed .emby-scroller / .verticalSection / .padded-top-focusscale.
  Fixed by extending scope.

INC4b -- VIDEO 'BLACK SCREEN' on play
  Not actually black-screen. CPU-only nullstone cannot sustain real-time
  4K HEVC HDR tonemap+x264 transcode -- 0.5x realtime, ffmpeg takes ~6s
  per 3s segment. With user resume seeks adding restart overhead, total
  wait ~18s before browser readyState rises. User saw black, gave up.
  Fix: disable EnableTonemapping (R&M fake HDR per doc 21) + cap
  RemoteClientBitrateLimit=20Mbps on every user (1080p target, no 4K
  scale). Headless v2 test confirms HEVC + AV1 episodes now hit
  readyState=3/4 within wait window; 4K HDR R&M still slow (heaviest).

INC4 testing methodology audit -- bin/headless-test-v2.py
  v1 only logged in as guest and never clicked Play. v2 runs both admin
  and guest, walks 3 codec-tagged items per role (HEVC/AV1/H.264),
  clicks Play, captures <video> state, sweeps DOM for opaque bgs over
  backdrop layer. False positives: off-viewport #reactRoot + collapsed
  .mainDrawer (negative coords). Allowlist refinement TODO.

Open: 4K HDR sources still slow even post-fix. Real fix path = pre-
transcode masters to 1080p H.264 SDR via separate batch, OR migrate to
10.11.8 with vaapi/qsv driver fixed.
2026-05-09 01:46:47 +01:00
s8n
9b06bb48c6 doc 26 INC2+INC3: pin backdrop, transparent sub-sections
After INC1 fixed the Abspielen + first-fold backdrop, owner reported black
band hiding artwork in More from Season 1 / below-fold sections. Two more
patches required:

INC2 — pin .backdropContainer + .backgroundContainer position:fixed; height
100vh so backdrop persists during scroll. Added vertical fade ::after.

INC3 — extend transparent-scope to ALL detail-page sub-sections
(.detailVerticalSection, .scrollSlider, .padded-bottom-page,
.itemsContainer etc) so section wrappers don't paint over the pinned
backdrop section by section.

bin/headless-test.py now takes top + scrolled viewport screenshots.
full_page=True hides position:fixed regressions, dual-screenshot exposes
them. Use both to bisect.

bin/apply-26-incident-fixes.sh updated with INC2+INC3.

Open: AV1+Opus playback (Mike Nolan Show) still tracked for 10.11.8
migration. .detailLogo regression possible — test in actual browser.
2026-05-09 01:21:01 +01:00
s8n
549c86efdf doc 26 + bin: incident 2026-05-09 + headless smoke-test
Symptoms: Page Unresponsive on poster grid, posters missing then black
backdrops, 'Abspielen' German Play button surviving Traefik+force-english
chases, video black-screen on play.

Root causes (different from initial guesses):
- Browser hangs: deployed index.html drifted ahead of repo; uncommitted
  forceEnglishUI() text-walker MutationObserver froze main thread on poster
  lazy-load. Reverted to repo HEAD.
- 'Abspielen': Cineplex theme HARDCODES German via 'content:' ::after rule
  -- not a Jellyfin locale issue. Doc 25 already proved per-user UICulture
  is theatre. Override CSS with content: 'Play'.
- Backdrops black: BLACK-PASS CustomCss block paints #000 !important on
  .layout-desktop / .pageContainer -- occludes backdrop layer (z-index:-1).
  Existing transparent-scope rule used body.itemDetailPage selector that
  doesn't match in 10.10.3 (body class is libraryDocument). Replaced with
  :has(.itemDetailPage) ancestor scoping.
- HLS 499: encoding.xml had EnableThrottling+EnableSegmentDeletion=true,
  segments reaped before browser re-request. Disabled both.

Verified via new bin/headless-test.py (playwright Chromium login + screenshot
+ computed-style probe). Fixes idempotent and re-runnable via new
bin/apply-26-incident-fixes.sh.

Open: AV1+Opus items still black-screen in Chrome due to DirectStream
codec-tag mislabel bug. Tracked for 10.11.8 migration.
2026-05-09 01:11:38 +01:00
s8n
117fa33048 doc 25: english leak deep-dive (Abspielen post-lockdown) 2026-05-08 22:09:59 +01:00
s8n
cdf415c862 import-log: youtube-sassy-the-sasquatch 2026-05-08 — eps 1-5 (ep6 age-restricted) 2026-05-08 22:03:42 +01:00
s8n
6a54cae82e doc 22: jellyfin runtime perf audit (read-only)
Server-runtime focus; supplements doc 13. Headline: 4 concurrent ffmpeg
processes for ONE viewer all transcoding 1080p->2160p with PGS subtitle
burn-in, on uncapped jellyfin container sharing 12-core host with
uncapped Forgejo BlueBuild CI runner (88-99 % CPU). Load avg 15.4 on 12
cores. Throttling+SegmentDeletion still off (doc 13 finding 03 now
non-optional). Top quick-win: enable transcode throttling + segment
deletion + cap RemoteClientBitrateLimit.
2026-05-08 17:51:06 +01:00
s8n
851f317dbb doc 23: arrflix edge / network / browser-load-path perf audit (read-only)
Edge audit complementing doc 13 (server-side perf). Confirms cold-load
"feels slow" perception is dominated by:
  - no HTTP compression at Traefik (2.74 MiB raw JS bundles per cold load)
  - no Cache-Control on hashed-asset URLs (28 conditional GETs per warm load)
  - first-fetch poster image transcode ~385 ms (server-side, doc 13 #02)

TLS, MTU, HTTP/2, cert chain, middleware chain, Pi-hole hairpin all
audited and clean. Pi-hole missing local DNS rewrite for arrflix.s8n.ru
(LAN clients hairpin via WAN unless /etc/hosts pin in place).

Top quick win: add `compress@file` middleware in
/opt/docker/traefik/config/dynamic.yml + reference from Jellyfin router
label. ~70 % cold-load wire-size reduction (2.74 MiB to ~0.82 MiB
gzip / ~0.69 MiB brotli). One file edit, no architectural change.

No fixes applied. No state mutated. No Traefik reload.
2026-05-08 17:50:52 +01:00
s8n
fbe9f37e08 audit: storage I/O for arrflix media path 2026-05-08 17:47:19 +01:00
s8n
2f8c02a2d3 audit: rick-and-morty color/HDR diagnosis 2026-05-08 17:45:34 +01:00
s8n
a3f82dfcc0 doc 19: english-only lockdown audit (read-only baseline)
Cross-layer audit supplementing docs 15 and 16. Confirms doc-15 root
cause still live (8/8 users have UICulture absent; force-english script
unrun), enumerates 93 served locale chunks (de-json contains 'Abspielen'),
and proposes 4-pronged remediation: per-user POST + wrapper patch +
Traefik Accept-Language rewrite + navigator.language shim.

Read-only. No Jellyfin mutations performed.
2026-05-08 17:05:11 +01:00
s8n
d5d68563d2 docs+bin: English-only lockdown — re-apply runner + doc 20
doc 20 covers the multi-layer pin (server / per-user / web SPA / Accept-
Language), the idempotent re-apply runner, drift-check curl one-liners,
known gaps, and a systemd-timer suggestion for weekly auto re-application.

bin/english-lockdown-runner.sh: idempotent runner that POSTs server-wide
UICulture / PreferredMetadataLanguage / MetadataCountryCode and per-user
UICulture / Audio+Subtitle prefs / PlayDefaultAudioTrack. Reads
JELLYFIN_API_TOKEN from env (set -u, refuses to run without it). One-line
summary per surface; exit 0 on full success, 1 on any failure.

doc 15 prefaced with a "Status as of 2026-05-08" section noting the
multi-agent lockdown sweep and cross-linking the audit baseline (doc 19,
sibling) and the new lockdown procedure (doc 20). Original body preserved
verbatim as historical context.
2026-05-08 17:04:12 +01:00
s8n
38b6bc4bdb drop tv.s8n.ru — arrflix.s8n.ru is canonical
Replaced 25 occurrences across README, docs/00-overview, and
docs/04-theming-and-users. Removed the obsolete tv→arrflix rename
blockquote (rename complete) and deduped the Live-at bullet.
2026-05-08 16:46:26 +01:00
s8n
667694adbf strip: remove Claude attribution from ROADMAP + audit docs
ROADMAP owner column 's8n' (was 'claude'). Audit-run-by lines in
docs/{11,14,16} reattributed to s8n. Removed CLAUDE.md memory ref
from docs/04 hosts-pin note.
2026-05-08 16:44:49 +01:00
s8n
3214476486 docs: add 00-overview as technical landing page 2026-05-08 16:37:30 +01:00
s8n
937589c7a2 redact: scrub leaked Jellyfin admin API token from public repo
Token 76858153...f8b1 was committed across 9 docs + 1 snapshot RESTORE.md
and exposed via the brief public window of this repo. Replaced with
`<JELLYFIN_API_TOKEN>` placeholder.

WARNING: this commit only redacts HEAD — the token remains in git history.
Anyone who cloned during the public window has the full value. Treat the
old token as compromised and rotate at Jellyfin Dashboard > API Keys.
Original value backed up to private s8n/secrets/ARRFLIX/.
2026-05-08 15:36:14 +01:00
s8n
4772ddf934 doc 17: dev mirror + Settings drawer leak fix (dev only, no prod swap) 2026-05-08 13:34:04 +01:00
s8n
3734ef90e8 doc 16: Jellyfin branding leaks audit (read-only) 2026-05-08 04:29:26 +01:00
s8n
c4ac896342 doc 14: theme audit + detail-page backdrop diagnosis (read-only) 2026-05-08 04:27:28 +01:00
s8n
6614911432 doc 13: read-only optimization audit 2026-05-08 04:24:21 +01:00
s8n
14f63e8027 doc 15: force English UI for all users (plan + script)
Owner saw "Abspielen" on the Play button — caused by every user having
Configuration.UICulture absent, so the web SPA falls back to browser
Accept-Language. No server-side flag exists to override this.

Adds docs/15-force-english.md with the per-user forcing mechanism,
limits (pre-auth splash bundle still uses navigator.language), and a
ready-to-execute bash script bin/force-english-all-users.sh that pins
UICulture=en-US on every user via POST /Users/{id}/Configuration.

Plan-only commit — no live config changed. Owner triggers when ready.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 04:22:04 +01:00
s8n
7a0eb93a0a doc 11: NeutralFin render audit (read-only)
Live render audited at https://arrflix.s8n.ru. Owner believed NeutralFin
was applied; live /Branding/Configuration shows Cineplex v1.0.6 — a
sibling POST won the race per §3b operational rule. Audit covers visual
contract, drift table for every CustomCss + critical-path index.html
rule, NeutralFin variable conflicts, logo aspect ratio (235x85, fits),
ranked fix list. No state mutated; recommendation pending owner sign-off.
2026-05-08 04:18:07 +01:00
s8n
404dc114b4 doc 04 §3e: ElegantFin migration with ARRFLIX recolor
Migrated active CSS theme from Cineplex v1.0.6 to ElegantFin v25.12.31
with Netflix-red #E50914 accent overrides over ElegantFin's default
Jellyseerr-blue/violet palette. ARRFLIX wordmark logo preserved on both
.adminDrawerLogo img and .pageTitleWithLogo selectors (split-rule form).

Eight accent variables overridden at :root: --uiAccentColor, --activeColor
(+Alpha), --osdSeekBarPlayedColor, --checkboxCheckedBgColor,
--highlightOutlineColor, --btnSubmitColor, --btnSubmitBorderColor.

All prior custom blocks preserved verbatim: cast/crew hide, Quick Connect
hide, header-icon hide (§3c), white slider thumbs (§3d), pure-black bg
(§3d), Settings drawer hide, count badge hide, ARRFLIX logo override.
LoginDisclaimer + SplashscreenEnabled untouched.

POST → 204; GET /Branding/Configuration confirms no Cineplex import,
ElegantFin pinned to v25.12.31, all overrides intact. Smoke test on
https://arrflix.s8n.ru/ → HTTP 302 (baseline). No container restart.

Restructured §1: Cineplex content moved to §1 'Previous themes'
subsection (#### Why Cineplex won, #### Tradeoffs, #### What it looked
like, #### Theme history) with the new ElegantFin+recolor stack as
the canonical current theme.

Snapshot tag for rollback: snapshot-2026-05-08-pre-elegantfin
2026-05-08 04:03:32 +01:00
s8n
d41aaa04fd shim: nukeSettings() drops drawer Settings link for non-admins
CSS selectors in CustomCss (a[href*=mypreferencesmenu], :has(...) wrappers)
weren't reliably hiding the entry — bundle renders it via MUI ListItemButton
+ React Router NavLink and the rendered DOM didn't match the wrapper rules.

Add nukeSettings() to the runtime shim: queries any
a[href*=mypreferencesmenu] / [to*=mypreferencesmenu], walks up to closest
li/.MuiListItem-root/[role=menuitem] and sets display:none. Wired into
start(), a new MutationObserver on document.body, and the existing 1s
setInterval. CustomCss rules left in place as belt-and-braces.

Doc: extend 10-spa-runtime-shim.md with the diagnosis, the bind-mount inode
gotcha (single-file binds + os.replace orphans the container's view), and
the nsenter-based recovery path.
2026-05-08 03:51:48 +01:00
s8n
0fa723e482 index.html: inline critical-path black bg + red button to kill pre-bundle flash 2026-05-08 03:44:24 +01:00
s8n
88296d892b doc 04 §3d: slider thumbs white + page bg pure black
Two cosmetic CSS tweaks appended to CustomCss via standard
GET-edit-POST flow (HTTP 204, all prior blocks preserved).

Thumbs: scope to .MuiSlider-thumb / .osdPositionSlider / .osdVolumeSlider
(plus legacy emby-slider .sliderThumb) -> #fff. Avoids touching
--mui-palette-primary-main so buttons/focus rings stay untinted.

Background: force --primary-background-color + --background-color and
html/body/.skinHeader/.mainAnimatedPages/#reactRoot/.dashboardDocument
to #000 so OLED + Netflix-style artwork fades read clean.

Last branding POST in this sequence.
2026-05-08 03:38:32 +01:00
s8n
004016b3cf doc 04 §3c: header icon hide (keep search, drop syncplay/cast/user)
Three top-right header icons hidden via CSS appended to existing CustomCss:
.headerSyncButton, .headerCastButton, .headerUserButton. Search button
.headerSearchButton intentionally untouched so its event handler still
fires. Selectors confirmed by grepping live JF 10.10.3 web bundle.
Branding POST returned 204; verified via GET that Cineplex @import,
cast/crew hide, ARRFLIX logo override, Quick Connect hide, Settings
drawer hide, LoginDisclaimer, and SplashscreenEnabled all preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 03:33:27 +01:00
s8n
ba4c281ce0 doc 04 §3b: triple-logo fix re-applied (sibling POST overwrote first attempt)
Branding endpoint accepts full-object POSTs only — no field-level merge,
no ETag locking. Concurrent agents writing to /System/Configuration/branding
race; last writer wins. Lock-in: branding-CSS POST must be the final POST
in any sequence touching that endpoint.
2026-05-08 03:26:19 +01:00
s8n
514dcb6ffc Branding shim: lock <title> + favicon at runtime against SPA overwrites
The static <title>ARRFLIX</title> patch wasn't enough - Jellyfin's bundle
calls document.title=... on hydrate and per-route, so the tab kept showing
'Jellyfin'. Add a self-contained inline IIFE in <head> that:

  - Replaces 'Jellyfin' with 'ARRFLIX' on the title (incl. ' - Jellyfin' suffix)
  - Pins favicon hrefs to the existing data: URL already in the page
  - Watches <head> via MutationObserver for SPA churn
  - Has a 1s setInterval safety net for late-binding navigations
  - One-shot unregisters the Jellyfin service worker so old clients reload fresh

bin/inject-shim.py is the source of truth - idempotent (replaces marker block).
docs/10-spa-runtime-shim.md covers root cause, deploy flow, SW eviction, and
how to extend the shim on Jellyfin upgrade.
2026-05-08 03:25:16 +01:00
s8n
6bf78d66e1 Restrict non-admin users + 3 imports landed
- EnableUserPreferenceAccess=false on guest + 5 (hides Display, Home,
  Playback, Subtitles pref pages — owner controls UX centrally).
- Wrapper bin/add-jellyfin-user.sh updated to bake this into all future
  non-admin user creations.
- ROADMAP entries (added by sibling import agents):
  - Imported: The Incredible Hulk (2008), TMDB 1724, 4 images
  - Imported: Idiocracy (2006), TMDB 7512 (NOT 1542 = Office Space)
  - Imported: American Dad! (2005) S01-S04, 58 eps, TMDB 1433
- WAN exposure docs added (doc 09, 256 lines): Gandi A record live,
  no-guest middleware dropped, lockout=5 baked in. Owner still must
  port-forward 80/443 on home router for actual public access.
2026-05-08 03:18:58 +01:00
s8n
84799e1bd3 Branding fixes: triple-logo overlap + Quick Connect disable + index.html override
- Logo override: removed phantom .imgLogoIcon selector + split content/
  background-image per element type (.adminDrawerLogo img uses content:,
  .pageTitleWithLogo uses background-image:). Triple-stack gone.
- Quick Connect: server-disabled via POST /System/Configuration with
  QuickConnectAvailable=false; belt-and-braces .btnQuick CSS hide.
- index.html bind-mount: title=ARRFLIX, application-name=ARRFLIX,
  apple-touch-icon + favicon set to logo data URL, .splashLogo background
  replaces Jellyfin banner with ARRFLIX wordmark. Mounted via compose
  /opt/docker/jellyfin/web-overrides/index.html → /jellyfin/jellyfin-web/.
- Doc 04 updated: §3a logo fix, §4g Quick Connect disabled.
- Compose synced from nullstone (PublishedServerUrl + Host + bind mount).
2026-05-08 03:09:25 +01:00
s8n
1f5ba31483 Rename: nasflix → ARRFLIX + apply Cineplex theme
Domain + repo rename: nasflix.s8n.ru → arrflix.s8n.ru, NASFLIX → ARRFLIX
(Forgejo repo, Pi-hole DNS, Traefik file+label routes, compose env+labels,
onyx /etc/hosts, branding LoginDisclaimer, all repo refs, logo asset).

Theme: ElegantFin → Cineplex v1.0.6 (MRunkehl, pinned). Picked by research
agent over JellyFlix (halted), DarkFlix (10.8.x only), Theme Park (no
Netflix preset). Real #E50914 + Netflix Sans webfont + transform:scale
hover + gradient login backdrop. Doc 04 updated with full candidate
matrix, theme-history subsection, rollback-to-ElegantFin snippet.

Logo asset saved at assets/logo.png (235x85 RGBA).

Live: https://arrflix.s8n.ru → 302. tv.s8n.ru + nasflix.s8n.ru retired (404).
2026-05-08 02:57:34 +01:00
s8n
cb95dce8bc Rename: tv.s8n.ru → nasflix.s8n.ru, jellyfin-stack → NASFLIX
- Domain: tv.s8n.ru retired (404). nasflix.s8n.ru live (302 → /web).
  Pi-hole local DNS updated. Traefik file-provider router rule + docker-label
  router rule both flipped. Jellyfin PublishedServerUrl env updated. Cert
  re-issued via Gandi DNS-01. Onyx /etc/hosts pin moved.
- Repo: forgejo PATCH /api/v1/repos rename. Local clone remote URL updated.
  All in-tree refs to tv.s8n.ru and jellyfin-stack swept (sed).
- Scope: TV Shows + Movies only. anime/, musicvideos/, home/, music/,
  docs-*/ libraries removed from canonical layout. Sections kept as
  reference for re-introduction.
- Branding LoginDisclaimer text updated to nasflix.s8n.ru.
2026-05-08 02:53:46 +01:00
s8n
1a6a697afd Add pre-import cleanup + filename normalization rulesets
- 07-pre-import-cleanup: 1002-line ruleset for stripping non-media junk before
  files land in /home/user/media/. Catalogs 10 categories (codec promo,
  group brag, promo images, OS thumb caches, samples, sub leftovers, torrent
  residue, proof folders, multi-disc cruft, Win executables). NFO discriminator
  uses 4096-byte head + XML-root regex (covers prologue case the brief 100-byte
  version misses). 15 auto-delete security categories (.exe/.msi/.bat/.scr/...);
  threat model = friend clicking 'Download original' then running on Win.
  Verified extras folders against Jellyfin docs (lowercase 'featurettes',
  'behind the scenes', etc.). Includes idempotent dry-run-default
  cleanup-import.sh that quarantines first, returns staging path on stdout.

- 08-filename-normalization: 1853-line normative renaming ruleset.
  Canonical: 'Show (Year) - SXXEXX - Title.ext' for TV; '<Title> (<Year>).ext'
  for movies; 'Show - NNNN - Title [Sub|Dub].ext' for absolute-numbered anime.
  Strips group tags ([YIFY]/[RARBG]/[FS99 Joy]/[GalaxyRG]), resolution
  (1080p/2160p/4K), codec (x264/x265/HEVC/10bit), source (WEB-DL/BluRay/HDTV),
  audio (DTS-HD.MA/Atmos/5.1/AAC), release-process (PROPER/REPACK/INTERNAL),
  trailing -NOGRP/-RARBG/-EVO, URL refs, basename language tokens.
  Includes stdlib-only normalize.py: dry-run default, --apply commits,
  --force overwrites, audit log to /var/log/jellyfin-imports/<date>.log,
  idempotent. Worked Futurama before/after; flags drift on live tree
  (current 'Futurama/' lacks '(1999)').
2026-05-08 02:07:11 +01:00
s8n
19382879f9 Drop home/ and music/ from canonical layout per owner
Architecture A trimmed to: movies, tv, anime, musicvideos. Removed
mkdir/compose-mount/library-creation curl for home + music. Sections 6
(Music) and the Home-videos category remain in this doc as reference for
re-introduction later.
2026-05-08 01:49:30 +01:00
s8n
e19f20eb75 Add file-structure rules + per-library theming research
- 05-file-structure-rules: 1165-line authoritative ruleset covering 11 media
  categories (movies, tv, anime, stand-up, concerts, docs, home video, extras,
  subs, artwork, NFO). Architecture A flat layout chosen at
  /home/user/media/{movies,tv,anime,musicvideos,music,home}. Top 3 gotchas
  surfaced: no-per-item-folder breaks extras/NFO; year must be in parens;
  anime absolute numbering past 99 needs Shoko or split-by-TVDB-season.

- 06-per-library-themes: 319-line research memo. Verdict: partially feasible.
  No native per-library theming; CustomCss is global, Jellyfin web sets no
  body class for libraryId/collectionType. Recommended approach: JS Injector
  plugin (n00bcodr fork, MIT, last release 2025-12-08) + ~30-line shim that
  mirrors topParentId/collectionType from URL hash to body class, plus three
  scoped CSS blocks (body.lib-movies, body.lib-anime, body.lib-music).
  Reaches 'tinted, branded, recognisable' — not pixel-perfect. Pixel-perfect
  fidelity needs subdomain split (3 instances) at ~100x maintenance.
2026-05-08 01:46:38 +01:00
s8n
f7c872d687 Add operations playbooks: artwork, metadata, subtitles, theming/users
Four research-grade docs covering everything four parallel agents found while
fixing the live Futurama deploy:

- 01-artwork-and-images: root-cause of missing posters (EnableInternetProviders=false
  + wrong fetcher names 'The Movie Database' vs 'TheMovieDb' in 10.10.x). Fixed
  in-place. Doc covers image-type matrix, scraper-to-imagetype map, refresh API.
- 02-metadata-and-titles: Futurama series had empty ProviderIds; locked to
  TMDB 615 (1999 original, not 2023 reboot). All 44 eps now have proper titles +
  Polish overviews. Doc covers filename regex, Identify flow, language cascade.
- 03-subtitles: installed OpenSubtitles plugin v20.0.0.0 (v21+ needs JF 10.11
  ABI). User must add opensubtitles.com creds. Doc covers sidecar naming,
  embedded extraction, per-user prefs.
- 04-theming-and-users: applied ElegantFin v25.12.31 via Branding API. Doc covers
  theme rationale, multi-user policy template, SyncPlay, friend playbook.
2026-05-08 01:13:42 +01:00