Commit Graph
3040 Commits
Author SHA1 Message Date
4grayandClaude Fable 5.1 aaa86f8c9c chore(i18n): baseline the detail strings that match English in seven locales
Trailer, duration and source labels read the same in de, es, fr, it,
nl, pl and pt; entries for keys the branch removed or translated are
dropped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:35:03 +02:00
4gray 042016e578 Merge remote-tracking branch 'origin/master' into claude/iptvnator-vod-hero-redesign-2c8950 2026-10-03 16:31:18 +02:00
4grayandClaude Fable 5.1 5a5fe4adcf fix(ui): hold the provider play action and the reset row during their busy windows
The downloaded movie's provider action stays enabled while a start was
pending, so a second press could start beside a launch already inside
the player IPC. The series menu's reset row stayed enabled while a
watched batch persisted, although the hosts refuse the reset meanwhile.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:31:18 +02:00
4grayandClaude Fable 5.1 5c9a12fa79 fix(ui): the trailer backdrop stops while the trailer modal is open
Opening the modal neither blurs the window nor hides the document, so an
unmuted backdrop kept sounding under the modal's own copy. The dialog
service now tracks open modals and the backdrop unmounts meanwhile,
waiting idle again, muted, once the modal closed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:15:54 +02:00
4grayandClaude Fable 5.1 93523a1d3c fix(portals): a failed MPV/VLC movie launch is reported to the viewer
The launch settlement swallowed a rejected launch together with a
superseded one, so the menu's launch had nothing to report. It now hands
a failure that nothing superseded to the page, which logs it and shows
the playback error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:15:54 +02:00
4grayandClaude Fable 5.1 cf191eb1a0 fix(portals): a choice made while the opened player closes is the one that starts
The queued entry stays in place while the player the launch opened
closes, so a choice made meanwhile replaces it instead of being stranded
(Stalker) or registering a second replay that starts beside the first
(Xtream). The series launch helpers log through the shared redacting
logger.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:15:54 +02:00
4grayandClaude Fable 5.1 22fd53f6cf fix(portals): a queued episode choice replaces the player its launch opened
Replaying a choice held during a forced MPV/VLC launch closed nothing, so
with the embedded player configured the inline player mounted next to
the external player that had just opened. Both portals now close the
session the launch opened before the choice starts, keep the series
pending while that player closes, and drop the choice when the player
has to stay or the page moved on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:00:15 +02:00
4grayandClaude Opus 5.5 0768ae5ea2 ci(i18n): fail on new English-identical translations (#1793)
* ci(i18n): fail on new English-identical translations

The drift check only warned about locale values identical to English, so
untranslated strings kept landing. It now fails on any such value that
tools/i18n/identical-en-baseline.json does not record for that locale and
key. The baseline captures today's 2,015 entries: legitimately identical
values (brand and technical names, language autonyms, PIN) and the
existing debt. An entry only covers the English text it recorded, so
copying reworded English into a locale fails too.

Baseline entries that are no longer identical are reported, not fatal.
`pnpm run i18n:baseline:update` rewrites the baseline deliberately; CI
runs `pnpm run i18n:validate` (node tests, then the check) and never
rewrites it. `--fail-on-identical` remains as a strict audit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(i18n): keep the baseline intact on failed updates and strict audits

`--update-baseline` now writes nothing while any locale is unreadable or
has missing or extra keys, so an incomplete translation cannot reshape
the baseline. `--fail-on-identical` no longer reads the baseline it
ignores, so a damaged file cannot block a strict audit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 16:00:11 +02:00
4grayandClaude Fable 5.1 ac23230fe8 fix(portals): a settling launch keeps the choices other series hold
The held episode choices live in a per-series queue: the series view is
reused across series, so a launch of one series settling no longer drops
what a viewer chose for another series whose launch is still in flight.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:39:33 +02:00
4grayandClaude Fable 5.1 36079b89c1 fix(portals): a Stalker series start cannot double a launch still in flight
The forced MPV/VLC launch IPC cannot be cancelled by a later generation,
so an episode chosen while it runs now waits for it and plays once it
settles, instead of opening a second player next to the first. The hero
button and the external-player menu row are held while a start is
pending, in both portals.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:32:10 +02:00
4grayandClaude Fable 5.1 5787a6643a test(portals): cover page tokens across recreated series pages
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:22:55 +02:00
4grayandClaude Fable 5.1 1bb03d883c fix(portals): a recreated series page never reuses a page token
The token carries a module-wide instance number next to the visit
counter, so a page that replaced a destroyed one cannot collide with the
launches that page left behind.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:18:09 +02:00
4grayandClaude Fable 5.1 3cdf1bd3ea fix(portals): a reopened series can relaunch an episode an earlier visit still settles
The duplicate guard of forced episode launches is keyed by the page
visit, not the owner, so a launch left behind by an earlier visit of the
same series no longer swallows the reopened page's click; that click
queues behind the stale launch on the owner's chain instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:14:08 +02:00
4gray 4adc3ba20f fix(ui): one watch-progress colour in app chrome and in the player (#1798) 2026-10-03 15:11:10 +02:00
4grayandClaude Fable 5.1 023c3444af fix(portals): a failed episode launch is reported to its own visit only
The menu compares the playback service's series+visit page token, so a
launch started on an earlier visit of the same series does not surface
its failure after the viewer came back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:08:12 +02:00
4grayandClaude Fable 5.1 426de69efb fix(portals): a failed episode launch is reported on its own series only
The series page is reused across titles; a launch that fails after the
viewer moved on is logged but not shown over the new series.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:03:37 +02:00
4grayandClaude Fable 5.1 d087cf4d1c fix(portals): twenty-fourth review round on the cinematic details
- A forced Xtream episode launch returns its promise to the menu, which
  reports a rejection; the bookkeeping consumes a settled copy.
- Launch bookkeeping is guarded by a page token (series + visit), checked
  again after the asynchronous save, so neither a return to the same
  series nor a navigation during the save contaminates another page.
- A Stalker launch re-anchors to the host's request id after the host's
  own inline teardown: only a later start supersedes it, and that still
  silences the old launch's failure.
- The shared movie page disables Play and Start Over while a start is
  pending, so nothing starts beside an in-flight launch.
- Episode sublines honour duration_secs before the formatted duration.
- The external session → episode ids derivation moves into the launch
  helper.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:57:51 +02:00
4grayandClaude Fable 5.1 d71a92cec8 fix(portals): twenty-second review round on the cinematic details
- A Stalker launch that already started reports its failure even though
  the host's own inline teardown retired the request id.
- An Xtream episode launch's bookkeeping applies only while the page
  still shows the series it started on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:46:37 +02:00
4grayandClaude Fable 5.1 6de998094a fix(portals): a reopened series keeps its queued episode choice
One settle handler per owner hands the latest queued choice to the start
callback that came with it, so the page the viewer left cannot consume
the choice a reopened page made.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:37:59 +02:00
4grayandClaude Fable 5.1 39ec848110 fix(portals): a queued episode choice stays with its series
The choice made while a forced launch settles is kept per playlist:series
owner by the launch helper and only starts if the page still shows that
series, so a Similar-rail navigation cannot play it under another title.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:28:56 +02:00
4grayandClaude Fable 5.1 5b2fbe296b fix(portals): nineteenth review round and the web E2E line limit
- A queued Xtream episode launch checks the page owner before it closes
  the running player, so a viewer who left the series keeps playback.
- A Play or episode choice made while a forced launch settles starts
  once it settled instead of being dropped; only the latest choice runs.
- Both series menus disable the bulk watched actions while a start has
  not published its session yet.
- The series-menu E2E helpers are shared, which brings the Stalker web
  spec back under the line limit; the inline episode state derivation
  moves into ui/playback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:21:46 +02:00
4grayandClaude Fable 5.1 956e7c36b7 fix(portals): a forced Xtream episode launch blocks other starts and the reset
The launch helper keeps a reactive per-series pending count; the
playback service exposes it, refuses a non-forced start while a forced
launch settles, and the series menu disables the reset row for that
window. The inline progress row moves into a shared helper.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:08:09 +02:00
4grayandClaude Fable 5.1 f7c71c222a fix(portals): queue a different Xtream episode behind a settling launch
Only a repeat of the same episode is ignored while its launch settles;
another episode of the series waits its turn and then replaces the
running player like any later start.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 14:04:35 +02:00
4grayandClaude Fable 5.1 65d7804b21 fix(portals): seventeenth review round on the cinematic details
- A superseded Stalker launch that fails stays silent; the newer start
  reports for the movie.
- Xtream episode launches are serialized per series until the launch
  settles, so a repeat before the first session is published cannot start
  a second player.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:53:26 +02:00
4grayandClaude Fable 5.1 95197baf98 fix(portals): playlist-scoped hero and pending-start keys for series and movies
Provider ids are playlist-scoped: the Stalker series hero key and its
pending-start key, and the Xtream series and movie hero keys, include
the playlist so a cross-playlist navigation to the same number gets its
own layout decision and does not inherit a pending start.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:33:27 +02:00
4grayandClaude Fable 5.1 4ad5f471e4 fix(portals): the shared movie page keys its hero layout by playlist too
Collection details reuse the mounted view across playlists whose movies
share a numeric id; each playlist's movie now gets its own decision.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:21:14 +02:00
4grayandClaude Fable 5.1 0524429fbd fix(portals): fourteenth review round on the cinematic details
- The hero keys its one-time stage/compact decision on a stable content
  identity (provider + id) that every host passes, so a TMDB rename plus
  a late backdrop no longer flips the visible hero.
- An explicit Stalker movie launch joins its host's start generation: it
  supersedes an earlier start and is dropped once a Play, Start Over or
  later launch begins, on the controller, search, collection and catalog
  hosts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:14:07 +02:00
4grayandClaude Opus 5.5 a8dd1eaa97 fix(import): consistent add-source forms with masked passwords and URL errors (#1796)
* fix(import): consistent add-source forms with masked passwords and URL errors

- Mask the Xtream password in add and edit (and the Stalker one in edit)
  behind a shared PasswordVisibilityToggleDirective: one translated
  "Show password" label, state in aria-pressed, type="button".
- Give the Xtream server URL its own mat-error and a neutral hint instead
  of the EPG file error; give the M3U URL a mat-error.
- Use "Playlist title" in every add form, "MAC address" casing, a single
  ellipsis in "Validating portal…" and one "Add playlist" submit label;
  translate the method radiogroup's aria-label.
- Show Stalker refusals inline under the portal URL (role="status", like
  the Xtream connection test), translated in the template and cleared by
  edits; translate the snackbars for outcomes that close the dialog.
- Translate new strings into all locales; reuse the identical Stalker URL
  error translations; fix MAC casing and ellipses; drop unused keys.
- Unit specs per form, edit-dialog spec, new add-source-forms web E2E;
  update E2E locators; UI guidelines Forms section; Stalker contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(import): mask the password again when an add form is cleared

Clear erased the password but left the visibility toggle on, so the next
password typed in the Xtream or Stalker form showed in plain text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:13:54 +02:00
4grayandClaude Fable 5.1 4e18306d06 fix(portals): a reset finished under another playlist leaves its store alone
The store positions are only reloaded for the playlist the reset started
on while that playlist is still current; a playlist switched meanwhile
keeps its own positions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:56:07 +02:00
4grayandClaude Fable 5.1 b3c422c9b5 fix(portals): twelfth review round on the cinematic details
- The Stalker explicit-launch guard tracks every in-flight movie, so a
  repeat of a pending launch is rejected even after another movie's
  launch was started in between.
- The Xtream movie reset only touches the route's state while it still
  shows the movie the reset started on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:52:22 +02:00
4grayandClaude Fable 5.1 95a3130883 fix(portals): the Stalker launch guard is per movie
A launch still resolving for the movie the user left no longer blocks
the explicit launch of the movie now on screen; only a repeat for the
same movie is ignored.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:47:04 +02:00
4grayandClaude Fable 5.1 b47aeda543 fix(portals): one explicit Stalker launch at a time
A second "Open in external player" while the first create_link is still
resolving is ignored, and the menu row is disabled for that window, so
two resolutions cannot each start a player.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:38:25 +02:00
4grayandClaude Fable 5.1 175967e06b fix(portals): a collection series never passes as the resolving movie
The collection's selected movie id is reported only while the shown item
is a movie, so a series with the same provider number cannot let a stale
external launch start over it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:36:08 +02:00
4grayandClaude Fable 5.1 fad77eda18 fix(portals): ninth review round and the spec typecheck
- The Favorites/Recent Stalker detail wires the menu's external launch
  and progress reset to collection-owned actions.
- The Stalker search host passes its pending-start state to the detail,
  so the reset row is disabled while a launch resolves.
- A rejected forced Stalker episode launch is logged and reported.
- The spec mocks of the external playback handle are signals, as the
  contract types them (CI spec typecheck).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:27:15 +02:00
4grayandClaude Opus 5.5 8e1cb05913 test(perf): add the serial-depth fields to the J3 IPC capture fixture (#1797)
#1773 added `ambiguousTimelineCompletions` and `timeline` to
`JourneyMainIpcCaptureState`, while #1774 merged the J3 playback record
spec with a fixture of the old shape, so the spec no longer type-checks
(TS2739). The harness runs it through tsx without type checking, so CI
stayed green.

The timeline holds one start per counted call, matching `callsByMethod`
and `callsBeforeSentinel`, so the fixture stays a capture a real run
could produce.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:20:32 +02:00
4grayandClaude Fable 5.1 23b70c524f fix(portals): keep a forced Stalker episode launch pending until it starts
The launch is awaited inside the start, so the pending state covers the
close of the previous player and the launch itself instead of clearing
as soon as the launch was kicked off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:07:48 +02:00
4grayandClaude Fable 5.1 d0fe593f92 fix(portals): eighth review round on the cinematic details
- The external player rows of every details menu follow the managed
  external player capability instead of the downloads availability.
- An explicit Stalker movie launch is a pending start for the selected
  movie while its stream resolves, so the reset row is disabled meanwhile.
- The resume clock formatter moves into the presentation helpers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 12:03:01 +02:00
4grayandClaude Fable 5.1 4e17c0533b fix(portals): count a pending Stalker start for its own series only
A start still resolving its stream for a series the view has since left
no longer keeps the new series' reset row disabled.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 11:57:31 +02:00
4grayandClaude Fable 5.1 aaae2b0572 fix(portals): seventh review round on the cinematic details
- The shared movie menu offers the external player in provider-only
  mode too; that mode hides local/download controls, not the provider's
  stream in MPV/VLC.
- The movie and Stalker series reset-progress rows are also disabled
  while a start is still resolving its stream, so a slow create_link
  cannot recreate a just-cleared row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 11:48:59 +02:00
d677fbaf8c perf(electron): look up the login shell PATH without blocking the main thread (#1784)
* perf(electron): look up the login shell PATH without blocking the main thread

fix-path ran $SHELL -ilc env synchronously right after the first load.
With a typical zsh profile that held the main thread for 1-2 s, while the
database worker's ready message and the renderer's first IPC calls waited,
so the launch journey's first card came that much later. Use shell-path's
async shellPath() with fix-path's fallback, so the resulting PATH is the
same and the main thread stays free.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(perf): name the PR that made the login shell PATH lookup async

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): let bare-name player spawns wait for the login shell PATH

With the lookup now asynchronous, an external player launched (or the
Linux embedded MPV support check, which runs and caches a bare
`mpv --version`) within the first seconds could see the inherited PATH.
The OPEN_MPV_PLAYER / OPEN_VLC_PLAYER handlers and every embedded MPV
handler now await waitForLoginShellPath() (settled lookup, at most 10 s,
immediate on Windows), restoring the guarantee the blocking lookup gave.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): wait for the login shell PATH only for bare-name spawns

External players wait only when they resolve to a bare name (no
configured path, no well-known install found); a path to an executable
starts at once. Embedded MPV waits only on Linux and only for support and
prepare, which run the cached bare-name `mpv --version` check; sessions
and controls never wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): wait for the login shell PATH only before the mpv probe

Embedded MPV support and prepare waited on every Linux call, although
getSupport() returns before the bare-name `mpv --version` probe for the
frame-copy engine, native Wayland, a disabled feature or a cached result.
willProbeLinuxMpvExecutable() now gates the wait on the probe actually
running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): stop waiting for a login shell that already timed out once

After the first wait for a hung `$SHELL -ilc env` runs out, later
bare-name player launches and Linux mpv probes proceed at once instead
of each waiting the full limit again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): bound login shell PATH waits by the lookup's own budget

Replace the latch on the first expired wait with a deadline set when the
lookup starts (10 s). Every wait ends when the lookup settles or the
deadline passes: a launch retried while the shell is still within its
budget waits for the PATH again, and once the budget is spent no launch
waits, so a hung shell still delays at most the first seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): re-probe a missing mpv once a late login shell answers

When the PATH lookup runs out of budget, the Linux embedded MPV support
check probes `mpv --version` with the inherited PATH and caches a
missing result for the rest of the session. waitForLoginShellPath() now
reports whether the lookup settled; after a timed-out wait the handler
forgets a cached "missing" once the lookup finishes, so the next support
check probes again with the login shell PATH.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): share one deadline among waits before the PATH lookup starts

A bare-name launch that waited before the lookup was scheduled started
its own 10 s limit, so while startup was stuck every retry paid the full
delay again. The first early wait now sets the shared deadline; the
lookup still replaces it with its own budget when it starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): re-probe mpv after a late login shell PATH either way

A Linux mpv probe that ran on the inherited PATH can be wrong in both
directions: the login shell PATH may add mpv or drop the directory the
inherited one found it in. forgetLinuxMpvExecutableProbe() now clears a
found result as well as a missing one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): skip the login shell PATH wait for Flatpak host launches

In Flatpak, players start through `flatpak-spawn --host`, which resolves
the name with the host's PATH; the sandbox's login shell lookup cannot
change it. The launch handlers now decide from the same launch context
the player uses: no wait in flatpak-host mode, otherwise only for a bare
player name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 11:48:06 +02:00
4grayandClaude Fable 5.1 5b8717b69c fix(portals): sixth review round on the cinematic details
- A forced Stalker episode launch compares against a generation captured
  after the inline close instead of the one that close retired, so the
  menu's MPV/VLC action starts again while stale launches still drop.
- The Stalker movie guard reports the selected id only while a movie is
  on screen; a series with the same provider number never passes it.
- The series reset-progress row is disabled while an episode plays or
  launches, independent of the bulk watched action's state.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 11:34:17 +02:00
4grayandClaude Fable 5.1 2bc13c5dd3 test(e2e): point the header-Back spec at the Episodes heading
The series page's section heading is "Episodes" with its own test id
since the cinematic redesign; the spec from master still measured
".section-title" and the old "Seasons and Episodes" translation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 11:29:43 +02:00
4gray 87d7e1d46c Merge remote-tracking branch 'origin/master' into claude/iptvnator-vod-hero-redesign-2c8950
# Conflicts:
#	apps/electron-backend-e2e/src/detail-back-lane.e2e.ts
#	apps/web-e2e/src/m3u-movie-details.e2e.ts
#	docs/architecture/iptvnator-ui-guidelines.md
#	libs/ui/components/src/lib/content-hero/content-hero.component.scss
#	libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.scss
2026-10-03 11:25:57 +02:00
4grayandClaude Fable 5.1 87cc85a54f fix(portals): fifth review round on the cinematic details
- Stalker movie and series menu launches in MPV/VLC close the title's
  own running external session first through the new shared
  replaceOwnedExternalSession(), cancelling when teardown is not
  confirmed or the selection moved on.
- The reset-progress row is disabled while an external player owns the
  position, on the shared and the Xtream movie menus.
- Every ISO comma-bearing country name stays whole in provider lists.
- The dashboard hero spec competes a favorite movie for a slot so the
  movie-title case is actually exercised.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 11:19:22 +02:00
4gray cb252940b2 fix(workspace): move detail Back into the header and drop the rail brand (#1789) 2026-10-03 11:17:34 +02:00
4gray 9c77e9e41a test(web-e2e): assert M3U movie metadata in the visible About block (#1791) 2026-10-03 11:17:16 +02:00
4grayandClaude Fable 5.1 026a69c14e fix(portals): drop a forced episode launch once the page moved on
Closing the previous external session takes time; a launch whose series
page is gone or shows another series by then no longer starts. The
service clears its bindings on destroy and exposes the page's
playlist:series owner for that check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 10:59:56 +02:00
4grayandClaude Fable 5.1 d79e6504a5 fix(portals): third review round on the cinematic details
- A forced MPV/VLC episode launch closes an episode of the same series
  that is still running externally before starting, as the movie flow
  does; a failed close keeps the running player.
- A Stalker external launch resolved after the user moved to another
  movie is dropped instead of launching the old stream or closing the
  new item's inline playback.
- The trailer's sound toggle is rendered by the hero above its content
  layer, so it can actually be clicked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 10:50:52 +02:00
4grayandClaude Fable 5.1 efd70b75e6 fix(portals): second review round on the cinematic details
- The movie menu's MPV/VLC launch is a regular route-owned start with
  the player forced: a running external session is replaced through the
  same guard instead of a second player starting beside it.
- The trailer-backdrop setting is shown for every player; it is a
  details-page feature, not a web-player control.
- The series menu matches the recent list by content type as well, so a
  movie sharing the provider id does not stand in for the series row,
  and the hide action follows the refreshed list instead of a permanent
  hidden marker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 10:32:22 +02:00
c9d169e3dc fix(dashboard): scroll a focused rail card fully into view (#1785)
* fix(dashboard): scroll a focused rail card fully into view

Chromium skips its focus scroll when 32px or more of the element already
shows, so Tab onto the last source card of a rail that overflows by less
than a card left it half-hidden under the edge fade. The rail track now
handles focusin and scrolls to the first card-start snap position that
reveals the whole card; a plain "nearest" scroll is not enough because
mandatory snapping can round it back (seen on the live channel rail).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): keep mouse clicks on partly hidden rail cards

A mouse press focuses the card link on mousedown. Revealing the card at
that moment could slide it from under the pointer when the target snap
position overshoots (the live channel rail moves 316px for a 306px
card), so the click landed elsewhere. The rail now reveals a card only
for keyboard and programmatic focus, using the CDK FocusMonitor origin.

Adds an Electron E2E that checks the final layout after snapping: Tab and
focus() leave the last source card fully visible, and a mouse press keeps
the rail still and still opens the source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): tell pointer focus apart without touching the DOM

FocusMonitor toggles cdk-*-focused classes on the monitored track, so a
mouse press on a source card mutated the DOM before the click. The J2
"open a source" performance journey rejects iterations with DOM activity
between its settle snapshot and the click. Read the input modality from
the CDK InputModalityDetector in a focusin handler instead: it only
listens, so the rail stays untouched until the click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): reveal script-focused rail cards after a mouse click

The input modality stays "mouse" after any click, so a later focus() on
a partly hidden card left it clipped. The rail now skips the reveal only
for focus caused by a press inside the track: the focus has to arrive
within 100ms of that pointerdown (650ms for touch, whose focus comes
with the tap's compatibility mouse events, as in the CDK FocusMonitor).
Only event timestamps are compared, so the DOM still stays untouched
before the click.

The E2E now clicks elsewhere before the script focus, and unit tests
cover a tap and focus() after an earlier mouse press.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): keep an over-wide focused rail card in view

In a window narrower than a card (or under zoom), a focused card could
never fit, so its own snap offset fell short of the needed scroll and
the rail jumped to the next card's snap point, moving the focused card
offscreen. Such a card is now aligned at its own start instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(dashboard): select rail internals through stable test ids

The dashboard contract makes data-test-id hooks the supported Electron
E2E selector surface. The rail now exposes -viewport, -track and
-card-link hooks next to its existing ones, and the focus E2E selects
those (and the rail heading by role) instead of internal class names.
The dashboard doc lists the new hooks and records the focus-reveal
contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:24:57 +02:00