Gary Gary - 3 months ago 9
HTML Question

How to run a script every time a new page is loaded on YouTube?

Since some time last year, YouTube made it so that every page is not actually loading an entirely new page, but primarily just re-loading the contents in

div#content
. You can notice this when you click on a link in YouTube and see the red loading bar at the top of the page.

I have a Greasemonkey script that modified elements on YouTube, but now that YouTube doesn't reload the entire page, the Greasemonkey script no longer fires on every "new" page. How can I make the Greasemonkey script fire on every "new" page that I load on YouTube?

I'm using jQuery in this Greasemonkey script. I tried using functions like
.on()
with
DOMNodeInserted
but I can't find the right combination to make it work properly. With the event listeners that I've been using, I end up running my script hundreds of times for each page load, such as with the following:

$('div#page').on('DOMNodeInserted', 'div#content', function() { });


Another solution I was thinking of was making all links on YouTube load pages like normal, without the new way that they are doing it.

Answer

I figured it out myself after some research. First off, I don't like solutions that use setTimeout. This is often one method suggested in favor over the deprecated DOMNodeInserted for instance (which I use in some of my scripts, but try to avoid as much as possible), but if possible, I always prefer a solution where the script actually executes after a specific event. I've posted the solution I initially used in the first section below, then the final solution I used in the second section. All code below requires jQuery.

Decent solution, but not the best

At first, I had a solution where I added a click event to all A elements, which would run a timer that ran my script after 2 seconds. This isn't elegant, because if the page loads quickly, then there's a split second where the script hasn't run. And if the page loads for more than two seconds, then the script doesn't run at all. Script below:

$('a').click(function()
{
    setTimeout(youtubeFunction, 2000);
});

Much better solution

So I began looking for a solution that was related to what I wanted to accomplish. I eventually found other people with a similar problem to mine (such as people wanting to create a Chrome script that modifies YouTube pages). This led me to this particular Stack Overflow solution, which basically says that the red loading bar at the top of YouTube pages was a CSS transition element, and that it created a transitionend (case sensitive) event when it was finished. The code in the linked solution wasn't complete (for me anyway), but it did explain how to achieve a working solution. The code I have runs only once per page, which is perfect. So here's what I have now:

function youtubePageChange()
{
    youtubeFunction();
    $('body').on('transitionend', function(event)
    {
        if (event.target.id != 'progress') return false;
        youtubeFunction();
    });
}

$(youtubePageChange);

To explain the code above, basically I run the code once for when you first load a YouTube page (such as by typing the URL in the address bar). Then for every subsequent click that requires the progress bar, the code runs again.

Red progress bar code

Oh, and for future reference, when the red progress bar appears at the top of YouTube pages, the site temporarily adds a new DIV to the end of BODY, with the following code:

<div id="progress" class="waiting" style="transition-duration: 400ms; width: 99%;"><dt></dt><dd></dd></div>
Comments