Commit Graph
543 Commits
Author SHA1 Message Date
4gray dbc90bed06 fix(dashboard): address rail review feedback 2026-06-20 23:10:18 +02:00
4gray b6c5367d63 fix(dashboard): speed up startup rails 2026-06-20 21:46:42 +02:00
4gray ffc07146fe feat(xtream): sort and filter the VOD/series catalog by IMDb rating
Adds IMDb rating sort and minimum-rating filtering for Xtream VOD/series catalogs, consolidates refinement controls, and guards rating controls away from Live TV.
2026-06-20 13:50:56 +02:00
4gray 2f27895e6b Merge pull request #1084 from 4gray/agent/sources-header-style
Align sources header with panel style
2026-06-20 13:50:22 +02:00
4gray c276d48bb7 Show sources playlist scrollbar 2026-06-20 12:52:16 +02:00
4gray e3388de989 Address sources header review feedback 2026-06-20 12:39:00 +02:00
4gray 4e732d3e51 Align sources header with panel style 2026-06-20 12:30:24 +02:00
4gray 2edc430935 feat(xtream): add live all-items grid 2026-06-20 09:36:34 +02:00
4gray bfa865c55c test(xtream): cover live auto-open state reset 2026-06-19 21:00:22 +02:00
4gray 6ad5f5e207 fix(xtream): address live recents review feedback 2026-06-19 20:50:14 +02:00
4gray 210f0ebabc feat(xtream): show recently added live channels 2026-06-19 19:59:42 +02:00
4gray 8739e95b70 Merge pull request #1065 from 4gray/codex/xtream-portal-compatibility
fix(xtream): improve portal compatibility
2026-06-14 14:40:39 +02:00
4gray 20d0f01428 fix(xtream): address portal review feedback 2026-06-14 13:47:42 +02:00
4gray 1444047a1d refactor: split dashboard rails and settings logic
Split dashboard rails and settings logic into focused helpers/facades while preserving behavior.
2026-06-14 13:34:23 +02:00
4gray 254879f92b fix(xtream): improve portal compatibility 2026-06-14 13:21:56 +02:00
4gray bc4a5958dc fix(remote-control): apply volume to built-in M3U players
Closes #1061
2026-06-14 13:12:45 +02:00
4gray adf37e7504 feat(dashboard): add configurable dashboard rails
* feat(dashboard): add configurable dashboard rails

* fix(dashboard): address rail review feedback
2026-06-14 11:52:44 +02:00
4gray 4094a36fef Harden Linux embedded MPV packaging (#1043) 2026-06-13 17:24:13 +02:00
4gray dfdb5bb8ad fix(playlist): save xtream details in pwa
- save Xtream playlist details through browser-safe metadata persistence in PWA\n- keep PWA Xtream data source cache in sync with current playlist metadata\n- cover dialog close timing, stale cache, and PWA data-source bootstrap regression
2026-06-13 16:04:54 +02:00
4gray 8d672f8b81 feat(playback): add web player series navigation (#1049) 2026-06-13 10:19:57 +02:00
4grayand4gray e8aa7c3a34 [codex] Add scoped EPG security trust controls (#1054)
* Add scoped EPG security trust controls

* fix: address scoped trust review feedback

---------

Co-authored-by: 4gray <fourgray@proton.me>
2026-06-12 20:46:24 +02:00
4grayand4gray 9043116ebd [codex] fix Electron hardening follow-ups (#1053)
* fix: clean up Electron hardening follow-ups

* fix: remove duplicate Xtream probe comment

---------

Co-authored-by: 4gray <fourgray@proton.me>
2026-06-12 20:46:01 +02:00
Salem 2c032cd3c8 fix(security): complete Electron hardening and review follow-ups
* fix(security): harden Electron IPC against MITM, SSRF, path and injection risks

S1 TLS: validate certs by default on playlist/EPG fetches (opt-out via IPTVNATOR_ALLOW_INSECURE_TLS); new util/secure-https.ts.
S2: write-file IPC restricted to save-dialog-authorized paths.
S3: XTREAM_PROBE_URL guarded by assertRemoteUrlAllowed + maxRedirects:0; new events/url-safety.ts (+19 tests).
S4: EPG titles rendered via interpolation, not [innerHTML].
S5: downloads reveal/play limited to recorded download paths.
S6: Stalker cmd encoded (slash-preserving) to block query injection.
EPG-worker and Stalker fetches reject file://-style/credentialed URLs; LAN/self-hosted targets remain allowed.

* perf(player): lazy-load web video players via @defer

Wrap Video.js/HTML5/ArtPlayer in @defer (on immediate) so video.js, hls.js,
artplayer and mpegts.js split into a deferred chunk loaded on first playback
instead of eagerly on the player route. Embedded MPV (native) stays eager.
Spec uses DeferBlockBehavior.Playthrough.

* fix(player): remove leaked HTML video listeners on destroy

volumechange used a mismatched removeEventListener reference, while
loadedmetadata and timeupdate were never removed at all. Bind all three to
stable handler fields used for both add and remove, and add a teardown
regression test asserting each listener is detached on destroy.

* refactor(dashboard): extract pure navigation helpers from DashboardDataService

Move the 8 stateless link/navigation-state/type-kind helpers into a new
dashboard-navigation.util.ts so the routing logic is independently testable and
the 1260-line god-service shrinks. DashboardDataService keeps the public methods
as thin delegators (facade) so the public API and the single consumer
(workspace-dashboard-rails) are unchanged. First slice of the DashboardDataService
decomposition; verified by the existing service spec (33/33) and the app typecheck.

* fix(review): address PR feedback (IPv6 link-local, write-path cap, @defer placeholder)

- url-safety: broaden IPv6 link-local detection to the full fe80::/10 range
  (fe80:: through febf::), not just the fe80:: prefix (+ regression tests).
- playlist.events: cap authorizedWritePaths (evict oldest past 32) so a save
  dialog opened without a following write cannot accumulate entries until restart.
- web-player-view: add a @placeholder to each @defer (on immediate) player block
  to avoid the one-frame blank/layout-shift before the chunk resolves.

* fix(security): close Electron network and download gaps

* test(downloads): cover cancellation and restart cleanup

* fix(downloads): address Greptile review gaps

* test(security): reproduce remaining Greptile findings

* fix(security): close remaining Greptile findings

* test(downloads): reproduce early database queue stall

* fix(downloads): release queue after setup failures

* test(downloads): reproduce completion queue stall

* fix(downloads): release queue after completion failures
2026-06-12 15:24:29 +02:00
4grayandClaude Fable 5 8e0abe6feb feat(ui): custom title bar with window controls for Windows and Linux (#1042)
* feat(ui): add custom title bar window controls for Windows and Linux

Hide the native title bar on win32/linux (titleBarStyle: 'hidden', frame
untouched so native resize borders and snapping keep working) and render
minimize / maximize-restore / close buttons in the renderer, mirroring the
existing macOS traffic-light setup.

- New WINDOW:* IPC contract (minimize, toggle-maximize, close, get-state)
  handled in window.events.ts, resolved from the sender WebContents;
  close goes through win.close() so window-bounds persistence still runs.
- WINDOW:STATE_CHANGED pushed on maximize/unmaximize/fullscreen so the
  maximize/restore glyph stays correct for OS-triggered changes; controls
  hide while fullscreen.
- WindowControlsComponent mounts once in app-root as a manual popover so
  it stays in the browser top layer above CDK overlays (dialogs,
  multi-EPG) - same behavior as macOS traffic lights.
- Theme-aware via CSS vars (--app-on-surface, --app-hover-overlay);
  Windows-red close hover. Drag regions get right padding through a
  body-level frameless-platform class.
- Gated by RuntimeCapabilitiesService.usesCustomWindowControls; PWA and
  macOS never mount the controls.

Includes unit specs for the component and IPC handlers, an Electron E2E
suite (window-controls.e2e.ts), and a window-chrome section in
docs/architecture/workspace-shell.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(linux): upgrade Electron to 41 for frameless window decorations on Wayland

With the native title bar hidden, Linux windows lost the WM-drawn shadow
and rounded corners. Electron draws client-side decorations only on
native Wayland, and frameless-window CSD (GTK drop shadow + extended
resize boundaries) landed in Electron 41 - before that, frameless
windows render as plain rectangles.

- electron ^39.8.5 -> ^41.7.2 (Wayland auto-detected since 38.2; X11
  sessions remain undecorated, matching other frameless Electron apps;
  Windows keeps its DWM shadow and rounded corners).
- better-sqlite3 pinned to exactly 12.9.0: the last release shipping
  prebuilt binaries for both Node 20 (ABI 115, Jest) and Electron 41
  (ABI 145, runtime). 12.10.0 dropped the Node 20 prebuilds, forcing a
  from-source build that fails without a C++ toolchain.
- pnpm override node-abi 3.85.0 -> 3.92.0 so electron-builder
  install-app-deps can map Electron 41 to ABI 145.

Reviewed Electron 40/41 breaking changes: only the renderer clipboard
deprecation, which this app does not use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(e2e): address review feedback and window-managerless Linux CI

- Skip the three window-manager-dependent E2E assertions (maximize
  toggle, main-process state sync, minimize) on Linux CI: GitHub's
  ubuntu runners drive Electron under xvfb without a window manager, so
  maximize/minimize state never materializes there. Windows CI and
  local Linux/macOS runs keep the coverage.
- WINDOW:TOGGLE_MAXIMIZE now returns the requested state instead of
  re-reading isMaximized() right after the call, which races on Linux
  window managers where maximize()/unmaximize() complete
  asynchronously; the WINDOW:STATE_CHANGED push stays authoritative.
- Skip attaching window-state push listeners on macOS, where the
  custom controls never mount and the IPC traffic had no subscriber.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ui): gate custom window controls on the full bridge surface

Include getWindowState and onWindowStateChange in the
usesCustomWindowControls capability check — the controls rely on both
for initial state and for keeping the maximize/restore glyph in sync
with OS-triggered changes, so a partial bridge should not mount them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:03:27 +02:00
4gray 8517c7a8f7 fix(playback): suppress diagnostics for embedded mpv (#1038)
* fix(playback): suppress diagnostics for embedded mpv

* chore(playback): clarify selected player effect dependency
2026-06-10 10:53:46 +02:00
ilyesbrhandClaude Sonnet 4.6 5bb2dfed71 fix(xtream): open correct channel and category from Ctrl+F live search (#1034)
* fix(xtream): open correct channel and category from Ctrl+F live search

Three bugs prevented a live channel clicked from global search (Ctrl+F)
from playing and highlighting correctly in the sidebar:

1. Component reuse on same-route navigation: when the user was already
   on the /live route, Angular reused LiveStreamLayoutComponent without
   re-running the constructor, so openXtreamLiveItemId was never read
   from history state. Fixed by subscribing to NavigationEnd and calling
   checkPendingAutoOpenFromState() on every navigation.

2. Early effect firing with wrong content type: the auto-open effect
   could fire before syncRouteState set selectedContentType to 'live',
   causing the channel to be searched in VOD streams, not found, and
   the pending ID cleared. Fixed by guarding on selectedContentType()
   === 'live' before processing.

3. Category filter blocking channel lookup: getVisibleChannels() only
   returned channels in the currently selected category, so a channel
   from a different category was never found. Fixed by switching to
   getAllLiveStreams() (raw liveStreams signal) for the auto-open lookup.

Also sets selectedCategoryId to the opened channel's category so the
sidebar scrolls to the right category and highlights the channel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(xtream): address PR review feedback on live search auto-open

- Remove redundant constructor call: rely solely on NavigationEnd
  subscription to read openXtreamLiveItemId from history state, which
  fires after component creation for both initial and re-navigation
- Add explicit setSelectedItem call after auto-open so EPG loading and
  remote-control status reflect the playing channel independently of
  the constructStreamUrl side-effect
- Add 6 regression tests covering: initial NavigationEnd, category
  highlighting, content-type guard, lazy liveStreams loading, missing
  channel, and component-reuse re-navigation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 10:52:11 +02:00
4gray 77cf4065e0 feat(playback): add embedded mpv series navigation (#1030)
* fix(remote-control): use iptvnator favicon

* feat(playback): add embedded mpv series navigation

* refactor(playback): share series navigation state
2026-06-08 07:55:01 +02:00
4grayand4gray 4cc9b93321 [codex] Cover playlists service behavior (#1027)
* cover playlists service behavior

* clarify playlists service test contract

---------

Co-authored-by: 4gray <fourgray@proton.me>
2026-06-06 17:49:10 +02:00
4grayand4gray 0fa050f4c3 [codex] Cover playback stack helpers (#1026)
* cover playback stack helpers

* harden playback session controller specs

---------

Co-authored-by: 4gray <fourgray@proton.me>
2026-06-06 17:47:50 +02:00
4gray 1badb9a057 refactor(electron): share typed preload bridge contract (#1018)
* refactor(electron): share typed preload bridge contract

* refactor(electron): tighten bridge review fixes

* refactor(electron): tighten playlist bridge returns

* refactor(electron): use bridge epg progress type

* refactor(epg): alias progress bridge types
2026-06-01 09:52:22 +02:00
4gray 701cf23299 chore(frontend): clean logging and lint suppressions 2026-05-26 20:18:12 +02:00
4gray a1b0d9186c chore(test): clean lint and warning baseline 2026-05-26 19:30:21 +02:00
4gray 3d4d2ca9bf fix(angular): remove template diagnostics warnings (#1011)
* fix(angular): remove template diagnostics warnings

* fix(angular): preserve template fallback behavior
2026-05-26 18:33:44 +02:00
4gray 1bbe8f794e refactor(workspace): split workspace shell facade
Split WorkspaceShellFacade into focused component-scoped services and keep the facade as the stable template-facing delegation layer.
2026-05-26 17:51:02 +02:00
4gray 82c725ea5a refactor(playback): add playback position runtime bridge (#1009)
* refactor(playback): add playback position runtime bridge

* test(services): avoid angular testing import in playback specs
2026-05-25 01:14:11 +03:00
4gray 697eab6e73 refactor(epg): route renderer calls through runtime bridge
Add typed EPG runtime bridge, split EPG runtime capabilities, migrate renderer EPG callers away from direct window.electron access, and address Greptile review feedback.
2026-05-24 13:45:51 +03:00
4gray 003a8774a1 fix(electron): tighten navigation review feedback
Restrict packaged file navigation to the app renderer, guard redirects, and handle fire-and-forget header override IPC failures.
2026-05-23 19:05:38 +03:00
4gray 3c5f7ab92e fix(electron): preserve playlist header defaults
Keep playlist-level request header overrides active when channel-scoped headers are cleared, and cover layered override behavior.
2026-05-23 15:57:29 +03:00
4gray fc449ca73e feat(electron): harden renderer security
Scope playback request header overrides to active stream origins and document the Electron runtime security contract.
2026-05-22 23:31:41 +03:00
4gray 959f6061f0 fix(runtime): address greptile capability feedback 2026-05-22 14:37:06 +03:00
4gray cf0b06312b test(xtream): mock remote control runtime support 2026-05-22 14:32:12 +03:00
4gray ed8680116c fix(runtime): address consolidated review feedback 2026-05-22 14:02:56 +03:00
4gray 582422c512 refactor(runtime): gate settings backup file save by capability 2026-05-22 13:41:24 +03:00
4gray c9a0d5210e refactor(runtime): gate settings sections by capability 2026-05-22 13:41:24 +03:00
4gray 09e2e08fc1 refactor(runtime): gate settings external players by capability 2026-05-22 13:40:14 +03:00
4gray b4fd93354e refactor(runtime): enable pwa xtream section navigation 2026-05-22 13:38:53 +03:00
4gray 676e8bb5da refactor(runtime): gate downloads navigation by capability 2026-05-22 13:38:20 +03:00
4gray f626e176d2 refactor(runtime): require playlist storage bridge 2026-05-22 13:37:36 +03:00
4gray 4603bd83d5 refactor(runtime): gate playlist refresh by capability 2026-05-22 13:36:39 +03:00
4gray 9a5620bf95 refactor(runtime): require downloads bridge surface 2026-05-22 13:35:03 +03:00