How to play audio continuously using "src"?

For example, I typed “[sound:202301240727_001.mp3][sound:202301240727_002.mp3]” in {{Audiosound}}, then Anki could play these two audios continuously.

Then how can I get the same effect by typing “202301240727_001.mp3 202301240727_002.mp3” in {{Audio}} and using “scr”?

Or can I create another field called {{MergedAudio}} to achieve this?


Here is an example.

Requirements

Disable Don't play audio automatically in the deck options.

Audio field

e.g. foo.mp3 bar.mp3 baz.mp3

The following script assumes that each filename is separated by one or multiple spaces/  s.

Card template

<audio controls id="player">

<script>
    {
        const audios = `{{text:Audio}}`.trim().split(/\s+/);
        const player = document.getElementById("player");
        let index = 0;
        player.addEventListener("ended", () => {
            if (++index < audios.length) {
                player.src = audios[index];
                player.play();
            } else {
                // If there are no more audio files, make it possible to play from
                // the first file again when the play button is clicked.
                index = 0;
                player.src = audios[index];
            }
        });
        // play the first audio file
        player.src = audios[index];
        player.play();
    }
</script>

Note

If you take the approach of setting src dynamically with javascript, as in this example, instead of having a static <audio src="foo.mp3"> element for the field content, you should keep the Audiosound field in the screenshot as is. (You do not need to include the Audiosound field in the card template.) Otherwise, when you run Check Media or when you export the deck, Anki will not recognize that the note contains those audio files.

2 Likes

Wow, it works! Thank you very much! :smiley:

The previous code can achieve auto play, loop play, double speed play, custom double speed play function. Can I achieve all of these functions at the same time when playing multiple pieces of audio in succession? The previous code is listed as follows.

<div class="audio-box">
<audio id="audioTag" controlsList="nodownload " disablePictureInPicture controls src="{{Audio}}"></audio>
<div class="a-controls">
<div class="play-pause" id="playPause">
<div id="normal-play " class="turn-ward icon-btn icon-play show normal" onclick="handleNormalPlayback()">1</div>
</div>
<div id="turnNext" class="turn-ward t-right " onclick="handleTurnRight()">2</div>
<div id="turnNext" class="turn-ward t-right5 " onclick="handleTurnRight15()">1.5</div>
<div id="turnPrev" class="turn-ward t-left " onclick="handleTurnLeft()">0.7</div>
<div id="turnPrev" class="turn-ward t-left25 " onclick="handleTurnLeft025()">0.5</div>
</div>
<div style="margin:-1.8em 0 1em 0">
<input id="diySpeed" style="width:6em;" />
<button onclick="savePlaySpeed()">APPLY</button>
</div>
<div class="audio-footer">
<div>
<input type="checkbox" class="normal-play " onclick="handleNormalPlay()" />AUTOPLAY
</div>
<div>
<input type="checkbox" class="loop-Playback " onclick="handleLoopPlayback()" />LOOP PLAYBACK
</div>
</div>
</div>

<script>
var audio = document.getElementById('audioTag');
var icon_play = document.getElementsByClassName('icon-play');
var loop_btn = document.getElementsByClassName("loop-Playback");
var normal_play = document.getElementsByClassName("normal-play");

if (localStorage.getItem("isloop") === 'true') {
loop_btn[0].checked = true;
}
if (localStorage.getItem("is_normal") === 'true') {
audio.play()
normal_play[0].checked = true;
}

function handleLoopPlayback() {
if (localStorage.getItem("isloop") === 'true') {
audio.pause();
audio.currentTime = 0;
// isloop = false;
localStorage.setItem("isloop", false);
} else {
// isloop = true;
localStorage.setItem("isloop", true);
}
}

function handleNormalPlay(){
if (localStorage.getItem("is_normal") === 'true') {
localStorage.setItem("is_normal", false);
} else {
audio.play();
localStorage.setItem("is_normal", true);
}
}

function loadPlaySpeed() {
var oldPlaySpeed = localStorage.getItem("diySpeed");
document.getElementById("diySpeed").value = oldPlaySpeed;
}

function savePlaySpeed() {
var newPlaySpeed = document.getElementById('diySpeed').value;
localStorage.setItem("diySpeed", newPlaySpeed);
localStorage.setItem("isActive", "diy");
audio.playbackRate = newPlaySpeed;
audio.play();
}

audio.addEventListener("ended", function () { // Paused state Doing
if (localStorage.getItem("isloop") === 'true') {
/*If it's already paused*/
/*Play*/
audio.play();
} else {
audio.pause(); /*Pause*/
}
});

var isActive = localStorage.getItem("isActive");
loadPlaySpeed();

if (isActive === "diy") {
localStorage.setItem("isActive", "diy");
var oldPlaySpeed = document.getElementById("diySpeed").value;
audio.playbackRate = oldPlaySpeed;
} else if (isActive === null) {
localStorage.setItem("isActive", "normal");
}

changeIcon();

function changeIcon(oldActive) {
isActive = localStorage.getItem("isActive");
if (oldActive) {
if (oldActive === "diy") { oldActive = isActive; }
var old = document.getElementsByClassName(oldActive);
old[0].setAttribute('style', 'background-color: #fff !important;color:#000;border-color:#000 !important;');
audio.play();
}
var activeIcon = document.getElementsByClassName(isActive);
activeIcon[0].setAttribute('style', 'background-color: #0000ff96 !important;color:#fff;border-color:cornflowerblue !important;');
switch (isActive) {
case "normal":
audio.playbackRate = 1;
break;
case "t-left":
audio.playbackRate = 0.7;
break;
case "t-right":
audio.playbackRate = 2;
break;
case "t-left25":
audio.playbackRate = 0.5;
break;
case "t-right5":
audio.playbackRate = 1.5;
break;
default:
break;
}
}

function handleNormalPlayback() {
audio.playbackRate = 1;
var oldActive = localStorage.getItem("isActive");
localStorage.setItem("isActive", "normal");
changeIcon(oldActive);
}

var t_left = document.getElementsByClassName('t-left');
var t_right = document.getElementsByClassName('t-right');
var playPause = document.getElementById('playPause');

function handleTurnLeft() {
audio.playbackRate = 0.7;
var oldActive = localStorage.getItem("isActive");
localStorage.setItem("isActive", "t-left");
changeIcon(oldActive);
}

function handleTurnRight() {
audio.playbackRate = 2;
var oldActive = localStorage.getItem("isActive");
localStorage.setItem("isActive", "t-right");
changeIcon(oldActive);
}

function handleTurnLeft025() {
audio.playbackRate = 0.5;
var oldActive = localStorage.getItem("isActive");
localStorage.setItem("isActive", "t-left25");
changeIcon(oldActive);
}

function handleTurnRight15() {
audio.playbackRate = 1.5;
var oldActive = localStorage.getItem("isActive");
localStorage.setItem("isActive", "t-right5");
changeIcon(oldActive);
}

</script>

And the code in styling part:

body{
margin: 0;
padding: 0;
background-color:#fff;
}
audio#audioTag {
width: 80%;
margin: 10px;
}
audio::-webkit-media-controls { 
overflow: hidden !important 
} 
audio::-webkit-media-controls-enclosure { 
width: calc(100% + 40px); 
margin-left: auto; 
} 
audio { 
border-radius: 50px; 
} 

.audio-box {
text-align: center;
margin: 30px auto;
width: 80%;
border-radius: 30px;
background-color: #efefef;
border-top: 1px solid #dddddd;
}


.a-controls {
width: 100%;
padding: 0;
position: relative;
text-align: center;
margin-bottom: 28px;
display: flex;
}
.a-controls .play-pause {
border: 0;
outline: 0;
padding: 0;
width: 100%;
height: 65px;
display: flex;
justify-content: center;
background-color: #efefef;
}
.a-controls .play-pause .icon-btn {
display: inline-block;
width: 100%;
height: 100%;
cursor: pointer;
}


.a-controls .play-pause .show{
display: block;
}



.a-controls .play-pause .icon-play {
width: 40px;
height: 40px;
background-size: 100% 100%;
border: 3px solid rgb(0, 0, 0);
border-radius: 50%;
font-size: 25px;
background-color: #efefef;
}



.a-controls .turn-ward {
width: 40px;
height: 40px;
position: absolute;
top: 50%;
margin-top: -20px;
box-sizing: border-box;
line-height: 35px;
border-radius: 50%;
border: 3px solid #000;
cursor: pointer;
}
.a-controls .t-left {
left: 30%;
/* margin-left: -20px; */
}
.a-controls .t-right {
right: 15%;
/* margin-right: -20px; */
}

.t-right5 {
right: 30%;
}
.t-left25{
left: 15%;
font-size: 13px;
}

.audio-footer{
display: flex;
}

.audio-footer div{
flex: 50%;
text-align: center;
margin-bottom: 20px;
}

@media screen and (max-width: 400px) {
.a-controls .turn-ward{
width: 30px;
height: 30px;
font-size: 12px;
line-height: 25px;
}

.a-controls .play-pause .icon-play{
width: 30px;
height: 30px;
font-size: 12px;
line-height: 25px;
}
}

The script in my last post just sets the value of the src attribute to the next audio file and calls play() when the ended event is fired. I don’t think it’s that difficult to follow, and once you understand it properly, it should probably be easy to incorporate into your script. If you have trouble understanding it, you can learn more about controlling media playback with Javascript at the following link or some links in the ‘See also’ section of that page.

2 Likes

Thank you very much for your reply! I am very sorry, I don’t have any programming background. May I still ask you for help? I can pay you. :sob:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.