mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-28 00:55:16 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
bb6bb04c49
|
@@ -0,0 +1,5 @@
|
|||||||
|
type: fixed
|
||||||
|
area: release
|
||||||
|
|
||||||
|
- Fixed macOS packaging so the compiled mpv window helper is built into `dist/scripts` and required in the app bundle, preventing the overlay from falling back to slow Swift source startup.
|
||||||
|
- Removed a stale Windows helper resource entry that produced harmless missing-file warnings during packaging.
|
||||||
+1
-5
@@ -72,7 +72,7 @@
|
|||||||
"test:launcher": "bun run test:launcher:src",
|
"test:launcher": "bun run test:launcher:src",
|
||||||
"test:core": "bun run test:core:src",
|
"test:core": "bun run test:core:src",
|
||||||
"test:subtitle": "bun run test:subtitle:src",
|
"test:subtitle": "bun run test:subtitle:src",
|
||||||
"test:fast": "bun run test:config:src && bun run test:core:src && bun run test:docs:kb && bun test src/main-entry-runtime.test.ts src/anki-integration.test.ts src/anki-integration/card-creation-manual-update.test.ts src/anki-integration/anki-connect-proxy.test.ts src/anki-integration/field-grouping-workflow.test.ts src/anki-integration/field-grouping.test.ts src/anki-integration/field-grouping-merge.test.ts src/release-workflow.test.ts src/prerelease-workflow.test.ts src/ci-workflow.test.ts scripts/docs-versioning.test.ts scripts/docs-versioned-assets.test.ts scripts/build-changelog.test.ts scripts/electron-builder-after-pack.test.ts scripts/get-mpv-window-macos.test.ts scripts/mkv-to-readme-video.test.ts scripts/run-coverage-lane.test.ts scripts/update-aur-package.test.ts && bun test src/core/services/immersion-tracker/__tests__/query.test.ts src/core/services/immersion-tracker/__tests__/query-split-modules.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
|
"test:fast": "bun run test:config:src && bun run test:core:src && bun run test:docs:kb && bun test src/main-entry-runtime.test.ts src/anki-integration.test.ts src/anki-integration/card-creation-manual-update.test.ts src/anki-integration/anki-connect-proxy.test.ts src/anki-integration/field-grouping-workflow.test.ts src/anki-integration/field-grouping.test.ts src/anki-integration/field-grouping-merge.test.ts src/release-workflow.test.ts src/prerelease-workflow.test.ts src/ci-workflow.test.ts scripts/docs-versioning.test.ts scripts/docs-versioned-assets.test.ts scripts/build-changelog.test.ts scripts/electron-builder-after-pack.test.ts scripts/get-mpv-window-macos.test.ts scripts/prepare-build-assets.test.ts scripts/mkv-to-readme-video.test.ts scripts/run-coverage-lane.test.ts scripts/update-aur-package.test.ts && bun test src/core/services/immersion-tracker/__tests__/query.test.ts src/core/services/immersion-tracker/__tests__/query-split-modules.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
|
||||||
"generate:config-example": "bun run src/generate-config-example.ts",
|
"generate:config-example": "bun run src/generate-config-example.ts",
|
||||||
"verify:config-example": "bun run src/verify-config-example.ts",
|
"verify:config-example": "bun run src/verify-config-example.ts",
|
||||||
"start": "bun run build && electron . --start",
|
"start": "bun run build && electron . --start",
|
||||||
@@ -257,10 +257,6 @@
|
|||||||
{
|
{
|
||||||
"from": "dist/launcher/subminer",
|
"from": "dist/launcher/subminer",
|
||||||
"to": "launcher/subminer"
|
"to": "launcher/subminer"
|
||||||
},
|
|
||||||
{
|
|
||||||
"from": "dist/scripts/get-mpv-window-windows.ps1",
|
|
||||||
"to": "scripts/get-mpv-window-windows.ps1"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,24 @@
|
|||||||
const fs = require('node:fs/promises');
|
const fs = require('node:fs/promises');
|
||||||
|
const fsSync = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
|
|
||||||
const LINUX_FFMPEG_LIBRARY = 'libffmpeg.so';
|
const LINUX_FFMPEG_LIBRARY = 'libffmpeg.so';
|
||||||
|
const MACOS_WINDOW_HELPER = 'get-mpv-window-macos';
|
||||||
|
const DEFAULT_MACOS_APP_BUNDLE = 'SubMiner.app';
|
||||||
|
|
||||||
|
function resolveMacOSAppBundlePath(context) {
|
||||||
|
if (context.appOutDir.endsWith('.app')) {
|
||||||
|
return context.appOutDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
const productFilename = context.packager?.appInfo?.productFilename;
|
||||||
|
const bundleName =
|
||||||
|
typeof productFilename === 'string' && productFilename.trim()
|
||||||
|
? `${productFilename.trim()}.app`
|
||||||
|
: DEFAULT_MACOS_APP_BUNDLE;
|
||||||
|
|
||||||
|
return path.join(context.appOutDir, bundleName);
|
||||||
|
}
|
||||||
|
|
||||||
async function stageLinuxAppImageSharedLibrary(
|
async function stageLinuxAppImageSharedLibrary(
|
||||||
context,
|
context,
|
||||||
@@ -35,12 +52,50 @@ async function stageLinuxAppImageSharedLibrary(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function verifyMacOSWindowHelper(
|
||||||
|
context,
|
||||||
|
deps = {
|
||||||
|
access: (filePath, mode) => fs.access(filePath, mode),
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
if (context.electronPlatformName !== 'darwin') return false;
|
||||||
|
|
||||||
|
const appBundlePath = resolveMacOSAppBundlePath(context);
|
||||||
|
const helperPath = path.join(
|
||||||
|
appBundlePath,
|
||||||
|
'Contents',
|
||||||
|
'Resources',
|
||||||
|
'scripts',
|
||||||
|
MACOS_WINDOW_HELPER,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deps.access(helperPath, fsSync.constants.X_OK);
|
||||||
|
} catch (error) {
|
||||||
|
if (error && typeof error === 'object' && error.code === 'ENOENT') {
|
||||||
|
throw new Error(
|
||||||
|
`macOS packaging requires ${MACOS_WINDOW_HELPER} at ${helperPath}. Run bun run build:assets on macOS with swiftc available before packaging.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (error && typeof error === 'object' && error.code === 'EACCES') {
|
||||||
|
throw new Error(`macOS window helper is not executable: ${helperPath}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async function afterPack(context) {
|
async function afterPack(context) {
|
||||||
await stageLinuxAppImageSharedLibrary(context);
|
await stageLinuxAppImageSharedLibrary(context);
|
||||||
|
await verifyMacOSWindowHelper(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
LINUX_FFMPEG_LIBRARY,
|
LINUX_FFMPEG_LIBRARY,
|
||||||
|
MACOS_WINDOW_HELPER,
|
||||||
|
resolveMacOSAppBundlePath,
|
||||||
stageLinuxAppImageSharedLibrary,
|
stageLinuxAppImageSharedLibrary,
|
||||||
|
verifyMacOSWindowHelper,
|
||||||
default: afterPack,
|
default: afterPack,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,15 +6,22 @@ import test from 'node:test';
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
LINUX_FFMPEG_LIBRARY,
|
LINUX_FFMPEG_LIBRARY,
|
||||||
|
MACOS_WINDOW_HELPER,
|
||||||
default: afterPack,
|
default: afterPack,
|
||||||
stageLinuxAppImageSharedLibrary,
|
stageLinuxAppImageSharedLibrary,
|
||||||
|
verifyMacOSWindowHelper,
|
||||||
} = require('./electron-builder-after-pack.cjs') as {
|
} = require('./electron-builder-after-pack.cjs') as {
|
||||||
LINUX_FFMPEG_LIBRARY: string;
|
LINUX_FFMPEG_LIBRARY: string;
|
||||||
|
MACOS_WINDOW_HELPER: string;
|
||||||
default: (context: { appOutDir: string; electronPlatformName: string }) => Promise<void>;
|
default: (context: { appOutDir: string; electronPlatformName: string }) => Promise<void>;
|
||||||
stageLinuxAppImageSharedLibrary: (context: {
|
stageLinuxAppImageSharedLibrary: (context: {
|
||||||
appOutDir: string;
|
appOutDir: string;
|
||||||
electronPlatformName: string;
|
electronPlatformName: string;
|
||||||
}) => Promise<boolean>;
|
}) => Promise<boolean>;
|
||||||
|
verifyMacOSWindowHelper: (context: {
|
||||||
|
appOutDir: string;
|
||||||
|
electronPlatformName: string;
|
||||||
|
}) => Promise<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function createWorkspace(name: string): string {
|
function createWorkspace(name: string): string {
|
||||||
@@ -65,6 +72,53 @@ test('stageLinuxAppImageSharedLibrary skips non-Linux packaging contexts', async
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('verifyMacOSWindowHelper accepts packaged macOS helper binary', async () => {
|
||||||
|
const workspace = createWorkspace('subminer-after-pack-macos-helper');
|
||||||
|
const appOutDir = path.join(workspace, 'SubMiner-darwin-arm64');
|
||||||
|
const helperPath = path.join(
|
||||||
|
appOutDir,
|
||||||
|
'SubMiner.app',
|
||||||
|
'Contents',
|
||||||
|
'Resources',
|
||||||
|
'scripts',
|
||||||
|
MACOS_WINDOW_HELPER,
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.mkdirSync(path.dirname(helperPath), { recursive: true });
|
||||||
|
fs.writeFileSync(helperPath, 'compiled helper', 'utf8');
|
||||||
|
fs.chmodSync(helperPath, 0o755);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const verified = await verifyMacOSWindowHelper({
|
||||||
|
appOutDir,
|
||||||
|
electronPlatformName: 'darwin',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(verified, true);
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(workspace, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verifyMacOSWindowHelper throws when macOS helper binary is missing', async () => {
|
||||||
|
const workspace = createWorkspace('subminer-after-pack-macos-helper-missing');
|
||||||
|
const appOutDir = path.join(workspace, 'SubMiner-darwin-arm64');
|
||||||
|
|
||||||
|
fs.mkdirSync(path.join(appOutDir, 'SubMiner.app', 'Contents', 'Resources'), { recursive: true });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await assert.rejects(
|
||||||
|
verifyMacOSWindowHelper({
|
||||||
|
appOutDir,
|
||||||
|
electronPlatformName: 'darwin',
|
||||||
|
}),
|
||||||
|
/macOS packaging requires get-mpv-window-macos/,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(workspace, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('stageLinuxAppImageSharedLibrary throws when Linux packaging is missing libffmpeg.so', async () => {
|
test('stageLinuxAppImageSharedLibrary throws when Linux packaging is missing libffmpeg.so', async () => {
|
||||||
const workspace = createWorkspace('subminer-after-pack-missing-library');
|
const workspace = createWorkspace('subminer-after-pack-missing-library');
|
||||||
const appOutDir = path.join(workspace, 'SubMiner-linux-x64');
|
const appOutDir = path.join(workspace, 'SubMiner-linux-x64');
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ function buildMacosHelper() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureDir(scriptsOutputDir);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execFileSync('swiftc', ['-O', macosHelperSourcePath, '-o', macosHelperBinaryPath], {
|
execFileSync('swiftc', ['-O', macosHelperSourcePath, '-o', macosHelperBinaryPath], {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
const source = readFileSync('scripts/prepare-build-assets.mjs', 'utf8');
|
||||||
|
|
||||||
|
test('macOS helper build creates dist scripts directory before swiftc output', () => {
|
||||||
|
const buildFunctionIndex = source.indexOf('function buildMacosHelper()');
|
||||||
|
assert.notEqual(buildFunctionIndex, -1);
|
||||||
|
|
||||||
|
const swiftcIndex = source.indexOf("execFileSync('swiftc'", buildFunctionIndex);
|
||||||
|
assert.notEqual(swiftcIndex, -1);
|
||||||
|
|
||||||
|
const ensureDirIndex = source.lastIndexOf('ensureDir(scriptsOutputDir)', swiftcIndex);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
ensureDirIndex > buildFunctionIndex,
|
||||||
|
'buildMacosHelper must create dist/scripts before swiftc writes the helper binary',
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -190,6 +190,14 @@ test('release packaging stages generated launcher as an app resource', () => {
|
|||||||
assert.match(packageJson.scripts['build:launcher'] ?? '', /--banner='#!\/usr\/bin\/env bun'/);
|
assert.match(packageJson.scripts['build:launcher'] ?? '', /--banner='#!\/usr\/bin\/env bun'/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('release packaging does not reference removed Windows window helper script', () => {
|
||||||
|
assert.ok(
|
||||||
|
!(packageJson.build?.extraResources ?? []).some((resource) =>
|
||||||
|
[resource.from, resource.to].some((value) => value?.includes('get-mpv-window-windows.ps1')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('Makefile clean preserves committed prerelease notes', () => {
|
test('Makefile clean preserves committed prerelease notes', () => {
|
||||||
assert.match(makefile, /PRERELEASE_NOTES_BACKUP/);
|
assert.match(makefile, /PRERELEASE_NOTES_BACKUP/);
|
||||||
assert.match(makefile, /release\/prerelease-notes\.md/);
|
assert.match(makefile, /release\/prerelease-notes\.md/);
|
||||||
|
|||||||
Reference in New Issue
Block a user