Opened 5 years ago

Closed 5 years ago

#1154 closed change (incomplete)

Adblock Plus removes History.prototype.pushState on YouTube

Reported by: YePpHa Assignee:
Priority: P2 Milestone:
Module: Platform Keywords:
Cc: sebastian, mapx, trev Blocked By:
Blocking: Platform: Safari
Ready: no Confidential: no
Tester: Verified working: no
Review URL(s):

Description

Background

I was doing some work on making YouTube Center compatible with YouTube's SPF feature, but I found out that Adblock Plus removes the prototype function 'History.prototype.pushState', which is needed for the SPF feature to work.
In the work to make YouTube Center compatible with SPF I found an easy method to subscribe to the SPF events so that it should be possible for Adblock Plus to use the same method to remove ads delivered through SPF.

What to change

Adblock should instead of removing 'History.prototype.pushState' subscribe to the spf events on the document: spferror, spfrequested, spfpartreceived, spfpartprocessed, spfreceived, spfprocessed, spfready, spfjsbeforeunload, spfjsunload, spfcssbeforeunload and spfcssunload.

The 'spfrequested' event will always be called when navigating to another page. The 'spfprocessed' will always be called whenever SPF has finished its work and the page is ready to be interacted with.

SPF is able to stream multiple chunks of a page when navigating and it's called 'multipart'. The multipart will also call the 'spfpartreceived' and 'spfpartprocessed' event. The 'spfreceived' event will be called when every part of the page you're navigating to has been received.

When you add an event listener to these events some data is also being delivered through the event and it can be manipulated with so that YouTube will use the manipulated version as it's only a reference that is sent through the event. So by changing it everything else that received that reference through the event will get the changed version.

To add an event listener works the same way like other events (i.e. onclick, onscroll, etc.). SPF dispatches its events on the document element so the event listeners needs to be attached on that said element.

document.addEventListener("spfpartreceived", listener, false);

The event argument delivered to the listener callback when SPF dispatches said event will have a key named 'detail' as SPF uses the browser feature called CustomEvent. The listener function could then look something like this:

function listener(e) {
  var detail = e.detail;
  var part = detail.part;
  /* YouTube delivers the player config through swfcfg, which also contains ads */
  if (part && part.swfcfg) {
    part.swfcfg = removeAds(part.swfcfg);
  }
  /* .. more code to remove ads from HTML, which is also transferred like this */
}

I would believe that Adblock Plus could subscribe to the events and then remove the ads, which should be removed from the detail object.

The structure of the detail object is a little different for both the multipart type and the non-multipart type. The 'spfreceived' event will contain

{
  url: '/* Full URL */',
  response: {
    /* multipart type response */
    parts: [ /* The received parts */ ],
    /* non-multipart type response */
    js: "...",
    css: "...",
    title: "...",
    html: { ... },
    attr: { ... }
  }
}

I've stored some of detail objects for when navigating to https://www.youtube.com/ and https://www.youtube.com/watch?v=jDELybyZ4oU.

When I navigated to the watch page I got three parts through the 'spfpartreceived' event:
[0]: https://gist.github.com/YePpHa/effa0886f19bc5469b36
[1]: https://gist.github.com/YePpHa/b7c337ec58d5bff3d389
[2]: https://gist.github.com/YePpHa/b6bcdfa4778ae57aac29
and then I got the 'spfreceived' event, which had this in the detail object: https://gist.github.com/YePpHa/75c4da4877a14f2d673a.

For when I navigated to https://www.youtube.com/ I got the detail object for 'spfreceived': https://gist.github.com/YePpHa/1515199e283babb97f5c.

For my own project YouTube Center I've created a very simple wrapper to add event listeners to SPF, where it's also possible to check if the SPF feature is enabled or disable. It can be found at https://gist.github.com/YePpHa/279ef0c2b122c176c370.

Change History (7)

comment:1 Changed 5 years ago by mapx

  • Cc mapx added
  • Component changed from Unknown to Platform
  • Priority changed from Unknown to P2

comment:2 Changed 5 years ago by mapx

  • Cc sebastian added

comment:3 Changed 5 years ago by sebastian

  • Cc trev added
  • Platform changed from Chrome to Safari

Note that we only remove the history API on YouTube on Safari. We do so to make sure that the player is initialized with flashvars. So we can rewrite them to block the ads. This isn't necessary for other browsers like Chrome and Firefox, since we can just block the request loading the actual ads, there.

I like your approach. But I wonder how often it will break after YouTube updated their website?

comment:4 Changed 5 years ago by YePpHa

It's true that YouTube have made a lot of changes over these past few year including SPF, but I think that was because they were still experimenting with SPF. As they have released their SPF library I don't think these changes would occur again. Though I could be incorrect, but it would be fairly easy to track the work done on that repository and see if they make any changes that would break the current method to attach the event listeners and manipulate the detail object. I would be more concerned about the browser making the detail object unique for each listener so that the detail object can't be manipulated, but this is very unlikely.

Also you said you only remove the history API on YouTube on Safari, but I'm running Chrome on Windows 8.1 and the history API is still removed. So I think that someone accidentally also added that feature to the Chrome version of Adblock Plus.

comment:5 Changed 5 years ago by sebastian

Might it be that you are not using Adblock Plus, but a different adblocker?

comment:6 Changed 5 years ago by YePpHa

Seems like you're correct.

comment:7 Changed 5 years ago by mapx

  • Resolution set to invalid
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.