'(OBSOLETE) How do I get around the "removeCue not listed" bug?

I FIGURED OUT A FIX FOR THIS MYSELF, PLEASE DISREGARD THIS.

I am working on a website that contains a video player with toggleable subtitles. Since I found out that VTT files cannot be displayed with local files, I decided to use a different set of code to get around it.

I have a button that is supposed to turn the subtitles on or off. While pressing the button once creates a subtitle line as it should, turning it off a second time doesn't make them disappear, it just triggers this error:

VM513:84 Uncaught DOMException: Failed to execute 'removeCue' on 'TextTrack': The specified cue is not listed in the TextTrack's list of cues.
    at <anonymous>:84:8
    at Array.map (<anonymous>)
    at subtitles (<anonymous>:79:51)
    at HTMLButtonElement.onclick (https://www.w3schools.com/html/tryit.asp?filename=tryhtml5_audio_all:1:220)

As a result, a third click results in a second copy of the subtitle track spawning, and so on.

Please help me find a way to fix this!

Code:

<html>
<head>
    <title>Subtitle Toggle</title>
</head>

<center>
    <video controls id="movie">
        <source src="https://www.w3schools.com/html/movie.mp4" type="video/mp4">
    </video><br/><br/>
    <button onclick="subtitles()">Toggle Subtitles</button>
</center>

<!-- Subtitles -->
<script type="text/vtt" id="sub">
    WEBVTT
    
    1
    00:00:01.000 --> 00:00:03.000
    Subtitle line 1
    
    2
    00:00:04.000 --> 00:00:05.000
    Subtitle line 2
    
    3
    00:00:06.000 --> 00:00:10.000
    Subtitle lines 3
    and 4
</script>

<script>
var subs = 0;
var trk = movie.addTextTrack('subtitles');
trk.mode = "showing";

// Get around "VTT not displaying" bug
function parse_timestamp(s)
{
    // Relaxing the timestamp format:
    var match = s.match(/^(?:([0-9]+):)?([0-5][0-9]):([0-5][0-9](?:[.,][0-9]{0,3})?)/);
    if (match == null)
    {
        throw 'Invalid timestamp format: ' + s;
    }
    var hours = parseInt(match[1] || "0", 10);
    var minutes = parseInt(match[2], 10);
    var seconds = parseFloat(match[3].replace(',', '.'));
    return seconds + 60 * minutes + 60 * 60 * hours;
}

function quick_and_dirty_vtt_or_srt_parser(vtt)
{
    var lines = vtt.trim().replace('\r\n', '\n').split(/[\r\n]/).map(function(line)
    {
        return line.trim();
    });
    var cues = [];
    var start = null;
    var end = null;
    var payload = null;
    for (var i = 0; i < lines.length; i++)
    {
        if (lines[i].indexOf('-->') >= 0)
        {
            var splitted = lines[i].split(/[ \t]+-->[ \t]+/);
            if (splitted.length != 2)
            {
                throw 'Error when splitting "-->": ' + lines[i];
            }

            // Already ignoring anything past the "end" timestamp (i.e. cue settings).
            start = parse_timestamp(splitted[0]);
            end = parse_timestamp(splitted[1]);
        }
        else if (lines[i] == '')
        {
            if (start && end)
            {
                var cue = new VTTCue(start, end, payload);
                cues.push(cue);
                start = null;
                end = null;
                payload = null;
            }
        }
        else if (start && end)
        {
            if (payload == null)
            {
                payload = lines[i];
            }
            else
            {
                payload += '\n' + lines[i];
            }
        }
    }
    if (start && end)
    {
        var cue = new VTTCue(start, end, payload);
        cues.push(cue);
    }
    return cues;
}

function subtitles()
{
    subs ++;
    quick_and_dirty_vtt_or_srt_parser(sub.innerHTML).map(function(cue)
    {
        if (subs == 1) trk.addCue(cue); else
        {
            subs = 0;
            trk.removeCue(cue);
        }
    });
}
</script>

</html>


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source