Skip to content

fix(parental-lock): close external players on relock, count them as playback, release stalled video - #2256

Open
mahmutyum wants to merge 2 commits into
4gray:masterfrom
mahmutyum:fix/parental-relock-external-players
Open

mahmutyum wants to merge 2 commits into
4gray:masterfrom
mahmutyum:fix/parental-relock-external-players

Conversation

@mahmutyum

@mahmutyum mahmutyum commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Three parental-lock gaps around players that render outside the page, plus one display-sleep leak that also defers the relock.

  1. Relock left MPV/VLC running. "Lock now" and the idle relock stepped off in-app playback, but an MPV/VLC window opened while unlocked kept playing locked content. Only Xtream Live closed its own sessions.
  2. Idle relock ignored Embedded MPV and MPV/VLC. The only busy probe was <video> keep-awake plus <audio>, so a film in those players was cut off after 15 minutes.
  3. A stream that died after starting held keep-awake forever. Starved MSE fires waiting and never pause/ended, so the display never slept and the relock stayed deferred.

Changes

  • New ParentalLockExternalSessions (apps/web/src/app/services/parental-lock-external-sessions.ts), started by the enforcement service, tracks sessions from onExternalPlayerSessionUpdate:
    • Relock: a session whose media was opened while unlocked (a launch, or an in-place switch with a changed stream URL; status reports do not count) is closed when the lock store is unreadable or the session's source has a locked category. The source is contentInfo.playlistId, else the source route of the launch; a launch from a global page counts as any source. Sessions carry no category, so this is per source and fails closed. A session opened while locked came from the filtered catalog and keeps playing. A launch first reported after a relock it started before is treated as opened while unlocked.
    • Close mirrors XtreamExternalLiveSessions.enforce: closeExternalPlayerSession(id, true), dock dismissal first, a re-close once a launch has a closer, a 1 s retry on rejection, and the dismissal undone when the app is unlocked before the close lands.
    • Reload: on start the page reads the sessions still open in the main process (new listExternalPlayerSessions bridge, ExternalPlayerSessionRegistry.listOpenSessions()). A session that started before the page counts as opened while unlocked, with an unknown source, so a player left running by a reloaded or crashed renderer is closed under the same rule.
    • Ownership: ParentalLockSessionOwners (libs/services) lets a feature that knows its sessions' categories claim them. Xtream Live does, so it keeps closing only withheld channels.
    • Busy probe: Embedded MPV counts while any session is playing (two with multiview). An MPV/VLC film or episode counts while its reported position moved in the last 15 s, so a pause lets the timer run. Players that report no position (live MPV/VLC, M3U films without contentInfo, Flatpak MPV without the socket bridge) do not count: they cannot report a pause, and a paused window must not keep the app unlocked indefinitely.
  • PlaybackKeepAwakeService: a tracked video that fires waiting/stalled and does not advance currentTime for 60 s is released. A video that moved is checked again until playing reports it resumed, and the next playing tracks a released video again.
  • ParentalLockLockStore.hasLocks(playlistId | null).
  • XtreamLiveOwner helpers moved to xtream-live-owner.ts and re-exported. This is behaviour-neutral and only keeps the service under the 400-line limit.

Docs

  • docs/architecture/parental-lock.md: new "External players" section, the product rule on playback as interaction, and the Files list.
  • docs/architecture/player-controls-contract.md: stall release under "Display sleep during playback".
  • Release note: .changes/parental-lock-external-players.md.

Validation

  • New and updated tests fail on the old code and pass with the fix:
    • web: parental-lock-external-sessions.spec.ts, parental-lock-enforcement.service.spec.ts, playback-keep-awake.service.spec.ts
    • services: parental-lock-lock-store.service.spec.ts
    • Xtream feature: xtream-external-live-sessions.service.spec.ts
  • New Electron E2E parental-lock-external-player.e2e.ts. Real IPC and session registry, with the MPV process replaced by a quiet child. A session opened while unlocked from a source with a locked category is closed on Lock now. A session opened while locked survives an unlock and the next relock. A player opened while unlocked is closed after a renderer reload. It fails without the fix.
  • Unit suites:
    • web 1159/1159 (plus the parental-lock specs added since)
    • electron-backend 3264/3264
    • portal-xtream-feature 890/890
    • services: all parental-lock specs pass. One DatabaseService browser guards case fails locally on Node 26; it fails on unmodified master too.
  • Existing E2E: Electron parental-lock-pin-dialog 2/2, web parental-lock-ui (Chromium) 3/3.
  • Lint: no new warnings on the touched projects. typecheck:web and typecheck:backend clean. release:notes:validate and agents:validate pass.

Known limitations

  • Per-source closing also closes an unlocked item when its source has other locked categories. The session does not carry its category, and a lookup at relock time could hang.
  • Embedded MPV busy state is rebuilt from session updates, so it is empty right after a renderer reload until the next update.

…layback, release stalled video

- A relock closes an MPV/VLC session whose media was opened while
  unlocked when its source has a locked category (any source, when it
  cannot be told) or the lock store is unreadable. Sessions opened while
  locked keep playing. Xtream Live claims its own sessions through
  ParentalLockSessionOwners and keeps closing only withheld categories.
  A session that could not be closed before an unlock is shown again.
- The idle relock counts Embedded MPV while playing and an MPV/VLC film
  or episode while its reported position moves; players that report no
  position (live, M3U films, Flatpak MPV) cannot report a pause and do
  not hold the lock open.
- Keep-awake releases a video that stalls without advancing for 60 s and
  keeps checking one that advanced until playing reports it resumed, so a
  dead stream no longer pins the display or defers the relock.
@greptile-apps

greptile-apps Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new blocking issues were found.

Summary

The latest changes recover MPV/VLC sessions after a renderer reload so the parental lock can close players left running by the old page.

  • External players now follow relocks and count toward playback activity.
  • Frozen web videos stop holding the display awake.

The previous unnumbered reload-tracking finding is addressed. No new actionable issues were found.

Reviews (2) · Last reviewed commit: "fix(parental-lock): close players a relo..." · Reviewed by Greptile

@codecov

codecov Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.70053% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.00%. Comparing base (ff90ccb) to head (a6bd2f1).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...rc/app/services/parental-lock-external-sessions.ts 89.74% 4 Missing and 8 partials ⚠️
.../lib/parental-lock/parental-lock-session-owners.ts 25.00% 6 Missing ⚠️
apps/electron-backend/src/app/api/main.preload.ts 0.00% 2 Missing ⚠️
...s/electron-backend/src/app/events/player.events.ts 50.00% 1 Missing ⚠️
...re/src/lib/live-stream-layout/xtream-live-owner.ts 85.71% 0 Missing and 1 partial ⚠️
libs/shared/interfaces/src/lib/ipc-commands.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2256      +/-   ##
==========================================
+ Coverage   81.98%   82.00%   +0.01%     
==========================================
  Files        1921     1924       +3     
  Lines      102911   103089     +178     
  Branches    24419    25223     +804     
==========================================
+ Hits        84376    84539     +163     
- Misses      11112    11122      +10     
- Partials     7423     7428       +5     
Flag Coverage Δ
unit 82.00% <87.70%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

A renderer reload or crash cleared the tracked sessions while MPV/VLC kept
running. The page now reads the open sessions from the main process on
start, and treats any session that started before it as opened while
unlocked with an unknown source, so the relock rule still closes it.
@mahmutyum

Copy link
Copy Markdown
Contributor Author

@greptileai

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant