mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-04 13:21:43 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
77c4e3981f | |||
1cb4038abf | |||
ec6c3fc8a3 | |||
b27f84b980 | |||
37d0a0c6e2 | |||
5d272425db | |||
6b5cdca51a | |||
90a5613959 | |||
1bdfa6c23f | |||
47fbbdcb59 | |||
69a8db092e | |||
928a1484d7 | |||
65ca3dab0e | |||
35a783c53e | |||
afe3809061 | |||
5eeb15f201 | |||
71b4109385 | |||
8286429cc3 | |||
ae24005f08 | |||
2626408cbe | |||
804f751646 | |||
13a20f30e5 | |||
46265f2ccd | |||
93d77c3783 |
@ -1,5 +1,5 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 3.5.0
|
||||
// @version 3.5.2
|
||||
// ==/UserScript==
|
||||
|
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 3.5.0
|
||||
// @version 3.5.2
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
/* ADDITIONAL CODE */
|
||||
|
||||
const SCRIPT_VERSION = '3.4.0';
|
||||
const SCRIPT_VERSION = '3.5.2';
|
||||
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||
|
||||
// Setup flags
|
||||
@ -491,7 +491,7 @@ const Translations = {
|
||||
"左下",
|
||||
"좌측 하단",
|
||||
"Lewy dolny róg",
|
||||
"Inferior Esquerdo",
|
||||
"Inferior esquerdo",
|
||||
"Левый нижний угол",
|
||||
"Sol alt",
|
||||
"Внизу ліворуч",
|
||||
@ -508,7 +508,7 @@ const Translations = {
|
||||
"右下",
|
||||
"우측 하단",
|
||||
"Prawy dolny róg",
|
||||
"Inferior-direito",
|
||||
"Inferior direito",
|
||||
"Правый нижний угол",
|
||||
"Sağ alt",
|
||||
"Внизу праворуч",
|
||||
@ -669,7 +669,7 @@ const Translations = {
|
||||
"关闭",
|
||||
],
|
||||
"combine-audio-video-streams": [
|
||||
,
|
||||
"Audio- und Video-Streams kombinieren",
|
||||
"Gabung audio & video stream",
|
||||
"Combine audio & video streams",
|
||||
,
|
||||
@ -686,7 +686,7 @@ const Translations = {
|
||||
"合并视频音频流",
|
||||
],
|
||||
"combine-audio-video-streams-summary": [
|
||||
,
|
||||
"Könnte das Problem mit verzögertem Ton beheben",
|
||||
"Mungkin memperbaiki masalah lag pada audio",
|
||||
"May fix the laggy audio problem",
|
||||
,
|
||||
@ -695,7 +695,7 @@ const Translations = {
|
||||
"音声の遅延を改善できる可能性があります",
|
||||
,
|
||||
"Może rozwiązać problem z zacinającym dźwiękiem",
|
||||
"Pode corrigir o problema de áudio Laggy",
|
||||
"Pode corrigir o problema de áudio atrasado",
|
||||
"Может исправить проблему подвисания звука",
|
||||
"Sesteki gecikme sorununa çözüm olabilir",
|
||||
"Може виправити проблему із затримкою звуку",
|
||||
@ -882,7 +882,7 @@ const Translations = {
|
||||
"カスタム",
|
||||
"사용자 지정",
|
||||
"Niestandardowe",
|
||||
"Customizado",
|
||||
"Personalizado",
|
||||
"Вручную",
|
||||
"Özel",
|
||||
"Користувацькі",
|
||||
@ -899,7 +899,7 @@ const Translations = {
|
||||
"デッドゾーンのカウンターウエイト",
|
||||
,
|
||||
"Przeciwwaga martwej strefy",
|
||||
"Contador da Zona Morta",
|
||||
"Contrapeso de zona morta",
|
||||
"Противодействие мертвой зоне игры",
|
||||
"Ölü alan denge ağırlığı",
|
||||
"Противага Deadzone",
|
||||
@ -1264,7 +1264,7 @@ const Translations = {
|
||||
"启用",
|
||||
],
|
||||
"experimental": [
|
||||
,
|
||||
"Experimentell",
|
||||
"Eksperimental",
|
||||
"Experimental",
|
||||
,
|
||||
@ -1409,7 +1409,7 @@ const Translations = {
|
||||
"Webページのスクロールバーを隠す",
|
||||
,
|
||||
"Ukryj pasek przewijania strony",
|
||||
"Oculta a barra de rolagem da página",
|
||||
"Ocultar a barra de rolagem da página",
|
||||
"Скрыть полосу прокрутки страницы",
|
||||
"Yandaki kaydırma çubuğunu gizle",
|
||||
"Приховати смугу прокрутки вебсторінок",
|
||||
@ -1579,7 +1579,7 @@ const Translations = {
|
||||
"ロード画面",
|
||||
"로딩 화면",
|
||||
"Ekran wczytywania",
|
||||
"Tela de Carregamento",
|
||||
"Tela de carregamento",
|
||||
"Экран загрузки",
|
||||
"Yükleme ekranı",
|
||||
"Екран завантаження",
|
||||
@ -1698,7 +1698,7 @@ const Translations = {
|
||||
"ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります",
|
||||
,
|
||||
"Może być również konieczne dostosowanie czułości w grze i ustawienia 'martwej strefy' urządzenia",
|
||||
"Você também pode precisar ajustar as configurações de sensibilidade e zona morta no jogo",
|
||||
"Você talvez também precise ajustar as configurações de sensibilidade e zona morta no jogo",
|
||||
"Также может потребоваться изменить настройки чувствительности и мертвой зоны в игре",
|
||||
"Bu seçenek etkinken bile oyun içi seçeneklerden hassasiyet ve ölü bölge ayarlarını düzeltmeniz gerekebilir",
|
||||
"Можливо, вам також доведеться регулювати чутливість і deadzone у параметрах гри",
|
||||
@ -2004,7 +2004,7 @@ const Translations = {
|
||||
"IPv6 サーバーを優先",
|
||||
"IPv6 서버 우선",
|
||||
"Preferuj serwer IPv6",
|
||||
"Preferir servidor IPV6",
|
||||
"Preferir servidor IPv6",
|
||||
"Предпочитать IPv6 сервер",
|
||||
"IPv6 sunucusunu tercih et",
|
||||
"Віддавати перевагу IPv6",
|
||||
@ -2174,7 +2174,7 @@ const Translations = {
|
||||
"リモートプレイ",
|
||||
"리모트 플레이",
|
||||
"Gra zdalna",
|
||||
"Jogo Remoto",
|
||||
"Reprodução remota",
|
||||
"Удаленная игра",
|
||||
"Uzaktan Bağlanma",
|
||||
"Віддалена гра",
|
||||
@ -2361,7 +2361,7 @@ const Translations = {
|
||||
"スクリーンショットにビデオフィルターを適用",
|
||||
,
|
||||
"Stosuje filtry wideo do zrzutów ekranu",
|
||||
"Aplicar filtros às capturas de tela",
|
||||
"Aplicar filtros de vídeo às capturas de tela",
|
||||
"Применяет фильтры видео к скриншотам",
|
||||
"Görsel filtreleri ekran görüntülerine de uygular",
|
||||
"Застосовує відеофільтри до знімків екрана",
|
||||
@ -2786,7 +2786,7 @@ const Translations = {
|
||||
"スティックの減衰の最小値",
|
||||
,
|
||||
"Minimalne opóźnienie drążka",
|
||||
"Mínimo decaimento do analógico",
|
||||
"Tempo mínimo de redefinição do analógico",
|
||||
"Минимальная перезарядка стика",
|
||||
"Çubuğun ortalanma süresi minimumu",
|
||||
"Мінімальне згасання стіка",
|
||||
@ -2803,7 +2803,7 @@ const Translations = {
|
||||
"スティックの減衰の強さ",
|
||||
,
|
||||
"Siła opóźnienia drążka",
|
||||
"Força de decaimento do analógico",
|
||||
"Velocidade de redefinição do analógico",
|
||||
"Скорость перезарядки стика",
|
||||
"Çubuğun ortalanma gücü",
|
||||
"Сила згасання стіка",
|
||||
@ -2854,7 +2854,7 @@ const Translations = {
|
||||
"Better xCloudをサポート",
|
||||
,
|
||||
"Wesprzyj Better xCloud",
|
||||
"Suporte ao Better xCloud",
|
||||
"Apoie o Better xCloud",
|
||||
"Поддержать Better xCloud",
|
||||
"Better xCloud'a destek ver",
|
||||
"Підтримати Better xCloud",
|
||||
@ -2990,7 +2990,7 @@ const Translations = {
|
||||
"ミュートカラー",
|
||||
"저채도 색상",
|
||||
"Stonowane kolory",
|
||||
"Cores silenciadas",
|
||||
"Cores opacas",
|
||||
"Приглушенные цвета",
|
||||
"Yumuşak renkler",
|
||||
"Приглушені кольори",
|
||||
@ -3041,7 +3041,7 @@ const Translations = {
|
||||
"上",
|
||||
"중앙 상단",
|
||||
"Wyśrodkowany na górze",
|
||||
"Superior-centralizado",
|
||||
"Superior centralizado",
|
||||
"Сверху",
|
||||
"Orta üst",
|
||||
"Зверху по центру",
|
||||
@ -3058,7 +3058,7 @@ const Translations = {
|
||||
"左上",
|
||||
"좌측 상단",
|
||||
"Lewy górny róg",
|
||||
"Superior-esquerdo",
|
||||
"Superior esquerdo",
|
||||
"Левый верхний угол",
|
||||
"Sol üst",
|
||||
"Зверху ліворуч",
|
||||
@ -3075,7 +3075,7 @@ const Translations = {
|
||||
"右上",
|
||||
"우측 상단",
|
||||
"Prawy górny róg",
|
||||
"Superior-direito",
|
||||
"Superior direito",
|
||||
"Справа",
|
||||
"Sağ üst",
|
||||
"Зверху праворуч",
|
||||
@ -3601,6 +3601,7 @@ class RemotePlay {
|
||||
static XCLOUD_TOKEN;
|
||||
static XHOME_TOKEN;
|
||||
static #CONSOLES = null;
|
||||
static #REGIONS;
|
||||
|
||||
static #STATE_LABELS = {
|
||||
'On': t('powered-on'),
|
||||
@ -3672,40 +3673,56 @@ class RemotePlay {
|
||||
|
||||
if (!RemotePlay.#CONSOLES || RemotePlay.#CONSOLES.length === 0) {
|
||||
$fragment.appendChild(CE('span', {}, t('no-consoles-found')));
|
||||
} else {
|
||||
const $settingNote = CE('p', {});
|
||||
RemotePlay.#$content = CE('div', {}, $fragment);
|
||||
return;
|
||||
}
|
||||
|
||||
const resolutions = [1080, 720];
|
||||
const currentResolution = getPref(Preferences.REMOTE_PLAY_RESOLUTION);
|
||||
const $resolutionSelect = CE('select', {});
|
||||
for (const resolution of resolutions) {
|
||||
const value = `${resolution}p`;
|
||||
const $settingNote = CE('p', {});
|
||||
|
||||
const $option = CE('option', {'value': value}, value);
|
||||
if (currentResolution === value) {
|
||||
$option.selected = true;
|
||||
}
|
||||
const resolutions = [1080, 720];
|
||||
const currentResolution = getPref(Preferences.REMOTE_PLAY_RESOLUTION);
|
||||
const $resolutionGroup = CE('div', {});
|
||||
for (const resolution of resolutions) {
|
||||
const value = `${resolution}p`;
|
||||
const id = `bx_radio_xhome_resolution_${resolution}`;
|
||||
|
||||
$resolutionSelect.appendChild($option);
|
||||
}
|
||||
$resolutionSelect.addEventListener('change', e => {
|
||||
const value = $resolutionSelect.value;
|
||||
const $radio = CE('input', {
|
||||
'type': 'radio',
|
||||
'value': value,
|
||||
'id': id,
|
||||
'name': 'bx_radio_xhome_resolution',
|
||||
}, value);
|
||||
|
||||
$radio.addEventListener('change', e => {
|
||||
const value = e.target.value;
|
||||
|
||||
$settingNote.textContent = value === '1080p' ? '✅ ' + t('can-stream-xbox-360-games') : '❌ ' + t('cant-stream-xbox-360-games');
|
||||
setPref(Preferences.REMOTE_PLAY_RESOLUTION, value);
|
||||
});
|
||||
$resolutionSelect.dispatchEvent(new Event('change'));
|
||||
|
||||
const $qualitySettings = CE('div', {'class': 'bx-remote-play-settings'},
|
||||
CE('div', {},
|
||||
CE('label', {}, t('target-resolution'), $settingNote),
|
||||
$resolutionSelect,
|
||||
)
|
||||
);
|
||||
const $label = CE('label', {
|
||||
'for': id,
|
||||
'class': 'bx-remote-play-resolution',
|
||||
}, $radio, `${resolution}p`);
|
||||
|
||||
$fragment.appendChild($qualitySettings);
|
||||
$resolutionGroup.appendChild($label);
|
||||
|
||||
if (currentResolution === value) {
|
||||
$radio.checked = true;
|
||||
$radio.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
|
||||
const $qualitySettings = CE('div', {'class': 'bx-remote-play-settings'},
|
||||
CE('div', {},
|
||||
CE('label', {}, t('target-resolution'), $settingNote),
|
||||
$resolutionGroup,
|
||||
)
|
||||
);
|
||||
|
||||
$fragment.appendChild($qualitySettings);
|
||||
|
||||
// Render concoles list
|
||||
for (let con of RemotePlay.#CONSOLES) {
|
||||
let $connectButton;
|
||||
const $child = CE('div', {'class': 'bx-remote-play-device-wrapper'},
|
||||
@ -3731,6 +3748,14 @@ class RemotePlay {
|
||||
$fragment.appendChild($child);
|
||||
}
|
||||
|
||||
// Add Help button
|
||||
$fragment.appendChild(createButton({
|
||||
icon: Icon.QUESTION,
|
||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
||||
url: 'https://better-xcloud.github.io/remote-play',
|
||||
label: t('help'),
|
||||
}));
|
||||
|
||||
RemotePlay.#$content = CE('div', {}, $fragment);
|
||||
}
|
||||
|
||||
@ -3775,6 +3800,7 @@ class RemotePlay {
|
||||
},
|
||||
}).then(resp => resp.json())
|
||||
.then(json => {
|
||||
RemotePlay.#REGIONS = json.offeringSettings.regions;
|
||||
RemotePlay.XHOME_TOKEN = json.gsToken;
|
||||
callback();
|
||||
});
|
||||
@ -3786,13 +3812,6 @@ class RemotePlay {
|
||||
return;
|
||||
}
|
||||
|
||||
let servers;
|
||||
if (!REMOTE_PLAY_SERVER) {
|
||||
servers = ['wus2', 'eus', 'uks']; // Possible values: wus2 (WestUS2), eus (EastUS), uks (UkSouth)
|
||||
} else {
|
||||
servers = REMOTE_PLAY_SERVER;
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@ -3801,16 +3820,16 @@ class RemotePlay {
|
||||
};
|
||||
|
||||
// Test servers one by one
|
||||
for (const server of servers) {
|
||||
for (const region of RemotePlay.#REGIONS) {
|
||||
try {
|
||||
const url = `https://${server}.gssv-play-prodxhome.xboxlive.com/v6/servers/home?mr=50`;
|
||||
const url = `${region.baseUri}/v6/servers/home?mr=50`;
|
||||
const resp = await fetch(url, options);
|
||||
|
||||
const json = await resp.json();
|
||||
RemotePlay.#CONSOLES = json.results;
|
||||
|
||||
// Store working server
|
||||
REMOTE_PLAY_SERVER = server;
|
||||
REMOTE_PLAY_SERVER = region.baseUri;
|
||||
|
||||
callback();
|
||||
} catch (e) {}
|
||||
@ -4991,7 +5010,7 @@ class MkbPreset {
|
||||
[MkbPreset.KEY_MOUSE_STICK_DECAY_STRENGTH]: {
|
||||
label: t('stick-decay-strength'),
|
||||
type: SettingElement.TYPE_NUMBER_STEPPER,
|
||||
default: 18,
|
||||
default: 100,
|
||||
min: 10,
|
||||
max: 100,
|
||||
|
||||
@ -5004,7 +5023,7 @@ class MkbPreset {
|
||||
[MkbPreset.KEY_MOUSE_STICK_DECAY_MIN]: {
|
||||
label: t('stick-decay-minimum'),
|
||||
type: SettingElement.TYPE_NUMBER_STEPPER,
|
||||
default: 6,
|
||||
default: 10,
|
||||
min: 1,
|
||||
max: 10,
|
||||
|
||||
@ -5271,8 +5290,10 @@ class MkbHandler {
|
||||
static get DEFAULT_DEADZONE_COUNTERWEIGHT() { return 0.01; }
|
||||
static get MAXIMUM_STICK_RANGE() { return 1.1; }
|
||||
|
||||
VIRTUAL_GAMEPAD_ID = 'Xbox 360 Controller';
|
||||
|
||||
#VIRTUAL_GAMEPAD = {
|
||||
id: 'Xbox 360 Controller',
|
||||
id: MkbHandler.VIRTUAL_GAMEPAD_ID,
|
||||
index: 3,
|
||||
connected: false,
|
||||
hapticActuators: null,
|
||||
@ -5394,7 +5415,7 @@ class MkbHandler {
|
||||
const isKeyDown = e.type === 'keydown';
|
||||
|
||||
// Toggle MKB feature
|
||||
if (isKeyDown && e.code === 'F9') {
|
||||
if (isKeyDown && e.code === 'F8') {
|
||||
e.preventDefault();
|
||||
this.toggle();
|
||||
return;
|
||||
@ -5534,7 +5555,7 @@ class MkbHandler {
|
||||
this.#enabled = !this.#enabled;
|
||||
this.#enabled ? document.pointerLockElement && this.start() : this.stop();
|
||||
|
||||
Toast.show(t('mouse-and-keyboard'), t(this.#enabled ? 'enabled' : 'disabled'));
|
||||
Toast.show(t('mouse-and-keyboard'), t(this.#enabled ? 'enabled' : 'disabled'), {instant: true});
|
||||
|
||||
if (this.#enabled) {
|
||||
!document.pointerLockElement && this.#waitForPointerLock(true);
|
||||
@ -5605,6 +5626,7 @@ class MkbHandler {
|
||||
this.#$message = CE('div', {'class': 'bx-mkb-pointer-lock-msg bx-gone'},
|
||||
createButton({
|
||||
icon: Icon.MOUSE_SETTINGS,
|
||||
style: ButtonStyle.PRIMARY,
|
||||
onClick: e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@ -5614,7 +5636,7 @@ class MkbHandler {
|
||||
}),
|
||||
CE('div', {},
|
||||
CE('p', {}, t('mkb-click-to-activate')),
|
||||
CE('p', {}, t('press-key-to-toggle-mkb')({key: 'F9'})),
|
||||
CE('p', {}, t('press-key-to-toggle-mkb')({key: 'F8'})),
|
||||
),
|
||||
);
|
||||
|
||||
@ -7909,6 +7931,26 @@ class Patcher {
|
||||
return funcStr.replace(text, '.disableTelemetry=function(){return!0}');
|
||||
},
|
||||
|
||||
disableTelemetryProvider: function(funcStr) {
|
||||
const text = 'this.enableLightweightTelemetry=!';
|
||||
if (!funcStr.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newCode = [
|
||||
'this.trackEvent',
|
||||
'this.trackPageView',
|
||||
'this.trackHttpCompleted',
|
||||
'this.trackHttpFailed',
|
||||
'this.trackError',
|
||||
'this.trackErrorLike',
|
||||
'this.onTrackEvent',
|
||||
'()=>{}',
|
||||
].join('=');
|
||||
|
||||
return funcStr.replace(text, newCode + ';' + text);
|
||||
},
|
||||
|
||||
// Disable IndexDB logging
|
||||
disableIndexDbLogging(funcStr) {
|
||||
const text = 'async addLog(e,t=1e4){';
|
||||
@ -7967,6 +8009,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)||''`);
|
||||
},
|
||||
|
||||
// Fix the Guide/Nexus button not working in Remote Play
|
||||
remotePlayGuideWorkaround: function(funcStr) {
|
||||
const text = 'nexusButtonHandler:this.featureGates.EnableClientGuideInStream';
|
||||
if (!funcStr.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return funcStr.replace(text, `nexusButtonHandler: !window.BX_REMOTE_PLAY_CONFIG && this.featureGates.EnableClientGuideInStream`);
|
||||
},
|
||||
|
||||
// Disable trackEvent() function
|
||||
disableTrackEvent: function(funcStr) {
|
||||
const text = 'this.trackEvent=';
|
||||
@ -7999,7 +8051,7 @@ class Patcher {
|
||||
},
|
||||
|
||||
enableXcloudLogger: function(funcStr) {
|
||||
const text = 'this.telemetryProvider=e}log(e,t,r){';
|
||||
const text = 'this.telemetryProvider=e}log(e,t,i){';
|
||||
if (!funcStr.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
@ -8239,6 +8291,22 @@ if (gamepadFound) {
|
||||
funcStr = funcStr.replace(text, 'this.useCombinedAudioVideoStream=true');
|
||||
return funcStr;
|
||||
},
|
||||
|
||||
patchStreamHud: function(funcStr) {
|
||||
const text = 'let{onCollapse';
|
||||
if (!funcStr.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore the "..." button
|
||||
funcStr = funcStr.replace(text, 'e.guideUI = null;' + text);
|
||||
|
||||
// Remove the TAK Edit button when the touch controller is disabled
|
||||
if (getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'off') {
|
||||
funcStr = funcStr.replace(text, 'e.canShowTakHUD = false;' + text);
|
||||
}
|
||||
return funcStr;
|
||||
},
|
||||
};
|
||||
|
||||
static #PATCH_ORDERS = [
|
||||
@ -8247,6 +8315,8 @@ if (gamepadFound) {
|
||||
'disableTelemetry',
|
||||
],
|
||||
|
||||
getPref(Preferences.BLOCK_TRACKING) && ['disableTelemetryProvider'],
|
||||
|
||||
['disableStreamGate'],
|
||||
|
||||
getPref(Preferences.UI_LAYOUT) === 'tv' && ['tvLayout'],
|
||||
@ -8279,6 +8349,9 @@ if (gamepadFound) {
|
||||
// Only when playing
|
||||
static #PLAYING_PATCH_ORDERS = [
|
||||
getPref(Preferences.REMOTE_PLAY_ENABLED) && ['remotePlayConnectMode'],
|
||||
getPref(Preferences.REMOTE_PLAY_ENABLED) && ['remotePlayGuideWorkaround'],
|
||||
|
||||
['patchStreamHud'],
|
||||
|
||||
['playVibration'],
|
||||
HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'all' && ['exposeTouchLayoutManager'],
|
||||
@ -8558,6 +8631,13 @@ div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
/* Remove the "Cloud Gaming" text in header when the screen is too small */
|
||||
@media screen and (max-width: 600px) {
|
||||
header a[href="/play"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.bx-button {
|
||||
display: inline-block;
|
||||
}
|
||||
@ -8648,31 +8728,27 @@ a.bx-button.bx-full-width {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bx-remote-play-button {
|
||||
.bx-header-remote-play-button {
|
||||
height: auto;
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
||||
.bx-remote-play-button svg {
|
||||
width: 28px;
|
||||
.bx-header-remote-play-button svg {
|
||||
width: 24px;
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
.bx-remote-play-button[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.bx-settings-button {
|
||||
.bx-header-settings-button {
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
text-transform: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.bx-settings-button[data-update-available]::after {
|
||||
.bx-header-settings-button[data-update-available]::after {
|
||||
content: ' 🌟';
|
||||
}
|
||||
|
||||
.bx-button.bx-focusable, .bx-settings-button {
|
||||
.bx-button.bx-focusable, .bx-header-settings-button {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -9681,6 +9757,11 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
||||
}
|
||||
}
|
||||
|
||||
.bx-remote-play-container > .bx-button {
|
||||
display: table;
|
||||
margin: 0 0 0 auto;
|
||||
}
|
||||
|
||||
.bx-remote-play-settings {
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
@ -9710,6 +9791,19 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bx-remote-play-resolution {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bx-remote-play-resolution input[type="radio"] {
|
||||
accent-color: var(--bx-primary-button-color);
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.bx-remote-play-resolution input[type="radio"]:focus {
|
||||
accent-color: var(--bx-primary-button-hover-color);
|
||||
}
|
||||
|
||||
.bx-remote-play-device-wrapper {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
@ -9903,15 +9997,25 @@ body::-webkit-scrollbar {
|
||||
}
|
||||
|
||||
|
||||
function getPreferredServerRegion() {
|
||||
function getPreferredServerRegion(shortName = false) {
|
||||
let preferredRegion = getPref(Preferences.SERVER_REGION);
|
||||
if (preferredRegion in SERVER_REGIONS) {
|
||||
return preferredRegion;
|
||||
if (shortName && SERVER_REGIONS[preferredRegion].shortName) {
|
||||
return SERVER_REGIONS[preferredRegion].shortName;
|
||||
} else {
|
||||
return preferredRegion;
|
||||
}
|
||||
}
|
||||
|
||||
for (let regionName in SERVER_REGIONS) {
|
||||
const region = SERVER_REGIONS[regionName];
|
||||
if (region.isDefault) {
|
||||
if (!region.isDefault) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shortName && region.shortName) {
|
||||
return region.shortName;
|
||||
} else {
|
||||
return regionName;
|
||||
}
|
||||
}
|
||||
@ -10141,7 +10245,7 @@ function interceptHttpRequests() {
|
||||
}
|
||||
|
||||
const index = request.url.indexOf('.xboxlive.com');
|
||||
let newUrl = `https://${REMOTE_PLAY_SERVER}.gssv-play-prodxhome` + request.url.substring(index);
|
||||
let newUrl = REMOTE_PLAY_SERVER + request.url.substring(index + 13);
|
||||
|
||||
request = new Request(newUrl, opts);
|
||||
|
||||
@ -10266,7 +10370,38 @@ function interceptHttpRequests() {
|
||||
|
||||
// Get server list
|
||||
if (!Object.keys(SERVER_REGIONS).length) {
|
||||
const serverEmojis = {
|
||||
AustraliaEast: '🇦🇺',
|
||||
AustraliaSouthEast: '🇦🇺',
|
||||
BrazilSouth: '🇧🇷',
|
||||
EastUS: '🇺🇸',
|
||||
EastUS2: '🇺🇸',
|
||||
JapanEast: '🇯🇵',
|
||||
KoreaCentral: '🇰🇷',
|
||||
MexicoCentral: '🇲🇽',
|
||||
NorthCentralUs: '🇺🇸',
|
||||
SouthCentralUS: '🇺🇸',
|
||||
UKSouth: '🇬🇧',
|
||||
WestEurope: '🇪🇺',
|
||||
WestUS: '🇺🇸',
|
||||
WestUS2: '🇺🇸',
|
||||
};
|
||||
|
||||
const regex = /\/\/(\w+)\./;
|
||||
|
||||
for (let region of obj.offeringSettings.regions) {
|
||||
let shortName = region.name;
|
||||
|
||||
let match = regex.exec(region.baseUri);
|
||||
if (match) {
|
||||
shortName = match[1];
|
||||
if (serverEmojis[region.name]) {
|
||||
shortName = serverEmojis[region.name] + ' ' + shortName;
|
||||
}
|
||||
}
|
||||
|
||||
region.shortName = shortName.toUpperCase();
|
||||
|
||||
SERVER_REGIONS[region.name] = Object.assign({}, region);
|
||||
}
|
||||
|
||||
@ -10334,7 +10469,7 @@ function interceptHttpRequests() {
|
||||
if (PREF_UI_LOADING_SCREEN_WAIT_TIME && url.includes('xboxlive.com') && url.includes('/waittime/')) {
|
||||
const response = await NATIVE_FETCH(...arg);
|
||||
|
||||
const json = await response.clone.json();
|
||||
const json = await response.clone().json();
|
||||
if (json.estimatedAllocationTimeInSeconds > 0) {
|
||||
// Setup wait time overlay
|
||||
LoadingScreen.setupWaitTime(json.estimatedTotalWaitTimeInSeconds);
|
||||
@ -10405,7 +10540,7 @@ function interceptHttpRequests() {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && (url.includes('/titles') || url.includes('/mru'))) {
|
||||
if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && (url.includes('/v2/titles') || url.includes('/mru'))) {
|
||||
const response = await NATIVE_FETCH(...arg);
|
||||
const json = await response.clone().json()
|
||||
for (let game of json.results) {
|
||||
@ -10645,15 +10780,20 @@ function setupSettingsUi() {
|
||||
});
|
||||
|
||||
selectedValue = PREF_PREFERRED_REGION;
|
||||
|
||||
setting.options = {};
|
||||
for (let regionName in SERVER_REGIONS) {
|
||||
const region = SERVER_REGIONS[regionName];
|
||||
let value = regionName;
|
||||
|
||||
let label = regionName;
|
||||
let label = `${region.shortName} - ${regionName}`;
|
||||
if (region.isDefault) {
|
||||
label += ` (${t('default')})`;
|
||||
value = 'default';
|
||||
|
||||
if (selectedValue === regionName) {
|
||||
selectedValue = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
setting.options[value] = label;
|
||||
@ -10663,9 +10803,11 @@ function setupSettingsUi() {
|
||||
const label = setting.options[value];
|
||||
|
||||
const $option = CE('option', {value: value}, label);
|
||||
$option.selected = value === selectedValue || label.includes(selectedValue);
|
||||
$control.appendChild($option);
|
||||
}
|
||||
|
||||
// Select preferred region
|
||||
$control.value = selectedValue;
|
||||
} else {
|
||||
if (settingId === Preferences.BETTER_XCLOUD_LOCALE) {
|
||||
$control = PREFS.toElement(settingId, e => {
|
||||
@ -10742,7 +10884,7 @@ function injectSettingsButton($parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const PREF_PREFERRED_REGION = getPreferredServerRegion();
|
||||
const PREF_PREFERRED_REGION = getPreferredServerRegion(true);
|
||||
const PREF_LATEST_VERSION = getPref(Preferences.LATEST_VERSION);
|
||||
|
||||
const $headerFragment = document.createDocumentFragment();
|
||||
@ -10750,7 +10892,7 @@ function injectSettingsButton($parent) {
|
||||
// Remote Play button
|
||||
if (getPref(Preferences.REMOTE_PLAY_ENABLED)) {
|
||||
const $remotePlayBtn = createButton({
|
||||
classes: ['bx-remote-play-button'],
|
||||
classes: ['bx-header-remote-play-button'],
|
||||
icon: Icon.REMOTE_PLAY,
|
||||
title: t('remote-play'),
|
||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
||||
@ -10764,7 +10906,7 @@ function injectSettingsButton($parent) {
|
||||
|
||||
// Setup Settings button
|
||||
const $settingsBtn = createButton({
|
||||
classes: ['bx-settings-button'],
|
||||
classes: ['bx-header-settings-button'],
|
||||
label: PREF_PREFERRED_REGION,
|
||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_HEIGHT,
|
||||
onClick: e => {
|
||||
@ -10889,7 +11031,7 @@ div[data-testid="media-container"] {
|
||||
|
||||
|
||||
function checkHeader() {
|
||||
const $button = document.querySelector('.bx-settings-button');
|
||||
const $button = document.querySelector('.bx-header-settings-button');
|
||||
|
||||
if (!$button) {
|
||||
const $rightHeader = document.querySelector('#PageContent div[class*=EdgewaterHeader-module__rightSectionSpacing]');
|
||||
@ -11957,6 +12099,11 @@ MkbHandler.setupEvents();
|
||||
|
||||
// Show a toast when connecting/disconecting controller
|
||||
function showGamepadToast(gamepad) {
|
||||
// Don't show Toast for virtual controller
|
||||
if (gamepad.id === MkbHandler.VIRTUAL_GAMEPAD_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(gamepad);
|
||||
let text = '🎮';
|
||||
|
||||
|
Reference in New Issue
Block a user