Search code examples
html5-videoclosed-captionsvtt

HTML5 video player won't load .vtt subtitle track


I'm trying to add a subtitle track to a video and I can't figure out why it isn't working correctly. Here is my HTML:

<video controls>
  <source src="../assets/video/sample.mp4" type="video/mp4" />
  <track
    src="../assets/video/sample.vtt"
    kind="subtitles"
    srclang="en"
    label="English"
  />
</video>

And here is my .vtt file:

WEBVTT

00:00:00.500 --> 00:00:02.000
The Web is always changing

00:00:02.500 --> 00:00:04.300
and the way we access it is changing

Problem:
When I run my website locally the video will load, but when I click on the closed captions button and select English, there is a console error that reads:

GET http://localhost:8080/assets/video/sample.vtt 404 (Not Found).  

If I deploy the website and run it from the server instead, selecting the English subtitle track doesn't display any errors, but...

  • The subtitles don't appear on the video.
  • The Closed Captions button is removed from the video player controls on Chrome.
  • In other browsers, the Closed Caption button remains, but everything else is identical.

If I check the Network tab in Chrome dev tools, I can see that the request was made for sample.vtt at the correct request URL and returned a 200 status code.

The odd thing is that when I look at the response for that request, instead of seeing the text of the .vtt file, it shows the full text of my website's index.html file, which is located in an entirely separate folder.

I'm not sure why this is happening, and it seems like this should be a relatively simple thing to set up, so I can't figure out what's going wrong.


Solution

  • This ended up being an issue with Webpack. This app is in Vue, so I added the following options under the "vue" rule in vue.config.js, and it worked:

    config.module
          .rule("vue")
          .use("vue-loader")
          .loader("vue-loader")
          .tap((options) => {
            options.transpileOptions = {
              transforms: {
                dangerousTaggedTemplateString: true,
              },
            };
            options["transformAssetUrls"] = {
              video: ["src", "poster"],
              source: "src",
              img: "src",
              image: ["xlink:href", "href"],
              use: ["xlink:href", "href"],
              "b-embed": ["src", "poster"],
              track: "src",
            };
            return options;
          });
        config.module
          .rule("media")
          .test(/\.(vtt|mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/);