-
-
Save pixeltris/ee77c8338d7ebe1b9973dfcc973409d8 to your computer and use it in GitHub Desktop.
twitch-videoad.js application/javascript | |
(function() { | |
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; } | |
// Worker injection by instance01 (https://github.com/instance01/Twitch-HLS-AdBlock) | |
const oldWorker = window.Worker; | |
window.Worker = class Worker extends oldWorker { | |
constructor(twitchBlobUrl) { | |
var jsURL = getWasmWorkerUrl(twitchBlobUrl); | |
var version = jsURL.match(/wasmworker\.min\-(.*)\.js/)[1]; | |
var functions = getFuncsForInjection(); | |
var newBlobStr = ` | |
var Module = { | |
WASM_BINARY_URL: '${jsURL.replace('.js', '.wasm')}', | |
WASM_CACHE_MODE: true | |
} | |
${ functions } | |
importScripts('${jsURL}'); | |
` | |
super(URL.createObjectURL(new Blob([newBlobStr]))); | |
var adDiv = null; | |
this.onmessage = function(e) { | |
if (e.data.key == 'UboShowAdBanner') { | |
if (adDiv == null) { adDiv = getAdDiv(); } | |
adDiv.style.display = 'block'; | |
} | |
else if (e.data.key == 'UboHideAdBanner') { | |
if (adDiv == null) { adDiv = getAdDiv(); } | |
adDiv.style.display = 'none'; | |
} | |
} | |
function getAdDiv() { | |
var msg = 'uBlock Origin is waiting for ads to finish...'; | |
var playerRootDiv = document.querySelector(".video-player"); | |
var adDiv = null; | |
if (playerRootDiv != null) { | |
adDiv = playerRootDiv.querySelector('.ubo-overlay'); | |
if (adDiv == null) { | |
adDiv = document.createElement('div'); | |
adDiv.className = 'ubo-overlay'; | |
adDiv.innerHTML = '<div class="player-ad-notice" style="color: white; background-color: rgba(0, 0, 0, 0.8); position: absolute; top: 0px; left: 0px; padding: 10px;"><p>' + msg + '</p></div>'; | |
adDiv.style.display = 'none'; | |
playerRootDiv.appendChild(adDiv); | |
} | |
} | |
return adDiv; | |
} | |
} | |
} | |
function getWasmWorkerUrl (twitchBlobUrl) { | |
var req = new XMLHttpRequest(); | |
req.open('GET', twitchBlobUrl, false); | |
req.send(); | |
return req.responseText.split("'")[1]; | |
} | |
function getFuncsForInjection () { | |
function stripAds (textStr) { | |
var haveAdTags = textStr.includes('#EXT-X-SCTE35-OUT') || textStr.includes('stitched-ad'); | |
if (haveAdTags && !textStr.includes(',live')) { | |
textStr = "#EXTM3U\n#EXT-X-MEDIA-SEQUENCE:-1\n#EXT-X-TARGETDURATION:1\n#EXTINF:2.000,live\nhttps://localhost/twitch_url_which_will_always_fail.ts" | |
postMessage({key:'UboShowAdBanner'}); | |
} | |
else { | |
postMessage({key:'UboHideAdBanner'}); | |
if (haveAdTags) { | |
var trimStartIndex = -1; | |
var hasLiveSegment = false; | |
var lines = textStr.replace("\r", "").split("\n"); | |
for (var i = 0; i < lines.length; i++) { | |
var line = lines[i]; | |
if (line.startsWith("#EXT-X-PROGRAM-DATE-TIME")) { | |
trimStartIndex = i; | |
} | |
else if (line.startsWith("#EXTINF:")) { | |
if (!line.includes(",live") && trimStartIndex >= 0) { | |
for (var j = trimStartIndex; j < lines.length; j++) { | |
var isEnd = !lines[j].startsWith("#"); | |
lines[j] = ""; | |
if (isEnd) { | |
break; | |
} | |
} | |
} | |
} | |
} | |
textStr = lines.join("\n"); | |
} | |
} | |
return textStr; | |
} | |
return `${stripAds.toString()}${fetchTs.toString()}fetchTs();` | |
} | |
function fetchTs() { | |
var realFetch = fetch; | |
fetch = async function(url, options) { | |
if (typeof url === 'string') { | |
if (url.endsWith('m3u8')) { | |
// Based on https://github.com/jpillora/xhook | |
return new Promise(function(resolve, reject) { | |
var processAfter = async function(response) { | |
var str = stripAds(await response.text()); | |
var modifiedResponse = new Response(str); | |
resolve(modifiedResponse); | |
}; | |
var send = function() { | |
return realFetch(url, options).then(function(response) { | |
processAfter(response); | |
})["catch"](function(err) { | |
console.log('fetch hook err ' + err); | |
reject(err); | |
}); | |
}; | |
send(); | |
}); | |
} | |
} | |
return realFetch.apply(this, arguments); | |
} | |
} | |
})(); |
I've tested on chrome/firefox and I haven't noticed m3u8 spam. It will spam the m3u8 if you strip all segments which is why insert a fake sequence in such cases. This might break down at mid-roll ads as the sequence number that I use is -1. This could potentially cause the m3u8 spam (or most likely just break the stream). More advanced sequence number tracking is required in such scenarios but sequence modifications can introduce stuttering / loops.
The current duration for the fake sequence is set to 1 or 2 seconds I think before it requests another m3u8. If you want to increase that duration just modify the durations here #EXT-X-TARGETDURATION:1\n#EXTINF:2.000,live
.
But yea improvements need to be made to this in general as I think midrolls just result in error code #1000 or something (likely due to the -1 squence). There's still a looping issue which occurs sometimes when first entering a stream too, I really need to inspect the m3u8 files when this happens to see what's going on, annoyingly it doesn't happen every time.
@pixeltris, I think (I cannot test extensively because of my limited connection) this causes Twitch to request m3u files in a loop, using more bandwidth than normal stream.