Compare commits

...

13 Commits
v2.0 ... v2.0.2

3 changed files with 145 additions and 68 deletions

View File

@ -67,7 +67,7 @@ Don't see your browser in the table? If it supports Tampermonkey/Userscript then
## Features ## Features
<img width="400" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/70b754fa-a638-4d02-bd05-0a3bdf5e1fcd"> <img width="400" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/ca38b3fa-1e89-4b37-937c-a6796c07cdf1">
<br> <br>
<img width="400" alt="Remote Play dialog" src="https://github.com/redphx/better-xcloud/assets/96280/daf7f698-a228-4f9c-8f23-9669e061a64c"> <img width="400" alt="Remote Play dialog" src="https://github.com/redphx/better-xcloud/assets/96280/daf7f698-a228-4f9c-8f23-9669e061a64c">
<br> <br>
@ -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. > Hide the mouse cursor after 3 seconds of not moving.
### Controller ### Controller
- Adjust controller polling rate - Enable controller shortcuts
> Higher is better (reduce input latency).
- Enable controller shortcuts
> `Home` is the button which activates the Xbox sidebar menu (similar to the Xbox/Nexus button on the official controller). > `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). > 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. > More shortcuts will be added later.

View File

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

View File

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Better xCloud // @name Better xCloud
// @namespace https://github.com/redphx // @namespace https://github.com/redphx
// @version 2.0 // @version 2.0.2
// @description Improve Xbox Cloud Gaming (xCloud) experience // @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx // @author redphx
// @license MIT // @license MIT
@ -13,7 +13,7 @@
// ==/UserScript== // ==/UserScript==
'use strict'; 'use strict';
const SCRIPT_VERSION = '2.0'; const SCRIPT_VERSION = '2.0.2';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud'; const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_MKB = false; const ENABLE_MKB = false;
@ -311,6 +311,7 @@ const Translations = {
"can-stream-xbox-360-games": { "can-stream-xbox-360-games": {
"de-DE": "Kann Xbox 360 Spiele streamen", "de-DE": "Kann Xbox 360 Spiele streamen",
"en-US": "Can stream Xbox 360 games", "en-US": "Can stream Xbox 360 games",
"es-ES": "Puede transmitir juegos de Xbox 360",
"it-IT": "Puoi riprodurre i giochi Xbox 360", "it-IT": "Puoi riprodurre i giochi Xbox 360",
"ja-JP": "Xbox 360ゲームのストリーミング可能", "ja-JP": "Xbox 360ゲームのストリーミング可能",
"pl-PL": "Można strumieniować gry Xbox 360", "pl-PL": "Można strumieniować gry Xbox 360",
@ -321,6 +322,7 @@ const Translations = {
"cant-stream-xbox-360-games": { "cant-stream-xbox-360-games": {
"de-DE": "Kann Xbox 360 Spiele nicht streamen", "de-DE": "Kann Xbox 360 Spiele nicht streamen",
"en-US": "Can't stream Xbox 360 games", "en-US": "Can't stream Xbox 360 games",
"es-ES": "No puede transmitir juegos de Xbox 360",
"it-IT": "Impossibile riprodurre i giochi Xbox 360", "it-IT": "Impossibile riprodurre i giochi Xbox 360",
"ja-JP": "Xbox 360ゲームのストリーミング不可", "ja-JP": "Xbox 360ゲームのストリーミング不可",
"pl-PL": "Nie można strumieniować gier Xbox 360", "pl-PL": "Nie można strumieniować gier Xbox 360",
@ -406,6 +408,7 @@ const Translations = {
"console-connect": { "console-connect": {
"de-DE": "Verbinden", "de-DE": "Verbinden",
"en-US": "Connect", "en-US": "Connect",
"es-ES": "Conectar",
"it-IT": "Connetti", "it-IT": "Connetti",
"ja-JP": "本体に接続", "ja-JP": "本体に接続",
"pl-PL": "Połącz", "pl-PL": "Połącz",
@ -432,6 +435,7 @@ const Translations = {
"controller": { "controller": {
"de-DE": "Controller", "de-DE": "Controller",
"en-US": "Controller", "en-US": "Controller",
"es-ES": "Joystick",
"it-IT": "Controller", "it-IT": "Controller",
"ja-JP": "コントローラー", "ja-JP": "コントローラー",
"pl-PL": "Kontroler", "pl-PL": "Kontroler",
@ -441,8 +445,11 @@ const Translations = {
"zh-CN": "手柄", "zh-CN": "手柄",
}, },
"controller-polling-rate": { "controller-polling-rate": {
"de-DE": "Controller-Abfragerate",
"en-US": "Controller polling rate", "en-US": "Controller polling rate",
"es-ES": "Tasa de sondeo del Joystick",
"ja-JP": "コントローラーポーリングレート", "ja-JP": "コントローラーポーリングレート",
"pl-PL": "Częstotliwości raportowania kontrolera",
"pt-BR": "Taxa de consulta do controle", "pt-BR": "Taxa de consulta do controle",
"tr-TR": "Oyun kumandası işlem hızı", "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", "vi-VN": "Tần suất cập nhật của bộ điều khiển",
@ -568,6 +575,7 @@ const Translations = {
"enable-controller-shortcuts": { "enable-controller-shortcuts": {
"de-DE": "Controller-Shortcuts aktivieren", "de-DE": "Controller-Shortcuts aktivieren",
"en-US": "Enable controller shortcuts", "en-US": "Enable controller shortcuts",
"es-ES": "Habilitar accesos directos del Joystick",
"it-IT": "Consenti scorciatoie da controller", "it-IT": "Consenti scorciatoie da controller",
"ja-JP": "コントローラーショートカットを有効化", "ja-JP": "コントローラーショートカットを有効化",
"pl-PL": "Włącz skróty kontrolera", "pl-PL": "Włącz skróty kontrolera",
@ -592,8 +600,12 @@ const Translations = {
"zh-CN": "游戏启动时打开麦克风", "zh-CN": "游戏启动时打开麦克风",
}, },
"enable-mkb": { "enable-mkb": {
"de-DE": "Maus- und Tastaturunterstützung aktivieren",
"en-US": "Enable Mouse & Keyboard support", "en-US": "Enable Mouse & Keyboard support",
"es-ES": "Habilitar soporte para ratón y teclado",
"ja-JP": "マウス&キーボードのサポートを有効化", "ja-JP": "マウス&キーボードのサポートを有効化",
"pl-PL": "Włącz obsługę myszy i klawiatury",
"pt-BR": "Habilitar suporte ao Mouse & Teclado",
"tr-TR": "Klavye ve fare desteğini aktive et", "tr-TR": "Klavye ve fare desteğini aktive et",
"vi-VN": "Kích hoạt hỗ trợ Chuột & Bàn phím", "vi-VN": "Kích hoạt hỗ trợ Chuột & Bàn phím",
}, },
@ -612,6 +624,16 @@ const Translations = {
"vi-VN": "Bật chế độ \"Xem nhanh\"", "vi-VN": "Bật chế độ \"Xem nhanh\"",
"zh-CN": "仅在打开设置时显示统计信息", "zh-CN": "仅在打开设置时显示统计信息",
}, },
"enable-remote-play-feature": {
"de-DE": "\"Remote Play\" Funktion aktivieren",
"en-US": "Enable the \"Remote Play\" feature",
"es-ES": "Activar la función \"Reproducción remota\"",
"ja-JP": "リモートプレイ機能を有効化",
"pl-PL": "Włącz funkcję \"Gra zdalna\"",
"pt-BR": "Ativar o recurso \"Reprodução Remota\"",
"tr-TR": "\"Uzaktan Oynama\" özelliğini aktive et",
"vi-VN": "Bật tính năng \"Chơi từ xa\"",
},
"enable-volume-control": { "enable-volume-control": {
"de-DE": "Lautstärkeregelung aktivieren", "de-DE": "Lautstärkeregelung aktivieren",
"en-US": "Enable volume control feature", "en-US": "Enable volume control feature",
@ -627,14 +649,19 @@ const Translations = {
"zh-CN": "启用音量控制", "zh-CN": "启用音量控制",
}, },
"fast": { "fast": {
"de-DE": "Schnell",
"en-US": "Fast", "en-US": "Fast",
"es-ES": "Rápido",
"ja-JP": "高速", "ja-JP": "高速",
"pl-PL": "Szybko",
"pt-BR": "Rápido",
"tr-TR": "Hızlı", "tr-TR": "Hızlı",
"vi-VN": "Nhanh", "vi-VN": "Nhanh",
}, },
"getting-consoles-list": { "getting-consoles-list": {
"de-DE": "Rufe Liste der Konsolen ab...", "de-DE": "Rufe Liste der Konsolen ab...",
"en-US": "Getting the list of consoles...", "en-US": "Getting the list of consoles...",
"es-ES": "Obteniendo la lista de consolas...",
"it-IT": "Ottenere la lista delle consoles...", "it-IT": "Ottenere la lista delle consoles...",
"ja-JP": "本体のリストを取得中...", "ja-JP": "本体のリストを取得中...",
"pl-PL": "Pobieranie listy konsoli...", "pl-PL": "Pobieranie listy konsoli...",
@ -703,8 +730,11 @@ const Translations = {
"zh-CN": "大", "zh-CN": "大",
}, },
"layout": { "layout": {
"de-DE": "Layout",
"en-US": "Layout", "en-US": "Layout",
"es-ES": "Diseño",
"ja-JP": "レイアウト", "ja-JP": "レイアウト",
"pl-PL": "Układ",
"pt-BR": "Layout", "pt-BR": "Layout",
"tr-TR": "Arayüz Görünümü", "tr-TR": "Arayüz Görünümü",
"vi-VN": "Bố cục", "vi-VN": "Bố cục",
@ -725,14 +755,22 @@ const Translations = {
"zh-CN": "载入画面", "zh-CN": "载入画面",
}, },
"max-bitrate": { "max-bitrate": {
"de-DE": "Max. Bitrate",
"en-US": "Max bitrate", "en-US": "Max bitrate",
"es-ES": "Tasa de bits máxima",
"ja-JP": "最大ビットレート", "ja-JP": "最大ビットレート",
"pl-PL": "Maksymalny bitrate",
"pt-BR": "Taxa máxima dos bits",
"tr-TR": "Maksimum bithızı", "tr-TR": "Maksimum bithızı",
"vi-VN": "Bitrate tối đa", "vi-VN": "Bitrate tối đa",
}, },
"may-not-work-properly": { "may-not-work-properly": {
"de-DE": "Funktioniert evtl. nicht fehlerfrei!",
"en-US": "May not work properly!", "en-US": "May not work properly!",
"es-ES": "¡Puede que no funcione correctamente!",
"ja-JP": "正常に動作しない場合があります!", "ja-JP": "正常に動作しない場合があります!",
"pl-PL": "Może nie działać poprawnie!",
"pt-BR": "Pode não funcionar corretamente!",
"tr-TR": "Düzgün çalışmayabilir!", "tr-TR": "Düzgün çalışmayabilir!",
"vi-VN": "Có thể không hoạt động!", "vi-VN": "Có thể không hoạt động!",
}, },
@ -769,6 +807,7 @@ const Translations = {
"microphone": { "microphone": {
"de-DE": "Mikrofon", "de-DE": "Mikrofon",
"en-US": "Microphone", "en-US": "Microphone",
"es-ES": "Micrófono",
"it-IT": "Microfono", "it-IT": "Microfono",
"ja-JP": "マイク", "ja-JP": "マイク",
"pl-PL": "Mikrofon", "pl-PL": "Mikrofon",
@ -778,14 +817,19 @@ const Translations = {
"zh-CN": "麦克风", "zh-CN": "麦克风",
}, },
"mouse-and-keyboard": { "mouse-and-keyboard": {
"de-DE": "Maus & Tastatur",
"en-US": "Mouse & Keyboard", "en-US": "Mouse & Keyboard",
"es-ES": "Ratón y teclado",
"ja-JP": "マウス&キーボード", "ja-JP": "マウス&キーボード",
"pl-PL": "Mysz i klawiatura",
"pt-BR": "Mouse e Teclado",
"tr-TR": "Klavye ve Fare", "tr-TR": "Klavye ve Fare",
"vi-VN": "Chuột và Bàn phím", "vi-VN": "Chuột và Bàn phím",
}, },
"muted": { "muted": {
"de-DE": "Stumm", "de-DE": "Stumm",
"en-US": "Muted", "en-US": "Muted",
"es-ES": "Silenciado",
"it-IT": "Microfono disattivato", "it-IT": "Microfono disattivato",
"ja-JP": "ミュート", "ja-JP": "ミュート",
"pl-PL": "Wyciszony", "pl-PL": "Wyciszony",
@ -797,6 +841,7 @@ const Translations = {
"no-consoles-found": { "no-consoles-found": {
"de-DE": "Keine Konsolen gefunden", "de-DE": "Keine Konsolen gefunden",
"en-US": "No consoles found", "en-US": "No consoles found",
"es-ES": "No se encontraron consolas",
"it-IT": "Nessuna console trovata", "it-IT": "Nessuna console trovata",
"ja-JP": "本体が見つかりません", "ja-JP": "本体が見つかりません",
"pl-PL": "Nie znaleziono konsoli", "pl-PL": "Nie znaleziono konsoli",
@ -838,6 +883,7 @@ const Translations = {
"on": { "on": {
"de-DE": "An", "de-DE": "An",
"en-US": "On", "en-US": "On",
"es-ES": "Activado",
"it-IT": "Attivo", "it-IT": "Attivo",
"ja-JP": "オン", "ja-JP": "オン",
"pl-PL": "Włącz", "pl-PL": "Włącz",
@ -846,9 +892,13 @@ const Translations = {
"vi-VN": "Bật", "vi-VN": "Bật",
"zh-CN": "开启", "zh-CN": "开启",
}, },
"only-support-some-games": { "only-supports-some-games": {
"en-US": "Only support some games", "de-DE": "Unterstützt nur einige Spiele",
"en-US": "Only supports some games",
"es-ES": "Sólo soporta algunos juegos",
"ja-JP": "一部のゲームのみサポート", "ja-JP": "一部のゲームのみサポート",
"pl-PL": "Wspiera tylko niektóre gry",
"pt-BR": "Suporta apenas alguns jogos",
"tr-TR": "Yalnızca belli oyunlar destekleniyor", "tr-TR": "Yalnızca belli oyunlar destekleniyor",
"vi-VN": "Chỉ hỗ trợ một vài game", "vi-VN": "Chỉ hỗ trợ một vài game",
}, },
@ -900,8 +950,9 @@ const Translations = {
"powered-off": { "powered-off": {
"de-DE": "Ausgeschaltet", "de-DE": "Ausgeschaltet",
"en-US": "Powered off", "en-US": "Powered off",
"es-ES": "Desactivado",
"it-IT": "Spento", "it-IT": "Spento",
"ja-JP": "電源オフ", "ja-JP": "本体オフ",
"pl-PL": "Zasilanie wyłączone", "pl-PL": "Zasilanie wyłączone",
"pt-BR": "Desligado", "pt-BR": "Desligado",
"tr-TR": "Kapalı", "tr-TR": "Kapalı",
@ -911,8 +962,9 @@ const Translations = {
"powered-on": { "powered-on": {
"de-DE": "Eingeschaltet", "de-DE": "Eingeschaltet",
"en-US": "Powered on", "en-US": "Powered on",
"es-ES": "Activado",
"it-IT": "Acceso", "it-IT": "Acceso",
"ja-JP": "電源オン", "ja-JP": "本体オン",
"pl-PL": "Zasilanie włączone", "pl-PL": "Zasilanie włączone",
"pt-BR": "Ligado", "pt-BR": "Ligado",
"tr-TR": "Açık", "tr-TR": "Açık",
@ -997,6 +1049,7 @@ const Translations = {
"remote-play": { "remote-play": {
"de-DE": "Remote Play", "de-DE": "Remote Play",
"en-US": "Remote Play", "en-US": "Remote Play",
"es-ES": "Reproducción remota",
"it-IT": "Riproduzione Remota", "it-IT": "Riproduzione Remota",
"ja-JP": "リモートプレイ", "ja-JP": "リモートプレイ",
"pl-PL": "Gra zdalna", "pl-PL": "Gra zdalna",
@ -1231,8 +1284,12 @@ const Translations = {
"zh-CN": "跳过 Xbox 启动动画", "zh-CN": "跳过 Xbox 启动动画",
}, },
"slow": { "slow": {
"de-DE": "Langsam",
"en-US": "Slow", "en-US": "Slow",
"es-ES": "Lento",
"ja-JP": "低速", "ja-JP": "低速",
"pl-PL": "Wolno",
"pt-BR": "Lento",
"tr-TR": "Yavaş", "tr-TR": "Yavaş",
"vi-VN": "Chậm", "vi-VN": "Chậm",
}, },
@ -1252,8 +1309,11 @@ const Translations = {
"zh-CN": "小", "zh-CN": "小",
}, },
"smart-tv": { "smart-tv": {
"de-DE": "Smart TV",
"en-US": "Smart TV", "en-US": "Smart TV",
"es-ES": "Smart TV",
"ja-JP": "スマートTV", "ja-JP": "スマートTV",
"pl-PL": "Smart TV",
"pt-BR": "Smart TV", "pt-BR": "Smart TV",
"tr-TR": "Akıllı TV", "tr-TR": "Akıllı TV",
"vi-VN": "TV thông minh", "vi-VN": "TV thông minh",
@ -1261,6 +1321,7 @@ const Translations = {
"sound": { "sound": {
"de-DE": "Ton", "de-DE": "Ton",
"en-US": "Sound", "en-US": "Sound",
"es-ES": "Sonido",
"it-IT": "Suoni", "it-IT": "Suoni",
"ja-JP": "サウンド", "ja-JP": "サウンド",
"pl-PL": "Dźwięk", "pl-PL": "Dźwięk",
@ -1272,6 +1333,7 @@ const Translations = {
"standby": { "standby": {
"de-DE": "Standby", "de-DE": "Standby",
"en-US": "Standby", "en-US": "Standby",
"es-ES": "Modo de espera",
"it-IT": "Sospendi", "it-IT": "Sospendi",
"ja-JP": "スタンバイ", "ja-JP": "スタンバイ",
"pl-PL": "Stan czuwania", "pl-PL": "Stan czuwania",
@ -1643,6 +1705,7 @@ const Translations = {
"unknown": { "unknown": {
"de-DE": "Unbekannt", "de-DE": "Unbekannt",
"en-US": "Unknown", "en-US": "Unknown",
"es-ES": "Desconocido",
"it-IT": "Sconosciuto", "it-IT": "Sconosciuto",
"ja-JP": "不明", "ja-JP": "不明",
"pl-PL": "Nieznane", "pl-PL": "Nieznane",
@ -1652,14 +1715,19 @@ const Translations = {
"zh-CN": "未知", "zh-CN": "未知",
}, },
"unlimited": { "unlimited": {
"de-DE": "Unbegrenzt",
"en-US": "Unlimited", "en-US": "Unlimited",
"es-ES": "Ilimitado",
"ja-JP": "無制限", "ja-JP": "無制限",
"pl-PL": "Bez ograniczeń",
"pt-BR": "Ilimitado",
"tr-TR": "Limitsiz", "tr-TR": "Limitsiz",
"vi-VN": "Không giới hạn", "vi-VN": "Không giới hạn",
}, },
"unmuted": { "unmuted": {
"de-DE": "Ton an", "de-DE": "Ton an",
"en-US": "Unmuted", "en-US": "Unmuted",
"es-ES": "Activar sonido",
"it-IT": "Microfono attivato", "it-IT": "Microfono attivato",
"ja-JP": "ミュート解除", "ja-JP": "ミュート解除",
"pl-PL": "Wyciszenie wyłączone", "pl-PL": "Wyciszenie wyłączone",
@ -1669,8 +1737,12 @@ const Translations = {
"zh-CN": "已取消静音", "zh-CN": "已取消静音",
}, },
"use-mouse-absolute-position": { "use-mouse-absolute-position": {
"de-DE": "Absolute Position der Maus verwenden",
"en-US": "Use mouse's absolute position", "en-US": "Use mouse's absolute position",
"es-ES": "Usar la posición absoluta del ratón",
"ja-JP": "マウスの絶対座標を使用", "ja-JP": "マウスの絶対座標を使用",
"pl-PL": "Użyj pozycji bezwzględnej myszy",
"pt-BR": "Usar posição absoluta do mouse",
"tr-TR": "Farenin mutlak pozisyonunu baz al", "tr-TR": "Farenin mutlak pozisyonunu baz al",
"vi-VN": "Sử dụng vị trí tuyệt đối của chuột", "vi-VN": "Sử dụng vị trí tuyệt đối của chuột",
}, },
@ -2047,13 +2119,12 @@ class RemotePlay {
$connectButton = CE('button', {'class': 'bx-primary-button bx-no-margin'}, __('console-connect')), $connectButton = CE('button', {'class': 'bx-primary-button bx-no-margin'}, __('console-connect')),
); );
REMOTE_PLAY_CONFIG = {
serverId: con.serverId,
};
$connectButton.addEventListener('click', e => { $connectButton.addEventListener('click', e => {
const url = window.location.href.substring(0, 31) + '/launch/starfield/9NCJSXWZTP88#remote-play'; REMOTE_PLAY_CONFIG = {
// const url = '/play'; serverId: con.serverId,
};
const url = window.location.href.substring(0, 31) + '/launch/fortnite/BT5P2X999VH2#remote-play';
const $pageContent = document.getElementById('PageContent'); const $pageContent = document.getElementById('PageContent');
const $anchor = CE('a', {href: url, class: 'bx-hidden', style: 'position:absolute;top:-9990px;left:-9999px'}, ''); const $anchor = CE('a', {href: url, class: 'bx-hidden', style: 'position:absolute;top:-9990px;left:-9999px'}, '');
@ -2074,18 +2145,11 @@ class RemotePlay {
RemotePlay.#$content.parentElement.replaceChild($fragment, RemotePlay.#$content); 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() { static detect() {
if (!PREFS.get(Preferences.REMOTE_PLAY_ENABLED)) {
return;
}
IS_REMOTE_PLAYING = window.location.pathname.includes('/launch/') && window.location.hash.startsWith('#remote-play'); IS_REMOTE_PLAYING = window.location.pathname.includes('/launch/') && window.location.hash.startsWith('#remote-play');
if (IS_REMOTE_PLAYING) { if (IS_REMOTE_PLAYING) {
window.BX_REMOTE_PLAY_CONFIG = REMOTE_PLAY_CONFIG; window.BX_REMOTE_PLAY_CONFIG = REMOTE_PLAY_CONFIG;
@ -3276,7 +3340,7 @@ class PreloadedState {
return this._state; return this._state;
}, },
set: (state) => { set: state => {
this._state = state; this._state = state;
APP_CONTEXT = structuredClone(state.appContext); APP_CONTEXT = structuredClone(state.appContext);
@ -3322,7 +3386,6 @@ class Preferences {
static get STREAM_DISABLE_FEEDBACK_DIALOG() { return 'stream_disable_feedback_dialog'; } static get STREAM_DISABLE_FEEDBACK_DIALOG() { return 'stream_disable_feedback_dialog'; }
static get CONTROLLER_ENABLE_SHORTCUTS() { return 'controller_enable_shortcuts'; } 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_ENABLED() { return 'mkb_enabled'; }
static get MKB_ABSOLUTE_MOUSE() { return 'mkb_absolute_mouse'; } static get MKB_ABSOLUTE_MOUSE() { return 'mkb_absolute_mouse'; }
@ -3360,6 +3423,7 @@ class Preferences {
static get STATS_OPACITY() { return 'stats_opacity'; } static get STATS_OPACITY() { return 'stats_opacity'; }
static get STATS_CONDITIONAL_FORMATTING() { return 'stats_conditional_formatting'; } 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'; } static get REMOTE_PLAY_RESOLUTION() { return 'xhome_resolution'; }
// Deprecated // Deprecated
@ -3553,15 +3617,6 @@ class Preferences {
[Preferences.CONTROLLER_ENABLE_SHORTCUTS]: { [Preferences.CONTROLLER_ENABLE_SHORTCUTS]: {
'default': false, '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]: { [Preferences.MKB_ENABLED]: {
'default': false, 'default': false,
@ -3707,6 +3762,10 @@ class Preferences {
'default': false, 'default': false,
}, },
[Preferences.REMOTE_PLAY_ENABLED]: {
'default': false,
},
[Preferences.REMOTE_PLAY_RESOLUTION]: { [Preferences.REMOTE_PLAY_RESOLUTION]: {
'default': 1080, 'default': 1080,
'options': { 'options': {
@ -4033,36 +4092,24 @@ const PREFS = new Preferences();
class Patcher { class Patcher {
static #PATCHES = { 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 // Enable Remote Play feature
connectMode: function(funcStr) { remotePlayConnectMode: PREFS.get(Preferences.REMOTE_PLAY_ENABLED) && function(funcStr) {
const text = 'connectMode:"cloud-connect"'; const text = 'connectMode:"cloud-connect"';
if (!funcStr.includes(text)) { if (!funcStr.includes(text)) {
return false; 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" // Replace "/direct-connect" with "/play"
directConnectUrl: function(funcStr) { remotePlayDirectConnectUrl: PREFS.get(Preferences.REMOTE_PLAY_ENABLED) && function(funcStr) {
const index = funcStr.indexOf('/direct-connect'); const index = funcStr.indexOf('/direct-connect');
if (index === -1) { if (index === -1) {
return false; 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 // Set disableTelemetry() to true
@ -4085,6 +4132,31 @@ class Patcher {
return funcStr.replace(text, 'this.trackEvent=e=>{},this.uwuwu='); 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 // Set TV layout
tvLayout: PREFS.get(Preferences.UI_LAYOUT) === 'tv' && function(funcStr) { tvLayout: PREFS.get(Preferences.UI_LAYOUT) === 'tv' && function(funcStr) {
const text = '?"tv":"default"'; const text = '?"tv":"default"';
@ -4107,7 +4179,7 @@ class Patcher {
} }
return funcStr; return funcStr;
} },
}; };
static #patchFunctionBind() { static #patchFunctionBind() {
@ -5341,9 +5413,6 @@ function interceptHttpRequests() {
try { try {
const clone = request.clone(); const clone = request.clone();
const resp = (await (await orgFetch(...arg)).json());
RemotePlay.XCLOUD_TOKEN = resp.gsToken;
const obj = await clone.json(); const obj = await clone.json();
obj.offeringId = 'xhome'; obj.offeringId = 'xhome';
@ -5424,6 +5493,9 @@ function interceptHttpRequests() {
return promise.then(response => { return promise.then(response => {
return response.clone().json().then(obj => { return response.clone().json().then(obj => {
// Store xCloud token
RemotePlay.XCLOUD_TOKEN = obj.gsToken;
// Get server list // Get server list
if (!Object.keys(SERVER_REGIONS).length) { if (!Object.keys(SERVER_REGIONS).length) {
for (let region of obj.offeringSettings.regions) { for (let region of obj.offeringSettings.regions) {
@ -5620,6 +5692,7 @@ function injectSettingsButton($parent) {
const CE = createElement; const CE = createElement;
const PREF_PREFERRED_REGION = getPreferredServerRegion(); const PREF_PREFERRED_REGION = getPreferredServerRegion();
const PREF_LATEST_VERSION = PREFS.get(Preferences.LATEST_VERSION); const PREF_LATEST_VERSION = PREFS.get(Preferences.LATEST_VERSION);
const PREF_REMOTE_PLAY_ENABLED = PREFS.get(Preferences.REMOTE_PLAY_ENABLED);
// Setup Settings button // Setup Settings button
const $button = CE('button', {'class': 'bx-settings-button'}, PREF_PREFERRED_REGION); const $button = CE('button', {'class': 'bx-settings-button'}, PREF_PREFERRED_REGION);
@ -5643,7 +5716,7 @@ function injectSettingsButton($parent) {
}); });
let $updateAvailable; let $updateAvailable;
let $remotePlayLink; let $remotePlayBtn;
const $wrapper = CE('div', {'class': 'bx-settings-wrapper'}, const $wrapper = CE('div', {'class': 'bx-settings-wrapper'},
CE('div', {'class': 'bx-settings-title-wrapper'}, CE('div', {'class': 'bx-settings-title-wrapper'},
CE('a', { CE('a', {
@ -5651,7 +5724,7 @@ function injectSettingsButton($parent) {
'href': SCRIPT_HOME, 'href': SCRIPT_HOME,
'target': '_blank', 'target': '_blank',
}, 'Better xCloud ' + SCRIPT_VERSION), }, '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', { $updateAvailable = CE('a', {
@ -5660,12 +5733,17 @@ function injectSettingsButton($parent) {
'target': '_blank', 'target': '_blank',
}); });
$remotePlayLink.addEventListener('click', e => { if (PREF_REMOTE_PLAY_ENABLED) {
RemotePlay.showDialog(); $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); $wrapper.appendChild($updateAvailable);
// Show new version indicator // Show new version indicator
@ -5678,6 +5756,7 @@ function injectSettingsButton($parent) {
const SETTINGS_UI = { const SETTINGS_UI = {
'Better xCloud': { 'Better xCloud': {
[Preferences.BETTER_XCLOUD_LOCALE]: __('language'), [Preferences.BETTER_XCLOUD_LOCALE]: __('language'),
[Preferences.REMOTE_PLAY_ENABLED]: __('enable-remote-play-feature'),
}, },
[__('server')]: { [__('server')]: {
[Preferences.SERVER_REGION]: __('region'), [Preferences.SERVER_REGION]: __('region'),
@ -5694,7 +5773,6 @@ function injectSettingsButton($parent) {
[Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: __('disable-post-stream-feedback-dialog'), [Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: __('disable-post-stream-feedback-dialog'),
}, },
[__('controller')]: { [__('controller')]: {
[Preferences.CONTROLLER_POLLING_RATE]: __('controller-polling-rate'),
[Preferences.CONTROLLER_ENABLE_SHORTCUTS]: __('enable-controller-shortcuts'), [Preferences.CONTROLLER_ENABLE_SHORTCUTS]: __('enable-controller-shortcuts'),
}, },
[__('touch-controller')]: { [__('touch-controller')]: {
@ -5705,7 +5783,7 @@ function injectSettingsButton($parent) {
[__('mouse-and-keyboard')]: { [__('mouse-and-keyboard')]: {
'_note': '⚠️ ' + __('may-not-work-properly'), '_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'), [Preferences.MKB_ABSOLUTE_MOUSE]: __('use-mouse-absolute-position'),
}, },
@ -6623,4 +6701,5 @@ if (PREFS.get(Preferences.CONTROLLER_ENABLE_SHORTCUTS)) {
} }
Patcher.initialize(); Patcher.initialize();
RemotePlay.detect(); RemotePlay.detect();