11

I'm writing a Chrome extension so I need to be able to listen for changes in the YouTube URL (i.e., see that you switched videos). YouTube makes this hard because with its HTML5 video player there is no full page reload, there is no URL fragment change (cannot listen for hashchange event as other answers have suggested). Listening for pushState also doesn't work. I've spent a lot of time looking for answers here on SO and all the ones I've seen thus far (except for one -- that I really don't want to use) don't work.

The only answer I've seen that works is setting a timeout to run every second to see if the URL changed (ugly!).

Edit: The possible duplicate question is a totally different question--one dealing with listening to URL changes the other dealing with getting the extension to load.

Question: How can I detect URL changes in YouTube's HTML5 video player without polling?

Community
  • 1
  • 1
eb80
  • 4,700
  • 5
  • 25
  • 30
  • Possible duplicate of [Chrome extension is not loading on browser navigation at YouTube](http://stackoverflow.com/questions/18397962/chrome-extension-is-not-loading-on-browser-navigation-at-youtube) – brasofilo Nov 27 '15 at 03:02
  • The possible duplicate question is a totally different question--one dealing with listening to URL changes the other dealing with getting the extension to load. – eb80 Nov 29 '15 at 00:58
  • @eb80 Did you find any solution after all? – Samuel Bushi Nov 04 '17 at 05:42

4 Answers4

14

My solution was to simply check for the transitionend event on the #progress element (this is the red progress bar that shows up at the top).

document.addEventListener('transitionend', function(e) {
    if (e.target.id === 'progress')
        // do stuff
});


Update:

An even cleaner solution is to just listen for the spfdone event triggered by spfjs, the framework used by YouTube to manipulate push state. Credit to Rob for the answer.

document.addEventListener('spfdone', function() {
    // do stuff
});
Drazen Bjelovuk
  • 5,201
  • 5
  • 37
  • 64
  • 3
    Upvoted because the 'spfdone' event is fired but unfortunately not on YouTube's [new material design](https://www.youtube.com/new) – cprcrack May 23 '17 at 12:05
  • I'm curious @Drazen, what extension did you develop? Is it compatible with the new material design? – cprcrack May 23 '17 at 12:10
  • Interesting. I haven't tested it with the new material design, so not sure about that. [Here's the userscript I needed this for](https://greasyfork.org/en/scripts/19151-get-youtube-thumbnail). – Drazen Bjelovuk May 23 '17 at 15:03
10

I stumbled across this issue, so maybe this will benefit someone. What did the trick for me is to listen for the yt-page-data-updated event, which detects a video switch.

I was able to inspect it by using the monitorEvents(document.body) and getEventListeners(document.body) Chrome DevTools Commands upon page update. But keep in mind that it won't work on full page reload (by directly accessing the URL), so I had to coordinate with a load event, something like this:

window.addEventListener('load', function () {
    console.log('load');
});

window.addEventListener('yt-page-data-updated', function () {
    console.log('url change');
});
Yassine Addi
  • 343
  • 2
  • 10
  • 9
    I found the `yt-navigate-finish` event, which seems more appropriate, and it also works on full page reload, so you no longer need the `load` event! – Pauan Mar 24 '19 at 13:51
  • There's also `yt-navigate-start` if you prefer to run your hook immediately upon navigation rather than waiting for the new content to load. – Andy Jul 26 '22 at 19:19
1

I'm not entirely sure how this would work from a chrome extension, but if it's feasible the onStateChange event could be of great benefit to you. I'm fairly new to the YouTube API, but this works for me:

var player = document.getElementById('youtubeVideo');
player.addEventListener('onStateChange', function(e) {
  if (e.data === 1) {
    // Video started playing.
    // Should work for when the video changes as well.
    // As long as it's within the same element.
    console.log(player.getVideoUrl());
  }
  // Watch for other events?
});
Joe
  • 2,596
  • 2
  • 14
  • 11
  • This looks very promising. Can you explain a little more how i'd use this? Do I need to include a YouTube JS API script in my extension? It doesn't look like this code can just be put in the YouTube.com page as is. – eb80 Jun 19 '14 at 12:50
  • Running on YT page, I'm seeing `movie_player` instead of `youtubeVideo` and `e.data` does not exist, should be `e === -1`... further tests required, I'm commenting just for the records – brasofilo Nov 27 '15 at 03:12
0

How to update the title and URL from a YouTube page:

Firstly, I disagree with all the above solutions because they're not solutions in my books, as they rely on Google's programming which is ever-changing!

The cardinal rule is to NEVER rely on Google's variable names and/or programming structure, so here's a universal solution that should work irrespective of any future YouTube changes, as long as they're using the standard HTML video player.

So working on an iframe loaded with a /watch?v=C2cMG33mWVY URL format (meaning browser/extension authors only), one can...

var D=W.contentWindow.document;  // Where "W" is your tab/frame ID.

We can monitor the duration-change event of the video player...

NB: I'm using this event because two videos in succession having exactly the same duration although not impossible, would be extremely rare!

D.getElementsByTagName('video')[0].ondurationchange=function(){ setTimeout(function(){ UpdateTab(W.id, D.title, D.URL); },1500); };

NB #1: I've added a little delay before updating to allow plenty of time for the title and url to change.

NB #2: UpdateTab() is my custom function which you can replace with yours... I'm sure you get the drift.

That's it.

J4GD33P 51NGH
  • 630
  • 1
  • 8
  • 24