From a05a698774b60fd5c3e9cb8f5886196c28955207 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sat, 25 Apr 2026 19:45:02 -0700 Subject: [PATCH] fix(mpv): avoid crash notification on video close --- ...ion-when-closing-launcher-managed-video.md | 54 +++++++++++++++++++ changes/296-mpv-close-crash-notification.md | 4 ++ plugin/subminer/lifecycle.lua | 9 ++-- plugin/subminer/process.lua | 2 + scripts/test-plugin-start-gate.lua | 14 ++++- 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 backlog/tasks/task-296 - Suppress-crash-notification-when-closing-launcher-managed-video.md create mode 100644 changes/296-mpv-close-crash-notification.md diff --git a/backlog/tasks/task-296 - Suppress-crash-notification-when-closing-launcher-managed-video.md b/backlog/tasks/task-296 - Suppress-crash-notification-when-closing-launcher-managed-video.md new file mode 100644 index 00000000..b2a18f89 --- /dev/null +++ b/backlog/tasks/task-296 - Suppress-crash-notification-when-closing-launcher-managed-video.md @@ -0,0 +1,54 @@ +--- +id: TASK-296 +title: Suppress crash notification when closing launcher-managed video +status: Done +assignee: [] +created_date: '2026-04-25 23:12' +updated_date: '2026-04-26 02:44' +labels: + - bug + - launcher + - mpv +dependencies: [] +priority: high +--- + +## Description + + +Investigate and fix regression where closing a running mpv video causes SubMiner/Electron service crash notification (`/SubMiner has encountered a fatal error and was closed.`). Not present on origin/main/v0.12.0 path. + + +## Acceptance Criteria + +- [x] #1 Closing a launcher-managed video stops the overlay/app without desktop crash notification. +- [x] #2 Regression test covers the shutdown path that caused the notification. +- [x] #3 Relevant launcher/app tests pass. + + +## Implementation Plan + + +1. Confirm notification source from local crash metadata and mpv/app logs. +2. Add regression coverage for mpv quit/shutdown lifecycle helper spawning. +3. Update mpv Lua lifecycle to avoid Electron helper subprocesses during quit/shutdown while preserving normal end-file hide behavior. +4. Run plugin tests and changelog lint. + + +## Implementation Notes + + +Crash records in ~/.cache/drkonqi show SIGBUS in Electron NetworkService utility process for SubMiner AppImage. mpv log shows shutdown starts two `/home/sudacode/.local/bin/SubMiner.AppImage --hide-visible-overlay` subprocesses and kills them during close. Root cause is mpv plugin spawning Electron control helpers during quit/shutdown. + +Follow-up after retest: installed plugin matched source patch and no close-time hide command was spawned. New mpv log shows the initial `/home/sudacode/.local/bin/SubMiner.AppImage --start ...` subprocess remains owned by mpv for the whole playback and is killed when mpv quits. New DrKonqi crash at 2026-04-25 16:44 again shows SIGBUS in Electron NetworkService from that AppImage mount. Need detach the long-lived plugin-launched `--start` app process from mpv. + +Second fix: plugin-launched `--start` now includes `--background`, using SubMiner's existing background relaunch path so mpv owns only a short-lived starter process rather than the long-running Electron app. Ran `make install-plugin` so ~/.config/mpv/scripts/subminer now contains both lifecycle and background-start fixes. Full `scripts/test-plugin-start-gate.lua` is currently blocked by an unrelated dirty-worktree primary subtitle bar binding test from TASK-297. + + +## Final Summary + + +Changed the mpv Lua lifecycle so `shutdown` no longer spawns a `--hide-visible-overlay` helper, and `end-file` skips that helper when mpv reports `reason = "quit"`. Also changed plugin-launched `--start` to include `--background`, so mpv owns only SubMiner's short background launcher process instead of the long-running Electron/AppImage process. This addresses both observed crash sources: close-time helper commands and mpv killing the main SubMiner child process at quit. Installed the updated plugin into `~/.config/mpv/scripts/subminer` with `make install-plugin`, and the user confirmed the latest close no longer produced the notification. + +Tests: `lua scripts/test-plugin-start-gate.lua` initially proved the shutdown regression failed before the lifecycle fix; full start-gate is currently affected by other dirty work in this file. Passing checks for this commit: `lua scripts/test-plugin-lua-compat.lua && lua scripts/test-plugin-binary-windows.lua`; `bun run changelog:lint`. + diff --git a/changes/296-mpv-close-crash-notification.md b/changes/296-mpv-close-crash-notification.md new file mode 100644 index 00000000..e29dd8e3 --- /dev/null +++ b/changes/296-mpv-close-crash-notification.md @@ -0,0 +1,4 @@ +type: fixed +area: mpv + +- Stopped mpv from owning long-running SubMiner AppImage subprocesses during playback shutdown, preventing desktop crash notifications when closing video. diff --git a/plugin/subminer/lifecycle.lua b/plugin/subminer/lifecycle.lua index eac8dc08..2ffd5de2 100644 --- a/plugin/subminer/lifecycle.lua +++ b/plugin/subminer/lifecycle.lua @@ -73,10 +73,6 @@ function M.create(ctx) aniskip.clear_aniskip_state() hover.clear_hover_overlay() process.disarm_auto_play_ready_gate() - if state.overlay_running then - subminer_log("info", "lifecycle", "mpv shutting down, hiding SubMiner overlay") - process.hide_visible_overlay() - end end local function register_lifecycle_hooks() @@ -85,10 +81,11 @@ function M.create(ctx) mp.register_event("file-loaded", function() hover.clear_hover_overlay() end) - mp.register_event("end-file", function() + mp.register_event("end-file", function(event) process.disarm_auto_play_ready_gate() hover.clear_hover_overlay() - if state.overlay_running then + local reason = type(event) == "table" and event.reason or nil + if state.overlay_running and reason ~= "quit" then process.hide_visible_overlay() end end) diff --git a/plugin/subminer/process.lua b/plugin/subminer/process.lua index eb4e125d..b8d543ad 100644 --- a/plugin/subminer/process.lua +++ b/plugin/subminer/process.lua @@ -186,6 +186,8 @@ function M.create(ctx) end if action == "start" then + table.insert(args, "--background") + local backend = resolve_backend(overrides.backend) if backend and backend ~= "" then table.insert(args, "--backend") diff --git a/scripts/test-plugin-start-gate.lua b/scripts/test-plugin-start-gate.lua index 67893c0f..3a149ed6 100644 --- a/scripts/test-plugin-start-gate.lua +++ b/scripts/test-plugin-start-gate.lua @@ -499,10 +499,10 @@ local function count_property_set(property_sets, name, value) return count end -local function fire_event(recorded, name) +local function fire_event(recorded, name, ...) local listeners = recorded.events[name] or {} for _, listener in ipairs(listeners) do - listener() + listener(...) end end @@ -768,6 +768,7 @@ do fire_event(recorded, "file-loaded") local start_call = find_start_call(recorded.async_calls) assert_true(start_call ~= nil, "auto-start should issue --start command") + assert_true(call_has_arg(start_call, "--background"), "auto-start should launch SubMiner in background mode") assert_true(call_has_arg(start_call, "--texthooker"), "auto-start should include --texthooker on the main --start command when enabled") assert_true(find_control_call(recorded.async_calls, "--texthooker") == nil, "auto-start should not issue a separate texthooker helper command") assert_true( @@ -1054,11 +1055,20 @@ do }) assert_true(recorded ~= nil, "plugin failed to load for shutdown-preserve-background scenario: " .. tostring(err)) fire_event(recorded, "file-loaded") + fire_event(recorded, "end-file", { reason = "quit" }) + assert_true( + find_control_call(recorded.async_calls, "--hide-visible-overlay") == nil, + "mpv quit end-file should not spawn hide-visible-overlay helper commands" + ) fire_event(recorded, "shutdown") assert_true( find_control_call(recorded.async_calls, "--stop") == nil, "mpv shutdown should not stop the background SubMiner process" ) + assert_true( + find_control_call(recorded.async_calls, "--hide-visible-overlay") == nil, + "mpv shutdown should not spawn hide-visible-overlay helper commands" + ) end do