This will be quite complicated because you want to play multiple audio files.
If you only had one audio file to play in specific situations then code like below works fine. Here, you’d place your first time audio in the note field First_time_audio
and the normal audio in Normal_audio
.
Only one audio file per case
<div id="first-time-audio">
{{First_time_audio}}
</div>
<div id="normal-audio">
{{Normal_audio}}
</div>
<script>
var handlePromise = (val, func) => {
if (typeof val === "object" && val !== null && !!val.then) {
val.then((res) => func(res.value));
} else {
func(val);
}
};
var setReps = (repsVal) =>
handlePromise(repsVal, (reps = 0) => {
let id = "normal-audio";
if (reps === 0) id = "first-time-audio";
// If there's multiple audio, this only selects the first one
var audioBtn = document.querySelector(`#${id} .replay-button`);
// Use R to replay audio
document.addEventListener("keydown", (event) => {
// Android keydown event always has keyCode = 229
if (event.isComposing || event.keyCode === 229) {
return;
}
// q = 81
if (event.key === "r" && audioBtn) {
audioBtn.click();
}
});
// Set replay to AnkiDroid userAction
window.userJs1 = () => {
audioBtn.click();
};
if (audioBtn) audioBtn.click();
});
try {
var jsApiContract = {
version: "0.0.3",
developer: "your@email.here"
};
var api = new AnkiDroidJS(jsApiContract);
consoleLog("AnkiDroid API", api);
setReps(AnkiDroidJS.ankiGetCardReps());
} catch {
pycmd("AnkiJS.ankiGetCardReps()", setReps);
}
</script>
The problem with multiple audio files is that when you do audioBtn.click();
in a loop, only the first audio actually plays. You’d need to somehow wait for the audio playing to finish before calling the next audioBtn.click();
There is a solution to this too… but then it gets a lot more difficult as you will need to play your audio files using <audio>
tags instead, copy your audio file references a second time in your note fields and then add more javascript to manage playing the files in a row.
Variation on the script from here: [AnkiMobile] Auto-advance vs. html audio element? - #7 by jhhr
Multiple audio files one or the other case
<audio id="player" controls></audio>
<script>
function parseAudioArray(audioArrayStr) {
try {
return JSON.parse(audioArrayStr);
} catch (e) {
console.log("Error parsing audio array, check your audio fields", e);
return [];
}
function playAudiosForRepCount(repsNum) {
let audios = parseAudioArray(`{{Normal_audio_array}}`);
if (repsNum === 0) {
audios = parseAudioArray(`{{First_time_audio_array}}`);
// Add notification sound as first audio
audios.unshift("_notification.mp3");
};
const player = document.getElementById("player");
let index = 0;
player.addEventListener("ended", () => {
if (++index < audios.length) {
player.src = audios[index];
player.play();
}
});
// play the first audio file
player.src = audios[index];
player.play();
}
// Default to normal audio
var playAudios = () => {
playAudiosForRepCount(1);
}
// Use R to replay audio
document.addEventListener("keydown", (event) => {
// Android keydown event always has keyCode = 229
if (event.isComposing || event.keyCode === 229) {
return;
}
// q = 81
if (event.key === "r" && audioBtn) {
playAudios()
}
});
// Set replay to AnkiDroid userAction
window.userJs1 = playAudios;
var handlePromise = (val, func) => {
if (typeof val === "object" && val !== null && !!val.then) {
val.then((res) => func(res.value));
} else {
func(val);
}
};
var setReps = (repsVal) => {
handlePromise(repsVal, (repsNum = 0) => {
playAudios = () => {
playAudiosForRepCount(repsNum);
};
});
};
try {
const jsApiContract = { version: "0.0.3", developer: "your@email.here" };
const api = new AnkiDroidJS(jsApiContract);
console.log("AnkiDroid API", api);
setReps(api.ankiGetCardReps());
} catch (e) {
if (globalThis.ankiPlatform !== "desktop") {
console.log("AnkiDroid API error", e);
} else {
pycmd("AnkiJS.ankiGetCardReps()", setReps);
}
}
</script>
And then you’ll need to copy your audio files into additional fields in your notes (like I suggested here 我让卡片中的视频自动轮播,我需要知道某个视频何时结束? - #4 by jhhr). In your case you’ll have to store your audios in at least three fields
- All_audios =
[sound:first_time_audio_1.mp3][sound:first_time_audio_2.mp3][sound:short_audio.mp3]
This field is needed so that checking media doesn’t mark your audio files as unused. You won’t be using this in your template.
- First_time_audio_array =
[“first_time_audio_1.mp3”, “first_time_audio_2.mp4”]
- Normal_audio_array =
["short_audio.mp3"]
- Ensure that First_time_audio_array and Normal_audio_array contains a valid javascript array
Your notification sound is going to be the same every time so it doesn’t need to be in the note fields. You can prefix the file name with _ and put that in your collection.media, in my example above the file name is _notification.mp3