How to detect page navigation on YouTube and modify its appearance seamlessly?

YouTube site doesn’t reload pages on navigation, it replaces the history state.

The extension’s content scripts aren’t reinjected when URL changes without a page being reloaded. Naturally when you reload a page manually the content script is executed.

There are several methods to detect page transitions on Youtube site:

  • using a background page script: webNavigation API, tabs API

  • using a content script: transitionend event for the progress meter on video pages

  • using a content script and a site-specific event triggered on video navigation:

    Run getEventListeners(document) in devtools console and inspect the output.

    enter image description here

    yt-navigate-start is what we need in this case.

    Notes:

    • for other tasks we might want yt-navigate-finish
    • the old youtube design was using spfdone event

manifest.json:

{
  "name": "YouTube Playlist Length",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": ".............",
  "content_scripts": [{
      "matches": [ "*://*.youtube.com/*" ],
      "js": [ "content.js" ],
      "run_at": "document_start"
  }]
}

Note: the matches key encompasses the entire youtube.com domain so that the content script runs when the user first opens the home youtube page then navigates to a watch page.

content.js:

document.addEventListener('yt-navigate-start', process);

if (document.body) process();
else document.addEventListener('DOMContentLoaded', process);

The process function will alter the page.
Note, the specified element classes and structure will change in the future.

function process() {
  if (!location.pathname.startsWith('/playlist')) {
    return;
  }
  var seconds = [].reduce.call(
    document.getElementsByClassName('timestamp'),
    function (sum, ts) {
      var minsec = ts.textContent.split(':');
      return sum + minsec[0] * 60 + minsec[1] * 1;
    },
    0,
  );
  if (!seconds) {
    console.warn('Got no timestamps. Empty playlist?');
    return;
  }
  var timeHMS = new Date(seconds * 1000).toUTCString().split(' ')[4]
    .replace(/^[0:]+/, ''); // trim leading zeroes
  document.querySelector('.pl-header-details')
    .insertAdjacentHTML('beforeend', '<li>Length: ' + timeHMS + '</li>');
}

Leave a Comment