[codex] Make Windows mpv shortcut self-contained (#40)

This commit is contained in:
2026-04-03 21:35:18 -07:00
committed by GitHub
parent d6c72806bb
commit 7514985feb
131 changed files with 3367 additions and 716 deletions
+100 -3
View File
@@ -14,8 +14,10 @@ test('buildFirstRunSetupHtml renders macchiato setup actions and disabled finish
dictionaryCount: 0,
canFinish: false,
externalYomitanConfigured: false,
pluginStatus: 'optional',
pluginStatus: 'required',
pluginInstallPathSummary: null,
mpvExecutablePath: '',
mpvExecutablePathStatus: 'blank',
windowsMpvShortcuts: {
supported: false,
startMenuEnabled: true,
@@ -29,6 +31,7 @@ test('buildFirstRunSetupHtml renders macchiato setup actions and disabled finish
assert.match(html, /SubMiner setup/);
assert.match(html, /Install mpv plugin/);
assert.match(html, /Required before SubMiner setup can finish/);
assert.match(html, /Open Yomitan Settings/);
assert.match(html, /Finish setup/);
assert.match(html, /disabled/);
@@ -42,6 +45,8 @@ test('buildFirstRunSetupHtml switches plugin action to reinstall when already in
externalYomitanConfigured: false,
pluginStatus: 'installed',
pluginInstallPathSummary: '/tmp/mpv',
mpvExecutablePath: 'C:\\Program Files\\mpv\\mpv.exe',
mpvExecutablePathStatus: 'configured',
windowsMpvShortcuts: {
supported: true,
startMenuEnabled: true,
@@ -54,6 +59,62 @@ test('buildFirstRunSetupHtml switches plugin action to reinstall when already in
});
assert.match(html, /Reinstall mpv plugin/);
assert.match(html, /mpv executable path/);
assert.match(html, /Leave blank to auto-discover mpv\.exe from PATH\./);
assert.match(html, /aria-label="Path to mpv\.exe"/);
assert.match(
html,
/Finish stays unlocked once the mpv plugin is installed and Yomitan reports at least one installed dictionary\./,
);
});
test('buildFirstRunSetupHtml marks an invalid configured mpv path as invalid', () => {
const html = buildFirstRunSetupHtml({
configReady: true,
dictionaryCount: 1,
canFinish: true,
externalYomitanConfigured: false,
pluginStatus: 'installed',
pluginInstallPathSummary: '/tmp/mpv',
mpvExecutablePath: 'C:\\Broken\\mpv.exe',
mpvExecutablePathStatus: 'invalid',
windowsMpvShortcuts: {
supported: true,
startMenuEnabled: true,
desktopEnabled: true,
startMenuInstalled: false,
desktopInstalled: false,
status: 'optional',
},
message: null,
});
assert.match(html, />Invalid</);
assert.match(html, /Current: C:\\Broken\\mpv\.exe \(invalid; file not found\)/);
});
test('buildFirstRunSetupHtml explains the config blocker when setup is missing config', () => {
const html = buildFirstRunSetupHtml({
configReady: false,
dictionaryCount: 0,
canFinish: false,
externalYomitanConfigured: false,
pluginStatus: 'required',
pluginInstallPathSummary: null,
mpvExecutablePath: '',
mpvExecutablePathStatus: 'blank',
windowsMpvShortcuts: {
supported: false,
startMenuEnabled: true,
desktopEnabled: true,
startMenuInstalled: false,
desktopInstalled: false,
status: 'optional',
},
message: null,
});
assert.match(html, /Create or provide the config file before finishing setup\./);
});
test('buildFirstRunSetupHtml explains external yomitan mode and keeps finish enabled', () => {
@@ -62,8 +123,10 @@ test('buildFirstRunSetupHtml explains external yomitan mode and keeps finish ena
dictionaryCount: 0,
canFinish: true,
externalYomitanConfigured: true,
pluginStatus: 'optional',
pluginStatus: 'installed',
pluginInstallPathSummary: null,
mpvExecutablePath: '',
mpvExecutablePathStatus: 'blank',
windowsMpvShortcuts: {
supported: false,
startMenuEnabled: true,
@@ -83,9 +146,22 @@ test('buildFirstRunSetupHtml explains external yomitan mode and keeps finish ena
});
test('parseFirstRunSetupSubmissionUrl parses supported custom actions', () => {
assert.deepEqual(
parseFirstRunSetupSubmissionUrl(
'subminer://first-run-setup?action=configure-mpv-executable-path&mpvExecutablePath=C%3A%5CApps%5Cmpv%5Cmpv.exe',
),
{
action: 'configure-mpv-executable-path',
mpvExecutablePath: 'C:\\Apps\\mpv\\mpv.exe',
},
);
assert.deepEqual(parseFirstRunSetupSubmissionUrl('subminer://first-run-setup?action=refresh'), {
action: 'refresh',
});
assert.equal(
parseFirstRunSetupSubmissionUrl('subminer://first-run-setup?action=skip-plugin'),
null,
);
assert.equal(parseFirstRunSetupSubmissionUrl('https://example.com'), null);
});
@@ -121,6 +197,25 @@ test('first-run setup navigation handler prevents default and dispatches action'
assert.deepEqual(calls, ['preventDefault', 'install-plugin']);
});
test('first-run setup navigation handler swallows stale custom-scheme actions', () => {
const calls: string[] = [];
const handleNavigation = createHandleFirstRunSetupNavigationHandler({
parseSubmissionUrl: (url) => parseFirstRunSetupSubmissionUrl(url),
handleAction: async (submission) => {
calls.push(submission.action);
},
logError: (message) => calls.push(message),
});
const prevented = handleNavigation({
url: 'subminer://first-run-setup?action=skip-plugin',
preventDefault: () => calls.push('preventDefault'),
});
assert.equal(prevented, true);
assert.deepEqual(calls, ['preventDefault']);
});
test('closing incomplete first-run setup quits app outside background mode', async () => {
const calls: string[] = [];
let closedHandler: (() => void) | undefined;
@@ -146,8 +241,10 @@ test('closing incomplete first-run setup quits app outside background mode', asy
dictionaryCount: 0,
canFinish: false,
externalYomitanConfigured: false,
pluginStatus: 'optional',
pluginStatus: 'required',
pluginInstallPathSummary: null,
mpvExecutablePath: '',
mpvExecutablePathStatus: 'blank',
windowsMpvShortcuts: {
supported: false,
startMenuEnabled: true,