Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
317 commits
Select commit Hold shift + click to select a range
53a3d4b
i18n: add latency-aware service status labels (en/fr)
ndandan Jun 16, 2026
ffcb7a5
feat(dashboard): render service status word + latency in health chips
ndandan Jun 16, 2026
fc75ae2
style(dashboard): add five-state dot colors for health chips
ndandan Jun 16, 2026
c12364c
docs: changelog for latency-aware service health chips
ndandan Jun 16, 2026
8c483a3
refactor(health): clarify status cache key, add cache-hit test
ndandan Jun 16, 2026
7e304a1
Merge branch 'feat/service-health-latency': latency-aware service hea…
ndandan Jun 16, 2026
b392690
docs: record latency-aware service health widget in fork changes
ndandan Jun 16, 2026
33394e8
docs: design spec for Tautulli activity page enhancements
ndandan Jun 16, 2026
e5ac4c8
docs: implementation plan for Tautulli activity page enhancements
ndandan Jun 16, 2026
8ede583
feat(tautulli): show stream-summary strip on the activity page
ndandan Jun 16, 2026
3c4333c
feat(tautulli): add getRecentlyAdded client method + normalizer
ndandan Jun 16, 2026
526f738
test(tautulli): assert recently-added normalizer drops added_at
ndandan Jun 16, 2026
1c4b789
feat(tautulli): add recently-added fragment endpoint + template
ndandan Jun 16, 2026
a71d479
feat(tautulli): wire Recently Added section into the activity page
ndandan Jun 16, 2026
7b5da77
style(tautulli): drop redundant plex-sessions class on recently-added…
ndandan Jun 16, 2026
d266a01
feat(tautulli): expose dynamic-range + codec fields on sessions
ndandan Jun 16, 2026
56477de
test(tautulli): cover dynamic-range source fallback + ip_address_public
ndandan Jun 16, 2026
8632d61
feat(tautulli): add HDR/SDR badge + codec-transition transcode detail
ndandan Jun 16, 2026
ff5ce84
docs: changelog + fork-changes for Tautulli activity enhancements
ndandan Jun 16, 2026
0564345
refactor(tautulli): drop dead icon import + add recently-added smoke …
ndandan Jun 16, 2026
5a6cc9c
docs: design spec for Tautulli activity page v2 (declutter + graphs)
ndandan Jun 16, 2026
e41b19e
docs: implementation plan for Tautulli activity page v2
ndandan Jun 16, 2026
b604c22
revert(tautulli): remove Recently Added section
ndandan Jun 16, 2026
c72e7e0
style(tautulli): collapse stray blank lines from Recently Added removal
ndandan Jun 16, 2026
e9ebf49
feat(tautulli): add stream-type/hour/dow/platform chart feeds; drop T…
ndandan Jun 16, 2026
92e35ab
docs(tautulli): generalize normalizePlaysByDate docblock; cover getPl…
ndandan Jun 16, 2026
ff6864a
feat(tautulli): add stream-type/activity/clients chart endpoints
ndandan Jun 16, 2026
7499284
feat(tautulli): dense History grid + slim Libraries list
ndandan Jun 16, 2026
3475e8c
feat(tautulli): Media/Stream plays toggle + activity & problem-client…
ndandan Jun 16, 2026
04f005c
docs: changelog + fork-changes for Tautulli page v2
ndandan Jun 16, 2026
b149b6d
chore: stop tracking internal docs/superpowers specs + plans
ndandan Jun 17, 2026
d79f539
docs: correct FORK-CHANGES scope stats vs upstream
ndandan Jun 17, 2026
fd61910
docs: add measured library-page perf numbers to fork-changes
ndandan Jun 17, 2026
0507d50
docs: document the Plex Activity page (Tautulli) in the README
ndandan Jun 17, 2026
d7f734a
ci: run Docker Hub README sync only on the upstream repo
ndandan Jun 17, 2026
eaed24a
feat(dashboard): library quick-look view-model + body partial
ndandan Jun 18, 2026
7396ac3
fix(dashboard): provide router in quick-look tests; use runtime i18n key
ndandan Jun 18, 2026
148e5b5
feat(dashboard): TMDb quick-look view-model builder
ndandan Jun 18, 2026
f29af41
fix(dashboard): render 0-season TMDb shows in quick-look metaLine
ndandan Jun 18, 2026
3ebe446
feat(dashboard): quick-look fragment endpoints + i18n keys
ndandan Jun 18, 2026
ade1238
feat(dashboard): tag tile data with slug + hero quick-look fields
ndandan Jun 18, 2026
29cc32c
feat(dashboard): emit data-ql-* on all media tiles
ndandan Jun 18, 2026
0a61619
feat(dashboard): quick-look modal shell, styles, and JS wiring
ndandan Jun 18, 2026
319ee70
docs(dashboard): correct quickLookTmdbAction docblock
ndandan Jun 18, 2026
069ea18
docs: document dashboard in-place quick-look (README, CHANGELOG, FORK…
ndandan Jun 19, 2026
6ab8101
feat(tautulli): home-stats normalizer gains duration, popular & concu…
ndandan Jun 22, 2026
9978b11
test(tautulli): guard popular_movies file path in home-stats privacy …
ndandan Jun 22, 2026
7a08211
feat(tautulli): stats tiles gain metric toggle, Most Popular & Most C…
ndandan Jun 22, 2026
f665d8a
test(tautulli): assert stats endpoint renders empty-state fragment shape
ndandan Jun 22, 2026
763e460
feat(tautulli): add users-table & user-names normalizers (privacy-safe)
ndandan Jun 22, 2026
515c952
test(tautulli): assert second users-table row + user_thumb key absence
ndandan Jun 22, 2026
db6ae1c
feat(tautulli): users overview endpoints + fragment
ndandan Jun 22, 2026
1740461
feat(tautulli): metric/user-aware charts + resolution, user-stream-ty…
ndandan Jun 22, 2026
8d9b400
test(tautulli): exercise metric/user (incl. invalid) on chart endpoints
ndandan Jun 22, 2026
a6a0660
feat(tautulli): page toolbar (metric + user filter), new graphs & use…
ndandan Jun 22, 2026
be69aef
feat(tautulli): scope history fragment by the per-user filter
ndandan Jun 22, 2026
392bc6b
i18n(tautulli): keys for metric toggle, user filter, new graphs & use…
ndandan Jun 22, 2026
f32822f
docs(readme): document Plex Activity stats, graphs, per-user filter &…
ndandan Jun 23, 2026
38610aa
feat(themes): add ColorMath HSL→RGB/hex helper
ndandan Jun 25, 2026
8449875
feat(themes): add curated HSL theme presets
ndandan Jun 25, 2026
c12c80c
feat(themes): resolve presets to CSS variables in ThemeService
ndandan Jun 25, 2026
4d72700
feat(themes): register display_theme setting, theme() Twig fn, accent…
ndandan Jun 25, 2026
437acca
feat(themes): apply resolved theme in base layout, drop light/dark to…
ndandan Jun 25, 2026
3c41f16
fix(themes): reproduce midnight sidebar/footer surface tiers (visual …
ndandan Jun 25, 2026
70897b1
fix(themes): theme-track the sticky topbar background
ndandan Jun 25, 2026
9a0f4cc
fix(themes): full reload on theme change so colours apply without man…
ndandan Jun 25, 2026
26d727e
feat(themes): expand presets to the full glance catalog (17 themes)
ndandan Jun 25, 2026
affdd77
Merge feat/dashboard-themes: glance-style theming system
ndandan Jun 25, 2026
9541d97
Merge remote-tracking branch 'upstream/main'
ndandan Jun 26, 2026
1d15a24
feat(dashboard): add DashboardSections registry
ndandan Jun 26, 2026
94b1cc9
feat(dashboard): add DashboardLayoutService order/visibility resolver
ndandan Jun 26, 2026
c62d9b6
test(dashboard): make DashboardLayoutService cache test verify the in…
ndandan Jun 26, 2026
8572339
refactor(dashboard): render sections from DashboardLayoutService order
ndandan Jun 26, 2026
23080b9
feat(dashboard): admin settings card to reorder + hide dashboard sect…
ndandan Jun 26, 2026
b3f7e97
fix(dashboard): restore final on DashboardLayoutService; use real ins…
ndandan Jun 26, 2026
be8ae49
feat(dashboard): admin endpoint to persist layout from edit mode
ndandan Jun 26, 2026
622ba97
test(dashboard): assert layout endpoint JSON body and config invalida…
ndandan Jun 26, 2026
f07d569
feat(dashboard): on-dashboard drag-to-reorder + hide edit mode
ndandan Jun 26, 2026
8c43ada
fix(dashboard): guard edit-mode init against double-binding; drop dea…
ndandan Jun 26, 2026
47be773
ci(ghcr): publish :beta on manual dispatch from a non-main branch
ndandan Jun 26, 2026
db58c6d
fix(dashboard): no edit-mode affordances on empty/gated-out sections
ndandan Jun 26, 2026
7802d91
test(dashboard): update DashboardControllerTest for new constructor arg
ndandan Jun 26, 2026
1231c46
feat(quicklook): movie theater/digital/physical release dates in view…
ndandan Jun 26, 2026
50585f2
feat(quicklook): series air status + first/next/ended dates in view m…
ndandan Jun 26, 2026
3f439a5
test(quicklook): cover ended-series air status + end date
ndandan Jun 26, 2026
0172cb5
feat(quicklook): render release-date block + EN/FR labels
ndandan Jun 26, 2026
20019be
refactor(quicklook): make the quick-look modal app-global via shared …
ndandan Jun 26, 2026
84f6601
feat(search): open rich detail modal on result click with release dat…
ndandan Jun 27, 2026
a3134f3
fix(search): expose manage i18n key + quick-add fallback for tmdb-les…
ndandan Jun 27, 2026
985c79f
style(quicklook): styling for release-date chips + upcoming/air-statu…
ndandan Jun 27, 2026
611633c
style(quicklook): vertically center the air-status pill text
ndandan Jun 27, 2026
1b94d25
Merge: rich search-result detail modal with release/air dates
ndandan Jun 27, 2026
e917cd4
feat(quicklook): enrich modal with cast, providers, trailer, links + …
ndandan Jun 27, 2026
f6e5e1c
feat(quicklook): unify the Explorer modal into the global quick-look
ndandan Jun 27, 2026
0d48e1c
fix(search): stop icon overlapping text in compact density
ndandan Jun 28, 2026
1896c91
feat(unraid): add UnraidClient for the Unraid 7 GraphQL API
ndandan Jul 1, 2026
6ff4346
feat(unraid): register Unraid in HealthService (ping, kill switch, te…
ndandan Jul 1, 2026
447e02a
feat(unraid): register the admin-only server section in the dashboard…
ndandan Jul 1, 2026
4e57797
feat(unraid): admin-only server section widget on the dashboard
ndandan Jul 1, 2026
af52ce8
feat(unraid): admin settings card (URL, API key, TLS skip, kill switc…
ndandan Jul 2, 2026
70ecb51
fix(unraid): live-test polish — UPS runtime seconds→minutes, relative…
ndandan Jul 2, 2026
b3dc7c0
Merge: Unraid server monitoring widget on the dashboard
ndandan Jul 2, 2026
9039866
feat(unraid): fail fast on a dead host + neutral badge for a stopped …
ndandan Jul 2, 2026
0be0c18
fix(settings): drop duplicate tautulli FIELDS block
ndandan Jul 2, 2026
d2708b5
Merge: Unraid widget polish (dead-host fail-fast, stopped-array badge…
ndandan Jul 2, 2026
27f0959
feat(unraid): expose full docker container list (name + running), sorted
ndandan Jul 2, 2026
3ea4fbc
feat(unraid): parity group — live check progress (vars) + last-check …
ndandan Jul 2, 2026
1aa3c4b
feat(server-widget): parity tile + full-width docker container chip row
ndandan Jul 2, 2026
aa0d96e
feat(health): shared chips() builder — colors, sab/nzbget, admin-gate…
ndandan Jul 2, 2026
b2f8aa0
refactor(dashboard): health section renders from shared HealthService…
ndandan Jul 2, 2026
fc871eb
style(tests): restore method indentation lost in test removal
ndandan Jul 2, 2026
58eb991
feat(health-api): chips payload mirroring the dashboard list, unraid …
ndandan Jul 2, 2026
d3a9d81
feat(topbar): health popover mirrors the dashboard chip list
ndandan Jul 2, 2026
51e000c
fix(unraid): parity progress on large arrays — overflow-safe denominator
ndandan Jul 3, 2026
73373d4
Merge: Server widget v2 — parity tile, docker chip row, unified healt…
ndandan Jul 3, 2026
8957054
feat(unraid): parity ETA from live throughput (mdResyncDb/mdResyncDt)
ndandan Jul 3, 2026
dc0c290
Merge: parity ETA from live throughput
ndandan Jul 3, 2026
3b0047e
perf(health): cache service-status verdicts across requests
ndandan Jul 3, 2026
fbba482
perf(assets): browser cache headers for hashed and static assets
ndandan Jul 3, 2026
46ea6b1
perf(docker): warm the prod cache at image build
ndandan Jul 3, 2026
fead625
docs(changelog): record the cross-request health cache, asset cache h…
ndandan Jul 3, 2026
95303da
feat(tautulli): open Plex items in the app-global quick-look modal
ndandan Jul 3, 2026
bc05653
Merge: cross-request health cache, asset cache headers, build-time wa…
ndandan Jul 3, 2026
1f80af8
Merge: Plex items open the app-global quick-look modal
ndandan Jul 3, 2026
2072d43
fix(unraid): synthesize parity last-check from vars.sbSynced2 when hi…
ndandan Jul 4, 2026
efe4d39
Merge: parity last-check falls back to vars.sbSynced2 when history lags
ndandan Jul 4, 2026
3ee94c9
feat(houndarr): client skeleton + widget payload normalization
ndandan Jul 4, 2026
352256e
feat(houndarr): widget fetch with TTL cache, auth mapping, ping
ndandan Jul 4, 2026
74c009c
feat(houndarr): health chip, ping, kill switch, test-connection probe
ndandan Jul 4, 2026
4d558c1
feat(houndarr): admin settings card with kill switch and test button
ndandan Jul 4, 2026
dbc91b9
feat(houndarr): dashboard stat section with async hydration + 60s ref…
ndandan Jul 4, 2026
75f030b
docs: changelog for Houndarr widget
ndandan Jul 4, 2026
b72bc9f
feat(houndarr): widget v2 — library-health bar + per-instance *arr wa…
ndandan Jul 4, 2026
9f93b68
Merge: Houndarr dashboard widget (stat tiles, library-health bar, per…
ndandan Jul 4, 2026
ada0e6c
docs: rewrite README + FORK-CHANGES to reflect the fork
ndandan Jul 5, 2026
00e2d2a
feat(deluge): JSON-RPC client plumbing (auth, transport, circuit brea…
ndandan Jul 5, 2026
5fb9e86
feat(deluge): torrent read side — normalization, list, detail, stats,…
ndandan Jul 5, 2026
fbcb6e4
feat(deluge): actions, add-torrent, per-torrent + global speed limits
ndandan Jul 5, 2026
e34d3f2
feat(deluge): controller — page, list/detail API, actions, add, limits
ndandan Jul 5, 2026
5c08a89
feat(deluge): torrent page template (trimmed qBit UI, labels + seedin…
ndandan Jul 6, 2026
3685f8d
fix(deluge): pause/resume-all via session RPCs, title key, seeds sort
ndandan Jul 6, 2026
2b987ff
feat(deluge): wiring — sidebar+poll, route guard, health, setup wizar…
ndandan Jul 6, 2026
08e3482
fix(deluge): final-review — escape tracker status, detail fields, fil…
ndandan Jul 6, 2026
265fb70
docs(deluge): changelog
ndandan Jul 6, 2026
c9b4c2d
fix(deluge): register service card in admin settings template (meta, …
ndandan Jul 6, 2026
24ec0c9
Merge: Deluge tab (full torrent management via deluge-web JSON-RPC)
ndandan Jul 6, 2026
50661ee
docs: refresh screenshots (new capture set incl. Deluge, Sonarr, Requ…
ndandan Jul 6, 2026
07d37e2
feat(unifi): UnifiClient — classic Network API client (health, 24h us…
ndandan Jul 7, 2026
cff8a15
test(unifi): drop kill-switch assertion that exercised the test mock,…
ndandan Jul 7, 2026
8fdbc09
feat(unifi): NetworkUsageChart — pure SVG geometry for the 24h usage …
ndandan Jul 7, 2026
e002fd8
feat(unifi): health integration — probe, admin-gated chip, kill switc…
ndandan Jul 7, 2026
47b3174
fix(unifi): include unifi in HealthService invalidate() per-service c…
ndandan Jul 7, 2026
d6d3ad8
feat(unifi): admin settings card — fields, kill switch, test button, …
ndandan Jul 7, 2026
acaddcd
feat(unifi): network dashboard section — registry entry, admin-gated …
ndandan Jul 7, 2026
a2b45ac
feat(unifi): network widget templates — stat tiles, inline-SVG 24h ch…
ndandan Jul 7, 2026
6c29714
fix(unifi): clear network poller timer on turbo:before-render like si…
ndandan Jul 7, 2026
003eeac
docs(unifi): changelog + fork-changes for the Network dashboard widget
ndandan Jul 7, 2026
e227856
fix(unifi): final-review fixes — FORK-CHANGES accuracy rewrite, chart…
ndandan Jul 7, 2026
3b3767e
fix(unifi): pin upload chart series to sky blue — indistinguishable f…
ndandan Jul 7, 2026
cdb97be
Merge: UniFi Network dashboard widget (WAN, clients, 24h usage, infra…
ndandan Jul 7, 2026
456cf1a
refactor(setup): stepper and test-result dots to Tabler steps/status …
ndandan Jul 10, 2026
7bb722d
fix(setup): neutralize Tabler doc-steps border-left bleeding into the…
ndandan Jul 10, 2026
9b672bd
refactor(setup): buttons, card, badges and actions bar to stock Table…
ndandan Jul 10, 2026
6935fe4
refactor(setup): forms, secret toggles, typography and sections to Ta…
ndandan Jul 10, 2026
968da85
Merge: setup wizard consolidated onto Tabler primitives (steps/status…
ndandan Jul 10, 2026
d702516
docs: changelog + fork-changes entries for the setup-wizard Tabler co…
ndandan Jul 10, 2026
92d5488
refactor(ui): single shared secret_input macro for all password-revea…
ndandan Jul 10, 2026
ea1e953
fix(setup): render the pending test label via textContent like the re…
ndandan Jul 10, 2026
74c6045
Merge: wizard-ship housekeeping — docs, shared secret_input macro (9 …
ndandan Jul 10, 2026
d6f40f5
refactor(ui): empty states to stock Tabler .empty component
ndandan Jul 10, 2026
bda8561
refactor(ui): system status key/value blocks to Tabler .datagrid
ndandan Jul 10, 2026
7a6e3f7
fix(responsive): shared mobile pass — inline-badge type floor, coarse…
ndandan Jul 10, 2026
8de0f84
fix(responsive): dashboard mobile pass — type floor, tablet 2-col sec…
ndandan Jul 10, 2026
4077f5d
fix(responsive): Discover — touch-visible card actions and type floor
ndandan Jul 10, 2026
2a8cf66
fix(responsive): floor sub-12px text on library, calendar and quick-look
ndandan Jul 10, 2026
b71a517
fix(responsive): revert tablet 2-col dashboard — lone half-width sect…
ndandan Jul 10, 2026
4eb3608
Merge: Tabler round 2 (.empty/.datagrid) + mobile/tablet responsive f…
ndandan Jul 10, 2026
13817d4
perf(opcache): preload framework + app class graph at boot
ndandan Jul 10, 2026
be98458
Merge: OPcache preload of framework + app class graph (perf)
ndandan Jul 10, 2026
bf00add
fix(settings): pack External Services cards with CSS multi-column
ndandan Jul 10, 2026
1b0fd5a
feat(mobile): offcanvas filter drawer for library pages
ndandan Jul 10, 2026
94aeffd
fix(mobile): open Discover filter drawer without the bootstrap global
ndandan Jul 10, 2026
1386ba9
Merge: settings card packing + offcanvas mobile filters
ndandan Jul 10, 2026
b2c6c71
perf(worker): opt-in FrankenPHP/Symfony worker mode (PRISMARR_WORKER)
ndandan Jul 10, 2026
d83a54c
fix(worker): accept PRISMARR_WORKER as an on/off flag OR a worker count
ndandan Jul 10, 2026
dad0cb3
chore(worker): log worker-mode decision at boot for observability
ndandan Jul 10, 2026
fe5a1c1
Merge: opt-in FrankenPHP/Symfony worker mode (perf)
ndandan Jul 10, 2026
9b00d55
docs(readme): highlight worker-mode perf, add PR #70, clarify worker …
ndandan Jul 11, 2026
c646349
fix(dashboard): visible retryable error state when a widget fragment …
ndandan Jul 11, 2026
e2f1d93
fix(dashboard): use the correct common.action.retry key on the widget…
ndandan Jul 11, 2026
1064a50
ui: P2 design-critique sweep — earned semantic hues, desktop text flo…
ndandan Jul 11, 2026
65ff8fb
fix(prowlarr): hide the ADDED column below the real table fit point (…
ndandan Jul 11, 2026
1a1322d
ui: polish batch from critique re-run — calendar legibility, localiza…
ndandan Jul 11, 2026
7f4107f
fix(media): route the async films-warnings endpoint through warning_f…
ndandan Jul 11, 2026
d9d56e2
Merge: design-critique round — widget failure states, P2 sweep, polis…
ndandan Jul 11, 2026
f1718f5
ui: calendar in-place quick-look + legend-true episode colors, retire…
ndandan Jul 11, 2026
f49cc7c
ui: fix light-preset readability — tokenize hardcoded dark literals (#1)
ndandan Jul 11, 2026
50f672c
a11y: make clickable card DIVs keyboard-operable (#5)
ndandan Jul 11, 2026
d07aa16
ui: Tabler round 3 — avatar-list of Plex viewers + "New" card ribbon
ndandan Jul 11, 2026
5072a73
ui: P3 polish — season plural, logo honors home pref, theme/accent he…
ndandan Jul 11, 2026
e2d23fb
tmdb: drive release/cert/provider region priority from locale, not FR…
ndandan Jul 12, 2026
cff7737
ui(#6 slice A): unify download-client view-switchers into one partial
ndandan Jul 12, 2026
a043140
ui(#6 slice B): shared stat-tile vocabulary + partial
ndandan Jul 12, 2026
d03fe63
ui(#6 slice C): unify filter pills into one .filter-pill vocabulary
ndandan Jul 12, 2026
5e62504
Merge: design-critique round 2 — light-preset fix, calendar quick-loo…
ndandan Jul 12, 2026
5473381
perf(dashboard): coalesce five widget pollers into one scheduler + en…
ndandan Jul 12, 2026
646fcc5
Merge: dashboard poller consolidation — one coalescing scheduler + co…
ndandan Jul 12, 2026
e850556
docs: bring README, CHANGELOG and FORK-CHANGES current
ndandan Jul 12, 2026
49d85bc
feat(library): shared filter-memory module + global load
ndandan Jul 13, 2026
a9faff1
feat(films): persist last-used filters per instance
ndandan Jul 13, 2026
03bd40b
feat(series): persist last-used filters per instance
ndandan Jul 13, 2026
49a275a
fix(library): drive filter memory from head-loaded module + DOM marker
ndandan Jul 13, 2026
7f639f6
perf(library): defer the filter-memory script to unblock head render
ndandan Jul 13, 2026
fb33535
Merge: persistent per-tab library filters (films & series)
ndandan Jul 13, 2026
24c6e77
fix(library): widen heavy library-fetch timeout to 30s (issue #41)
ndandan Jul 14, 2026
4d84db8
fix(qbittorrent): guard against stale pagination responses
jeromelefeuvre Jul 23, 2026
eca7a01
feat(unifi): add UnifiFetcher transport seam to UnifiClient
ndandan Jul 25, 2026
59c1172
feat(unifi): let NetworkUsageChart take an axis-label format
ndandan Jul 25, 2026
865e2b7
feat(unifi): add SpeedtestChart geometry helper
ndandan Jul 25, 2026
edb40bf
feat(unifi): add UnifiHistoryReader (7-day usage, speedtest archive)
ndandan Jul 25, 2026
821671b
feat(unifi): add UnifiInfraReader (devices, radios, neighbors, networks)
ndandan Jul 25, 2026
4124b3c
feat(unifi): add UnifiLiveReader (tiles, wireless, talkers, reservati…
ndandan Jul 25, 2026
6e0a11e
feat(unifi): add UnifiController, sidebar entry and route guard
ndandan Jul 25, 2026
3e410da
feat(unifi): add the Network tab history panel
ndandan Jul 25, 2026
3174067
feat(unifi): add the Network tab infrastructure panel
ndandan Jul 25, 2026
d1b4937
feat(unifi): add the Network tab live panel
ndandan Jul 25, 2026
dd36bd4
feat(unifi): add the Network tab shell and coalescing poller
ndandan Jul 25, 2026
99009ee
feat(unifi): link the dashboard widget to the Network tab
ndandan Jul 25, 2026
0e69e4f
refactor(unifi): densify the infrastructure and RF panels
ndandan Jul 25, 2026
760b250
refactor(unifi): page-scoped chart CSS, fix the mobile text floor
ndandan Jul 25, 2026
6e5f8f3
fix(unifi): three defects found in live review
ndandan Jul 25, 2026
a7daffe
Merge: UniFi Network tab (/unifi)
ndandan Jul 25, 2026
48d30f3
Merge: guard qBittorrent pagination against stale poll responses (#17)
ndandan Jul 25, 2026
7b7b810
feat(transmission): add Transmission torrent client integration
jeromelefeuvre Jul 23, 2026
0764b92
fix(setup): restore the qBittorrent wizard prefill defaults
ndandan Jul 25, 2026
b26b27b
test(transmission): pin the registration points against silent drops
ndandan Jul 25, 2026
68b53c9
test(transmission): assert route parity with Deluge
ndandan Jul 25, 2026
1158ba2
refactor(transmission): rebuild the page template on the Deluge base
ndandan Jul 25, 2026
24b78b5
fix(transmission): request rateDownload/rateUpload for the detail panel
ndandan Jul 25, 2026
687470a
test(transmission): render the index template in CI
ndandan Jul 25, 2026
47b14ca
chore(transmission): reuse the qbittorrent.* keys, drop 193 orphaned …
ndandan Jul 25, 2026
d3dd54b
fix(transmission): title the page Transmission, correct the refresh h…
ndandan Jul 25, 2026
79e8ce3
Merge: Transmission integration (#18, reworked)
ndandan Jul 26, 2026
bebb65e
fix(torrents): share the poll timer handle across the three client pages
ndandan Jul 26, 2026
1ed4daa
docs: record the torrent poller fix, and backfill Transmission
ndandan Jul 26, 2026
b5ea6b2
Merge: fix cross-page torrent poller leak (qBittorrent / Deluge / Tra…
ndandan Jul 26, 2026
4db91d7
docs: cover the UniFi Network tab and the qBittorrent pagination guard
ndandan Jul 26, 2026
fd09b50
Merge: document the UniFi Network tab and the qBittorrent pagination …
ndandan Jul 26, 2026
bd6911f
fix(media): collapse the download queue widget by default on Radarr/S…
jeromelefeuvre Jul 29, 2026
4a8837e
Merge branch 'main' into feature/collapsed-downloads-widget
jeromelefeuvre Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Container control files are read inside a Linux image. A CRLF here makes
# s6-rc-compile reject the service ("type must be oneshot, longrun, or bundle")
# and breaks shell shebang parsing, so a `docker build` from a Windows checkout
# (core.autocrlf=true) produces an unbootable image. Pin them to LF regardless
# of the contributor's git settings.
docker/** text eol=lf
*.sh text eol=lf
78 changes: 78 additions & 0 deletions .github/workflows/ghcr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: GHCR

# Build the FrankenPHP image and publish it to the GitHub Container Registry
# (ghcr.io/<owner>/prismarr) for self-hosted testing — e.g. on Unraid. Uses
# the built-in GITHUB_TOKEN, so no external registry credentials are needed
# (unlike the Docker Hub release/beta workflows).
#
# amd64 only: Unraid is x86_64 and a single-arch build keeps this fast. Add
# linux/arm64 back to `platforms` (with setup-qemu-action) if you need it.
#
# After the first successful run the package is created PRIVATE — make it
# public once at:
# https://github.com/users/<owner>/packages/container/prismarr/settings
# so Unraid can pull ghcr.io/<owner>/prismarr:latest without a login.

on:
workflow_dispatch:
push:
branches: [main]

jobs:
publish:
name: Build and push to GHCR (amd64)
runs-on: ubuntu-latest
timeout-minutes: 60

permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v5

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Resolve lowercase image name
id: image
# GHCR requires the namespace to be lowercase.
run: echo "name=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')/prismarr" >> "$GITHUB_OUTPUT"

- name: Resolve tags + version
id: meta
# A manual dispatch from a NON-main branch publishes only the :beta tag
# for self-hosted testing (e.g. Unraid), leaving the stable :latest
# untouched. Pushes to main (or a dispatch on main) keep publishing
# :latest + the commit-sha tag as before.
run: |
IMG="${{ steps.image.outputs.name }}"
if [ "${{ github.ref_name }}" = "main" ]; then
echo "tags=${IMG}:latest,${IMG}:${{ github.sha }}" >> "$GITHUB_OUTPUT"
echo "version=1.1.0-tautulli" >> "$GITHUB_OUTPUT"
else
echo "tags=${IMG}:beta" >> "$GITHUB_OUTPUT"
echo "version=beta-${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi

- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v7
with:
context: .
file: docker/frankenphp/Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
PRISMARR_VERSION=${{ steps.meta.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Brainstorming companion scratch (superpowers visual companion)
.superpowers/

# Symfony
symfony/vendor/
symfony/var/
Expand Down Expand Up @@ -37,3 +40,8 @@ CLAUDE.md
AGENTS.md
REDDIT_POST.md
REDDIT_POSTS.md
# Superpowers brainstorming specs + implementation plans (internal scaffolding)
docs/superpowers/

# Local screenshots dropped in the repo root (not part of the project)
/*.png
26 changes: 26 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

380 changes: 209 additions & 171 deletions README.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions docker-compose.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ services:
# itself. Setting it drops X-Frame-Options. (Issue #25.)
# PRISMARR_FRAME_ANCESTORS: https://organizr.example.com

# FrankenPHP/Symfony worker mode (opt-in, OFF by default). Set to 1 to
# keep the Symfony kernel resident across requests (skips the per-request
# bootstrap for faster responses). Toggling needs no image rebuild. Leave
# unset for the classic per-request mode.
# PRISMARR_WORKER: 1
# Optional worker/thread count when PRISMARR_WORKER=1 (default: 2x CPU).
# PRISMARR_WORKER_NUM: 4

# Persistent volume — contains SQLite DB, .env.local, sessions, cache.
volumes:
- prismarr_data:/var/www/html/var/data
Expand Down
26 changes: 25 additions & 1 deletion docker/frankenphp/Caddyfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
{
frankenphp
# Worker mode is opt-in and OFF by default. The s6 run script exports
# PRISMARR_WORKER_DIRECTIVE=`worker /var/www/html/public/index.php [num]`
# only when PRISMARR_WORKER=1; otherwise this placeholder expands to
# nothing and the block is empty — i.e. classic single-request mode,
# byte-for-byte the old `frankenphp` behaviour. In worker mode the global
# `worker` directive keeps the Symfony kernel resident and `php_server`
# below automatically routes matching requests through it. Symfony 8's
# default runtime (symfony/runtime FrankenPhpWorkerRunner) enters the
# worker loop when FrankenPHP sets FRANKENPHP_WORKER, so no APP_RUNTIME or
# extra composer package is required.
frankenphp {
{$PRISMARR_WORKER_DIRECTIVE}
}
order mercure after encode

# No HTTPS (local or behind a reverse proxy)
Expand Down Expand Up @@ -43,6 +55,18 @@
# Compression
encode zstd gzip

# Browser caching for static assets.
# /assets/* are AssetMapper-compiled files with a content digest in the
# filename — safe to cache forever (a new build = a new URL).
# /static/* (vendored Tabler/Chart.js) and /img/* are NOT fingerprinted:
# one day keeps them out of the request log without pinning a stale UI
# past an image upgrade (Caddy's ETag revalidates them after expiry).
@hashed_assets path /assets/*
header @hashed_assets Cache-Control "public, max-age=31536000, immutable"

@static_assets path /static/* /img/* /favicon.ico
header @static_assets Cache-Control "public, max-age=86400"

# Mercure hub (real-time SSE).
# Bolt DB stored in var/data (volume) so www-data can write to it.
# cors_origins is exposed via env so public deployments can restrict
Expand Down
6 changes: 6 additions & 0 deletions docker/frankenphp/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ COPY symfony/ .
RUN composer install --no-dev --optimize-autoloader --no-scripts --no-interaction \
&& php bin/console importmap:install --no-interaction \
&& php bin/console asset-map:compile --no-interaction \
# Warm the prod cache (compiled container, routes, twig, serializer) at
# build time — without this the first request after every container
# (re)start pays the 1-3 s compile. Env vars stay runtime-resolved
# placeholders in the compiled container, so the boot-generated
# APP_SECRET / user DATABASE_URL don't invalidate the warmed cache.
&& php bin/console cache:warmup --no-interaction \
&& apk del --purge .build-deps

# Permissions
Expand Down
10 changes: 10 additions & 0 deletions docker/frankenphp/php.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 0
opcache.validate_timestamps = 0

; Preload the framework + app class graph into shared memory at boot, so no
; request pays to link them. Symfony emits config/preload.php (which requires
; the compiled var/cache/prod/*.preload.php) during the cache:warmup already
; run at image build, so the referenced files exist in the image. Since the
; code is baked and validate_timestamps=0, the preloaded graph is stable for
; the container's lifetime. preload_user is required when PHP starts as root
; (s6 runs the init as root, then drops to www-data for the server).
opcache.preload = /var/www/html/config/preload.php
opcache.preload_user = www-data

; Realpath cache (Symfony perf)
realpath_cache_size = 4096K
realpath_cache_ttl = 600
Expand Down
41 changes: 41 additions & 0 deletions docker/frankenphp/s6/frankenphp/run
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,46 @@ fi
# Caddy needs a writable HOME for its internal data store (XDG paths).
# var/caddy is created and chowned by init.sh.
export HOME=/var/www/html/var/caddy

# ── FrankenPHP worker mode (opt-in, default OFF) ────────────────────────
# Worker mode boots the Symfony kernel once and keeps it resident, so requests
# skip the per-request kernel bootstrap. Controlled by PRISMARR_WORKER:
# unset / "" / 0 / false / no / off → OFF (classic per-request mode)
# 1 (or true / yes / on) → ON, FrankenPHP's default count (2x CPU)
# a positive integer N (e.g. 4) → ON, with N resident workers
# PRISMARR_WORKER_NUM, if set, overrides the count in every case. The directive
# is injected into the global `frankenphp { }` block via the
# {$PRISMARR_WORKER_DIRECTIVE} Caddyfile placeholder; an unset/OFF value leaves
# it empty — byte-for-byte the classic path. Symfony 8's default runtime
# auto-detects FrankenPHP's worker loop (FRANKENPHP_WORKER) — no APP_RUNTIME /
# extra package needed.
case "${PRISMARR_WORKER:-}" in
''|0|false|False|FALSE|no|No|NO|off|Off|OFF)
: ;; # classic — leave the directive empty
*)
_pw_num="${PRISMARR_WORKER_NUM:-}"
# No explicit count and PRISMARR_WORKER is a plain integer >1 → use it as
# the worker count (so PRISMARR_WORKER=4 means "4 workers").
case "${PRISMARR_WORKER}" in
''|*[!0-9]*) : ;; # not a pure integer
*) [ -z "${_pw_num}" ] && [ "${PRISMARR_WORKER}" -gt 1 ] && _pw_num="${PRISMARR_WORKER}" ;;
esac
if [ -n "${_pw_num}" ]; then
export PRISMARR_WORKER_DIRECTIVE="worker /var/www/html/public/index.php ${_pw_num}"
else
export PRISMARR_WORKER_DIRECTIVE="worker /var/www/html/public/index.php"
fi
;;
esac

# Log the decision so worker status is visible in the container log (the
# FrankenPHP process runs as www-data / non-dumpable, so its env can't be
# inspected from outside, and FrankenPHP doesn't log worker startup at info).
if [ -n "${PRISMARR_WORKER_DIRECTIVE:-}" ]; then
echo "[prismarr] FrankenPHP worker mode ENABLED — ${PRISMARR_WORKER_DIRECTIVE}"
else
echo "[prismarr] FrankenPHP worker mode disabled (classic per-request; set PRISMARR_WORKER=1)"
fi

# Drop privileges: FrankenPHP and all PHP scripts run as www-data (UID 82).
exec s6-setuidgid www-data frankenphp run --config /etc/caddy/Caddyfile
Loading