mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-13 20:12:54 -07:00
feat: inject bundled mpv plugin for managed launches, remove legacy glob (#62)
* feat: inject bundled mpv plugin for managed launches, remove legacy glob - SubMiner-managed launcher and Windows shortcut launches inject the bundled plugin when no global plugin is detected - First-run setup detects and removes legacy global plugin files via OS trash before managed playback starts - Makefile `install-plugin` target and Windows config-rewrite script removed; Linux/macOS install now copies plugin to app data dir - AniList stats search and post-watch tracking now go through the shared rate limiter - Stats cover-art lookup reuses cached AniList data before issuing a new request - Closing mpv in a launcher-managed session now terminates the background Electron app * harden bootstrap version load and clean plugin on uninstall - Use pcall for version.lua in bootstrap.lua so missing version module does not crash plugin startup - Remove plugin/subminer from app-data dirs in uninstall-linux and uninstall-macos targets - Add Lua compat test asserting bootstrap uses defensive pcall for version load - Add release-workflow test asserting uninstall targets clean bundled plugin dirs - Delete completed planning document
This commit is contained in:
+58
-8
@@ -32,31 +32,81 @@ export async function waitForSetupCompletion(deps: {
|
||||
return 'timeout';
|
||||
}
|
||||
|
||||
export async function waitForLegacyMpvPluginPromptResolution(deps: {
|
||||
readSetupState: () => SetupState | null;
|
||||
sleep: (ms: number) => Promise<void>;
|
||||
now: () => number;
|
||||
timeoutMs: number;
|
||||
pollIntervalMs: number;
|
||||
initialState?: SetupState | null;
|
||||
}): Promise<'acknowledged' | 'cancelled' | 'timeout'> {
|
||||
const deadline = deps.now() + deps.timeoutMs;
|
||||
const initialCompleted = isSetupCompleted(deps.initialState);
|
||||
const initialCompletedAt = deps.initialState?.completedAt ?? null;
|
||||
|
||||
while (deps.now() <= deadline) {
|
||||
const state = deps.readSetupState();
|
||||
if (
|
||||
isSetupCompleted(state) &&
|
||||
(!initialCompleted || state?.completedAt !== initialCompletedAt)
|
||||
) {
|
||||
return 'acknowledged';
|
||||
}
|
||||
if (!initialCompleted && state?.status === 'cancelled') {
|
||||
return 'cancelled';
|
||||
}
|
||||
|
||||
await deps.sleep(deps.pollIntervalMs);
|
||||
}
|
||||
|
||||
return 'timeout';
|
||||
}
|
||||
|
||||
export async function ensureLauncherSetupReady(deps: {
|
||||
readSetupState: () => SetupState | null;
|
||||
isExternalYomitanConfigured?: () => boolean;
|
||||
isPluginInstalled?: () => boolean;
|
||||
hasLegacyMpvPlugin?: () => boolean;
|
||||
launchSetupApp: () => void;
|
||||
sleep: (ms: number) => Promise<void>;
|
||||
now: () => number;
|
||||
timeoutMs: number;
|
||||
pollIntervalMs: number;
|
||||
}): Promise<boolean> {
|
||||
const initialState = deps.readSetupState();
|
||||
let setupLaunched = false;
|
||||
const launchSetupApp = () => {
|
||||
if (setupLaunched) return;
|
||||
setupLaunched = true;
|
||||
deps.launchSetupApp();
|
||||
};
|
||||
|
||||
if (deps.hasLegacyMpvPlugin?.()) {
|
||||
launchSetupApp();
|
||||
const result = await waitForLegacyMpvPluginPromptResolution({
|
||||
readSetupState: deps.readSetupState,
|
||||
sleep: deps.sleep,
|
||||
now: deps.now,
|
||||
timeoutMs: deps.timeoutMs,
|
||||
pollIntervalMs: deps.pollIntervalMs,
|
||||
initialState,
|
||||
});
|
||||
if (result === 'cancelled' || result === 'timeout') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (deps.isExternalYomitanConfigured?.()) {
|
||||
return true;
|
||||
}
|
||||
if (deps.isPluginInstalled?.()) {
|
||||
return true;
|
||||
}
|
||||
const initialState = deps.readSetupState();
|
||||
if (isSetupCompleted(initialState)) {
|
||||
const stateAfterLegacyPrompt = deps.readSetupState();
|
||||
if (isSetupCompleted(stateAfterLegacyPrompt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
deps.launchSetupApp();
|
||||
launchSetupApp();
|
||||
const result = await waitForSetupCompletion({
|
||||
...deps,
|
||||
ignoreInitialCancelledState: initialState?.status === 'cancelled',
|
||||
ignoreInitialCancelledState: stateAfterLegacyPrompt?.status === 'cancelled',
|
||||
});
|
||||
return result === 'completed';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user