mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-13 05:16:18 -07:00
feat(anki): add media timing review before card creation
- Add draggable timing previews with audio playback and exact media ranges - Support cancellation choices, including deleting existing cards
This commit is contained in:
@@ -85,6 +85,7 @@ function createManualUpdateService(overrides: Partial<CardCreationDeps> = {}): {
|
||||
},
|
||||
findNotes: async () => [42],
|
||||
retrieveMediaFile: async () => '',
|
||||
deleteNotes: async () => undefined,
|
||||
},
|
||||
mediaGenerator: {
|
||||
generateAudio: async () => Buffer.from('audio'),
|
||||
@@ -129,6 +130,7 @@ function createManualUpdateService(overrides: Partial<CardCreationDeps> = {}): {
|
||||
}),
|
||||
getFallbackDurationSeconds: () => 10,
|
||||
appendKnownWordsFromNoteInfo: () => undefined,
|
||||
removeKnownWordNote: () => undefined,
|
||||
isUpdateInProgress: () => false,
|
||||
setUpdateInProgress: () => undefined,
|
||||
trackLastAddedNoteId: () => undefined,
|
||||
@@ -331,6 +333,7 @@ test('manual clipboard subtitle update marks Kiku word cards as word-and-sentenc
|
||||
storeMediaFile: async () => undefined,
|
||||
findNotes: async () => [42],
|
||||
retrieveMediaFile: async () => '',
|
||||
deleteNotes: async () => undefined,
|
||||
},
|
||||
getEffectiveSentenceCardConfig: () => ({
|
||||
model: 'Sentence',
|
||||
@@ -378,6 +381,7 @@ test('manual clipboard subtitle update uses configured audio when SentenceAudio
|
||||
},
|
||||
findNotes: async () => [42],
|
||||
retrieveMediaFile: async () => '',
|
||||
deleteNotes: async () => undefined,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -466,6 +470,7 @@ test('manual clipboard subtitle update uses resolved mpv stream URLs for remote
|
||||
},
|
||||
findNotes: async () => [42],
|
||||
retrieveMediaFile: async () => '',
|
||||
deleteNotes: async () => undefined,
|
||||
},
|
||||
mediaGenerator: {
|
||||
generateAudio: async (path) => {
|
||||
@@ -514,3 +519,47 @@ test('createSentenceCard relies on Anki progress notification without standalone
|
||||
assert.deepEqual(progressMessages, ['Creating sentence card']);
|
||||
assert.deepEqual(statusMessages, []);
|
||||
});
|
||||
|
||||
test('discarding an audio-card timing review deletes the note before evicting its cache entry', async () => {
|
||||
const events: string[] = [];
|
||||
const statusMessages: string[] = [];
|
||||
const { service } = createManualUpdateService({
|
||||
getMpvClient: () =>
|
||||
({
|
||||
currentVideoPath: '/video.mp4',
|
||||
currentSubText: '字幕',
|
||||
currentSubStart: 4,
|
||||
currentSubEnd: 6,
|
||||
currentTimePos: 5,
|
||||
}) as never,
|
||||
client: {
|
||||
addNote: async () => 0,
|
||||
addTags: async () => undefined,
|
||||
notesInfo: async () => [
|
||||
{
|
||||
noteId: 42,
|
||||
fields: { Expression: { value: '単語' } },
|
||||
},
|
||||
],
|
||||
updateNoteFields: async () => undefined,
|
||||
storeMediaFile: async () => undefined,
|
||||
findNotes: async () => [42],
|
||||
retrieveMediaFile: async () => '',
|
||||
deleteNotes: async (noteIds) => {
|
||||
events.push(`delete:${noteIds.join(',')}`);
|
||||
},
|
||||
},
|
||||
reviewMediaTiming: async () => ({ action: 'discard' }),
|
||||
removeKnownWordNote: (noteId) => {
|
||||
events.push(`cache:${noteId}`);
|
||||
},
|
||||
showStatusNotification: (message) => {
|
||||
statusMessages.push(message);
|
||||
},
|
||||
});
|
||||
|
||||
await service.markLastCardAsAudioCard();
|
||||
|
||||
assert.deepEqual(events, ['delete:42', 'cache:42']);
|
||||
assert.deepEqual(statusMessages, ['Card deleted.']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user