* fix(playback): harden embedded MPV polling loop and IPC error visibility
The 500ms session polling interval called refreshSession() unguarded:
a throwing addon call (getAddon/getSessionSnapshot) escaped the interval
callback as an uncaughtException in the main process on every tick.
Wrap each refresh in try-catch, log the first failure only, and resume
session updates once the addon recovers.
Embedded MPV IPC handlers also forwarded service calls without any
error handling, unlike every other events module. The renderer swallows
these rejections by design (guardIpc), so addon errors were completely
invisible. Route all registrations through a wrapper that logs the
failing channel in the main process before rethrowing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(playback): track poll-failure log suppression per session
A healthy session in the same poll tick reset the shared
pollFailureLogged flag before the failing session was processed, so a
mixed healthy/failing session set logged the failure on every 500ms
tick — the flooding the flag was meant to prevent. Track logged
failures per session id instead and clean entries up on dispose.
Addresses Greptile/Codex review feedback on #1041.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(epg): dedupe concurrent fetches and await worker termination
Two concurrent fetchEpgFromUrl calls for the same URL spawned two
workers parsing and writing the same EPG data, with the second one
overwriting the first one's entry in the workers map and leaking that
worker. Share the in-flight promise instead of spawning a competitor.
worker.terminate() was also fired without awaiting it in every settle
path. A terminated-but-still-running worker can keep holding the SQLite
lock, blocking the next EPG operation. All settle paths now resolve or
reject only after the worker thread has really exited; the settle guard
runs first so the worker's own exit event cannot hijack the outcome.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(epg): close review gaps in fetch dedupe and clear sequencing
- Check the in-flight map before the fetched-URL shortcut: a completed
fetch is added to fetchedUrls while its worker is still terminating,
and a concurrent request must keep awaiting that window instead of
resolving early.
- clearEpgData now resolves only after every interrupted fetch worker
has terminated too, not just the clear worker — they may still hold
the SQLite lock the caller expects to be free.
Addresses Codex/Greptile review feedback on #1040.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
When the reuse-instance setting is enabled, the spawned MPV/VLC process
is stored globally and kept alive (non-detached, piped stdio) so follow-up
streams can be loaded into it. Nothing killed that process on app quit,
so every app restart left an orphaned player running in the background.
Register an explicit shutdown in the before-quit hook that kills the
stored process and stops position polling, mirroring the existing
embedded-MPV shutdown path.
Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Adds experimental embedded MPV support for Windows and Linux, expands packaging/runtime validation, and updates CI coverage for the cross-platform native addon.
Split EPG IPC orchestration, worker lifecycle, and query logic into focused services. Harden clear-worker lifecycle after review with timeout/exit handling and regression coverage.
Split the Electron external-player IPC monolith into focused launch-context, playback-request, runtime, MPV session, and VLC session modules. Includes Greptile follow-up fixes for Homebrew Cask VLC path resolution and VLC spawn-error promise handling, with regression coverage.
- 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