mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-29 02:41:44 +02:00
Compare commits
2 Commits
v6.7.0
...
typescript
Author | SHA1 | Date | |
---|---|---|---|
59e72582c3 | |||
1e4294746c |
8
dist/better-xcloud.pretty.user.js
vendored
8
dist/better-xcloud.pretty.user.js
vendored
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 6.7.0
|
||||
// @version 6.7.1-beta
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -194,7 +194,7 @@ class UserAgent {
|
||||
});
|
||||
}
|
||||
}
|
||||
var SCRIPT_VERSION = "6.7.0", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||
var SCRIPT_VERSION = "6.7.1-beta", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||
UserAgent.init();
|
||||
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, STATES = {
|
||||
supportedRegion: !0,
|
||||
@ -5192,8 +5192,8 @@ class PatcherUtils {
|
||||
}
|
||||
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;
|
||||
let text = ".track=function(", index = str.indexOf('"AppInsightsCore.initialize"');
|
||||
if (index > -1 && (index = PatcherUtils.indexOf(str, '"AppInsightsCore.track"', index)), index > -1 && (index = PatcherUtils.lastIndexOf(str, text, index, 300)), index < 0) return !1;
|
||||
return PatcherUtils.replaceWith(str, index, text, ".track=function(e){},!!function(");
|
||||
},
|
||||
disableTelemetryProvider(str) {
|
||||
|
6
dist/better-xcloud.user.js
vendored
6
dist/better-xcloud.user.js
vendored
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 6.7.0
|
||||
// @version 6.7.1-beta
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -26,7 +26,7 @@ var ALL_PREFS = {global: ["audio.mic.onPlaying","audio.volume.booster.enabled","
|
||||
var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "125.0.0.0";
|
||||
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);if (match) CHROMIUM_VERSION = match[1];}
|
||||
class UserAgent {static STORAGE_KEY = "BetterXcloud.UserAgent";static #config;static #isMobile = null;static #isSafari = null;static #isSafariMobile = null;static #USER_AGENTS = {"windows-edge": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROMIUM_VERSION} Safari/537.36 Edg/${CHROMIUM_VERSION}`,"macos-safari": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.1","smarttv-generic": `${window.navigator.userAgent} Smart-TV`,"smarttv-tizen": `Mozilla/5.0 (SMART-TV; LINUX; Tizen 7.0) AppleWebKit/537.36 (KHTML, like Gecko) ${CHROMIUM_VERSION}/7.0 TV Safari/537.36 ${SMART_TV_UNIQUE_ID}`,"vr-oculus": window.navigator.userAgent + " OculusBrowser VR"};static init() {if (UserAgent.#config = JSON.parse(window.localStorage.getItem(UserAgent.STORAGE_KEY) || "{}"), !UserAgent.#config.profile) UserAgent.#config.profile = BX_FLAGS.DeviceInfo.deviceType === "android-tv" || BX_FLAGS.DeviceInfo.deviceType === "webos" ? "vr-oculus" : "default";if (!UserAgent.#config.custom) UserAgent.#config.custom = "";UserAgent.spoof();}static updateStorage(profile, custom) {let config = UserAgent.#config;if (config.profile = profile, profile === "custom" && typeof custom !== "undefined") config.custom = custom;window.localStorage.setItem(UserAgent.STORAGE_KEY, JSON.stringify(config));}static getDefault() {return window.navigator.orgUserAgent || window.navigator.userAgent;}static get(profile) {let defaultUserAgent = window.navigator.userAgent;switch (profile) {case "default":return defaultUserAgent;case "custom":return UserAgent.#config.custom || defaultUserAgent;default:return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;}}static isSafari() {if (this.#isSafari !== null) return this.#isSafari;let userAgent = UserAgent.getDefault().toLowerCase(), result = userAgent.includes("safari") && !userAgent.includes("chrom");return this.#isSafari = result, result;}static isSafariMobile() {if (this.#isSafariMobile !== null) return this.#isSafariMobile;let userAgent = UserAgent.getDefault().toLowerCase(), result = this.isSafari() && userAgent.includes("mobile");return this.#isSafariMobile = result, result;}static isMobile() {if (this.#isMobile !== null) return this.#isMobile;let userAgent = UserAgent.getDefault().toLowerCase(), result = /iphone|ipad|android/.test(userAgent);return this.#isMobile = result, result;}static spoof() {let profile = UserAgent.#config.profile;if (profile === "default") return;let newUserAgent = UserAgent.get(profile);if ("userAgentData" in window.navigator) window.navigator.orgUserAgentData = window.navigator.userAgentData, Object.defineProperty(window.navigator, "userAgentData", {});window.navigator.orgUserAgent = window.navigator.userAgent, Object.defineProperty(window.navigator, "userAgent", {value: newUserAgent});}}
|
||||
var SCRIPT_VERSION = "6.7.0", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||
var SCRIPT_VERSION = "6.7.1-beta", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||
UserAgent.init();
|
||||
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, STATES = {supportedRegion: !0,serverRegions: {},selectedRegion: {},gsToken: "",isSignedIn: !1,isPlaying: !1,browser: {capabilities: {touch: browserHasTouchSupport,batteryApi: "getBattery" in window.navigator,deviceVibration: !!window.navigator.vibrate,mkb: AppInterface || !UserAgent.getDefault().toLowerCase().match(/(android|iphone|ipad)/),emulatedNativeMkb: !!AppInterface}},userAgent: {isTv,capabilities: {touch: userAgentHasTouchSupport,mkb: AppInterface || !userAgent.match(/(android|iphone|ipad)/)}},currentStream: {},remotePlay: {},pointerServerPort: 9269};
|
||||
function deepClone(obj) {if (!obj) return {};if ("structuredClone" in window) return structuredClone(obj);return JSON.parse(JSON.stringify(obj));}
|
||||
@ -157,7 +157,7 @@ var vibration_adjust_default = `if(e?.gamepad?.connected){let gamepadSettings=wi
|
||||
var stream_hud_default = `window.BX_EXPOSED.showStreamMenu=$onShowStreamMenu$;$guideUI$=null;window.BX_EXPOSED.reactUseEffect(()=>{window.BxEventBus.Stream.emit("ui.streamHud.rendered",{expanded:$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 replaceAfterIndex(txt, search, replaceWith, index) {let before = txt.slice(0, index), after = txt.slice(index).replace(search, replaceWith);return before + after;}static filterPatches(patches) {return patches.filter((item2) => !!item2);}static patchBeforePageLoad(str, page) {let index = str.indexOf(`chunkName:()=>"${page}-page",`);if (index < 0) return !1;return str = PatcherUtils.replaceAfterIndex(str, "requireAsync(e){", `requireAsync(e){window.BX_EXPOSED.beforePageLoad("${page}");`, index), str = PatcherUtils.replaceAfterIndex(str, "requireSync(e){", `requireSync(e){window.BX_EXPOSED.beforePageLoad("${page}");`, index), 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, separator = ";") {let newCode = `window.BX_EXPOSED.reactUseEffect(() => window.BxEventBus.${group}.emit('${eventName}', {}), [])${separator}`;return str = PatcherUtils.insertAt(str, index, newCode), str;}static findAndParseParams(str, index, maxRange) {let substr = str.substring(index, index + maxRange), startIndex = substr.indexOf("({");if (startIndex < 0) return !1;startIndex += 1;let endIndex = substr.indexOf("})", startIndex);if (endIndex < 0) return !1;endIndex += 1;try {let input = substr.substring(startIndex, endIndex);return PatcherUtils.parseObjectVariables(input);} catch {return null;}}static parseObjectVariables(input) {try {let pairs = [...input.matchAll(/(\w+)\s*:\s*([a-zA-Z_$][\w$]*)/g)], result = {};for (let [_, key, value] of pairs)result[key] = value;return result;} catch {return null;}}}
|
||||
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(");},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}"`);},remotePlayPostStreamRedirectUrl(str) {let text = ".RemotePlayRoot.getLink()):";if (!str.includes(text)) return !1;return str = str.replace(text, ".Home.getLink()):"), str;},remotePlayKeepAlive(str) {let text = "onServerDisconnectMessage(e){";if (!str.includes(text)) return !1;return str = str.replace(text, text + remote_play_keep_alive_default), str;},remotePlayDisableAchievementToast(str) {let text = ".AchievementUnlock:{";if (!str.includes(text)) return !1;let newCode = "if (window.location.pathname.includes('/play/consoles/launch/')) return;";return str.replace(text, text + newCode);},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 index = str.indexOf("this.telemetryProvider.trackErrorLike");if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "}log(", index, 1500)), index > -1 && (index = PatcherUtils.indexOf(str, "{", index, 30, !0)), index < 0) return !1;let newCode = `
|
||||
var LOG_TAG2 = "Patcher", PATCHES = {disableAiTrack(str) {let text = ".track=function(", index = str.indexOf('"AppInsightsCore.initialize"');if (index > -1 && (index = PatcherUtils.indexOf(str, '"AppInsightsCore.track"', index)), index > -1 && (index = PatcherUtils.lastIndexOf(str, text, index, 300)), index < 0) return !1;return PatcherUtils.replaceWith(str, index, text, ".track=function(e){},!!function(");},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}"`);},remotePlayPostStreamRedirectUrl(str) {let text = ".RemotePlayRoot.getLink()):";if (!str.includes(text)) return !1;return str = str.replace(text, ".Home.getLink()):"), str;},remotePlayKeepAlive(str) {let text = "onServerDisconnectMessage(e){";if (!str.includes(text)) return !1;return str = str.replace(text, text + remote_play_keep_alive_default), str;},remotePlayDisableAchievementToast(str) {let text = ".AchievementUnlock:{";if (!str.includes(text)) return !1;let newCode = "if (window.location.pathname.includes('/play/consoles/launch/')) return;";return str.replace(text, text + newCode);},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 index = str.indexOf("this.telemetryProvider.trackErrorLike");if (index > -1 && (index = PatcherUtils.lastIndexOf(str, "}log(", index, 1500)), index > -1 && (index = PatcherUtils.indexOf(str, "{", index, 30, !0)), index < 0) return !1;let newCode = `
|
||||
const [logTag, logLevel, logMessage] = Array.from(arguments);
|
||||
const logFunc = [console.debug, console.log, console.warn, console.error][logLevel];
|
||||
logFunc(logTag, '//', logMessage);
|
||||
|
@ -30,8 +30,10 @@ const PATCHES = {
|
||||
// Disable ApplicationInsights.track() function
|
||||
disableAiTrack(str: string) {
|
||||
let text = '.track=function(';
|
||||
const index = str.indexOf(text);
|
||||
if (index < 0 || PatcherUtils.indexOf(str, '"AppInsightsCore', index, 200) < 0) {
|
||||
let index = str.indexOf('"AppInsightsCore.initialize"');
|
||||
(index > -1) && (index = PatcherUtils.indexOf(str, '"AppInsightsCore.track"', index));
|
||||
(index > -1) && (index = PatcherUtils.lastIndexOf(str, text, index, 300));
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ export abstract class BaseCanvasPlayer extends BaseStreamPlayer {
|
||||
const $video = this.$video;
|
||||
frameCallback = $video.requestVideoFrameCallback.bind($video);
|
||||
} else {
|
||||
frameCallback = requestAnimationFrame;
|
||||
frameCallback = window.requestAnimationFrame.bind(window);
|
||||
}
|
||||
|
||||
this.frameCallback = frameCallback;
|
||||
|
Reference in New Issue
Block a user