From a285eeda5046a304c5eb38b958c875afca066daa Mon Sep 17 00:00:00 2001 From: pixeltris <6952411+pixeltris@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:08:30 +0100 Subject: [PATCH] Fix preroll on every page refresh #188 --- vaft/vaft-ublock-origin.js | 38 ++++++++++---- vaft/vaft.user.js | 40 +++++++++++---- .../video-swap-new-ublock-origin.js | 49 +++++++++++++----- video-swap-new/video-swap-new.user.js | 51 +++++++++++++------ 4 files changed, 130 insertions(+), 48 deletions(-) diff --git a/vaft/vaft-ublock-origin.js b/vaft/vaft-ublock-origin.js index bb2194f..f203123 100644 --- a/vaft/vaft-ublock-origin.js +++ b/vaft/vaft-ublock-origin.js @@ -311,6 +311,7 @@ twitch-videoad.js text/javascript StreamInfos[channelName] = streamInfo = {}; } streamInfo.ChannelName = channelName; + streamInfo.RequestedAds = new Set(); streamInfo.Urls = [];// xxx.m3u8 -> { Resolution: "284x160", FrameRate: 30.0 } streamInfo.EncodingsM3U8Cache = []; streamInfo.EncodingsM3U8 = encodingsM3u8; @@ -471,6 +472,21 @@ twitch-videoad.js text/javascript var isMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); //Reduces ad frequency. TODO: Reduce the number of requests. This is really spamming Twitch with requests. if (!isMidroll) { + if (playerType === PlayerType2) { + var lines = textStr.replace('\r', '').split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line.startsWith('#EXTINF') && lines.length > i + 1) { + if (!line.includes(',live') && !streamInfo.RequestedAds.has(lines[i + 1])) { + // Only request one .ts file per .m3u8 request to avoid making too many requests + //console.log('Fetch ad .ts file'); + streamInfo.RequestedAds.add(lines[i + 1]); + fetch(lines[i + 1]).then((response)=>{response.blob()}); + break; + } + } + } + } try { //tryNotifyTwitch(textStr); } catch (err) {} @@ -658,7 +674,7 @@ twitch-videoad.js text/javascript } function gqlRequest(body, realFetch) { if (ClientIntegrityHeader == null) { - console.warn('ClientIntegrityHeader is null'); + //console.warn('ClientIntegrityHeader is null'); //throw 'ClientIntegrityHeader is null'; } var fetchFunc = realFetch ? realFetch : fetch; @@ -856,16 +872,20 @@ twitch-videoad.js text/javascript } //Client integrity header ClientIntegrityHeader = init.headers['Client-Integrity']; - twitchMainWorker.postMessage({ - key: 'UpdateClientIntegrityHeader', - value: init.headers['Client-Integrity'] - }); + if (ClientIntegrityHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrityHeader', + value: init.headers['Client-Integrity'] + }); + } //Authorization header AuthorizationHeader = init.headers['Authorization']; - twitchMainWorker.postMessage({ - key: 'UpdateAuthorizationHeader', - value: init.headers['Authorization'] - }); + if (AuthorizationHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateAuthorizationHeader', + value: init.headers['Authorization'] + }); + } } //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')) { diff --git a/vaft/vaft.user.js b/vaft/vaft.user.js index 9807890..28ffac7 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.8.4 +// @version 5.8.5 // @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 @@ -322,6 +322,7 @@ StreamInfos[channelName] = streamInfo = {}; } streamInfo.ChannelName = channelName; + streamInfo.RequestedAds = new Set(); streamInfo.Urls = [];// xxx.m3u8 -> { Resolution: "284x160", FrameRate: 30.0 } streamInfo.EncodingsM3U8Cache = []; streamInfo.EncodingsM3U8 = encodingsM3u8; @@ -482,6 +483,21 @@ var isMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); //Reduces ad frequency. TODO: Reduce the number of requests. This is really spamming Twitch with requests. if (!isMidroll) { + if (playerType === PlayerType2) { + var lines = textStr.replace('\r', '').split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line.startsWith('#EXTINF') && lines.length > i + 1) { + if (!line.includes(',live') && !streamInfo.RequestedAds.has(lines[i + 1])) { + // Only request one .ts file per .m3u8 request to avoid making too many requests + //console.log('Fetch ad .ts file'); + streamInfo.RequestedAds.add(lines[i + 1]); + fetch(lines[i + 1]).then((response)=>{response.blob()}); + break; + } + } + } + } try { //tryNotifyTwitch(textStr); } catch (err) {} @@ -669,7 +685,7 @@ } function gqlRequest(body, realFetch) { if (ClientIntegrityHeader == null) { - console.warn('ClientIntegrityHeader is null'); + //console.warn('ClientIntegrityHeader is null'); //throw 'ClientIntegrityHeader is null'; } var fetchFunc = realFetch ? realFetch : fetch; @@ -867,16 +883,20 @@ } //Client integrity header ClientIntegrityHeader = init.headers['Client-Integrity']; - twitchMainWorker.postMessage({ - key: 'UpdateClientIntegrityHeader', - value: init.headers['Client-Integrity'] - }); + if (ClientIntegrityHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrityHeader', + value: init.headers['Client-Integrity'] + }); + } //Authorization header AuthorizationHeader = init.headers['Authorization']; - twitchMainWorker.postMessage({ - key: 'UpdateAuthorizationHeader', - value: init.headers['Authorization'] - }); + if (AuthorizationHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateAuthorizationHeader', + value: init.headers['Authorization'] + }); + } } //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')) { diff --git a/video-swap-new/video-swap-new-ublock-origin.js b/video-swap-new/video-swap-new-ublock-origin.js index 2166aae..80f55f1 100644 --- a/video-swap-new/video-swap-new-ublock-origin.js +++ b/video-swap-new/video-swap-new-ublock-origin.js @@ -152,11 +152,27 @@ twitch-videoad.js text/javascript var streamM3u8Response = await realFetch(streamM3u8Url); if (streamM3u8Response.status == 200) { var streamM3u8 = await streamM3u8Response.text(); - if (streamM3u8 != null && !streamM3u8.includes(AD_SIGNIFIER)) { - console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); - streamInfo.UseBackupStream = false; - postMessage({key:'UboHideAdBanner'}); - postMessage({key:'UboReloadPlayer'}); + if (streamM3u8 != null) { + if (!streamM3u8.includes(AD_SIGNIFIER)) { + console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); + streamInfo.UseBackupStream = false; + postMessage({key:'UboHideAdBanner'}); + postMessage({key:'UboReloadPlayer'}); + } else if (!streamM3u8.includes('"MIDROLL"') && !streamM3u8.includes('"midroll"')) { + var lines = streamM3u8.replace('\r', '').split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line.startsWith('#EXTINF') && lines.length > i + 1) { + if (!line.includes(LIVE_SIGNIFIER) && !streamInfo.RequestedAds.has(lines[i + 1])) { + // Only request one .ts file per .m3u8 request to avoid making too many requests + //console.log('Fetch ad .ts file'); + streamInfo.RequestedAds.add(lines[i + 1]); + fetch(lines[i + 1]).then((response)=>{response.blob()}); + break; + } + } + } + } } } } @@ -211,6 +227,7 @@ twitch-videoad.js text/javascript var useBackupStream = false; if (streamInfo == null || streamInfo.Encodings == null || streamInfo.BackupEncodings == null) { StreamInfos[channelName] = streamInfo = { + RequestedAds: new Set(), Encodings: null, BackupEncodings: null, IsMidroll: false, @@ -340,7 +357,7 @@ twitch-videoad.js text/javascript } function gqlRequest(body, realFetch) { if (ClientIntegrityHeader == null) { - console.warn('ClientIntegrityHeader is null'); + //console.warn('ClientIntegrityHeader is null'); //throw 'ClientIntegrityHeader is null'; } var fetchFunc = realFetch ? realFetch : fetch; @@ -466,17 +483,21 @@ twitch-videoad.js text/javascript } if (typeof init.headers['Client-Integrity'] === 'string') { ClientIntegrityHeader = init.headers['Client-Integrity']; - twitchMainWorker.postMessage({ - key: 'UpdateClientIntegrityHeader', - value: init.headers['Client-Integrity'] - }); + if (ClientIntegrityHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrityHeader', + value: init.headers['Client-Integrity'] + }); + } } if (typeof init.headers['Authorization'] === 'string') { AuthorizationHeader = init.headers['Authorization']; - twitchMainWorker.postMessage({ - key: 'UpdateAuthorizationHeader', - value: init.headers['Authorization'] - }); + if (AuthorizationHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateAuthorizationHeader', + value: init.headers['Authorization'] + }); + } } } } diff --git a/video-swap-new/video-swap-new.user.js b/video-swap-new/video-swap-new.user.js index ab5fd76..e53b1c5 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.21 +// @version 1.22 // @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) @@ -163,11 +163,27 @@ var streamM3u8Response = await realFetch(streamM3u8Url); if (streamM3u8Response.status == 200) { var streamM3u8 = await streamM3u8Response.text(); - if (streamM3u8 != null && !streamM3u8.includes(AD_SIGNIFIER)) { - console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); - streamInfo.UseBackupStream = false; - postMessage({key:'UboHideAdBanner'}); - postMessage({key:'UboReloadPlayer'}); + if (streamM3u8 != null) { + if (!streamM3u8.includes(AD_SIGNIFIER)) { + console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); + streamInfo.UseBackupStream = false; + postMessage({key:'UboHideAdBanner'}); + postMessage({key:'UboReloadPlayer'}); + } else if (!streamM3u8.includes('"MIDROLL"') && !streamM3u8.includes('"midroll"')) { + var lines = streamM3u8.replace('\r', '').split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line.startsWith('#EXTINF') && lines.length > i + 1) { + if (!line.includes(LIVE_SIGNIFIER) && !streamInfo.RequestedAds.has(lines[i + 1])) { + // Only request one .ts file per .m3u8 request to avoid making too many requests + //console.log('Fetch ad .ts file'); + streamInfo.RequestedAds.add(lines[i + 1]); + fetch(lines[i + 1]).then((response)=>{response.blob()}); + break; + } + } + } + } } } } @@ -222,6 +238,7 @@ var useBackupStream = false; if (streamInfo == null || streamInfo.Encodings == null || streamInfo.BackupEncodings == null) { StreamInfos[channelName] = streamInfo = { + RequestedAds: new Set(), Encodings: null, BackupEncodings: null, IsMidroll: false, @@ -351,7 +368,7 @@ } function gqlRequest(body, realFetch) { if (ClientIntegrityHeader == null) { - console.warn('ClientIntegrityHeader is null'); + //console.warn('ClientIntegrityHeader is null'); //throw 'ClientIntegrityHeader is null'; } var fetchFunc = realFetch ? realFetch : fetch; @@ -477,17 +494,21 @@ } if (typeof init.headers['Client-Integrity'] === 'string') { ClientIntegrityHeader = init.headers['Client-Integrity']; - twitchMainWorker.postMessage({ - key: 'UpdateClientIntegrityHeader', - value: init.headers['Client-Integrity'] - }); + if (ClientIntegrityHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateClientIntegrityHeader', + value: init.headers['Client-Integrity'] + }); + } } if (typeof init.headers['Authorization'] === 'string') { AuthorizationHeader = init.headers['Authorization']; - twitchMainWorker.postMessage({ - key: 'UpdateAuthorizationHeader', - value: init.headers['Authorization'] - }); + if (AuthorizationHeader && twitchMainWorker) { + twitchMainWorker.postMessage({ + key: 'UpdateAuthorizationHeader', + value: init.headers['Authorization'] + }); + } } } }