mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-03 06:12:07 -07:00
Fix launcher binary discovery and defaults
This commit is contained in:
@@ -62,6 +62,7 @@ test('createDefaultArgs normalizes configured language codes and env thread over
|
|||||||
assert.deepEqual(parsed.youtubeAudioLangs, ['ja', 'jpn', 'en', 'eng']);
|
assert.deepEqual(parsed.youtubeAudioLangs, ['ja', 'jpn', 'en', 'eng']);
|
||||||
assert.equal(parsed.whisperThreads, 7);
|
assert.equal(parsed.whisperThreads, 7);
|
||||||
assert.equal(parsed.youtubeWhisperSourceLanguage, 'ja');
|
assert.equal(parsed.youtubeWhisperSourceLanguage, 'ja');
|
||||||
|
assert.equal(parsed.profile, '');
|
||||||
} finally {
|
} finally {
|
||||||
if (originalThreads === undefined) {
|
if (originalThreads === undefined) {
|
||||||
delete process.env.SUBMINER_WHISPER_THREADS;
|
delete process.env.SUBMINER_WHISPER_THREADS;
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export function createDefaultArgs(launcherConfig: LauncherYoutubeSubgenConfig):
|
|||||||
backend: 'auto',
|
backend: 'auto',
|
||||||
directory: '.',
|
directory: '.',
|
||||||
recursive: false,
|
recursive: false,
|
||||||
profile: 'subminer',
|
profile: '',
|
||||||
startOverlay: false,
|
startOverlay: false,
|
||||||
whisperBin: process.env.SUBMINER_WHISPER_BIN || launcherConfig.whisperBin || '',
|
whisperBin: process.env.SUBMINER_WHISPER_BIN || launcherConfig.whisperBin || '',
|
||||||
whisperModel: process.env.SUBMINER_WHISPER_MODEL || launcherConfig.whisperModel || '',
|
whisperModel: process.env.SUBMINER_WHISPER_MODEL || launcherConfig.whisperModel || '',
|
||||||
|
|||||||
@@ -427,6 +427,16 @@ function withFindAppBinaryEnvSandbox(run: () => void): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withFindAppBinaryPlatformSandbox(platform: NodeJS.Platform, run: () => void): void {
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
try {
|
||||||
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
||||||
|
withFindAppBinaryEnvSandbox(run);
|
||||||
|
} finally {
|
||||||
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function withAccessSyncStub(
|
function withAccessSyncStub(
|
||||||
isExecutablePath: (filePath: string) => boolean,
|
isExecutablePath: (filePath: string) => boolean,
|
||||||
run: () => void,
|
run: () => void,
|
||||||
@@ -455,7 +465,7 @@ test('findAppBinary resolves ~/.local/bin/SubMiner.AppImage when it exists', ()
|
|||||||
const appImage = path.join(baseDir, '.local/bin/SubMiner.AppImage');
|
const appImage = path.join(baseDir, '.local/bin/SubMiner.AppImage');
|
||||||
makeExecutable(appImage);
|
makeExecutable(appImage);
|
||||||
|
|
||||||
withFindAppBinaryEnvSandbox(() => {
|
withFindAppBinaryPlatformSandbox('linux', () => {
|
||||||
const result = findAppBinary('/some/other/path/subminer');
|
const result = findAppBinary('/some/other/path/subminer');
|
||||||
assert.equal(result, appImage);
|
assert.equal(result, appImage);
|
||||||
});
|
});
|
||||||
@@ -470,7 +480,7 @@ test('findAppBinary resolves /opt/SubMiner/SubMiner.AppImage when ~/.local/bin c
|
|||||||
const originalHomedir = os.homedir;
|
const originalHomedir = os.homedir;
|
||||||
try {
|
try {
|
||||||
os.homedir = () => baseDir;
|
os.homedir = () => baseDir;
|
||||||
withFindAppBinaryEnvSandbox(() => {
|
withFindAppBinaryPlatformSandbox('linux', () => {
|
||||||
withAccessSyncStub(
|
withAccessSyncStub(
|
||||||
(filePath) => filePath === '/opt/SubMiner/SubMiner.AppImage',
|
(filePath) => filePath === '/opt/SubMiner/SubMiner.AppImage',
|
||||||
() => {
|
() => {
|
||||||
@@ -497,7 +507,7 @@ test('findAppBinary finds subminer on PATH when AppImage candidates do not exist
|
|||||||
makeExecutable(wrapperPath);
|
makeExecutable(wrapperPath);
|
||||||
process.env.PATH = `${binDir}${path.delimiter}${originalPath ?? ''}`;
|
process.env.PATH = `${binDir}${path.delimiter}${originalPath ?? ''}`;
|
||||||
|
|
||||||
withFindAppBinaryEnvSandbox(() => {
|
withFindAppBinaryPlatformSandbox('linux', () => {
|
||||||
withAccessSyncStub(
|
withAccessSyncStub(
|
||||||
(filePath) => filePath === wrapperPath,
|
(filePath) => filePath === wrapperPath,
|
||||||
() => {
|
() => {
|
||||||
@@ -513,3 +523,59 @@ test('findAppBinary finds subminer on PATH when AppImage candidates do not exist
|
|||||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('findAppBinary resolves Windows install paths when present', () => {
|
||||||
|
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-win-'));
|
||||||
|
const originalHomedir = os.homedir;
|
||||||
|
const originalLocalAppData = process.env.LOCALAPPDATA;
|
||||||
|
try {
|
||||||
|
os.homedir = () => baseDir;
|
||||||
|
process.env.LOCALAPPDATA = path.join(baseDir, 'AppData', 'Local');
|
||||||
|
const appExe = path.join(baseDir, 'AppData', 'Local', 'Programs', 'SubMiner', 'SubMiner.exe');
|
||||||
|
|
||||||
|
withFindAppBinaryPlatformSandbox('win32', () => {
|
||||||
|
withAccessSyncStub(
|
||||||
|
(filePath) => filePath === appExe,
|
||||||
|
() => {
|
||||||
|
const result = findAppBinary(path.join(baseDir, 'launcher', 'SubMiner.exe'));
|
||||||
|
assert.equal(result, appExe);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
os.homedir = originalHomedir;
|
||||||
|
if (originalLocalAppData === undefined) {
|
||||||
|
delete process.env.LOCALAPPDATA;
|
||||||
|
} else {
|
||||||
|
process.env.LOCALAPPDATA = originalLocalAppData;
|
||||||
|
}
|
||||||
|
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('findAppBinary resolves SubMiner.exe on PATH on Windows', () => {
|
||||||
|
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-win-path-'));
|
||||||
|
const originalHomedir = os.homedir;
|
||||||
|
const originalPath = process.env.PATH;
|
||||||
|
try {
|
||||||
|
os.homedir = () => baseDir;
|
||||||
|
const binDir = path.join(baseDir, 'bin');
|
||||||
|
const wrapperPath = path.join(binDir, 'SubMiner.exe');
|
||||||
|
makeExecutable(wrapperPath);
|
||||||
|
process.env.PATH = `${binDir}${path.delimiter}${originalPath ?? ''}`;
|
||||||
|
|
||||||
|
withFindAppBinaryPlatformSandbox('win32', () => {
|
||||||
|
withAccessSyncStub(
|
||||||
|
(filePath) => filePath === wrapperPath,
|
||||||
|
() => {
|
||||||
|
const result = findAppBinary(path.join(baseDir, 'launcher', 'SubMiner.exe'));
|
||||||
|
assert.equal(result, wrapperPath);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
os.homedir = originalHomedir;
|
||||||
|
process.env.PATH = originalPath;
|
||||||
|
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -243,18 +243,44 @@ export function detectBackend(backend: Backend): Exclude<Backend, 'auto'> {
|
|||||||
fail('Could not detect display backend');
|
fail('Could not detect display backend');
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveMacAppBinaryCandidate(candidate: string): string {
|
function resolveAppBinaryCandidate(candidate: string): string {
|
||||||
const direct = resolveBinaryPathCandidate(candidate);
|
const direct = resolveBinaryPathCandidate(candidate);
|
||||||
if (!direct) return '';
|
if (!direct) return '';
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
return isExecutable(direct) ? direct : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isExecutable(direct)) {
|
if (isExecutable(direct)) {
|
||||||
return direct;
|
return direct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(direct) && fs.statSync(direct).isDirectory()) {
|
||||||
|
for (const candidateBinary of ['SubMiner.exe', 'subminer.exe']) {
|
||||||
|
const nestedCandidate = path.join(direct, candidateBinary);
|
||||||
|
if (isExecutable(nestedCandidate)) {
|
||||||
|
return nestedCandidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.extname(direct)) {
|
||||||
|
for (const extension of ['.exe', '.cmd', '.bat']) {
|
||||||
|
const withExtension = `${direct}${extension}`;
|
||||||
|
if (isExecutable(withExtension)) {
|
||||||
|
return withExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
const appIndex = direct.indexOf('.app/');
|
const appIndex = direct.indexOf('.app/');
|
||||||
const appPath =
|
const appPath =
|
||||||
direct.endsWith('.app') && direct.includes('.app')
|
direct.endsWith('.app') && direct.includes('.app')
|
||||||
@@ -278,37 +304,73 @@ function resolveMacAppBinaryCandidate(candidate: string): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findCommandOnPath(candidates: string[]): string {
|
||||||
|
const pathDirs = getPathEnv().split(path.delimiter);
|
||||||
|
for (const candidateName of candidates) {
|
||||||
|
for (const dir of pathDirs) {
|
||||||
|
if (!dir) continue;
|
||||||
|
|
||||||
|
const directCandidate = path.join(dir, candidateName);
|
||||||
|
if (isExecutable(directCandidate)) {
|
||||||
|
return directCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32' && !path.extname(candidateName)) {
|
||||||
|
for (const extension of ['.exe', '.cmd', '.bat']) {
|
||||||
|
const extendedCandidate = path.join(dir, `${candidateName}${extension}`);
|
||||||
|
if (isExecutable(extendedCandidate)) {
|
||||||
|
return extendedCandidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
export function findAppBinary(selfPath: string): string | null {
|
export function findAppBinary(selfPath: string): string | null {
|
||||||
const envPaths = [process.env.SUBMINER_APPIMAGE_PATH, process.env.SUBMINER_BINARY_PATH].filter(
|
const envPaths = [process.env.SUBMINER_APPIMAGE_PATH, process.env.SUBMINER_BINARY_PATH].filter(
|
||||||
(candidate): candidate is string => Boolean(candidate),
|
(candidate): candidate is string => Boolean(candidate),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const envPath of envPaths) {
|
for (const envPath of envPaths) {
|
||||||
const resolved = resolveMacAppBinaryCandidate(envPath);
|
const resolved = resolveAppBinaryCandidate(envPath);
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const candidates: string[] = [];
|
const candidates: string[] = [];
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'win32') {
|
||||||
|
const localAppData =
|
||||||
|
process.env.LOCALAPPDATA?.trim() ||
|
||||||
|
(process.env.APPDATA?.trim() || '').replace(/[\\/]Roaming$/i, `${path.sep}Local`) ||
|
||||||
|
path.join(os.homedir(), 'AppData', 'Local');
|
||||||
|
const programFiles = process.env.ProgramFiles?.trim() || 'C:\\Program Files';
|
||||||
|
const programFilesX86 = process.env['ProgramFiles(x86)']?.trim() || 'C:\\Program Files (x86)';
|
||||||
|
candidates.push(path.join(localAppData, 'Programs', 'SubMiner', 'SubMiner.exe'));
|
||||||
|
candidates.push(path.join(programFiles, 'SubMiner', 'SubMiner.exe'));
|
||||||
|
candidates.push(path.join(programFilesX86, 'SubMiner', 'SubMiner.exe'));
|
||||||
|
candidates.push('C:\\SubMiner\\SubMiner.exe');
|
||||||
|
} else if (process.platform === 'darwin') {
|
||||||
candidates.push('/Applications/SubMiner.app/Contents/MacOS/SubMiner');
|
candidates.push('/Applications/SubMiner.app/Contents/MacOS/SubMiner');
|
||||||
candidates.push('/Applications/SubMiner.app/Contents/MacOS/subminer');
|
candidates.push('/Applications/SubMiner.app/Contents/MacOS/subminer');
|
||||||
candidates.push(path.join(os.homedir(), 'Applications/SubMiner.app/Contents/MacOS/SubMiner'));
|
candidates.push(path.join(os.homedir(), 'Applications/SubMiner.app/Contents/MacOS/SubMiner'));
|
||||||
candidates.push(path.join(os.homedir(), 'Applications/SubMiner.app/Contents/MacOS/subminer'));
|
candidates.push(path.join(os.homedir(), 'Applications/SubMiner.app/Contents/MacOS/subminer'));
|
||||||
}
|
} else {
|
||||||
|
|
||||||
candidates.push(path.join(os.homedir(), '.local/bin/SubMiner.AppImage'));
|
candidates.push(path.join(os.homedir(), '.local/bin/SubMiner.AppImage'));
|
||||||
candidates.push('/opt/SubMiner/SubMiner.AppImage');
|
candidates.push('/opt/SubMiner/SubMiner.AppImage');
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
|
||||||
if (isExecutable(candidate)) return candidate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fromPath = getPathEnv()
|
for (const candidate of candidates) {
|
||||||
.split(path.delimiter)
|
const resolved = resolveAppBinaryCandidate(candidate);
|
||||||
.map((dir) => path.join(dir, 'subminer'))
|
if (resolved) return resolved;
|
||||||
.find((candidate) => isExecutable(candidate));
|
}
|
||||||
|
|
||||||
|
const fromPath = findCommandOnPath(
|
||||||
|
process.platform === 'win32' ? ['SubMiner', 'subminer'] : ['subminer'],
|
||||||
|
);
|
||||||
|
|
||||||
if (fromPath) {
|
if (fromPath) {
|
||||||
const resolvedSelf = realpathMaybe(selfPath);
|
const resolvedSelf = realpathMaybe(selfPath);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"test-yomitan-parser:electron": "bun run build:yomitan && bun build scripts/test-yomitan-parser.ts --format=cjs --target=node --outfile dist/scripts/test-yomitan-parser.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/test-yomitan-parser.js",
|
"test-yomitan-parser:electron": "bun run build:yomitan && bun build scripts/test-yomitan-parser.ts --format=cjs --target=node --outfile dist/scripts/test-yomitan-parser.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/test-yomitan-parser.js",
|
||||||
"build:yomitan": "bun scripts/build-yomitan.mjs",
|
"build:yomitan": "bun scripts/build-yomitan.mjs",
|
||||||
"build:assets": "bun scripts/prepare-build-assets.mjs",
|
"build:assets": "bun scripts/prepare-build-assets.mjs",
|
||||||
|
"build:launcher": "bun build ./launcher/main.ts --target=bun --packages=bundle --outfile=dist/launcher/subminer",
|
||||||
"build:stats": "cd stats && bun run build",
|
"build:stats": "cd stats && bun run build",
|
||||||
"dev:stats": "cd stats && bun run dev",
|
"dev:stats": "cd stats && bun run dev",
|
||||||
"build": "bun run build:yomitan && bun run build:stats && tsc -p tsconfig.json && bun run build:renderer && bun run build:assets",
|
"build": "bun run build:yomitan && bun run build:stats && tsc -p tsconfig.json && bun run build:renderer && bun run build:assets",
|
||||||
|
|||||||
Reference in New Issue
Block a user