Compare commits

...

6 Commits

Author SHA1 Message Date
b4149e718b Bump version to 2.0.4 2023-12-06 20:06:41 +07:00
7c22685e95 Update README.md 2023-12-05 14:50:32 +07:00
ad98eb60e1 Only call eval() once per patch group 2023-12-05 06:38:35 +07:00
049e65429a Fix not applying patches correctly 2023-12-03 16:36:02 +07:00
a5b77ae8c0 Improve Patcher class 2023-12-03 10:38:10 +07:00
49550eed0a Add "enableXcloudLogger" patch 2023-12-02 17:31:51 +07:00
3 changed files with 107 additions and 32 deletions

View File

@ -1,5 +1,5 @@
# Better xCloud
Improve [Xbox Cloud Gaming (xCloud)](https://www.xbox.com/play/) experience on web browser.
Improve Xbox Cloud Gaming (xCloud) experience on [xbox.com/play](https://www.xbox.com/play).
The main target of this script is mobile users, but it should work great on desktop too.
Supported platforms:

View File

@ -1,5 +1,5 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
// @version 2.0.3
// @version 2.0.4
// ==/UserScript==

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
// @version 2.0.3
// @version 2.0.4
// @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx
// @license MIT
@ -13,10 +13,11 @@
// ==/UserScript==
'use strict';
const SCRIPT_VERSION = '2.0.3';
const SCRIPT_VERSION = '2.0.4';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_MKB = false;
const ENABLE_XCLOUD_LOGGER = false;
console.log(`[Better xCloud] readyState: ${document.readyState}`);
@ -4304,30 +4305,21 @@ class Patcher {
return funcStr.replace(funcStr.substring(index - 9, index + 15), 'https://www.xbox.com/play');
},
// Disable trackEvent() function
disableTrackEvent: PREFS.get(Preferences.BLOCK_TRACKING) && function(funcStr) {
const text = 'this.trackEvent=';
if (!funcStr.includes(text)) {
return false;
}
return funcStr.replace(text, 'this.trackEvent=e=>{},this.uwuwu=');
},
remotePlayKeepAlive: PREFS.get(Preferences.REMOTE_PLAY_ENABLED) && function(funcStr) {
if (!funcStr.includes('onServerDisconnectMessage(e){')) {
return false;
}
funcStr = funcStr.replace('onServerDisconnectMessage(e){', `onServerDisconnectMessage (e) {
funcStr = funcStr.replace('onServerDisconnectMessage(e){', `onServerDisconnectMessage(e) {
const msg = JSON.parse(e);
if (msg.reason === 'WarningForBeingIdle') {
try {
this.sendKeepAlive();
return;
} catch (ex) {}
} catch (ex) { console.log(ex); }
}
`);
return funcStr;
},
@ -4341,6 +4333,16 @@ class Patcher {
return funcStr.replace(text, `connectMode:window.BX_REMOTE_PLAY_CONFIG?"xhome-connect":"cloud-connect",remotePlayServerId:(window.BX_REMOTE_PLAY_CONFIG&&window.BX_REMOTE_PLAY_CONFIG.serverId)||''`);
},
// Disable trackEvent() function
disableTrackEvent: PREFS.get(Preferences.BLOCK_TRACKING) && function(funcStr) {
const text = 'this.trackEvent=';
if (!funcStr.includes(text)) {
return false;
}
return funcStr.replace(text, 'this.trackEvent=e=>{},this.uwuwu=');
},
// Block WebRTC stats collector
blockWebRtcStatsCollector: PREFS.get(Preferences.BLOCK_TRACKING) && function(funcStr) {
const text = 'this.intervalMs=0,';
@ -4351,6 +4353,16 @@ class Patcher {
return funcStr.replace(text, 'false,' + text);
},
enableXcloudLogger: ENABLE_XCLOUD_LOGGER && function(funcStr) {
const text = 'if(t!==Ke.LogLevel.Error&&t!==Ke.LogLevel.Warn)';
if (!funcStr.includes(text)) {
return false;
}
funcStr = funcStr.replaceAll(text, 'console.log(arguments);' + text);
return funcStr;
},
// Enable Mouse and Keyboard support
enableMouseAndKeyboard: PREFS.get(Preferences.MKB_ENABLED) && function(funcStr) {
if (!funcStr.includes('EnableMouseAndKeyboard:')) {
@ -4366,6 +4378,26 @@ class Patcher {
},
};
static #PATCH_ORDERS = [
[
'disableAiTrack',
'disableTelemetry',
],
['tvLayout'],
[
'enableMouseAndKeyboard',
'enableXcloudLogger',
'remotePlayDirectConnectUrl',
'disableTrackEvent',
'remotePlayKeepAlive',
'blockWebRtcStatsCollector',
],
['remotePlayConnectMode'],
];
static #patchFunctionBind() {
Function.prototype.nativeBind = Function.prototype.bind;
Function.prototype.bind = function() {
@ -4400,39 +4432,82 @@ class Patcher {
};
}
static length() { return Object.keys(Patcher.#PATCHES).length };
static length() { return Patcher.#PATCH_ORDERS.length; };
static patch(item) {
let patchName;
let appliedPatches;
for (let id in item[1]) {
if (Patcher.length() <= 0) {
if (Patcher.#PATCH_ORDERS.length <= 0) {
return;
}
appliedPatches = [];
const func = item[1][id];
const funcStr = func.toString();
let funcStr = func.toString();
// Only check the first patch
if (!patchName) {
patchName = Object.keys(Patcher.#PATCHES)[0];
}
for (let groupIndex = 0; groupIndex < Patcher.#PATCH_ORDERS.length; groupIndex++) {
const group = Patcher.#PATCH_ORDERS[groupIndex];
let modified = false;
const patchedFuncStr = Patcher.#PATCHES[patchName].call(null, funcStr);
if (patchedFuncStr) {
console.log(`[Better xCloud] Applied "${patchName}" patch`);
for (let patchIndex = 0; patchIndex < group.length; patchIndex++) {
const patchName = group[patchIndex];
if (appliedPatches.indexOf(patchName) > -1) {
continue;
}
item[1][id] = eval(patchedFuncStr);
delete Patcher.#PATCHES[patchName];
patchName = null;
const patchedFuncStr = Patcher.#PATCHES[patchName].call(null, funcStr);
if (!patchedFuncStr) {
// Only stop if the first patch is failed
if (patchIndex === 0) {
break;
} else {
continue;
}
}
modified = true;
funcStr = patchedFuncStr;
console.log(`[Better xCloud] Applied "${patchName}" patch`);
appliedPatches.push(patchName);
// Remove patch from group
group.splice(patchIndex, 1);
patchIndex--;
}
// Apply patched functions
if (modified) {
item[1][id] = eval(funcStr);
}
// Remove empty group
if (!group.length) {
Patcher.#PATCH_ORDERS.splice(groupIndex, 1);
groupIndex--;
}
}
}
}
static initialize() {
// Remove disabled patches
for (const patchName in Patcher.#PATCHES) {
if (!Patcher.#PATCHES[patchName]) {
delete Patcher.#PATCHES[patchName];
for (let groupIndex = Patcher.#PATCH_ORDERS.length - 1; groupIndex >= 0; groupIndex--) {
const group = Patcher.#PATCH_ORDERS[groupIndex];
for (let patchIndex = group.length - 1; patchIndex >= 0; patchIndex--) {
const patchName = group[patchIndex];
if (!Patcher.#PATCHES[patchName]) {
// Remove disabled patch
group.splice(patchIndex, 1);
}
}
// Remove empty group
if (!group.length) {
Patcher.#PATCH_ORDERS.splice(groupIndex, 1);
}
}