mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-01 19:21:34 -07:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
6607c333bc
|
|||
|
b2bbf1ae12
|
@@ -607,7 +607,7 @@
|
|||||||
"deleteDuplicateInAuto": true // When Kiku field grouping is "auto", delete the duplicate source card after grouping completes. Values: true | false
|
"deleteDuplicateInAuto": true // When Kiku field grouping is "auto", delete the duplicate source card after grouping completes. Values: true | false
|
||||||
}, // Is kiku setting.
|
}, // Is kiku setting.
|
||||||
"lapisKiku": {
|
"lapisKiku": {
|
||||||
"wordCardKind": "word-and-sentence" // Card-type flag SubMiner marks on Kiku/Lapis word cards: word-and-sentence (IsWordAndSentenceCard), click (IsClickCard), sentence (IsSentenceCard), audio (IsAudioCard), or none to leave the flags untouched. Only applies when isKiku.enabled or isLapis.enabled; the other card-type flags are cleared so a note never claims two kinds. Cards mined with the dedicated sentence/audio actions keep their own flag. Values: word-and-sentence | click | sentence | audio | none
|
"wordCardKind": "word-and-sentence" // Card-type flag SubMiner marks on Kiku/Lapis word cards. Only one flag is set at a time; the others are cleared. Requires isKiku.enabled or isLapis.enabled. Values: word-and-sentence | click | sentence | audio | none
|
||||||
} // Lapis kiku setting.
|
} // Lapis kiku setting.
|
||||||
}, // Automatic Anki updates and media generation options.
|
}, // Automatic Anki updates and media generation options.
|
||||||
|
|
||||||
|
|||||||
@@ -607,7 +607,7 @@
|
|||||||
"deleteDuplicateInAuto": true // When Kiku field grouping is "auto", delete the duplicate source card after grouping completes. Values: true | false
|
"deleteDuplicateInAuto": true // When Kiku field grouping is "auto", delete the duplicate source card after grouping completes. Values: true | false
|
||||||
}, // Is kiku setting.
|
}, // Is kiku setting.
|
||||||
"lapisKiku": {
|
"lapisKiku": {
|
||||||
"wordCardKind": "word-and-sentence" // Card-type flag SubMiner marks on Kiku/Lapis word cards: word-and-sentence (IsWordAndSentenceCard), click (IsClickCard), sentence (IsSentenceCard), audio (IsAudioCard), or none to leave the flags untouched. Only applies when isKiku.enabled or isLapis.enabled; the other card-type flags are cleared so a note never claims two kinds. Cards mined with the dedicated sentence/audio actions keep their own flag. Values: word-and-sentence | click | sentence | audio | none
|
"wordCardKind": "word-and-sentence" // Card-type flag SubMiner marks on Kiku/Lapis word cards. Only one flag is set at a time; the others are cleared. Requires isKiku.enabled or isLapis.enabled. Values: word-and-sentence | click | sentence | audio | none
|
||||||
} // Lapis kiku setting.
|
} // Lapis kiku setting.
|
||||||
}, // Automatic Anki updates and media generation options.
|
}, // Automatic Anki updates and media generation options.
|
||||||
|
|
||||||
|
|||||||
@@ -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