mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 00:55:16 -07:00
fix: managed playback overlay lifecycle for launcher-owned sessions
- Remove --background from launcher-owned mpv starts; quit only non-tray/non-background managed sessions - Defer autoplay-ready signal until overlay window content is loaded; retry after flush - Retry socket availability before auto-starting overlay (up to 25 attempts, 200ms apart) - Extract warm tokenization signal into autoplay-tokenization-warm-release with stale-media guard - Queue second-instance commands until app ready runtime completes - Guard globalShortcut cleanup with isAppReady check to avoid pre-ready crash - Recognize "osx" as a macOS platform alias in Lua environment detection
This commit is contained in:
@@ -18,8 +18,14 @@ function M.create(ctx)
|
||||
|
||||
local function is_macos()
|
||||
local platform = mp.get_property("platform") or ""
|
||||
if platform == "macos" or platform == "darwin" then
|
||||
return true
|
||||
if platform ~= "" then
|
||||
local normalized = platform:lower()
|
||||
if normalized == "macos" or normalized == "darwin" or normalized == "osx" then
|
||||
return true
|
||||
end
|
||||
if normalized == "windows" or normalized == "win32" or normalized == "linux" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local ostype = os.getenv("OSTYPE") or ""
|
||||
return ostype:find("darwin") ~= nil
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
local M = {}
|
||||
|
||||
local AUTO_START_SOCKET_RETRY_DELAY_SECONDS = 0.2
|
||||
local AUTO_START_SOCKET_RETRY_MAX_ATTEMPTS = 25
|
||||
|
||||
function M.create(ctx)
|
||||
local mp = ctx.mp
|
||||
local opts = ctx.opts
|
||||
@@ -52,6 +55,11 @@ function M.create(ctx)
|
||||
return options_helper.coerce_bool(raw_auto_start, false)
|
||||
end
|
||||
|
||||
local function next_auto_start_retry_generation()
|
||||
state.auto_start_retry_generation = (state.auto_start_retry_generation or 0) + 1
|
||||
return state.auto_start_retry_generation
|
||||
end
|
||||
|
||||
local function rearm_managed_subtitle_defaults()
|
||||
if not process.has_matching_mpv_ipc_socket(opts.socket_path) then
|
||||
return false
|
||||
@@ -63,13 +71,58 @@ function M.create(ctx)
|
||||
return true
|
||||
end
|
||||
|
||||
local function start_overlay_when_socket_ready(generation, media_identity, same_media_loaded, attempt)
|
||||
if generation ~= state.auto_start_retry_generation then
|
||||
return
|
||||
end
|
||||
if media_identity ~= nil and state.current_media_identity ~= media_identity then
|
||||
return
|
||||
end
|
||||
if not resolve_auto_start_enabled() then
|
||||
schedule_aniskip_fetch("file-loaded", 0)
|
||||
return
|
||||
end
|
||||
|
||||
local has_matching_socket = rearm_managed_subtitle_defaults()
|
||||
if not has_matching_socket then
|
||||
if attempt < AUTO_START_SOCKET_RETRY_MAX_ATTEMPTS then
|
||||
mp.add_timeout(AUTO_START_SOCKET_RETRY_DELAY_SECONDS, function()
|
||||
start_overlay_when_socket_ready(generation, media_identity, same_media_loaded, attempt + 1)
|
||||
end)
|
||||
return
|
||||
end
|
||||
subminer_log(
|
||||
"info",
|
||||
"lifecycle",
|
||||
"Skipping auto-start: input-ipc-server does not match configured socket_path"
|
||||
)
|
||||
schedule_aniskip_fetch("file-loaded", 0)
|
||||
return
|
||||
end
|
||||
|
||||
process.start_overlay({
|
||||
auto_start_trigger = true,
|
||||
socket_path = opts.socket_path,
|
||||
rearm_pause_until_ready = not same_media_loaded,
|
||||
})
|
||||
-- Give the overlay process a moment to initialize before querying AniSkip.
|
||||
schedule_aniskip_fetch("overlay-start", 0.8)
|
||||
end
|
||||
|
||||
local function on_file_loaded()
|
||||
local media_identity = resolve_media_identity()
|
||||
local retry_generation = next_auto_start_retry_generation()
|
||||
local previous_media_identity = state.current_media_identity
|
||||
local same_media_reload = (
|
||||
media_identity ~= nil
|
||||
and state.pending_reload_media_identity ~= nil
|
||||
and media_identity == state.pending_reload_media_identity
|
||||
)
|
||||
local same_media_loaded = (
|
||||
media_identity ~= nil
|
||||
and previous_media_identity ~= nil
|
||||
and media_identity == previous_media_identity
|
||||
)
|
||||
state.pending_reload_media_identity = nil
|
||||
state.current_media_identity = media_identity
|
||||
|
||||
@@ -92,32 +145,18 @@ function M.create(ctx)
|
||||
if not preserve_active_auto_start_gate then
|
||||
process.disarm_auto_play_ready_gate()
|
||||
end
|
||||
has_matching_socket = rearm_managed_subtitle_defaults()
|
||||
|
||||
if should_auto_start then
|
||||
if not has_matching_socket then
|
||||
subminer_log(
|
||||
"info",
|
||||
"lifecycle",
|
||||
"Skipping auto-start: input-ipc-server does not match configured socket_path"
|
||||
)
|
||||
schedule_aniskip_fetch("file-loaded", 0)
|
||||
return
|
||||
end
|
||||
|
||||
process.start_overlay({
|
||||
auto_start_trigger = true,
|
||||
socket_path = opts.socket_path,
|
||||
})
|
||||
-- Give the overlay process a moment to initialize before querying AniSkip.
|
||||
schedule_aniskip_fetch("overlay-start", 0.8)
|
||||
start_overlay_when_socket_ready(retry_generation, media_identity, same_media_loaded, 1)
|
||||
return
|
||||
end
|
||||
|
||||
rearm_managed_subtitle_defaults()
|
||||
schedule_aniskip_fetch("file-loaded", 0)
|
||||
end
|
||||
|
||||
local function on_shutdown()
|
||||
next_auto_start_retry_generation()
|
||||
aniskip.clear_aniskip_state()
|
||||
hover.clear_hover_overlay()
|
||||
process.disarm_auto_play_ready_gate()
|
||||
@@ -139,6 +178,8 @@ function M.create(ctx)
|
||||
state.pending_reload_media_identity = state.current_media_identity or resolve_media_identity()
|
||||
return
|
||||
end
|
||||
next_auto_start_retry_generation()
|
||||
state.current_media_identity = nil
|
||||
state.pending_reload_media_identity = nil
|
||||
if state.overlay_running and reason ~= "quit" then
|
||||
process.hide_visible_overlay()
|
||||
|
||||
@@ -207,7 +207,6 @@ function M.create(ctx)
|
||||
end
|
||||
|
||||
if action == "start" then
|
||||
table.insert(args, "--background")
|
||||
table.insert(args, "--managed-playback")
|
||||
|
||||
local backend = resolve_backend(overrides.backend)
|
||||
@@ -411,7 +410,15 @@ function M.create(ctx)
|
||||
if overrides.auto_start_trigger == true then
|
||||
subminer_log("debug", "process", "Auto-start ignored because overlay is already running")
|
||||
local socket_path = overrides.socket_path or opts.socket_path
|
||||
if not state.auto_play_ready_gate_armed then
|
||||
local should_pause_until_ready = (
|
||||
overrides.rearm_pause_until_ready == true
|
||||
and resolve_visible_overlay_startup()
|
||||
and resolve_pause_until_ready()
|
||||
and has_matching_mpv_ipc_socket(socket_path)
|
||||
)
|
||||
if should_pause_until_ready then
|
||||
arm_auto_play_ready_gate()
|
||||
elseif not state.auto_play_ready_gate_armed then
|
||||
disarm_auto_play_ready_gate()
|
||||
end
|
||||
local visibility_action = resolve_visible_overlay_startup()
|
||||
|
||||
@@ -37,6 +37,7 @@ function M.new()
|
||||
force_ready_overlay_restore = false,
|
||||
current_media_identity = nil,
|
||||
pending_reload_media_identity = nil,
|
||||
auto_start_retry_generation = 0,
|
||||
session_binding_generation = 0,
|
||||
session_binding_names = {},
|
||||
session_numeric_binding_names = {},
|
||||
|
||||
Reference in New Issue
Block a user