mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-10 03:13:32 -07:00
feat(plugin): route restart feedback through playback feedback surface
- Show overlay loading OSD spinner during restart and keep it alive until overlay reports ready - Route restart progress/completion through notify_playback_feedback so overlay/both modes display in overlay - Delay "Restarted successfully" until show-visible-overlay completes - Add test-plugin-restart-feedback.lua covering the restart feedback flow
This commit is contained in:
@@ -10,6 +10,7 @@ breaking: true
|
|||||||
- Preserved character dictionary checking/building/importing/ready phases in overlay notification history and sent those phases to system notifications when `notificationType` is `both`.
|
- Preserved character dictionary checking/building/importing/ready phases in overlay notification history and sent those phases to system notifications when `notificationType` is `both`.
|
||||||
- Initialized the tray and visible overlay shell before deferred tokenization warmups finish on visible-overlay startup, while keeping playback paused until SubMiner reports autoplay readiness.
|
- Initialized the tray and visible overlay shell before deferred tokenization warmups finish on visible-overlay startup, while keeping playback paused until SubMiner reports autoplay readiness.
|
||||||
- Kept playback feedback such as subtitle visibility, subtitle track, subtitle delay, and AniSkip prompt/skip text on overlay/OSD surfaces only; desktop/system notifications are reserved for real notifications like mined cards, errors, and updates.
|
- Kept playback feedback such as subtitle visibility, subtitle track, subtitle delay, and AniSkip prompt/skip text on overlay/OSD surfaces only; desktop/system notifications are reserved for real notifications like mined cards, errors, and updates.
|
||||||
|
- Routed mpv-plugin restart feedback through the configured overlay/OSD feedback surface so `overlay` and `both` notification modes show restart progress and completion in the overlay, while keeping the loading OSD spinner visible until the overlay reports ready.
|
||||||
- Reused the active primary/secondary subtitle mode overlay notification while cycling modes so rapid toggles update one card instead of stacking duplicate feedback.
|
- Reused the active primary/secondary subtitle mode overlay notification while cycling modes so rapid toggles update one card instead of stacking duplicate feedback.
|
||||||
- Updated repeated progress notifications such as subsync syncing in place so their spinner stays live instead of flickering on every tick.
|
- Updated repeated progress notifications such as subsync syncing in place so their spinner stays live instead of flickering on every tick.
|
||||||
- Stabilized overlay startup notifications so queued progress updates do not replay the card entrance animation or trigger macOS pass-through hover flicker after the loading OSD hands off to overlay notifications.
|
- Stabilized overlay startup notifications so queued progress updates do not replay the card entrance animation or trigger macOS pass-through hover flicker after the loading OSD hands off to overlay notifications.
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -875,14 +875,22 @@ function M.create(ctx)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function show_restart_feedback(message)
|
||||||
|
notify_playback_feedback(message, function()
|
||||||
|
show_osd(message)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
start_overlay_loading_osd()
|
||||||
subminer_log("info", "process", "Restarting overlay...")
|
subminer_log("info", "process", "Restarting overlay...")
|
||||||
show_osd("Restarting...")
|
show_restart_feedback("Restarting...")
|
||||||
|
|
||||||
run_control_command_async("stop", nil, function(ok, result)
|
run_control_command_async("stop", nil, function(ok, result)
|
||||||
if not ok then
|
if not ok then
|
||||||
local reason = result and result.stderr or "unknown error"
|
local reason = result and result.stderr or "unknown error"
|
||||||
subminer_log("warn", "process", "Restart stop command failed: " .. reason)
|
subminer_log("warn", "process", "Restart stop command failed: " .. reason)
|
||||||
show_osd("Restart failed")
|
stop_overlay_loading_osd()
|
||||||
|
show_restart_feedback("Restart failed")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -917,14 +925,17 @@ function M.create(ctx)
|
|||||||
"process",
|
"process",
|
||||||
"Overlay start failed: " .. (error or (result and result.stderr) or "unknown error")
|
"Overlay start failed: " .. (error or (result and result.stderr) or "unknown error")
|
||||||
)
|
)
|
||||||
show_osd("Restart failed")
|
stop_overlay_loading_osd()
|
||||||
|
show_restart_feedback("Restart failed")
|
||||||
else
|
else
|
||||||
wait_for_app_ping_state(true, "own the single-instance lock", function()
|
wait_for_app_ping_state(true, "own the single-instance lock", function()
|
||||||
run_control_command_async("show-visible-overlay")
|
run_control_command_async("show-visible-overlay", nil, function()
|
||||||
show_osd("Restarted successfully")
|
show_restart_feedback("Restarted successfully")
|
||||||
|
end)
|
||||||
end, function()
|
end, function()
|
||||||
run_control_command_async("show-visible-overlay")
|
run_control_command_async("show-visible-overlay", nil, function()
|
||||||
show_osd("Restarted successfully")
|
show_restart_feedback("Restarted successfully")
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -933,7 +944,8 @@ function M.create(ctx)
|
|||||||
ensure_texthooker_running(function() end)
|
ensure_texthooker_running(function() end)
|
||||||
end
|
end
|
||||||
end, function()
|
end, function()
|
||||||
show_osd("Restart failed")
|
stop_overlay_loading_osd()
|
||||||
|
show_restart_feedback("Restart failed")
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package.path = "plugin/subminer/?.lua;" .. package.path
|
||||||
|
|
||||||
|
local process_module = require("process")
|
||||||
|
local options_helper = require("options")
|
||||||
|
|
||||||
|
local function assert_true(condition, message)
|
||||||
|
if condition then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
error(message or "assert_true failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function has_arg(args, target)
|
||||||
|
for _, value in ipairs(args or {}) do
|
||||||
|
if value == target then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_restart_runtime(config)
|
||||||
|
config = config or {}
|
||||||
|
local recorded = {
|
||||||
|
async_calls = {},
|
||||||
|
feedback = {},
|
||||||
|
osd = {},
|
||||||
|
periodic_timers = {},
|
||||||
|
}
|
||||||
|
local app_ping_index = 0
|
||||||
|
local opts = {
|
||||||
|
binary_path = "/tmp/SubMiner",
|
||||||
|
socket_path = "/tmp/subminer-socket",
|
||||||
|
backend = "x11",
|
||||||
|
osd_messages = config.osd_messages == true,
|
||||||
|
texthooker_enabled = false,
|
||||||
|
log_level = "info",
|
||||||
|
}
|
||||||
|
local state = {
|
||||||
|
binary_path = opts.binary_path,
|
||||||
|
overlay_running = true,
|
||||||
|
texthooker_running = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
local mp = {}
|
||||||
|
|
||||||
|
function mp.command_native_async(command, callback)
|
||||||
|
recorded.async_calls[#recorded.async_calls + 1] = command
|
||||||
|
local args = command.args or {}
|
||||||
|
if has_arg(args, "--playback-feedback") then
|
||||||
|
recorded.feedback[#recorded.feedback + 1] = args[#args]
|
||||||
|
callback(true, { status = 0, stdout = "", stderr = "" }, nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if has_arg(args, "--app-ping") then
|
||||||
|
app_ping_index = app_ping_index + 1
|
||||||
|
local statuses = config.app_ping_statuses or { 1, 0 }
|
||||||
|
local status = statuses[app_ping_index] or statuses[#statuses]
|
||||||
|
callback(status == 0, { status = status, stdout = "", stderr = "" }, nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
callback(true, { status = 0, stdout = "", stderr = "" }, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mp.add_timeout(_, callback)
|
||||||
|
return {
|
||||||
|
killed = false,
|
||||||
|
kill = function(self)
|
||||||
|
self.killed = true
|
||||||
|
end,
|
||||||
|
callback = callback,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function mp.add_periodic_timer()
|
||||||
|
local timer = {
|
||||||
|
killed = false,
|
||||||
|
kill = function(self)
|
||||||
|
self.killed = true
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
recorded.periodic_timers[#recorded.periodic_timers + 1] = timer
|
||||||
|
return timer
|
||||||
|
end
|
||||||
|
|
||||||
|
function mp.get_property(name)
|
||||||
|
if name == "input-ipc-server" then
|
||||||
|
return opts.socket_path
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
function mp.get_time()
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function mp.set_property_native() end
|
||||||
|
|
||||||
|
local process = process_module.create({
|
||||||
|
mp = mp,
|
||||||
|
utils = {},
|
||||||
|
opts = opts,
|
||||||
|
state = state,
|
||||||
|
binary = {
|
||||||
|
ensure_binary_available = function()
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
environment = {
|
||||||
|
is_linux = function()
|
||||||
|
return false
|
||||||
|
end,
|
||||||
|
detect_backend = function()
|
||||||
|
return "x11"
|
||||||
|
end,
|
||||||
|
resolve_subminer_config_dir = function()
|
||||||
|
return "/tmp"
|
||||||
|
end,
|
||||||
|
join_path = function(...)
|
||||||
|
return table.concat({ ... }, "/")
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
options_helper = options_helper,
|
||||||
|
log = {
|
||||||
|
normalize_log_level = function(level)
|
||||||
|
return level or "info"
|
||||||
|
end,
|
||||||
|
subminer_log = function() end,
|
||||||
|
show_osd = function(message, options)
|
||||||
|
if opts.osd_messages or (options and options.force == true) then
|
||||||
|
recorded.osd[#recorded.osd + 1] = message
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
process = process,
|
||||||
|
recorded = recorded,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local runtime = create_restart_runtime({ osd_messages = false })
|
||||||
|
|
||||||
|
runtime.process.restart_overlay()
|
||||||
|
|
||||||
|
assert_true(
|
||||||
|
runtime.recorded.osd[1] == "Overlay loading |",
|
||||||
|
"restart should show the forced overlay loading OSD while the overlay reloads"
|
||||||
|
)
|
||||||
|
assert_true(
|
||||||
|
#runtime.recorded.periodic_timers == 1,
|
||||||
|
"restart should refresh the forced overlay loading OSD while the overlay reloads"
|
||||||
|
)
|
||||||
|
assert_true(
|
||||||
|
runtime.recorded.feedback[1] == "Restarting...",
|
||||||
|
"restart should route progress through playback feedback"
|
||||||
|
)
|
||||||
|
assert_true(
|
||||||
|
runtime.recorded.feedback[#runtime.recorded.feedback] == "Restarted successfully",
|
||||||
|
"restart should route success through playback feedback"
|
||||||
|
)
|
||||||
|
assert_true(
|
||||||
|
runtime.recorded.periodic_timers[1].killed ~= true,
|
||||||
|
"restart should keep the loading OSD alive until the overlay reports ready"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
print("plugin restart feedback tests: OK")
|
||||||
Reference in New Issue
Block a user