Commit Graph
9 Commits
Author SHA1 Message Date
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
4gray 724e4b1ab3 feat(playback): add embedded mpv (macos) stream recording (#916)
* feat(playback): add embedded mpv stream recording
Entire-Checkpoint: f957cd9849e0

* fix(playback): address embedded mpv recording review
Entire-Checkpoint: f957cd9849e0

* fix(playback): track mpv recording auto-stop replies
Entire-Checkpoint: f957cd9849e0
2026-05-10 12:27:09 +02:00
4grayandClaude Opus 4.7 b5dbc33e62 fix(embedded-mpv): make slider track and thumb visible
The timeline and volume sliders were rendering invisibly because:

- --embedded-mpv-accent resolved to var(--mat-sys-primary) with no
  fallback. If the Material 3 theme tokens did not cascade into the
  component scope, the variable was empty and both the thumb and the
  Firefox progress fill rendered with no color.
- The track contrast was 22% of var(--mat-sys-on-surface) which has the
  same scoping fragility on top of being subtle even when it does
  resolve.
- The thumb had no border, so even when accent was present it could
  blend into similarly-toned popover backgrounds.
- The played portion of the timeline had no fill in Chromium because
  ::-webkit-slider-runnable-track does not support a native progress
  state.

Fixes:

- Add hard fallbacks on every theme-token reference (accent falls back to
  #7dd3fc, surface to #0f1620, outline-variant to a translucent white).
- Add --embedded-mpv-track and --embedded-mpv-thumb-ring as theme-
  independent CSS variables so the slider stays legible regardless of
  the parent theme provider.
- Give the thumb a 2 px white ring border + a stronger drop shadow so it
  reads on any background (panel glass, dark backdrop, accent-coloured
  area).
- Implement played-progress fill via a linear-gradient on
  ::-webkit-slider-runnable-track keyed off a CSS variable
  --slider-progress, set per-slider from the template based on the
  current playback position / volume. Firefox uses native
  ::-moz-range-progress.
- Tidy disabled state styling so live-stream timelines (no duration)
  are dim but still visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 10:33:18 +02:00
4grayandClaude Opus 4.7 0249a3a9f7 refactor(embedded-mpv): split player component into focused units
The component had grown to ~1000 lines with session lifecycle, IPC plumbing,
keyboard shortcuts, popover state, formatters, and view orchestration all
living in one file. Per CLAUDE.md's 350–400 line hard cap, split into:

- embedded-mpv-format.utils.ts (~100): pure helpers (formatTime, track
  labels, volume icon/label, persisted-volume access, measureBounds) and
  preset constants (SPEED_PRESETS, ASPECT_PRESETS, HIDDEN_BOUNDS).
- embedded-mpv-shortcuts.ts (~90): EmbeddedMpvShortcuts class that owns the
  document keydown listener and routes through a handler interface; the
  component just provides callbacks.
- embedded-mpv-ui-state.ts (~110): EmbeddedMpvMenuState (single-open
  popover state machine with toggle/open/close/closeAll + anyOpen signal)
  and EmbeddedMpvFeedback (transient overlay with auto-clearing flash).
- embedded-mpv-session-controller.ts (~395): component-scoped Injectable
  that owns support/session/sessionId/stalled/retryToken signals, the
  session-update IPC subscription, bounds-sync (resize, scroll, overlay
  state), the stalled timer, and all per-session IPC operations
  (togglePaused, seekBy, seekTo, applyVolume, setAudioTrack,
  setSubtitleTrack, setSpeed, setAspect, retry).
- embedded-mpv-player.component.ts (now ~540, was ~1000): view-only
  orchestration — view children, derived computed signals, DOM event
  listeners (pointerdown/pointermove/fullscreenchange/dblclick), and three
  effects (session start/teardown, overlay-active bounds sync, session
  payload → volume/timeUpdate fan-out).

No behavior changes. Build clean, electron-backend tests still pass.
Component is still over the 400-line cap but the bulk of its size is now
the necessarily-coupled-to-view computed signals and constructor effects;
the remaining over-cap delta is structural to a player root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 10:09:31 +02:00
4grayandClaude Opus 4.7 8e3f559033 feat(embedded-mpv): subtitles, playback speed, aspect override, retry on error
Native addon (apps/electron-backend/native/src/embedded_mpv.mm)
- Extend SessionSnapshot with subtitleTracks, selectedSubtitleTrackId,
  playbackSpeed, aspectOverride.
- Refactor track parsing into a shared updateTracksFromNode helper that
  filters by mpv "type" so audio and subtitle tracks share the code path.
- Observe sid, speed, video-aspect-override; clear sub state on
  MPV_EVENT_START_FILE.
- Export setSubtitleTrack (handles trackId === -1 as "no" to disable),
  setSpeed (clamped to 0.25–4.0), setAspect (passthrough string for
  video-aspect-override).
- Snapshot output now includes the new fields.

Service (embedded-mpv-native.service.ts) + IPC + preload
- Mirror methods on EmbeddedMpvNativeService with capability detection: each
  method throws a descriptive error if the loaded addon doesn't expose the
  underlying native function (i.e. user is running an older build).
- New IPC channels EMBEDDED_MPV_SET_SUBTITLE_TRACK, _SET_SPEED, _SET_ASPECT
  registered in events file and exposed via preload.
- Extend EmbeddedMpvSupport with a capabilities probe so the renderer can
  hide controls for features the current addon build doesn't ship.

Renderer (embedded-mpv-player.component.{ts,html})
- Three new popovers anchored above their buttons (subtitle / speed /
  aspect), gated by capabilities() and (for subtitles) by track count.
- Subtitle popover includes an Off entry; speed/aspect use fixed presets.
- Error state now surfaces the same overlay as the stalled state, with a
  Retry button that bumps the existing retryNonce signal — covers #8 from
  the audit.
- All session-payload defaults (loading stub, error stub, refresh fallback,
  dispose payload, native createSession default) updated for the new
  required fields.

NOTE: Existing addon binaries do not expose the new methods. Until the
addon is rebuilt (pnpm run serve:backend:embedded-mpv or the release
build script), capabilities will report subtitles/playbackSpeed/
aspectOverride as false and the new buttons will simply not appear.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 09:53:32 +02:00
4grayandClaude Opus 4.7 dea1d40c3d feat(embedded-mpv): polish bundle — popovers, mute, retry, feedback
- Volume button now toggles mute on click; the slider opens via hover/focus
  in an absolute popover anchored above the button (with hover-bridge so the
  cursor can reach it without crossing a dead zone). Wheel over the volume
  area adjusts volume.
- Audio track menu likewise becomes a click-toggle popover anchored to its
  button instead of a panel takeover; the back-arrow / mode-panel
  scaffolding is gone.
- Slider gets explicit thumb/track styling for both WebKit and Firefox so
  it reads as part of the design system instead of a raw native control;
  aria-valuetext on the timeline announces formatted time.
- Stalled overlay: if status remains "loading" for 30 s, surface a centered
  warning with a Retry button that disposes the session and recreates it
  via a retryNonce signal the playback effect tracks.
- Keypress feedback overlay: ←/→ seek, ↑/↓ volume, M mute now flash a
  centered pill with the icon + delta so the action is visible (especially
  important in fullscreen where the controls are hidden).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 09:39:19 +02:00
4grayandClaude Opus 4.7 e2a9af37db feat(embedded-mpv): keyboard shortcuts and double-click fullscreen
Add the standard set of player shortcuts to match the audio/HTML video
players already in the app:

- Space, K   — play/pause
- F          — toggle fullscreen
- Left/Right — seek -5 s / +5 s
- Up/Down    — volume +/- 5 %
- M          — toggle mute (restores prior volume)

Shortcuts are ignored while focus is in an input/select/textarea or while
any MatDialog (e.g. command palette) is open, so the palette's filter and
dialog inputs keep their keys. Volume changes route through a shared
applyVolume helper so keyboard/wheel/slider all persist to localStorage
and the active session.

Also bind dblclick on the player root to toggle fullscreen, with a guard
so double-clicks on buttons/sliders don't trigger it. Note: the native
MPV NSView intercepts mouse events over the video itself, so dblclick
only fires on DOM-receiving regions (currently the controls strip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 09:26:26 +02:00
4grayandClaude Opus 4.7 2b57f3a35d style(embedded-mpv): align chrome with app theme and fix viewport crop
- Switch palette and surfaces to Material 3 tokens (--mat-sys-*) so the
  player respects the app theme instead of a hardcoded cyan/sky scheme.
- Stop reserving 96 px below the viewport for the control panel; the panel
  now floats over the bottom with a gradient fade so the video fills the
  frame (especially in fullscreen).
- Drop control panel height from 96 to 64 px (88 px on narrow widths).
- Replace the corner "Loading stream in MPV..." pill with a centered
  spinner + concise label during load; move the transient status toast
  to the top-right and add role="status" aria-live.
- Add a red badge with pulsing dot for live streams in place of the plain
  "LIVE" text label.
- Apply font-variant-numeric: tabular-nums to time/volume readouts so
  digits stop jittering as playback advances.
- Slightly loosen transport/actions gaps for a less cramped rhythm and
  use ease-out easing on control fade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-05 09:10:58 +02:00
4gray 9f873e6bed feat(player): add embedded-mpv player for macOS as experimental feature
- Introduced tooling for building and staging the macOS `libmpv` runtime for IPTVnator's embedded MPV player.
- Added `build-macos-runtime.mjs` for building an LGPL-compatible runtime from source.
- Created `stage-macos-runtime.mjs` for staging the built runtime artifacts.
- Implemented validation for the packaged embedded MPV runtime in `electron-after-pack.cjs` and `embedded-mpv-macos.cjs`.
- Updated packaging scripts to ensure the embedded MPV runtime is correctly integrated and validated during the build process.
- Added README files to document the expected layout and usage for the embedded MPV runtime artifacts.

Entire-Checkpoint: c6e522b4276c
2026-04-27 00:32:14 +02:00