mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
fix(plugin): keep loading OSD off on warm playlist advance (#317)
* fix(plugin): keep loading OSD off on warm playlist advance - Track overlay_content_ready_seen when the app sends subminer-overlay-loading-ready - Skip restarting the "Overlay loading" spinner for an overlay that already reported ready, so it no longer times out into "Overlay did not become ready" (#315) - Reset the flag on stop, restart, start failure and shutdown - Add start-gate tests for warm and not-yet-ready playlist advances * fix(plugin): only report overlay ready once content has loaded Hide paths dismissed the loading OSD with subminer-overlay-loading-ready, which the plugin now remembers to skip the spinner on later playlist files. A hide before the overlay had content would wrongly mark it ready. The app now sends ready only when the overlay window content is ready, and a new stop-only subminer-overlay-loading-dismissed message otherwise. * fix(plugin): resync overlay readiness on dismissal and mpv connect A dismissal now clears the plugin's readiness flag, since the app sends it only while its overlay window has no content (e.g. a replaced window). On mpv (re)connect the app resends subminer-overlay-loading-ready when the overlay already has content, so a ready signal lost while mpv was away, or sent before this mpv's plugin existed, still reaches the plugin. * refactor(main): pass overlay readiness handler directly
This commit is contained in:
1 parent
b99409bbcd
commit
848a6c4021
13 files changed
+309
-9
No files matched your search
@@ -0,0 +1,60 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import type { BrowserWindow } from 'electron';
|
||||
|
||||
import { OVERLAY_WINDOW_CONTENT_READY_FLAG } from '../../core/services/overlay-window-flags';
|
||||
import type { MpvIpcClient } from '../../core/services';
|
||||
import type { ResolvedConfig } from '../../types';
|
||||
import { createOverlayNotificationsRuntime } from './overlay-notifications-runtime';
|
||||
|
||||
function createRuntimeHarness(contentReady: boolean) {
|
||||
const sent: unknown[][] = [];
|
||||
const overlayWindow = {
|
||||
isDestroyed: () => false,
|
||||
[OVERLAY_WINDOW_CONTENT_READY_FLAG]: contentReady,
|
||||
} as unknown as BrowserWindow;
|
||||
const mpvClient = {
|
||||
send: ({ command }: { command: unknown[] }) => {
|
||||
sent.push(command);
|
||||
},
|
||||
} as unknown as MpvIpcClient;
|
||||
const runtime = createOverlayNotificationsRuntime({
|
||||
getResolvedConfig: () => ({}) as ResolvedConfig,
|
||||
getMainOverlayWindow: () => overlayWindow,
|
||||
getVisibleOverlayVisible: () => false,
|
||||
broadcastToOverlayWindows: () => {},
|
||||
showMpvOsd: () => {},
|
||||
getMpvClient: () => mpvClient,
|
||||
getAnkiIntegration: () => null,
|
||||
getRuntimeOptionsManager: () => null,
|
||||
});
|
||||
const scriptMessages = () =>
|
||||
sent.filter((command) => command[0] === 'script-message').map((command) => command[1]);
|
||||
return { runtime, scriptMessages };
|
||||
}
|
||||
|
||||
test('dismissing the loading OSD before overlay content is ready only stops the plugin spinner', () => {
|
||||
const { runtime, scriptMessages } = createRuntimeHarness(false);
|
||||
|
||||
runtime.dismissOverlayLoadingStatusNotification();
|
||||
|
||||
assert.deepEqual(scriptMessages(), ['subminer-overlay-loading-dismissed']);
|
||||
});
|
||||
|
||||
test('dismissing the loading OSD once overlay content is ready reports readiness to the plugin', () => {
|
||||
const { runtime, scriptMessages } = createRuntimeHarness(true);
|
||||
|
||||
runtime.dismissOverlayLoadingStatusNotification();
|
||||
|
||||
assert.deepEqual(scriptMessages(), ['subminer-overlay-loading-ready']);
|
||||
});
|
||||
|
||||
test('reporting overlay readiness after an mpv connect resends ready only for loaded content', () => {
|
||||
const ready = createRuntimeHarness(true);
|
||||
ready.runtime.reportOverlayContentReadyToPlugin();
|
||||
assert.deepEqual(ready.scriptMessages(), ['subminer-overlay-loading-ready']);
|
||||
|
||||
const loading = createRuntimeHarness(false);
|
||||
loading.runtime.reportOverlayContentReadyToPlugin();
|
||||
assert.deepEqual(loading.scriptMessages(), []);
|
||||
});
|
||||
@@ -61,6 +61,7 @@ export function createOverlayNotificationsRuntime(deps: OverlayNotificationsRunt
|
||||
showYoutubeFlowStatusNotification: (message: string) => void;
|
||||
showOverlayLoadingStatusNotification: () => void;
|
||||
dismissOverlayLoadingStatusNotification: () => void;
|
||||
reportOverlayContentReadyToPlugin: () => void;
|
||||
maybeStartOverlayLoadingOsd: (mediaPath?: string | null) => void;
|
||||
} {
|
||||
function isVisibleOverlayContentReady(): boolean {
|
||||
@@ -229,15 +230,39 @@ export function createOverlayNotificationsRuntime(deps: OverlayNotificationsRunt
|
||||
getOverlayLoadingOsdController().start();
|
||||
}
|
||||
|
||||
function isMainOverlayContentReady(): boolean {
|
||||
const overlayWindow = deps.getMainOverlayWindow();
|
||||
return Boolean(overlayWindow && isOverlayWindowContentReady(overlayWindow));
|
||||
}
|
||||
|
||||
function sendPluginOverlayLoadingMessage(
|
||||
message: 'subminer-overlay-loading-ready' | 'subminer-overlay-loading-dismissed',
|
||||
): void {
|
||||
sendMpvCommandRuntime(deps.getMpvClient(), ['script-message', message]);
|
||||
}
|
||||
|
||||
// Hide paths also dismiss, often before the overlay has content. Only a content-ready window
|
||||
// reports `subminer-overlay-loading-ready`: the plugin remembers it and skips the spinner on
|
||||
// later playlist files, so other dismissals send the stop-only message, which also makes the
|
||||
// plugin forget readiness from a replaced window.
|
||||
function dismissOverlayLoadingStatusNotification(): void {
|
||||
getOverlayLoadingOsdController().stop();
|
||||
sendMpvCommandRuntime(deps.getMpvClient(), [
|
||||
'script-message',
|
||||
'subminer-overlay-loading-ready',
|
||||
]);
|
||||
sendPluginOverlayLoadingMessage(
|
||||
isMainOverlayContentReady()
|
||||
? 'subminer-overlay-loading-ready'
|
||||
: 'subminer-overlay-loading-dismissed',
|
||||
);
|
||||
dismissOverlayNotification('overlay-loading-status');
|
||||
}
|
||||
|
||||
// Called when mpv (re)connects: a ready message sent while mpv was away, or before this mpv's
|
||||
// plugin existed, was lost. Never sends the dismissal, since nothing is being hidden.
|
||||
function reportOverlayContentReadyToPlugin(): void {
|
||||
if (isMainOverlayContentReady()) {
|
||||
sendPluginOverlayLoadingMessage('subminer-overlay-loading-ready');
|
||||
}
|
||||
}
|
||||
|
||||
const maybeStartOverlayLoadingOsd = createMaybeStartOverlayLoadingOsdHandler({
|
||||
getVisibleOverlayRequested: () => deps.getVisibleOverlayVisible(),
|
||||
isOverlayContentReady: () => isVisibleOverlayContentReady(),
|
||||
@@ -261,6 +286,7 @@ export function createOverlayNotificationsRuntime(deps: OverlayNotificationsRunt
|
||||
showYoutubeFlowStatusNotification,
|
||||
showOverlayLoadingStatusNotification,
|
||||
dismissOverlayLoadingStatusNotification,
|
||||
reportOverlayContentReadyToPlugin,
|
||||
maybeStartOverlayLoadingOsd,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user