mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
initial commit
This commit is contained in:
773
plugin/subminer.lua
Normal file
773
plugin/subminer.lua
Normal file
@@ -0,0 +1,773 @@
|
||||
local input = require("mp.input")
|
||||
local mp = require("mp")
|
||||
local msg = require("mp.msg")
|
||||
local options = require("mp.options")
|
||||
local utils = require("mp.utils")
|
||||
|
||||
local function is_windows()
|
||||
return package.config:sub(1, 1) == "\\"
|
||||
end
|
||||
|
||||
local function is_macos()
|
||||
local platform = mp.get_property("platform") or ""
|
||||
if platform == "macos" or platform == "darwin" then
|
||||
return true
|
||||
end
|
||||
local ostype = os.getenv("OSTYPE") or ""
|
||||
return ostype:find("darwin") ~= nil
|
||||
end
|
||||
|
||||
local function default_socket_path()
|
||||
if is_windows() then
|
||||
return "\\\\.\\pipe\\subminer-socket"
|
||||
end
|
||||
return "/tmp/subminer-socket"
|
||||
end
|
||||
|
||||
local function is_linux()
|
||||
return not is_windows() and not is_macos()
|
||||
end
|
||||
|
||||
local opts = {
|
||||
binary_path = "",
|
||||
socket_path = default_socket_path(),
|
||||
texthooker_enabled = true,
|
||||
texthooker_port = 5174,
|
||||
backend = "auto",
|
||||
auto_start = true,
|
||||
auto_start_overlay = false, -- legacy alias, maps to auto_start_visible_overlay
|
||||
auto_start_visible_overlay = false,
|
||||
auto_start_invisible_overlay = "platform-default", -- platform-default | visible | hidden
|
||||
osd_messages = true,
|
||||
log_level = "info",
|
||||
}
|
||||
|
||||
options.read_options(opts, "subminer")
|
||||
|
||||
local state = {
|
||||
overlay_running = false,
|
||||
texthooker_running = false,
|
||||
overlay_process = nil,
|
||||
binary_available = false,
|
||||
binary_path = nil,
|
||||
detected_backend = nil,
|
||||
invisible_overlay_visible = false,
|
||||
}
|
||||
|
||||
local LOG_LEVEL_PRIORITY = {
|
||||
debug = 10,
|
||||
info = 20,
|
||||
warn = 30,
|
||||
error = 40,
|
||||
}
|
||||
|
||||
local function normalize_log_level(level)
|
||||
local normalized = (level or "info"):lower()
|
||||
if LOG_LEVEL_PRIORITY[normalized] then
|
||||
return normalized
|
||||
end
|
||||
return "info"
|
||||
end
|
||||
|
||||
local function should_log(level)
|
||||
local current = normalize_log_level(opts.log_level)
|
||||
local target = normalize_log_level(level)
|
||||
return LOG_LEVEL_PRIORITY[target] >= LOG_LEVEL_PRIORITY[current]
|
||||
end
|
||||
|
||||
local function subminer_log(level, scope, message)
|
||||
if not should_log(level) then
|
||||
return
|
||||
end
|
||||
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
|
||||
local line = string.format("[subminer] - %s - %s - [%s] %s", timestamp, string.upper(level), scope, message)
|
||||
if level == "error" then
|
||||
msg.error(line)
|
||||
elseif level == "warn" then
|
||||
msg.warn(line)
|
||||
elseif level == "debug" then
|
||||
msg.debug(line)
|
||||
else
|
||||
msg.info(line)
|
||||
end
|
||||
end
|
||||
|
||||
local function show_osd(message)
|
||||
if opts.osd_messages then
|
||||
mp.osd_message("SubMiner: " .. message, 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function detect_backend()
|
||||
if state.detected_backend then
|
||||
return state.detected_backend
|
||||
end
|
||||
|
||||
local backend = nil
|
||||
|
||||
if is_macos() then
|
||||
backend = "macos"
|
||||
elseif is_windows() then
|
||||
backend = nil
|
||||
elseif os.getenv("HYPRLAND_INSTANCE_SIGNATURE") then
|
||||
backend = "hyprland"
|
||||
elseif os.getenv("SWAYSOCK") then
|
||||
backend = "sway"
|
||||
elseif os.getenv("XDG_SESSION_TYPE") == "x11" or os.getenv("DISPLAY") then
|
||||
backend = "x11"
|
||||
else
|
||||
subminer_log("warn", "backend", "Could not detect window manager, falling back to x11")
|
||||
backend = "x11"
|
||||
end
|
||||
|
||||
state.detected_backend = backend
|
||||
if backend then
|
||||
subminer_log("info", "backend", "Detected backend: " .. backend)
|
||||
else
|
||||
subminer_log("info", "backend", "No backend detected")
|
||||
end
|
||||
return backend
|
||||
end
|
||||
|
||||
local function file_exists(path)
|
||||
local info = utils.file_info(path)
|
||||
return info ~= nil
|
||||
end
|
||||
|
||||
local function find_binary()
|
||||
if opts.binary_path ~= "" and file_exists(opts.binary_path) then
|
||||
return opts.binary_path
|
||||
end
|
||||
|
||||
local search_paths = {
|
||||
"/Applications/SubMiner.app/Contents/MacOS/SubMiner",
|
||||
utils.join_path(os.getenv("HOME") or "", "Applications/SubMiner.app/Contents/MacOS/SubMiner"),
|
||||
"C:\\Program Files\\SubMiner\\SubMiner.exe",
|
||||
"C:\\Program Files (x86)\\SubMiner\\SubMiner.exe",
|
||||
"C:\\SubMiner\\SubMiner.exe",
|
||||
utils.join_path(os.getenv("HOME") or "", ".local/bin/SubMiner.AppImage"),
|
||||
"/opt/SubMiner/SubMiner.AppImage",
|
||||
"/usr/local/bin/SubMiner",
|
||||
"/usr/bin/SubMiner",
|
||||
}
|
||||
|
||||
for _, path in ipairs(search_paths) do
|
||||
if file_exists(path) then
|
||||
subminer_log("info", "binary", "Found binary at: " .. path)
|
||||
return path
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function ensure_binary_available()
|
||||
if state.binary_available and state.binary_path and file_exists(state.binary_path) then
|
||||
return true
|
||||
end
|
||||
|
||||
local discovered = find_binary()
|
||||
if discovered then
|
||||
state.binary_path = discovered
|
||||
state.binary_available = true
|
||||
return true
|
||||
end
|
||||
|
||||
state.binary_path = nil
|
||||
state.binary_available = false
|
||||
return false
|
||||
end
|
||||
|
||||
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 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 == "debug" then
|
||||
table.insert(args, "--verbose")
|
||||
elseif log_level ~= "info" then
|
||||
table.insert(args, "--log-level")
|
||||
table.insert(args, log_level)
|
||||
end
|
||||
|
||||
local needs_start_context = (
|
||||
action == "start"
|
||||
or action == "toggle"
|
||||
or action == "show"
|
||||
or action == "hide"
|
||||
or action == "toggle-visible-overlay"
|
||||
or action == "show-visible-overlay"
|
||||
or action == "hide-visible-overlay"
|
||||
or action == "toggle-invisible-overlay"
|
||||
or action == "show-invisible-overlay"
|
||||
or action == "hide-invisible-overlay"
|
||||
)
|
||||
|
||||
if needs_start_context then
|
||||
-- Explicitly request MPV IPC connection for active overlay control.
|
||||
if action ~= "start" then
|
||||
table.insert(args, "--start")
|
||||
end
|
||||
|
||||
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 coerce_bool(value, fallback)
|
||||
if type(value) == "boolean" then
|
||||
return value
|
||||
end
|
||||
if type(value) == "string" then
|
||||
local normalized = value:lower()
|
||||
if normalized == "yes" or normalized == "true" or normalized == "1" or normalized == "on" then
|
||||
return true
|
||||
end
|
||||
if normalized == "no" or normalized == "false" or normalized == "0" or normalized == "off" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return fallback
|
||||
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 = 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 = coerce_bool(opts.auto_start_visible_overlay, false)
|
||||
-- Backward compatibility for old config key.
|
||||
if 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
|
||||
|
||||
-- platform-default
|
||||
return not 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 == "debug" then
|
||||
table.insert(args, "--verbose")
|
||||
elseif 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)
|
||||
|
||||
-- Give the process a moment to acquire the app lock before sending --start.
|
||||
mp.add_timeout(0.35, callback)
|
||||
end
|
||||
|
||||
local function start_overlay(overrides)
|
||||
if not 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)
|
||||
|
||||
-- Apply explicit startup visibility for each overlay layer.
|
||||
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 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("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 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("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 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("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 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("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 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("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 restart_overlay
|
||||
local check_status
|
||||
|
||||
local function show_menu()
|
||||
if not state.binary_available then
|
||||
subminer_log("error", "binary", "SubMiner binary not found")
|
||||
show_osd("Error: binary not found")
|
||||
return
|
||||
end
|
||||
|
||||
local items = {
|
||||
"Start overlay",
|
||||
"Stop overlay",
|
||||
"Toggle overlay",
|
||||
"Toggle invisible overlay",
|
||||
"Open options",
|
||||
"Restart overlay",
|
||||
"Check status",
|
||||
}
|
||||
|
||||
local actions = {
|
||||
start_overlay,
|
||||
stop_overlay,
|
||||
toggle_overlay,
|
||||
toggle_invisible_overlay,
|
||||
open_options,
|
||||
restart_overlay,
|
||||
check_status,
|
||||
}
|
||||
|
||||
input.select({
|
||||
prompt = "SubMiner: ",
|
||||
items = items,
|
||||
submit = function(index)
|
||||
if index and actions[index] then
|
||||
actions[index]()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
restart_overlay = function()
|
||||
if not state.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
|
||||
|
||||
check_status = function()
|
||||
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
|
||||
|
||||
local function on_file_loaded()
|
||||
state.binary_path = find_binary()
|
||||
if state.binary_path then
|
||||
state.binary_available = true
|
||||
subminer_log("info", "lifecycle", "SubMiner ready (binary: " .. state.binary_path .. ")")
|
||||
local should_auto_start = coerce_bool(opts.auto_start, false)
|
||||
if should_auto_start then
|
||||
start_overlay()
|
||||
end
|
||||
else
|
||||
state.binary_available = false
|
||||
subminer_log("warn", "binary", "SubMiner binary not found - overlay features disabled")
|
||||
if opts.binary_path ~= "" then
|
||||
subminer_log("warn", "binary", "Configured path '" .. opts.binary_path .. "' does not exist")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_shutdown()
|
||||
if (state.overlay_running or state.texthooker_running) and state.binary_available then
|
||||
subminer_log("info", "lifecycle", "mpv shutting down, stopping SubMiner process")
|
||||
show_osd("Shutting down...")
|
||||
stop_overlay()
|
||||
end
|
||||
end
|
||||
|
||||
local function register_keybindings()
|
||||
mp.add_key_binding("y-s", "subminer-start", start_overlay)
|
||||
mp.add_key_binding("y-S", "subminer-stop", stop_overlay)
|
||||
mp.add_key_binding("y-t", "subminer-toggle", toggle_overlay)
|
||||
mp.add_key_binding("y-i", "subminer-toggle-invisible", toggle_invisible_overlay)
|
||||
mp.add_key_binding("y-I", "subminer-show-invisible", show_invisible_overlay)
|
||||
mp.add_key_binding("y-u", "subminer-hide-invisible", hide_invisible_overlay)
|
||||
mp.add_key_binding("y-y", "subminer-menu", show_menu)
|
||||
mp.add_key_binding("y-o", "subminer-options", open_options)
|
||||
mp.add_key_binding("y-r", "subminer-restart", restart_overlay)
|
||||
mp.add_key_binding("y-c", "subminer-status", check_status)
|
||||
end
|
||||
|
||||
local function register_script_messages()
|
||||
mp.register_script_message("subminer-start", start_overlay_from_script_message)
|
||||
mp.register_script_message("subminer-stop", stop_overlay)
|
||||
mp.register_script_message("subminer-toggle", toggle_overlay)
|
||||
mp.register_script_message("subminer-toggle-invisible", toggle_invisible_overlay)
|
||||
mp.register_script_message("subminer-show-invisible", show_invisible_overlay)
|
||||
mp.register_script_message("subminer-hide-invisible", hide_invisible_overlay)
|
||||
mp.register_script_message("subminer-menu", show_menu)
|
||||
mp.register_script_message("subminer-options", open_options)
|
||||
mp.register_script_message("subminer-restart", restart_overlay)
|
||||
mp.register_script_message("subminer-status", check_status)
|
||||
end
|
||||
|
||||
local function init()
|
||||
register_keybindings()
|
||||
register_script_messages()
|
||||
|
||||
mp.register_event("file-loaded", on_file_loaded)
|
||||
mp.register_event("shutdown", on_shutdown)
|
||||
|
||||
subminer_log("info", "lifecycle", "SubMiner plugin loaded")
|
||||
end
|
||||
|
||||
init()
|
||||
Reference in New Issue
Block a user