11twitch - videoad . js text / javascript
22( function ( ) {
33 if ( / ( ^ | \. ) t w i t c h \. t v $ / . test ( document . location . hostname ) === false ) { return ; }
4- var ourTwitchAdSolutionsVersion = 5 ; // Only bump this when there's a breaking change to Twitch, the script, or there's a conflict with an unmaintained extension which uses this script
5- if ( window . twitchAdSolutionsVersion && window . twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion ) {
6- console . log ( "skipping vaft as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window . twitchAdSolutionsVersion ) ;
7- window . twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion ;
4+ var ourTwitchAdSolutionsVersion = 6 ; // Only bump this when there's a breaking change to Twitch, the script, or there's a conflict with an unmaintained extension which uses this script
5+ if ( typeof unsafeWindow === 'undefined' ) {
6+ unsafeWindow = window ;
7+ }
8+ if ( typeof unsafeWindow . twitchAdSolutionsVersion !== 'undefined' && unsafeWindow . twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion ) {
9+ console . log ( "skipping vaft as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + unsafeWindow . twitchAdSolutionsVersion ) ;
10+ unsafeWindow . twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion ;
811 return ;
912 }
10- window . twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion ;
13+ unsafeWindow . twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion ;
1114 function declareOptions ( scope ) {
1215 scope . AdSignifier = 'stitched' ;
1316 scope . ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko' ;
1417 scope . ClientVersion = 'null' ;
1518 scope . ClientSession = 'null' ;
1619 scope . PlayerType2 = 'embed' ; //Source
1720 scope . PlayerType3 = 'site' ; //Source
18- scope . PlayerType4 = 'picture-by-picture ' ; //360p
21+ scope . PlayerType4 = 'autoplay ' ; //360p
1922 scope . CurrentChannelName = null ;
2023 scope . UsherParams = null ;
2124 scope . WasShowingAd = false ;
@@ -90,8 +93,8 @@ twitch-videoad.js text/javascript
9093 || workerStringReinsert . some ( ( x ) => workerString . includes ( x ) ) ;
9194 }
9295 function hookWindowWorker ( ) {
93- var reinsert = getWorkersForReinsert ( window . Worker ) ;
94- var newWorker = class Worker extends getCleanWorker ( window . Worker ) {
96+ var reinsert = getWorkersForReinsert ( unsafeWindow . Worker ) ;
97+ var newWorker = class Worker extends getCleanWorker ( unsafeWindow . Worker ) {
9598 constructor ( twitchBlobUrl , options ) {
9699 var isTwitchWorker = false ;
97100 try {
@@ -242,10 +245,10 @@ twitch-videoad.js text/javascript
242245 qualityToSelect = 0 ;
243246 }
244247 }
245- var currentQualityLS = window . localStorage . getItem ( 'video-quality' ) ;
248+ var currentQualityLS = unsafeWindow . localStorage . getItem ( 'video-quality' ) ;
246249 lowQuality [ qualityToSelect ] . click ( ) ;
247250 settingsCog . click ( ) ;
248- window . localStorage . setItem ( 'video-quality' , currentQualityLS ) ;
251+ unsafeWindow . localStorage . setItem ( 'video-quality' , currentQualityLS ) ;
249252 if ( e . data . value != null ) {
250253 OriginalVideoPlayerQuality = null ;
251254 IsPlayerAutoQuality = null ;
@@ -292,7 +295,7 @@ twitch-videoad.js text/javascript
292295 }
293296 } ;
294297 var workerInstance = reinsertWorkers ( newWorker , reinsert ) ;
295- Object . defineProperty ( window , 'Worker' , {
298+ Object . defineProperty ( unsafeWindow , 'Worker' , {
296299 get : function ( ) {
297300 return workerInstance ;
298301 } ,
@@ -836,26 +839,81 @@ twitch-videoad.js text/javascript
836839 } catch ( err ) { }
837840 } catch ( err ) { }
838841 }
839- window . reloadTwitchPlayer = doTwitchPlayerTask ;
842+ unsafeWindow . reloadTwitchPlayer = doTwitchPlayerTask ;
840843 var localDeviceID = null ;
841- localDeviceID = window . localStorage . getItem ( 'local_copy_unique_id' ) ;
844+ localDeviceID = unsafeWindow . localStorage . getItem ( 'local_copy_unique_id' ) ;
842845 function postTwitchWorkerMessage ( key , value ) {
843846 twitchWorkers . forEach ( ( worker ) => {
844847 worker . postMessage ( { key : key , value : value } ) ;
845848 } ) ;
846849 }
850+ function makeGmXmlHttpRequest ( fetchRequest ) {
851+ return new Promise ( ( resolve , reject ) => {
852+ GM . xmlHttpRequest ( {
853+ method : fetchRequest . options . method ,
854+ url : fetchRequest . url ,
855+ data : fetchRequest . options . body ,
856+ headers : fetchRequest . options . headers ,
857+ onload : response => resolve ( response ) ,
858+ onerror : error => reject ( error )
859+ } ) ;
860+ } ) ;
861+ }
862+ // Taken from https://github.com/dimdenGD/YeahTwitter/blob/9e0520f5abe029f57929795d8de0d2e5d3751cf3/us.js#L48
863+ function parseHeaders ( headersString ) {
864+ const headers = new Headers ( ) ;
865+ const lines = headersString . trim ( ) . split ( / [ \r \n ] + / ) ;
866+ lines . forEach ( line => {
867+ const parts = line . split ( ':' ) ;
868+ const header = parts . shift ( ) ;
869+ const value = parts . join ( ':' ) ;
870+ headers . append ( header , value ) ;
871+ } ) ;
872+ return headers ;
873+ }
874+ var serverLikesThisBrowser = false ;
875+ var serverHatesThisBrowser = false ;
847876 async function handleWorkerFetchRequest ( fetchRequest ) {
848877 try {
849- const response = await window . realFetch ( fetchRequest . url , fetchRequest . options ) ;
850- const responseBody = await response . text ( ) ;
851- const responseObject = {
852- id : fetchRequest . id ,
853- status : response . status ,
854- statusText : response . statusText ,
855- headers : Object . fromEntries ( response . headers . entries ( ) ) ,
856- body : responseBody
857- } ;
858- return responseObject ;
878+ if ( serverLikesThisBrowser || ! serverHatesThisBrowser ) {
879+ const response = await unsafeWindow . realFetch ( fetchRequest . url , fetchRequest . options ) ;
880+ const responseBody = await response . text ( ) ;
881+ const responseObject = {
882+ id : fetchRequest . id ,
883+ status : response . status ,
884+ statusText : response . statusText ,
885+ headers : Object . fromEntries ( response . headers . entries ( ) ) ,
886+ body : responseBody
887+ } ;
888+ if ( responseObject . status === 200 ) {
889+ var resp = JSON . parse ( responseBody ) ;
890+ if ( typeof resp . errors !== 'undefined' ) {
891+ serverHatesThisBrowser = true ;
892+ } else {
893+ serverLikesThisBrowser = true ;
894+ }
895+ }
896+ if ( serverLikesThisBrowser || ! serverHatesThisBrowser ) {
897+ return responseObject ;
898+ }
899+ }
900+ if ( typeof GM !== 'undefined' && typeof GM . xmlHttpRequest !== 'undefined' ) {
901+ fetchRequest . options . headers [ 'User-Agent' ] = 'Mozilla/5.0 (X11; Linux i686; rv:140.0) Gecko/20100101 Firefox/140.0' ;
902+ fetchRequest . options . headers [ 'Referer' ] = 'https://www.twitch.tv/' ;
903+ fetchRequest . options . headers [ 'Origin' ] = 'https://www.twitch.tv/' ;
904+ fetchRequest . options . headers [ 'Host' ] = 'gql.twitch.tv' ;
905+ const response = await makeGmXmlHttpRequest ( fetchRequest ) ;
906+ const responseBody = response . responseText ;
907+ const responseObject = {
908+ id : fetchRequest . id ,
909+ status : response . status ,
910+ statusText : response . statusText ,
911+ headers : Object . fromEntries ( parseHeaders ( response . responseHeaders ) . entries ( ) ) ,
912+ body : responseBody
913+ } ;
914+ return responseObject ;
915+ }
916+ throw { message : 'Failed to resolve GQL request. Try the userscript version of the ad blocking solution' } ;
859917 } catch ( error ) {
860918 return {
861919 id : fetchRequest . id ,
@@ -864,12 +922,12 @@ twitch-videoad.js text/javascript
864922 }
865923 }
866924 function hookFetch ( ) {
867- var realFetch = window . fetch ;
868- window . realFetch = realFetch ;
869- window . fetch = function ( url , init , ...args ) {
925+ var realFetch = unsafeWindow . fetch ;
926+ unsafeWindow . realFetch = realFetch ;
927+ unsafeWindow . fetch = function ( url , init , ...args ) {
870928 if ( typeof url === 'string' ) {
871929 //Check if squad stream.
872- if ( window . location . pathname . includes ( '/squad' ) ) {
930+ if ( unsafeWindow . location . pathname . includes ( '/squad' ) ) {
873931 postTwitchWorkerMessage ( 'UpdateIsSquadStream' , true ) ;
874932 } else {
875933 postTwitchWorkerMessage ( 'UpdateIsSquadStream' , false ) ;
@@ -992,13 +1050,13 @@ twitch-videoad.js text/javascript
9921050 }
9931051 } catch { }
9941052 }
995- declareOptions ( window ) ;
1053+ declareOptions ( unsafeWindow ) ;
9961054 hookWindowWorker ( ) ;
9971055 hookFetch ( ) ;
9981056 if ( document . readyState === "complete" || document . readyState === "loaded" || document . readyState === "interactive" ) {
9991057 onContentLoaded ( ) ;
10001058 } else {
1001- window . addEventListener ( "DOMContentLoaded" , function ( ) {
1059+ unsafeWindow . addEventListener ( "DOMContentLoaded" , function ( ) {
10021060 onContentLoaded ( ) ;
10031061 } ) ;
10041062 }
0 commit comments