From 4ef55e67a233217a81a381c3461eb20773b4def6 Mon Sep 17 00:00:00 2001 From: pixeltris <6952411+pixeltris@users.noreply.github.com> Date: Sat, 12 Jun 2021 15:22:18 +0100 Subject: [PATCH] Reduce number of web requests --- base/base.user.js | 132 ++++++++----------- notify-reload/notify-reload-ublock-origin.js | 130 ++++++++---------- notify-reload/notify-reload.user.js | 132 ++++++++----------- notify-strip/notify-strip-ublock-origin.js | 130 ++++++++---------- notify-strip/notify-strip.cfg | 1 - notify-strip/notify-strip.user.js | 132 ++++++++----------- 6 files changed, 283 insertions(+), 374 deletions(-) diff --git a/base/base.user.js b/base/base.user.js index 39580a3..22b41ae 100644 --- a/base/base.user.js +++ b/base/base.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name TwitchAdSolutions // @namespace https://github.com/pixeltris/TwitchAdSolutions -// @version 1.5 +// @version 1.6 // @description Multiple solutions for blocking Twitch ads // @author pixeltris // @match *://*.twitch.tv/* @@ -15,8 +15,6 @@ scope.OPT_ROLLING_DEVICE_ID = false; scope.OPT_MODE_STRIP_AD_SEGMENTS = false; scope.OPT_MODE_NOTIFY_ADS_WATCHED = false; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST = false; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION = 10000;// In milliseconds scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_RELOAD_PLAYER_ON_AD_SEGMENT = false; scope.OPT_BACKUP_PLAYER_TYPE = 'picture-by-picture';//'picture-by-picture';'thunderdome'; @@ -154,24 +152,9 @@ streamInfo.IsMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); postMessage({key:'UboShowAdBanner',isMidroll:streamInfo.IsMidroll}); // Notify ads "watched" TODO: Keep crafting these requests even after ad tags are gone as sometimes it stops too early. - if (OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST && streamInfo != null && !streamInfo.NotifyObservedNoAds) { - var noAds = false; - var encodingsM3u8Response = await realFetch(streamInfo.RootM3U8Url); - if (encodingsM3u8Response.status === 200) { - var encodingsM3u8 = await encodingsM3u8Response.text(); - var streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/m)[0]; - var streamM3u8Response = await realFetch(streamM3u8Url); - if (streamM3u8Response.status == 200) { - noAds = (await tryNotifyAdsWatchedM3U8(await streamM3u8Response.text())) == 1; - console.log('Notify ad watched. Response has ads: ' + !noAds); - } - } - if (streamInfo.NotifyFirstTime == 0) { - streamInfo.NotifyFirstTime = Date.now(); - } - if (noAds && !streamInfo.NotifyObservedNoAds && Date.now() >= streamInfo.NotifyFirstTime + OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION) { - streamInfo.NotifyObservedNoAds = true; - } + // Deferred to after backup obtained to reduce slowdown. Midrolls are futile. + if (OPT_MODE_NOTIFY_ADS_WATCHED && !streamInfo.IsMidroll && (streamInfo.BackupFailed || streamInfo.BackupUrl != null)) { + await tryNotifyAdsWatchedM3U8(textStr); } postMessage({ key: 'UboFoundAdSegment', @@ -353,12 +336,6 @@ streamInfo.BackupRegRes = null; streamInfo.IsMidroll = false; streamInfo.HadAds = false; - streamInfo.NotifyFirstTime = 0; - streamInfo.NotifyObservedNoAds = false; - streamInfo.RealSeqNumber = -1; - streamInfo.BackupSeqNumber = -1; - streamInfo.FakeSeqNumber = 0; - streamInfo.FinalSegUrl = null; var lines = encodingsM3u8.replace('\r', '').split('\n'); for (var i = 0; i < lines.length; i++) { if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) { @@ -447,58 +424,63 @@ })); } async function tryNotifyAdsWatchedM3U8(streamM3u8) { - //console.log(streamM3u8); - if (!streamM3u8.includes(AD_SIGNIFIER)) { - return 1; - } - var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); - if (matches.length > 1) { - const attrString = matches[1]; - const attr = parseAttributes(attrString); - var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); - var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); - var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; - var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; - var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; - var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; - var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; - var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); - const baseData = { - stitched: true, - roll_type: rollType, - player_mute: false, - player_volume: 0.5, - visible: true, - }; - for (let podPosition = 0; podPosition < podLength; podPosition++) { - if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { - // This is all that's actually required at the moment - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); - } else { - const extendedData = { - ...baseData, - ad_id: adId, - ad_position: podPosition, - duration: 30, - creative_id: creativeId, - total_ads: podLength, - order_id: orderId, - line_item_id: lineItemId, - }; - await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); - for (let quartile = 0; quartile < 4; quartile++) { - await gqlRequest( - makeGraphQlPacket('video_ad_quartile_complete', radToken, { - ...extendedData, - quartile: quartile + 1, - }) - ); + try { + //console.log(streamM3u8); + if (!streamM3u8.includes(AD_SIGNIFIER)) { + return 1; + } + var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); + if (matches.length > 1) { + const attrString = matches[1]; + const attr = parseAttributes(attrString); + var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); + var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); + var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; + var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; + var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; + var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; + var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; + var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); + const baseData = { + stitched: true, + roll_type: rollType, + player_mute: false, + player_volume: 0.5, + visible: true, + }; + for (let podPosition = 0; podPosition < podLength; podPosition++) { + if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { + // This is all that's actually required at the moment + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); + } else { + const extendedData = { + ...baseData, + ad_id: adId, + ad_position: podPosition, + duration: 30, + creative_id: creativeId, + total_ads: podLength, + order_id: orderId, + line_item_id: lineItemId, + }; + await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); + for (let quartile = 0; quartile < 4; quartile++) { + await gqlRequest( + makeGraphQlPacket('video_ad_quartile_complete', radToken, { + ...extendedData, + quartile: quartile + 1, + }) + ); + } + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } } + return 0; + } catch (err) { + console.log(err); + return 0; } - return 0; } function hookFetch() { var realFetch = window.fetch; diff --git a/notify-reload/notify-reload-ublock-origin.js b/notify-reload/notify-reload-ublock-origin.js index ca94ccd..48aeac3 100644 --- a/notify-reload/notify-reload-ublock-origin.js +++ b/notify-reload/notify-reload-ublock-origin.js @@ -6,8 +6,6 @@ twitch-videoad.js application/javascript scope.OPT_ROLLING_DEVICE_ID = true; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST = false; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION = 10000;// In milliseconds scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_RELOAD_PLAYER_ON_AD_SEGMENT = true; scope.OPT_BACKUP_PLAYER_TYPE = 'picture-by-picture';//'picture-by-picture';'thunderdome'; @@ -145,24 +143,9 @@ twitch-videoad.js application/javascript streamInfo.IsMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); postMessage({key:'UboShowAdBanner',isMidroll:streamInfo.IsMidroll}); // Notify ads "watched" TODO: Keep crafting these requests even after ad tags are gone as sometimes it stops too early. - if (OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST && streamInfo != null && !streamInfo.NotifyObservedNoAds) { - var noAds = false; - var encodingsM3u8Response = await realFetch(streamInfo.RootM3U8Url); - if (encodingsM3u8Response.status === 200) { - var encodingsM3u8 = await encodingsM3u8Response.text(); - var streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/m)[0]; - var streamM3u8Response = await realFetch(streamM3u8Url); - if (streamM3u8Response.status == 200) { - noAds = (await tryNotifyAdsWatchedM3U8(await streamM3u8Response.text())) == 1; - console.log('Notify ad watched. Response has ads: ' + !noAds); - } - } - if (streamInfo.NotifyFirstTime == 0) { - streamInfo.NotifyFirstTime = Date.now(); - } - if (noAds && !streamInfo.NotifyObservedNoAds && Date.now() >= streamInfo.NotifyFirstTime + OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION) { - streamInfo.NotifyObservedNoAds = true; - } + // Deferred to after backup obtained to reduce slowdown. Midrolls are futile. + if (OPT_MODE_NOTIFY_ADS_WATCHED && !streamInfo.IsMidroll && (streamInfo.BackupFailed || streamInfo.BackupUrl != null)) { + await tryNotifyAdsWatchedM3U8(textStr); } postMessage({ key: 'UboFoundAdSegment', @@ -344,12 +327,6 @@ twitch-videoad.js application/javascript streamInfo.BackupRegRes = null; streamInfo.IsMidroll = false; streamInfo.HadAds = false; - streamInfo.NotifyFirstTime = 0; - streamInfo.NotifyObservedNoAds = false; - streamInfo.RealSeqNumber = -1; - streamInfo.BackupSeqNumber = -1; - streamInfo.FakeSeqNumber = 0; - streamInfo.FinalSegUrl = null; var lines = encodingsM3u8.replace('\r', '').split('\n'); for (var i = 0; i < lines.length; i++) { if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) { @@ -438,58 +415,63 @@ twitch-videoad.js application/javascript })); } async function tryNotifyAdsWatchedM3U8(streamM3u8) { - //console.log(streamM3u8); - if (!streamM3u8.includes(AD_SIGNIFIER)) { - return 1; - } - var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); - if (matches.length > 1) { - const attrString = matches[1]; - const attr = parseAttributes(attrString); - var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); - var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); - var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; - var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; - var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; - var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; - var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; - var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); - const baseData = { - stitched: true, - roll_type: rollType, - player_mute: false, - player_volume: 0.5, - visible: true, - }; - for (let podPosition = 0; podPosition < podLength; podPosition++) { - if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { - // This is all that's actually required at the moment - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); - } else { - const extendedData = { - ...baseData, - ad_id: adId, - ad_position: podPosition, - duration: 30, - creative_id: creativeId, - total_ads: podLength, - order_id: orderId, - line_item_id: lineItemId, - }; - await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); - for (let quartile = 0; quartile < 4; quartile++) { - await gqlRequest( - makeGraphQlPacket('video_ad_quartile_complete', radToken, { - ...extendedData, - quartile: quartile + 1, - }) - ); + try { + //console.log(streamM3u8); + if (!streamM3u8.includes(AD_SIGNIFIER)) { + return 1; + } + var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); + if (matches.length > 1) { + const attrString = matches[1]; + const attr = parseAttributes(attrString); + var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); + var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); + var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; + var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; + var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; + var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; + var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; + var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); + const baseData = { + stitched: true, + roll_type: rollType, + player_mute: false, + player_volume: 0.5, + visible: true, + }; + for (let podPosition = 0; podPosition < podLength; podPosition++) { + if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { + // This is all that's actually required at the moment + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); + } else { + const extendedData = { + ...baseData, + ad_id: adId, + ad_position: podPosition, + duration: 30, + creative_id: creativeId, + total_ads: podLength, + order_id: orderId, + line_item_id: lineItemId, + }; + await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); + for (let quartile = 0; quartile < 4; quartile++) { + await gqlRequest( + makeGraphQlPacket('video_ad_quartile_complete', radToken, { + ...extendedData, + quartile: quartile + 1, + }) + ); + } + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } } + return 0; + } catch (err) { + console.log(err); + return 0; } - return 0; } function hookFetch() { var realFetch = window.fetch; diff --git a/notify-reload/notify-reload.user.js b/notify-reload/notify-reload.user.js index dd1f886..d300622 100644 --- a/notify-reload/notify-reload.user.js +++ b/notify-reload/notify-reload.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name TwitchAdSolutions (notify-reload) // @namespace https://github.com/pixeltris/TwitchAdSolutions -// @version 1.5 +// @version 1.6 // @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/notify-reload/notify-reload.user.js // @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/notify-reload/notify-reload.user.js // @description Multiple solutions for blocking Twitch ads (notify-reload) @@ -17,8 +17,6 @@ scope.OPT_ROLLING_DEVICE_ID = true; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST = false; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION = 10000;// In milliseconds scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_RELOAD_PLAYER_ON_AD_SEGMENT = true; scope.OPT_BACKUP_PLAYER_TYPE = 'picture-by-picture';//'picture-by-picture';'thunderdome'; @@ -156,24 +154,9 @@ streamInfo.IsMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); postMessage({key:'UboShowAdBanner',isMidroll:streamInfo.IsMidroll}); // Notify ads "watched" TODO: Keep crafting these requests even after ad tags are gone as sometimes it stops too early. - if (OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST && streamInfo != null && !streamInfo.NotifyObservedNoAds) { - var noAds = false; - var encodingsM3u8Response = await realFetch(streamInfo.RootM3U8Url); - if (encodingsM3u8Response.status === 200) { - var encodingsM3u8 = await encodingsM3u8Response.text(); - var streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/m)[0]; - var streamM3u8Response = await realFetch(streamM3u8Url); - if (streamM3u8Response.status == 200) { - noAds = (await tryNotifyAdsWatchedM3U8(await streamM3u8Response.text())) == 1; - console.log('Notify ad watched. Response has ads: ' + !noAds); - } - } - if (streamInfo.NotifyFirstTime == 0) { - streamInfo.NotifyFirstTime = Date.now(); - } - if (noAds && !streamInfo.NotifyObservedNoAds && Date.now() >= streamInfo.NotifyFirstTime + OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION) { - streamInfo.NotifyObservedNoAds = true; - } + // Deferred to after backup obtained to reduce slowdown. Midrolls are futile. + if (OPT_MODE_NOTIFY_ADS_WATCHED && !streamInfo.IsMidroll && (streamInfo.BackupFailed || streamInfo.BackupUrl != null)) { + await tryNotifyAdsWatchedM3U8(textStr); } postMessage({ key: 'UboFoundAdSegment', @@ -355,12 +338,6 @@ streamInfo.BackupRegRes = null; streamInfo.IsMidroll = false; streamInfo.HadAds = false; - streamInfo.NotifyFirstTime = 0; - streamInfo.NotifyObservedNoAds = false; - streamInfo.RealSeqNumber = -1; - streamInfo.BackupSeqNumber = -1; - streamInfo.FakeSeqNumber = 0; - streamInfo.FinalSegUrl = null; var lines = encodingsM3u8.replace('\r', '').split('\n'); for (var i = 0; i < lines.length; i++) { if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) { @@ -449,58 +426,63 @@ })); } async function tryNotifyAdsWatchedM3U8(streamM3u8) { - //console.log(streamM3u8); - if (!streamM3u8.includes(AD_SIGNIFIER)) { - return 1; - } - var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); - if (matches.length > 1) { - const attrString = matches[1]; - const attr = parseAttributes(attrString); - var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); - var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); - var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; - var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; - var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; - var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; - var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; - var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); - const baseData = { - stitched: true, - roll_type: rollType, - player_mute: false, - player_volume: 0.5, - visible: true, - }; - for (let podPosition = 0; podPosition < podLength; podPosition++) { - if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { - // This is all that's actually required at the moment - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); - } else { - const extendedData = { - ...baseData, - ad_id: adId, - ad_position: podPosition, - duration: 30, - creative_id: creativeId, - total_ads: podLength, - order_id: orderId, - line_item_id: lineItemId, - }; - await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); - for (let quartile = 0; quartile < 4; quartile++) { - await gqlRequest( - makeGraphQlPacket('video_ad_quartile_complete', radToken, { - ...extendedData, - quartile: quartile + 1, - }) - ); + try { + //console.log(streamM3u8); + if (!streamM3u8.includes(AD_SIGNIFIER)) { + return 1; + } + var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); + if (matches.length > 1) { + const attrString = matches[1]; + const attr = parseAttributes(attrString); + var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); + var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); + var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; + var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; + var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; + var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; + var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; + var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); + const baseData = { + stitched: true, + roll_type: rollType, + player_mute: false, + player_volume: 0.5, + visible: true, + }; + for (let podPosition = 0; podPosition < podLength; podPosition++) { + if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { + // This is all that's actually required at the moment + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); + } else { + const extendedData = { + ...baseData, + ad_id: adId, + ad_position: podPosition, + duration: 30, + creative_id: creativeId, + total_ads: podLength, + order_id: orderId, + line_item_id: lineItemId, + }; + await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); + for (let quartile = 0; quartile < 4; quartile++) { + await gqlRequest( + makeGraphQlPacket('video_ad_quartile_complete', radToken, { + ...extendedData, + quartile: quartile + 1, + }) + ); + } + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } } + return 0; + } catch (err) { + console.log(err); + return 0; } - return 0; } function hookFetch() { var realFetch = window.fetch; diff --git a/notify-strip/notify-strip-ublock-origin.js b/notify-strip/notify-strip-ublock-origin.js index b053b7d..a62c9ca 100644 --- a/notify-strip/notify-strip-ublock-origin.js +++ b/notify-strip/notify-strip-ublock-origin.js @@ -6,8 +6,6 @@ twitch-videoad.js application/javascript scope.OPT_ROLLING_DEVICE_ID = true; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION = 10000;// In milliseconds scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_RELOAD_PLAYER_ON_AD_SEGMENT = false; scope.OPT_BACKUP_PLAYER_TYPE = 'picture-by-picture';//'picture-by-picture';'thunderdome'; @@ -145,24 +143,9 @@ twitch-videoad.js application/javascript streamInfo.IsMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); postMessage({key:'UboShowAdBanner',isMidroll:streamInfo.IsMidroll}); // Notify ads "watched" TODO: Keep crafting these requests even after ad tags are gone as sometimes it stops too early. - if (OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST && streamInfo != null && !streamInfo.NotifyObservedNoAds) { - var noAds = false; - var encodingsM3u8Response = await realFetch(streamInfo.RootM3U8Url); - if (encodingsM3u8Response.status === 200) { - var encodingsM3u8 = await encodingsM3u8Response.text(); - var streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/m)[0]; - var streamM3u8Response = await realFetch(streamM3u8Url); - if (streamM3u8Response.status == 200) { - noAds = (await tryNotifyAdsWatchedM3U8(await streamM3u8Response.text())) == 1; - console.log('Notify ad watched. Response has ads: ' + !noAds); - } - } - if (streamInfo.NotifyFirstTime == 0) { - streamInfo.NotifyFirstTime = Date.now(); - } - if (noAds && !streamInfo.NotifyObservedNoAds && Date.now() >= streamInfo.NotifyFirstTime + OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION) { - streamInfo.NotifyObservedNoAds = true; - } + // Deferred to after backup obtained to reduce slowdown. Midrolls are futile. + if (OPT_MODE_NOTIFY_ADS_WATCHED && !streamInfo.IsMidroll && (streamInfo.BackupFailed || streamInfo.BackupUrl != null)) { + await tryNotifyAdsWatchedM3U8(textStr); } postMessage({ key: 'UboFoundAdSegment', @@ -344,12 +327,6 @@ twitch-videoad.js application/javascript streamInfo.BackupRegRes = null; streamInfo.IsMidroll = false; streamInfo.HadAds = false; - streamInfo.NotifyFirstTime = 0; - streamInfo.NotifyObservedNoAds = false; - streamInfo.RealSeqNumber = -1; - streamInfo.BackupSeqNumber = -1; - streamInfo.FakeSeqNumber = 0; - streamInfo.FinalSegUrl = null; var lines = encodingsM3u8.replace('\r', '').split('\n'); for (var i = 0; i < lines.length; i++) { if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) { @@ -438,58 +415,63 @@ twitch-videoad.js application/javascript })); } async function tryNotifyAdsWatchedM3U8(streamM3u8) { - //console.log(streamM3u8); - if (!streamM3u8.includes(AD_SIGNIFIER)) { - return 1; - } - var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); - if (matches.length > 1) { - const attrString = matches[1]; - const attr = parseAttributes(attrString); - var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); - var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); - var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; - var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; - var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; - var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; - var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; - var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); - const baseData = { - stitched: true, - roll_type: rollType, - player_mute: false, - player_volume: 0.5, - visible: true, - }; - for (let podPosition = 0; podPosition < podLength; podPosition++) { - if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { - // This is all that's actually required at the moment - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); - } else { - const extendedData = { - ...baseData, - ad_id: adId, - ad_position: podPosition, - duration: 30, - creative_id: creativeId, - total_ads: podLength, - order_id: orderId, - line_item_id: lineItemId, - }; - await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); - for (let quartile = 0; quartile < 4; quartile++) { - await gqlRequest( - makeGraphQlPacket('video_ad_quartile_complete', radToken, { - ...extendedData, - quartile: quartile + 1, - }) - ); + try { + //console.log(streamM3u8); + if (!streamM3u8.includes(AD_SIGNIFIER)) { + return 1; + } + var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); + if (matches.length > 1) { + const attrString = matches[1]; + const attr = parseAttributes(attrString); + var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); + var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); + var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; + var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; + var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; + var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; + var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; + var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); + const baseData = { + stitched: true, + roll_type: rollType, + player_mute: false, + player_volume: 0.5, + visible: true, + }; + for (let podPosition = 0; podPosition < podLength; podPosition++) { + if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { + // This is all that's actually required at the moment + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); + } else { + const extendedData = { + ...baseData, + ad_id: adId, + ad_position: podPosition, + duration: 30, + creative_id: creativeId, + total_ads: podLength, + order_id: orderId, + line_item_id: lineItemId, + }; + await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); + for (let quartile = 0; quartile < 4; quartile++) { + await gqlRequest( + makeGraphQlPacket('video_ad_quartile_complete', radToken, { + ...extendedData, + quartile: quartile + 1, + }) + ); + } + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } } + return 0; + } catch (err) { + console.log(err); + return 0; } - return 0; } function hookFetch() { var realFetch = window.fetch; diff --git a/notify-strip/notify-strip.cfg b/notify-strip/notify-strip.cfg index 76a756a..371b012 100644 --- a/notify-strip/notify-strip.cfg +++ b/notify-strip/notify-strip.cfg @@ -1,5 +1,4 @@ OPT_ROLLING_DEVICE_ID true OPT_MODE_STRIP_AD_SEGMENTS true OPT_MODE_NOTIFY_ADS_WATCHED true -OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST true OPT_ACCESS_TOKEN_PLAYER_TYPE 'site' \ No newline at end of file diff --git a/notify-strip/notify-strip.user.js b/notify-strip/notify-strip.user.js index 3481cde..4594508 100644 --- a/notify-strip/notify-strip.user.js +++ b/notify-strip/notify-strip.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name TwitchAdSolutions (notify-strip) // @namespace https://github.com/pixeltris/TwitchAdSolutions -// @version 1.5 +// @version 1.6 // @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/notify-strip/notify-strip.user.js // @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/notify-strip/notify-strip.user.js // @description Multiple solutions for blocking Twitch ads (notify-strip) @@ -17,8 +17,6 @@ scope.OPT_ROLLING_DEVICE_ID = true; scope.OPT_MODE_STRIP_AD_SEGMENTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST = true; - scope.OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION = 10000;// In milliseconds scope.OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS = true; scope.OPT_MODE_NOTIFY_ADS_WATCHED_RELOAD_PLAYER_ON_AD_SEGMENT = false; scope.OPT_BACKUP_PLAYER_TYPE = 'picture-by-picture';//'picture-by-picture';'thunderdome'; @@ -156,24 +154,9 @@ streamInfo.IsMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"'); postMessage({key:'UboShowAdBanner',isMidroll:streamInfo.IsMidroll}); // Notify ads "watched" TODO: Keep crafting these requests even after ad tags are gone as sometimes it stops too early. - if (OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST && streamInfo != null && !streamInfo.NotifyObservedNoAds) { - var noAds = false; - var encodingsM3u8Response = await realFetch(streamInfo.RootM3U8Url); - if (encodingsM3u8Response.status === 200) { - var encodingsM3u8 = await encodingsM3u8Response.text(); - var streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/m)[0]; - var streamM3u8Response = await realFetch(streamM3u8Url); - if (streamM3u8Response.status == 200) { - noAds = (await tryNotifyAdsWatchedM3U8(await streamM3u8Response.text())) == 1; - console.log('Notify ad watched. Response has ads: ' + !noAds); - } - } - if (streamInfo.NotifyFirstTime == 0) { - streamInfo.NotifyFirstTime = Date.now(); - } - if (noAds && !streamInfo.NotifyObservedNoAds && Date.now() >= streamInfo.NotifyFirstTime + OPT_MODE_NOTIFY_ADS_WATCHED_PERSIST_EXPECTED_DURATION) { - streamInfo.NotifyObservedNoAds = true; - } + // Deferred to after backup obtained to reduce slowdown. Midrolls are futile. + if (OPT_MODE_NOTIFY_ADS_WATCHED && !streamInfo.IsMidroll && (streamInfo.BackupFailed || streamInfo.BackupUrl != null)) { + await tryNotifyAdsWatchedM3U8(textStr); } postMessage({ key: 'UboFoundAdSegment', @@ -355,12 +338,6 @@ streamInfo.BackupRegRes = null; streamInfo.IsMidroll = false; streamInfo.HadAds = false; - streamInfo.NotifyFirstTime = 0; - streamInfo.NotifyObservedNoAds = false; - streamInfo.RealSeqNumber = -1; - streamInfo.BackupSeqNumber = -1; - streamInfo.FakeSeqNumber = 0; - streamInfo.FinalSegUrl = null; var lines = encodingsM3u8.replace('\r', '').split('\n'); for (var i = 0; i < lines.length; i++) { if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) { @@ -449,58 +426,63 @@ })); } async function tryNotifyAdsWatchedM3U8(streamM3u8) { - //console.log(streamM3u8); - if (!streamM3u8.includes(AD_SIGNIFIER)) { - return 1; - } - var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); - if (matches.length > 1) { - const attrString = matches[1]; - const attr = parseAttributes(attrString); - var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); - var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); - var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; - var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; - var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; - var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; - var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; - var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); - const baseData = { - stitched: true, - roll_type: rollType, - player_mute: false, - player_volume: 0.5, - visible: true, - }; - for (let podPosition = 0; podPosition < podLength; podPosition++) { - if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { - // This is all that's actually required at the moment - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); - } else { - const extendedData = { - ...baseData, - ad_id: adId, - ad_position: podPosition, - duration: 30, - creative_id: creativeId, - total_ads: podLength, - order_id: orderId, - line_item_id: lineItemId, - }; - await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); - for (let quartile = 0; quartile < 4; quartile++) { - await gqlRequest( - makeGraphQlPacket('video_ad_quartile_complete', radToken, { - ...extendedData, - quartile: quartile + 1, - }) - ); + try { + //console.log(streamM3u8); + if (!streamM3u8.includes(AD_SIGNIFIER)) { + return 1; + } + var matches = streamM3u8.match(/#EXT-X-DATERANGE:(ID="stitched-ad-[^\n]+)\n/); + if (matches.length > 1) { + const attrString = matches[1]; + const attr = parseAttributes(attrString); + var podLength = parseInt(attr['X-TV-TWITCH-AD-POD-LENGTH'] ? attr['X-TV-TWITCH-AD-POD-LENGTH'] : '1'); + var podPosition = parseInt(attr['X-TV-TWITCH-AD-POD-POSITION'] ? attr['X-TV-TWITCH-AD-POD-POSITION'] : '0'); + var radToken = attr['X-TV-TWITCH-AD-RADS-TOKEN']; + var lineItemId = attr['X-TV-TWITCH-AD-LINE-ITEM-ID']; + var orderId = attr['X-TV-TWITCH-AD-ORDER-ID']; + var creativeId = attr['X-TV-TWITCH-AD-CREATIVE-ID']; + var adId = attr['X-TV-TWITCH-AD-ADVERTISER-ID']; + var rollType = attr['X-TV-TWITCH-AD-ROLL-TYPE'].toLowerCase(); + const baseData = { + stitched: true, + roll_type: rollType, + player_mute: false, + player_volume: 0.5, + visible: true, + }; + for (let podPosition = 0; podPosition < podLength; podPosition++) { + if (OPT_MODE_NOTIFY_ADS_WATCHED_MIN_REQUESTS) { + // This is all that's actually required at the moment + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); + } else { + const extendedData = { + ...baseData, + ad_id: adId, + ad_position: podPosition, + duration: 30, + creative_id: creativeId, + total_ads: podLength, + order_id: orderId, + line_item_id: lineItemId, + }; + await gqlRequest(makeGraphQlPacket('video_ad_impression', radToken, extendedData)); + for (let quartile = 0; quartile < 4; quartile++) { + await gqlRequest( + makeGraphQlPacket('video_ad_quartile_complete', radToken, { + ...extendedData, + quartile: quartile + 1, + }) + ); + } + await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } - await gqlRequest(makeGraphQlPacket('video_ad_pod_complete', radToken, baseData)); } } + return 0; + } catch (err) { + console.log(err); + return 0; } - return 0; } function hookFetch() { var realFetch = window.fetch;