diff --git a/changes/fix-stats-vocab-example-mining.md b/changes/fix-stats-vocab-example-mining.md index 78267776..068aacdc 100644 --- a/changes/fix-stats-vocab-example-mining.md +++ b/changes/fix-stats-vocab-example-mining.md @@ -3,7 +3,7 @@ area: stats - Fixed vocab-page example sentence mining buttons failing when the Anki deck setting is blank or Yomitan card formats are ordered with a non-term card first. - Fixed vocab-page example word and audio mining so English subtitles are only written to Selection Text for sentence cards, leaving word cards to show the normal Yomitan dictionary glossary. -- Fixed stats-page mining audio updates so generated sentence clips populate `SentenceAudio` when that field exists, while preserving configured expression-audio behavior for direct sentence cards. +- Fixed stats-page sentence mining audio updates so generated sentence clips populate `SentenceAudio` without also writing the same clip to the configured expression-audio field. - Fixed stats-page word mining so the hidden Yomitan helper uses the same configured word-audio sources as the normal Yomitan plus button. - Fixed stats-page sentence mining to use the current Anki deck/settings at request time, create direct sentence cards before slow media generation completes, and include stored English subtitle text as Selection Text. - Fixed secondary subtitle auto-selection to prefer regular English tracks over Signs/Songs tracks when both are available. diff --git a/src/core/services/__tests__/stats-server.test.ts b/src/core/services/__tests__/stats-server.test.ts index 7cb16802..a45cb33c 100644 --- a/src/core/services/__tests__/stats-server.test.ts +++ b/src/core/services/__tests__/stats-server.test.ts @@ -1852,7 +1852,7 @@ describe('stats server API routes', () => { const updateRequest = requests.find((request) => request.action === 'updateNoteFields'); const audioValue = updateRequest?.params?.note?.fields?.SentenceAudio; assert.match(audioValue ?? '', /^\[sound:subminer_audio_\d+\.mp3\]$/); - assert.equal(updateRequest?.params?.note?.fields?.ExpressionAudio, audioValue); + assert.equal(updateRequest?.params?.note?.fields?.ExpressionAudio, undefined); }); }); }); diff --git a/src/core/services/stats-server.ts b/src/core/services/stats-server.ts index 640d3256..6d654ba7 100644 --- a/src/core/services/stats-server.ts +++ b/src/core/services/stats-server.ts @@ -172,6 +172,7 @@ function getStatsWordMiningAudioFieldName( function getStatsDirectMiningAudioFieldNames( ankiConfig: AnkiConnectConfig, noteInfo: StatsServerNoteInfo | null, + mode: 'sentence' | 'audio', ): string[] { const configuredAudioField = ankiConfig.fields?.audio ?? 'ExpressionAudio'; if (!ankiConfig.isLapis?.enabled && !ankiConfig.isKiku?.enabled) { @@ -185,6 +186,10 @@ function getStatsDirectMiningAudioFieldNames( ? resolveStatsNoteFieldName(noteInfo, configuredAudioField) : null; + if (mode === 'sentence') { + return uniqueFieldNames(sentenceAudioField); + } + return uniqueFieldNames(sentenceAudioField, expressionAudioField); } @@ -1395,7 +1400,7 @@ export function createStatsApp( client.storeMediaFile(audioFilename, audioBuffer), ); const audioValue = `[sound:${audioFilename}]`; - for (const fieldName of getStatsDirectMiningAudioFieldNames(ankiConfig, noteInfo)) { + for (const fieldName of getStatsDirectMiningAudioFieldNames(ankiConfig, noteInfo, mode)) { mediaFields[fieldName] = audioValue; } } catch (err) { diff --git a/stats/src/components/search/SearchTab.test.ts b/stats/src/components/search/SearchTab.test.ts index 27f822ce..34e35f41 100644 --- a/stats/src/components/search/SearchTab.test.ts +++ b/stats/src/components/search/SearchTab.test.ts @@ -22,11 +22,11 @@ test('SearchTab forwards stored secondary subtitle text when mining from search test('SearchTab enables headword sentence search by default and forwards the toggle', () => { const source = fs.readFileSync(SEARCH_TAB_PATH, 'utf8'); + assert.match(source, /const \[searchByHeadword,\s*setSearchByHeadword\] = useState\(true\);/); assert.match( source, - /const \[searchByHeadword,\s*setSearchByHeadword\] = useState\(true\);/, + /apiClient\s*\.\s*searchSentences\(trimmed,\s*SEARCH_LIMIT,\s*searchByHeadword\)/, ); - assert.match(source, /apiClient\s*\.\s*searchSentences\(trimmed,\s*SEARCH_LIMIT,\s*searchByHeadword\)/); assert.match(source, /checked=\{searchByHeadword\}/); assert.match(source, /setSearchByHeadword\(event\.target\.checked\)/); });