JavaScript replace, insert audio file if text string

Hi!

I use this script to replace certain text strings with images whenever they are present in a field:

<div id=front>{{Front}}</div>
<script>
    var str = document.getElementById("front").innerHTML;
        var res = str.replace('1', "<img src='_1.png'>");
    document.getElementById("front").innerHTML = res;
</script>

Is it possible to do the same for audio?

So whenever 1 is present in the field, the saved audio file _1.wav is played, just as if the field were to contain [sound:_1.wav].

I’ve tried a few different things but can’t get it to work. This for example just plays the audio regardless of if 1 is present in the field or not:

var res = str.replace('1', "[sound:_1.wav]");

If I instead use this script I get what I want…

<script>
var audioElement = new Audio('_1.wav');
var field = document.getElementById('front').innerText;
if (field.includes('1')) {
  audioElement.play();
}
</script>

… only it results in all audio files playing at the same time if I have several present in the field.

Could someone help me out a bit?

You can try the following:

<div id="front">{{Front}}</div>
<div id="audio-players" />

<script>
    var audioMap = [
        ["foo", "_foo.mp3"],
        ["bar", "_bar.mp3"],
        ["baz", "_baz.mp3"],
    ];

    var field = document.getElementById("front").innerText;
    var index = 0;
    var audios = audioMap
        .filter(([word, _]) => field.includes(word))
        .map(([_, file]) => {
            const audio = new Audio(file);
            audio.controls = true;
            audio.addEventListener(
                "ended",
                () => {
                    if (++index < audios.length) {
                        audios[index].play();
                    }
                },
                { once: true },
            );
            return audio;
        });

    document.getElementById("audio-players").append(...audios);

    if (audios.length) {
        audios[0].play();
    }
</script>

If you do not wish to display the players, delete the following three lines:

  • <div id="audio-players" />
  • audio.controls = true;
  • document.getElementById("audio-players").append(...audios);
1 Like

Thank you @hkr, I’ve tried your script now. I have two issues, the audio is played in the order of the var audioMap = [ mapping and not the order of the card (so if I have 1 3 2 in a field it is played as 1 2 3 regardless). And if the same text string exists at several different places in a field it is only played once, I need it to be played for every instance. Can this be fixed?

I misunderstood what you want to do. I think maybe the following is what you want (or something close to it).

<div id="front">{{Front}}</div>
<div id="audio-players" />

<script>
    var audioMap = new Map([
        ["foo", "_foo.mp3"],
        ["bar", "_bar.mp3"],
        ["baz", "_baz.mp3"],
    ]);

    // https://stackoverflow.com/a/3561711
    function escapeRegex(string) {
        return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
    }

    var words = [...audioMap.keys()].map(escapeRegex);
    var regexp = new RegExp(words.join("|"), "g");
    var field = document.getElementById("front").innerText;
    var index = 0;
    var audios = [...field.matchAll(regexp)].map(([word]) => {
        const audio = new Audio(audioMap.get(word));
        audio.controls = true;
        audio.addEventListener(
            "ended",
            () => {
                if (++index < audios.length) {
                    audios[index].play();
                }
            },
            { once: true },
        );
        return audio;
    });

    document.getElementById("audio-players").append(...audios);

    if (audios.length) {
        audios[0].play();
    }
</script>
1 Like

Works like a charm :+1: Thank you for the help, I appreciate it!

1 Like

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