mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
fix(anki): regenerate sentence furigana when mined context changes
- Regenerate SentenceFurigana from the final sentence after timing-review expansion or stats-dashboard word mining - Add a Yomitan parseText-based generator with a 10s timeout and escaped, highlighted output - Clear stale furigana on failure so templates fall back to Sentence - Keep existing furigana formatting when the sentence is unchanged - Document the behavior in the anki-integration and immersion-tracking docs
This commit is contained in:
16 files changed
+489
-18
No files matched your search
@@ -188,13 +188,14 @@ test('NoteUpdateWorkflow uses configured fields for word-card enrichment with La
|
||||
|
||||
test('NoteUpdateWorkflow updates sentence furigana when highlight processor changes it', async () => {
|
||||
const harness = createWorkflowHarness();
|
||||
harness.deps.getCurrentSubtitleText = () => 'tokugi';
|
||||
harness.deps.client.notesInfo = async () =>
|
||||
[
|
||||
{
|
||||
noteId: 42,
|
||||
fields: {
|
||||
Expression: { value: 'tokugi' },
|
||||
Sentence: { value: '' },
|
||||
Sentence: { value: 'tokugi' },
|
||||
SentenceFurigana: { value: '<span class="term">tokugi</span>' },
|
||||
},
|
||||
},
|
||||
@@ -206,7 +207,7 @@ test('NoteUpdateWorkflow updates sentence furigana when highlight processor chan
|
||||
|
||||
assert.equal(harness.updates.length, 1);
|
||||
assert.deepEqual(harness.updates[0]?.fields, {
|
||||
Sentence: 'subtitle-text',
|
||||
Sentence: 'tokugi',
|
||||
SentenceFurigana: '<span class="term"><b>tokugi</b></span>',
|
||||
});
|
||||
});
|
||||
@@ -798,3 +799,63 @@ test('NoteUpdateWorkflow keeps cache unchanged and reports when deletion fails',
|
||||
assert.deepEqual(statusMessages, ['Card deletion failed: delete failed']);
|
||||
assert.ok(harness.warnings.length === 0);
|
||||
});
|
||||
|
||||
for (const outcome of ['success', 'unavailable', 'throws'] as const) {
|
||||
test(`NoteUpdateWorkflow regenerates expanded furigana (${outcome})`, async () => {
|
||||
const harness = createWorkflowHarness();
|
||||
harness.deps.client.notesInfo = async () => [
|
||||
{
|
||||
noteId: 42,
|
||||
fields: {
|
||||
Expression: { value: '猫' },
|
||||
Sentence: { value: '<b>猫</b>を見た。' },
|
||||
SentenceFurigana: { value: ' 猫[ねこ]を 見[み]た。' },
|
||||
},
|
||||
},
|
||||
];
|
||||
harness.deps.captureSubtitleMediaContext = () => ({
|
||||
source: 'overlay',
|
||||
text: '猫を見た。',
|
||||
startTime: 4,
|
||||
endTime: 6,
|
||||
});
|
||||
harness.deps.reviewMediaTiming = async () => ({
|
||||
action: 'confirm',
|
||||
text: '猫を見た。犬もいた。',
|
||||
startTime: 2,
|
||||
endTime: 8,
|
||||
});
|
||||
harness.deps.generateSentenceFurigana = async (text, fields) => {
|
||||
assert.equal(text, '猫を見た。犬もいた。');
|
||||
assert.equal(fields.expression, '猫');
|
||||
if (outcome === 'throws') throw new Error('parser unavailable');
|
||||
return outcome === 'success' ? '<b> 猫[ねこ]</b>を 見[み]た。 犬[いぬ]もいた。' : null;
|
||||
};
|
||||
await harness.workflow.execute(42);
|
||||
assert.equal(harness.updates[0]?.fields.Sentence, '猫を見た。犬もいた。');
|
||||
assert.equal(
|
||||
harness.updates[0]?.fields.SentenceFurigana,
|
||||
outcome === 'success' ? '<b> 猫[ねこ]</b>を 見[み]た。 犬[いぬ]もいた。' : '',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test('NoteUpdateWorkflow preserves native furigana formatting when sentence context is unchanged', async () => {
|
||||
const harness = createWorkflowHarness();
|
||||
harness.deps.client.notesInfo = async () => [
|
||||
{
|
||||
noteId: 42,
|
||||
fields: {
|
||||
Expression: { value: '猫' },
|
||||
Sentence: { value: '<b>猫</b>を見た。' },
|
||||
SentenceFurigana: { value: '<ruby>猫<rt>ねこ</rt></ruby>を見た。' },
|
||||
},
|
||||
},
|
||||
];
|
||||
harness.deps.getCurrentSubtitleText = () => '猫を見た。';
|
||||
harness.deps.generateSentenceFurigana = async () => {
|
||||
assert.fail('unchanged sentence must keep native formatting');
|
||||
};
|
||||
await harness.workflow.execute(42);
|
||||
assert.equal(harness.updates[0]?.fields.SentenceFurigana, undefined);
|
||||
});
|
||||
Reference in new issue
Block a user