Commit Graph
2337 Commits
Author SHA1 Message Date
4gray 1806cb46aa refactor(web): harden runtime service payloads 2026-05-22 11:20:50 +03:00
4gray 76346a569b Merge pull request #966 from 4gray/agent/playlist-delete-lifecycle
refactor(playlists): centralize delete lifecycle
2026-05-22 11:18:15 +03:00
4gray b2778d8b18 refactor(playlists): centralize delete lifecycle 2026-05-22 11:10:04 +03:00
4gray 6a4c4c49c2 Merge pull request #965 from 4gray/agent/runtime-capabilities
refactor(runtime): centralize platform capabilities
2026-05-22 11:08:40 +03:00
4gray c571c57c5b refactor(runtime): centralize platform capabilities 2026-05-22 11:00:34 +03:00
4gray 39c1c10492 Merge pull request #964 from 4gray/agent/pwa-self-hosted-hardening
fix(pwa): harden self-hosted runtime boundaries
2026-05-22 10:37:35 +03:00
4gray 36bce47764 merge: resolve master conflicts for pwa hardening
- merge origin/master into PR #964 and keep embedded MPV test on the isolated playback sub-entrypoint

- centralize EPG capability through DataService.supportsEpg and update PWA web-e2e expectations

- split BrowserAccessError copy between Electron and PWA diagnostics
2026-05-22 10:20:03 +03:00
4gray c96a805b47 Merge pull request #987 from 4gray/agent/electron-ipc-sqlite-contracts
test(electron): add sqlite ipc contract coverage
2026-05-22 09:39:25 +03:00
4gray 9d69443d01 Merge pull request #963 from 4gray/agent/embedded-mpv-ci-runtime-cache
ci: cache embedded mpv runtime
2026-05-22 09:38:26 +03:00
4gray 0345ad7e5e Merge pull request #970 from 4gray/agent/web-strict-mode
chore(web): enable strict TypeScript mode
2026-05-22 09:31:41 +03:00
4gray dce5b557af test(electron): split sqlite ipc contract fixtures 2026-05-22 03:53:35 +03:00
4gray 6cf730ddf6 test(electron): add sqlite ipc contract coverage 2026-05-22 03:42:01 +03:00
4gray 5d355b6f10 fix(web): address strict mode review feedback 2026-05-22 03:11:14 +03:00
4gray 4ab8915483 chore(web): enable strict TypeScript mode 2026-05-22 02:58:12 +03:00
4gray f3c0cd3820 ci: clarify embedded mpv cache inputs 2026-05-22 02:16:32 +03:00
4gray 55efc24608 fix(pwa): harden self-hosted runtime boundaries 2026-05-22 02:09:57 +03:00
4gray 0b19155469 ci: cache embedded mpv runtime 2026-05-22 02:02:06 +03:00
4gray ff9c13058c Merge pull request #955 from 4gray/claude/elegant-hertz-40b11b
Unified color, rebuilt dashboard, polished Settings & Multi-EPG
2026-05-22 01:58:57 +03:00
4gray 2a769ad44e Merge origin/master into PR 955 2026-05-22 01:34:56 +03:00
4gray 5cfe3aef06 fix(dashboard): localize progress labels 2026-05-22 01:02:04 +03:00
4gray 2ecb5c28f4 fix(dashboard): address PR review feedback 2026-05-22 00:59:17 +03:00
4gray 67d512d44c Merge pull request #961 from 4gray/agent/pwa-provider-target-flow
fix(docker): exclude agent worktrees from build context
2026-05-22 00:47:22 +03:00
4gray 4c2666520c fix(pwa): parallelize dashboard xtream loads 2026-05-21 21:40:24 +03:00
4gray 69b7bca9df fix(pwa): prefer xtream collection snapshots 2026-05-21 21:13:58 +03:00
4gray 87dfaec03d fix(pwa): filter stalker from xtream collections 2026-05-21 20:33:02 +03:00
4gray 6438eec49f fix(pwa): align xtream content identity 2026-05-21 20:18:39 +03:00
4gray ed0b6833d6 fix(pwa): persist xtream collection snapshots 2026-05-21 20:00:38 +03:00
4gray 3ccbfe4f99 fix(pwa): remove dashboard xtream items via data source 2026-05-21 19:52:39 +03:00
4gray 9097ff5bc1 fix(pwa): align xtream recent clearing 2026-05-21 19:45:07 +03:00
4gray d1e057887f fix(pwa): avoid persisting xtream passwords 2026-05-21 19:41:16 +03:00
4gray ec098f98b1 fix(pwa): hydrate xtream user collections 2026-05-21 19:35:36 +03:00
4gray 1ea6914f98 fix(pwa): harden xtream identity normalization 2026-05-21 19:27:40 +03:00
4gray 1d4d793aac fix(pwa): restore xtream user collections 2026-05-21 19:23:25 +03:00
4gray b2909a1186 feat(workspace): add keyboard shortcuts help (#957)
* feat(workspace): add keyboard shortcuts help

* style(workspace): polish keyboard shortcuts dialog

* fix(workspace): address shortcuts review feedback

* docs(workspace): clarify desktop shortcut availability

* refactor(workspace): split keyboard shortcut definitions
2026-05-21 19:15:46 +03:00
4gray 362595525d test(pwa): tighten self-hosted proxy assertions 2026-05-21 18:44:42 +03:00
4gray 6829c667bd fix(pwa): restore xtream rail and vod navigation 2026-05-21 14:18:11 +03:00
4gray 89df1ada0a fix(docker): exclude agent worktrees from build context 2026-05-21 13:36:32 +03:00
4gray 401d434bce test(pwa): cover self-hosted provider target flow 2026-05-21 11:19:04 +03:00
4gray 5d31c1d49a ci(docker): publish images after trusted events 2026-05-21 09:37:43 +02:00
4gray fd59447064 docs(docker): restore self-hosted PWA compose flow
* docs(docker): restore self-hosted PWA compose flow

* fix(docker): supervise self-hosted runtime processes

* fix(docker): exit cleanly on container stop
2026-05-21 09:30:57 +02:00
4gray 738397c9ed feat(website): add giscus blog comments 2026-05-20 18:02:19 +02:00
4grayandClaude Opus 4.7 7083bd2af4 fix(shell): keep Add Playlist reachable on Settings; fix dashboard e2e
Two Electron E2E regressions from this branch's redesigns:

1. Hiding the playlist switcher on /settings (a playlist-scoped control)
   also hid the global "Add playlist" button, which lives in the same
   header-actions block. A user configuring Settings before importing
   their first source had no way to add a playlist — and the settings /
   playlist-switcher E2E suites, which add a portal right after saving a
   setting, timed out waiting for the button. The Add Playlist button is
   a global action, so it now stays visible on Settings; only the
   per-playlist context shortcut and bulk actions are hidden there.

2. dashboard-activation.e2e.ts asserted on `dashboard-global-favorites-
   rail`, the mixed Favorites rail removed earlier in this branch. The
   test now targets the v0.22 rails: live favorites resolve through the
   favorites-first `dashboard-live-recent-rail`, and the played movie /
   series resolve through `dashboard-continue-watching-rail` (renamed
   from `dashboard-recently-watched-rail`). The movie-from-favorites
   assertion was dropped — that dashboard surface no longer exists; the
   favorites collection still has its own page-level coverage.

Verified locally: dashboard-activation, settings, and playlist-switcher
E2E specs all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:55:06 +02:00
4gray 3096115e64 docs: add external players playback article 2026-05-20 15:35:38 +02:00
4grayandClaude Opus 4.7 a8253c5801 test(e2e): adapt to v0.22 dialog + theme picker redesigns
The redesign rollup in this branch replaced the Add Playlist dialog's
2-level type × subtype tabs with a single flat 5-card radiogroup, and
replaced the Settings theme list with a compact segmented control whose
options are just "Light"/"Dark"/"System" (no "theme" suffix). E2E tests
that pinned to the old roles/labels failed in CI:

  - basic / xtream / stalker / self-hosted: getByRole('tab', ...) on
    "Add via file upload" / "Xtream" / "Stalker" — there are no tabs in
    the new dialog. Switched to getByRole('radio', { name: /M3U file/i })
    and friends, matched against the new radio labels.
  - settings: getByRole('radio', { name: 'System theme' }) — the new
    picker uses just "System". Scoped to the [data-test-id="select-theme"]
    radiogroup so it doesn't collide with the identically-labelled
    cover-size options below.

The Electron `clickDialogSegmentedOption` helper grew a radio-role lookup
as its primary path and keeps the old tab/button/legacy-selector
fallbacks so a future redesign won't break every fixture again. The
"M3U" parent category becomes a no-op (the new picker has no standalone
M3U tile — callers always specialise to M3U URL/file/text immediately
after, which is what we want anyway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 22:07:26 +02:00
4gray 5b091809ef fix(xtream): ignore future recently added dates
## Summary
- Normalize Xtream recently-added timestamps across UI, import, and dashboard query paths.
- Filter future/invalid provider dates before ranking rails and migrate legacy millisecond cache rows.
- Add regression coverage for future timestamps, series date priority, and DB migration behavior.

## Validation
- GitHub checks passed, including Unit Tests and Typechecks, Web E2E, Electron E2E on macOS/Ubuntu/Windows, CodeQL, builds, and Greptile Review.
2026-05-19 14:39:38 +02:00
4grayandClaude Opus 4.7 8091dec074 feat(dashboard): show S·E badge on Continue Watching series cards
For series in the Continue Watching rail, surface which episode the user
left off on as a small "S2·E5" chip next to the card subtitle. Sources
the season/episode straight off the matched PlaybackPositionData so the
information is always in sync with the resume target.

Fixes a latent bug in the same patch: getPlaybackPositionForItem could
not resolve series whose recent_items row carried the series id (the
landing-page path), because playback_positions are keyed by the episode
id. The lookup now matches both shapes (contentXtreamId === xtreamId OR
seriesXtreamId === xtreamId) and prefers the most recently updated
episode, which also restores the resume progress bar that had been
silently dropping out for series.

Localised in all 17 non-English locales — most use language-specific
short forms (St·F in German, T·E in Spanish/Portuguese, С·Э in
Russian/Belarusian, 시즌N N화 in Korean) rather than the English S·E.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:32:13 +02:00
4grayandClaude Opus 4.7 6891a1ca30 i18n(epg): translate multi-EPG toolbar tooltips
The Zoom/Filter/Search Programs buttons in the Multi-EPG header
hard-coded English matTooltip strings, so they never localized — even
when the rest of the toolbar (Close, Previous/Next day) used keys. Adds
six new EPG.* keys (ZOOM_IN, ZOOM_OUT, FILTER_CHANNELS, CLOSE_FILTER,
SEARCH_PROGRAMS, CLOSE_PROGRAM_SEARCH), wires both [matTooltip] and
[attr.aria-label] through `| translate`, and fans the strings out to
all 17 non-English locales via the i18n-fill pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:15:35 +02:00
4grayandClaude Opus 4.7 55215a5059 feat(radio): add tooltips + aria-labels on every player button
Radio audio-player buttons (skip-prev, play/pause FAB, skip-next, mute,
volume slider) had zero matTooltip or aria-label. The UX audit flagged
this: "Skip-prev / Skip-next — what do they skip? In radio, is the
next 'track' the next station? Next in favourites? Random? Without a
tooltip the buttons trade silently." Same critique applied to mute
and play/pause for screen-reader users.

Add hover tooltips and screen-reader labels on all 5 controls. Skip
prev/next say "Previous station" / "Next station" so the behaviour is
explicit (they walk the active filtered list). Play/Pause flips its
label with state. Mute/unmute flips when isMuted() || volume === 0.
Volume slider gets its own label so the slider thumb is announced
correctly.

i18n: 7 new AUDIO_PLAYER.* keys translated across all 17 non-English
locales by per-locale agents; all 18 locales pass coverage and
placeholder integrity checks.

52/52 ui-playback tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:03:14 +02:00
4grayandClaude Opus 4.7 86ec1685a5 chore(settings): drop uppercase eyebrow on rail title
After switching from mono to sans, the SETTINGS label still used
uppercase + 0.1em letter-spacing — an eyebrow treatment that doesn't
appear anywhere else in the workspace rail. The neighbouring items
("Dashboard", "Sources", "Global favorites") are all sentence case,
so the uppercase header stood out as a one-off.

Use sentence case "Settings" with the same typography family as the
rail items: same font, same case, small + muted so it still reads as
a quiet caption rather than competing with the clickable items below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:05:14 +02:00
4grayandClaude Opus 4.7 231c22f7d4 chore(settings): switch SETTINGS eyebrow to inherited sans-serif
The v0.22 mockup uses JetBrains Mono for eyebrow labels as part of its
broader editorial design language. The previous commit ported that one
element verbatim, but the rest of the workspace shell never uses mono
for chrome — only for code-adjacent data (EPG time codes, kbd glyphs,
port numbers). So the SETTINGS rail title became a one-off mono label
in an otherwise all-sans shell.

Drop the `font-family: 'JetBrains Mono'…` declaration so the eyebrow
inherits DM Sans. Bump the weight from 500 → 600 to compensate for
mono's higher visual density. Uppercase + 0.1em letter-spacing + small
size are kept — those carry the eyebrow effect regardless of typeface.

If we ever want to port the broader mono-eyebrow system across rails
and chips, that's a separate (bigger) design decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:03:50 +02:00