YouTube API - how to display closed captions in my own div?

Hi,

Im using the iFrame API. I want to display the closed captions - with the timing - in my own div.

I can obtain the xml file thanks to this post: https://stackoverflow.com/questions/32142656/get-youtube-captions . But is there a way I can display the captions in my own div which is updated automatically to sync with the video? (the client doesnt want the captions to display within the video, only outside it).

Thanks

Hi @bolton, I don’t think you can hide the captions altogether – just force show them via the cc_load_policy parameter, but the default is to respect the user preferences.

As for displaying the captions in your own div though, this can be achieved by embedding the player using the JS API, parsing the loaded XML and display the text matching the current time of the player:

<div id="my-player"></div>
<div id="captions"></div>
/* global YT */

function initPlayer (xml) {
  const captions = document.getElementById('captions')

  // Load the player
  const player = new YT.Player('my-player', {
    videoId: '5MgBikgcWnY'
  })

  // Map the text elements to objects for easier access
  const texts = Array.from(
    xml.querySelectorAll('text'),
    text => ({
      text: text.textContent,
      start: Number(text.getAttribute('start')),
      dur: Number(text.getAttribute('dur'))
    })
  )

  let handle = null

  player.addEventListener('onStateChange', event => {
    if (event.data !== YT.PlayerState.PLAYING) {
      return window.clearInterval(handle)
    }

    // Find and display the text matching the current player time
    handle = window.setInterval(() => {
      const time = player.getCurrentTime()
      const current = texts.find(text => (
        text.start <= time &&
        text.start + text.dur >= time
      ))

      captions.textContent = current ? current.text : ''
    }, 100)
  })
}

window.onYouTubePlayerAPIReady = function () {
  // Load and parse the captions XML, then initialize the player
  fetch('https://video.google.com/timedtext?lang=en&v=5MgBikgcWnY')
    .then(res => res.text())
    .then(text => new DOMParser()
      .parseFromString(text, 'text/xml')
    ).then(initPlayer)
}
1 Like

Oh wow! Thanks so much, Ill have a play with this later.

1 Like

Hi guys. How can I add my own button which toggles the captions on/off?

Ive tried

 $("#show-captions").click(function(){
		 player.setOptions('captions', 1);
  });

but thats not working.
Thanks

The setOptions() functions takes 3 arguments: module, option and value. The only supported options for the captions module (which is in fact the only supported module) are fontSize and reload though – see here for details.

Hmm. Thanks. So theres no way I can interact with my initial code:

  function onYouTubePlayerAPIReady() {
	 player = new YT.Player('player', {
		 videoId: '<?=$videoID;?>',
		 playerVars: {'controls': 0, 'cc_load_policy': 0, 'iv_load_policy': 0, 'rel': 0, 'modestbranding': 1, 'disablekb': 1, 'start': <?=$timestamp;?>},
		events: {
			'onStateChange': onPlayerStateChange
		  }
    }); 
}

via jquery? For example, changing the settings of playerVars?

Ah, Ive just re-read your post and can see this wont be possible.

Im going to try and reload the iframe src (appending the cc_policy parameter) and see if that works.

Well, from the docs:

Setting the parameter’s value to 1 causes closed captions to be shown by default, even if the user has turned captions off. The default behavior is based on user preference.

So it appears that 1 is the only possible value for the cc_load_policy parameter – you can show the captions even if the user has disabled them in the settings, but not the other way round.