Skip to content

Instantly share code, notes, and snippets.

@odensc

odensc/ads.js Secret

Last active May 21, 2024 16:13
Show Gist options
  • Save odensc/764900d841cbdd8aa400796001e189f1 to your computer and use it in GitHub Desktop.
Save odensc/764900d841cbdd8aa400796001e189f1 to your computer and use it in GitHub Desktop.
uBlock Twitch ad fix (v3) - Alternative link with no caching; https://ttv-ublock.vercel.app/twitch-videoad.js
/// twitch-videoad.js
const origFetch = window.fetch;
window.fetch = (url, init, ...args) => {
if (typeof url === "string") {
if (url.includes("/access_token")) {
// url = url.replace("player_type=site", "player_type=site");
} else if (
url.includes("/gql") &&
init &&
typeof init.body === "string" &&
init.body.includes("PlaybackAccessToken")
) {
// const newBody = JSON.parse(init.body);
// newBody.variables.playerType = "site";
// init.body = JSON.stringify(newBody);
}
}
return origFetch(url, init, ...args);
};
@pixeltris
Copy link

Oh right that's where you got the picture-by-picture value from. Interestingly although it's 360p it does get flagged as server_ads:false (which is how things used to go with these kinds of edits). Long term it's probably a useful thing to consider as a hybrid approach if they close all of the other holes.

I guess I would be incorrect about the original m3u8 being uninterrupted then. A new stream is created at 360p and the old one gets the ad segments.

@odensc
Copy link
Author

odensc commented Oct 30, 2020

Yeah I think the (more) permanent fix will be to hide the main stream while the ads are playing and swap over to the 360p one, and back.

@pixeltris
Copy link

Here's a very rough / crappy proof of concept for that https://gist.github.com/pixeltris/77c676ef65b0b76e7aa56d8a0e0b3897

It can be tested here https://www.twitch.tv/twitchmedia28 which gives pre-roll ads at a 100% rate.

When it detects ad segments it fetches that mini player (no-ad) stream. It then tries matching up the segments between the two m3u8 files. It kinda (but not really) works. It will often fail to load, and when it does it will skip a few seconds. Maybe stripping out the #EXT-X-DISCONTINUITY entries might help out with that though. Additionally it assumes segments match up in duration which for ads may not be the case (I think Twitch uses 2 seconds for everything, but it would be a bad idea to rely on that).

Some better handling would be required to make this smooth (probably re-creating the entire m3u8 file from scratch with your own sequencing / timing stuff). I'm probably not going to do anything more with it though. It was just a bit of a fun experiment.

@f0rmatme
Copy link

f0rmatme commented Nov 1, 2020

@pixeltris hey i mean it blocks ads and gets the job done for now until someone maybe converts it into python and adds it to like stream link

@PureFallen
Copy link

PureFallen commented Nov 1, 2020

@odensc @pixeltris I wonder if that stream shown in the mini player does have Audio in first place?
30 seconds of audio-less 360p stream per 10 minutes is probably annoying, but the best we can come up with for the moment when Twitch apparently has a problem with uBO now.

Twitch might be changing their tactic now, which in instead of fixing the bypass for pre-rolls ad just increase the flooding of mid-roll ads for users, slightly highlighted in this tweet, picking more aggressive messages or serving ads to Subscribers or Twitch Turbo Users when they have uBO installed, yet it is always hard to say if the last one is intended or just a bug from their daily experiments with their users...

Seeing that pixeltris managed to match different m3u8 files together, i wonder how suitable the idea is of crowdsourcing correct segments over P2P or servers? (that is assuming that ad segments can be recognised as those, preferly seconds before they are displayed). Random pre-rolls or mid-rolls could probably be crowdsourced by everyone, while manually triggered ads by streamers (displayed for everyone at the same time) would probably require Subs/Turbos to crowdsource.
That the community has theoretically the power of doing something like that has been shown with Sponsorblock before, through blocking advertisments embedded into YouTube Videos using Timestamps is way easier as swapping out segments on the fly.
Wish there would be an easier solution, but it did not sound like someone came up with something better yet? (And it is probably not something possible to do as userResource of uBO, almost feeling like that would need to become an external project that needs to be distributed so... meh..)

@pixeltris
Copy link

pixeltris commented Nov 1, 2020

The 360p stream does have audio. The implementation I made was just a quick proof of concept. More advanced segment matching / m3u8 re-creation would probably be a more ideal solution.

It should be noted that embeded streams don't even show pre-roll ads, so you could simply start with the embeded and then switch to the regular. The .ts urls might even match up exactly when doing this, so you could get a perfect switch without any lost time.

I actually believe Twitch when they say that ad-screen was unintended. Their choice to simply change the message which is displayed rather than 'fixing' the issue was maybe a bit of a "fuck you" to people circumventing ads. But the original issue happened from the first time the switch was made in the script.

Crowdsourcing segments may be an end-game solution, yes. But for now there are several ways of avoiding ads (although a perfect solution hasn't been created yet). It is possible to write a uBlock script as complex as you want (e.g. the widely used Nano Defender), but it wont get accepted into the uBlock repo.

@f0rmatme as noted it's just a proof of concept. Streamlink already does a lot of processing on the m3u8 files. Those guys would be able to produce a much better solution in their scenario.

@PureFallen
Copy link

The crowdsourcing was maybe grabbed a bit far for the current situation, but with Twitch being busy trying to fix our ways to avoid ads for now in a daily basis, i kinda wanted to drop that brain ghost from mine just in case.
Thanks for your input pixeltris! I hope myself that it never comes so far but yeah, only the future knows and in case we run out of workarounds, we better want to have the research on theoretical inplementation of crowdsourcing done, before we are forced to do it and run into issues at the wrong time. Having it integrated as optional parameter in Streamlink and getting them and their experience with m3m8 processing with in the boat would probably be great news, through for now thats more of a dream as an actual solution and i am aware of that.

@Hideman85
Copy link

From my side the issue is that probably twitch look at this (and other) conversation about this issue and everything you made will be wipe out with a next twitch update. So one first solution would be to make the conversation more private and a way to manage users that can access to the information so the fixes you or others makes would work for a longer period.
PS: Keep in mind that twitch looks to actively works on this since lot of changes has been made over the month to fix breaches.

A public solution (not optimal but better than nothing) is just doing some simple scripting for muting the ad and do some styling to have the picture to picture player taking the place of the ad (even full screen if user is) and then revert back to the user config (full screen or not, volume, ...) when the ad is done. This solution make the assumption that twitch will always keep the feature of a mini player during the ad and so this will work on the long term.

An other issue is twitch start to detect that the user use an ad blocker and then become more aggressive for that user (this is also mentioned above) that at the end is even more annoying (I think this is the goal in order to change the mind of the persons).

The reel issue is that twitch ads system is too much intrusive, it would be better to have a skip button like on youtube (this also has been mentioned on original uBO issue) maybe a good solution would be to have a way to change this behavior, potentially a petition or something like this could change mind on this (and we can also trigger regular users (users without blockers) to have a bigger voice).

In any case thanks a lot for your investigating the twitch ad system is truly annoying and the work you do helps a lot in this way.

PS: I've remarked a behavior with the current script that could be exploited but it would be safer to use a private conv if we want to keep this exploit longer.

@PureFallen
Copy link

PureFallen commented Nov 1, 2020

@Hideman85 Having the discussion enclosed is just a temporary fix itself. The moment a new fix is distributed to the users, Twitch will be able to take care of that. It is not like the sourcecode has such a complexity that Twitch could not figure out how the workaround works. Otherwise they haven't been able to fix it in a couple of hours in the last months before.
Hiding the conversation probably makes only sense for a new solution to catch Twitch offguard with, for example gathering all developers for the crowdsource idea (or a similar endgame solution) together in an IRC, Discord, Telegram Chat etc. just to make it accessable to the public later anyway once the fix itself hits the userbase again. That is kinda the point of security using opensource, enclosing information never works in the longrun or hurts the trust towards the users.

Edit (03/11/2020)
Not sure if caused by the thunderdome revision (or if that one was supposed to fix it), but recently it seems like that the Midroll no longer shows the Mini Player, as well of staying displayed after the "supposed to be 30 second adbreak" ends. This happened now multiple times to me already, never happened before but like starting from this morning. Could it be intentional from Twitch or am i just unlucky?
Image for Reference

Edit (04/11/2020)
As already might noticed from Reddit, Twitch fixed advertisments for the thunderdome-playertype.

@pixeltris
Copy link

@PureFallen that specific twitch channel shouldn't be used for those kinds of tests as they force ads to be shown.

I've noticed that embed still works on https://twitchls.com. One interesting thing about it is that if you copy the main m3u8 url that it requests and enter that url into your browser url bar manually, you will get a response with ads. But the response they get NEVER has ads. I've been unable to find out why. I've copied every http header, and still I always get ads on my requests. Thoughts?

@PureFallen
Copy link

@pixeltris I want to apologize. I missed the opportunity to document it when i saw pre-rolls and mid-roll ads on a regular Twitch Channel and head over to Twitchmedia. Same mistake won't happen again. I gonna replace the source as soon as it happens again with the updated script & cache cleared/browser restarted.
According to some people they got ads on https://twitchls.com too... Biggest concern is for now that Amazon is rolling out fixes in waves which makes it hard to reproduce for us all at the same time.

@odensc
Copy link
Author

odensc commented Nov 4, 2020

@pixeltris Interesting. I'm seeing the same result. Let me look into this

@odensc
Copy link
Author

odensc commented Nov 4, 2020

@pixeltris So it comes down to the video-weaver.xxx.xxx.ttvnw.net m3u8 playlist request. If the Origin header is set to https://player.twitch.tv, it returns a playlist with no ads. Anything else, and it has pre-rolls.

There's no way to set the origin via JS AFAIK, besides a browser extension.

@pixeltris
Copy link

pixeltris commented Nov 4, 2020

Weirdly I haven't been able to reproduce the same. But I'm using standard .NET request stuff so maybe there's some weird header overwrite going on.

A browser extension probably isn't a terrible idea if Twitch is dedicated to their cause. I have a feeling the embedded scenarios will likely continue to avoid pre-roll ads as playing ads straight away doesn't bode well for trying to draw in new users to their platform.

@PureFallen
Copy link

PureFallen commented Nov 5, 2020

Setting up a browser extension to change the Origin header sounds like a better solution then setting up a whole network for Crowdsourcing. Yet in both cases, it will get hard to get the extension distributed underneath users again.

Another thing i worry about is that some privacy settings/configurations on browsers might break the Origin header that would need to be tried out and checked for in the extension. That could also explain why some solutions seem to work for one user, while it does not for others.
For example, people have been reporting that the November 2nd Update of the "Alternative Player" Extension would have fixed ads but from i can tell, it did not work for me when clicking through some regular Twitch channels.

@Brybry
Copy link

Brybry commented Nov 5, 2020

Doesn't greasemonkey/tampermonkey's GM_xmlhttpRequest allow modifying the Origin header?
So in the fetch hook do a XHR on video-weaver.xxx.xxx.ttvnw.net m3u8 requests instead. I'm just not sure on implementation for wrapping GM_XHR and properly emulating fetch API behavior with a Response promise.

@odensc
Copy link
Author

odensc commented Nov 5, 2020

Extension/tampermonkey script (if what @Brybry said is true) will probably be needed soon. Twitch is now getting feisty and doing things like limiting to 480p to annoy people into disabling uBlock. Found another player_type but it won't last long obviously.

@PureFallen
Copy link

The recent update to reset the playertype to a "non resolution capped one" having the funny side effect of "player_type=site" apparently now being used everywhere, greeting users with up to 90 seconds of pre-rolls at the frontpage.

That the frontpage still works for non uBO users while "player_type=frontpage" as we used it a few days before got fixed by Twitch, it should be clear that there is atleast one ingredient on the formular we are missing out on. Origin might be already a good start.

@fREAST
Copy link

fREAST commented Nov 6, 2020

I've been using the script @pixeltris posted here a couple of days ago (https://gist.github.com/pixeltris/77c676ef65b0b76e7aa56d8a0e0b3897), without any problems like forced low resolution or ads, it's been working fine for me and when ads are played (both preroll and midroll), its replaced by the PIP feed (that is 480p though), but I have not once seen an ad since I changed to that script.

@odensc
Copy link
Author

odensc commented Nov 6, 2020

@PureFallen thanks for that note, I just completely commented it out for now. Also, they locked the frontpage player_type so it only blocks ads on streams that are actually featured on the frontpage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment