mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-11 04:19:26 -07:00
Improve startup dictionary sync UX and default playback keybindings
- Add default `f` fullscreen overlay binding and switch default AniSkip skip key to `Tab` - Make character-dictionary auto-sync non-blocking at startup with tokenization gating for Yomitan mutations - Add ordered startup OSD progress (checking/generating/updating/importing), refresh current subtitle on sync completion, and extend regression tests
This commit is contained in:
70
src/main/runtime/current-media-tokenization-gate.ts
Normal file
70
src/main/runtime/current-media-tokenization-gate.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
function normalizeMediaPath(mediaPath: string | null | undefined): string | null {
|
||||
if (typeof mediaPath !== 'string') {
|
||||
return null;
|
||||
}
|
||||
const trimmed = mediaPath.trim();
|
||||
return trimmed.length > 0 ? trimmed : null;
|
||||
}
|
||||
|
||||
export function createCurrentMediaTokenizationGate(): {
|
||||
updateCurrentMediaPath: (mediaPath: string | null | undefined) => void;
|
||||
markReady: (mediaPath: string | null | undefined) => void;
|
||||
waitUntilReady: (mediaPath: string | null | undefined) => Promise<void>;
|
||||
} {
|
||||
let currentMediaPath: string | null = null;
|
||||
let readyMediaPath: string | null = null;
|
||||
let pendingMediaPath: string | null = null;
|
||||
let pendingPromise: Promise<void> | null = null;
|
||||
let resolvePending: (() => void) | null = null;
|
||||
|
||||
const resolvePendingWaiter = (): void => {
|
||||
resolvePending?.();
|
||||
resolvePending = null;
|
||||
pendingPromise = null;
|
||||
pendingMediaPath = null;
|
||||
};
|
||||
|
||||
const ensurePendingPromise = (mediaPath: string): Promise<void> => {
|
||||
if (pendingMediaPath === mediaPath && pendingPromise) {
|
||||
return pendingPromise;
|
||||
}
|
||||
resolvePendingWaiter();
|
||||
pendingMediaPath = mediaPath;
|
||||
pendingPromise = new Promise<void>((resolve) => {
|
||||
resolvePending = resolve;
|
||||
});
|
||||
return pendingPromise;
|
||||
};
|
||||
|
||||
return {
|
||||
updateCurrentMediaPath: (mediaPath) => {
|
||||
const normalizedPath = normalizeMediaPath(mediaPath);
|
||||
if (normalizedPath === currentMediaPath) {
|
||||
return;
|
||||
}
|
||||
currentMediaPath = normalizedPath;
|
||||
readyMediaPath = null;
|
||||
resolvePendingWaiter();
|
||||
if (normalizedPath) {
|
||||
ensurePendingPromise(normalizedPath);
|
||||
}
|
||||
},
|
||||
markReady: (mediaPath) => {
|
||||
const normalizedPath = normalizeMediaPath(mediaPath);
|
||||
if (!normalizedPath) {
|
||||
return;
|
||||
}
|
||||
readyMediaPath = normalizedPath;
|
||||
if (pendingMediaPath === normalizedPath) {
|
||||
resolvePendingWaiter();
|
||||
}
|
||||
},
|
||||
waitUntilReady: async (mediaPath) => {
|
||||
const normalizedPath = normalizeMediaPath(mediaPath) ?? currentMediaPath;
|
||||
if (!normalizedPath || readyMediaPath === normalizedPath) {
|
||||
return;
|
||||
}
|
||||
await ensurePendingPromise(normalizedPath);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user