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
+79 -21
View File
@@ -1,7 +1,7 @@
twitch-videoad.js text/javascript
(function() {
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
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 vaft as there's another script active. ourVersion:" + ourTwitchAdSolutionsVersion + " activeVersion:" + window.twitchAdSolutionsVersion);
window.twitchAdSolutionsVersion = ourTwitchAdSolutionsVersion;
@@ -102,6 +102,7 @@ twitch-videoad.js text/javascript
return;
}
var newBlobStr = `
const pendingFetchRequests = new Map();
${getStreamUrlForResolution.toString()}
${getStreamForResolution.toString()}
${stripUnusedParams.toString()}
@@ -131,6 +132,23 @@ twitch-videoad.js text/javascript
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();
@@ -244,6 +262,16 @@ twitch-videoad.js text/javascript
}
}
});
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 getAdBlockDiv() {
//To display a notification to the user, that an ad is being blocked.
var playerRootDiv = document.querySelector('.video-player');
@@ -655,7 +683,7 @@ twitch-videoad.js text/javascript
},
}];
}
function getAccessToken(channelName, playerType, realFetch) {
function getAccessToken(channelName, playerType) {
var body = null;
var templateQuery = 'query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!) { streamPlaybackAccessToken(channelName: $login, params: {platform: "ios", playerBackend: "mediaplayer", playerType: $playerType}) @include(if: $isLive) { value signature __typename } videoPlaybackAccessToken(id: $vodID, params: {platform: "ios", playerBackend: "mediaplayer", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}';
body = {
@@ -669,14 +697,9 @@ twitch-videoad.js text/javascript
'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;
function gqlRequest(body) {
if (!GQLDeviceID) {
var dcharacters = 'abcdefghijklmnopqrstuvwxyz0123456789';
var dcharactersLength = dcharacters.length;
@@ -684,18 +707,34 @@ twitch-videoad.js text/javascript
GQLDeviceID += dcharacters.charAt(Math.floor(Math.random() * dcharactersLength));
}
}
return fetchFunc('https://gql.twitch.tv/gql', {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Client-ID': ClientID,
'Client-Integrity': ClientIntegrityHeader,
'Device-ID': GQLDeviceID,
'X-Device-Id': GQLDeviceID,
'Client-Version': ClientVersion,
'Client-Session-Id': ClientSession,
'Authorization': AuthorizationHeader
}
var headers = {
'Client-ID': ClientID,
'Client-Integrity': ClientIntegrityHeader,
'Device-ID': GQLDeviceID,
'X-Device-Id': GQLDeviceID,
'Client-Version': ClientVersion,
'Client-Session-Id': ClientSession,
'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 doTwitchPlayerTask(isPausePlay, isCheckQuality, isCorrectBuffer, isAutoQuality, setAutoQuality) {
@@ -805,6 +844,25 @@ twitch-videoad.js text/javascript
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) {