Overlay 2.0 (#12)

This commit is contained in:
2026-03-01 02:36:51 -08:00
committed by GitHub
parent 45df3c466b
commit 44c7761c7c
397 changed files with 15139 additions and 7127 deletions

View File

@@ -13,6 +13,17 @@ function shouldAutoConnectJellyfinRemote(config: {
return config.enabled && config.remoteControlEnabled && config.remoteControlAutoConnect;
}
function createDeferred(): {
promise: Promise<void>;
resolve: () => void;
} {
let resolve!: () => void;
const promise = new Promise<void>((nextResolve) => {
resolve = nextResolve;
});
return { promise, resolve };
}
test('launchBackgroundWarmupTask logs completion timing', async () => {
const debugLogs: string[] = [];
const launchTask = createLaunchBackgroundWarmupTaskHandler({
@@ -41,6 +52,10 @@ test('startBackgroundWarmups no-ops when already started', () => {
createMecabTokenizerAndCheck: async () => {},
ensureYomitanExtensionLoaded: async () => {},
prewarmSubtitleDictionaries: async () => {},
shouldWarmupMecab: () => true,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => true,
shouldWarmupJellyfinRemoteSession: () => true,
shouldAutoConnectJellyfinRemote: () => false,
startJellyfinRemoteSession: async () => {},
});
@@ -49,7 +64,7 @@ test('startBackgroundWarmups no-ops when already started', () => {
assert.equal(launches, 0);
});
test('startBackgroundWarmups does not schedule jellyfin warmup when jellyfin.enabled is false', () => {
test('startBackgroundWarmups respects per-integration warmup toggles', () => {
const labels: string[] = [];
let started = false;
const startWarmups = createStartBackgroundWarmupsHandler({
@@ -64,9 +79,13 @@ test('startBackgroundWarmups does not schedule jellyfin warmup when jellyfin.ena
createMecabTokenizerAndCheck: async () => {},
ensureYomitanExtensionLoaded: async () => {},
prewarmSubtitleDictionaries: async () => {},
shouldWarmupMecab: () => false,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => false,
shouldWarmupJellyfinRemoteSession: () => false,
shouldAutoConnectJellyfinRemote: () =>
shouldAutoConnectJellyfinRemote({
enabled: false,
enabled: true,
remoteControlEnabled: true,
remoteControlAutoConnect: true,
}),
@@ -75,7 +94,7 @@ test('startBackgroundWarmups does not schedule jellyfin warmup when jellyfin.ena
startWarmups();
assert.equal(started, true);
assert.deepEqual(labels, ['mecab', 'yomitan-extension', 'subtitle-dictionaries']);
assert.deepEqual(labels, ['subtitle-tokenization']);
});
test('startBackgroundWarmups schedules jellyfin warmup when all jellyfin flags are enabled', () => {
@@ -93,6 +112,10 @@ test('startBackgroundWarmups schedules jellyfin warmup when all jellyfin flags a
createMecabTokenizerAndCheck: async () => {},
ensureYomitanExtensionLoaded: async () => {},
prewarmSubtitleDictionaries: async () => {},
shouldWarmupMecab: () => true,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => true,
shouldWarmupJellyfinRemoteSession: () => true,
shouldAutoConnectJellyfinRemote: () =>
shouldAutoConnectJellyfinRemote({
enabled: true,
@@ -104,10 +127,138 @@ test('startBackgroundWarmups schedules jellyfin warmup when all jellyfin flags a
startWarmups();
assert.equal(started, true);
assert.deepEqual(labels, [
'mecab',
'yomitan-extension',
'subtitle-dictionaries',
'jellyfin-remote-session',
]);
assert.deepEqual(labels, ['subtitle-tokenization', 'jellyfin-remote-session']);
});
test('startBackgroundWarmups skips jellyfin warmup when warmup is deferred', () => {
const labels: string[] = [];
let started = false;
const startWarmups = createStartBackgroundWarmupsHandler({
getStarted: () => started,
setStarted: (value) => {
started = value;
},
isTexthookerOnlyMode: () => false,
launchTask: (label) => {
labels.push(label);
},
createMecabTokenizerAndCheck: async () => {},
ensureYomitanExtensionLoaded: async () => {},
prewarmSubtitleDictionaries: async () => {},
shouldWarmupMecab: () => false,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => false,
shouldWarmupJellyfinRemoteSession: () => false,
shouldAutoConnectJellyfinRemote: () =>
shouldAutoConnectJellyfinRemote({
enabled: true,
remoteControlEnabled: true,
remoteControlAutoConnect: true,
}),
startJellyfinRemoteSession: async () => {},
});
startWarmups();
assert.equal(started, true);
assert.deepEqual(labels, ['subtitle-tokenization']);
});
test('startBackgroundWarmups logs per-stage progress for enabled tokenization warmups', async () => {
const debugLogs: string[] = [];
const labels: string[] = [];
let started = false;
const startWarmups = createStartBackgroundWarmupsHandler({
getStarted: () => started,
setStarted: (value) => {
started = value;
},
isTexthookerOnlyMode: () => false,
launchTask: (label, task) => {
labels.push(label);
void task();
},
createMecabTokenizerAndCheck: async () => {},
ensureYomitanExtensionLoaded: async () => {},
prewarmSubtitleDictionaries: async () => {},
shouldWarmupMecab: () => true,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => true,
shouldWarmupJellyfinRemoteSession: () => true,
shouldAutoConnectJellyfinRemote: () => true,
startJellyfinRemoteSession: async () => {},
logDebug: (message) => {
debugLogs.push(message);
},
});
startWarmups();
await Promise.resolve();
await Promise.resolve();
assert.deepEqual(labels, ['subtitle-tokenization', 'jellyfin-remote-session']);
assert.ok(debugLogs.includes('[startup-warmup] stage start: yomitan-extension'));
assert.ok(debugLogs.includes('[startup-warmup] stage ready: yomitan-extension'));
assert.ok(debugLogs.includes('[startup-warmup] stage start: mecab'));
assert.ok(debugLogs.includes('[startup-warmup] stage ready: mecab'));
assert.ok(debugLogs.includes('[startup-warmup] stage start: subtitle-dictionaries'));
assert.ok(debugLogs.includes('[startup-warmup] stage ready: subtitle-dictionaries'));
assert.ok(debugLogs.includes('[startup-warmup] stage start: jellyfin-remote-session'));
assert.ok(debugLogs.includes('[startup-warmup] stage ready: jellyfin-remote-session'));
});
test('startBackgroundWarmups starts mecab and dictionary warmups without waiting for yomitan warmup', async () => {
const startedStages: string[] = [];
let started = false;
let subtitleTokenizationTask: Promise<void> | null = null;
const yomitanDeferred = createDeferred();
const mecabDeferred = createDeferred();
const subtitleDictionariesDeferred = createDeferred();
const startWarmups = createStartBackgroundWarmupsHandler({
getStarted: () => started,
setStarted: (value) => {
started = value;
},
isTexthookerOnlyMode: () => false,
launchTask: (label, task) => {
if (label === 'subtitle-tokenization') {
subtitleTokenizationTask = task();
}
},
createMecabTokenizerAndCheck: async () => {
startedStages.push('mecab');
await mecabDeferred.promise;
},
ensureYomitanExtensionLoaded: async () => {
startedStages.push('yomitan-extension');
await yomitanDeferred.promise;
},
prewarmSubtitleDictionaries: async () => {
startedStages.push('subtitle-dictionaries');
await subtitleDictionariesDeferred.promise;
},
shouldWarmupMecab: () => true,
shouldWarmupYomitanExtension: () => true,
shouldWarmupSubtitleDictionaries: () => true,
shouldWarmupJellyfinRemoteSession: () => false,
shouldAutoConnectJellyfinRemote: () => false,
startJellyfinRemoteSession: async () => {},
});
startWarmups();
await Promise.resolve();
await Promise.resolve();
assert.ok(subtitleTokenizationTask);
assert.equal(startedStages.includes('yomitan-extension'), true);
assert.equal(startedStages.includes('mecab'), true);
assert.equal(startedStages.includes('subtitle-dictionaries'), true);
yomitanDeferred.resolve();
mecabDeferred.resolve();
subtitleDictionariesDeferred.resolve();
if (!subtitleTokenizationTask) {
throw new Error('Expected subtitle tokenization warmup task');
}
await subtitleTokenizationTask;
});