From 05c023ff1c5b20e96b698df8503770b59c97f356 Mon Sep 17 00:00:00 2001 From: pixeltris <6952411+pixeltris@users.noreply.github.com> Date: Thu, 1 Jun 2023 08:03:45 +0100 Subject: [PATCH] Fix video-swap-new / vaft (add integrity header) --- vaft/vaft-ublock-origin.js | 21 +++++++-- vaft/vaft.user.js | 23 ++++++++-- .../video-swap-new-ublock-origin.js | 44 ++++++++++++------ video-swap-new/video-swap-new.user.js | 46 +++++++++++++------ 4 files changed, 98 insertions(+), 36 deletions(-) diff --git a/vaft/vaft-ublock-origin.js b/vaft/vaft-ublock-origin.js index 3ac2887..fb59934 100644 --- a/vaft/vaft-ublock-origin.js +++ b/vaft/vaft-ublock-origin.js @@ -1,4 +1,3 @@ -// This code is directly copied from https://github.com/cleanlock/VideoAdBlockForTwitch (only change is whitespace is removed for the ublock origin script - also indented) twitch-videoad.js text/javascript (function() { if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; } @@ -74,6 +73,7 @@ twitch-videoad.js text/javascript scope.DefaultProxyType = null; scope.DefaultForcedQuality = null; scope.DefaultProxyQuality = null; + scope.ClientIntegrity = null; } declareOptions(window); var TwitchAdblockSettings = { @@ -123,6 +123,8 @@ twitch-videoad.js text/javascript ClientID = e.data.value; } else if (e.data.key == 'UpdateDeviceId') { GQLDeviceID = e.data.value; + } else if (e.data.key == 'UpdateClientIntegrity') { + ClientIntegrity = e.data.value; } }); hookWorkerFetch(); @@ -150,9 +152,9 @@ twitch-videoad.js text/javascript } else if (e.data.key == 'ForceChangeQuality') { //This is used to fix the bug where the video would freeze. try { - if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) { + //if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) { return; - } + //} var autoQuality = doTwitchPlayerTask(false, false, false, true, false); var currentQuality = doTwitchPlayerTask(false, true, false, false, false); if (IsPlayerAutoQuality == null) { @@ -656,6 +658,10 @@ twitch-videoad.js text/javascript return gqlRequest(body, realFetch); } function gqlRequest(body, realFetch) { + if (ClientIntegrity == null) { + console.error('ClientIntegrity is null'); + throw 'ClientIntegrity is null'; + } var fetchFunc = realFetch ? realFetch : fetch; if (!GQLDeviceID) { var dcharacters = 'abcdefghijklmnopqrstuvwxyz0123456789'; @@ -669,6 +675,7 @@ twitch-videoad.js text/javascript body: JSON.stringify(body), headers: { 'Client-ID': ClientID, + 'Client-Integrity': ClientIntegrity, 'Device-ID': GQLDeviceID, 'X-Device-Id': GQLDeviceID, 'Client-Version': ClientVersion, @@ -848,6 +855,14 @@ twitch-videoad.js text/javascript }); } } + //Client integrity + if (url.includes('gql') && init && typeof init.headers['Client-Integrity'] === 'string') { + ClientIntegrity = init.headers['Client-Integrity']; + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrity', + value: init.headers['Client-Integrity'] + }); + } //To prevent pause/resume loop for mid-rolls. if (url.includes('gql') && init && typeof init.body === 'string' && init.body.includes('PlaybackAccessToken') && init.body.includes('picture-by-picture')) { init.body = ''; diff --git a/vaft/vaft.user.js b/vaft/vaft.user.js index 0d67493..f376b4c 100644 --- a/vaft/vaft.user.js +++ b/vaft/vaft.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name TwitchAdSolutions (vaft) // @namespace https://github.com/pixeltris/TwitchAdSolutions -// @version 5.5.1 +// @version 5.8.0 // @description Multiple solutions for blocking Twitch ads (vaft) // @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js // @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js @@ -10,7 +10,6 @@ // @run-at document-start // @grant none // ==/UserScript== -// This code is directly copied from https://github.com/cleanlock/VideoAdBlockForTwitch (only change is whitespace is removed for the ublock origin script - also indented) (function() { 'use strict'; //This stops Twitch from pausing the player when in another tab and an ad shows. @@ -85,6 +84,7 @@ scope.DefaultProxyType = null; scope.DefaultForcedQuality = null; scope.DefaultProxyQuality = null; + scope.ClientIntegrity = null; } declareOptions(window); var TwitchAdblockSettings = { @@ -134,6 +134,8 @@ ClientID = e.data.value; } else if (e.data.key == 'UpdateDeviceId') { GQLDeviceID = e.data.value; + } else if (e.data.key == 'UpdateClientIntegrity') { + ClientIntegrity = e.data.value; } }); hookWorkerFetch(); @@ -161,9 +163,9 @@ } else if (e.data.key == 'ForceChangeQuality') { //This is used to fix the bug where the video would freeze. try { - if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) { + //if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) { return; - } + //} var autoQuality = doTwitchPlayerTask(false, false, false, true, false); var currentQuality = doTwitchPlayerTask(false, true, false, false, false); if (IsPlayerAutoQuality == null) { @@ -667,6 +669,10 @@ return gqlRequest(body, realFetch); } function gqlRequest(body, realFetch) { + if (ClientIntegrity == null) { + console.error('ClientIntegrity is null'); + throw 'ClientIntegrity is null'; + } var fetchFunc = realFetch ? realFetch : fetch; if (!GQLDeviceID) { var dcharacters = 'abcdefghijklmnopqrstuvwxyz0123456789'; @@ -680,6 +686,7 @@ body: JSON.stringify(body), headers: { 'Client-ID': ClientID, + 'Client-Integrity': ClientIntegrity, 'Device-ID': GQLDeviceID, 'X-Device-Id': GQLDeviceID, 'Client-Version': ClientVersion, @@ -859,6 +866,14 @@ }); } } + //Client integrity + if (url.includes('gql') && init && typeof init.headers['Client-Integrity'] === 'string') { + ClientIntegrity = init.headers['Client-Integrity']; + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrity', + value: init.headers['Client-Integrity'] + }); + } //To prevent pause/resume loop for mid-rolls. if (url.includes('gql') && init && typeof init.body === 'string' && init.body.includes('PlaybackAccessToken') && init.body.includes('picture-by-picture')) { init.body = ''; diff --git a/video-swap-new/video-swap-new-ublock-origin.js b/video-swap-new/video-swap-new-ublock-origin.js index a4e3f3f..5fc59eb 100644 --- a/video-swap-new/video-swap-new-ublock-origin.js +++ b/video-swap-new/video-swap-new-ublock-origin.js @@ -3,13 +3,13 @@ twitch-videoad.js text/javascript if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; } function declareOptions(scope) { // Options / globals - scope.OPT_ROLLING_DEVICE_ID = true; + scope.OPT_ROLLING_DEVICE_ID = false; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = false; scope.OPT_BACKUP_PLAYER_TYPE = 'embed'; scope.OPT_REGULAR_PLAYER_TYPE = 'site'; - scope.OPT_ACCESS_TOKEN_PLAYER_TYPE = 'site'; + scope.OPT_ACCESS_TOKEN_PLAYER_TYPE = null; scope.AD_SIGNIFIER = 'stitched-ad'; scope.LIVE_SIGNIFIER = ',live'; scope.CLIENT_ID = 'kimne78kx3ncx6brgo4mv6wki5h1ko'; @@ -28,6 +28,7 @@ twitch-videoad.js text/javascript scope.gql_device_id_rolling += charTable[(bs.charCodeAt(i) ^ di) % charTable.length]; } scope.gql_device_id_rolling = '1';//temporary + scope.ClientIntegrity = null; } declareOptions(window); var twitchMainWorker = null; @@ -57,6 +58,8 @@ twitch-videoad.js text/javascript self.addEventListener('message', function(e) { if (e.data.key == 'UboUpdateDeviceId') { gql_device_id = e.data.value; + } else if (e.data.key == 'UpdateClientIntegrity') { + ClientIntegrity = e.data.value; } }); hookWorkerFetch(); @@ -72,23 +75,18 @@ twitch-videoad.js text/javascript adDiv.P.textContent = 'Blocking' + (e.data.isMidroll ? ' midroll' : '') + ' ads...'; //adDiv.style.display = 'block'; } - } - else if (e.data.key == 'UboHideAdBanner') { + } else if (e.data.key == 'UboHideAdBanner') { var adDiv = getAdDiv(); if (adDiv != null) { adDiv.style.display = 'none'; } - } - else if (e.data.key == 'UboChannelNameM3U8Changed') { + } else if (e.data.key == 'UboChannelNameM3U8Changed') { //console.log('M3U8 channel name changed to ' + e.data.value); - } - else if (e.data.key == 'UboReloadPlayer') { + } else if (e.data.key == 'UboReloadPlayer') { reloadTwitchPlayer(); - } - else if (e.data.key == 'UboPauseResumePlayer') { + } else if (e.data.key == 'UboPauseResumePlayer') { reloadTwitchPlayer(false, true); - } - else if (e.data.key == 'UboSeekPlayer') { + } else if (e.data.key == 'UboSeekPlayer') { reloadTwitchPlayer(true); } } @@ -305,12 +303,17 @@ twitch-videoad.js text/javascript return gqlRequest(body, realFetch); } function gqlRequest(body, realFetch) { + if (ClientIntegrity == null) { + console.error('ClientIntegrity is null'); + throw 'ClientIntegrity 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-Id': CLIENT_ID, + 'Client-Integrity': ClientIntegrity, 'X-Device-Id': OPT_ROLLING_DEVICE_ID ? gql_device_id_rolling : gql_device_id } }); @@ -407,7 +410,13 @@ twitch-videoad.js text/javascript if (typeof init.body === 'string' && init.body.includes('PlaybackAccessToken')) { if (OPT_ACCESS_TOKEN_PLAYER_TYPE) { const newBody = JSON.parse(init.body); - newBody.variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + if (Array.isArray(newBody)) { + for (let i = 0; i < newBody.length; i++) { + newBody[i].variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + } + } else { + newBody.variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + } init.body = JSON.stringify(newBody); } if (OPT_ROLLING_DEVICE_ID) { @@ -418,6 +427,13 @@ twitch-videoad.js text/javascript init.headers['Device-ID'] = gql_device_id_rolling; } } + if (typeof init.headers['Client-Integrity'] === 'string') { + ClientIntegrity = init.headers['Client-Integrity']; + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrity', + value: init.headers['Client-Integrity'] + }); + } } } } diff --git a/video-swap-new/video-swap-new.user.js b/video-swap-new/video-swap-new.user.js index 8b6413a..0699257 100644 --- a/video-swap-new/video-swap-new.user.js +++ b/video-swap-new/video-swap-new.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name TwitchAdSolutions (video-swap-new) // @namespace https://github.com/pixeltris/TwitchAdSolutions -// @version 1.16 +// @version 1.17 // @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) @@ -14,13 +14,13 @@ 'use strict'; function declareOptions(scope) { // Options / globals - scope.OPT_ROLLING_DEVICE_ID = true; + scope.OPT_ROLLING_DEVICE_ID = false; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = false; scope.OPT_BACKUP_PLAYER_TYPE = 'embed'; scope.OPT_REGULAR_PLAYER_TYPE = 'site'; - scope.OPT_ACCESS_TOKEN_PLAYER_TYPE = 'site'; + scope.OPT_ACCESS_TOKEN_PLAYER_TYPE = null; scope.AD_SIGNIFIER = 'stitched-ad'; scope.LIVE_SIGNIFIER = ',live'; scope.CLIENT_ID = 'kimne78kx3ncx6brgo4mv6wki5h1ko'; @@ -39,6 +39,7 @@ scope.gql_device_id_rolling += charTable[(bs.charCodeAt(i) ^ di) % charTable.length]; } scope.gql_device_id_rolling = '1';//temporary + scope.ClientIntegrity = null; } declareOptions(window); var twitchMainWorker = null; @@ -68,6 +69,8 @@ self.addEventListener('message', function(e) { if (e.data.key == 'UboUpdateDeviceId') { gql_device_id = e.data.value; + } else if (e.data.key == 'UpdateClientIntegrity') { + ClientIntegrity = e.data.value; } }); hookWorkerFetch(); @@ -83,23 +86,18 @@ adDiv.P.textContent = 'Blocking' + (e.data.isMidroll ? ' midroll' : '') + ' ads...'; //adDiv.style.display = 'block'; } - } - else if (e.data.key == 'UboHideAdBanner') { + } else if (e.data.key == 'UboHideAdBanner') { var adDiv = getAdDiv(); if (adDiv != null) { adDiv.style.display = 'none'; } - } - else if (e.data.key == 'UboChannelNameM3U8Changed') { + } else if (e.data.key == 'UboChannelNameM3U8Changed') { //console.log('M3U8 channel name changed to ' + e.data.value); - } - else if (e.data.key == 'UboReloadPlayer') { + } else if (e.data.key == 'UboReloadPlayer') { reloadTwitchPlayer(); - } - else if (e.data.key == 'UboPauseResumePlayer') { + } else if (e.data.key == 'UboPauseResumePlayer') { reloadTwitchPlayer(false, true); - } - else if (e.data.key == 'UboSeekPlayer') { + } else if (e.data.key == 'UboSeekPlayer') { reloadTwitchPlayer(true); } } @@ -316,12 +314,17 @@ return gqlRequest(body, realFetch); } function gqlRequest(body, realFetch) { + if (ClientIntegrity == null) { + console.error('ClientIntegrity is null'); + throw 'ClientIntegrity 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-Id': CLIENT_ID, + 'Client-Integrity': ClientIntegrity, 'X-Device-Id': OPT_ROLLING_DEVICE_ID ? gql_device_id_rolling : gql_device_id } }); @@ -418,7 +421,13 @@ if (typeof init.body === 'string' && init.body.includes('PlaybackAccessToken')) { if (OPT_ACCESS_TOKEN_PLAYER_TYPE) { const newBody = JSON.parse(init.body); - newBody.variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + if (Array.isArray(newBody)) { + for (let i = 0; i < newBody.length; i++) { + newBody[i].variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + } + } else { + newBody.variables.playerType = OPT_ACCESS_TOKEN_PLAYER_TYPE; + } init.body = JSON.stringify(newBody); } if (OPT_ROLLING_DEVICE_ID) { @@ -429,6 +438,13 @@ init.headers['Device-ID'] = gql_device_id_rolling; } } + if (typeof init.headers['Client-Integrity'] === 'string') { + ClientIntegrity = init.headers['Client-Integrity']; + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrity', + value: init.headers['Client-Integrity'] + }); + } } } }