Compare commits

..

8 Commits
v2.0 ... v2.0.1

3 changed files with 96 additions and 58 deletions

View File

@ -120,9 +120,7 @@ Don't see your browser in the table? If it supports Tampermonkey/Userscript then
> Hide the mouse cursor after 3 seconds of not moving.
### Controller
- Adjust controller polling rate
> Higher is better (reduce input latency).
- Enable controller shortcuts
- Enable controller shortcuts
> `Home` is the button which activates the Xbox sidebar menu (similar to the Xbox/Nexus button on the official controller).
> Not all controllers have this button. It's the `B16` button on the [Gamepad Tester site](https://hardwaretester.com/gamepad).
> More shortcuts will be added later.

View File

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

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
// @version 2.0
// @version 2.0.1
// @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx
// @license MIT
@ -13,7 +13,7 @@
// ==/UserScript==
'use strict';
const SCRIPT_VERSION = '2.0';
const SCRIPT_VERSION = '2.0.1';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_MKB = false;
@ -441,8 +441,10 @@ const Translations = {
"zh-CN": "手柄",
},
"controller-polling-rate": {
"de-DE": "Controller-Abfragerate",
"en-US": "Controller polling rate",
"ja-JP": "コントローラーポーリングレート",
"pl-PL": "Częstotliwości raportowania kontrolera",
"pt-BR": "Taxa de consulta do controle",
"tr-TR": "Oyun kumandası işlem hızı",
"vi-VN": "Tần suất cập nhật của bộ điều khiển",
@ -592,8 +594,10 @@ const Translations = {
"zh-CN": "游戏启动时打开麦克风",
},
"enable-mkb": {
"de-DE": "Maus- und Tastaturunterstützung aktivieren",
"en-US": "Enable Mouse & Keyboard support",
"ja-JP": "マウス&キーボードのサポートを有効化",
"pl-PL": "Włącz obsługę myszy i klawiatury",
"tr-TR": "Klavye ve fare desteğini aktive et",
"vi-VN": "Kích hoạt hỗ trợ Chuột & Bàn phím",
},
@ -612,6 +616,14 @@ const Translations = {
"vi-VN": "Bật chế độ \"Xem nhanh\"",
"zh-CN": "仅在打开设置时显示统计信息",
},
"enable-remote-play-feature": {
"de-DE": "\"Remote Play\" Funktion aktivieren",
"en-US": "Enable the \"Remote Play\" feature",
"ja-JP": "リモートプレイ機能を有効化",
"pl-PL": "Włącz funkcję \"Gra zdalna\"",
"tr-TR": "\"Uzaktan Oynama\" özelliğini aktive et",
"vi-VN": "Bật tính năng \"Chơi từ xa\"",
},
"enable-volume-control": {
"de-DE": "Lautstärkeregelung aktivieren",
"en-US": "Enable volume control feature",
@ -627,8 +639,10 @@ const Translations = {
"zh-CN": "启用音量控制",
},
"fast": {
"de-DE": "Schnell",
"en-US": "Fast",
"ja-JP": "高速",
"pl-PL": "Szybko",
"tr-TR": "Hızlı",
"vi-VN": "Nhanh",
},
@ -703,8 +717,10 @@ const Translations = {
"zh-CN": "大",
},
"layout": {
"de-DE": "Layout",
"en-US": "Layout",
"ja-JP": "レイアウト",
"pl-PL": "Układ",
"pt-BR": "Layout",
"tr-TR": "Arayüz Görünümü",
"vi-VN": "Bố cục",
@ -725,14 +741,18 @@ const Translations = {
"zh-CN": "载入画面",
},
"max-bitrate": {
"de-DE": "Max. Bitrate",
"en-US": "Max bitrate",
"ja-JP": "最大ビットレート",
"pl-PL": "Maksymalny bitrate",
"tr-TR": "Maksimum bithızı",
"vi-VN": "Bitrate tối đa",
},
"may-not-work-properly": {
"de-DE": "Funktioniert evtl. nicht fehlerfrei!",
"en-US": "May not work properly!",
"ja-JP": "正常に動作しない場合があります!",
"pl-PL": "Może nie działać poprawnie!",
"tr-TR": "Düzgün çalışmayabilir!",
"vi-VN": "Có thể không hoạt động!",
},
@ -778,8 +798,10 @@ const Translations = {
"zh-CN": "麦克风",
},
"mouse-and-keyboard": {
"de-DE": "Maus & Tastatur",
"en-US": "Mouse & Keyboard",
"ja-JP": "マウス&キーボード",
"pl-PL": "Mysz i klawiatura",
"tr-TR": "Klavye ve Fare",
"vi-VN": "Chuột và Bàn phím",
},
@ -846,9 +868,11 @@ const Translations = {
"vi-VN": "Bật",
"zh-CN": "开启",
},
"only-support-some-games": {
"en-US": "Only support some games",
"only-supports-some-games": {
"de-DE": "Unterstützt nur einige Spiele",
"en-US": "Only supports some games",
"ja-JP": "一部のゲームのみサポート",
"pl-PL": "Wspiera tylko niektóre gry",
"tr-TR": "Yalnızca belli oyunlar destekleniyor",
"vi-VN": "Chỉ hỗ trợ một vài game",
},
@ -901,7 +925,7 @@ const Translations = {
"de-DE": "Ausgeschaltet",
"en-US": "Powered off",
"it-IT": "Spento",
"ja-JP": "電源オフ",
"ja-JP": "本体オフ",
"pl-PL": "Zasilanie wyłączone",
"pt-BR": "Desligado",
"tr-TR": "Kapalı",
@ -912,7 +936,7 @@ const Translations = {
"de-DE": "Eingeschaltet",
"en-US": "Powered on",
"it-IT": "Acceso",
"ja-JP": "電源オン",
"ja-JP": "本体オン",
"pl-PL": "Zasilanie włączone",
"pt-BR": "Ligado",
"tr-TR": "Açık",
@ -1231,8 +1255,10 @@ const Translations = {
"zh-CN": "跳过 Xbox 启动动画",
},
"slow": {
"de-DE": "Langsam",
"en-US": "Slow",
"ja-JP": "低速",
"pl-PL": "Wolno",
"tr-TR": "Yavaş",
"vi-VN": "Chậm",
},
@ -1252,8 +1278,10 @@ const Translations = {
"zh-CN": "小",
},
"smart-tv": {
"de-DE": "Smart TV",
"en-US": "Smart TV",
"ja-JP": "スマートTV",
"pl-PL": "Smart TV",
"pt-BR": "Smart TV",
"tr-TR": "Akıllı TV",
"vi-VN": "TV thông minh",
@ -1652,8 +1680,10 @@ const Translations = {
"zh-CN": "未知",
},
"unlimited": {
"de-DE": "Unbegrenzt",
"en-US": "Unlimited",
"ja-JP": "無制限",
"pl-PL": "Bez ograniczeń",
"tr-TR": "Limitsiz",
"vi-VN": "Không giới hạn",
},
@ -1669,8 +1699,10 @@ const Translations = {
"zh-CN": "已取消静音",
},
"use-mouse-absolute-position": {
"de-DE": "Absolute Position der Maus verwenden",
"en-US": "Use mouse's absolute position",
"ja-JP": "マウスの絶対座標を使用",
"pl-PL": "Użyj pozycji bezwzględnej myszy",
"tr-TR": "Farenin mutlak pozisyonunu baz al",
"vi-VN": "Sử dụng vị trí tuyệt đối của chuột",
},
@ -2074,18 +2106,11 @@ class RemotePlay {
RemotePlay.#$content.parentElement.replaceChild($fragment, RemotePlay.#$content);
}
static #onLoad() {
const CE = createElement;
const $ui = CE('div', {'class': 'bx-container'},
CE('h2', {}, __('remote-play')),
CE('div', {'id': 'bxUi'}, __('getting-consoles-list')),
);
const $landingPageHeader = document.querySelector('h2[class*=LandingPage-module__header]');
$landingPageHeader.parentElement.insertBefore($ui, $landingPageHeader);
}
static detect() {
if (!PREFS.get(Preferences.REMOTE_PLAY_ENABLED)) {
return;
}
IS_REMOTE_PLAYING = window.location.pathname.includes('/launch/') && window.location.hash.startsWith('#remote-play');
if (IS_REMOTE_PLAYING) {
window.BX_REMOTE_PLAY_CONFIG = REMOTE_PLAY_CONFIG;
@ -3276,7 +3301,7 @@ class PreloadedState {
return this._state;
},
set: (state) => {
set: state => {
this._state = state;
APP_CONTEXT = structuredClone(state.appContext);
@ -3322,7 +3347,6 @@ class Preferences {
static get STREAM_DISABLE_FEEDBACK_DIALOG() { return 'stream_disable_feedback_dialog'; }
static get CONTROLLER_ENABLE_SHORTCUTS() { return 'controller_enable_shortcuts'; }
static get CONTROLLER_POLLING_RATE() { return 'controller_polling_rate'; }
static get MKB_ENABLED() { return 'mkb_enabled'; }
static get MKB_ABSOLUTE_MOUSE() { return 'mkb_absolute_mouse'; }
@ -3360,6 +3384,7 @@ class Preferences {
static get STATS_OPACITY() { return 'stats_opacity'; }
static get STATS_CONDITIONAL_FORMATTING() { return 'stats_conditional_formatting'; }
static get REMOTE_PLAY_ENABLED() { return 'xhome_enabled'; }
static get REMOTE_PLAY_RESOLUTION() { return 'xhome_resolution'; }
// Deprecated
@ -3553,15 +3578,6 @@ class Preferences {
[Preferences.CONTROLLER_ENABLE_SHORTCUTS]: {
'default': false,
},
[Preferences.CONTROLLER_POLLING_RATE]: {
'type': 'number',
'default': 50,
'options': {
16: '62.5 Hz (16ms)',
32: '31.25 Hz (32ms)',
50: `20 Hz (50ms - ${__('default')})`,
},
},
[Preferences.MKB_ENABLED]: {
'default': false,
@ -3707,6 +3723,10 @@ class Preferences {
'default': false,
},
[Preferences.REMOTE_PLAY_ENABLED]: {
'default': false,
},
[Preferences.REMOTE_PLAY_RESOLUTION]: {
'default': 1080,
'options': {
@ -4033,36 +4053,24 @@ const PREFS = new Preferences();
class Patcher {
static #PATCHES = {
// Modify controller polling rate
controllerPollingRate: (PREFS.get(Preferences.CONTROLLER_POLLING_RATE) !== 50) && function(funcStr) {
const text = '.startGamepadPolling=()';
const index = funcStr.indexOf(text);
if (index === -1) {
return false;
}
const patchedStr = funcStr.substring(index, index + 100).replace(/setInterval\((\w+),(\d+)\)/, `setInterval($1,${PREFS.get(Preferences.CONTROLLER_POLLING_RATE)})`);
return funcStr.substring(0, index) + patchedStr + funcStr.substring(index + 100);
},
// Enable Remote Play feature
connectMode: function(funcStr) {
remotePlayConnectMode: PREFS.get(Preferences.REMOTE_PLAY_ENABLED) && function(funcStr) {
const text = 'connectMode:"cloud-connect"';
if (!funcStr.includes(text)) {
return false;
}
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||''`);
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)||''`);
},
// Replace "/direct-connect" with "/play"
directConnectUrl: function(funcStr) {
remotePlayDirectConnectUrl: PREFS.get(Preferences.REMOTE_PLAY_ENABLED) && function(funcStr) {
const index = funcStr.indexOf('/direct-connect');
if (index === -1) {
return false;
}
return funcStr.replace(funcStr.substring(index - 9, index + 15), '/play');
return funcStr.replace(funcStr.substring(index - 9, index + 15), 'https://www.xbox.com/play');
},
// Set disableTelemetry() to true
@ -4085,6 +4093,31 @@ class Patcher {
return funcStr.replace(text, 'this.trackEvent=e=>{},this.uwuwu=');
},
// Disable ApplicationInsights.track() function
disableAiTrack: PREFS.get(Preferences.BLOCK_TRACKING) && function(funcStr) {
const text = '.track=function(';
const index = funcStr.indexOf(text);
if (index === -1) {
return false;
}
if (funcStr.substring(0, index + 200).includes('"AppInsightsCore')) {
return false;
}
return funcStr.substring(0, index) + '.track=function(e){},!!function(' + funcStr.substring(index + text.length);
},
// Block WebRTC stats collector
blockWebRtcStatsCollector: PREFS.get(Preferences.BLOCK_TRACKING) && function(funcStr) {
const text = 'this.intervalMs=0,';
if (!funcStr.includes(text)) {
return false;
}
return funcStr.replace(text, 'false,' + text);
},
// Set TV layout
tvLayout: PREFS.get(Preferences.UI_LAYOUT) === 'tv' && function(funcStr) {
const text = '?"tv":"default"';
@ -4107,7 +4140,7 @@ class Patcher {
}
return funcStr;
}
},
};
static #patchFunctionBind() {
@ -5620,6 +5653,7 @@ function injectSettingsButton($parent) {
const CE = createElement;
const PREF_PREFERRED_REGION = getPreferredServerRegion();
const PREF_LATEST_VERSION = PREFS.get(Preferences.LATEST_VERSION);
const PREF_REMOTE_PLAY_ENABLED = PREFS.get(Preferences.REMOTE_PLAY_ENABLED);
// Setup Settings button
const $button = CE('button', {'class': 'bx-settings-button'}, PREF_PREFERRED_REGION);
@ -5643,7 +5677,7 @@ function injectSettingsButton($parent) {
});
let $updateAvailable;
let $remotePlayLink;
let $remotePlayBtn;
const $wrapper = CE('div', {'class': 'bx-settings-wrapper'},
CE('div', {'class': 'bx-settings-title-wrapper'},
CE('a', {
@ -5651,7 +5685,7 @@ function injectSettingsButton($parent) {
'href': SCRIPT_HOME,
'target': '_blank',
}, 'Better xCloud ' + SCRIPT_VERSION),
$remotePlayLink = CE('button', {'class': 'bx-primary-button bx-no-margin'}, __('remote-play')),
$remotePlayBtn = CE('button', {'class': 'bx-primary-button bx-no-margin'}, __('remote-play')),
)
);
$updateAvailable = CE('a', {
@ -5660,12 +5694,17 @@ function injectSettingsButton($parent) {
'target': '_blank',
});
$remotePlayLink.addEventListener('click', e => {
RemotePlay.showDialog();
if (PREF_REMOTE_PLAY_ENABLED) {
$remotePlayBtn.addEventListener('click', e => {
RemotePlay.showDialog();
// Hide Settings
$container.classList.add('bx-gone');
});
} else {
$remotePlayBtn.classList.add('bx-gone');
}
// Hide Settings
$container.classList.add('bx-gone');
});
$wrapper.appendChild($updateAvailable);
// Show new version indicator
@ -5678,6 +5717,7 @@ function injectSettingsButton($parent) {
const SETTINGS_UI = {
'Better xCloud': {
[Preferences.BETTER_XCLOUD_LOCALE]: __('language'),
[Preferences.REMOTE_PLAY_ENABLED]: __('enable-remote-play-feature'),
},
[__('server')]: {
[Preferences.SERVER_REGION]: __('region'),
@ -5694,7 +5734,6 @@ function injectSettingsButton($parent) {
[Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: __('disable-post-stream-feedback-dialog'),
},
[__('controller')]: {
[Preferences.CONTROLLER_POLLING_RATE]: __('controller-polling-rate'),
[Preferences.CONTROLLER_ENABLE_SHORTCUTS]: __('enable-controller-shortcuts'),
},
[__('touch-controller')]: {
@ -5705,7 +5744,7 @@ function injectSettingsButton($parent) {
[__('mouse-and-keyboard')]: {
'_note': '⚠️ ' + __('may-not-work-properly'),
[Preferences.MKB_ENABLED]: [__('enable-mkb'), __('only-support-some-games')],
[Preferences.MKB_ENABLED]: [__('enable-mkb'), __('only-supports-some-games')],
[Preferences.MKB_ABSOLUTE_MOUSE]: __('use-mouse-absolute-position'),
},
@ -6623,4 +6662,5 @@ if (PREFS.get(Preferences.CONTROLLER_ENABLE_SHORTCUTS)) {
}
Patcher.initialize();
RemotePlay.detect();