mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-07 23:01:44 +02:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
35a783c53e | |||
afe3809061 | |||
5eeb15f201 | |||
71b4109385 | |||
8286429cc3 | |||
ae24005f08 | |||
2626408cbe | |||
804f751646 | |||
13a20f30e5 | |||
46265f2ccd | |||
93d77c3783 | |||
eeb7ab749a | |||
2af3dc315b | |||
bd7b7d5ef5 | |||
93b540d995 | |||
9f26021ec6 | |||
bd8aedaf30 | |||
414bc2268e | |||
6b12b4add4 | |||
cdc64da95f | |||
1a2fb6c89a | |||
351cb0204b | |||
f6a7a78be7 | |||
66695b2fc2 | |||
6f8f425003 | |||
1966c7c127 | |||
67788bd365 | |||
bf9942ca4f | |||
8d22533d7f |
@ -1,5 +1,5 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 3.4.0
|
// @version 3.5.1
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 3.4.0
|
// @version 3.5.1
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
/* ADDITIONAL CODE */
|
/* ADDITIONAL CODE */
|
||||||
|
|
||||||
const SCRIPT_VERSION = '3.4.0';
|
const SCRIPT_VERSION = '3.5.1';
|
||||||
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||||
|
|
||||||
// Setup flags
|
// Setup flags
|
||||||
const DEFAULT_FLAGS = {
|
const DEFAULT_FLAGS = {
|
||||||
|
CheckForUpdate: true,
|
||||||
PreloadRemotePlay: true,
|
PreloadRemotePlay: true,
|
||||||
PreloadUi: false,
|
PreloadUi: false,
|
||||||
EnableXcloudLogging: false,
|
EnableXcloudLogging: false,
|
||||||
@ -667,6 +668,40 @@ const Translations = {
|
|||||||
"Đóng",
|
"Đóng",
|
||||||
"关闭",
|
"关闭",
|
||||||
],
|
],
|
||||||
|
"combine-audio-video-streams": [
|
||||||
|
,
|
||||||
|
"Gabung audio & video stream",
|
||||||
|
"Combine audio & video streams",
|
||||||
|
,
|
||||||
|
,
|
||||||
|
,
|
||||||
|
"音声を映像ストリーミングと統合",
|
||||||
|
,
|
||||||
|
"Połącz strumienie audio i wideo",
|
||||||
|
"Combinar fluxos de áudio e vídeo",
|
||||||
|
"Объединить аудио и видео потоки",
|
||||||
|
"Ses ve görüntü akışını birleştir",
|
||||||
|
"Поєднайте аудіо та відео потоки",
|
||||||
|
"Hòa hợp nguồn của âm thanh và hình ảnh",
|
||||||
|
"合并视频音频流",
|
||||||
|
],
|
||||||
|
"combine-audio-video-streams-summary": [
|
||||||
|
,
|
||||||
|
"Mungkin memperbaiki masalah lag pada audio",
|
||||||
|
"May fix the laggy audio problem",
|
||||||
|
,
|
||||||
|
,
|
||||||
|
,
|
||||||
|
"音声の遅延を改善できる可能性があります",
|
||||||
|
,
|
||||||
|
"Może rozwiązać problem z zacinającym dźwiękiem",
|
||||||
|
"Pode corrigir o problema de áudio Laggy",
|
||||||
|
"Может исправить проблему подвисания звука",
|
||||||
|
"Sesteki gecikme sorununa çözüm olabilir",
|
||||||
|
"Може виправити проблему із затримкою звуку",
|
||||||
|
"Có thể sửa được lỗi trễ tiếng",
|
||||||
|
"有助于缓解音频延迟",
|
||||||
|
],
|
||||||
"conditional-formatting": [
|
"conditional-formatting": [
|
||||||
"Zustandsabhängige Textfarbe",
|
"Zustandsabhängige Textfarbe",
|
||||||
"Format teks kondisional",
|
"Format teks kondisional",
|
||||||
@ -1228,6 +1263,23 @@ const Translations = {
|
|||||||
"Đã bật",
|
"Đã bật",
|
||||||
"启用",
|
"启用",
|
||||||
],
|
],
|
||||||
|
"experimental": [
|
||||||
|
,
|
||||||
|
"Eksperimental",
|
||||||
|
"Experimental",
|
||||||
|
,
|
||||||
|
,
|
||||||
|
,
|
||||||
|
"実験的機能",
|
||||||
|
,
|
||||||
|
"Eksperymentalne",
|
||||||
|
"Experimental",
|
||||||
|
"Экспериментально",
|
||||||
|
"Deneme aşamasında",
|
||||||
|
"Експериментальне",
|
||||||
|
"Thử nghiệm",
|
||||||
|
"实验性功能",
|
||||||
|
],
|
||||||
"export": [
|
"export": [
|
||||||
"Exportieren",
|
"Exportieren",
|
||||||
"Ekspor",
|
"Ekspor",
|
||||||
@ -1348,21 +1400,21 @@ const Translations = {
|
|||||||
"空闲时隐藏鼠标",
|
"空闲时隐藏鼠标",
|
||||||
],
|
],
|
||||||
"hide-scrollbar": [
|
"hide-scrollbar": [
|
||||||
,
|
"Scrollbalken der Webseite ausblenden",
|
||||||
,
|
"Sembunyikan bilah gulir halaman",
|
||||||
"Hide web page's scrollbar",
|
"Hide web page's scrollbar",
|
||||||
,
|
,
|
||||||
,
|
,
|
||||||
,
|
,
|
||||||
|
"Webページのスクロールバーを隠す",
|
||||||
,
|
,
|
||||||
,
|
"Ukryj pasek przewijania strony",
|
||||||
,
|
"Oculta a barra de rolagem da página",
|
||||||
,
|
"Скрыть полосу прокрутки страницы",
|
||||||
,
|
"Yandaki kaydırma çubuğunu gizle",
|
||||||
,
|
"Приховати смугу прокрутки вебсторінок",
|
||||||
,
|
|
||||||
"Ẩn thanh cuộn của trang web",
|
"Ẩn thanh cuộn của trang web",
|
||||||
,
|
"隐藏浏览器滚动条",
|
||||||
],
|
],
|
||||||
"hide-system-menu-icon": [
|
"hide-system-menu-icon": [
|
||||||
"Symbol des System-Menüs ausblenden",
|
"Symbol des System-Menüs ausblenden",
|
||||||
@ -2308,13 +2360,13 @@ const Translations = {
|
|||||||
,
|
,
|
||||||
"スクリーンショットにビデオフィルターを適用",
|
"スクリーンショットにビデオフィルターを適用",
|
||||||
,
|
,
|
||||||
,
|
"Stosuje filtry wideo do zrzutów ekranu",
|
||||||
"Aplicar filtros às capturas de tela",
|
"Aplicar filtros às capturas de tela",
|
||||||
"Применяет фильтры видео к скриншотам",
|
"Применяет фильтры видео к скриншотам",
|
||||||
"Görsel filtreleri ekran görüntülerine de uygular",
|
"Görsel filtreleri ekran görüntülerine de uygular",
|
||||||
"Застосовує відеофільтри до знімків екрана",
|
"Застосовує відеофільтри до знімків екрана",
|
||||||
"Áp dụng hiệu ứng video vào ảnh chụp màn hình",
|
"Á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",
|
||||||
@ -3219,15 +3271,15 @@ const Translations = {
|
|||||||
],
|
],
|
||||||
"vibration-status": [
|
"vibration-status": [
|
||||||
"Vibration",
|
"Vibration",
|
||||||
,
|
"Getaran",
|
||||||
"Vibration",
|
"Vibration",
|
||||||
,
|
,
|
||||||
,
|
,
|
||||||
,
|
,
|
||||||
"振動",
|
"振動",
|
||||||
,
|
,
|
||||||
,
|
"Wibracje",
|
||||||
,
|
"Vibração",
|
||||||
"Вибрация",
|
"Вибрация",
|
||||||
"Titreşim",
|
"Titreşim",
|
||||||
"Вібрація",
|
"Вібрація",
|
||||||
@ -3548,7 +3600,8 @@ class Dialog {
|
|||||||
class RemotePlay {
|
class RemotePlay {
|
||||||
static XCLOUD_TOKEN;
|
static XCLOUD_TOKEN;
|
||||||
static XHOME_TOKEN;
|
static XHOME_TOKEN;
|
||||||
static #CONSOLES;
|
static #CONSOLES = null;
|
||||||
|
static #REGIONS;
|
||||||
|
|
||||||
static #STATE_LABELS = {
|
static #STATE_LABELS = {
|
||||||
'On': t('powered-on'),
|
'On': t('powered-on'),
|
||||||
@ -3611,9 +3664,6 @@ class RemotePlay {
|
|||||||
RemotePlay.#getConsolesList(() => {
|
RemotePlay.#getConsolesList(() => {
|
||||||
console.log(RemotePlay.#CONSOLES);
|
console.log(RemotePlay.#CONSOLES);
|
||||||
RemotePlay.#renderConsoles();
|
RemotePlay.#renderConsoles();
|
||||||
|
|
||||||
const $btn = document.querySelector('.bx-remote-play-button');
|
|
||||||
$btn && ($btn.disabled = false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3726,6 +3776,7 @@ class RemotePlay {
|
|||||||
},
|
},
|
||||||
}).then(resp => resp.json())
|
}).then(resp => resp.json())
|
||||||
.then(json => {
|
.then(json => {
|
||||||
|
RemotePlay.#REGIONS = json.offeringSettings.regions;
|
||||||
RemotePlay.XHOME_TOKEN = json.gsToken;
|
RemotePlay.XHOME_TOKEN = json.gsToken;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
@ -3737,13 +3788,6 @@ class RemotePlay {
|
|||||||
return;
|
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 = {
|
const options = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
@ -3752,16 +3796,16 @@ class RemotePlay {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Test servers one by one
|
// Test servers one by one
|
||||||
for (const server of servers) {
|
for (const region of RemotePlay.#REGIONS) {
|
||||||
try {
|
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 resp = await fetch(url, options);
|
||||||
|
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
RemotePlay.#CONSOLES = json.results;
|
RemotePlay.#CONSOLES = json.results;
|
||||||
|
|
||||||
// Store working server
|
// Store working server
|
||||||
REMOTE_PLAY_SERVER = server;
|
REMOTE_PLAY_SERVER = region.baseUri;
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@ -3815,6 +3859,7 @@ class RemotePlay {
|
|||||||
|
|
||||||
static togglePopup(force = null) {
|
static togglePopup(force = null) {
|
||||||
if (!getPref(Preferences.REMOTE_PLAY_ENABLED) || !RemotePlay.isReady()) {
|
if (!getPref(Preferences.REMOTE_PLAY_ENABLED) || !RemotePlay.isReady()) {
|
||||||
|
Toast.show(t('getting-consoles-list'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7048,7 +7093,7 @@ class UserAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!newUserAgent) {
|
if (!newUserAgent) {
|
||||||
newUserAgent = UserAgent.get(profile) || defaultUserAgent;
|
newUserAgent = UserAgent.get(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -7116,6 +7161,8 @@ class Preferences {
|
|||||||
static get USER_AGENT_CUSTOM() { return 'user_agent_custom'; }
|
static get USER_AGENT_CUSTOM() { return 'user_agent_custom'; }
|
||||||
static get STREAM_SIMPLIFY_MENU() { return 'stream_simplify_menu'; }
|
static get STREAM_SIMPLIFY_MENU() { return 'stream_simplify_menu'; }
|
||||||
|
|
||||||
|
static get STREAM_COMBINE_SOURCES() { return 'stream_combine_sources'; }
|
||||||
|
|
||||||
static get STREAM_TOUCH_CONTROLLER() { return 'stream_touch_controller'; }
|
static get STREAM_TOUCH_CONTROLLER() { return 'stream_touch_controller'; }
|
||||||
static get STREAM_TOUCH_CONTROLLER_AUTO_OFF() { return 'stream_touch_controller_auto_off'; }
|
static get STREAM_TOUCH_CONTROLLER_AUTO_OFF() { return 'stream_touch_controller_auto_off'; }
|
||||||
static get STREAM_TOUCH_CONTROLLER_STYLE_STANDARD() { return 'stream_touch_controller_style_standard'; }
|
static get STREAM_TOUCH_CONTROLLER_STYLE_STANDARD() { return 'stream_touch_controller_style_standard'; }
|
||||||
@ -7347,6 +7394,12 @@ class Preferences {
|
|||||||
'default': false,
|
'default': false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[Preferences.STREAM_COMBINE_SOURCES]: {
|
||||||
|
'default': false,
|
||||||
|
'experimental': true,
|
||||||
|
'note': t('combine-audio-video-streams-summary'),
|
||||||
|
},
|
||||||
|
|
||||||
[Preferences.STREAM_TOUCH_CONTROLLER]: {
|
[Preferences.STREAM_TOUCH_CONTROLLER]: {
|
||||||
'default': 'all',
|
'default': 'all',
|
||||||
'options': {
|
'options': {
|
||||||
@ -7579,6 +7632,7 @@ class Preferences {
|
|||||||
},
|
},
|
||||||
[Preferences.AUDIO_ENABLE_VOLUME_CONTROL]: {
|
[Preferences.AUDIO_ENABLE_VOLUME_CONTROL]: {
|
||||||
'default': false,
|
'default': false,
|
||||||
|
'experimental': true,
|
||||||
},
|
},
|
||||||
[Preferences.AUDIO_VOLUME]: {
|
[Preferences.AUDIO_VOLUME]: {
|
||||||
'type': SettingElement.TYPE_NUMBER_STEPPER,
|
'type': SettingElement.TYPE_NUMBER_STEPPER,
|
||||||
@ -7908,6 +7962,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)||''`);
|
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
|
// Disable trackEvent() function
|
||||||
disableTrackEvent: function(funcStr) {
|
disableTrackEvent: function(funcStr) {
|
||||||
const text = 'this.trackEvent=';
|
const text = 'this.trackEvent=';
|
||||||
@ -8170,6 +8234,32 @@ if (gamepadFound) {
|
|||||||
funcStr = funcStr.replace(text, newCode + text);
|
funcStr = funcStr.replace(text, newCode + text);
|
||||||
return funcStr;
|
return funcStr;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
streamCombineSources: function(funcStr) {
|
||||||
|
const text = 'this.useCombinedAudioVideoStream=!!this.deviceInformation.isTizen';
|
||||||
|
if (!funcStr.includes(text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = [
|
static #PATCH_ORDERS = [
|
||||||
@ -8210,6 +8300,9 @@ if (gamepadFound) {
|
|||||||
// Only when playing
|
// Only when playing
|
||||||
static #PLAYING_PATCH_ORDERS = [
|
static #PLAYING_PATCH_ORDERS = [
|
||||||
getPref(Preferences.REMOTE_PLAY_ENABLED) && ['remotePlayConnectMode'],
|
getPref(Preferences.REMOTE_PLAY_ENABLED) && ['remotePlayConnectMode'],
|
||||||
|
getPref(Preferences.REMOTE_PLAY_ENABLED) && ['remotePlayGuideWorkaround'],
|
||||||
|
|
||||||
|
['patchStreamHud'],
|
||||||
|
|
||||||
['playVibration'],
|
['playVibration'],
|
||||||
HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'all' && ['exposeTouchLayoutManager'],
|
HAS_TOUCH_SUPPORT && getPref(Preferences.STREAM_TOUCH_CONTROLLER) === 'all' && ['exposeTouchLayoutManager'],
|
||||||
@ -8223,6 +8316,8 @@ if (gamepadFound) {
|
|||||||
'disableGamepadDisconnectedScreen',
|
'disableGamepadDisconnectedScreen',
|
||||||
ENABLE_NATIVE_MKB_BETA && 'mkbMouseAndKeyboardEnabled',
|
ENABLE_NATIVE_MKB_BETA && 'mkbMouseAndKeyboardEnabled',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
getPref(Preferences.STREAM_COMBINE_SOURCES) && ['streamCombineSources'],
|
||||||
];
|
];
|
||||||
|
|
||||||
static #patchFunctionBind() {
|
static #patchFunctionBind() {
|
||||||
@ -8358,7 +8453,7 @@ if (gamepadFound) {
|
|||||||
|
|
||||||
|
|
||||||
function checkForUpdate() {
|
function checkForUpdate() {
|
||||||
const CHECK_INTERVAL_SECONDS = 4 * 3600; // check every 4 hours
|
const CHECK_INTERVAL_SECONDS = 2 * 3600; // check every 2 hours
|
||||||
|
|
||||||
const currentVersion = getPref(Preferences.CURRENT_VERSION);
|
const currentVersion = getPref(Preferences.CURRENT_VERSION);
|
||||||
const lastCheck = getPref(Preferences.LAST_UPDATE_CHECK);
|
const lastCheck = getPref(Preferences.LAST_UPDATE_CHECK);
|
||||||
@ -8487,6 +8582,11 @@ div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module
|
|||||||
left: -9999px;
|
left: -9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove the "Cloud Gaming" text in header */
|
||||||
|
header a[href="/play"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
a.bx-button {
|
a.bx-button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@ -8577,31 +8677,27 @@ a.bx-button.bx-full-width {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bx-remote-play-button {
|
.bx-header-remote-play-button {
|
||||||
height: auto;
|
height: auto;
|
||||||
margin-right: 8px !important;
|
margin-right: 8px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bx-remote-play-button svg {
|
.bx-header-remote-play-button svg {
|
||||||
width: 28px;
|
width: 24px;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bx-remote-play-button[disabled] {
|
.bx-header-settings-button {
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bx-settings-button {
|
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
font-size: 14px;
|
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: ' 🌟';
|
content: ' 🌟';
|
||||||
}
|
}
|
||||||
|
|
||||||
.bx-button.bx-focusable, .bx-settings-button {
|
.bx-button.bx-focusable, .bx-header-settings-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9817,6 +9913,10 @@ body:not([data-media-type=tv]) div[class*=MenuItem-module__label] {
|
|||||||
// Hide scrollbar
|
// Hide scrollbar
|
||||||
if (getPref(Preferences.UI_SCROLLBAR_HIDE)) {
|
if (getPref(Preferences.UI_SCROLLBAR_HIDE)) {
|
||||||
css += `
|
css += `
|
||||||
|
html {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
body::-webkit-scrollbar {
|
body::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -9828,16 +9928,16 @@ body::-webkit-scrollbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getPreferredServerRegion() {
|
function getPreferredServerRegion(shortName = false) {
|
||||||
let preferredRegion = getPref(Preferences.SERVER_REGION);
|
let preferredRegion = getPref(Preferences.SERVER_REGION);
|
||||||
if (preferredRegion in SERVER_REGIONS) {
|
if (preferredRegion in SERVER_REGIONS) {
|
||||||
return preferredRegion;
|
return shortName ? SERVER_REGIONS[preferredRegion].shortName : preferredRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let regionName in SERVER_REGIONS) {
|
for (let regionName in SERVER_REGIONS) {
|
||||||
const region = SERVER_REGIONS[regionName];
|
const region = SERVER_REGIONS[regionName];
|
||||||
if (region.isDefault) {
|
if (region.isDefault) {
|
||||||
return regionName;
|
return shortName ? region.shortName : regionName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9983,16 +10083,15 @@ function interceptHttpRequests() {
|
|||||||
|
|
||||||
const consoleAddrs = {};
|
const consoleAddrs = {};
|
||||||
|
|
||||||
const patchIceCandidates = function(...arg) {
|
const patchIceCandidates = async (...arg) => {
|
||||||
// ICE server candidates
|
// ICE server candidates
|
||||||
const request = arg[0];
|
const request = arg[0];
|
||||||
const url = (typeof request === 'string') ? request : request.url;
|
const url = (typeof request === 'string') ? request : request.url;
|
||||||
|
|
||||||
if (url && url.endsWith('/ice') && url.includes('/sessions/') && request.method === 'GET') {
|
if (url && url.endsWith('/ice') && url.includes('/sessions/') && request.method === 'GET') {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
|
const text = await response.clone().text();
|
||||||
|
|
||||||
return promise.then(response => {
|
|
||||||
return response.clone().text().then(text => {
|
|
||||||
if (!text.length) {
|
if (!text.length) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -10011,8 +10110,6 @@ function interceptHttpRequests() {
|
|||||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -10041,7 +10138,7 @@ function interceptHttpRequests() {
|
|||||||
BxEvent.dispatch(window, BxEvent.STREAM_STARTING);
|
BxEvent.dispatch(window, BxEvent.STREAM_STARTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_REMOTE_PLAYING && (url.includes('/sessions/home') || url.includes('inputconfigs'))) {
|
if (url.includes('/sessions/home') || (IS_REMOTE_PLAYING && url.includes('inputconfigs'))) {
|
||||||
TouchController.disable();
|
TouchController.disable();
|
||||||
|
|
||||||
const clone = request.clone();
|
const clone = request.clone();
|
||||||
@ -10069,7 +10166,7 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const index = request.url.indexOf('.xboxlive.com');
|
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);
|
request = new Request(newUrl, opts);
|
||||||
|
|
||||||
@ -10078,10 +10175,9 @@ function interceptHttpRequests() {
|
|||||||
|
|
||||||
// Get console IP
|
// Get console IP
|
||||||
if (url.includes('/configuration')) {
|
if (url.includes('/configuration')) {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
|
|
||||||
return promise.then(response => {
|
const obj = await response.clone().json()
|
||||||
return response.clone().json().then(obj => {
|
|
||||||
console.log(obj);
|
console.log(obj);
|
||||||
|
|
||||||
const serverDetails = obj.serverDetails;
|
const serverDetails = obj.serverDetails;
|
||||||
@ -10097,13 +10193,10 @@ function interceptHttpRequests() {
|
|||||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
} else if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && url.includes('inputconfigs')) {
|
} else if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && url.includes('inputconfigs')) {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
|
const obj = await response.clone().json();
|
||||||
|
|
||||||
return promise.then(response => {
|
|
||||||
return response.clone().json().then(obj => {
|
|
||||||
const xboxTitleId = JSON.parse(opts.body).titleIds[0];
|
const xboxTitleId = JSON.parse(opts.body).titleIds[0];
|
||||||
GAME_XBOX_TITLE_ID = xboxTitleId;
|
GAME_XBOX_TITLE_ID = xboxTitleId;
|
||||||
|
|
||||||
@ -10130,14 +10223,12 @@ function interceptHttpRequests() {
|
|||||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return patchIceCandidates(...arg) || NATIVE_FETCH(...arg);
|
return await patchIceCandidates(...arg) || NATIVE_FETCH(...arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_REMOTE_PLAYING && url.includes('/login/user')) {
|
if (IS_REMOTE_PLAYING && url.includes('xhome') && url.includes('/login/user')) {
|
||||||
try {
|
try {
|
||||||
const clone = request.clone();
|
const clone = request.clone();
|
||||||
|
|
||||||
@ -10182,23 +10273,56 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ICE server candidates
|
// ICE server candidates
|
||||||
const patchedIpv6 = patchIceCandidates(...arg);
|
const patchedIpv6 = await patchIceCandidates(...arg);
|
||||||
if (patchedIpv6) {
|
if (patchedIpv6) {
|
||||||
return patchedIpv6;
|
return patchedIpv6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server list
|
// Server list
|
||||||
if (!url.includes('xhome.') && url.endsWith('/v2/login/user')) {
|
if (!url.includes('xhome.') && url.endsWith('/v2/login/user')) {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
|
const obj = await response.clone().json();
|
||||||
|
|
||||||
|
// Preload Remote Play
|
||||||
|
BX_FLAGS.PreloadRemotePlay && RemotePlay.preload();
|
||||||
|
|
||||||
return promise.then(response => {
|
|
||||||
return response.clone().json().then(obj => {
|
|
||||||
// Store xCloud token
|
// Store xCloud token
|
||||||
RemotePlay.XCLOUD_TOKEN = obj.gsToken;
|
RemotePlay.XCLOUD_TOKEN = obj.gsToken;
|
||||||
|
|
||||||
// Get server list
|
// Get server list
|
||||||
if (!Object.keys(SERVER_REGIONS).length) {
|
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) {
|
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);
|
SERVER_REGIONS[region.name] = Object.assign({}, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10220,8 +10344,6 @@ function interceptHttpRequests() {
|
|||||||
|
|
||||||
response.json = () => Promise.resolve(obj);
|
response.json = () => Promise.resolve(obj);
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get region
|
// Get region
|
||||||
@ -10266,22 +10388,18 @@ function interceptHttpRequests() {
|
|||||||
|
|
||||||
// Get wait time
|
// Get wait time
|
||||||
if (PREF_UI_LOADING_SCREEN_WAIT_TIME && url.includes('xboxlive.com') && url.includes('/waittime/')) {
|
if (PREF_UI_LOADING_SCREEN_WAIT_TIME && url.includes('xboxlive.com') && url.includes('/waittime/')) {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
return promise.then(response => {
|
|
||||||
return response.clone().json().then(json => {
|
const json = await response.clone.json();
|
||||||
if (json.estimatedAllocationTimeInSeconds > 0) {
|
if (json.estimatedAllocationTimeInSeconds > 0) {
|
||||||
// Setup wait time overlay
|
// Setup wait time overlay
|
||||||
LoadingScreen.setupWaitTime(json.estimatedTotalWaitTimeInSeconds);
|
LoadingScreen.setupWaitTime(json.estimatedTotalWaitTimeInSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.endsWith('/configuration') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
if (url.endsWith('/configuration') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
|
||||||
|
|
||||||
// Touch controller for all games
|
// Touch controller for all games
|
||||||
if (PREF_STREAM_TOUCH_CONTROLLER === 'all') {
|
if (PREF_STREAM_TOUCH_CONTROLLER === 'all') {
|
||||||
TouchController.disable();
|
TouchController.disable();
|
||||||
@ -10296,8 +10414,8 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Intercept configurations
|
// Intercept configurations
|
||||||
return promise.then(response => {
|
const response = await NATIVE_FETCH(...arg);
|
||||||
return response.clone().text().then(text => {
|
const text = await response.clone().text();
|
||||||
if (!text.length) {
|
if (!text.length) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -10329,35 +10447,28 @@ function interceptHttpRequests() {
|
|||||||
response.text = () => Promise.resolve(JSON.stringify(obj));
|
response.text = () => Promise.resolve(JSON.stringify(obj));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// catalog.gamepass
|
// catalog.gamepass
|
||||||
if (url.startsWith('https://catalog.gamepass.com') && url.includes('/products')) {
|
if (url.startsWith('https://catalog.gamepass.com') && url.includes('/products')) {
|
||||||
const promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
return promise.then(response => {
|
const json = await response.clone().json()
|
||||||
return response.clone().json().then(json => {
|
|
||||||
for (let productId in json.Products) {
|
for (let productId in json.Products) {
|
||||||
TitlesInfo.saveFromCatalogInfo(json.Products[productId]);
|
TitlesInfo.saveFromCatalogInfo(json.Products[productId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
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 promise = NATIVE_FETCH(...arg);
|
const response = await NATIVE_FETCH(...arg);
|
||||||
return promise.then(response => {
|
const json = await response.clone().json()
|
||||||
return response.clone().json().then(json => {
|
|
||||||
for (let game of json.results) {
|
for (let game of json.results) {
|
||||||
TitlesInfo.saveFromTitleInfo(game);
|
TitlesInfo.saveFromTitleInfo(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NATIVE_FETCH(...arg);
|
return NATIVE_FETCH(...arg);
|
||||||
@ -10365,60 +10476,17 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function injectSettingsButton($parent) {
|
function setupSettingsUi() {
|
||||||
if (!$parent) {
|
// Avoid rendering the Settings multiple times
|
||||||
|
if (document.querySelector('.bx-settings-container')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PREF_PREFERRED_REGION = getPreferredServerRegion();
|
const PREF_PREFERRED_REGION = getPreferredServerRegion();
|
||||||
const PREF_LATEST_VERSION = getPref(Preferences.LATEST_VERSION);
|
const PREF_LATEST_VERSION = getPref(Preferences.LATEST_VERSION);
|
||||||
|
|
||||||
const $headerFragment = document.createDocumentFragment();
|
|
||||||
let $reloadBtnWrapper;
|
let $reloadBtnWrapper;
|
||||||
|
|
||||||
// Remote Play button
|
|
||||||
if (getPref(Preferences.REMOTE_PLAY_ENABLED)) {
|
|
||||||
const $remotePlayBtn = createButton({
|
|
||||||
classes: ['bx-remote-play-button'],
|
|
||||||
icon: Icon.REMOTE_PLAY,
|
|
||||||
title: t('remote-play'),
|
|
||||||
disabled: !RemotePlay.isReady(),
|
|
||||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
|
||||||
onClick: e => {
|
|
||||||
RemotePlay.togglePopup();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
$headerFragment.appendChild($remotePlayBtn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Setup Settings button
|
|
||||||
const $settingsBtn = createButton({
|
|
||||||
classes: ['bx-settings-button'],
|
|
||||||
label: PREF_PREFERRED_REGION,
|
|
||||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_HEIGHT,
|
|
||||||
onClick: e => {
|
|
||||||
const $settings = document.querySelector('.bx-settings-container');
|
|
||||||
$settings.classList.toggle('bx-gone');
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
document.activeElement && document.activeElement.blur();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show new update status
|
|
||||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
|
||||||
$settingsBtn.setAttribute('data-update-available', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the Settings button to the web page
|
|
||||||
$headerFragment.appendChild($settingsBtn);
|
|
||||||
$parent.appendChild($headerFragment);
|
|
||||||
|
|
||||||
// Avoid rendering the Settings multiple times
|
|
||||||
if (document.querySelector('.bx-settings-container')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup Settings UI
|
// Setup Settings UI
|
||||||
const $container = CE('div', {
|
const $container = CE('div', {
|
||||||
'class': 'bx-settings-container bx-gone',
|
'class': 'bx-settings-container bx-gone',
|
||||||
@ -10481,12 +10549,14 @@ function injectSettingsButton($parent) {
|
|||||||
[Preferences.STREAM_TARGET_RESOLUTION]: t('target-resolution'),
|
[Preferences.STREAM_TARGET_RESOLUTION]: t('target-resolution'),
|
||||||
[Preferences.STREAM_CODEC_PROFILE]: t('visual-quality'),
|
[Preferences.STREAM_CODEC_PROFILE]: t('visual-quality'),
|
||||||
[Preferences.GAME_FORTNITE_FORCE_CONSOLE]: '🎮 ' + t('fortnite-force-console-version'),
|
[Preferences.GAME_FORTNITE_FORCE_CONSOLE]: '🎮 ' + t('fortnite-force-console-version'),
|
||||||
[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_BUTTON_POSITION]: t('screenshot-button-position'),
|
||||||
[Preferences.SCREENSHOT_APPLY_FILTERS]: t('screenshot-apply-filters'),
|
[Preferences.SCREENSHOT_APPLY_FILTERS]: t('screenshot-apply-filters'),
|
||||||
|
|
||||||
|
[Preferences.AUDIO_ENABLE_VOLUME_CONTROL]: t('enable-volume-control'),
|
||||||
|
[Preferences.STREAM_COMBINE_SOURCES]: t('combine-audio-video-streams'),
|
||||||
},
|
},
|
||||||
|
|
||||||
[t('local-co-op')]: {
|
[t('local-co-op')]: {
|
||||||
@ -10521,9 +10591,9 @@ function injectSettingsButton($parent) {
|
|||||||
},
|
},
|
||||||
[t('ui')]: {
|
[t('ui')]: {
|
||||||
[Preferences.UI_LAYOUT]: t('layout'),
|
[Preferences.UI_LAYOUT]: t('layout'),
|
||||||
[Preferences.UI_SCROLLBAR_HIDE]: t('hide-scrollbar'),
|
|
||||||
[Preferences.STREAM_SIMPLIFY_MENU]: t('simplify-stream-menu'),
|
[Preferences.STREAM_SIMPLIFY_MENU]: t('simplify-stream-menu'),
|
||||||
[Preferences.SKIP_SPLASH_VIDEO]: t('skip-splash-video'),
|
[Preferences.SKIP_SPLASH_VIDEO]: t('skip-splash-video'),
|
||||||
|
[!AppInterface && Preferences.UI_SCROLLBAR_HIDE]: t('hide-scrollbar'),
|
||||||
[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'),
|
||||||
},
|
},
|
||||||
@ -10571,14 +10641,27 @@ function injectSettingsButton($parent) {
|
|||||||
|
|
||||||
for (let settingId in SETTINGS_UI[groupLabel]) {
|
for (let settingId in SETTINGS_UI[groupLabel]) {
|
||||||
// Don't render custom settings
|
// Don't render custom settings
|
||||||
if (settingId.startsWith('_')) {
|
if (!settingId || settingId === 'false' || settingId === 'undefined' || settingId.startsWith('_')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setting = Preferences.SETTINGS[settingId];
|
const setting = Preferences.SETTINGS[settingId];
|
||||||
|
if (!setting) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const settingLabel = SETTINGS_UI[groupLabel][settingId];
|
let settingLabel = SETTINGS_UI[groupLabel][settingId];
|
||||||
const settingNote = setting.note;
|
let settingNote = setting.note || '';
|
||||||
|
|
||||||
|
// Add Experimental text
|
||||||
|
if (setting.experimental) {
|
||||||
|
settingLabel = '🧪 ' + settingLabel;
|
||||||
|
if (!settingNote) {
|
||||||
|
settingNote = t('experimental')
|
||||||
|
} else {
|
||||||
|
settingNote = `${t('experimental')}: ${settingNote}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let $control, $inpCustomUserAgent;
|
let $control, $inpCustomUserAgent;
|
||||||
let labelAttrs = {};
|
let labelAttrs = {};
|
||||||
@ -10623,7 +10706,7 @@ function injectSettingsButton($parent) {
|
|||||||
const region = SERVER_REGIONS[regionName];
|
const region = SERVER_REGIONS[regionName];
|
||||||
let value = regionName;
|
let value = regionName;
|
||||||
|
|
||||||
let label = regionName;
|
let label = `${region.shortName} - ${regionName}`;
|
||||||
if (region.isDefault) {
|
if (region.isDefault) {
|
||||||
label += ` (${t('default')})`;
|
label += ` (${t('default')})`;
|
||||||
value = 'default';
|
value = 'default';
|
||||||
@ -10709,6 +10792,57 @@ function injectSettingsButton($parent) {
|
|||||||
$pageContent.parentNode.insertBefore($container, $pageContent);
|
$pageContent.parentNode.insertBefore($container, $pageContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function injectSettingsButton($parent) {
|
||||||
|
if (!$parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PREF_PREFERRED_REGION = getPreferredServerRegion(true);
|
||||||
|
const PREF_LATEST_VERSION = getPref(Preferences.LATEST_VERSION);
|
||||||
|
|
||||||
|
const $headerFragment = document.createDocumentFragment();
|
||||||
|
|
||||||
|
// Remote Play button
|
||||||
|
if (getPref(Preferences.REMOTE_PLAY_ENABLED)) {
|
||||||
|
const $remotePlayBtn = createButton({
|
||||||
|
classes: ['bx-header-remote-play-button'],
|
||||||
|
icon: Icon.REMOTE_PLAY,
|
||||||
|
title: t('remote-play'),
|
||||||
|
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
||||||
|
onClick: e => {
|
||||||
|
RemotePlay.togglePopup();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
$headerFragment.appendChild($remotePlayBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Setup Settings button
|
||||||
|
const $settingsBtn = createButton({
|
||||||
|
classes: ['bx-header-settings-button'],
|
||||||
|
label: PREF_PREFERRED_REGION,
|
||||||
|
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_HEIGHT,
|
||||||
|
onClick: e => {
|
||||||
|
setupSettingsUi();
|
||||||
|
|
||||||
|
const $settings = document.querySelector('.bx-settings-container');
|
||||||
|
$settings.classList.toggle('bx-gone');
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
document.activeElement && document.activeElement.blur();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show new update status
|
||||||
|
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||||
|
$settingsBtn.setAttribute('data-update-available', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Settings button to the web page
|
||||||
|
$headerFragment.appendChild($settingsBtn);
|
||||||
|
$parent.appendChild($headerFragment);
|
||||||
|
}
|
||||||
|
|
||||||
function getVideoPlayerFilterStyle() {
|
function getVideoPlayerFilterStyle() {
|
||||||
const filters = [];
|
const filters = [];
|
||||||
|
|
||||||
@ -10811,7 +10945,7 @@ div[data-testid="media-container"] {
|
|||||||
|
|
||||||
|
|
||||||
function checkHeader() {
|
function checkHeader() {
|
||||||
const $button = document.querySelector('.bx-settings-button');
|
const $button = document.querySelector('.bx-header-settings-button');
|
||||||
|
|
||||||
if (!$button) {
|
if (!$button) {
|
||||||
const $rightHeader = document.querySelector('#PageContent div[class*=EdgewaterHeader-module__rightSectionSpacing]');
|
const $rightHeader = document.querySelector('#PageContent div[class*=EdgewaterHeader-module__rightSectionSpacing]');
|
||||||
@ -11135,6 +11269,10 @@ function patchVideoApi() {
|
|||||||
return nativePlay.apply(this);
|
return nativePlay.apply(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!this.src) {
|
||||||
|
return nativePlay.apply(this);
|
||||||
|
}
|
||||||
|
|
||||||
this.addEventListener('playing', showFunc);
|
this.addEventListener('playing', showFunc);
|
||||||
injectStreamMenuButtons();
|
injectStreamMenuButtons();
|
||||||
|
|
||||||
@ -11769,7 +11907,7 @@ window.addEventListener(BxEvent.STREAM_STOPPED, e => {
|
|||||||
PreloadedState.override();
|
PreloadedState.override();
|
||||||
|
|
||||||
// Check for Update
|
// Check for Update
|
||||||
checkForUpdate();
|
BX_FLAGS.CheckForUpdate && checkForUpdate();
|
||||||
|
|
||||||
// Monkey patches
|
// Monkey patches
|
||||||
if (getPref(Preferences.AUDIO_ENABLE_VOLUME_CONTROL)) {
|
if (getPref(Preferences.AUDIO_ENABLE_VOLUME_CONTROL)) {
|
||||||
@ -11866,7 +12004,6 @@ Patcher.initialize();
|
|||||||
|
|
||||||
// Preload Remote Play
|
// Preload Remote Play
|
||||||
if (getPref(Preferences.REMOTE_PLAY_ENABLED)) {
|
if (getPref(Preferences.REMOTE_PLAY_ENABLED)) {
|
||||||
BX_FLAGS.PreloadRemotePlay && RemotePlay.preload();
|
|
||||||
RemotePlay.detect();
|
RemotePlay.detect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user