mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-31 19:21:33 -07:00
fix(overlay): strip spinner frame from subsync overlay card
- Add overlayBody override to ConfiguredStatusNotificationOptions so overlay/OSD/desktop can diverge - Extract getSubsyncStatusNotificationOptions() to strip the ASCII spinner frame from the overlay card (OSD keeps it since it renders the raw spinner) - Add tests for spinner stripping and subsync result notifications
This commit is contained in:
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
|
|||||||
import test from 'node:test';
|
import test from 'node:test';
|
||||||
import {
|
import {
|
||||||
getPlaybackFeedbackNotificationOptions,
|
getPlaybackFeedbackNotificationOptions,
|
||||||
|
getSubsyncStatusNotificationOptions,
|
||||||
getYoutubeFlowStatusNotificationOptions,
|
getYoutubeFlowStatusNotificationOptions,
|
||||||
notifyConfiguredStatus,
|
notifyConfiguredStatus,
|
||||||
} from './configured-status-notification';
|
} from './configured-status-notification';
|
||||||
@@ -158,6 +159,64 @@ test('notifyConfiguredStatus can suppress desktop delivery for progress ticks',
|
|||||||
assert.deepEqual(calls, ['overlay:subsync-status:Subsync:Subsync: syncing |:progress:pin']);
|
assert.deepEqual(calls, ['overlay:subsync-status:Subsync:Subsync: syncing |:progress:pin']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('subsync progress keeps the osd spinner frame but strips it from the overlay card', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
|
||||||
|
for (const frame of ['|', '/', '-', '\\']) {
|
||||||
|
const message = `Subsync: syncing ${frame}`;
|
||||||
|
notifyConfiguredStatus(
|
||||||
|
message,
|
||||||
|
{
|
||||||
|
getNotificationType: () => 'both',
|
||||||
|
showOsd: (osdMessage) => {
|
||||||
|
calls.push(`osd:${osdMessage}`);
|
||||||
|
},
|
||||||
|
showOverlayNotification: (payload) =>
|
||||||
|
calls.push(
|
||||||
|
`overlay:${payload.body}:${payload.variant}:${payload.persistent ? 'pin' : 'auto'}`,
|
||||||
|
),
|
||||||
|
showDesktopNotification: (title, options) =>
|
||||||
|
calls.push(`desktop:${title}:${options.body ?? ''}`),
|
||||||
|
},
|
||||||
|
getSubsyncStatusNotificationOptions(message),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.deepEqual(calls, [
|
||||||
|
'overlay:Subsync: syncing:progress:pin',
|
||||||
|
'overlay:Subsync: syncing:progress:pin',
|
||||||
|
'overlay:Subsync: syncing:progress:pin',
|
||||||
|
'overlay:Subsync: syncing:progress:pin',
|
||||||
|
]);
|
||||||
|
|
||||||
|
calls.length = 0;
|
||||||
|
notifyConfiguredStatus(
|
||||||
|
'Subsync: syncing /',
|
||||||
|
{
|
||||||
|
getNotificationType: () => 'osd',
|
||||||
|
showOsd: (osdMessage) => {
|
||||||
|
calls.push(`osd:${osdMessage}`);
|
||||||
|
},
|
||||||
|
showOverlayNotification: (payload) => calls.push(`overlay:${payload.body}`),
|
||||||
|
showDesktopNotification: (title, options) =>
|
||||||
|
calls.push(`desktop:${title}:${options.body ?? ''}`),
|
||||||
|
},
|
||||||
|
getSubsyncStatusNotificationOptions('Subsync: syncing /'),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(calls, ['osd:Subsync: syncing /']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('subsync result notifications keep their message intact', () => {
|
||||||
|
assert.equal(
|
||||||
|
getSubsyncStatusNotificationOptions('Subtitle synchronized with ffsubsync').overlayBody,
|
||||||
|
'Subtitle synchronized with ffsubsync',
|
||||||
|
);
|
||||||
|
const failure = getSubsyncStatusNotificationOptions('ffsubsync synchronization failed: boom');
|
||||||
|
assert.equal(failure.variant, 'error');
|
||||||
|
assert.equal(failure.overlayBody, 'ffsubsync synchronization failed: boom');
|
||||||
|
});
|
||||||
|
|
||||||
test('notifyConfiguredStatus routes feedback through overlay without desktop delivery', () => {
|
test('notifyConfiguredStatus routes feedback through overlay without desktop delivery', () => {
|
||||||
const calls: string[] = [];
|
const calls: string[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export interface ConfiguredStatusNotificationDeps {
|
|||||||
|
|
||||||
export interface ConfiguredStatusNotificationOptions {
|
export interface ConfiguredStatusNotificationOptions {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** Overrides the overlay card body (the OSD/desktop paths keep the raw message). */
|
||||||
|
overlayBody?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
variant?: OverlayNotificationPayload['variant'];
|
variant?: OverlayNotificationPayload['variant'];
|
||||||
persistent?: boolean;
|
persistent?: boolean;
|
||||||
@@ -31,6 +33,23 @@ export function getPlaybackFeedbackNotificationOptions(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSubsyncStatusNotificationOptions(
|
||||||
|
message: string,
|
||||||
|
): ConfiguredStatusNotificationOptions {
|
||||||
|
const syncing = message.startsWith('Subsync: syncing');
|
||||||
|
const failed = message.toLowerCase().includes('failed');
|
||||||
|
return {
|
||||||
|
id: 'subsync-status',
|
||||||
|
title: 'Subsync',
|
||||||
|
// The overlay card renders its own animated spinner, so drop the ASCII
|
||||||
|
// spinner frame that the OSD path still needs.
|
||||||
|
overlayBody: syncing ? message.replace(/\s+[|/\-\\]$/, '') : message,
|
||||||
|
variant: failed ? 'error' : syncing ? 'progress' : 'info',
|
||||||
|
persistent: syncing,
|
||||||
|
desktop: !syncing,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function getYoutubeFlowStatusNotificationOptions(
|
export function getYoutubeFlowStatusNotificationOptions(
|
||||||
message: string,
|
message: string,
|
||||||
): ConfiguredStatusNotificationOptions {
|
): ConfiguredStatusNotificationOptions {
|
||||||
@@ -74,7 +93,7 @@ export function notifyConfiguredStatus(
|
|||||||
deps.showOverlayNotification({
|
deps.showOverlayNotification({
|
||||||
id: options.id,
|
id: options.id,
|
||||||
title: options.title ?? 'SubMiner',
|
title: options.title ?? 'SubMiner',
|
||||||
body: message,
|
body: options.overlayBody ?? message,
|
||||||
variant: options.variant ?? 'info',
|
variant: options.variant ?? 'info',
|
||||||
persistent: options.persistent ?? false,
|
persistent: options.persistent ?? false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { withConfiguredOverlayNotificationPosition } from './overlay-notificatio
|
|||||||
import { createOverlayNotificationDelivery } from './overlay-notification-delivery';
|
import { createOverlayNotificationDelivery } from './overlay-notification-delivery';
|
||||||
import {
|
import {
|
||||||
getPlaybackFeedbackNotificationOptions,
|
getPlaybackFeedbackNotificationOptions,
|
||||||
|
getSubsyncStatusNotificationOptions,
|
||||||
getYoutubeFlowStatusNotificationOptions,
|
getYoutubeFlowStatusNotificationOptions,
|
||||||
notifyConfiguredStatus,
|
notifyConfiguredStatus,
|
||||||
type ConfiguredStatusNotificationOptions,
|
type ConfiguredStatusNotificationOptions,
|
||||||
@@ -195,15 +196,7 @@ export function createOverlayNotificationsRuntime(deps: OverlayNotificationsRunt
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showSubsyncStatusNotification(message: string): void {
|
function showSubsyncStatusNotification(message: string): void {
|
||||||
const syncing = message.startsWith('Subsync: syncing');
|
showConfiguredStatusNotification(message, getSubsyncStatusNotificationOptions(message));
|
||||||
const failed = message.toLowerCase().includes('failed');
|
|
||||||
showConfiguredStatusNotification(message, {
|
|
||||||
id: 'subsync-status',
|
|
||||||
title: 'Subsync',
|
|
||||||
variant: failed ? 'error' : syncing ? 'progress' : 'info',
|
|
||||||
persistent: syncing,
|
|
||||||
desktop: !syncing,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showYoutubeFlowStatusNotification(message: string): void {
|
function showYoutubeFlowStatusNotification(message: string): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user