Compare commits

...

15 Commits
v3.0 ... v3.0.1

Author SHA1 Message Date
redphx
675aac207f Bump version to 3.0.1 2024-01-06 19:08:17 +07:00
redphx
0c7a6153f2 Update translations 2024-01-06 18:03:08 +07:00
redphx
d3ce3dd26d Update translations 2024-01-06 17:38:25 +07:00
redphx
25d87c5367 Allow connecting to IPv6 address when Remote Playing 2024-01-06 16:46:34 +07:00
redphx
989634b52e Clear logs in DB 2024-01-06 16:04:07 +07:00
redphx
281787d955 Fix iPhone detection 2024-01-06 15:47:34 +07:00
redphx
9d4eaf8024 Fix StreamHud not collapsing when clicking on custom buttons 2024-01-06 15:38:00 +07:00
redphx
4c601234ef Fix the StreamHud buttons being wonky 2024-01-06 14:38:18 +07:00
redphx
e8de67c817 Optimize Patcher.#patchFunctionBind() 2024-01-06 12:05:08 +07:00
redphx
c3d37b7034 Another attempt to fix the StreamMenu buttons 2024-01-06 11:51:02 +07:00
redphx
03926451ec Fix some buttons not hiding when the System menu bar is collapsed 2024-01-06 11:12:41 +07:00
redphx
dac5b39097 Disable the MKB feature for mobile browsers 2024-01-06 10:36:41 +07:00
redphx
9332892353 Add "unsupported" property to Preferences.SETTINGS 2024-01-06 10:21:35 +07:00
redphx
00041eb911 Use a different method to disable StreamGate (#210) 2024-01-06 08:12:49 +07:00
redphx
6c996769b7 Update README.md 2024-01-05 17:18:52 +07:00
3 changed files with 258 additions and 79 deletions

View File

@@ -30,7 +30,7 @@ Visit [this page](https://better-xcloud.github.io/browsers) to know how to insta
## Features
<img width="400" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/ca38b3fa-1e89-4b37-937c-a6796c07cdf1">
<img width="400" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/4bec2d62-31df-499c-9aad-2485626b6925">
<br>
<img width="400" alt="Remote Play dialog" src="https://github.com/redphx/better-xcloud/assets/96280/daf7f698-a228-4f9c-8f23-9669e061a64c">
<br>
@@ -56,12 +56,15 @@ Visit [this page](https://better-xcloud.github.io/browsers) to know how to insta
> Enable touch controller support for all games.
- [And more...](https://better-xcloud.github.io/features/)
## Donation
If you think this project is useful and want to support future developments, please consider making a donate via [my Ko-fi page](https://ko-fi.com/redphx).
Or you can give this project a star, that's also helpful.
Thank you.
## Translation
Help translating **Better xCloud** to another languagues using [Crowdin](https://crowdin.com/project/better-xcloud).
Use [this post](https://github.com/redphx/better-xcloud/discussions/131) for discussion.
## Acknowledgements
- The mouse controlling feature is heavily inspired by the "Mouse spinning" feature in [Yuzu emulator](https://github.com/yuzu-emu/yuzu-mainline)
- [n-thumann/xbox-cloud-server-selector](https://github.com/n-thumann/xbox-cloud-server-selector) for the idea of IPv6 feature

View File

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

View File

@@ -1,7 +1,7 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
// @version 3.0
// @version 3.0.1
// @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx
// @license MIT
@@ -13,7 +13,7 @@
// ==/UserScript==
'use strict';
const SCRIPT_VERSION = '3.0';
const SCRIPT_VERSION = '3.0.1';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_XCLOUD_LOGGER = false;
@@ -158,19 +158,27 @@ const Translations = {
"activate": {
"de-DE": "Aktivieren",
"en-US": "Activate",
"ja-JP": "有効にする",
"es-ES": "Activo",
"ja-JP": "設定する",
"ko-KR": "활성화",
"pl-PL": "Aktywuj",
"pt-BR": "Ativar",
"ru-RU": "Активировать",
"tr-TR": "Etkinleştir",
"uk-UA": "Активувати",
"vi-VN": "Kích hoạt",
},
"activated": {
"de-DE": "Aktiviert",
"en-US": "Activated",
"ja-JP": "有効化済み",
"es-ES": "Activado",
"ja-JP": "設定中",
"ko-KR": "활성화 됨",
"pl-PL": "Aktywowane",
"pt-BR": "Ativado",
"ru-RU": "Активирован",
"tr-TR": "Etkin",
"uk-UA": "Активований",
"vi-VN": "Đã kích hoạt",
},
"active": {
@@ -180,6 +188,8 @@ const Translations = {
"ja-JP": "有効",
"ko-KR": "활성화",
"pl-PL": "Aktywny",
"pt-BR": "Ativo",
"ru-RU": "Активный",
"tr-TR": "Etkin",
"uk-UA": "Активний",
"vi-VN": "Hoạt động",
@@ -204,8 +214,12 @@ const Translations = {
"apply": {
"de-DE": "Anwenden",
"en-US": "Apply",
"es-ES": "Aplicar",
"ja-JP": "適用",
"pt-BR": "Aplicar",
"ru-RU": "Применить",
"tr-TR": "Uygula",
"uk-UA": "Застосувати",
"vi-VN": "Áp dụng",
},
"audio": {
@@ -438,6 +452,8 @@ const Translations = {
"ja-JP": "キャンセル",
"ko-KR": "취소",
"pl-PL": "Anuluj",
"pt-BR": "Cancelar",
"ru-RU": "Отмена",
"tr-TR": "Vazgeç",
"uk-UA": "Скасувати",
"vi-VN": "Hủy",
@@ -497,6 +513,8 @@ const Translations = {
"ja-JP": "消去",
"ko-KR": "비우기",
"pl-PL": "Wyczyść",
"pt-BR": "Limpar",
"ru-RU": "Очистить",
"tr-TR": "Temizle",
"uk-UA": "Очистити",
"vi-VN": "Xóa",
@@ -541,6 +559,8 @@ const Translations = {
"ja-JP": "このプリセットを削除しますか?",
"ko-KR": "이 프리셋을 삭제하시겠습니까?",
"pl-PL": "Czy na pewno chcesz usunąć ten szablon?",
"pt-BR": "Você quer excluir esta predefinição?",
"ru-RU": "Вы точно хотите удалить этот шаблон?",
"tr-TR": "Bu hazır ayarı silmek istiyor musunuz?",
"uk-UA": "Ви бажаєте видалити цей пресет?",
"vi-VN": "Bạn có muốn xoá thiết lập sẵn này không?",
@@ -625,10 +645,14 @@ const Translations = {
"copy": {
"de-DE": "Kopieren",
"en-US": "Copy",
"es-ES": "Copiar",
"ja-JP": "コピー",
"ko-KR": "복사",
"pl-PL": "Kopiuj",
"pt-BR": "Copiar",
"ru-RU": "Скопировать",
"tr-TR": "Kopyala",
"uk-UA": "Копіювати",
"vi-VN": "Sao chép",
},
"custom": {
@@ -650,8 +674,12 @@ const Translations = {
"deadzone-counterweight": {
"de-DE": "Deadzone Gegengewicht",
"en-US": "Deadzone counterweight",
"es-ES": "Contrapeso de la zona muerta",
"ja-JP": "デッドゾーンのカウンターウエイト",
"pt-BR": "Contador da Zona Morta",
"ru-RU": "Противовес мертвой зоны",
"tr-TR": "Ölü alan denge ağırlığı",
"uk-UA": "Противага Deadzone",
"vi-VN": "Đối trọng vùng chết",
},
"default": {
@@ -677,6 +705,8 @@ const Translations = {
"ja-JP": "削除",
"ko-KR": "삭제",
"pl-PL": "Usuń",
"pt-BR": "Deletar",
"ru-RU": "Удалить",
"tr-TR": "Sil",
"uk-UA": "Видалити",
"vi-VN": "Xóa",
@@ -797,6 +827,8 @@ const Translations = {
"ja-JP": "無効",
"ko-KR": "비활성화됨",
"pl-PL": "Wyłączony",
"pt-BR": "Desativado",
"ru-RU": "Отключено",
"tr-TR": "Kapalı",
"uk-UA": "Вимкнено",
"vi-VN": "Đã tắt",
@@ -809,6 +841,8 @@ const Translations = {
"ja-JP": "編集",
"ko-KR": "편집",
"pl-PL": "Edytuj",
"pt-BR": "Editar",
"ru-RU": "Редактировать",
"tr-TR": "Düzenle",
"uk-UA": "Редагувати",
"vi-VN": "Sửa",
@@ -914,6 +948,8 @@ const Translations = {
"ja-JP": "有効",
"ko-KR": "활성화됨",
"pl-PL": "Włączony",
"pt-BR": "Ativado",
"ru-RU": "Включено",
"tr-TR": "Açık",
"uk-UA": "Увімкнено",
"vi-VN": "Đã bật",
@@ -926,6 +962,8 @@ const Translations = {
"ja-JP": "エクスポート(書出し)",
"ko-KR": "내보내기",
"pl-PL": "Eksportuj",
"pt-BR": "Exportar",
"ru-RU": "Экспортировать",
"tr-TR": "Dışa aktar",
"uk-UA": "Експорт",
"vi-VN": "Xuất",
@@ -996,9 +1034,13 @@ const Translations = {
"horizontal-sensitivity": {
"de-DE": "Horizontale Empfindlichkeit",
"en-US": "Horizontal sensitivity",
"es-ES": "Sensibilidad horizontal",
"ja-JP": "左右方向の感度",
"pl-PL": "Czułość pozioma",
"pt-BR": "Sensibilidade horizontal",
"ru-RU": "Горизонтальная чувствительность",
"tr-TR": "Yatay hassasiyet",
"uk-UA": "Горизонтальна чутливість",
"vi-VN": "Độ nhạy ngang",
},
"import": {
@@ -1008,6 +1050,8 @@ const Translations = {
"ja-JP": "インポート(読込み)",
"ko-KR": "가져오기",
"pl-PL": "Importuj",
"pt-BR": "Importar",
"ru-RU": "Импортировать",
"tr-TR": "İçeri aktar",
"uk-UA": "Імпорт",
"vi-VN": "Nhập",
@@ -1063,10 +1107,14 @@ const Translations = {
"left-stick": {
"de-DE": "Linker Stick",
"en-US": "Left stick",
"es-ES": "Joystick izquierdo",
"ja-JP": "左スティック",
"ko-KR": "왼쪽 스틱",
"pl-PL": "Lewy drążek analogowy",
"pt-BR": "Direcional analógico esquerdo",
"ru-RU": "Левый стик",
"tr-TR": "Sol analog çubuk",
"uk-UA": "Лівий стік",
"vi-VN": "Analog trái",
},
"loading-screen": {
@@ -1088,9 +1136,13 @@ const Translations = {
"map-mouse-to": {
"de-DE": "Maus binden an",
"en-US": "Map mouse to",
"es-ES": "Mapear ratón a",
"ja-JP": "マウスの割り当て",
"pl-PL": "Przypisz myszkę do",
"pt-BR": "Mapear o mouse para",
"ru-RU": "Наведите мышку на",
"tr-TR": "Fareyi ata",
"uk-UA": "Прив'язати мишу до",
"vi-VN": "Gán chuột với",
},
"max-bitrate": {
@@ -1173,15 +1225,23 @@ const Translations = {
"mkb-adjust-ingame-settings": {
"de-DE": "Vielleicht müssen auch Empfindlichkeit & Deadzone in den Spieleinstellungen angepasst werden",
"en-US": "You may also need to adjust the in-game sensitivity & deadzone settings",
"es-ES": "También puede que necesites ajustar la sensibilidad del juego y la configuración de la zona muerta",
"ja-JP": "ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります",
"pt-BR": "Você também pode precisar ajustar as configurações de sensibilidade e zona morta no jogo",
"ru-RU": "Также может потребоваться изменить настройки чувствительности и мертвой зоны в игре",
"tr-TR": "Bu seçenek etkinken bile oyun içi seçeneklerden hassasiyet ve ölü bölge ayarlarını düzeltmeniz gerekebilir",
"uk-UA": "Можливо, вам також доведеться регулювати чутливість і deadzone у параметрах гри",
"vi-VN": "Có thể bạn cần phải điều chỉnh các thông số độ nhạy và điểm chết trong game",
},
"mkb-click-to-activate": {
"de-DE": "Klicken zum Aktivieren",
"en-US": "Click to activate",
"ja-JP": "クリックして有効化",
"es-ES": "Haz clic para activar",
"ja-JP": "マウスクリックで開始",
"pt-BR": "Clique para ativar",
"ru-RU": "Нажмите, чтобы активировать",
"tr-TR": "Etkinleştirmek için tıklayın",
"uk-UA": "Натисніть, щоб активувати",
"vi-VN": "Nhấn vào để kích hoạt",
},
"mouse-and-keyboard": {
@@ -1221,6 +1281,8 @@ const Translations = {
"ja-JP": "名前",
"ko-KR": "이름",
"pl-PL": "Nazwa",
"pt-BR": "Nome",
"ru-RU": "Имя",
"tr-TR": "İsim",
"uk-UA": "Назва",
"vi-VN": "Tên",
@@ -1229,10 +1291,14 @@ const Translations = {
"new": {
"de-DE": "Neu",
"en-US": "New",
"es-ES": "Nuevo",
"ja-JP": "新しい",
"ko-KR": "새로 만들기",
"pl-PL": "Nowy",
"pt-BR": "Novo",
"ru-RU": "Создать",
"tr-TR": "Yeni",
"uk-UA": "Новий",
"vi-VN": "Tạo mới",
},
"no-consoles-found": {
@@ -1351,6 +1417,8 @@ const Translations = {
"ja-JP": "プレイ中",
"ko-KR": "플레이 중",
"pl-PL": "W grze",
"pt-BR": "Jogando",
"ru-RU": "Играет",
"tr-TR": "Şu anda oyunda",
"uk-UA": "Гра триває",
"vi-VN": "Đang chơi",
@@ -1441,6 +1509,8 @@ const Translations = {
"ja-JP": "プリセット",
"ko-KR": "프리셋",
"pl-PL": "Szablon",
"pt-BR": "Predefinição",
"ru-RU": "Шаблон",
"tr-TR": "Hazır ayar",
"uk-UA": "Пресет",
"vi-VN": "Thiết lập sẵn",
@@ -1453,6 +1523,8 @@ const Translations = {
"ja-JP": "Escを押してキャンセル",
"ko-KR": "ESC를 눌러 취소",
"pl-PL": "Naciśnij Esc, aby anulować",
"pt-BR": "Pressione Esc para cancelar",
"ru-RU": "Нажмите Esc для отмены",
"tr-TR": "İptal etmek için Esc'ye basın",
"uk-UA": "Натисніть Esc, щоб скасувати",
"vi-VN": "Nhấn Esc để bỏ qua",
@@ -1465,6 +1537,8 @@ const Translations = {
"ja-JP": e => `${e.key} キーでマウスとキーボードの機能を切り替える`,
"ko-KR": e => `${e.key} 키를 눌러 마우스와 키보드 기능을 활성화 하십시오`,
"pl-PL": e => `Naciśnij ${e.key}, aby przełączyć funkcję myszy i klawiatury`,
"pt-BR": e => `Pressione ${e.key} para ativar/desativar a função de Mouse e Teclado`,
"ru-RU": e => `Нажмите ${e.key} для переключения функции мыши и клавиатуры`,
"tr-TR": e => `Klavye ve fare özelliğini açmak için ${e.key} tuşuna basın`,
"uk-UA": e => `Натисніть ${e.key}, щоб увімкнути або вимкнути функцію миші та клавіатури`,
"vi-VN": e => `Nhấn ${e.key} để bật/tắt tính năng Chuột và Bàn phím`,
@@ -1477,6 +1551,8 @@ const Translations = {
"ja-JP": "キーを押すかマウスをクリックして割り当て...",
"ko-KR": "정지하려면 아무키나 마우스를 클릭해주세요...",
"pl-PL": "Naciśnij klawisz lub kliknij myszą, aby przypisać...",
"pt-BR": "Pressione uma tecla ou clique do mouse para vincular...",
"ru-RU": "Нажмите клавишу или щелкните мышкой, чтобы связать...",
"tr-TR": "Klavyedeki bir tuşa basarak veya fareyle tıklayarak tuş ataması yapın...",
"uk-UA": "Натисніть клавішу або кнопку миші, щоб прив'язати...",
"vi-VN": "Nhấn nút hoặc nhấn chuột để gán...",
@@ -1485,10 +1561,14 @@ const Translations = {
"prompt-preset-name": {
"de-DE": "Voreinstellung Name:",
"en-US": "Preset's name:",
"es-ES": "Nombre del preajuste:",
"ja-JP": "プリセット名:",
"ko-KR": "프리셋 이름:",
"pl-PL": "Nazwa szablonu:",
"pt-BR": "Nome da predefinição:",
"ru-RU": "Имя шаблона:",
"tr-TR": "Hazır ayar adı:",
"uk-UA": "Назва пресету:",
"vi-VN": "Tên của mẫu sẵn:",
},
"ratio": {
@@ -1557,27 +1637,39 @@ const Translations = {
"rename": {
"de-DE": "Umbenennen",
"en-US": "Rename",
"es-ES": "Renombrar",
"ja-JP": "名前変更",
"ko-KR": "이름 바꾸기",
"pl-PL": "Zmień nazwę",
"pt-BR": "Renomear",
"ru-RU": "Переименовать",
"tr-TR": "Ad değiştir",
"uk-UA": "Перейменувати",
"vi-VN": "Sửa tên",
},
"right-click-to-unbind": {
"de-DE": "Rechtsklick auf Taste: Zuordnung aufheben",
"en-US": "Right-click on a key to unbind it",
"es-ES": "Clic derecho en una tecla para desvincularla",
"ja-JP": "右クリックで割り当て解除",
"ko-KR": "할당 해제하려면 키를 오른쪽 클릭하세요",
"pt-BR": "Clique com o botão direito em uma tecla para desvinculá-la",
"ru-RU": "Щелкните правой кнопкой мыши по кнопке, чтобы отвязать её",
"tr-TR": "Tuş atamasını kaldırmak için fareyle sağ tık yapın",
"uk-UA": "Натисніть правою кнопкою миші, щоб відв'язати",
"vi-VN": "Nhấn chuột phải lên một phím để gỡ nó",
},
"right-stick": {
"de-DE": "Rechter Stick",
"en-US": "Right stick",
"es-ES": "Joystick derecho",
"ja-JP": "右スティック",
"ko-KR": "오른쪽 스틱",
"pl-PL": "Prawy drążek analogowy",
"pt-BR": "Direcional analógico direito",
"ru-RU": "Правый стик",
"tr-TR": "Sağ analog çubuk",
"uk-UA": "Правий стік",
"vi-VN": "Analog phải",
},
"rocket-always-hide": {
@@ -1683,6 +1775,8 @@ const Translations = {
"ja-JP": "保存",
"ko-KR": "저장",
"pl-PL": "Zapisz",
"pt-BR": "Salvar",
"ru-RU": "Сохранить",
"tr-TR": "Kaydet",
"uk-UA": "Зберегти",
"vi-VN": "Lưu",
@@ -2024,6 +2118,7 @@ const Translations = {
"de-DE": "Stick Abklingzeit Minimum",
"en-US": "Stick decay minimum",
"ja-JP": "スティックの減衰の最小値",
"pt-BR": "Mínimo decaimento do analógico",
"tr-TR": "Çubuğun ortalanma süresi minimumu",
"vi-VN": "Độ suy giảm tối thiểu của cần điều khiển",
},
@@ -2031,6 +2126,7 @@ const Translations = {
"de-DE": "Stick Abklingzeit Geschwindigkeit",
"en-US": "Stick decay strength",
"ja-JP": "スティックの減衰の強さ",
"pt-BR": "Força de decaimento do analógico",
"tr-TR": "Çubuğun ortalanma gücü",
"vi-VN": "Sức mạnh độ suy giảm của cần điều khiển",
},
@@ -2069,8 +2165,12 @@ const Translations = {
"support-better-xcloud": {
"de-DE": "\"Better xCloud\" unterstützen",
"en-US": "Support Better xCloud",
"es-ES": "Apoyar a Better xCloud",
"ja-JP": "Better xCloudをサポート",
"pt-BR": "Suporte ao Melhor xCloud",
"ru-RU": "Поддержать Better xCloud",
"tr-TR": "Better xCloud'a destek ver",
"uk-UA": "Підтримати Better xCloud",
"vi-VN": "Hỗ trợ Better xCloud",
},
"swap-buttons": {
@@ -2389,9 +2489,13 @@ const Translations = {
"vertical-sensitivity": {
"de-DE": "Vertikale Empfindlichkeit",
"en-US": "Vertical sensitivity",
"es-ES": "Sensibilidad Vertical",
"ja-JP": "上下方向の感度",
"pl-PL": "Czułość pionowa",
"pt-BR": "Sensibilidade vertical",
"ru-RU": "Вертикальная чувствительность",
"tr-TR": "Dikey hassasiyet",
"uk-UA": "Вертикальна чутливість",
"vi-VN": "Độ ngạy dọc",
},
"vibration-intensity": {
@@ -5938,11 +6042,7 @@ class Preferences {
'default': __('default'),
};
if (typeof RTCRtpTransceiver === 'undefined' || !('setCodecPreferences' in RTCRtpTransceiver.prototype)) {
return options;
}
if (!('getCapabilities' in RTCRtpReceiver)) {
if (!('getCapabilities' in RTCRtpReceiver) || typeof RTCRtpTransceiver === 'undefined' || !('setCodecPreferences' in RTCRtpTransceiver.prototype)) {
return options;
}
@@ -5990,6 +6090,12 @@ class Preferences {
return options;
})(),
'ready': () => {
const options = Preferences.SETTINGS[Preferences.STREAM_CODEC_PROFILE].options;
if (Object.keys(options).length <= 1) {
Preferences.SETTINGS[Preferences.STREAM_CODEC_PROFILE].unsupported = __('browser-unsupported-feature');
}
},
},
[Preferences.PREFER_IPV6_SERVER]: {
'default': false,
@@ -6015,6 +6121,7 @@ class Preferences {
'all': __('tc-all-games'),
'off': __('off'),
},
'unsupported': !HAS_TOUCH_SUPPORT ? __('device-unsupported-touch') : false,
},
[Preferences.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: {
'default': 'default',
@@ -6023,6 +6130,7 @@ class Preferences {
'white': __('tc-all-white'),
'muted': __('tc-muted-colors'),
},
'unsupported': !HAS_TOUCH_SUPPORT ? __('device-unsupported-touch') : false,
},
[Preferences.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM]: {
'default': 'default',
@@ -6030,6 +6138,7 @@ class Preferences {
'default': __('default'),
'muted': __('tc-muted-colors'),
},
'unsupported': !HAS_TOUCH_SUPPORT ? __('device-unsupported-touch') : false,
},
[Preferences.STREAM_SIMPLIFY_MENU]: {
'default': false,
@@ -6072,6 +6181,10 @@ class Preferences {
[Preferences.MKB_ENABLED]: {
'default': false,
'unsupported': (() => {
const userAgent = (window.navigator.orgUserAgent || window.navigator.userAgent || '').toLowerCase();
return userAgent.match(/(android|iphone|ipad)/) ? __('browser-unsupported-feature') : false;
})(),
},
[Preferences.MKB_DEFAULT_PRESET_ID]: {
@@ -6290,6 +6403,7 @@ class Preferences {
}
const setting = Preferences.SETTINGS[settingId];
setting && setting.migrate && setting.migrate.call(this, savedPrefs, savedPrefs[settingId]);
setting && setting.ready && setting.ready.call(this);
}
for (let settingId in Preferences.SETTINGS) {
@@ -6355,9 +6469,9 @@ class Preferences {
return;
}
// Return "default" for STREAM_TOUCH_CONTROLLER pref when the browser doesn't support touch
if (!HAS_TOUCH_SUPPORT && key === Preferences.STREAM_TOUCH_CONTROLLER) {
return 'default';
// Return default value if the feature is not supported
if (Preferences.SETTINGS[key].unsupported) {
return Preferences.SETTINGS[key].default;
}
let value = this.#prefs[key];
@@ -6570,7 +6684,7 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
const endIndex = funcStr.indexOf('},', index);
const newSettings = [
'EnableStreamGate: false',
// 'EnableStreamGate: false',
'PwaPrompt: false',
];
@@ -6607,15 +6721,6 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
return funcStr.replace(text, 'get mouseAndKeyboardEnabled() {return this._titleSupportsMouseAndKeyboard;');
},
patchStreamHudSize: function(funcStr) {
if (!funcStr.includes('="StreamHUD-module__button')) {
return false;
}
funcStr = funcStr.replace('=3;', '=5;');
return funcStr;
},
disableGamepadDisconnectedScreen: function(funcStr) {
const index = funcStr.indexOf('"GamepadDisconnected_Title",');
if (index === -1) {
@@ -6651,9 +6756,24 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
return funcStr;
},
// Disable StreamGate
disableStreamGate: function(funcStr) {
const index = funcStr.indexOf('case"partially-ready":');
if (index === -1) {
return false;
}
const bracketIndex = funcStr.indexOf('=>{', index - 150) + 3;
funcStr = funcStr.substring(0, bracketIndex) + 'return 0;' + funcStr.substring(bracketIndex);
return funcStr;
},
};
static #PATCH_ORDERS = [
['disableStreamGate'],
[
'disableAiTrack',
'disableTelemetry',
@@ -6683,12 +6803,11 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
[
'disableGamepadDisconnectedScreen',
'mkbMouseAndKeyboardEnabled',
'patchStreamHudSize',
],
];
static #patchFunctionBind() {
Function.prototype.nativeBind = Function.prototype.bind;
const nativeBind = Function.prototype.bind;
Function.prototype.bind = function() {
let valid = false;
if (arguments.length === 2 && arguments[0] === null) {
@@ -6698,12 +6817,12 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
}
if (!valid) {
return this.nativeBind.apply(this, arguments);
return nativeBind.apply(this, arguments);
}
if (typeof arguments[1] === 'function') {
console.log('[Better xCloud] Restored Function.prototype.bind()');
Function.prototype.bind = Function.prototype.nativeBind;
Function.prototype.bind = nativeBind;
}
const orgFunc = this;
@@ -6717,7 +6836,7 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
orgFunc(a, item);
}
return newFunc.nativeBind.apply(newFunc, arguments);
return nativeBind.apply(newFunc, arguments);
};
}
@@ -6933,6 +7052,15 @@ function addCss() {
src: url('https://redphx.github.io/better-xcloud/fonts/promptfont.otf');
}
/* Fix Stream menu buttons not hiding */
div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module__hiddenContainer]) {
opacity: 0;
pointer-events: none !important;
position: absolute;
top: -9999px;
left: -9999px;
}
.bx-button {
background-color: var(--bx-default-button-color);
user-select: none;
@@ -8164,7 +8292,7 @@ function getPreferredServerRegion() {
function updateIceCandidates(candidates, options) {
const pattern = new RegExp(/a=candidate:(?<foundation>\d+) (?<component>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<the_rest>.*)/);
const pattern = new RegExp(/a=candidate:(?<foundation>\d+) (?<component>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<port>\d+) (?<the_rest>.*)/);
const lst = [];
for (let item of candidates) {
@@ -8182,52 +8310,71 @@ function updateIceCandidates(candidates, options) {
const newCandidates = [];
let foundation = 1;
const newCandidate = candidate => {
return {
'candidate': candidate,
'messageType': 'iceCandidate',
'sdpMLineIndex': '0',
'sdpMid': '0',
};
};
lst.forEach(item => {
item.foundation = foundation;
item.priority = (foundation == 1) ? 10000 : 1;
newCandidates.push({
'candidate': `a=candidate:${item.foundation} 1 UDP ${item.priority} ${item.ip} ${item.the_rest}`,
'messageType': 'iceCandidate',
'sdpMLineIndex': '0',
'sdpMid': '0',
});
newCandidates.push(newCandidate(`a=candidate:${item.foundation} 1 UDP ${item.priority} ${item.ip} ${item.port} ${item.the_rest}`));
++foundation;
});
if (options.consoleIp) {
newCandidates.push({
'candidate': `a=candidate:${newCandidates.length + 1} 1 UDP 1 ${options.consoleIp} 9002 typ host`,
'messageType': 'iceCandidate',
'sdpMLineIndex': '0',
'sdpMid': '0',
});
if (options.consoleAddrs) {
for (const ip in options.consoleAddrs) {
const port = options.consoleAddrs[ip];
newCandidates.push(newCandidate(`a=candidate:${newCandidates.length + 1} 1 UDP 1 ${ip} ${port} typ host`));
}
}
newCandidates.push({
'candidate': 'a=end-of-candidates',
'messageType': 'iceCandidate',
'sdpMLineIndex': '0',
'sdpMid': '0',
});
newCandidates.push(newCandidate('a=end-of-candidates'));
console.log(newCandidates);
return newCandidates;
}
function clearDbLogs(dbName, table) {
const request = window.indexedDB.open(dbName);
request.onsuccess = e => {
const db = e.target.result;
const objectStore = db.transaction(table, 'readwrite').objectStore(table);
const objectStoreRequest = objectStore.clear();
objectStoreRequest.onsuccess = function(event) {
console.log(`[Better xCloud] Cleared ${dbName}.${table}`);
};
}
}
function clearApplicationInsightsBuffers() {
window.sessionStorage.removeItem('AI_buffer');
window.sessionStorage.removeItem('AI_sentBuffer');
}
function clearAllLogs() {
clearApplicationInsightsBuffers();
clearDbLogs('StreamClientLogHandler', 'logs');
clearDbLogs('XCloudAppLogs', 'logs');
}
function interceptHttpRequests() {
var BLOCKED_URLS = [];
if (PREFS.get(Preferences.BLOCK_TRACKING)) {
// Clear Applications Insight buffers
clearApplicationInsightsBuffers();
clearAllLogs();
BLOCKED_URLS = BLOCKED_URLS.concat([
'https://arc.msn.com',
@@ -8259,7 +8406,7 @@ function interceptHttpRequests() {
for (let blocked of BLOCKED_URLS) {
if (this._url.startsWith(blocked)) {
if (blocked === 'https://dc.services.visualstudio.com') {
setTimeout(clearApplicationInsightsBuffers, 1000);
setTimeout(clearAllLogs, 1000);
}
return false;
}
@@ -8278,8 +8425,8 @@ function interceptHttpRequests() {
const PREF_AUDIO_MIC_ON_PLAYING = PREFS.get(Preferences.AUDIO_MIC_ON_PLAYING);
const orgFetch = window.fetch;
let consoleIp;
let consolePort;
const consoleAddrs = {};
const patchIceCandidates = function(...arg) {
// ICE server candidates
@@ -8297,7 +8444,7 @@ function interceptHttpRequests() {
const options = {
preferIpv6Server: PREF_PREFER_IPV6_SERVER,
consoleIp: consoleIp,
consoleAddrs: consoleAddrs,
};
const obj = JSON.parse(text);
@@ -8367,8 +8514,15 @@ function interceptHttpRequests() {
return promise.then(response => {
return response.clone().json().then(obj => {
console.log(obj);
consoleIp = obj.serverDetails.ipAddress;
consolePort = obj.serverDetails.port;
const serverDetails = obj.serverDetails;
if (serverDetails.ipV4Address) {
consoleAddrs[serverDetails.ipV4Address] = serverDetails.ipV4Port;
}
if (serverDetails.ipV6Address) {
consoleAddrs[serverDetails.ipV6Address] = serverDetails.ipV6Port;
}
response.json = () => Promise.resolve(obj);
response.text = () => Promise.resolve(JSON.stringify(obj));
@@ -8844,19 +8998,11 @@ function injectSettingsButton($parent) {
}
// Disable unsupported settings
if (settingId === Preferences.STREAM_CODEC_PROFILE) {
const options = Preferences.SETTINGS[Preferences.STREAM_CODEC_PROFILE].options;
if (Object.keys(options).length <= 1) {
$control.disabled = true;
$control.title = __('browser-unsupported-feature');
}
} else if (!HAS_TOUCH_SUPPORT) {
// Disable this setting for non-touchable devices
if ([Preferences.STREAM_TOUCH_CONTROLLER, Preferences.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD, Preferences.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM].indexOf(settingId) > -1) {
$control.disabled = true;
$control.title = __('device-unsupported-touch');
}
if (setting.unsupported) {
$control.disabled = true;
$control.title = setting.unsupported;
}
$control.disabled && ($control.style.cursor = 'help');
const $label = CE('label', labelAttrs, settingLabel);
@@ -9027,6 +9173,33 @@ function watchHeader() {
function cloneStreamHudButton($orgButton, label, svg_icon) {
const $container = $orgButton.cloneNode(true);
let timeout;
const onTransitionStart = e => {
if ( e.propertyName !== 'opacity') {
return;
}
timeout && clearTimeout(timeout);
$container.style.pointerEvents = 'none';
};
const onTransitionEnd = e => {
if ( e.propertyName !== 'opacity') {
return;
}
const left = document.getElementById('StreamHud').style.left;
if (left === '0px') {
timeout && clearTimeout(timeout);
timeout = setTimeout(() => {
$container.style.pointerEvents = 'auto';
}, 100);
}
};
$container.addEventListener('transitionstart', onTransitionStart);
$container.addEventListener('transitionend', onTransitionEnd);
const $button = $container.querySelector('button');
$button.setAttribute('title', label);
@@ -9082,7 +9255,7 @@ function injectStreamMenuButtons() {
$quickBar.classList.add('bx-gone');
$parent.removeEventListener('click', hideQuickBarFunc);
$parent.removeEventListener('touchstart', hideQuickBarFunc);
// $parent.removeEventListener('touchstart', hideQuickBarFunc);
}
let $btnStreamSettings;
@@ -9165,12 +9338,19 @@ function injectStreamMenuButtons() {
return;
}
const hideGripHandle = () => {
$gripHandle.dispatchEvent(new PointerEvent('pointerdown'));
$gripHandle.click();
$gripHandle.dispatchEvent(new PointerEvent('pointerdown'));
$gripHandle.click();
}
// Create Stream Settings button
if (!$btnStreamSettings) {
$btnStreamSettings = cloneStreamHudButton($orgButton, __('menu-stream-settings'), Icon.STREAM_SETTINGS);
$btnStreamSettings.addEventListener('click', e => {
hideGripHandle();
e.preventDefault();
e.stopPropagation();
const msVideoProcessing = $STREAM_VIDEO.msVideoProcessing;
$quickBar.setAttribute('data-clarity-boost', (msVideoProcessing && msVideoProcessing !== 'default'));
@@ -9179,12 +9359,10 @@ function injectStreamMenuButtons() {
$quickBar.classList.remove('bx-gone');
$parent.addEventListener('click', hideQuickBarFunc);
$parent.addEventListener('touchstart', hideQuickBarFunc);
//$parent.addEventListener('touchstart', hideQuickBarFunc);
const $touchSurface = document.getElementById('MultiTouchSurface');
$touchSurface && $touchSurface.style.display != 'none' && $touchSurface.addEventListener('touchstart', hideQuickBarFunc);
$gripHandle.click();
});
}
@@ -9192,16 +9370,14 @@ function injectStreamMenuButtons() {
if (!$btnStreamStats) {
$btnStreamStats = cloneStreamHudButton($orgButton, __('menu-stream-stats'), Icon.STREAM_STATS);
$btnStreamStats.addEventListener('click', e => {
hideGripHandle();
e.preventDefault();
e.stopPropagation();
// Toggle Stream Stats
StreamStats.toggle();
const btnStreamStatsOn = (!StreamStats.isHidden() && !StreamStats.isGlancing());
$btnStreamStats.classList.toggle('bx-stream-menu-button-on', btnStreamStatsOn);
$gripHandle.click();
});
}