Fix GQL requests failing under chrome #363

- Ref https://github.com/AdguardTeam/AdGuardExtra/issues/599
This commit is contained in:
pixeltris
2025-06-22 14:25:07 +01:00
parent 492c1db4cf
commit e23eae61dd
4 changed files with 324 additions and 80 deletions
+83 -19
View File
@@ -1,7 +1,7 @@
// ==UserScript==
// @name TwitchAdSolutions (video-swap-new)
// @namespace https://github.com/pixeltris/TwitchAdSolutions
// @version 1.35
// @version 1.36
// @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
// @description Multiple solutions for blocking Twitch ads (video-swap-new)
@@ -13,7 +13,7 @@
// ==/UserScript==
(function() {
'use strict';
var ourTwitchAdSolutionsVersion = 2;// 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
var ourTwitchAdSolutionsVersion = 3;// 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;
@@ -113,6 +113,7 @@
return;
}
var newBlobStr = `
const pendingFetchRequests = new Map();
${processM3U8.toString()}
${hookWorkerFetch.toString()}
${declareOptions.toString()}
@@ -132,6 +133,23 @@
ClientIntegrityHeader = e.data.value;
} else if (e.data.key == 'UpdateAuthorizationHeader') {
AuthorizationHeader = e.data.value;
} else if (e.data.key == 'FetchResponse') {
const responseData = e.data.value;
if (pendingFetchRequests.has(responseData.id)) {
const { resolve, reject } = pendingFetchRequests.get(responseData.id);
pendingFetchRequests.delete(responseData.id);
if (responseData.error) {
reject(new Error(responseData.error));
} else {
// Create a Response object from the response data
const response = new Response(responseData.body, {
status: responseData.status,
statusText: responseData.statusText,
headers: responseData.headers
});
resolve(response);
}
}
}
});
hookWorkerFetch();
@@ -164,6 +182,16 @@
reloadTwitchPlayer(true);
}
});
this.addEventListener('message', async event => {
if (event.data.key == 'FetchRequest') {
const fetchRequest = event.data.value;
const responseData = await handleWorkerFetchRequest(fetchRequest);
this.postMessage({
key: 'FetchResponse',
value: responseData
});
}
});
function getAdDiv() {
var playerRootDiv = document.querySelector('.video-player');
var adDiv = null;
@@ -329,7 +357,7 @@
for (var i = 0; i < 2; i++) {
var encodingsUrl = url;
if (i == 1) {
var accessTokenResponse = await getAccessToken(channelName, OPT_BACKUP_PLAYER_TYPE, OPT_BACKUP_PLATFORM, realFetch);
var accessTokenResponse = await getAccessToken(channelName, OPT_BACKUP_PLAYER_TYPE, OPT_BACKUP_PLATFORM);
if (accessTokenResponse != null && accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + channelName + '.m3u8' + (new URL(url)).search);
@@ -428,7 +456,7 @@
},
}];
}
function getAccessToken(channelName, playerType, platform, realFetch) {
function getAccessToken(channelName, playerType, platform) {
if (!platform) {
platform = 'web';
}
@@ -445,23 +473,40 @@
'playerType': playerType
}
};
return gqlRequest(body, realFetch);
return gqlRequest(body);
}
function gqlRequest(body, realFetch) {
if (ClientIntegrityHeader == null) {
//console.warn('ClientIntegrityHeader is null');
//throw 'ClientIntegrityHeader is null';
}
var fetchFunc = realFetch ? realFetch : fetch;
return fetchFunc('https://gql.twitch.tv/gql', {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Client-Id': CLIENT_ID,
'Client-Integrity': ClientIntegrityHeader,
'X-Device-Id': gql_device_id,
'Authorization': AuthorizationHeader
function gqlRequest(body) {
if (!gql_device_id) {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i += 1) {
gql_device_id += chars.charAt(Math.floor(Math.random() * chars.length));
}
}
var headers = {
'Client-Id': CLIENT_ID,
'Client-Integrity': ClientIntegrityHeader,
'X-Device-Id': gql_device_id,
'Authorization': AuthorizationHeader
};
return new Promise((resolve, reject) => {
const requestId = Math.random().toString(36).substring(2, 15);
const fetchRequest = {
id: requestId,
url: 'https://gql.twitch.tv/gql',
options: {
method: 'POST',
body: JSON.stringify(body),
headers
}
};
pendingFetchRequests.set(requestId, {
resolve,
reject
});
postMessage({
key: 'FetchRequest',
value: fetchRequest
});
});
}
function parseAttributes(str) {
@@ -540,6 +585,25 @@
worker.postMessage({key: key, value: value});
});
}
async function handleWorkerFetchRequest(fetchRequest) {
try {
const response = await window.fetch(fetchRequest.url, fetchRequest.options);
const responseBody = await response.text();
const responseObject = {
id: fetchRequest.id,
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries(response.headers.entries()),
body: responseBody
};
return responseObject;
} catch (error) {
return {
id: fetchRequest.id,
error: error.message
};
}
}
function hookFetch() {
var realFetch = window.fetch;
window.fetch = function(url, init, ...args) {