Closed Jta26 closed 4 years ago
yes it is fully broken
having ads again since 20 minutes
same here... Started getting ads about 10 minutes ago. I can't stream surf.
Same here :)
Question for @odensc, does this just spoof being an adsense crawler bot by setting the useragent header to Mediapartners-Google? Specifically setting it on the POST to the video-edge ttvnw.net link?
Yes it sets the user-agent on any request to ttvnw.net. I've tried a few other UAs that worked before, but they don't seem to anymore. They may have patched the whole user-agent bypass route, but I'm looking into it more when I have the time
Yes it sets the user-agent on any request to ttvnw.net. I've tried a few other UAs that worked before, but they don't seem to anymore. They may have patched the whole user-agent bypass route, but I'm looking into it more when I have the time
Yeah, they probably implemented something like this https://developers.google.com/search/docs/advanced/verifying-googlebot
Edit: they could have also just said screw it and are showing ads to web crawlers, considering that every web crawler user-agent is broken.
This works for me:
LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)
This works for me:
LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)
It no work :(
I've seen people post "working" user agents but they don't work for me. I think their account is just in a period where they have no prerolls because they've already watched one recently. You have to test it in incognito mode.
Yes it sets the user-agent on any request to ttvnw.net. I've tried a few other UAs that worked before, but they don't seem to anymore. They may have patched the whole user-agent bypass route, but I'm looking into it more when I have the time
(compatible; Mediapartners-Google/2.1; +http://www.google.com/bot.html)
^ This mobile version of Mediapartners user-agent works for me, anyone else test?
Seems to work so far
Update Doesn't work in incognito
I've seen people post "working" user agents but they don't work for me. I think their account is just in a period where they have no prerolls because they've already watched one recently. You have to test it in incognito mode.
I think this is the case too. Neither the linkedin bot or the mobile google bot are working for me. I'm not letting the ads finish playing, so it gives me another one.
@Jta26 i also have uBlock active. do you?
@codydbgt checked it in incognito mode. LinkedInBot works for me.
PS: reload the plugin
@Jta26 i also have uBlock active. do you?
@codydbgt checked it in incognito mode. LinkedInBot works for me.
Yeah, ublock is active, and I'm looking at the request headers and it's in there.
They could be rolling out the patch gradually
@PSSGCSim Yes this is a possibility too. could be a staged rollout. Previously when people were reporting it as broken last time, it was still working for me until about an hour later.
Fun fact, i use NextDNS on my iPhone with AdBlock Filter and i never get ads with the official Twitch App ... but what user-agent is it in there app?!
@revunix Mobile doesn't seem to have ads as often/at all.
@revunix Mobile doesn't seem to have ads as often/at all.
Same thing when running on something like a Chromecast.
@revunix Mobile doesn't seem to have ads as often/at all.
I use Twitch app on my Samsung and i've ads
LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com) seem to work for me after extension and twitch reloading
God dang it, so we ARE gg for now huh...
Temporary (and very janky) solution that replaces the video with an embed version (that doesn't get prerolls or midrolls?):
Open your Inspector, go to the Console, run the following:
let player = document.querySelector('.video-player')
const [url] = window.location.href.split('/').slice(-1)
player.outerHTML = "<iframe class='video-player' src='https://player.twitch.tv/?channel=" + url + "&parent=www.twitch.tv' data-a-target='video-player' data-a-player-type='site' data-test-selector='video-player__video-layout'></iframe>"
Temporary (and very janky) solution that replaces the video with an embed version (that doesn't get prerolls):
Open your Inspector, got to the Console, run the following:
let player = document.querySelector('.video-player') const [url] = window.location.href.split('/').slice(-1) player.outerHTML = "<iframe class='video-player' src='https://player.twitch.tv/?channel=" + url + "&parent=www.twitch.tv' data-a-target='video-player' data-a-player-type='site' data-test-selector='video-player__video-layout'></iframe>"
- Theatre mode doesn't work
- Switching channels doesn't work (need to refresh the page, and run the script again
- Midrolls might still come through, haven't watched long enough
This I think is a good temporary solution
edit: We can probably fix some of the issues you've lined up. Like listening for a change in the url bar to reload the iframe with the new stream.
This works for me:
LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)
Yes for the moment modifying header in the extension settings and reloading extension and Twitch working for the moment
This works for me:
LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)
meh .. i got ads again.
tested now Googlebot/2.1 (+http://www.google.com/bot.html)
and this "works"
@revunix Mobile doesn't seem to have ads as often/at all.
@odensc do you have a good user-agent to test?
I just got out of my cave and discovered theres no ads on the HLS version of twitch (https://twitchls.com), so if you are looking for a good blocker since a week like me, turns out we dont even need one :') GL guys and keep up the good work bc im pretty sure it won't last long before we get ads here too
I just got out of my cave and discovered theres no ads on the HLS version of twitch (https://twitchls.com), so if you are looking for a good blocker since a week like me, turns out we dont even need one :') GL guys and keep up the good work bc im pretty sure it won't last long before we get ads here too
I don't like this one cause I like to switch streams constantly, and the twitch UI is good for that.
edit: incognito w/ ublock and the extension has started working with the linkedin user-agent.
@Jta26
edit: We can probably fix some of the issues you've lined up. Like listening for a change in the url bar to reload the iframe with the new stream.
I tried some initial stuff, couldn't get anything working. Had a weird situation where the audio would play, even though the player was gone from its div. Probably didn't try hard enough, though.
The linkedin user agent seems to work for me. Using it in incognito, I've been clicking around multiple streams for the past 5-10 minutes and haven't seen an ad (yet), definitely no pre-rolls.
Make sure you set TTV ad-block's "Run in Private Windows" option to allow
(it's set to don't allow
by default)
edit: was just watching a stream where the streamer announced he was doing an ad break... no ads for me.
I've seen people post "working" user agents but they don't work for me. I think their account is just in a period where they have no prerolls because they've already watched one recently. You have to test it in incognito mode.
Testing the LinkedIn header with an incognito (with extension enabled) doesn't seem to work even after reloading the extension.
Edit: Firefox user
Twitch devs are here, reading all comments, code is open source, and will easily fix it next time too. Prove me wrong
This comment in another topic mentioned intercepting the GET requests to the M3U8 manifests rather than playing cat and mouse with the user agent string. I've never heard of Streamlink but it looks promising - does anyone know how long it's been around and how long their bypass has been working?
Twitch devs are here, reading all comments, code is open source, and will easily fix it next time too. Prove me wrong
This is a given. Adblocking is like the captcha problem with extra steps. Devs fix, then someone finds the workaround, repeat.
@sapphire-bt Their approach just removes the ad segments, which causes a black screen during ads AFAIK, doesn't actually skip them.
@Jta26 Exactly, the way I see it, it's much more beneficial to release it to a wide audience because nothing's gonna keep Twitch from getting the code if they wanted - it'll just hinder actual users. If I cared I'd have just kept it to myself from the start.
I find it slightly hilarious that some pissant manager is authorizing several thousands of dollars of employee time and resources to force what is now an extremely minor percent of twitch viewers to watch ads. There's no way it's a profitable use of time, and we will eventually win out unless they find the magic bullet of ads.
@sapphire-bt @rmanky @odensc
This comment in another topic mentioned intercepting the GET requests to the M3U8 manifests rather than playing cat and mouse with the user agent string. I've never heard of Streamlink but it looks promising - does anyone know how long it's been around and how long their bypass has been working?
I actually managed to reliably modify the m3u8 playlist. I think the next step is creating an addon that does this
let player = document.querySelector('.video-player')
const [url] = window.location.href.split('/').slice(-1)
player.outerHTML = "<iframe class='video-player' src='https://player.twitch.tv/?channel=" + url + "&parent=www.twitch.tv' data-a-target='video-player' data-a-player-type='site' data-test-selector='video-player__video-layout'></iframe>"
but uses the .m3u8
as a source which should be doable. Twitch devs are in here, we should take this conversation elsewhere.
If you setup a discord server somewhere I'd like to help the war effort. I was going to investigate twitchls's source code and see if there's anything there that gives a hint on what we could do.
On Wed, Nov 18, 2020, 7:33 PM Nicolas Martin notifications@github.com wrote:
This comment https://github.com/odensc/ttv-ublock/issues/8#issuecomment-728692054 in another topic mentioned intercepting the GET requests to the M3U8 manifests rather than playing cat and mouse with the user agent string. I've never heard of Streamlink but it looks promising - does anyone know how long it's been around and how long their bypass has been working?
I actually managed to reliably modify the m3u8 playlist. I think the next step is creating an addon that does this
let player = document.querySelector('.video-player') const [url] = window.location.href.split('/').slice(-1)player.outerHTML = ""
but uses the .m3u8 as a source which should be doable. Twitch devs are in here, we should take this conversation elsewhere.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/odensc/ttv-ublock/issues/11#issuecomment-730045338, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABUHXFMPTKY77CMR3NT56O3SQRRW3ANCNFSM4T2RWGZA .
@sapphire-bt @rmanky @odensc
This comment in another topic mentioned intercepting the GET requests to the M3U8 manifests rather than playing cat and mouse with the user agent string. I've never heard of Streamlink but it looks promising - does anyone know how long it's been around and how long their bypass has been working?
I actually managed to reliably modify the m3u8 playlist. I think the next step is creating an addon that does this
let player = document.querySelector('.video-player') const [url] = window.location.href.split('/').slice(-1) player.outerHTML = "<iframe class='video-player' src='https://player.twitch.tv/?channel=" + url + "&parent=www.twitch.tv' data-a-target='video-player' data-a-player-type='site' data-test-selector='video-player__video-layout'></iframe>"
but uses the
.m3u8
as a source which should be doable. Twitch devs are in here, we should take this conversation elsewhere.
Nice one - so is that effectively refreshing the iframe rather than "blocking" ads?
I don't think there's any point in moving the conversation elsewhere. If it's to be released as an add-on then the source code will be visible plain as day to anyone who wants to see it.
There's no docs for the usher.ttvnw.net
api I'm guessing it's not meant to be used publicly. That's why I was hesitant in sharing it, but you're right. If it's an extension it would have been visible anyway.
USER="$1"
OAUTH="$2"
RESP="`curl "https://api.twitch.tv/api/channels/$USER/access_token?adblock=true&need_https=true&platform=web&player_type=site&oauth_token" -H "Client-ID: $OAUTH" --compressed`"
TOKEN="`echo $RESP | jq '.token' | sed 's/\\\\"/"/g' | sed 's/\(^.\)//g' | sed 's/\(.$\)//g'`"
SIG="`echo $RESP | jq '.sig' | sed 's/\(^.\)//g' | sed 's/\(.$\)//g'`"
curl http://usher.ttvnw.net/api/channel/hls/$USER.m3u8\?allow_source\=true\&allow_audio_only\=true\&supported_codecs\=avc1\&sig\=$SIG\&token\=%7B%22adblock%22%3Afalse%2C%22authorization%22%3A%7B%22forbidden%22%3Afalse%2C%22reason%22%3A%22%22%7D%2C%22blackout_enabled%22%3Afalse%2C%22channel%22%3A%22jaeyun%22%2C%22channel_id%22%3A164378078%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%2C%22view_until%22%3A1924905600%7D%2C%22ci_gb%22%3Afalse%2C%22geoblock_reason%22%3A%22%22%2C%22device_id%22%3A%22a615b93a6c8acb58%22%2C%22expires%22%3A1605748569%2C%22extended_history_allowed%22%3Afalse%2C%22game%22%3A%22%22%2C%22hide_ads%22%3Afalse%2C%22https_required%22%3Afalse%2C%22mature%22%3Afalse%2C%22partner%22%3Afalse%2C%22platform%22%3A%22android%22%2C%22player_type%22%3A%22mobile_player%22%2C%22private%22%3A%7B%22allowed_to_view%22%3Atrue%7D%2C%22privileged%22%3Afalse%2C%22role%22%3A%22%22%2C%22server_ads%22%3Afalse%2C%22show_ads%22%3Atrue%2C%22subscriber%22%3Afalse%2C%22turbo%22%3Afalse%2C%22user_id%22%3A21251497%2C%22user_ip%22%3A%2299.99.99.99%22%2C%22version%22%3A2%7D
Streamlink pushed an update which does seem to block ads for now, but doesn't work with the suggested iframe
solution. They use a totally different api and get a different response. Which include ad format, start and stop time as well as the duration.
➜ ~ curl -s "$(streamlink --stream-url --twitch-disable-ads twitch.tv/reckful best)"
This might be possible on Firefox (the "Streamlink modify m3u8 playlist" method), but not on Chrome...
As far as I'm aware, modifying the response bodies would require this "bug" to not exist: https://bugs.chromium.org/p/chromium/issues/detail?id=104058
Will run some tests in Firefox
It seems like they detect where you're viewing the embed from and only omit ads if it's from some other website. I guess Twitch really doesn't want to have ads on legitimate embeds for some reason, so another workaround is to replace the video with an iframe to an arbitrary domain and have the extension intercept the html of that domain and turn it into a twitch embed.
^ seems to be quite valid actually. What I found is that if the parent
query parameter does not match your real domain, the content security policy will prevent anything form happening. On a whim I decided to put Twitch inside of....Twitch, and voila.
It's definitely worth doing some more experimentation, but by replacing the video player with an embed pointing to itself, I was able to skip ads (I manually paused the ad, replaced w/ the iframe). I'll work on a FF extension to automate this behavior and report back.
This is obviously quite a lazy thing as Twitch could always try to block itself from being an iframe parent, but it seems like a low-cost avenue.
On top of that, you can make any domain be the parent by having a parent iframe with a non-Twitch domain have an embed inside of it. It would be something like Twitch -> arbitrary domain -> Twitch, and Twitch thinks you're just watching via an embed on the arbitrary domain. They can never prevent that unless they decide to put ads on all embeds, which they've been reluctant to do.
There are several ways that can be done, the easiest of which is find domains that allow iframes (e.g. YouTube's embed subdomain) and use the extension to replace the html with a Twitch embed.
I'm working on a Twitch-in-Twitch proof of concept extension for Firefox right now, I'll report back if it seems consistent and maybe follow up with a middleman domain strategy.
I think the best ideas to get around this is something simple which forces them to make tough decisions - is it worth sacrificing X to get Y. This is probably one of those.
I'm going to head off to bed, but will leave my progress here. See update(s) below.
This is a Firefox addon (the background.js part), which attempts to splice out any ads from the m3u8 playlist/stream. It does not work currently, and if an ad starts playing it just kinda breaks.
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
// Filter the incoming data
filter.ondata = event => {
let str = decoder.decode(event.data, {
stream: true
});
// This splits the lines of the m3u8 by "#"
let lines = str.split("#");
// Rebuild is what gets sent to the player
// Debug is what gets logged to the console
let rebuild = "";
let debug = "";
// This pattern checks for the form #EXTINF:2.002,live
// Plz excuse bad regex
let pat = /EXTINF:([0-9]*\.[0-9]+|[0-9]+),[^l][^i][^v][^e]/
// For each line...
lines.forEach(line => {
// Make sure it isn't empty (the first line, basically)
if (line.length > 0) {
// Check for a series of ad-related tags (mostly taken from Streamlink)
if (line.indexOf("twitch-stitched-ad") == -1 &&
line.indexOf("stitched-ad-") == -1 &&
line.indexOf("X-TV-TWITCH-AD") == -1 &&
!pat.test(line)) {
rebuild += "#" + line;
debug += "#" + line;
} else {
// If ignored, only add it to the debug so we can track what is happening
debug += "<<DODGED BLOCK>>> #" + line;
}
}
});
console.log(debug);
filter.write(encoder.encode(rebuild));
filter.disconnect();
}
return {};
}
browser.webRequest.onBeforeRequest.addListener(
listener, {
urls: ["https://*.ttvnw.net/v1/playlist/*"]
}, ["blocking"]
);
console.log("goodbye ads? ☠")
I think the best ideas to get around this is something simple which forces them to make tough decisions - is it worth sacrificing X to get Y. This is probably one of those.
I agree, and abusing the embed would def be the way to do that. Not a bad idea to have multiple approaches, though.
Edit 10/19/2020 @ 10:30 AM I'm having a hard time getting ads to test (ironic, I know). When I do get an ad, the preview for the ad sits there but it never plays. Pressing the play/pause button causes the video to play the last bit of the ad, and then the stream starts normally. Sometimes, the a different ad will then play a few seconds later (which I don't quite understand, since there is no ".ts" file associated with those ads). I need to look at what Streamlink is doing further, and if they are actually able to splice out ads or if they just blackscreen during them. Also, I updated the code with some comments.
Edit 10/19/2020 @ 5:50 PM Keep scrolling, good news ahead
@rmanky You said the player stops until you toggle play, are the ads successfully skipped thereafter?
Here is the result of Twitch-in-Twitch: https://gfycat.com/PerfectWastefulAmericancrayfish
The code is dead simple, but will get more complex to account for the usability issues that are okay for a proof of concept but not for a real extension. For one, I'm just using 7.5 seconds as a guess to replace the window. Two, we'll need to adjust the target element to replace, as you can't switch channels without manually refreshing the page. There some smaller items as well such as resizability. But - it's definitely a promising line to go down.
Dead simple code:
setTimeout(() => {
const currentChannel = document.location.pathname.substring(1) // remove the leading slash.
const player = document.querySelector('.video-player');
const height = player.clientHeight;
const embedUrl = `https://player.twitch.tv/?channel=${currentChannel}&parent=twitch.tv`;
var frame = buildIframe(embedUrl, height);
player.replaceWith(frame);
}, 7.5 * 1000);
const buildIframe = (src, height) => {
var frame = document.createElement('iframe');
frame.setAttribute('src', src);
frame.setAttribute('height', height + 'px');
frame.setAttribute('width', '100%');
frame.setAttribute('allowfullscreen', true);
return frame;
};
@rmanky You said the player stops until you toggle play, are the ads successfully skipped thereafter?
it did a few times, something is wrong with the code though so some ads are playing... debugging
Here is the result of Twitch-in-Twitch: https://gfycat.com/PerfectWastefulAmericancrayfish
The code is dead simple, but will get more complex to account for the usability issues that are okay for a proof of concept but not for a real extension. For one, I'm just using 7.5 seconds as a guess to replace the window. Two, we'll need to adjust the target element to replace, as you can't switch channels without manually refreshing the page. There some smaller items as well such as resizability. But - it's definitely a promising line to go down.
Dead simple code:
setTimeout(() => { const currentChannel = document.location.pathname.substring(1) // remove the leading slash. const player = document.querySelector('.video-player'); const height = player.clientHeight; const embedUrl = `https://player.twitch.tv/?channel=${currentChannel}&parent=twitch.tv`; var frame = buildIframe(embedUrl, height); player.replaceWith(frame); }, 7.5 * 1000); const buildIframe = (src, height) => { var frame = document.createElement('iframe'); frame.setAttribute('src', src); frame.setAttribute('height', height + 'px'); frame.setAttribute('width', '100%'); frame.setAttribute('allowfullscreen', true); return frame; };
instead of waiting an arbitrary amount using setTimeout
, why not use document.onload
?
I'd love to contribute to keeping this updated, cause these ads are killing me.
1.1.1 seems to be not working, McDonald's is telling me to not use the ketchup in my fridge again.
Edit from maintainer:
https://github.com/odensc/ttv-ublock/issues/11#issuecomment-731700033