YouTube not triggering history.pushState
Asked Answered
M

2

3

I'm trying to detect a page change on YouTube by using history.pushState, but it never seems to trigger. I ultimately want to get this working from a Tampermonkey/Greasemonkey script, and for that I understand you need to inject the script into the actual page, which I've done like so, but to no avail:

html = 
    "var oldState      = history.pushState;"+
    "history.pushState = function() {" +
        "alert('url changed');" +
        "return oldState.apply(this);" +
    "}";

var head = document.getElementsByTagName("body")[0];         
var script = document.createElement('script');
script.type = 'text/javascript';
script.innerHTML = html;
head.appendChild(script);

I've also tried running the same code from the debug console:

var oldState      = history.pushState;
history.pushState = function() {
    alert('url changed');
    return oldState.apply(this);
};

But that didn't seem to do it either. Anyone have an idea of what's going on here?

Murage answered 12/5, 2015 at 18:54 Comment(8)
What makes you think history.pushState would detect a change? That methods adds an entry to the history. Detecting a change requires to listen for the popstate event.Blakeblakelee
I'm overriding the function, or at least that's the idea. onpopstate only seems to trigger when the back and forward buttons are pressed (from what I've tested). See https://mcmap.net/q/65755/-how-to-get-notified-about-changes-of-the-history-via-history-pushstateMurage
Ah, ok. Have you checked first of all, if your script insertion actually works? Like by trying to put a console.log statement in there, and see if that generates the expected output …Blakeblakelee
Yep, script insertion is fine.Murage
And console.log(history.pushState) (before overwriting it) yields what?Blakeblakelee
function () { [native code] }Murage
Did anyone ever find a solution to this?Tautologism
@EricNemchik Unfortunately not.Murage
S
4

YouTube uses spfjs to manipulate pushState. However it grabs the function generally before you can monkey patch it. This is why you are experiencing the issue.

Either move your monkey patch script up in the page before spf.js is loaded, or you can look for the spf events like spfdone to detect the change.

Scandian answered 31/8, 2016 at 3:9 Comment(3)
@Scandian I'm trying to monkey patch it in nw.js preload script (inject_js_start), which is definitely earlier than spfjs loads. Also, I verified that the function is successfully patched. Weird thing is that it won't be called with youtube (or spfjs). Looks like it does something weird (like manipulating history without calling it pushState/replaceState) - any ideas?Rawley
@Rawley I used the events for my script, not monkey patching. However it's been quite awhile and since the Material redesign most of my complaints have been solved so I haven't needed a user script for youtubeScandian
Thanks @Rob. I have resolved the issue - it was due to youtube using history API from an "about:blank" iframe and not from main window (and yet it's still affecting main window's history somehow). I don't understand why they're doing it, or why it works as it seems counter-intuitive. If anyone knows an answer to that please let me know. Oh and to make it even more confusing it still loads spfjs code that has history manipulation but never gets called.Rawley
L
0

I found a workaround to detect page change on Youtube. I followed Rob's suggestion, I tried to Proxy on window.spf (Spfjs) and window.history.pushState, also tried spf events but nothing worked!

I noticed that youtube changed the <title> </title> (browser tab's title) whenever the page is changed.

I ended up with a Mutation Observer on the title tag and combined it's event with the location.href to check the new page.


new MutationObserver(function (mutations) {
    if (window.location.href.includes('youtube') && window.location.href.includes('watch')) {
      
      // code for watch page
    }
    else if (window.location.href.includes('youtube') && window.location.href.includes('results')) {

      // code for search page
    }
  }).observe(
    document.querySelector('title'),
    { subtree: true, characterData: true, childList: true }
  );
Lindeman answered 30/5, 2023 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.