Cleanup + fix warnings caused by clearStats

This commit is contained in:
Younes Aassila 2025-02-04 15:38:26 +01:00
parent ac50e0c8b2
commit 010265c8f0
No known key found for this signature in database
4 changed files with 31 additions and 24 deletions

View File

@ -47,10 +47,13 @@ function onStoreLoad() {
/** /**
* Clear stats for stream on page load/reload. * Clear stats for stream on page load/reload.
* @param channelName
* @param delayMs
* @returns * @returns
*/ */
function clearStats(channelName: string | null) { async function clearStats(channelName: string | null, delayMs?: number) {
if (!channelName) return; if (!channelName) return;
if (delayMs) await new Promise(resolve => setTimeout(resolve, delayMs));
const channelNameLower = channelName.toLowerCase(); const channelNameLower = channelName.toLowerCase();
if (store.state.streamStatuses.hasOwnProperty(channelNameLower)) { if (store.state.streamStatuses.hasOwnProperty(channelNameLower)) {
delete store.state.streamStatuses[channelNameLower]; delete store.state.streamStatuses[channelNameLower];
@ -102,7 +105,7 @@ function onPageMessage(event: MessageEvent) {
return; return;
} }
const { message, responseType, responseMessageType } = event.data; const { message } = event.data;
if (!message) return; if (!message) return;
if (message.type === MessageType.GetStoreState) { if (message.type === MessageType.GetStoreState) {
@ -150,6 +153,7 @@ function onPageMessage(event: MessageEvent) {
isSubscribed, isSubscribed,
isWhitelisted, isWhitelisted,
}); });
const currentChannelName = findChannelFromTwitchTvUrl(location.href);
if (store.state.whitelistChannelSubscriptions && channelName != null) { if (store.state.whitelistChannelSubscriptions && channelName != null) {
if (!wasSubscribed && isSubscribed) { if (!wasSubscribed && isSubscribed) {
store.state.activeChannelSubscriptions.push(channelName); store.state.activeChannelSubscriptions.push(channelName);
@ -158,7 +162,9 @@ function onPageMessage(event: MessageEvent) {
console.log(`[TTV LOL PRO] Adding '${channelName}' to whitelist.`); console.log(`[TTV LOL PRO] Adding '${channelName}' to whitelist.`);
store.state.whitelistedChannels.push(channelName); store.state.whitelistedChannels.push(channelName);
} }
location.reload(); if (channelName === currentChannelName) {
location.reload();
}
} else if (wasSubscribed && !isSubscribed) { } else if (wasSubscribed && !isSubscribed) {
store.state.activeChannelSubscriptions = store.state.activeChannelSubscriptions =
store.state.activeChannelSubscriptions.filter( store.state.activeChannelSubscriptions.filter(
@ -174,7 +180,9 @@ function onPageMessage(event: MessageEvent) {
c => c.toLowerCase() !== channelName.toLowerCase() c => c.toLowerCase() !== channelName.toLowerCase()
); );
} }
location.reload(); if (channelName === currentChannelName) {
location.reload();
}
} }
} }
} }
@ -201,6 +209,6 @@ function onPageMessage(event: MessageEvent) {
} }
// --- // ---
else if (message.type === MessageType.ClearStats) { else if (message.type === MessageType.ClearStats) {
clearStats(message.channelName); clearStats(message.channelName, 2000);
} }
} }

View File

@ -71,9 +71,11 @@ export function getFetch(pageState: PageState): typeof fetch {
console.log("[TTV LOL PRO] Cleared stats (getFetch)."); console.log("[TTV LOL PRO] Cleared stats (getFetch).");
if (!message.channelName) break; if (!message.channelName) break;
const channelNameLower = message.channelName.toLowerCase(); const channelNameLower = message.channelName.toLowerCase();
usherManifests = usherManifests.filter( for (let i = 0; i < usherManifests.length; i++) {
manifest => manifest.channelName !== channelNameLower if (usherManifests[i].channelName === channelNameLower) {
); usherManifests[i].deleted = true;
}
}
if (cachedPlaybackTokenRequestBody?.includes(channelNameLower)) { if (cachedPlaybackTokenRequestBody?.includes(channelNameLower)) {
cachedPlaybackTokenRequestHeaders = null; cachedPlaybackTokenRequestHeaders = null;
cachedPlaybackTokenRequestBody = null; cachedPlaybackTokenRequestBody = null;
@ -294,9 +296,9 @@ export function getFetch(pageState: PageState): typeof fetch {
[...manifest.assignedMap.values()].includes(url) [...manifest.assignedMap.values()].includes(url)
); );
if (manifest == null) { if (manifest == null) {
console.log( console.warn(
"[TTV LOL PRO] No associated Usher manifest found for Video Weaver request." "[TTV LOL PRO] No associated Usher manifest found for Video Weaver request."
); // This can happen just after a ClearStats message if Twitch decides to send another Video Weaver request. );
} }
if (videoWeaverUrlsToNotProxy.has(url)) { if (videoWeaverUrlsToNotProxy.has(url)) {
if (IS_DEVELOPMENT) { if (IS_DEVELOPMENT) {
@ -442,6 +444,7 @@ export function getFetch(pageState: PageState): typeof fetch {
} }
const isLivestream = !/^\d+$/.test(channelName); // VODs have numeric IDs. const isLivestream = !/^\d+$/.test(channelName); // VODs have numeric IDs.
if (!isLivestream) break graphqlRes; if (!isLivestream) break graphqlRes;
await waitForStore(pageState);
const wasSubscribed = wasChannelSubscriber(channelName, pageState); const wasSubscribed = wasChannelSubscriber(channelName, pageState);
const hasSubStatusChanged = const hasSubStatusChanged =
(wasSubscribed && !isSubscribed) || (!wasSubscribed && isSubscribed); (wasSubscribed && !isSubscribed) || (!wasSubscribed && isSubscribed);
@ -465,6 +468,7 @@ export function getFetch(pageState: PageState): typeof fetch {
response.status < 400 response.status < 400
) { ) {
//#region Usher responses. //#region Usher responses.
// No need to wait for store here because all Usher requests have already waited for it.
const isLivestream = !url.includes("/vod/"); const isLivestream = !url.includes("/vod/");
const isFrontpage = url.includes( const isFrontpage = url.includes(
encodeURIComponent('"player_type":"frontpage"') encodeURIComponent('"player_type":"frontpage"')
@ -474,6 +478,7 @@ export function getFetch(pageState: PageState): typeof fetch {
if (!isLivestream) break usherRes; if (!isLivestream) break usherRes;
responseBody ??= await readResponseBody(); responseBody ??= await readResponseBody();
usherManifests = usherManifests.filter(manifest => !manifest.deleted); // Clean up deleted manifests.
const assignedMap = parseUsherManifest(responseBody); const assignedMap = parseUsherManifest(responseBody);
if (assignedMap != null) { if (assignedMap != null) {
console.debug( console.debug(
@ -486,9 +491,12 @@ export function getFetch(pageState: PageState): typeof fetch {
replacementMap: null, replacementMap: null,
consecutiveMidrollResponses: 0, consecutiveMidrollResponses: 0,
consecutiveMidrollCooldown: 0, consecutiveMidrollCooldown: 0,
deleted: false,
}); });
} else { } else {
console.debug("[TTV LOL PRO] Received Usher response."); console.error(
"[TTV LOL PRO] Received Usher response but failed to parse it."
);
} }
// Send Video Weaver URLs to content script. // Send Video Weaver URLs to content script.
const videoWeaverUrls = [...(assignedMap?.values() ?? [])]; const videoWeaverUrls = [...(assignedMap?.values() ?? [])];
@ -534,14 +542,11 @@ export function getFetch(pageState: PageState): typeof fetch {
console.log("[TTV LOL PRO] Midroll ad detected."); console.log("[TTV LOL PRO] Midroll ad detected.");
manifest.consecutiveMidrollResponses += 1; manifest.consecutiveMidrollResponses += 1;
manifest.consecutiveMidrollCooldown = 15; manifest.consecutiveMidrollCooldown = 15;
const isWhitelisted = isChannelWhitelisted( await waitForStore(pageState);
manifest.channelName,
pageState
);
const shouldUpdateReplacementMap = const shouldUpdateReplacementMap =
pageState.state?.optimizedProxiesEnabled === true && pageState.state?.optimizedProxiesEnabled === true &&
manifest.consecutiveMidrollResponses <= 2 && // Avoid infinite loop. manifest.consecutiveMidrollResponses <= 2 && // Avoid infinite loop.
!isWhitelisted; !videoWeaverUrlsToNotProxy.has(url);
if (shouldUpdateReplacementMap) { if (shouldUpdateReplacementMap) {
const success = await updateVideoWeaverReplacementMap( const success = await updateVideoWeaverReplacementMap(
pageState, pageState,
@ -746,10 +751,6 @@ function cancelRequest(): never {
throw new Error(); throw new Error();
} }
async function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
//#region Video Weaver URL replacement //#region Video Weaver URL replacement
/** /**

View File

@ -36,6 +36,7 @@ export interface UsherManifest {
replacementMap: Map<string, string> | null; // Same as above, but with new URLs. replacementMap: Map<string, string> | null; // Same as above, but with new URLs.
consecutiveMidrollResponses: number; // Used to avoid infinite loops. consecutiveMidrollResponses: number; // Used to avoid infinite loops.
consecutiveMidrollCooldown: number; // Used to avoid infinite loops. consecutiveMidrollCooldown: number; // Used to avoid infinite loops.
deleted: boolean; // Deletion flag for cleanup.
} }
export interface PlaybackAccessToken { export interface PlaybackAccessToken {

View File

@ -79,13 +79,10 @@ export const enum MessageType {
EnableFullMode = "TLP_EnableFullMode", EnableFullMode = "TLP_EnableFullMode",
EnableFullModeResponse = "TLP_EnableFullModeResponse", EnableFullModeResponse = "TLP_EnableFullModeResponse",
DisableFullMode = "TLP_DisableFullMode", DisableFullMode = "TLP_DisableFullMode",
ChannelSubStatusQuery = "TLP_ChannelSubStatusQuery",
ChannelSubStatusQueryResponse = "TLP_ChannelSubStatusQueryResponse",
ChannelSubStatusChange = "TLP_ChannelSubStatusChange",
ChannelSubStatusChangeResponse = "TLP_ChannelSubStatusChangeResponse",
UsherResponse = "TLP_UsherResponse", UsherResponse = "TLP_UsherResponse",
NewPlaybackAccessToken = "TLP_NewPlaybackAccessToken", NewPlaybackAccessToken = "TLP_NewPlaybackAccessToken",
NewPlaybackAccessTokenResponse = "TLP_NewPlaybackAccessTokenResponse", NewPlaybackAccessTokenResponse = "TLP_NewPlaybackAccessTokenResponse",
ChannelSubStatusChange = "TLP_ChannelSubStatusChange",
MultipleAdBlockersInUse = "TLP_MultipleAdBlockersInUse", MultipleAdBlockersInUse = "TLP_MultipleAdBlockersInUse",
ClearStats = "TLP_ClearStats", ClearStats = "TLP_ClearStats",
} }