mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
450 lines
14 KiB
Lua
450 lines
14 KiB
Lua
local M = {}
|
|
|
|
function M.create(ctx)
|
|
local mp = ctx.mp
|
|
local opts = ctx.opts
|
|
local state = ctx.state
|
|
local binary = ctx.binary
|
|
local environment = ctx.environment
|
|
local options_helper = ctx.options_helper
|
|
local subminer_log = ctx.log.subminer_log
|
|
local show_osd = ctx.log.show_osd
|
|
local normalize_log_level = ctx.log.normalize_log_level
|
|
|
|
local function resolve_backend(override_backend)
|
|
local selected = override_backend
|
|
if selected == nil or selected == "" then
|
|
selected = opts.backend
|
|
end
|
|
if selected == "auto" then
|
|
return environment.detect_backend()
|
|
end
|
|
return selected
|
|
end
|
|
|
|
local function build_command_args(action, overrides)
|
|
overrides = overrides or {}
|
|
local args = { state.binary_path }
|
|
|
|
table.insert(args, "--" .. action)
|
|
local log_level = normalize_log_level(overrides.log_level or opts.log_level)
|
|
if log_level ~= "info" then
|
|
table.insert(args, "--log-level")
|
|
table.insert(args, log_level)
|
|
end
|
|
|
|
local needs_start_context = action == "start"
|
|
if needs_start_context then
|
|
local backend = resolve_backend(overrides.backend)
|
|
if backend and backend ~= "" then
|
|
table.insert(args, "--backend")
|
|
table.insert(args, backend)
|
|
end
|
|
|
|
local socket_path = overrides.socket_path or opts.socket_path
|
|
table.insert(args, "--socket")
|
|
table.insert(args, socket_path)
|
|
end
|
|
|
|
return args
|
|
end
|
|
|
|
local function run_control_command(action)
|
|
local args = build_command_args(action)
|
|
subminer_log("debug", "process", "Control command: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
return result and result.status == 0
|
|
end
|
|
|
|
local function parse_start_script_message_overrides(...)
|
|
local overrides = {}
|
|
for i = 1, select("#", ...) do
|
|
local token = select(i, ...)
|
|
if type(token) == "string" and token ~= "" then
|
|
local key, value = token:match("^([%w_%-]+)=(.+)$")
|
|
if key and value then
|
|
local normalized_key = key:lower()
|
|
if normalized_key == "backend" then
|
|
local backend = value:lower()
|
|
if backend == "auto" or backend == "hyprland" or backend == "sway" or backend == "x11" or backend == "macos" then
|
|
overrides.backend = backend
|
|
end
|
|
elseif normalized_key == "socket" or normalized_key == "socket_path" then
|
|
overrides.socket_path = value
|
|
elseif normalized_key == "texthooker" or normalized_key == "texthooker_enabled" then
|
|
local parsed = options_helper.coerce_bool(value, nil)
|
|
if parsed ~= nil then
|
|
overrides.texthooker_enabled = parsed
|
|
end
|
|
elseif normalized_key == "log-level" or normalized_key == "log_level" then
|
|
overrides.log_level = normalize_log_level(value)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return overrides
|
|
end
|
|
|
|
local function resolve_visible_overlay_startup()
|
|
local visible = options_helper.coerce_bool(opts.auto_start_visible_overlay, false)
|
|
if options_helper.coerce_bool(opts.auto_start_overlay, false) then
|
|
visible = true
|
|
end
|
|
return visible
|
|
end
|
|
|
|
local function resolve_invisible_overlay_startup()
|
|
local raw = opts.auto_start_invisible_overlay
|
|
if type(raw) == "boolean" then
|
|
return raw
|
|
end
|
|
|
|
local mode = type(raw) == "string" and raw:lower() or "platform-default"
|
|
if mode == "visible" or mode == "show" or mode == "yes" or mode == "true" or mode == "on" then
|
|
return true
|
|
end
|
|
if mode == "hidden" or mode == "hide" or mode == "no" or mode == "false" or mode == "off" then
|
|
return false
|
|
end
|
|
|
|
return not environment.is_linux()
|
|
end
|
|
|
|
local function apply_startup_overlay_preferences()
|
|
local should_show_visible = resolve_visible_overlay_startup()
|
|
local should_show_invisible = resolve_invisible_overlay_startup()
|
|
|
|
local visible_action = should_show_visible and "show-visible-overlay" or "hide-visible-overlay"
|
|
if not run_control_command(visible_action) then
|
|
subminer_log("warn", "process", "Failed to apply visible startup action: " .. visible_action)
|
|
end
|
|
|
|
local invisible_action = should_show_invisible and "show-invisible-overlay" or "hide-invisible-overlay"
|
|
if not run_control_command(invisible_action) then
|
|
subminer_log("warn", "process", "Failed to apply invisible startup action: " .. invisible_action)
|
|
end
|
|
|
|
state.invisible_overlay_visible = should_show_invisible
|
|
end
|
|
|
|
local function build_texthooker_args()
|
|
local args = { state.binary_path, "--texthooker", "--port", tostring(opts.texthooker_port) }
|
|
local log_level = normalize_log_level(opts.log_level)
|
|
if log_level ~= "info" then
|
|
table.insert(args, "--log-level")
|
|
table.insert(args, log_level)
|
|
end
|
|
return args
|
|
end
|
|
|
|
local function ensure_texthooker_running(callback)
|
|
if not opts.texthooker_enabled then
|
|
callback()
|
|
return
|
|
end
|
|
if state.texthooker_running then
|
|
callback()
|
|
return
|
|
end
|
|
|
|
local args = build_texthooker_args()
|
|
subminer_log("info", "texthooker", "Starting texthooker process: " .. table.concat(args, " "))
|
|
state.texthooker_running = true
|
|
|
|
mp.command_native_async({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
}, function(success, result, error)
|
|
if not success or (result and result.status ~= 0) then
|
|
state.texthooker_running = false
|
|
subminer_log("warn", "texthooker", "Texthooker process exited unexpectedly: " .. (error or (result and result.stderr) or "unknown error"))
|
|
end
|
|
end)
|
|
|
|
mp.add_timeout(0.35, callback)
|
|
end
|
|
|
|
local function start_overlay(overrides)
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
if state.overlay_running then
|
|
subminer_log("info", "process", "Overlay already running")
|
|
show_osd("Already running")
|
|
return
|
|
end
|
|
|
|
overrides = overrides or {}
|
|
local texthooker_enabled = overrides.texthooker_enabled
|
|
if texthooker_enabled == nil then
|
|
texthooker_enabled = opts.texthooker_enabled
|
|
end
|
|
|
|
local function launch_overlay()
|
|
local args = build_command_args("start", overrides)
|
|
subminer_log("info", "process", "Starting overlay: " .. table.concat(args, " "))
|
|
show_osd("Starting...")
|
|
state.overlay_running = true
|
|
|
|
mp.command_native_async({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
}, function(success, result, error)
|
|
if not success or (result and result.status ~= 0) then
|
|
state.overlay_running = false
|
|
subminer_log("error", "process", "Overlay start failed: " .. (error or (result and result.stderr) or "unknown error"))
|
|
show_osd("Overlay start failed")
|
|
end
|
|
end)
|
|
|
|
mp.add_timeout(0.6, function()
|
|
apply_startup_overlay_preferences()
|
|
end)
|
|
end
|
|
|
|
if texthooker_enabled then
|
|
ensure_texthooker_running(launch_overlay)
|
|
else
|
|
launch_overlay()
|
|
end
|
|
end
|
|
|
|
local function start_overlay_from_script_message(...)
|
|
local overrides = parse_start_script_message_overrides(...)
|
|
start_overlay(overrides)
|
|
end
|
|
|
|
local function stop_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
|
|
local args = build_command_args("stop")
|
|
subminer_log("info", "process", "Stopping overlay: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
|
|
state.overlay_running = false
|
|
state.texthooker_running = false
|
|
if result.status == 0 then
|
|
subminer_log("info", "process", "Overlay stopped")
|
|
else
|
|
subminer_log("warn", "process", "Stop command returned non-zero status: " .. tostring(result.status))
|
|
end
|
|
show_osd("Stopped")
|
|
end
|
|
|
|
local function toggle_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
local args = build_command_args("toggle")
|
|
subminer_log("info", "process", "Toggling overlay: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
if result and result.status ~= 0 then
|
|
subminer_log("warn", "process", "Toggle command failed")
|
|
show_osd("Toggle failed")
|
|
end
|
|
end
|
|
|
|
local function toggle_invisible_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
local args = build_command_args("toggle-invisible-overlay")
|
|
subminer_log("info", "process", "Toggling invisible overlay: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
if result and result.status ~= 0 then
|
|
subminer_log("warn", "process", "Invisible toggle command failed")
|
|
show_osd("Invisible toggle failed")
|
|
return
|
|
end
|
|
state.invisible_overlay_visible = not state.invisible_overlay_visible
|
|
show_osd("Invisible overlay: " .. (state.invisible_overlay_visible and "visible" or "hidden"))
|
|
end
|
|
|
|
local function show_invisible_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
local args = build_command_args("show-invisible-overlay")
|
|
subminer_log("info", "process", "Showing invisible overlay: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
if result and result.status ~= 0 then
|
|
subminer_log("warn", "process", "Show invisible command failed")
|
|
show_osd("Show invisible failed")
|
|
return
|
|
end
|
|
state.invisible_overlay_visible = true
|
|
show_osd("Invisible overlay: visible")
|
|
end
|
|
|
|
local function hide_invisible_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
local args = build_command_args("hide-invisible-overlay")
|
|
subminer_log("info", "process", "Hiding invisible overlay: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
if result and result.status ~= 0 then
|
|
subminer_log("warn", "process", "Hide invisible command failed")
|
|
show_osd("Hide invisible failed")
|
|
return
|
|
end
|
|
state.invisible_overlay_visible = false
|
|
show_osd("Invisible overlay: hidden")
|
|
end
|
|
|
|
local function open_options()
|
|
if not state.binary_available then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
local args = build_command_args("settings")
|
|
subminer_log("info", "process", "Opening options: " .. table.concat(args, " "))
|
|
local result = mp.command_native({
|
|
name = "subprocess",
|
|
args = args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
if result.status == 0 then
|
|
subminer_log("info", "process", "Options window opened")
|
|
show_osd("Options opened")
|
|
else
|
|
subminer_log("warn", "process", "Failed to open options")
|
|
show_osd("Failed to open options")
|
|
end
|
|
end
|
|
|
|
local function restart_overlay()
|
|
if not binary.ensure_binary_available() then
|
|
subminer_log("error", "binary", "SubMiner binary not found")
|
|
show_osd("Error: binary not found")
|
|
return
|
|
end
|
|
|
|
subminer_log("info", "process", "Restarting overlay...")
|
|
show_osd("Restarting...")
|
|
|
|
local stop_args = build_command_args("stop")
|
|
mp.command_native({
|
|
name = "subprocess",
|
|
args = stop_args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
})
|
|
|
|
state.overlay_running = false
|
|
state.texthooker_running = false
|
|
|
|
ensure_texthooker_running(function()
|
|
local start_args = build_command_args("start")
|
|
subminer_log("info", "process", "Starting overlay: " .. table.concat(start_args, " "))
|
|
|
|
state.overlay_running = true
|
|
mp.command_native_async({
|
|
name = "subprocess",
|
|
args = start_args,
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true,
|
|
}, function(success, result, error)
|
|
if not success or (result and result.status ~= 0) then
|
|
state.overlay_running = false
|
|
subminer_log("error", "process", "Overlay start failed: " .. (error or (result and result.stderr) or "unknown error"))
|
|
show_osd("Restart failed")
|
|
else
|
|
show_osd("Restarted successfully")
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
local function check_status()
|
|
if not state.binary_available then
|
|
show_osd("Status: binary not found")
|
|
return
|
|
end
|
|
local status = state.overlay_running and "running" or "stopped"
|
|
show_osd("Status: overlay is " .. status)
|
|
subminer_log("info", "process", "Status check: overlay is " .. status)
|
|
end
|
|
|
|
return {
|
|
build_command_args = build_command_args,
|
|
run_control_command = run_control_command,
|
|
parse_start_script_message_overrides = parse_start_script_message_overrides,
|
|
apply_startup_overlay_preferences = apply_startup_overlay_preferences,
|
|
ensure_texthooker_running = ensure_texthooker_running,
|
|
start_overlay = start_overlay,
|
|
start_overlay_from_script_message = start_overlay_from_script_message,
|
|
stop_overlay = stop_overlay,
|
|
toggle_overlay = toggle_overlay,
|
|
toggle_invisible_overlay = toggle_invisible_overlay,
|
|
show_invisible_overlay = show_invisible_overlay,
|
|
hide_invisible_overlay = hide_invisible_overlay,
|
|
open_options = open_options,
|
|
restart_overlay = restart_overlay,
|
|
check_status = check_status,
|
|
}
|
|
end
|
|
|
|
return M
|