mirror of
https://github.com/pixeltris/TwitchAdSolutions.git
synced 2025-04-29 14:14:36 +02:00
parent
aa5dff2cb5
commit
43a0397504
@ -1,6 +1,13 @@
|
|||||||
twitch-videoad.js text/javascript
|
twitch-videoad.js text/javascript
|
||||||
(function() {
|
(function() {
|
||||||
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
|
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
|
||||||
|
var ourTwitchAdSolutionsVersion = 1;// 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
|
||||||
|
if (window.twitchAdSolutionsVersion && window.twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion) {
|
||||||
|
console.log("skipping vaft as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window.twitchAdSolutionsVersion);
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
function declareOptions(scope) {
|
function declareOptions(scope) {
|
||||||
scope.AdSignifier = 'stitched';
|
scope.AdSignifier = 'stitched';
|
||||||
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
|
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
|
||||||
@ -25,31 +32,79 @@ twitch-videoad.js text/javascript
|
|||||||
var adBlockDiv = null;
|
var adBlockDiv = null;
|
||||||
var OriginalVideoPlayerQuality = null;
|
var OriginalVideoPlayerQuality = null;
|
||||||
var IsPlayerAutoQuality = null;
|
var IsPlayerAutoQuality = null;
|
||||||
const oldWorker = window.Worker;
|
var workerStringConflicts = [
|
||||||
function isWorkerDoubleHooked(ourWorker, identifier) {
|
'twitch',
|
||||||
var ourWorkerString = ourWorker ? ourWorker.toString() : null;
|
'isVariantA'// TwitchNoSub
|
||||||
var proto = window.Worker;
|
];
|
||||||
while (proto)
|
var workerStringAllow = [];
|
||||||
{
|
//
|
||||||
|
// TwitchNoSub (userscript) conflicts in this scenario:
|
||||||
|
// - TwitchAdSolutions : TwitchNoSub : window.Worker
|
||||||
|
//
|
||||||
|
// But it's fine in this scenario:
|
||||||
|
// - TwitchNoSub : TwitchAdSolutions : window.Worker
|
||||||
|
//
|
||||||
|
// This is because their script ignores the incoming blob (our script) and replaces it with their own importScripts call
|
||||||
|
// To fix this we scoop out TwitchNoSub and re-insert it so that it inherits from our worker
|
||||||
|
var workerStringReinsert = [
|
||||||
|
'isVariantA'// TwitchNoSub
|
||||||
|
];
|
||||||
|
function getCleanWorker(worker) {
|
||||||
|
var root = null;
|
||||||
|
var parent = null;
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
var workerString = proto.toString();
|
var workerString = proto.toString();
|
||||||
if (workerString.includes(identifier) && workerString !== ourWorkerString) {
|
if (workerStringConflicts.some((x) => workerString.includes(x)) && !workerStringAllow.some((x) => workerString.includes(x))) {
|
||||||
return true;
|
if (parent !== null) {
|
||||||
|
Object.setPrototypeOf(parent, Object.getPrototypeOf(proto));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (root === null) {
|
||||||
|
root = proto;
|
||||||
|
}
|
||||||
|
parent = proto;
|
||||||
}
|
}
|
||||||
proto = Object.getPrototypeOf(proto);
|
proto = Object.getPrototypeOf(proto);
|
||||||
}
|
}
|
||||||
return false;
|
return root;
|
||||||
|
}
|
||||||
|
function getWorkersForReinsert(worker) {
|
||||||
|
var result = [];
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
|
var workerString = proto.toString();
|
||||||
|
if (workerStringReinsert.some((x) => workerString.includes(x))) {
|
||||||
|
result.push(proto);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
function reinsertWorkers(worker, reinsert) {
|
||||||
|
var parent = worker;
|
||||||
|
for (var i = 0; i < reinsert.length; i++) {
|
||||||
|
Object.setPrototypeOf(reinsert[i], parent);
|
||||||
|
parent = reinsert[i];
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
function isValidWorker(worker) {
|
||||||
|
var workerString = worker.toString();
|
||||||
|
return !workerStringConflicts.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringAllow.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringReinsert.some((x) => workerString.includes(x));
|
||||||
|
|
||||||
}
|
}
|
||||||
function hookWindowWorker() {
|
function hookWindowWorker() {
|
||||||
var newWorker = window.Worker = class Worker extends oldWorker {
|
var reinsert = getWorkersForReinsert(window.Worker);
|
||||||
|
var newWorker = class Worker extends getCleanWorker(window.Worker) {
|
||||||
constructor(twitchBlobUrl, options) {
|
constructor(twitchBlobUrl, options) {
|
||||||
var isTwitchWorker = false;
|
var isTwitchWorker = false;
|
||||||
try {
|
try {
|
||||||
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
||||||
} catch {}
|
} catch {}
|
||||||
if (isWorkerDoubleHooked(newWorker, 'twitch')) {
|
|
||||||
console.log('Multiple twitch adblockers installed. Skipping Worker hook (vaft)');
|
|
||||||
isTwitchWorker = false;
|
|
||||||
}
|
|
||||||
if (!isTwitchWorker) {
|
if (!isTwitchWorker) {
|
||||||
super(twitchBlobUrl, options);
|
super(twitchBlobUrl, options);
|
||||||
return;
|
return;
|
||||||
@ -66,34 +121,32 @@ twitch-videoad.js text/javascript
|
|||||||
${adRecordgqlPacket.toString()}
|
${adRecordgqlPacket.toString()}
|
||||||
${tryNotifyTwitch.toString()}
|
${tryNotifyTwitch.toString()}
|
||||||
${parseAttributes.toString()}
|
${parseAttributes.toString()}
|
||||||
${getWasmWorkerUrl.toString()}
|
${getWasmWorkerJs.toString()}
|
||||||
var workerUrl = getWasmWorkerUrl('${twitchBlobUrl.replaceAll("'", "%27")}');
|
var workerString = getWasmWorkerJs('${twitchBlobUrl.replaceAll("'", "%27")}');
|
||||||
if (workerUrl && workerUrl.includes('assets.twitch.tv/assets/amazon-ivs-wasmworker')) {
|
declareOptions(self);
|
||||||
declareOptions(self);
|
self.addEventListener('message', function(e) {
|
||||||
self.addEventListener('message', function(e) {
|
if (e.data.key == 'UpdateIsSquadStream') {
|
||||||
if (e.data.key == 'UpdateIsSquadStream') {
|
IsSquadStream = e.data.value;
|
||||||
IsSquadStream = e.data.value;
|
} else if (e.data.key == 'UpdateClientVersion') {
|
||||||
} else if (e.data.key == 'UpdateClientVersion') {
|
ClientVersion = e.data.value;
|
||||||
ClientVersion = e.data.value;
|
} else if (e.data.key == 'UpdateClientSession') {
|
||||||
} else if (e.data.key == 'UpdateClientSession') {
|
ClientSession = e.data.value;
|
||||||
ClientSession = e.data.value;
|
} else if (e.data.key == 'UpdateClientId') {
|
||||||
} else if (e.data.key == 'UpdateClientId') {
|
ClientID = e.data.value;
|
||||||
ClientID = e.data.value;
|
} else if (e.data.key == 'UpdateDeviceId') {
|
||||||
} else if (e.data.key == 'UpdateDeviceId') {
|
GQLDeviceID = e.data.value;
|
||||||
GQLDeviceID = e.data.value;
|
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
||||||
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
ClientIntegrityHeader = e.data.value;
|
||||||
ClientIntegrityHeader = e.data.value;
|
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
||||||
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
AuthorizationHeader = e.data.value;
|
||||||
AuthorizationHeader = e.data.value;
|
}
|
||||||
}
|
});
|
||||||
});
|
hookWorkerFetch();
|
||||||
hookWorkerFetch();
|
eval(workerString);
|
||||||
importScripts(workerUrl);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
||||||
twitchWorkers.push(this);
|
twitchWorkers.push(this);
|
||||||
this.onmessage = function(e) {
|
this.addEventListener('message', (e) => {
|
||||||
if (e.data.key == 'ShowAdBlockBanner') {
|
if (e.data.key == 'ShowAdBlockBanner') {
|
||||||
if (adBlockDiv == null) {
|
if (adBlockDiv == null) {
|
||||||
adBlockDiv = getAdBlockDiv();
|
adBlockDiv = getAdBlockDiv();
|
||||||
@ -198,7 +251,7 @@ twitch-videoad.js text/javascript
|
|||||||
IsPlayerAutoQuality = null;
|
IsPlayerAutoQuality = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
function getAdBlockDiv() {
|
function getAdBlockDiv() {
|
||||||
//To display a notification to the user, that an ad is being blocked.
|
//To display a notification to the user, that an ad is being blocked.
|
||||||
var playerRootDiv = document.querySelector('.video-player');
|
var playerRootDiv = document.querySelector('.video-player');
|
||||||
@ -218,16 +271,29 @@ twitch-videoad.js text/javascript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var workerInstance = reinsertWorkers(newWorker, reinsert);
|
||||||
|
Object.defineProperty(window, 'Worker', {
|
||||||
|
get: function() {
|
||||||
|
return workerInstance;
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
if (isValidWorker(value)) {
|
||||||
|
workerInstance = value;
|
||||||
|
} else {
|
||||||
|
console.log('Attempt to set twitch worker denied');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function getWasmWorkerUrl(twitchBlobUrl) {
|
function getWasmWorkerJs(twitchBlobUrl) {
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('GET', twitchBlobUrl, false);
|
req.open('GET', twitchBlobUrl, false);
|
||||||
req.overrideMimeType("text/javascript");
|
req.overrideMimeType("text/javascript");
|
||||||
req.send();
|
req.send();
|
||||||
return req.responseText.split("'")[1];
|
return req.responseText;
|
||||||
}
|
}
|
||||||
function hookWorkerFetch() {
|
function hookWorkerFetch() {
|
||||||
console.log('hookWorkerFetch');
|
console.log('hookWorkerFetch (vaft)');
|
||||||
var realFetch = fetch;
|
var realFetch = fetch;
|
||||||
fetch = async function(url, options) {
|
fetch = async function(url, options) {
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
@ -875,19 +941,14 @@ twitch-videoad.js text/javascript
|
|||||||
}
|
}
|
||||||
}catch{}
|
}catch{}
|
||||||
}
|
}
|
||||||
if (isWorkerDoubleHooked(null, 'twitch')) {
|
declareOptions(window);
|
||||||
console.log('Twitch Worker is already hooked. Skipping (vaft)');
|
hookWindowWorker();
|
||||||
|
hookFetch();
|
||||||
|
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
||||||
|
onContentLoaded();
|
||||||
} else {
|
} else {
|
||||||
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
declareOptions(window);
|
|
||||||
hookWindowWorker();
|
|
||||||
hookFetch();
|
|
||||||
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
|
||||||
onContentLoaded();
|
onContentLoaded();
|
||||||
} else {
|
});
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
|
||||||
onContentLoaded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name TwitchAdSolutions (vaft)
|
// @name TwitchAdSolutions (vaft)
|
||||||
// @namespace https://github.com/pixeltris/TwitchAdSolutions
|
// @namespace https://github.com/pixeltris/TwitchAdSolutions
|
||||||
// @version 14.0.0
|
// @version 15.0.0
|
||||||
// @description Multiple solutions for blocking Twitch ads (vaft)
|
// @description Multiple solutions for blocking Twitch ads (vaft)
|
||||||
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
|
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
|
||||||
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
|
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
|
||||||
@ -13,6 +13,13 @@
|
|||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var ourTwitchAdSolutionsVersion = 1;// 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
|
||||||
|
if (window.twitchAdSolutionsVersion && window.twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion) {
|
||||||
|
console.log("skipping vaft as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window.twitchAdSolutionsVersion);
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
function declareOptions(scope) {
|
function declareOptions(scope) {
|
||||||
scope.AdSignifier = 'stitched';
|
scope.AdSignifier = 'stitched';
|
||||||
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
|
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
|
||||||
@ -37,31 +44,79 @@
|
|||||||
var adBlockDiv = null;
|
var adBlockDiv = null;
|
||||||
var OriginalVideoPlayerQuality = null;
|
var OriginalVideoPlayerQuality = null;
|
||||||
var IsPlayerAutoQuality = null;
|
var IsPlayerAutoQuality = null;
|
||||||
const oldWorker = window.Worker;
|
var workerStringConflicts = [
|
||||||
function isWorkerDoubleHooked(ourWorker, identifier) {
|
'twitch',
|
||||||
var ourWorkerString = ourWorker ? ourWorker.toString() : null;
|
'isVariantA'// TwitchNoSub
|
||||||
var proto = window.Worker;
|
];
|
||||||
while (proto)
|
var workerStringAllow = [];
|
||||||
{
|
//
|
||||||
|
// TwitchNoSub (userscript) conflicts in this scenario:
|
||||||
|
// - TwitchAdSolutions : TwitchNoSub : window.Worker
|
||||||
|
//
|
||||||
|
// But it's fine in this scenario:
|
||||||
|
// - TwitchNoSub : TwitchAdSolutions : window.Worker
|
||||||
|
//
|
||||||
|
// This is because their script ignores the incoming blob (our script) and replaces it with their own importScripts call
|
||||||
|
// To fix this we scoop out TwitchNoSub and re-insert it so that it inherits from our worker
|
||||||
|
var workerStringReinsert = [
|
||||||
|
'isVariantA'// TwitchNoSub
|
||||||
|
];
|
||||||
|
function getCleanWorker(worker) {
|
||||||
|
var root = null;
|
||||||
|
var parent = null;
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
var workerString = proto.toString();
|
var workerString = proto.toString();
|
||||||
if (workerString.includes(identifier) && workerString !== ourWorkerString) {
|
if (workerStringConflicts.some((x) => workerString.includes(x)) && !workerStringAllow.some((x) => workerString.includes(x))) {
|
||||||
return true;
|
if (parent !== null) {
|
||||||
|
Object.setPrototypeOf(parent, Object.getPrototypeOf(proto));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (root === null) {
|
||||||
|
root = proto;
|
||||||
|
}
|
||||||
|
parent = proto;
|
||||||
}
|
}
|
||||||
proto = Object.getPrototypeOf(proto);
|
proto = Object.getPrototypeOf(proto);
|
||||||
}
|
}
|
||||||
return false;
|
return root;
|
||||||
|
}
|
||||||
|
function getWorkersForReinsert(worker) {
|
||||||
|
var result = [];
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
|
var workerString = proto.toString();
|
||||||
|
if (workerStringReinsert.some((x) => workerString.includes(x))) {
|
||||||
|
result.push(proto);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
function reinsertWorkers(worker, reinsert) {
|
||||||
|
var parent = worker;
|
||||||
|
for (var i = 0; i < reinsert.length; i++) {
|
||||||
|
Object.setPrototypeOf(reinsert[i], parent);
|
||||||
|
parent = reinsert[i];
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
function isValidWorker(worker) {
|
||||||
|
var workerString = worker.toString();
|
||||||
|
return !workerStringConflicts.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringAllow.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringReinsert.some((x) => workerString.includes(x));
|
||||||
|
|
||||||
}
|
}
|
||||||
function hookWindowWorker() {
|
function hookWindowWorker() {
|
||||||
var newWorker = window.Worker = class Worker extends oldWorker {
|
var reinsert = getWorkersForReinsert(window.Worker);
|
||||||
|
var newWorker = class Worker extends getCleanWorker(window.Worker) {
|
||||||
constructor(twitchBlobUrl, options) {
|
constructor(twitchBlobUrl, options) {
|
||||||
var isTwitchWorker = false;
|
var isTwitchWorker = false;
|
||||||
try {
|
try {
|
||||||
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
||||||
} catch {}
|
} catch {}
|
||||||
if (isWorkerDoubleHooked(newWorker, 'twitch')) {
|
|
||||||
console.log('Multiple twitch adblockers installed. Skipping Worker hook (vaft)');
|
|
||||||
isTwitchWorker = false;
|
|
||||||
}
|
|
||||||
if (!isTwitchWorker) {
|
if (!isTwitchWorker) {
|
||||||
super(twitchBlobUrl, options);
|
super(twitchBlobUrl, options);
|
||||||
return;
|
return;
|
||||||
@ -78,34 +133,32 @@
|
|||||||
${adRecordgqlPacket.toString()}
|
${adRecordgqlPacket.toString()}
|
||||||
${tryNotifyTwitch.toString()}
|
${tryNotifyTwitch.toString()}
|
||||||
${parseAttributes.toString()}
|
${parseAttributes.toString()}
|
||||||
${getWasmWorkerUrl.toString()}
|
${getWasmWorkerJs.toString()}
|
||||||
var workerUrl = getWasmWorkerUrl('${twitchBlobUrl.replaceAll("'", "%27")}');
|
var workerString = getWasmWorkerJs('${twitchBlobUrl.replaceAll("'", "%27")}');
|
||||||
if (workerUrl && workerUrl.includes('assets.twitch.tv/assets/amazon-ivs-wasmworker')) {
|
declareOptions(self);
|
||||||
declareOptions(self);
|
self.addEventListener('message', function(e) {
|
||||||
self.addEventListener('message', function(e) {
|
if (e.data.key == 'UpdateIsSquadStream') {
|
||||||
if (e.data.key == 'UpdateIsSquadStream') {
|
IsSquadStream = e.data.value;
|
||||||
IsSquadStream = e.data.value;
|
} else if (e.data.key == 'UpdateClientVersion') {
|
||||||
} else if (e.data.key == 'UpdateClientVersion') {
|
ClientVersion = e.data.value;
|
||||||
ClientVersion = e.data.value;
|
} else if (e.data.key == 'UpdateClientSession') {
|
||||||
} else if (e.data.key == 'UpdateClientSession') {
|
ClientSession = e.data.value;
|
||||||
ClientSession = e.data.value;
|
} else if (e.data.key == 'UpdateClientId') {
|
||||||
} else if (e.data.key == 'UpdateClientId') {
|
ClientID = e.data.value;
|
||||||
ClientID = e.data.value;
|
} else if (e.data.key == 'UpdateDeviceId') {
|
||||||
} else if (e.data.key == 'UpdateDeviceId') {
|
GQLDeviceID = e.data.value;
|
||||||
GQLDeviceID = e.data.value;
|
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
||||||
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
ClientIntegrityHeader = e.data.value;
|
||||||
ClientIntegrityHeader = e.data.value;
|
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
||||||
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
AuthorizationHeader = e.data.value;
|
||||||
AuthorizationHeader = e.data.value;
|
}
|
||||||
}
|
});
|
||||||
});
|
hookWorkerFetch();
|
||||||
hookWorkerFetch();
|
eval(workerString);
|
||||||
importScripts(workerUrl);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
||||||
twitchWorkers.push(this);
|
twitchWorkers.push(this);
|
||||||
this.onmessage = function(e) {
|
this.addEventListener('message', (e) => {
|
||||||
if (e.data.key == 'ShowAdBlockBanner') {
|
if (e.data.key == 'ShowAdBlockBanner') {
|
||||||
if (adBlockDiv == null) {
|
if (adBlockDiv == null) {
|
||||||
adBlockDiv = getAdBlockDiv();
|
adBlockDiv = getAdBlockDiv();
|
||||||
@ -210,7 +263,7 @@
|
|||||||
IsPlayerAutoQuality = null;
|
IsPlayerAutoQuality = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
function getAdBlockDiv() {
|
function getAdBlockDiv() {
|
||||||
//To display a notification to the user, that an ad is being blocked.
|
//To display a notification to the user, that an ad is being blocked.
|
||||||
var playerRootDiv = document.querySelector('.video-player');
|
var playerRootDiv = document.querySelector('.video-player');
|
||||||
@ -230,16 +283,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var workerInstance = reinsertWorkers(newWorker, reinsert);
|
||||||
|
Object.defineProperty(window, 'Worker', {
|
||||||
|
get: function() {
|
||||||
|
return workerInstance;
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
if (isValidWorker(value)) {
|
||||||
|
workerInstance = value;
|
||||||
|
} else {
|
||||||
|
console.log('Attempt to set twitch worker denied');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function getWasmWorkerUrl(twitchBlobUrl) {
|
function getWasmWorkerJs(twitchBlobUrl) {
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('GET', twitchBlobUrl, false);
|
req.open('GET', twitchBlobUrl, false);
|
||||||
req.overrideMimeType("text/javascript");
|
req.overrideMimeType("text/javascript");
|
||||||
req.send();
|
req.send();
|
||||||
return req.responseText.split("'")[1];
|
return req.responseText;
|
||||||
}
|
}
|
||||||
function hookWorkerFetch() {
|
function hookWorkerFetch() {
|
||||||
console.log('hookWorkerFetch');
|
console.log('hookWorkerFetch (vaft)');
|
||||||
var realFetch = fetch;
|
var realFetch = fetch;
|
||||||
fetch = async function(url, options) {
|
fetch = async function(url, options) {
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
@ -887,19 +953,14 @@
|
|||||||
}
|
}
|
||||||
}catch{}
|
}catch{}
|
||||||
}
|
}
|
||||||
if (isWorkerDoubleHooked(null, 'twitch')) {
|
declareOptions(window);
|
||||||
console.log('Twitch Worker is already hooked. Skipping (vaft)');
|
hookWindowWorker();
|
||||||
|
hookFetch();
|
||||||
|
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
||||||
|
onContentLoaded();
|
||||||
} else {
|
} else {
|
||||||
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
declareOptions(window);
|
|
||||||
hookWindowWorker();
|
|
||||||
hookFetch();
|
|
||||||
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
|
||||||
onContentLoaded();
|
onContentLoaded();
|
||||||
} else {
|
});
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
|
||||||
onContentLoaded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
twitch-videoad.js text/javascript
|
twitch-videoad.js text/javascript
|
||||||
(function() {
|
(function() {
|
||||||
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
|
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
|
||||||
|
var ourTwitchAdSolutionsVersion = 1;// 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
|
||||||
|
if (window.twitchAdSolutionsVersion && window.twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion) {
|
||||||
|
console.log("skipping video-swap-new as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window.twitchAdSolutionsVersion);
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
function declareOptions(scope) {
|
function declareOptions(scope) {
|
||||||
// Options / globals
|
// Options / globals
|
||||||
scope.OPT_MODE_STRIP_AD_SEGMENTS = true;
|
scope.OPT_MODE_STRIP_AD_SEGMENTS = true;
|
||||||
@ -24,31 +31,79 @@ twitch-videoad.js text/javascript
|
|||||||
scope.AuthorizationHeader = null;
|
scope.AuthorizationHeader = null;
|
||||||
}
|
}
|
||||||
var twitchWorkers = [];
|
var twitchWorkers = [];
|
||||||
const oldWorker = window.Worker;
|
var workerStringConflicts = [
|
||||||
function isWorkerDoubleHooked(ourWorker, identifier) {
|
'twitch',
|
||||||
var ourWorkerString = ourWorker ? ourWorker.toString() : null;
|
'isVariantA'// TwitchNoSub
|
||||||
var proto = window.Worker;
|
];
|
||||||
while (proto)
|
var workerStringAllow = [];
|
||||||
{
|
//
|
||||||
|
// TwitchNoSub (userscript) conflicts in this scenario:
|
||||||
|
// - TwitchAdSolutions : TwitchNoSub : window.Worker
|
||||||
|
//
|
||||||
|
// But it's fine in this scenario:
|
||||||
|
// - TwitchNoSub : TwitchAdSolutions : window.Worker
|
||||||
|
//
|
||||||
|
// This is because their script ignores the incoming blob (our script) and replaces it with their own importScripts call
|
||||||
|
// To fix this we scoop out TwitchNoSub and re-insert it so that it inherits from our worker
|
||||||
|
var workerStringReinsert = [
|
||||||
|
'isVariantA'// TwitchNoSub
|
||||||
|
];
|
||||||
|
function getCleanWorker(worker) {
|
||||||
|
var root = null;
|
||||||
|
var parent = null;
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
var workerString = proto.toString();
|
var workerString = proto.toString();
|
||||||
if (workerString.includes(identifier) && workerString !== ourWorkerString) {
|
if (workerStringConflicts.some((x) => workerString.includes(x)) && !workerStringAllow.some((x) => workerString.includes(x))) {
|
||||||
return true;
|
if (parent !== null) {
|
||||||
|
Object.setPrototypeOf(parent, Object.getPrototypeOf(proto));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (root === null) {
|
||||||
|
root = proto;
|
||||||
|
}
|
||||||
|
parent = proto;
|
||||||
}
|
}
|
||||||
proto = Object.getPrototypeOf(proto);
|
proto = Object.getPrototypeOf(proto);
|
||||||
}
|
}
|
||||||
return false;
|
return root;
|
||||||
|
}
|
||||||
|
function getWorkersForReinsert(worker) {
|
||||||
|
var result = [];
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
|
var workerString = proto.toString();
|
||||||
|
if (workerStringReinsert.some((x) => workerString.includes(x))) {
|
||||||
|
result.push(proto);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
function reinsertWorkers(worker, reinsert) {
|
||||||
|
var parent = worker;
|
||||||
|
for (var i = 0; i < reinsert.length; i++) {
|
||||||
|
Object.setPrototypeOf(reinsert[i], parent);
|
||||||
|
parent = reinsert[i];
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
function isValidWorker(worker) {
|
||||||
|
var workerString = worker.toString();
|
||||||
|
return !workerStringConflicts.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringAllow.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringReinsert.some((x) => workerString.includes(x));
|
||||||
|
|
||||||
}
|
}
|
||||||
function hookWindowWorker() {
|
function hookWindowWorker() {
|
||||||
var newWorker = window.Worker = class Worker extends oldWorker {
|
var reinsert = getWorkersForReinsert(window.Worker);
|
||||||
|
var newWorker = class Worker extends getCleanWorker(window.Worker) {
|
||||||
constructor(twitchBlobUrl, options) {
|
constructor(twitchBlobUrl, options) {
|
||||||
var isTwitchWorker = false;
|
var isTwitchWorker = false;
|
||||||
try {
|
try {
|
||||||
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
||||||
} catch {}
|
} catch {}
|
||||||
if (isWorkerDoubleHooked(newWorker, 'twitch')) {
|
|
||||||
console.log('Multiple twitch adblockers installed. Skipping Worker hook (video-swap-new)');
|
|
||||||
isTwitchWorker = false;
|
|
||||||
}
|
|
||||||
if (!isTwitchWorker) {
|
if (!isTwitchWorker) {
|
||||||
super(twitchBlobUrl, options);
|
super(twitchBlobUrl, options);
|
||||||
return;
|
return;
|
||||||
@ -63,26 +118,24 @@ twitch-videoad.js text/javascript
|
|||||||
${tryNotifyAdsWatchedM3U8.toString()}
|
${tryNotifyAdsWatchedM3U8.toString()}
|
||||||
${parseAttributes.toString()}
|
${parseAttributes.toString()}
|
||||||
${onFoundAd.toString()}
|
${onFoundAd.toString()}
|
||||||
${getWasmWorkerUrl.toString()}
|
${getWasmWorkerJs.toString()}
|
||||||
var workerUrl = getWasmWorkerUrl('${twitchBlobUrl.replaceAll("'", "%27")}');
|
var workerString = getWasmWorkerJs('${twitchBlobUrl.replaceAll("'", "%27")}');
|
||||||
if (workerUrl && workerUrl.includes('assets.twitch.tv/assets/amazon-ivs-wasmworker')) {
|
declareOptions(self);
|
||||||
declareOptions(self);
|
self.addEventListener('message', function(e) {
|
||||||
self.addEventListener('message', function(e) {
|
if (e.data.key == 'UboUpdateDeviceId') {
|
||||||
if (e.data.key == 'UboUpdateDeviceId') {
|
gql_device_id = e.data.value;
|
||||||
gql_device_id = e.data.value;
|
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
||||||
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
ClientIntegrityHeader = e.data.value;
|
||||||
ClientIntegrityHeader = e.data.value;
|
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
||||||
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
AuthorizationHeader = e.data.value;
|
||||||
AuthorizationHeader = e.data.value;
|
}
|
||||||
}
|
});
|
||||||
});
|
hookWorkerFetch();
|
||||||
hookWorkerFetch();
|
eval(workerString);
|
||||||
importScripts(workerUrl);
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
||||||
twitchWorkers.push(this);
|
twitchWorkers.push(this);
|
||||||
this.onmessage = function(e) {
|
this.addEventListener('message', (e) => {
|
||||||
// NOTE: Removed adDiv caching as '.video-player' can change between streams?
|
// NOTE: Removed adDiv caching as '.video-player' can change between streams?
|
||||||
if (e.data.key == 'UboShowAdBanner') {
|
if (e.data.key == 'UboShowAdBanner') {
|
||||||
var adDiv = getAdDiv();
|
var adDiv = getAdDiv();
|
||||||
@ -106,7 +159,7 @@ twitch-videoad.js text/javascript
|
|||||||
} else if (e.data.key == 'UboSeekPlayer') {
|
} else if (e.data.key == 'UboSeekPlayer') {
|
||||||
reloadTwitchPlayer(true);
|
reloadTwitchPlayer(true);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
function getAdDiv() {
|
function getAdDiv() {
|
||||||
var playerRootDiv = document.querySelector('.video-player');
|
var playerRootDiv = document.querySelector('.video-player');
|
||||||
var adDiv = null;
|
var adDiv = null;
|
||||||
@ -125,13 +178,26 @@ twitch-videoad.js text/javascript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var workerInstance = reinsertWorkers(newWorker, reinsert);
|
||||||
|
Object.defineProperty(window, 'Worker', {
|
||||||
|
get: function() {
|
||||||
|
return workerInstance;
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
if (isValidWorker(value)) {
|
||||||
|
workerInstance = value;
|
||||||
|
} else {
|
||||||
|
console.log('Attempt to set twitch worker denied');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function getWasmWorkerUrl(twitchBlobUrl) {
|
function getWasmWorkerJs(twitchBlobUrl) {
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('GET', twitchBlobUrl, false);
|
req.open('GET', twitchBlobUrl, false);
|
||||||
req.overrideMimeType("text/javascript");
|
req.overrideMimeType("text/javascript");
|
||||||
req.send();
|
req.send();
|
||||||
return req.responseText.split("'")[1];
|
return req.responseText;
|
||||||
}
|
}
|
||||||
function onFoundAd(streamInfo, textStr, reloadPlayer) {
|
function onFoundAd(streamInfo, textStr, reloadPlayer) {
|
||||||
console.log('Found ads, switch to backup');
|
console.log('Found ads, switch to backup');
|
||||||
@ -203,7 +269,7 @@ twitch-videoad.js text/javascript
|
|||||||
return textStr;
|
return textStr;
|
||||||
}
|
}
|
||||||
function hookWorkerFetch() {
|
function hookWorkerFetch() {
|
||||||
console.log('hookWorkerFetch');
|
console.log('hookWorkerFetch (video-swap-new)');
|
||||||
var realFetch = fetch;
|
var realFetch = fetch;
|
||||||
fetch = async function(url, options) {
|
fetch = async function(url, options) {
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
@ -666,19 +732,15 @@ twitch-videoad.js text/javascript
|
|||||||
return realGetItem.apply(this, arguments);
|
return realGetItem.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (isWorkerDoubleHooked(null, 'twitch')) {
|
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
||||||
console.log('Twitch Worker is already hooked. Skipping (video-swap-new)');
|
declareOptions(window);
|
||||||
|
hookWindowWorker();
|
||||||
|
hookFetch();
|
||||||
|
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
||||||
|
onContentLoaded();
|
||||||
} else {
|
} else {
|
||||||
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
declareOptions(window);
|
|
||||||
hookWindowWorker();
|
|
||||||
hookFetch();
|
|
||||||
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
|
||||||
onContentLoaded();
|
onContentLoaded();
|
||||||
} else {
|
});
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
|
||||||
onContentLoaded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name TwitchAdSolutions (video-swap-new)
|
// @name TwitchAdSolutions (video-swap-new)
|
||||||
// @namespace https://github.com/pixeltris/TwitchAdSolutions
|
// @namespace https://github.com/pixeltris/TwitchAdSolutions
|
||||||
// @version 1.32
|
// @version 1.33
|
||||||
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
|
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
|
||||||
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
|
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
|
||||||
// @description Multiple solutions for blocking Twitch ads (video-swap-new)
|
// @description Multiple solutions for blocking Twitch ads (video-swap-new)
|
||||||
@ -13,6 +13,13 @@
|
|||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var ourTwitchAdSolutionsVersion = 1;// 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
|
||||||
|
if (window.twitchAdSolutionsVersion && window.twitchAdSolutionsVersion >= ourTwitchAdSolutionsVersion) {
|
||||||
|
console.log("skipping video-swap-new as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window.twitchAdSolutionsVersion);
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
|
||||||
function declareOptions(scope) {
|
function declareOptions(scope) {
|
||||||
// Options / globals
|
// Options / globals
|
||||||
scope.OPT_MODE_STRIP_AD_SEGMENTS = true;
|
scope.OPT_MODE_STRIP_AD_SEGMENTS = true;
|
||||||
@ -36,31 +43,79 @@
|
|||||||
scope.AuthorizationHeader = null;
|
scope.AuthorizationHeader = null;
|
||||||
}
|
}
|
||||||
var twitchWorkers = [];
|
var twitchWorkers = [];
|
||||||
const oldWorker = window.Worker;
|
var workerStringConflicts = [
|
||||||
function isWorkerDoubleHooked(ourWorker, identifier) {
|
'twitch',
|
||||||
var ourWorkerString = ourWorker ? ourWorker.toString() : null;
|
'isVariantA'// TwitchNoSub
|
||||||
var proto = window.Worker;
|
];
|
||||||
while (proto)
|
var workerStringAllow = [];
|
||||||
{
|
//
|
||||||
|
// TwitchNoSub (userscript) conflicts in this scenario:
|
||||||
|
// - TwitchAdSolutions : TwitchNoSub : window.Worker
|
||||||
|
//
|
||||||
|
// But it's fine in this scenario:
|
||||||
|
// - TwitchNoSub : TwitchAdSolutions : window.Worker
|
||||||
|
//
|
||||||
|
// This is because their script ignores the incoming blob (our script) and replaces it with their own importScripts call
|
||||||
|
// To fix this we scoop out TwitchNoSub and re-insert it so that it inherits from our worker
|
||||||
|
var workerStringReinsert = [
|
||||||
|
'isVariantA'// TwitchNoSub
|
||||||
|
];
|
||||||
|
function getCleanWorker(worker) {
|
||||||
|
var root = null;
|
||||||
|
var parent = null;
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
var workerString = proto.toString();
|
var workerString = proto.toString();
|
||||||
if (workerString.includes(identifier) && workerString !== ourWorkerString) {
|
if (workerStringConflicts.some((x) => workerString.includes(x)) && !workerStringAllow.some((x) => workerString.includes(x))) {
|
||||||
return true;
|
if (parent !== null) {
|
||||||
|
Object.setPrototypeOf(parent, Object.getPrototypeOf(proto));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (root === null) {
|
||||||
|
root = proto;
|
||||||
|
}
|
||||||
|
parent = proto;
|
||||||
}
|
}
|
||||||
proto = Object.getPrototypeOf(proto);
|
proto = Object.getPrototypeOf(proto);
|
||||||
}
|
}
|
||||||
return false;
|
return root;
|
||||||
|
}
|
||||||
|
function getWorkersForReinsert(worker) {
|
||||||
|
var result = [];
|
||||||
|
var proto = worker;
|
||||||
|
while (proto) {
|
||||||
|
var workerString = proto.toString();
|
||||||
|
if (workerStringReinsert.some((x) => workerString.includes(x))) {
|
||||||
|
result.push(proto);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
function reinsertWorkers(worker, reinsert) {
|
||||||
|
var parent = worker;
|
||||||
|
for (var i = 0; i < reinsert.length; i++) {
|
||||||
|
Object.setPrototypeOf(reinsert[i], parent);
|
||||||
|
parent = reinsert[i];
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
function isValidWorker(worker) {
|
||||||
|
var workerString = worker.toString();
|
||||||
|
return !workerStringConflicts.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringAllow.some((x) => workerString.includes(x))
|
||||||
|
|| workerStringReinsert.some((x) => workerString.includes(x));
|
||||||
|
|
||||||
}
|
}
|
||||||
function hookWindowWorker() {
|
function hookWindowWorker() {
|
||||||
var newWorker = window.Worker = class Worker extends oldWorker {
|
var reinsert = getWorkersForReinsert(window.Worker);
|
||||||
|
var newWorker = class Worker extends getCleanWorker(window.Worker) {
|
||||||
constructor(twitchBlobUrl, options) {
|
constructor(twitchBlobUrl, options) {
|
||||||
var isTwitchWorker = false;
|
var isTwitchWorker = false;
|
||||||
try {
|
try {
|
||||||
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
isTwitchWorker = new URL(twitchBlobUrl).origin.endsWith('.twitch.tv');
|
||||||
} catch {}
|
} catch {}
|
||||||
if (isWorkerDoubleHooked(newWorker, 'twitch')) {
|
|
||||||
console.log('Multiple twitch adblockers installed. Skipping Worker hook (video-swap-new)');
|
|
||||||
isTwitchWorker = false;
|
|
||||||
}
|
|
||||||
if (!isTwitchWorker) {
|
if (!isTwitchWorker) {
|
||||||
super(twitchBlobUrl, options);
|
super(twitchBlobUrl, options);
|
||||||
return;
|
return;
|
||||||
@ -75,26 +130,24 @@
|
|||||||
${tryNotifyAdsWatchedM3U8.toString()}
|
${tryNotifyAdsWatchedM3U8.toString()}
|
||||||
${parseAttributes.toString()}
|
${parseAttributes.toString()}
|
||||||
${onFoundAd.toString()}
|
${onFoundAd.toString()}
|
||||||
${getWasmWorkerUrl.toString()}
|
${getWasmWorkerJs.toString()}
|
||||||
var workerUrl = getWasmWorkerUrl('${twitchBlobUrl.replaceAll("'", "%27")}');
|
var workerString = getWasmWorkerJs('${twitchBlobUrl.replaceAll("'", "%27")}');
|
||||||
if (workerUrl && workerUrl.includes('assets.twitch.tv/assets/amazon-ivs-wasmworker')) {
|
declareOptions(self);
|
||||||
declareOptions(self);
|
self.addEventListener('message', function(e) {
|
||||||
self.addEventListener('message', function(e) {
|
if (e.data.key == 'UboUpdateDeviceId') {
|
||||||
if (e.data.key == 'UboUpdateDeviceId') {
|
gql_device_id = e.data.value;
|
||||||
gql_device_id = e.data.value;
|
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
||||||
} else if (e.data.key == 'UpdateClientIntegrityHeader') {
|
ClientIntegrityHeader = e.data.value;
|
||||||
ClientIntegrityHeader = e.data.value;
|
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
||||||
} else if (e.data.key == 'UpdateAuthorizationHeader') {
|
AuthorizationHeader = e.data.value;
|
||||||
AuthorizationHeader = e.data.value;
|
}
|
||||||
}
|
});
|
||||||
});
|
hookWorkerFetch();
|
||||||
hookWorkerFetch();
|
eval(workerString);
|
||||||
importScripts(workerUrl);
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
super(URL.createObjectURL(new Blob([newBlobStr])), options);
|
||||||
twitchWorkers.push(this);
|
twitchWorkers.push(this);
|
||||||
this.onmessage = function(e) {
|
this.addEventListener('message', (e) => {
|
||||||
// NOTE: Removed adDiv caching as '.video-player' can change between streams?
|
// NOTE: Removed adDiv caching as '.video-player' can change between streams?
|
||||||
if (e.data.key == 'UboShowAdBanner') {
|
if (e.data.key == 'UboShowAdBanner') {
|
||||||
var adDiv = getAdDiv();
|
var adDiv = getAdDiv();
|
||||||
@ -118,7 +171,7 @@
|
|||||||
} else if (e.data.key == 'UboSeekPlayer') {
|
} else if (e.data.key == 'UboSeekPlayer') {
|
||||||
reloadTwitchPlayer(true);
|
reloadTwitchPlayer(true);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
function getAdDiv() {
|
function getAdDiv() {
|
||||||
var playerRootDiv = document.querySelector('.video-player');
|
var playerRootDiv = document.querySelector('.video-player');
|
||||||
var adDiv = null;
|
var adDiv = null;
|
||||||
@ -137,13 +190,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var workerInstance = reinsertWorkers(newWorker, reinsert);
|
||||||
|
Object.defineProperty(window, 'Worker', {
|
||||||
|
get: function() {
|
||||||
|
return workerInstance;
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
if (isValidWorker(value)) {
|
||||||
|
workerInstance = value;
|
||||||
|
} else {
|
||||||
|
console.log('Attempt to set twitch worker denied');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function getWasmWorkerUrl(twitchBlobUrl) {
|
function getWasmWorkerJs(twitchBlobUrl) {
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('GET', twitchBlobUrl, false);
|
req.open('GET', twitchBlobUrl, false);
|
||||||
req.overrideMimeType("text/javascript");
|
req.overrideMimeType("text/javascript");
|
||||||
req.send();
|
req.send();
|
||||||
return req.responseText.split("'")[1];
|
return req.responseText;
|
||||||
}
|
}
|
||||||
function onFoundAd(streamInfo, textStr, reloadPlayer) {
|
function onFoundAd(streamInfo, textStr, reloadPlayer) {
|
||||||
console.log('Found ads, switch to backup');
|
console.log('Found ads, switch to backup');
|
||||||
@ -215,7 +281,7 @@
|
|||||||
return textStr;
|
return textStr;
|
||||||
}
|
}
|
||||||
function hookWorkerFetch() {
|
function hookWorkerFetch() {
|
||||||
console.log('hookWorkerFetch');
|
console.log('hookWorkerFetch (video-swap-new)');
|
||||||
var realFetch = fetch;
|
var realFetch = fetch;
|
||||||
fetch = async function(url, options) {
|
fetch = async function(url, options) {
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
@ -678,19 +744,15 @@
|
|||||||
return realGetItem.apply(this, arguments);
|
return realGetItem.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (isWorkerDoubleHooked(null, 'twitch')) {
|
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
||||||
console.log('Twitch Worker is already hooked. Skipping (video-swap-new)');
|
declareOptions(window);
|
||||||
|
hookWindowWorker();
|
||||||
|
hookFetch();
|
||||||
|
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
||||||
|
onContentLoaded();
|
||||||
} else {
|
} else {
|
||||||
window.reloadTwitchPlayer = reloadTwitchPlayer;
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
declareOptions(window);
|
|
||||||
hookWindowWorker();
|
|
||||||
hookFetch();
|
|
||||||
if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
|
|
||||||
onContentLoaded();
|
onContentLoaded();
|
||||||
} else {
|
});
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
|
||||||
onContentLoaded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
Loading…
x
Reference in New Issue
Block a user