diff --git a/dist/better-xcloud.pretty.user.js b/dist/better-xcloud.pretty.user.js index b1daede..97e8430 100644 --- a/dist/better-xcloud.pretty.user.js +++ b/dist/better-xcloud.pretty.user.js @@ -5186,8 +5186,7 @@ class PatcherUtils { var LOG_TAG2 = "Patcher", PATCHES = { disableAiTrack(str) { let text = ".track=function(", index = str.indexOf(text); - if (index < 0) return !1; - if (PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) return !1; + if (index < 0 || PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) return !1; return PatcherUtils.replaceWith(str, index, text, ".track=function(e){},!!function("); }, disableTelemetry(str) { @@ -5734,32 +5733,32 @@ ${subsVar} = subs; ] : [], "exposeReactCreateComponent", "injectCreatePortal", - "injectGuideHomeUseEffect", - "injectHeaderUseEffect", - "injectErrorPageUseEffect", - "injectAchievementsProgressUseEffect", - "injectAchievementsDetailUseEffect", - "gameCardCustomIcons", + "broadcastPollingMode", + getGlobalPref("ui.gameCard.waitTime.show") && "patchSetCurrentFocus", + "patchGamepadPolling", + "optimizeGameSlugGenerator", + "modifyPreloadedState", + "detectBrowserRouterReady", + "exposeStreamSession", + "supportLocalCoOp", + "disableStreamGate", + "exposeDialogRoutes", ...getGlobalPref("ui.imageQuality") < 90 ? [ "setImageQuality" ] : [], - "modifyPreloadedState", - "optimizeGameSlugGenerator", - "detectBrowserRouterReady", "patchRequestInfoCrash", - "disableStreamGate", - "broadcastPollingMode", - "patchGamepadPolling", - "exposeStreamSession", - "exposeDialogRoutes", - "homePageBeforeLoad", - "productDetailPageBeforeLoad", + "injectErrorPageUseEffect", "streamPageBeforeLoad", + "injectGuideHomeUseEffect", + "injectAchievementsProgressUseEffect", + "injectAchievementsDetailUseEffect", "guideAchievementsDefaultLocked", + "injectHeaderUseEffect", + "homePageBeforeLoad", + "gameCardCustomIcons", + "productDetailPageBeforeLoad", "enableTvRoutes", - "supportLocalCoOp", "overrideStorageGetSettings", - getGlobalPref("ui.gameCard.waitTime.show") && "patchSetCurrentFocus", getGlobalPref("ui.layout") !== "default" && "websiteLayout", getGlobalPref("game.fortnite.forceConsole") && "forceFortniteConsole", ...STATES.userAgent.capabilities.touch ? [ @@ -5773,11 +5772,11 @@ ${subsVar} = subs; "disableTelemetryProvider" ] : [], ...getGlobalPref("xhome.enabled") ? [ - "remotePlayKeepAlive", "remotePlayDirectConnectUrl", + "remotePlayKeepAlive", + "remotePlayWebTitle", "remotePlayDisableAchievementToast", "remotePlayRecentlyUsedTitleIds", - "remotePlayWebTitle", STATES.userAgent.capabilities.touch && "patchUpdateInputConfigurationAsync" ] : [], ...BX_FLAGS.EnableXcloudLogging ? [ @@ -5785,16 +5784,14 @@ ${subsVar} = subs; "enableXcloudLogger" ] : [] ]), hideSections = getGlobalPref("ui.hideSections"), HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ - hideSections.includes("news") && "ignoreNewsSection", - (getGlobalPref("block.features").includes("friends") || hideSections.includes("friends")) && "ignorePlayWithFriendsSection", - hideSections.includes("all-games") && "ignoreAllGamesSection", hideSections.includes("genres") && "ignoreGenresSection", !getGlobalPref("block.features").includes("byog") && hideSections.includes("byog") && "ignoreByogSection", STATES.browser.capabilities.touch && hideSections.includes("touch") && "ignorePlayWithTouchSection", + getGlobalPref("ui.imageQuality") < 90 && "setBackgroundImageQuality", hideSections.some((value) => ["native-mkb", "most-popular"].includes(value)) && "ignoreSiglSections", - ...getGlobalPref("ui.imageQuality") < 90 ? [ - "setBackgroundImageQuality" - ] : [], + hideSections.includes("news") && "ignoreNewsSection", + (getGlobalPref("block.features").includes("friends") || hideSections.includes("friends")) && "ignorePlayWithFriendsSection", + hideSections.includes("all-games") && "ignoreAllGamesSection", ...blockSomeNotifications() ? [ "changeNotificationsSubscription" ] : [] diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js index 7f9731b..e93ad48 100755 --- a/dist/better-xcloud.user.js +++ b/dist/better-xcloud.user.js @@ -206,7 +206,7 @@ var vibration_adjust_default = `if(e?.gamepad?.connected){let gamepadSettings=wi var stream_hud_default = `var options=arguments[0];window.BX_EXPOSED.showStreamMenu=options.onShowStreamMenu;options.guideUI=null;window.BX_EXPOSED.reactUseEffect(()=>{window.BxEventBus.Stream.emit("ui.streamHud.rendered",{expanded:options.offset.x===0})});`; var create_portal_default = `var $dom=arguments[1];if($dom&&$dom instanceof HTMLElement&&$dom.id==="gamepass-dialog-root"){let showing=!1,$dialog=$dom.firstElementChild?.firstElementChild;if($dialog)showing=!$dialog.className.includes("pageChangeExit");window.BxEventBus.Script.emit(showing?"dialog.shown":"dialog.dismissed",{})}`; class PatcherUtils {static indexOf(txt, searchString, startIndex, maxRange = 0, after = !1) {if (startIndex < 0) return -1;let index = txt.indexOf(searchString, startIndex);if (index < 0 || maxRange && index - startIndex > maxRange) return -1;return after ? index + searchString.length : index;}static lastIndexOf(txt, searchString, startIndex, maxRange = 0, after = !1) {if (startIndex < 0) return -1;let index = txt.lastIndexOf(searchString, startIndex);if (index < 0 || maxRange && startIndex - index > maxRange) return -1;return after ? index + searchString.length : index;}static insertAt(txt, index, insertString) {return txt.substring(0, index) + insertString + txt.substring(index);}static replaceWith(txt, index, fromString, toString) {return txt.substring(0, index) + toString + txt.substring(index + fromString.length);}static filterPatches(patches) {return patches.filter((item2) => !!item2);}static patchBeforePageLoad(str, page) {let text = `chunkName:()=>"${page}-page",`;if (!str.includes(text)) return !1;return str = str.replace("requireAsync(e){", `requireAsync(e){window.BX_EXPOSED.beforePageLoad("${page}");`), str = str.replace("requireSync(e){", `requireSync(e){window.BX_EXPOSED.beforePageLoad("${page}");`), str;}static isVarCharacter(char) {let code = char.charCodeAt(0), isUppercase = code >= 65 && code <= 90, isLowercase = code >= 97 && code <= 122, isDigit = code >= 48 && code <= 57;return isUppercase || isLowercase || isDigit || (char === "_" || char === "$");}static getVariableNameBefore(str, index) {if (index < 0) return null;let end = index, start = end - 1;while (PatcherUtils.isVarCharacter(str[start]))start -= 1;return str.substring(start + 1, end);}static getVariableNameAfter(str, index) {if (index < 0) return null;let start = index, end = start + 1;while (PatcherUtils.isVarCharacter(str[end]))end += 1;return str.substring(start, end);}static injectUseEffect(str, index, group, eventName) {let newCode = `window.BX_EXPOSED.reactUseEffect(() => window.BxEventBus.${group}.emit('${eventName}', {}), []);`;return str = PatcherUtils.insertAt(str, index, newCode), str;}} -var LOG_TAG2 = "Patcher", PATCHES = {disableAiTrack(str) {let text = ".track=function(", index = str.indexOf(text);if (index < 0) return !1;if (PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) return !1;return PatcherUtils.replaceWith(str, index, text, ".track=function(e){},!!function(");},disableTelemetry(str) {let text = ".disableTelemetry=function(){return!1}";if (!str.includes(text)) return !1;return str.replace(text, ".disableTelemetry=function(){return!0}");},disableTelemetryProvider(str) {let text = "this.enableLightweightTelemetry=!";if (!str.includes(text)) return !1;let newCode = ["this.trackEvent","this.trackPageView","this.trackHttpCompleted","this.trackHttpFailed","this.trackError","this.trackErrorLike","this.onTrackEvent","()=>{}"].join("=");return str.replace(text, newCode + ";" + text);},disableIndexDbLogging(str) {let text = ",this.logsDb=new";if (!str.includes(text)) return !1;let newCode = ",this.log=()=>{}";return str.replace(text, newCode + text);},websiteLayout(str) {let text = '?"tv":"default"';if (!str.includes(text)) return !1;let layout = getGlobalPref("ui.layout") === "tv" ? "tv" : "default";return str.replace(text, `?"${layout}":"${layout}"`);},remotePlayDirectConnectUrl(str) {let index = str.indexOf("/direct-connect");if (index < 0) return !1;return str.replace(str.substring(index - 9, index + 15), "https://www.xbox.com/play");},remotePlayKeepAlive(str) {let text = "onServerDisconnectMessage(e){";if (!str.includes(text)) return !1;return str = str.replace(text, text + remote_play_keep_alive_default), str;},remotePlayConnectMode(str) {let text = 'connectMode:"cloud-connect",';if (!str.includes(text)) return !1;let newCode = `connectMode: window.BX_REMOTE_PLAY_CONFIG ? "xhome-connect" : "cloud-connect", +var LOG_TAG2 = "Patcher", PATCHES = {disableAiTrack(str) {let text = ".track=function(", index = str.indexOf(text);if (index < 0 || PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) return !1;return PatcherUtils.replaceWith(str, index, text, ".track=function(e){},!!function(");},disableTelemetry(str) {let text = ".disableTelemetry=function(){return!1}";if (!str.includes(text)) return !1;return str.replace(text, ".disableTelemetry=function(){return!0}");},disableTelemetryProvider(str) {let text = "this.enableLightweightTelemetry=!";if (!str.includes(text)) return !1;let newCode = ["this.trackEvent","this.trackPageView","this.trackHttpCompleted","this.trackHttpFailed","this.trackError","this.trackErrorLike","this.onTrackEvent","()=>{}"].join("=");return str.replace(text, newCode + ";" + text);},disableIndexDbLogging(str) {let text = ",this.logsDb=new";if (!str.includes(text)) return !1;let newCode = ",this.log=()=>{}";return str.replace(text, newCode + text);},websiteLayout(str) {let text = '?"tv":"default"';if (!str.includes(text)) return !1;let layout = getGlobalPref("ui.layout") === "tv" ? "tv" : "default";return str.replace(text, `?"${layout}":"${layout}"`);},remotePlayDirectConnectUrl(str) {let index = str.indexOf("/direct-connect");if (index < 0) return !1;return str.replace(str.substring(index - 9, index + 15), "https://www.xbox.com/play");},remotePlayKeepAlive(str) {let text = "onServerDisconnectMessage(e){";if (!str.includes(text)) return !1;return str = str.replace(text, text + remote_play_keep_alive_default), str;},remotePlayConnectMode(str) {let text = 'connectMode:"cloud-connect",';if (!str.includes(text)) return !1;let newCode = `connectMode: window.BX_REMOTE_PLAY_CONFIG ? "xhome-connect" : "cloud-connect", remotePlayServerId: (window.BX_REMOTE_PLAY_CONFIG && window.BX_REMOTE_PLAY_CONFIG.serverId) || '',`;return str.replace(text, newCode);},remotePlayDisableAchievementToast(str) {let text = ".AchievementUnlock:{";if (!str.includes(text)) return !1;let newCode = "if (!!window.BX_REMOTE_PLAY_CONFIG) return;";return str.replace(text, text + newCode);},remotePlayRecentlyUsedTitleIds(str) {let text = "(e.data.recentlyUsedTitleIds)){";if (!str.includes(text)) return !1;let newCode = "if (window.BX_REMOTE_PLAY_CONFIG) return;";return str.replace(text, text + newCode);},remotePlayWebTitle(str) {let text = "titleTemplate:void 0,title:", index = str.indexOf(text);if (index < 0) return !1;return str = PatcherUtils.insertAt(str, index + text.length, `!!window.BX_REMOTE_PLAY_CONFIG ? "${t("remote-play")} - Better xCloud" :`), str;},blockWebRtcStatsCollector(str) {let text = "this.shouldCollectStats=!0";if (!str.includes(text)) return !1;return str.replace(text, "this.shouldCollectStats=!1");},patchPollGamepads(str) {let index = str.indexOf("},this.pollGamepads=()=>{");if (index < 0) return !1;let setTimeoutIndex = str.indexOf("setTimeout(this.pollGamepads", index);if (setTimeoutIndex < 0) return !1;let codeBlock = str.substring(index, setTimeoutIndex), tmp = str.substring(setTimeoutIndex, setTimeoutIndex + 150), tmpPatched = tmp.replaceAll("Math.max(0,4-", "Math.max(0,window.BX_STREAM_SETTINGS.controllerPollingRate - ");if (str = PatcherUtils.replaceWith(str, setTimeoutIndex, tmp, tmpPatched), getGlobalPref("block.tracking")) codeBlock = codeBlock.replace("this.inputPollingIntervalStats.addValue", ""), codeBlock = codeBlock.replace("this.inputPollingDurationStats.addValue", "");let match = codeBlock.match(/this\.gamepadTimestamps\.set\(([A-Za-z0-9_$]+)\.index/);if (!match) return !1;let newCode = renderString(poll_gamepad_default, {gamepadVar: match[1]});if (codeBlock = codeBlock.replace("this.gamepadTimestamps.set", newCode + "this.gamepadTimestamps.set"), match = codeBlock.match(/let ([A-Za-z0-9_$]+)=this\.gamepadMappings\.find/), !match) return !1;let xCloudGamepadVar = match[1], inputFeedbackManager = PatcherUtils.indexOf(codeBlock, "this.inputFeedbackManager.onGamepadConnected(", 0, 1e4), backetIndex = PatcherUtils.indexOf(codeBlock, "}", inputFeedbackManager, 100);if (backetIndex < 0) return !1;let customizationCode = ";";return customizationCode += renderString(controller_customization_default, { xCloudGamepadVar }), codeBlock = PatcherUtils.insertAt(codeBlock, backetIndex, customizationCode), str = str.substring(0, index) + codeBlock + str.substring(setTimeoutIndex), str;},enableXcloudLogger(str) {let text = "this.telemetryProvider=e}log(e,t,r){";if (!str.includes(text)) return !1;let newCode = ` const [logTag, logLevel, logMessage] = Array.from(arguments); const logFunc = [console.debug, console.log, console.warn, console.error][logLevel]; @@ -246,8 +246,8 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) {const settings = let subs = ${subsVar}; subs = subs.filter(val => !${JSON.stringify(filters)}.includes(val)); ${subsVar} = subs; -`;return str = PatcherUtils.insertAt(str, index, newCode), str;},exposeReactCreateComponent(str) {let index = str.indexOf(".prototype.isReactComponent={}");if (index > -1 && (index = PatcherUtils.indexOf(str, ".createElement=", index)), index < 0) return !1;if (str = PatcherUtils.insertAt(str, index - 1, "window.BX_EXPOSED.reactCreateElement="), index = PatcherUtils.indexOf(str, ".useEffect=", index), index < 0) return !1;return str = PatcherUtils.insertAt(str, index - 1, "window.BX_EXPOSED.reactUseEffect="), str;},gameCardCustomIcons(str) {let initialIndex = str.indexOf("const{supportedInputIcons:");if (initialIndex < 0) return !1;let returnIndex = PatcherUtils.lastIndexOf(str, "return ", str.indexOf("SupportedInputsBadge"));if (returnIndex < 0) return !1;let arrowIndex = PatcherUtils.lastIndexOf(str, "=>{", initialIndex, 300);if (arrowIndex < 0) return !1;let paramVar = PatcherUtils.getVariableNameBefore(str, arrowIndex), supportedInputIconsVar = PatcherUtils.getVariableNameAfter(str, PatcherUtils.indexOf(str, "supportedInputIcons:", initialIndex, 100, !0));if (!paramVar || !supportedInputIconsVar) return !1;let newCode = renderString(game_card_icons_default, {param: paramVar,supportedInputIcons: supportedInputIconsVar});return str = PatcherUtils.insertAt(str, returnIndex, newCode), str;},setImageQuality(str) {let index = str.indexOf("const{size:{width:");if (index > -1 && (index = PatcherUtils.indexOf(str, "=new URLSearchParams", index, 500)), index < 0) return !1;let paramVar = PatcherUtils.getVariableNameBefore(str, index);if (!paramVar) return !1;index = PatcherUtils.indexOf(str, "return", index, 200);let newCode = `${paramVar}.set('q', ${getGlobalPref("ui.imageQuality")});`;return str = PatcherUtils.insertAt(str, index, newCode), str;},setBackgroundImageQuality(str) {let index = str.indexOf("}?w=${");if (index > -1 && (index = PatcherUtils.indexOf(str, "}", index + 1, 10, !0)), index < 0) return !1;return str = PatcherUtils.insertAt(str, index, `&q=${getGlobalPref("ui.imageQuality")}`), str;},injectHeaderUseEffect(str) {let index = str.indexOf('"EdgewaterHeader-module__spaceBetween');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 300)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.header.rendered");},injectErrorPageUseEffect(str) {let index = str.indexOf('"PureErrorPage-module__container');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.error.rendered");},injectStreamMenuUseEffect(str) {let index = str.indexOf('"StreamMenu-module__container');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Stream", "ui.streamMenu.rendered");},injectGuideHomeUseEffect(str) {let index = str.indexOf('"HomeLandingPage-module__authenticatedContentContainer');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideHome.rendered");},injectCreatePortal(str) {let index = str.indexOf(".createPortal=function");if (index > -1 && (index = PatcherUtils.indexOf(str, "{", index, 50, !0)), index < 0) return !1;return str = PatcherUtils.insertAt(str, index, create_portal_default), str;},injectAchievementsProgressUseEffect(str) {let index = str.indexOf('"AchievementsButton-module__progressBarContainer');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideAchievementProgress.rendered");},injectAchievementsDetailUseEffect(str) {let index = str.indexOf("GuideAchievementDetail.useParams()");if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "const", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideAchievementDetail.rendered");}}, PATCH_ORDERS = PatcherUtils.filterPatches([...AppInterface && getGlobalPref("nativeMkb.mode") === "on" ? ["enableNativeMkb","disableAbsoluteMouse"] : [],"exposeReactCreateComponent","injectCreatePortal","injectGuideHomeUseEffect","injectHeaderUseEffect","injectErrorPageUseEffect","injectAchievementsProgressUseEffect","injectAchievementsDetailUseEffect","gameCardCustomIcons",...getGlobalPref("ui.imageQuality") < 90 ? ["setImageQuality"] : [],"modifyPreloadedState","optimizeGameSlugGenerator","detectBrowserRouterReady","patchRequestInfoCrash","disableStreamGate","broadcastPollingMode","patchGamepadPolling","exposeStreamSession","exposeDialogRoutes","homePageBeforeLoad","productDetailPageBeforeLoad","streamPageBeforeLoad","guideAchievementsDefaultLocked","enableTvRoutes","supportLocalCoOp","overrideStorageGetSettings",getGlobalPref("ui.gameCard.waitTime.show") && "patchSetCurrentFocus",getGlobalPref("ui.layout") !== "default" && "websiteLayout",getGlobalPref("game.fortnite.forceConsole") && "forceFortniteConsole",...STATES.userAgent.capabilities.touch ? ["disableTouchContextMenu"] : [],...getGlobalPref("block.tracking") ? ["disableAiTrack","disableTelemetry","blockWebRtcStatsCollector","disableIndexDbLogging","disableTelemetryProvider"] : [],...getGlobalPref("xhome.enabled") ? ["remotePlayKeepAlive","remotePlayDirectConnectUrl","remotePlayDisableAchievementToast","remotePlayRecentlyUsedTitleIds","remotePlayWebTitle",STATES.userAgent.capabilities.touch && "patchUpdateInputConfigurationAsync"] : [],...BX_FLAGS.EnableXcloudLogging ? ["enableConsoleLogging","enableXcloudLogger"] : [] -]), hideSections = getGlobalPref("ui.hideSections"), HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([hideSections.includes("news") && "ignoreNewsSection",(getGlobalPref("block.features").includes("friends") || hideSections.includes("friends")) && "ignorePlayWithFriendsSection",hideSections.includes("all-games") && "ignoreAllGamesSection",hideSections.includes("genres") && "ignoreGenresSection",!getGlobalPref("block.features").includes("byog") && hideSections.includes("byog") && "ignoreByogSection",STATES.browser.capabilities.touch && hideSections.includes("touch") && "ignorePlayWithTouchSection",hideSections.some((value) => ["native-mkb", "most-popular"].includes(value)) && "ignoreSiglSections",...getGlobalPref("ui.imageQuality") < 90 ? ["setBackgroundImageQuality"] : [],...blockSomeNotifications() ? ["changeNotificationsSubscription"] : [] +`;return str = PatcherUtils.insertAt(str, index, newCode), str;},exposeReactCreateComponent(str) {let index = str.indexOf(".prototype.isReactComponent={}");if (index > -1 && (index = PatcherUtils.indexOf(str, ".createElement=", index)), index < 0) return !1;if (str = PatcherUtils.insertAt(str, index - 1, "window.BX_EXPOSED.reactCreateElement="), index = PatcherUtils.indexOf(str, ".useEffect=", index), index < 0) return !1;return str = PatcherUtils.insertAt(str, index - 1, "window.BX_EXPOSED.reactUseEffect="), str;},gameCardCustomIcons(str) {let initialIndex = str.indexOf("const{supportedInputIcons:");if (initialIndex < 0) return !1;let returnIndex = PatcherUtils.lastIndexOf(str, "return ", str.indexOf("SupportedInputsBadge"));if (returnIndex < 0) return !1;let arrowIndex = PatcherUtils.lastIndexOf(str, "=>{", initialIndex, 300);if (arrowIndex < 0) return !1;let paramVar = PatcherUtils.getVariableNameBefore(str, arrowIndex), supportedInputIconsVar = PatcherUtils.getVariableNameAfter(str, PatcherUtils.indexOf(str, "supportedInputIcons:", initialIndex, 100, !0));if (!paramVar || !supportedInputIconsVar) return !1;let newCode = renderString(game_card_icons_default, {param: paramVar,supportedInputIcons: supportedInputIconsVar});return str = PatcherUtils.insertAt(str, returnIndex, newCode), str;},setImageQuality(str) {let index = str.indexOf("const{size:{width:");if (index > -1 && (index = PatcherUtils.indexOf(str, "=new URLSearchParams", index, 500)), index < 0) return !1;let paramVar = PatcherUtils.getVariableNameBefore(str, index);if (!paramVar) return !1;index = PatcherUtils.indexOf(str, "return", index, 200);let newCode = `${paramVar}.set('q', ${getGlobalPref("ui.imageQuality")});`;return str = PatcherUtils.insertAt(str, index, newCode), str;},setBackgroundImageQuality(str) {let index = str.indexOf("}?w=${");if (index > -1 && (index = PatcherUtils.indexOf(str, "}", index + 1, 10, !0)), index < 0) return !1;return str = PatcherUtils.insertAt(str, index, `&q=${getGlobalPref("ui.imageQuality")}`), str;},injectHeaderUseEffect(str) {let index = str.indexOf('"EdgewaterHeader-module__spaceBetween');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 300)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.header.rendered");},injectErrorPageUseEffect(str) {let index = str.indexOf('"PureErrorPage-module__container');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.error.rendered");},injectStreamMenuUseEffect(str) {let index = str.indexOf('"StreamMenu-module__container');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Stream", "ui.streamMenu.rendered");},injectGuideHomeUseEffect(str) {let index = str.indexOf('"HomeLandingPage-module__authenticatedContentContainer');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideHome.rendered");},injectCreatePortal(str) {let index = str.indexOf(".createPortal=function");if (index > -1 && (index = PatcherUtils.indexOf(str, "{", index, 50, !0)), index < 0) return !1;return str = PatcherUtils.insertAt(str, index, create_portal_default), str;},injectAchievementsProgressUseEffect(str) {let index = str.indexOf('"AchievementsButton-module__progressBarContainer');if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "return", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideAchievementProgress.rendered");},injectAchievementsDetailUseEffect(str) {let index = str.indexOf("GuideAchievementDetail.useParams()");if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "const", index, 200)), index < 0) return !1;return PatcherUtils.injectUseEffect(str, index, "Script", "ui.guideAchievementDetail.rendered");}}, PATCH_ORDERS = PatcherUtils.filterPatches([...AppInterface && getGlobalPref("nativeMkb.mode") === "on" ? ["enableNativeMkb","disableAbsoluteMouse"] : [],"exposeReactCreateComponent","injectCreatePortal","broadcastPollingMode",getGlobalPref("ui.gameCard.waitTime.show") && "patchSetCurrentFocus","patchGamepadPolling","optimizeGameSlugGenerator","modifyPreloadedState","detectBrowserRouterReady","exposeStreamSession","supportLocalCoOp","disableStreamGate","exposeDialogRoutes",...getGlobalPref("ui.imageQuality") < 90 ? ["setImageQuality"] : [],"patchRequestInfoCrash","injectErrorPageUseEffect","streamPageBeforeLoad","injectGuideHomeUseEffect","injectAchievementsProgressUseEffect","injectAchievementsDetailUseEffect","guideAchievementsDefaultLocked","injectHeaderUseEffect","homePageBeforeLoad","gameCardCustomIcons","productDetailPageBeforeLoad","enableTvRoutes","overrideStorageGetSettings",getGlobalPref("ui.layout") !== "default" && "websiteLayout",getGlobalPref("game.fortnite.forceConsole") && "forceFortniteConsole",...STATES.userAgent.capabilities.touch ? ["disableTouchContextMenu"] : [],...getGlobalPref("block.tracking") ? ["disableAiTrack","disableTelemetry","blockWebRtcStatsCollector","disableIndexDbLogging","disableTelemetryProvider"] : [],...getGlobalPref("xhome.enabled") ? ["remotePlayDirectConnectUrl","remotePlayKeepAlive","remotePlayWebTitle","remotePlayDisableAchievementToast","remotePlayRecentlyUsedTitleIds",STATES.userAgent.capabilities.touch && "patchUpdateInputConfigurationAsync"] : [],...BX_FLAGS.EnableXcloudLogging ? ["enableConsoleLogging","enableXcloudLogger"] : [] +]), hideSections = getGlobalPref("ui.hideSections"), HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([hideSections.includes("genres") && "ignoreGenresSection",!getGlobalPref("block.features").includes("byog") && hideSections.includes("byog") && "ignoreByogSection",STATES.browser.capabilities.touch && hideSections.includes("touch") && "ignorePlayWithTouchSection",getGlobalPref("ui.imageQuality") < 90 && "setBackgroundImageQuality",hideSections.some((value) => ["native-mkb", "most-popular"].includes(value)) && "ignoreSiglSections",hideSections.includes("news") && "ignoreNewsSection",(getGlobalPref("block.features").includes("friends") || hideSections.includes("friends")) && "ignorePlayWithFriendsSection",hideSections.includes("all-games") && "ignoreAllGamesSection",...blockSomeNotifications() ? ["changeNotificationsSubscription"] : [] ]), STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches(["exposeInputChannel","patchXcloudTitleInfo","disableGamepadDisconnectedScreen","patchStreamHud","playVibration","alwaysShowStreamHud","injectStreamMenuUseEffect",getGlobalPref("audio.volume.booster.enabled") && !getGlobalPref("stream.video.combineAudio") && "patchAudioMediaStream",getGlobalPref("audio.volume.booster.enabled") && getGlobalPref("stream.video.combineAudio") && "patchCombinedAudioVideoMediaStream",getGlobalPref("ui.feedbackDialog.disabled") && "skipFeedbackDialog",...STATES.userAgent.capabilities.touch ? [getGlobalPref("touchController.mode") === "all" && "patchShowSensorControls",getGlobalPref("touchController.mode") === "all" && "exposeTouchLayoutManager",(getGlobalPref("touchController.mode") === "off" || getGlobalPref("touchController.autoOff")) && "disableTakRenderer",getGlobalPref("touchController.opacity.default") !== 100 && "patchTouchControlDefaultOpacity",getGlobalPref("touchController.mode") !== "off" && (getGlobalPref("mkb.enabled") || getGlobalPref("nativeMkb.mode") === "on") && "patchBabylonRendererClass"] : [],BX_FLAGS.EnableXcloudLogging && "enableConsoleLogging","patchPollGamepads",getGlobalPref("stream.video.combineAudio") && "streamCombineSources",...getGlobalPref("xhome.enabled") ? ["patchRemotePlayMkb","remotePlayConnectMode"] : [],...AppInterface && getGlobalPref("nativeMkb.mode") === "on" ? ["patchMouseAndKeyboardEnabled","disableNativeRequestPointerLock"] : [] ]), PRODUCT_DETAIL_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches(["detectProductDetailPage" ]), ALL_PATCHES = [...PATCH_ORDERS, ...HOME_PAGE_PATCH_ORDERS, ...STREAM_PAGE_PATCH_ORDERS, ...PRODUCT_DETAIL_PAGE_PATCH_ORDERS]; diff --git a/src/modules/patcher/patcher-utils.ts b/src/modules/patcher/patcher-utils.ts index 1bea174..83237a1 100644 --- a/src/modules/patcher/patcher-utils.ts +++ b/src/modules/patcher/patcher-utils.ts @@ -1,3 +1,4 @@ +import type { ScriptEvents, StreamEvents } from "@/utils/bx-event-bus"; import type { PatchArray, PatchName, PatchPage } from "./patcher"; export class PatcherUtils { @@ -35,7 +36,7 @@ export class PatcherUtils { return txt.substring(0, index) + toString + txt.substring(index + fromString.length); } - static filterPatches(patches: Array): PatchArray { + static filterPatches(patches: Array): PatchArray { return patches.filter((item): item is PatchName => !!item); } @@ -97,7 +98,7 @@ export class PatcherUtils { return str.substring(start, end); } - static injectUseEffect(str: string, index: number, group: 'Stream' | 'Script', eventName: string) { + static injectUseEffect(str: string, index: number, group: T, eventName: T extends 'Stream' ? keyof StreamEvents : keyof ScriptEvents) { const newCode = `window.BX_EXPOSED.reactUseEffect(() => window.BxEventBus.${group}.emit('${eventName}', {}), []);`; str = PatcherUtils.insertAt(str, index, newCode); diff --git a/src/modules/patcher/patcher.ts b/src/modules/patcher/patcher.ts index 13fc771..ebf22fe 100755 --- a/src/modules/patcher/patcher.ts +++ b/src/modules/patcher/patcher.ts @@ -23,6 +23,7 @@ import { PatcherUtils } from "./patcher-utils.js"; export type PatchName = keyof typeof PATCHES; export type PatchArray = PatchName[]; export type PatchPage = 'home' | 'stream' | 'product-detail'; +type PatchFunction = (str: string) => string | false; const LOG_TAG = 'Patcher'; @@ -31,11 +32,7 @@ const PATCHES = { disableAiTrack(str: string) { let text = '.track=function('; const index = str.indexOf(text); - if (index < 0) { - return false; - } - - if (PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) { + if (index < 0 || PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) { return false; } @@ -1204,62 +1201,95 @@ ${subsVar} = subs; return PatcherUtils.injectUseEffect(str, index, 'Script', 'ui.guideAchievementDetail.rendered'); }, -}; + + /* + patchBasicGameInfo(str: string) { + let index = str.indexOf('.ChildXboxTitleIds,offerings'); + index > -1 && (index = PatcherUtils.lastIndexOf(str, 'return{', index, 1000)); + if (index < 0) { + return false; + } + + const varName = PatcherUtils.getVariableNameBefore(str, PatcherUtils.lastIndexOf(str, '=>{', index)); + if (!varName) { + return false; + } + + const newCode = ` +const info = ${varName}; +if (info.ProductTitle.includes('Xbox One')) { + return {}; +} +`; + str = PatcherUtils.insertAt(str, index, newCode); + return str; + }, + */ +} as const satisfies { [key: string]: PatchFunction }; let PATCH_ORDERS = PatcherUtils.filterPatches([ ...(AppInterface && getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [ 'enableNativeMkb', 'disableAbsoluteMouse', - ] : []), + ] : []) as PatchArray, 'exposeReactCreateComponent', 'injectCreatePortal', - 'injectGuideHomeUseEffect', - 'injectHeaderUseEffect', + + 'broadcastPollingMode', + + getGlobalPref(GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME) && 'patchSetCurrentFocus', + + 'patchGamepadPolling', + + 'optimizeGameSlugGenerator', + + 'modifyPreloadedState', + + 'detectBrowserRouterReady', + + 'exposeStreamSession', + 'supportLocalCoOp', + + 'disableStreamGate', + + 'exposeDialogRoutes', + + ...(getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 ? [ + 'setImageQuality', + ] : []) as PatchArray, + + 'patchRequestInfoCrash', + 'injectErrorPageUseEffect', + + 'streamPageBeforeLoad', + + 'injectGuideHomeUseEffect', 'injectAchievementsProgressUseEffect', 'injectAchievementsDetailUseEffect', + 'guideAchievementsDefaultLocked', + + 'injectHeaderUseEffect', + + 'homePageBeforeLoad', 'gameCardCustomIcons', // 'gameCardPassTitle', - ...(getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 ? [ - 'setImageQuality', - ] : []), - - 'modifyPreloadedState', - - 'optimizeGameSlugGenerator', - - 'detectBrowserRouterReady', - 'patchRequestInfoCrash', - - 'disableStreamGate', - 'broadcastPollingMode', - 'patchGamepadPolling', - - 'exposeStreamSession', - 'exposeDialogRoutes', - - 'homePageBeforeLoad', 'productDetailPageBeforeLoad', - 'streamPageBeforeLoad', - - 'guideAchievementsDefaultLocked', 'enableTvRoutes', - 'supportLocalCoOp', 'overrideStorageGetSettings', - getGlobalPref(GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME) && 'patchSetCurrentFocus', getGlobalPref(GlobalPref.UI_LAYOUT) !== UiLayout.DEFAULT && 'websiteLayout', getGlobalPref(GlobalPref.GAME_FORTNITE_FORCE_CONSOLE) && 'forceFortniteConsole', ...(STATES.userAgent.capabilities.touch ? [ 'disableTouchContextMenu', - ] : []), + ] : []) as PatchArray, ...(getGlobalPref(GlobalPref.BLOCK_TRACKING) ? [ 'disableAiTrack', @@ -1269,41 +1299,41 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([ 'disableIndexDbLogging', 'disableTelemetryProvider', - ] : []), + ] : []) as PatchArray, ...(getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED) ? [ - 'remotePlayKeepAlive', 'remotePlayDirectConnectUrl', + 'remotePlayKeepAlive', + 'remotePlayWebTitle', 'remotePlayDisableAchievementToast', 'remotePlayRecentlyUsedTitleIds', - 'remotePlayWebTitle', STATES.userAgent.capabilities.touch && 'patchUpdateInputConfigurationAsync', - ] : []), + ] : []) as PatchArray, ...(BX_FLAGS.EnableXcloudLogging ? [ 'enableConsoleLogging', 'enableXcloudLogger', - ] : []), + ] : []) as PatchArray, ]); const hideSections = getGlobalPref(GlobalPref.UI_HIDE_SECTIONS); let HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ - hideSections.includes(UiSection.NEWS) && 'ignoreNewsSection', - (getGlobalPref(GlobalPref.BLOCK_FEATURES).includes(BlockFeature.FRIENDS) || hideSections.includes(UiSection.FRIENDS)) && 'ignorePlayWithFriendsSection', - hideSections.includes(UiSection.ALL_GAMES) && 'ignoreAllGamesSection', hideSections.includes(UiSection.GENRES) && 'ignoreGenresSection', !getGlobalPref(GlobalPref.BLOCK_FEATURES).includes(BlockFeature.BYOG) && hideSections.includes(UiSection.BOYG) && 'ignoreByogSection', STATES.browser.capabilities.touch && hideSections.includes(UiSection.TOUCH) && 'ignorePlayWithTouchSection', + + getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 && 'setBackgroundImageQuality', + hideSections.some(value => [UiSection.NATIVE_MKB, UiSection.MOST_POPULAR].includes(value)) && 'ignoreSiglSections', - ...(getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 ? [ - 'setBackgroundImageQuality', - ] : []), + hideSections.includes(UiSection.NEWS) && 'ignoreNewsSection', + (getGlobalPref(GlobalPref.BLOCK_FEATURES).includes(BlockFeature.FRIENDS) || hideSections.includes(UiSection.FRIENDS)) && 'ignorePlayWithFriendsSection', + hideSections.includes(UiSection.ALL_GAMES) && 'ignoreAllGamesSection', ...(blockSomeNotifications() ? [ 'changeNotificationsSubscription', - ] : []), + ] : []) as PatchArray, ]); // Only when playing @@ -1335,7 +1365,7 @@ let STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF || getGlobalPref(GlobalPref.TOUCH_CONTROLLER_AUTO_OFF)) && 'disableTakRenderer', getGlobalPref(GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY) !== 100 && 'patchTouchControlDefaultOpacity', (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.OFF && (getGlobalPref(GlobalPref.MKB_ENABLED) || getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON)) && 'patchBabylonRendererClass', - ] : []), + ] : []) as PatchArray, BX_FLAGS.EnableXcloudLogging && 'enableConsoleLogging', @@ -1346,13 +1376,13 @@ let STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ ...(getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED) ? [ 'patchRemotePlayMkb', 'remotePlayConnectMode', - ] : []), + ] : []) as PatchArray, // Native MKB ...(AppInterface && getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [ 'patchMouseAndKeyboardEnabled', 'disableNativeRequestPointerLock', - ] : []), + ] : []) as PatchArray, ]); let PRODUCT_DETAIL_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ diff --git a/src/utils/bx-event-bus.ts b/src/utils/bx-event-bus.ts index 1662c45..4105451 100644 --- a/src/utils/bx-event-bus.ts +++ b/src/utils/bx-event-bus.ts @@ -7,7 +7,7 @@ import type { SpeakerState } from "@/modules/shortcuts/sound-shortcut"; type EventCallback = (payload: T) => void; -type ScriptEvents = { +export type ScriptEvents = { 'xcloud.server': { status: 'ready' | 'unavailable' | 'signed-out', }; @@ -44,7 +44,7 @@ type ScriptEvents = { 'ui.guideAchievementDetail.rendered': {}, }; -type StreamEvents = { +export type StreamEvents = { 'state.loading': {}; 'state.starting': {}; 'state.playing': { $video?: HTMLVideoElement };