Prepare Windows release and signing process (#16)

This commit is contained in:
2026-03-08 19:51:30 -07:00
committed by GitHub
parent 34d2dce8dc
commit c799a8de3c
113 changed files with 5042 additions and 386 deletions

View File

@@ -1,6 +1,7 @@
local M = {}
function M.create(ctx)
local mp = ctx.mp
local utils = ctx.utils
local opts = ctx.opts
local state = ctx.state
@@ -26,6 +27,13 @@ function M.create(ctx)
end
local function binary_candidates_from_app_path(app_path)
if environment.is_windows() then
return {
utils.join_path(app_path, "SubMiner.exe"),
utils.join_path(app_path, "subminer.exe"),
}
end
return {
utils.join_path(app_path, "Contents", "MacOS", "SubMiner"),
utils.join_path(app_path, "Contents", "MacOS", "subminer"),
@@ -43,6 +51,11 @@ function M.create(ctx)
return true
end
local function directory_exists(path)
local info = utils.file_info(path)
return info ~= nil and info.is_dir == true
end
local function resolve_binary_candidate(candidate)
local normalized = normalize_binary_path_candidate(candidate)
if not normalized then
@@ -53,6 +66,25 @@ function M.create(ctx)
return normalized
end
if environment.is_windows() then
if not normalized:lower():match("%.exe$") then
local with_exe = normalized .. ".exe"
if file_exists(with_exe) then
return with_exe
end
end
if directory_exists(normalized) then
for _, path in ipairs(binary_candidates_from_app_path(normalized)) do
if file_exists(path) then
return path
end
end
end
return nil
end
if not normalized:lower():find("%.app") then
return nil
end
@@ -89,6 +121,109 @@ function M.create(ctx)
return nil
end
local function add_search_path(search_paths, candidate)
if type(candidate) == "string" and candidate ~= "" then
search_paths[#search_paths + 1] = candidate
end
end
local function trim_subprocess_stdout(value)
if type(value) ~= "string" then
return nil
end
local trimmed = value:match("^%s*(.-)%s*$") or ""
if trimmed == "" then
return nil
end
return trimmed
end
local function find_windows_binary_via_system_lookup()
if not environment.is_windows() then
return nil
end
if not mp or type(mp.command_native) ~= "function" then
return nil
end
local script = [=[
function Emit-FirstExistingPath {
param([string[]]$Candidates)
foreach ($candidate in $Candidates) {
if ([string]::IsNullOrWhiteSpace($candidate)) {
continue
}
if (Test-Path -LiteralPath $candidate -PathType Leaf) {
Write-Output $candidate
exit 0
}
}
}
$runningProcess = Get-CimInstance Win32_Process |
Where-Object { $_.Name -ieq 'SubMiner.exe' -or $_.Name -ieq 'subminer.exe' } |
Select-Object -First 1 -Property ExecutablePath, CommandLine
if ($null -ne $runningProcess) {
Emit-FirstExistingPath @($runningProcess.ExecutablePath)
}
$localAppData = [Environment]::GetFolderPath('LocalApplicationData')
$programFiles = [Environment]::GetFolderPath('ProgramFiles')
$programFilesX86 = ${env:ProgramFiles(x86)}
Emit-FirstExistingPath @(
$(if (-not [string]::IsNullOrWhiteSpace($localAppData)) { Join-Path $localAppData 'Programs\SubMiner\SubMiner.exe' } else { $null }),
$(if (-not [string]::IsNullOrWhiteSpace($programFiles)) { Join-Path $programFiles 'SubMiner\SubMiner.exe' } else { $null }),
$(if (-not [string]::IsNullOrWhiteSpace($programFilesX86)) { Join-Path $programFilesX86 'SubMiner\SubMiner.exe' } else { $null }),
'C:\SubMiner\SubMiner.exe'
)
foreach ($registryPath in @(
'HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\SubMiner.exe',
'HKLM:\Software\Microsoft\Windows\CurrentVersion\App Paths\SubMiner.exe',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths\SubMiner.exe'
)) {
try {
$appPath = (Get-ItemProperty -Path $registryPath -ErrorAction Stop).'(default)'
Emit-FirstExistingPath @($appPath)
} catch {
}
}
try {
$commandPath = Get-Command SubMiner.exe -ErrorAction Stop | Select-Object -First 1 -ExpandProperty Source
Emit-FirstExistingPath @($commandPath)
} catch {
}
]=]
local result = mp.command_native({
name = "subprocess",
args = {
"powershell.exe",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
script,
},
playback_only = false,
capture_stdout = true,
capture_stderr = false,
})
if not result or result.status ~= 0 then
return nil
end
local candidate = trim_subprocess_stdout(result.stdout)
if not candidate then
return nil
end
return resolve_binary_candidate(candidate)
end
local function find_binary()
local override = find_binary_override()
if override then
@@ -100,17 +235,34 @@ function M.create(ctx)
return configured
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",
}
local system_lookup_binary = find_windows_binary_via_system_lookup()
if system_lookup_binary then
subminer_log("info", "binary", "Found Windows binary via system lookup at: " .. system_lookup_binary)
return system_lookup_binary
end
local home = os.getenv("HOME") or os.getenv("USERPROFILE") or ""
local app_data = os.getenv("APPDATA") or ""
local app_data_local = app_data ~= "" and app_data:gsub("[/\\][Rr][Oo][Aa][Mm][Ii][Nn][Gg]$", "\\Local") or ""
local local_app_data = os.getenv("LOCALAPPDATA") or utils.join_path(home, "AppData", "Local")
local program_files = os.getenv("ProgramFiles") or "C:\\Program Files"
local program_files_x86 = os.getenv("ProgramFiles(x86)") or "C:\\Program Files (x86)"
local search_paths = {}
if environment.is_windows() then
add_search_path(search_paths, utils.join_path(app_data_local, "Programs", "SubMiner", "SubMiner.exe"))
add_search_path(search_paths, utils.join_path(local_app_data, "Programs", "SubMiner", "SubMiner.exe"))
add_search_path(search_paths, utils.join_path(program_files, "SubMiner", "SubMiner.exe"))
add_search_path(search_paths, utils.join_path(program_files_x86, "SubMiner", "SubMiner.exe"))
add_search_path(search_paths, "C:\\SubMiner\\SubMiner.exe")
else
add_search_path(search_paths, "/Applications/SubMiner.app/Contents/MacOS/SubMiner")
add_search_path(search_paths, utils.join_path(home, "Applications", "SubMiner.app", "Contents", "MacOS", "SubMiner"))
add_search_path(search_paths, utils.join_path(home, ".local", "bin", "SubMiner.AppImage"))
add_search_path(search_paths, "/opt/SubMiner/SubMiner.AppImage")
add_search_path(search_paths, "/usr/local/bin/SubMiner")
add_search_path(search_paths, "/usr/bin/SubMiner")
end
for _, path in ipairs(search_paths) do
if file_exists(path) then

View File

@@ -1,6 +1,12 @@
local M = {}
local BOOTSTRAP_GUARD_KEY = "__subminer_plugin_bootstrapped"
function M.init()
if rawget(_G, BOOTSTRAP_GUARD_KEY) == true then
return
end
rawset(_G, BOOTSTRAP_GUARD_KEY, true)
local input = require("mp.input")
local mp = require("mp")
local msg = require("mp.msg")

View File

@@ -61,8 +61,9 @@ function M.create(ctx)
aniskip.clear_aniskip_state()
hover.clear_hover_overlay()
process.disarm_auto_play_ready_gate()
if state.overlay_running or state.texthooker_running then
subminer_log("info", "lifecycle", "mpv shutting down, preserving SubMiner background process")
if state.overlay_running then
subminer_log("info", "lifecycle", "mpv shutting down, hiding SubMiner overlay")
process.hide_visible_overlay()
end
end
@@ -75,6 +76,9 @@ function M.create(ctx)
mp.register_event("end-file", function()
process.disarm_auto_play_ready_gate()
hover.clear_hover_overlay()
if state.overlay_running then
process.hide_visible_overlay()
end
end)
mp.register_event("shutdown", function()
hover.clear_hover_overlay()

View File

@@ -22,4 +22,9 @@ if not package.path:find(module_patterns, 1, true) then
package.path = module_patterns .. package.path
end
require("init").init()
local init_module = assert(loadfile(script_dir .. "/init.lua"))()
if type(init_module) == "table" and type(init_module.init) == "function" then
init_module.init()
elseif type(init_module) == "function" then
init_module()
end

View File

@@ -1,5 +1,27 @@
local M = {}
local function normalize_socket_path_option(socket_path, default_socket_path)
if type(default_socket_path) ~= "string" then
return socket_path
end
local trimmed_default = default_socket_path:match("^%s*(.-)%s*$")
local trimmed_socket = type(socket_path) == "string" and socket_path:match("^%s*(.-)%s*$") or socket_path
if trimmed_default ~= "\\\\.\\pipe\\subminer-socket" then
return trimmed_socket
end
if type(trimmed_socket) ~= "string" or trimmed_socket == "" then
return trimmed_default
end
if trimmed_socket == "/tmp/subminer-socket" or trimmed_socket == "\\tmp\\subminer-socket" then
return trimmed_default
end
if trimmed_socket == "\\\\.\\pipe\\tmp\\subminer-socket" then
return trimmed_default
end
return trimmed_socket
end
function M.load(options_lib, default_socket_path)
local opts = {
binary_path = "",
@@ -25,6 +47,7 @@ function M.load(options_lib, default_socket_path)
}
options_lib.read_options(opts, "subminer")
opts.socket_path = normalize_socket_path_option(opts.socket_path, default_socket_path)
return opts
end

View File

@@ -411,6 +411,28 @@ function M.create(ctx)
show_osd("Stopped")
end
local function hide_visible_overlay()
if not binary.ensure_binary_available() then
subminer_log("error", "binary", "SubMiner binary not found")
return
end
run_control_command_async("hide-visible-overlay", nil, function(ok, result)
if ok then
subminer_log("info", "process", "Visible overlay hidden")
else
subminer_log(
"warn",
"process",
"Hide-visible-overlay command returned non-zero status: "
.. tostring(result and result.status or "unknown")
)
end
end)
disarm_auto_play_ready_gate()
end
local function toggle_overlay()
if not binary.ensure_binary_available() then
subminer_log("error", "binary", "SubMiner binary not found")
@@ -511,6 +533,7 @@ function M.create(ctx)
start_overlay = start_overlay,
start_overlay_from_script_message = start_overlay_from_script_message,
stop_overlay = stop_overlay,
hide_visible_overlay = hide_visible_overlay,
toggle_overlay = toggle_overlay,
open_options = open_options,
restart_overlay = restart_overlay,