Compare commits

..

19 Commits

Author SHA1 Message Date
4376f37bd0 Bump version to 3.3.0 2024-03-23 17:33:59 +07:00
6ee55c6f30 Update translations 2024-03-23 17:32:50 +07:00
ea8dea99cd Add ADDITIONAL CODE block 2024-03-23 17:06:08 +07:00
805fc5dacb Update translations 2024-03-23 16:01:49 +07:00
12fc9e6353 New feature: apply video filters to screenshots 2024-03-23 15:55:46 +07:00
2eaca3e441 Add support for the screenshot feature in Android app 2024-03-23 11:27:17 +07:00
6d28e88b85 Merge branch 'main' of https://github.com/redphx/better-xcloud 2024-03-23 11:26:29 +07:00
259543cbaf Update README.md 2024-03-22 17:44:03 +07:00
ff9df84fb8 Don't render settings on unsupported features 2024-03-22 17:40:01 +07:00
2157d9cd41 Use BX_FLAGS to control feature flags 2024-03-22 17:24:05 +07:00
10e8a96a18 Update translations 2024-03-22 04:31:17 +07:00
7201efba9c Bump version to 3.2.5 2024-03-22 04:26:30 +07:00
e6504d246f Fix crashing on Kiwi v124 2024-03-22 04:21:55 +07:00
3847c27a1d Update issue templates 2024-03-21 09:45:23 +07:00
1e56e7b2a2 Fix loading time box not hidden sometimes 2024-03-20 17:56:21 +07:00
0d80edb7cb Swap position of "Low" & "High" values in "Visual quality" setting 2024-03-20 17:27:03 +07:00
b11a89037a Add back the "Off" option for "Touch controller > Availability" setting 2024-03-20 17:23:42 +07:00
ac08f657bb Add 18:9 screen ratio 2024-03-20 17:02:21 +07:00
469bac6693 Update README.md 2024-03-16 17:49:03 +07:00
5 changed files with 157 additions and 74 deletions

View File

@ -7,6 +7,8 @@ assignees: ''
--- ---
<!-- ⚠️ Only use English. Any other languages will be deleted. -->
**Platform** **Platform**
- Device: Phone, Laptop, Desktop, TV... - Device: Phone, Laptop, Desktop, TV...
- OS: Windows, Android, iOS... - OS: Windows, Android, iOS...

View File

@ -7,10 +7,12 @@ assignees: ''
--- ---
<!-- ⚠️ Only use English. Any other languages will be deleted. -->
**I'm using:** **I'm using:**
- Device: - Device:
- OS: - OS:
- Browser: - Browser:
**I want to suggest this feature:** **I want to suggest this feature:**
... ...

View File

@ -1,6 +1,12 @@
# Better xCloud # Better xCloud
Improve Xbox Cloud Gaming (xCloud) experience on [xbox.com/play](https://www.xbox.com/play). It also allows you to use Remote Play on the xCloud website. Improve Xbox Cloud Gaming (xCloud) experience on [xbox.com/play](https://www.xbox.com/play). It also allows you to use Remote Play on the xCloud website.
> [!TIP]
> The Android app is in development at [redphx/better-xcloud-android](https://github.com/redphx/better-xcloud-android)
> [!IMPORTANT]
> I don't accept pull requests at the moment (except PR for custom touch controls)
**Supported platforms:** **Supported platforms:**
- Windows - Windows
- macOS - macOS

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 3.2.4 // @version 3.3.0
// ==/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 3.2.4 // @version 3.3.0
// @description Improve Xbox Cloud Gaming (xCloud) experience // @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx // @author redphx
// @license MIT // @license MIT
@ -14,12 +14,23 @@
// ==/UserScript== // ==/UserScript==
'use strict'; 'use strict';
const SCRIPT_VERSION = '3.2.4'; /* ADDITIONAL CODE */
const SCRIPT_VERSION = '3.3.0';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud'; const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_XCLOUD_LOGGER = false; // Setup flags
const ENABLE_PRELOAD_BX_UI = false; const DEFAULT_FLAGS = {
const USE_DEV_TOUCH_LAYOUT = false; PreloadUi: false,
EnableXcloudLogging: false,
UseDevTouchLayout: false,
}
const BX_FLAGS = Object.assign(DEFAULT_FLAGS, window.BX_FLAGS || {});
delete window.BX_FLAGS;
const AppInterface = window.AppInterface;
let REMOTE_PLAY_SERVER; let REMOTE_PLAY_SERVER;
@ -89,7 +100,7 @@ const BxEvent = {
} }
} }
window.AppInterface && window.AppInterface.onEvent(eventName); AppInterface && AppInterface.onEvent(eventName);
target.dispatchEvent(event); target.dispatchEvent(event);
}, },
}; };
@ -558,7 +569,7 @@ const Translations = {
"Cancel", "Cancel",
"Cancelar", "Cancelar",
, ,
, "Cancella",
"キャンセル", "キャンセル",
"취소", "취소",
"Anuluj", "Anuluj",
@ -779,7 +790,7 @@ const Translations = {
"Controller shortcuts", "Controller shortcuts",
"Habilitar atajos del Joystick", "Habilitar atajos del Joystick",
, ,
, "Abilita scrociatorie da controller",
"コントローラーショートカット", "コントローラーショートカット",
, ,
"Skróty kontrolera", "Skróty kontrolera",
@ -881,7 +892,7 @@ const Translations = {
"Delete", "Delete",
"Borrar", "Borrar",
, ,
, "Elimina",
"削除", "削除",
"삭제", "삭제",
"Usuń", "Usuń",
@ -1041,7 +1052,7 @@ const Translations = {
"Desconectado", "Desconectado",
"Отключен", "Отключен",
"Bağlı değil", "Bağlı değil",
"Роз’єднано", "Від'єднано",
"Đã ngắt kết nối", "Đã ngắt kết nối",
"已断开连接", "已断开连接",
], ],
@ -1051,7 +1062,7 @@ const Translations = {
"Edit", "Edit",
"Editar", "Editar",
, ,
, "Modifica",
"編集", "編集",
"편집", "편집",
"Edytuj", "Edytuj",
@ -1136,7 +1147,7 @@ const Translations = {
"Emulate controller with Mouse & Keyboard", "Emulate controller with Mouse & Keyboard",
"Emular mandos con teclado y ratón", "Emular mandos con teclado y ratón",
, ,
"Abilitare il supporto di mouse e tastiera", "Abilita il supporto per mouse e tastiera",
"マウス&キーボード操作をコントローラー化", "マウス&キーボード操作をコントローラー化",
"마우스 & 키보드 활성화", "마우스 & 키보드 활성화",
"Emuluj kontroler za pomocą myszy i klawiatury", "Emuluj kontroler za pomocą myszy i klawiatury",
@ -1179,7 +1190,7 @@ const Translations = {
"\"Uzaktan Oynama\" özelliğini aktive et", "\"Uzaktan Oynama\" özelliğini aktive et",
"Увімкнути функцію \"Remote Play\"", "Увімкнути функцію \"Remote Play\"",
"Bật tính năng \"Chơi Từ Xa\"", "Bật tính năng \"Chơi Từ Xa\"",
"启用\"远程播放\"功能", "启用\"Remote Play\"主机串流",
], ],
"enable-volume-control": [ "enable-volume-control": [
"Lautstärkeregelung aktivieren", "Lautstärkeregelung aktivieren",
@ -1272,7 +1283,7 @@ const Translations = {
"Fortnite: force console version", "Fortnite: force console version",
"Fortnite: forzar versión de consola", "Fortnite: forzar versión de consola",
, ,
, "Fortnite: Foza la versione console",
"Fortnite: 強制的にコンソール版を起動する", "Fortnite: 強制的にコンソール版を起動する",
, ,
"Fortnite: wymuś wersję konsolową", "Fortnite: wymuś wersję konsolową",
@ -1394,10 +1405,10 @@ const Translations = {
, ,
"Android用のBetter xCloudをインストール", "Android用のBetter xCloudをインストール",
, ,
, "Zainstaluj aplikację Better xCloud na Androida",
"Instalar o aplicativo Better xCloud para Android", "Instalar o aplicativo Better xCloud para Android",
"Установите приложение Better xCloud для Android", "Установите приложение Better xCloud для Android",
, "Better xCloud'un Android uygulamasını indir",
"Встановити додаток Better xCloud для Android", "Встановити додаток Better xCloud для Android",
"Cài đặt ứng dụng Better xCloud cho Android", "Cài đặt ứng dụng Better xCloud cho Android",
"安装Better xCloud安卓客户端", "安装Better xCloud安卓客户端",
@ -1612,7 +1623,7 @@ const Translations = {
"You may also need to adjust the in-game sensitivity & deadzone settings", "You may also need to adjust the in-game sensitivity & deadzone settings",
"También puede que necesites ajustar la sensibilidad del juego y la configuración de la zona muerta", "También puede que necesites ajustar la sensibilidad del juego y la configuración de la zona muerta",
, ,
, "Potrebbe anche essere necessario regolare le impostazioni della sensibilità e deadzone del gioco",
"ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります", "ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります",
, ,
"Może być również konieczne dostosowanie czułości w grze i ustawienia 'martwej strefy' urządzenia", "Może być również konieczne dostosowanie czułości w grze i ustawienia 'martwej strefy' urządzenia",
@ -1629,7 +1640,7 @@ const Translations = {
"Click to activate", "Click to activate",
"Haz clic para activar", "Haz clic para activar",
, ,
, "Fare clic per attivare",
"マウスクリックで開始", "マウスクリックで開始",
, ,
"Kliknij, aby aktywować", "Kliknij, aby aktywować",
@ -1646,7 +1657,7 @@ const Translations = {
"Using this feature when playing online could be viewed as cheating", "Using this feature when playing online could be viewed as cheating",
"Usar esta función al jugar en línea podría ser visto como trampas", "Usar esta función al jugar en línea podría ser visto como trampas",
, ,
, "L'utilizzo di questa funzione quando si gioca online potrebbe essere considerato un baro",
"オンラインプレイでこの機能を使用すると不正行為と判定される可能性があります", "オンラインプレイでこの機能を使用すると不正行為と判定される可能性があります",
, ,
"Używanie tej funkcji podczas grania online może być postrzegane jako oszukiwanie", "Używanie tej funkcji podczas grania online może być postrzegane jako oszukiwanie",
@ -1850,7 +1861,7 @@ const Translations = {
"Playing", "Playing",
"Jugando", "Jugando",
, ,
, "Installa l'applicazione Better xCloud per Android",
"プレイ中", "プレイ中",
"플레이 중", "플레이 중",
"W grze", "W grze",
@ -2097,7 +2108,7 @@ const Translations = {
"Uzaktan Bağlanma", "Uzaktan Bağlanma",
"Віддалена гра", "Віддалена гра",
"Chơi Từ Xa", "Chơi Từ Xa",
"远程游玩", "远程串流",
], ],
"rename": [ "rename": [
"Umbenennen", "Umbenennen",
@ -2269,6 +2280,23 @@ const Translations = {
"Lưu", "Lưu",
"保存", "保存",
], ],
"screenshot-apply-filters": [
,
,
"Applies video filters to screenshots",
,
,
,
"スクリーンショットにビデオフィルターを適用",
,
,
,
"Применяет фильтры видео к скриншотам",
,
"Застосовує відеофільтри до знімків екрана",
"Áp dụng hiệu ứng video vào ảnh chụp màn hình",
,
],
"screenshot-button-position": [ "screenshot-button-position": [
"Position des Screenshot-Buttons", "Position des Screenshot-Buttons",
"Posisi tombol Screenshot", "Posisi tombol Screenshot",
@ -2282,7 +2310,7 @@ const Translations = {
"Posição do botão de captura de tela", "Posição do botão de captura de tela",
"Расположение кнопки скриншота", "Расположение кнопки скриншота",
"Ekran görüntüsü düğmesi konumu", "Ekran görüntüsü düğmesi konumu",
"Позиція кнопки скриншоту", "Позиція кнопки знімка екрана",
"Vị trí của nút Chụp màn hình", "Vị trí của nút Chụp màn hình",
"截图按钮位置", "截图按钮位置",
], ],
@ -2299,7 +2327,7 @@ const Translations = {
"Separar o Controle por Toque e o Controle #1", "Separar o Controle por Toque e o Controle #1",
"Раздельный сенсорный контроллер и контроллер #1", "Раздельный сенсорный контроллер и контроллер #1",
"Dokunmatik kumandayı ve birincil kumandayı ayrı tut", "Dokunmatik kumandayı ve birincil kumandayı ayrı tut",
"Окремо Сенсорний контролер та Контролер #1", "Відокремити Сенсорний контролер та Контролер #1",
"Tách biệt Bộ điều khiển cảm ứng và Tay cầm #1", "Tách biệt Bộ điều khiển cảm ứng và Tay cầm #1",
"虚拟摇杆和手柄分别控制不同角色", "虚拟摇杆和手柄分别控制不同角色",
], ],
@ -2768,7 +2796,7 @@ const Translations = {
"Swap buttons", "Swap buttons",
"Intercambiar botones", "Intercambiar botones",
, ,
, "Inverti i pulsanti",
"ボタン入れ替え", "ボタン入れ替え",
"버튼 바꾸기", "버튼 바꾸기",
"Zamień przyciski", "Zamień przyciski",
@ -2945,7 +2973,7 @@ const Translations = {
"Superior-centralizado", "Superior-centralizado",
"Сверху", "Сверху",
"Orta üst", "Orta üst",
"Зверху праворуч", "Зверху по центру",
"Chính giữa phía trên", "Chính giữa phía trên",
"顶部居中", "顶部居中",
], ],
@ -2989,7 +3017,7 @@ const Translations = {
"Touch control layout", "Touch control layout",
"Diseño de control táctil", "Diseño de control táctil",
, ,
, "Controller Touch",
"タッチコントロールレイアウト", "タッチコントロールレイアウト",
, ,
"Układ sterowania dotykowego", "Układ sterowania dotykowego",
@ -3142,7 +3170,7 @@ const Translations = {
"Vertical sensitivity", "Vertical sensitivity",
"Sensibilidad Vertical", "Sensibilidad Vertical",
, ,
, "Sensibilità Verticale",
"上下方向の感度", "上下方向の感度",
, ,
"Czułość pionowa", "Czułość pionowa",
@ -3302,7 +3330,7 @@ const Translations = {
"Tempo estimado de conclusão", "Tempo estimado de conclusão",
"Примерное время запуска", "Примерное время запуска",
"Tahminî bitiş süresi", "Tahminî bitiş süresi",
"Розрахунковий час завершення", "Орієнтовний час завершення",
"Thời gian hoàn thành dự kiến", "Thời gian hoàn thành dự kiến",
"预计等待时间", "预计等待时间",
], ],
@ -3960,7 +3988,7 @@ class LoadingScreen {
LoadingScreen.#orgWebTitle && (document.title = LoadingScreen.#orgWebTitle); LoadingScreen.#orgWebTitle && (document.title = LoadingScreen.#orgWebTitle);
LoadingScreen.#$waitTimeBox && LoadingScreen.#$waitTimeBox.classList.add('bx-gone'); LoadingScreen.#$waitTimeBox && LoadingScreen.#$waitTimeBox.classList.add('bx-gone');
if (LoadingScreen.#$bgStyle) { if (getPref(Preferences.UI_LOADING_SCREEN_GAME_ART) && LoadingScreen.#$bgStyle) {
const $rocketBg = document.querySelector('#game-stream rect[width="800"]'); const $rocketBg = document.querySelector('#game-stream rect[width="800"]');
$rocketBg && $rocketBg.addEventListener('transitionend', e => { $rocketBg && $rocketBg.addEventListener('transitionend', e => {
LoadingScreen.#$bgStyle.textContent += ` LoadingScreen.#$bgStyle.textContent += `
@ -4091,7 +4119,7 @@ class TouchController {
return; return;
} }
const baseUrl = `https://raw.githubusercontent.com/redphx/better-xcloud/gh-pages/touch-layouts${USE_DEV_TOUCH_LAYOUT ? '/dev' : ''}`; const baseUrl = `https://raw.githubusercontent.com/redphx/better-xcloud/gh-pages/touch-layouts${BX_FLAGS.UseDevTouchLayout ? '/dev' : ''}`;
const url = `${baseUrl}/${xboxTitleId}.json`; const url = `${baseUrl}/${xboxTitleId}.json`;
// Get layout info // Get layout info
@ -6191,7 +6219,7 @@ class VibrationManager {
static #playDeviceVibration(data) { static #playDeviceVibration(data) {
// console.log(+new Date, data); // console.log(+new Date, data);
if ('AppInterface' in window) { if (AppInterface) {
AppInterface.vibrate(JSON.stringify(data), window.BX_VIBRATION_INTENSITY); AppInterface.vibrate(JSON.stringify(data), window.BX_VIBRATION_INTENSITY);
return; return;
} }
@ -6917,13 +6945,22 @@ class UserAgent {
} }
static spoof() { static spoof() {
let newUserAgent;
const profile = getPref(Preferences.USER_AGENT_PROFILE); const profile = getPref(Preferences.USER_AGENT_PROFILE);
if (profile === UserAgent.PROFILE_DEFAULT) { if (profile === UserAgent.PROFILE_DEFAULT) {
return; // Fix Kiwi 124
if (window.navigator.userAgent.includes('Chrome/124.0.0.0')) {
newUserAgent = window.navigator.userAgent.replace('Chrome/124.0.0.0', 'Chrome/122.0.0.0')
} else {
return;
}
} }
const defaultUserAgent = window.navigator.userAgent; if (!newUserAgent) {
const userAgent = UserAgent.get(profile) || defaultUserAgent; newUserAgent = UserAgent.get(profile) || defaultUserAgent;
}
// Clear data of navigator.userAgentData, force xCloud to detect browser based on navigator.userAgent // Clear data of navigator.userAgentData, force xCloud to detect browser based on navigator.userAgent
Object.defineProperty(window.navigator, 'userAgentData', {}); Object.defineProperty(window.navigator, 'userAgentData', {});
@ -6931,10 +6968,10 @@ class UserAgent {
// Override navigator.userAgent // Override navigator.userAgent
window.navigator.orgUserAgent = window.navigator.userAgent; window.navigator.orgUserAgent = window.navigator.userAgent;
Object.defineProperty(window.navigator, 'userAgent', { Object.defineProperty(window.navigator, 'userAgent', {
value: userAgent, value: newUserAgent,
}); });
return userAgent; return newUserAgent;
} }
} }
@ -7011,6 +7048,8 @@ class Preferences {
static get MKB_DEFAULT_PRESET_ID() { return 'mkb_default_preset_id'; } static get MKB_DEFAULT_PRESET_ID() { return 'mkb_default_preset_id'; }
static get SCREENSHOT_BUTTON_POSITION() { return 'screenshot_button_position'; } static get SCREENSHOT_BUTTON_POSITION() { return 'screenshot_button_position'; }
static get SCREENSHOT_APPLY_FILTERS() { return 'screenshot_apply_filters'; }
static get BLOCK_TRACKING() { return 'block_tracking'; } static get BLOCK_TRACKING() { return 'block_tracking'; }
static get BLOCK_SOCIAL_FEATURES() { return 'block_social_features'; } static get BLOCK_SOCIAL_FEATURES() { return 'block_social_features'; }
static get SKIP_SPLASH_VIDEO() { return 'skip_splash_video'; } static get SKIP_SPLASH_VIDEO() { return 'skip_splash_video'; }
@ -7155,13 +7194,14 @@ class Preferences {
} }
} }
if (hasLowCodec) { if (hasHighCodec) {
if (!hasNormalCodec && !hasHighCodec) { if (!hasLowCodec && !hasNormalCodec) {
options.default = `${t('visual-quality-low')} (${t('default')})`; options.default = `${t('visual-quality-high')} (${t('default')})`;
} else { } else {
options.low = t('visual-quality-low'); options.high = t('visual-quality-high');
} }
} }
if (hasNormalCodec) { if (hasNormalCodec) {
if (!hasLowCodec && !hasHighCodec) { if (!hasLowCodec && !hasHighCodec) {
options.default = `${t('visual-quality-normal')} (${t('default')})`; options.default = `${t('visual-quality-normal')} (${t('default')})`;
@ -7169,11 +7209,12 @@ class Preferences {
options.normal = t('visual-quality-normal'); options.normal = t('visual-quality-normal');
} }
} }
if (hasHighCodec) {
if (!hasLowCodec && !hasNormalCodec) { if (hasLowCodec) {
options.default = `${t('visual-quality-high')} (${t('default')})`; if (!hasNormalCodec && !hasHighCodec) {
options.default = `${t('visual-quality-low')} (${t('default')})`;
} else { } else {
options.high = t('visual-quality-high'); options.low = t('visual-quality-low');
} }
} }
@ -7196,6 +7237,7 @@ class Preferences {
[Preferences.PREFER_IPV6_SERVER]: { [Preferences.PREFER_IPV6_SERVER]: {
'default': false, 'default': false,
}, },
[Preferences.SCREENSHOT_BUTTON_POSITION]: { [Preferences.SCREENSHOT_BUTTON_POSITION]: {
'default': 'bottom-left', 'default': 'bottom-left',
'options': { 'options': {
@ -7204,6 +7246,10 @@ class Preferences {
'none': t('disable'), 'none': t('disable'),
}, },
}, },
[Preferences.SCREENSHOT_APPLY_FILTERS]: {
'default': false,
},
[Preferences.SKIP_SPLASH_VIDEO]: { [Preferences.SKIP_SPLASH_VIDEO]: {
'default': false, 'default': false,
}, },
@ -7216,6 +7262,7 @@ class Preferences {
'options': { 'options': {
'default': t('default'), 'default': t('default'),
'all': t('tc-all-games'), 'all': t('tc-all-games'),
'off': t('off'),
}, },
'unsupported': !HAS_TOUCH_SUPPORT, 'unsupported': !HAS_TOUCH_SUPPORT,
'ready': () => { 'ready': () => {
@ -7393,6 +7440,7 @@ class Preferences {
'default': '16:9', 'default': '16:9',
'options': { 'options': {
'16:9': '16:9', '16:9': '16:9',
'18:9': '18:9',
'21:9': '21:9', '21:9': '21:9',
'16:10': '16:10', '16:10': '16:10',
'4:3': '4:3', '4:3': '4:3',
@ -8004,7 +8052,11 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
return false; return false;
} }
const newCode = ` let newCode = '';
if (getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'off') {
newCode = 'return;';
} else {
newCode = `
const gamepads = window.navigator.getGamepads(); const gamepads = window.navigator.getGamepads();
let gamepadFound = false; let gamepadFound = false;
@ -8019,6 +8071,7 @@ if (gamepadFound) {
return; return;
} }
`; `;
}
funcStr = funcStr.replace(text, newCode + text); funcStr = funcStr.replace(text, newCode + text);
return funcStr; return funcStr;
@ -8035,7 +8088,7 @@ if (gamepadFound) {
getPref(Preferences.UI_LAYOUT) === 'tv' && ['tvLayout'], getPref(Preferences.UI_LAYOUT) === 'tv' && ['tvLayout'],
ENABLE_XCLOUD_LOGGER && [ BX_FLAGS.EnableXcloudLogging && [
'enableConsoleLogging', 'enableConsoleLogging',
'enableXcloudLogger', 'enableXcloudLogger',
], ],
@ -8068,9 +8121,9 @@ if (gamepadFound) {
['playVibration'], ['playVibration'],
HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'all' && ['exposeTouchLayoutManager'], HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'all' && ['exposeTouchLayoutManager'],
HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER_AUTO_OFF) && ['disableTakRenderer'], HAS_TOUCH_SUPPORT && (getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'off' || getPref(Preferences.STREAM_TOUCH_CONTROLLER_AUTO_OFF)) && ['disableTakRenderer'],
ENABLE_XCLOUD_LOGGER && ['enableConsoleLogging'], BX_FLAGS.EnableXcloudLogging && ['enableConsoleLogging'],
getPref(Preferences.BLOCK_TRACKING) && ['blockGamepadStatsCollector'], getPref(Preferences.BLOCK_TRACKING) && ['blockGamepadStatsCollector'],
@ -8621,6 +8674,10 @@ a.bx-button.bx-full-width {
color: #828282; color: #828282;
} }
.bx-settings-group-label b {
margin-bottom: 8px;
}
@media not (hover: hover) { @media not (hover: hover) {
.bx-settings-row:focus-within { .bx-settings-row:focus-within {
background-color: #242424; background-color: #242424;
@ -8720,12 +8777,9 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
box-sizing: border-box; box-sizing: border-box;
width: 16vh; width: 60px;
height: 16vh; height: 60px;
max-width: 128px; padding: 16px;
max-height: 128px;
padding: 2vh;
padding: 24px 24px 12px 12px;
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
background-origin: content-box; background-origin: content-box;
@ -8742,7 +8796,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
} }
.bx-screenshot-button[data-capturing=true] { .bx-screenshot-button[data-capturing=true] {
padding: 1vh; padding: 8px;
} }
.bx-screenshot-canvas { .bx-screenshot-canvas {
@ -10251,7 +10305,7 @@ function injectSettingsButton($parent) {
} }
// Show link to Android app // Show link to Android app
if (!window.AppInterface) { if (!AppInterface) {
const userAgent = UserAgent.getDefault().toLowerCase(); const userAgent = UserAgent.getDefault().toLowerCase();
if (userAgent.includes('android')) { if (userAgent.includes('android')) {
const $btn = createButton({ const $btn = createButton({
@ -10284,6 +10338,9 @@ function injectSettingsButton($parent) {
[Preferences.AUDIO_ENABLE_VOLUME_CONTROL]: t('enable-volume-control'), [Preferences.AUDIO_ENABLE_VOLUME_CONTROL]: t('enable-volume-control'),
[Preferences.AUDIO_MIC_ON_PLAYING]: t('enable-mic-on-startup'), [Preferences.AUDIO_MIC_ON_PLAYING]: t('enable-mic-on-startup'),
[Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: t('disable-post-stream-feedback-dialog'), [Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: t('disable-post-stream-feedback-dialog'),
[Preferences.SCREENSHOT_BUTTON_POSITION]: t('screenshot-button-position'),
[Preferences.SCREENSHOT_APPLY_FILTERS]: t('screenshot-apply-filters'),
}, },
[t('local-co-op')]: { [t('local-co-op')]: {
@ -10292,8 +10349,6 @@ function injectSettingsButton($parent) {
}, },
[t('mouse-and-keyboard')]: { [t('mouse-and-keyboard')]: {
// '_note': '⚠️ ' + t('may-not-work-properly'),
// [Preferences.MKB_ENABLED]: [t('enable-mkb'), t('only-supports-some-games')],
[Preferences.MKB_ENABLED]: t('enable-mkb'), [Preferences.MKB_ENABLED]: t('enable-mkb'),
[Preferences.MKB_HIDE_IDLE_CURSOR]: t('hide-idle-cursor'), [Preferences.MKB_HIDE_IDLE_CURSOR]: t('hide-idle-cursor'),
}, },
@ -10306,6 +10361,7 @@ function injectSettingsButton($parent) {
[t('touch-controller')]: { [t('touch-controller')]: {
_note: !HAS_TOUCH_SUPPORT ? '⚠️ ' + t('device-unsupported-touch') : null, _note: !HAS_TOUCH_SUPPORT ? '⚠️ ' + t('device-unsupported-touch') : null,
_unsupported: !HAS_TOUCH_SUPPORT,
[Preferences.STREAM_TOUCH_CONTROLLER]: t('tc-availability'), [Preferences.STREAM_TOUCH_CONTROLLER]: t('tc-availability'),
[Preferences.STREAM_TOUCH_CONTROLLER_AUTO_OFF]: t('tc-auto-off'), [Preferences.STREAM_TOUCH_CONTROLLER_AUTO_OFF]: t('tc-auto-off'),
[Preferences.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: t('tc-standard-layout-style'), [Preferences.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: t('tc-standard-layout-style'),
@ -10323,7 +10379,6 @@ function injectSettingsButton($parent) {
[Preferences.SKIP_SPLASH_VIDEO]: t('skip-splash-video'), [Preferences.SKIP_SPLASH_VIDEO]: t('skip-splash-video'),
[Preferences.HIDE_DOTS_ICON]: t('hide-system-menu-icon'), [Preferences.HIDE_DOTS_ICON]: t('hide-system-menu-icon'),
[Preferences.REDUCE_ANIMATIONS]: t('reduce-animations'), [Preferences.REDUCE_ANIMATIONS]: t('reduce-animations'),
[Preferences.SCREENSHOT_BUTTON_POSITION]: t('screenshot-button-position'),
}, },
[t('other')]: { [t('other')]: {
[Preferences.BLOCK_SOCIAL_FEATURES]: t('disable-social-features'), [Preferences.BLOCK_SOCIAL_FEATURES]: t('disable-social-features'),
@ -10345,6 +10400,11 @@ function injectSettingsButton($parent) {
$wrapper.appendChild($group); $wrapper.appendChild($group);
// Don't render settings if this is an unsupported feature
if (SETTINGS_UI[groupLabel]._unsupported) {
continue;
}
let onChange = e => { let onChange = e => {
if (!$reloadBtnWrapper) { if (!$reloadBtnWrapper) {
return; return;
@ -10363,6 +10423,7 @@ function injectSettingsButton($parent) {
}; };
for (let settingId in SETTINGS_UI[groupLabel]) { for (let settingId in SETTINGS_UI[groupLabel]) {
// Don't render custom settings
if (settingId.startsWith('_')) { if (settingId.startsWith('_')) {
continue; continue;
} }
@ -10557,6 +10618,11 @@ function updateVideoPlayerCss() {
videoCss += `filter: ${filters} !important;`; videoCss += `filter: ${filters} !important;`;
} }
// Apply video filters to screenshots
if (getPref(Preferences.SCREENSHOT_APPLY_FILTERS)) {
$SCREENSHOT_CANVAS.getContext('2d').filter = filters;
}
const PREF_RATIO = getPref(Preferences.VIDEO_RATIO); const PREF_RATIO = getPref(Preferences.VIDEO_RATIO);
if (PREF_RATIO && PREF_RATIO !== '16:9') { if (PREF_RATIO && PREF_RATIO !== '16:9') {
if (PREF_RATIO.includes(':')) { if (PREF_RATIO.includes(':')) {
@ -11309,6 +11375,15 @@ function takeScreenshot(callback) {
const $canvasContext = $SCREENSHOT_CANVAS.getContext('2d'); const $canvasContext = $SCREENSHOT_CANVAS.getContext('2d');
$canvasContext.drawImage($STREAM_VIDEO, 0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height); $canvasContext.drawImage($STREAM_VIDEO, 0, 0, $SCREENSHOT_CANVAS.width, $SCREENSHOT_CANVAS.height);
// Get data URL and pass to parent app
if (AppInterface) {
const data = $SCREENSHOT_CANVAS.toDataURL('image/png').split(';base64,')[1];
AppInterface.saveScreenshot(GAME_TITLE_ID, data);
callback && callback();
return;
}
$SCREENSHOT_CANVAS.toBlob(blob => { $SCREENSHOT_CANVAS.toBlob(blob => {
// Download screenshot // Download screenshot
const now = +new Date; const now = +new Date;
@ -11427,18 +11502,15 @@ function disablePwa() {
} }
function setupBxUi() { function setupBxUi() {
updateVideoPlayerCss();
// Prevent initializing multiple times // Prevent initializing multiple times
if (document.querySelector('.bx-quick-settings-bar')) { if (!document.querySelector('.bx-quick-settings-bar')) {
return; window.addEventListener('resize', updateVideoPlayerCss);
setupQuickSettingsBar();
setupScreenshotButton();
StreamStats.render();
} }
window.addEventListener('resize', updateVideoPlayerCss); updateVideoPlayerCss();
setupQuickSettingsBar();
setupScreenshotButton();
StreamStats.render();
} }
@ -11470,7 +11542,7 @@ window.addEventListener(BxEvent.STREAM_LOADING, e => {
window.addEventListener(BxEvent.STREAM_STARTING, e => { window.addEventListener(BxEvent.STREAM_STARTING, e => {
// Hide loading screen // Hide loading screen
getPref(Preferences.UI_LOADING_SCREEN_GAME_ART) && LoadingScreen.hide(); LoadingScreen.hide();
}); });
window.addEventListener(BxEvent.STREAM_PLAYING, e => { window.addEventListener(BxEvent.STREAM_PLAYING, e => {
@ -11488,6 +11560,7 @@ window.addEventListener(BxEvent.STREAM_PLAYING, e => {
const PREF_SCREENSHOT_BUTTON_POSITION = getPref(Preferences.SCREENSHOT_BUTTON_POSITION); const PREF_SCREENSHOT_BUTTON_POSITION = getPref(Preferences.SCREENSHOT_BUTTON_POSITION);
$SCREENSHOT_CANVAS.width = $video.videoWidth; $SCREENSHOT_CANVAS.width = $video.videoWidth;
$SCREENSHOT_CANVAS.height = $video.videoHeight; $SCREENSHOT_CANVAS.height = $video.videoHeight;
updateVideoPlayerCss();
// Setup screenshot button // Setup screenshot button
if (PREF_SCREENSHOT_BUTTON_POSITION !== 'none') { if (PREF_SCREENSHOT_BUTTON_POSITION !== 'none') {
@ -11623,7 +11696,7 @@ patchVideoApi();
// Setup UI // Setup UI
addCss(); addCss();
Toast.setup(); Toast.setup();
ENABLE_PRELOAD_BX_UI && setupBxUi(); BX_FLAGS.PreloadUi && setupBxUi();
disablePwa(); disablePwa();