@Ab_Bc: I wouldn’t want to strip the [sound] tags because Anki would then identify those audio files as unused media when running the “Check Media” tool. That could cause unnecessary complications down the line.
@Anon_0000: I didn’t realize that simply referencing a field name in the script would automatically trigger audio playback. I had assumed the <script> tags would protect the content inside and prevent this behavior. Thanks for pointing that out!
As for your suggestion, I do have another field that mirrors the audio, which could potentially be useful. It’s the {{Back}} field, and it’s not displayed on the card by default. It’s structured in the same way as the {{B_Audio}} field, with each audio entry separated by <br>:
word 1<br>
word 2
If that works, we could use it instead. My only hesitation is that I’m not entirely sure whether referencing the {{Back}} field in the front template will inadvertently display its content on the front side of the card.
Me too. But in this case I think the python backend handles the audio (instead of javascript) and that’s why it’s not protected. Or maybe it’s just a bug in ankis code, not sure.
Yes, that’s excelent!
It won’t. Audio is different because anki handles the audio tags in a different way.
Here’s what I came up with:
<script>
// count how many <br> there are. Also see: https://stackoverflow.com/a/4009768
var count = ("{{Back}}".match(/<br>/g) || []).length;
// check if item "did_run" exists in sessionStorage. This is necessary to make
// the variable persist. Also see: https://forums.ankiweb.net/t/is-it-even-possible-to-persist-javascript-variables-on-ankidroid/19820/2?u=anon_0000
// if it doesn't exist, then the audio in the front never played.
if (!sessionStorage.getItem("did_run")) {
// if count is above 0, then there is a synonym
if (count > 0) {
var audio = new Audio('_ding.ogg');
audio.play();
}
// now set the "did_run" in sessionStorage. This makes it so that
// the audio won't be replayed again, if the backside is viewed.
sessionStorage.setItem("did_run", JSON.stringify("yes"));
} else {
// The sessionStorage entry exists, which means the audio played before.
// The audio might have played in a previous card though (e.g. if you
// review card A and then B, B wouldn't play the audio anymore because
// "did_run" is set. That's an issue). To solve this, we clear the
// storage every time.
sessionStorage.clear();
}
</script>
{{Front}}
I tested it with multiple cards in an actual review on desktop (I used a filtered deck).
The audio plays only on the front side.
It only plays if there is a synonym.
It doesn’t matter if you have sentences in your {{Back}} field – it will work regardless (as long as at least one <br> is used when synonyms are active).
Anki will recognize all your audios like usual during e.g. export, since you now continue to use the default [sound:hello_world.mp3].
However:
I haven’t found a way to play the front audio after the ding. Which means they will play simultaneasly.
I have no idea if it works for AnkiDroid, though – reading the forum link from the code above – it should work fine.
I’d love to provide more useful feedback than just “it doesn’t work,” but my capabilities in this area are pretty limited. I tried checking for the most trivial errors, but I didn’t run into anything obvious.
The audio file is definitely _ding.ogg.
The field name is Back, and it contains words, sometimes separated by <br> when there are multiple synonyms.
The only change I made to your script was leaving out {{Front}}, since it’s already present in my template.
Later…
I heavily simplified my card template and an example card for testing.
I made sure there was nothing but {{Front}} and your script.
In the Back field, I only had a single <br> tag to simulate multiple synonyms.
Unfortunately, _ding.ogg never played.
I’m not sure what’s causing the issue, but let me know if there’s anything specific I can test or check to help troubleshoot.
If this is on desktop, then you could download the AnkiWebView Inspector addon, right click, inspect and then show me what the console shows you.
If it’s AnkiDroid, then I’m not sure how to debug it.
If it actually doesn’t work for you on desktop, I’d be very surprised though, because it works for me and I see no reason why the webviews would behave differently for us.
I hope this helps because it’s all Greek to me.
Here’s the output from the console:
Uncaught SyntaxError: Invalid or unexpected token
at reviewer.js:441:19592
at new Promise (<anonymous>)
at $c (reviewer.js:441:19337)
at reviewer.js:441:19842
at Generator.next (<anonymous>)
at reviewer.js:1:1377
at new Promise (<anonymous>)
at at (reviewer.js:1:1197)
at ss (reviewer.js:441:19640)
at reviewer.js:442:213
I hope it’s related.
I am using this front template:
{{Front}}
<script>
// count how many <br> there are. Also see: https://stackoverflow.com/a/4009768
var count = ("{{Back}}".match(/<br>/g) || []).length;
// check if item "did_run" exists in sessionStorage. This is necessary to make
// the variable persist. Also see: https://forums.ankiweb.net/t/is-it-even-possible-to-persist-javascript-variables-on-ankidroid/19820/2?u=anon_0000
// if it doesn't exist, then the audio in the front never played.
if (!sessionStorage.getItem("did_run")) {
// if count is above 0, then there is a synonym
if (count > 0) {
var audio = new Audio('_ding.ogg');
audio.play();
}
// now set the "did_run" in sessionStorage. This makes it so that
// the audio won't be replayed again, if the backside is viewed.
sessionStorage.setItem("did_run", JSON.stringify("yes"));
} else {
// The sessionStorage entry exists, which means the audio played before.
// The audio might have played in a previous card though (e.g. if you
// review card A and then B, B wouldn't play the audio anymore because
// "did_run" is set. That's an issue). To solve this, we clear the
// storage every time.
sessionStorage.clear();
}
</script>
I would like to save you from extra work.
It’s most likely a local interference that you won’t be able to observe without the actual environment.
To make it easier, I’m publishing a card for you to test. Example.apkg
Hopefully, this will help narrow things down!
Oddly enough, your {{Back}} field is the issue. It shows the following in HTML view:
acabar<br>
terminar
This breaks the code though, because I didn’t think multiline strings would be needed here. For reference, the following wouldn’t break the code:
acabar<br>terminar
I solved this issue. I also substituted the missing language files with test files to verify that audio playback works. It now works fine for me using your example deck.
I only changed the var count =… line to multiline. But for reference, here is the entire front template:
<div class="background-layer {{Tags}}"></div>
<div class="word-type">{{WType}}</div>
<hr>
<span class="word {{F_Classes}}">{{Front}}</span> {{F_Audio}}
<script>
// count how many <br> there are. Also see: https://stackoverflow.com/a/4009768
var count = (`{{Back}}`.match(/<br>/g) || []).length;
// check if item "did_run" exists in sessionStorage. This is necessary to make
// the variable persist. Also see: https://forums.ankiweb.net/t/is-it-even-possible-to-persist-javascript-variables-on-ankidroid/19820/2?u=anon_0000
// if it doesn't exist, then the audio in the front never played.
if (!sessionStorage.getItem("did_run")) {
// if count is above 0, then there is a synonym
if (count > 0) {
var audio = new Audio('_ding.ogg');
audio.play();
}
// now set the "did_run" in sessionStorage. This makes it so that
// the audio won't be replayed again, if the backside is viewed.
sessionStorage.setItem("did_run", JSON.stringify("yes"));
} else {
// The sessionStorage entry exists, which means the audio played before.
// The audio might have played in a previous card though (e.g. if you
// review card A and then B, B wouldn't play the audio anymore because
// "did_run" is set. That's an issue). To solve this, we clear the
// storage every time.
sessionStorage.clear();
}
</script>
Except for updating the front card, there is nothing more you have to do. It should work this time.
I can’t thank you enough for your patience and precision throughout this process.
I really appreciate the time and effort you put into troubleshooting this with me.
I use multiline fields for easier readability.
Thank you for catching that detail and adjusting accordingly!
Also, huge thanks for posting the whole template instead of just small portions; it helped minimize any misunderstandings.
I tested it on various clients, and it worked perfectly on every device.
Great job!