fix(anki): default fields.audio to SentenceAudio

- Generated sentence audio no longer overwrites Yomitan's ExpressionAudio on default configs
- fields.wordAudio still defaults to ExpressionAudio
- Regenerate config.example.jsonc and update the Anki and configuration docs
- Add changelog fragment
This commit is contained in:
sudacode committed 2026-10-28 22:47:54 -07:00
1 parent 586d7950cf
commit 0129e03c0f
7 files changed
+20 -16

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
type: fixed
area: anki
- `ankiConnect.fields.audio` now defaults to `SentenceAudio` instead of `ExpressionAudio`, so generated sentence audio no longer overwrites Yomitan's word audio on default configs. `fields.wordAudio` still defaults to `ExpressionAudio`. If you relied on the old default, set `fields.audio` to `ExpressionAudio` explicitly.
+1 -1
View File
@@ -578,7 +578,7 @@
"deck": "", // Restrict duplicate detection and card enrichment to this Anki deck. Leave empty to use the Yomitan mining deck when available.
"fields": {
"word": "Expression", // Card field for the mined word or expression text.
"audio": "ExpressionAudio", // Card field that receives generated sentence audio.
"audio": "SentenceAudio", // Card field that receives generated sentence audio.
"wordAudio": "ExpressionAudio", // Existing word-audio field read to time the frozen first frame of animated images. This mapping is only used for synchronization.
"image": "Picture", // Card field that receives the captured screenshot or animated image.
"sentence": "Sentence", // Card field that receives the source sentence text.
+1 -1
View File
@@ -103,7 +103,7 @@ Field names are matched case-insensitively. A mapped field that is missing from
Hachidori prepares downloadable word audio before it saves a note through the proxy, so the animated image delay works on the first mine. Set a downloadable pronunciation source in Hachidori's Audio settings. Browser speech cannot be saved to Anki. Without word audio, Hachidori shows a warning and the card gets no word-audio hold.
`fields.audio` gets sentence audio, not word audio. Yomitan writes its own dictionary audio into your note, so point `fields.audio` at a separate field such as `SentenceAudio`. The default, `ExpressionAudio`, is the field many note types use for Yomitan's word audio, so leaving it would overwrite that audio.
`fields.audio` gets sentence audio, not word audio. Yomitan writes its own dictionary audio into your note (often `ExpressionAudio`), so keep `fields.audio` pointed at a separate field such as the default `SentenceAudio`. Pointing it at Yomitan's word-audio field would overwrite that audio.
`ankiConnect.tags` adds tags to every mined or updated card. Set it to `[]` to add none.
+9 -9
View File
@@ -329,15 +329,15 @@ Creates and updates Anki cards with sentence, audio, and screenshot. Needs the [
**Fields**
| Key | Default | What it does |
| ------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `ankiConnect.fields.word` | `"Expression"` | Word field |
| `ankiConnect.fields.audio` | `"ExpressionAudio"` | Field that receives sentence audio. Set a separate field such as `SentenceAudio` so it does not overwrite Yomitan's word audio |
| `ankiConnect.fields.wordAudio` | `"ExpressionAudio"` | Existing word-audio field, read only to time animated images |
| `ankiConnect.fields.image` | `"Picture"` | Screenshot field |
| `ankiConnect.fields.sentence` | `"Sentence"` | Sentence field |
| `ankiConnect.fields.miscInfo` | `"MiscInfo"` | Metadata field. `null` disables |
| `ankiConnect.metadata.pattern` | `"[SubMiner] %f (%t)"` | MiscInfo template: `%f` filename, `%F` filename with extension, `%t` time, `%T` time with ms, `<br>` newline |
| Key | Default | What it does |
| ------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `ankiConnect.fields.word` | `"Expression"` | Word field |
| `ankiConnect.fields.audio` | `"SentenceAudio"` | Field that receives sentence audio. Keep it separate from Yomitan's word-audio field so it does not overwrite that audio |
| `ankiConnect.fields.wordAudio` | `"ExpressionAudio"` | Existing word-audio field, read only to time animated images |
| `ankiConnect.fields.image` | `"Picture"` | Screenshot field |
| `ankiConnect.fields.sentence` | `"Sentence"` | Sentence field |
| `ankiConnect.fields.miscInfo` | `"MiscInfo"` | Metadata field. `null` disables |
| `ankiConnect.metadata.pattern` | `"[SubMiner] %f (%t)"` | MiscInfo template: `%f` filename, `%F` filename with extension, `%t` time, `%T` time with ms, `<br>` newline |
**Media**
+1 -1
View File
@@ -578,7 +578,7 @@
"deck": "", // Restrict duplicate detection and card enrichment to this Anki deck. Leave empty to use the Yomitan mining deck when available.
"fields": {
"word": "Expression", // Card field for the mined word or expression text.
"audio": "ExpressionAudio", // Card field that receives generated sentence audio.
"audio": "SentenceAudio", // Card field that receives generated sentence audio.
"wordAudio": "ExpressionAudio", // Existing word-audio field read to time the frozen first frame of animated images. This mapping is only used for synchronization.
"image": "Picture", // Card field that receives the captured screenshot or animated image.
"sentence": "Sentence", // Card field that receives the source sentence text.
+3 -3
View File
@@ -637,7 +637,7 @@ test('AnkiIntegration queues YouTube media updates against recovered source URLs
noteId: 404,
noteInfo: {
noteId: 404,
fields: { ExpressionAudio: { value: '' }, Picture: { value: '' } },
fields: { SentenceAudio: { value: '' }, Picture: { value: '' } },
},
label: 'resolved source',
});
@@ -648,8 +648,8 @@ test('AnkiIntegration queues YouTube media updates against recovered source URLs
assert.equal(queued, true);
assert.equal(updatedNotes.length, 1);
assert.equal(updatedNotes[0]?.noteId, 404);
assert.match(updatedNotes[0]?.fields.ExpressionAudio ?? '', /^\[sound:audio_/);
assert.equal(updatedNotes[0]?.fields.SentenceAudio, undefined);
assert.match(updatedNotes[0]?.fields.SentenceAudio ?? '', /^\[sound:audio_/);
assert.equal(updatedNotes[0]?.fields.ExpressionAudio, undefined);
assert.match(updatedNotes[0]?.fields.Picture ?? '', /^<img src="image_/);
assert.equal(storedMedia.length, 2);
assert.deepEqual(audioVolumeScales, [0.3 ** 3]);
@@ -28,7 +28,7 @@ export const INTEGRATIONS_DEFAULT_CONFIG: Pick<
deck: '',
fields: {
word: 'Expression',
audio: 'ExpressionAudio',
audio: 'SentenceAudio',
wordAudio: 'ExpressionAudio',
image: 'Picture',
sentence: 'Sentence',