mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-06 07:37:19 +02:00
Update better-xcloud.user.js
This commit is contained in:
parent
85eac4be14
commit
e9b0d900b0
527
dist/better-xcloud.user.js
vendored
527
dist/better-xcloud.user.js
vendored
@ -13,15 +13,112 @@
|
||||
// @downloadURL https://github.com/redphx/better-xcloud/releases/latest/download/better-xcloud.user.js
|
||||
// ==/UserScript==
|
||||
'use strict';
|
||||
// src/utils/user-agent.ts
|
||||
var UserAgentProfile;
|
||||
(function(UserAgentProfile2) {
|
||||
UserAgentProfile2["WINDOWS_EDGE"] = "windows-edge";
|
||||
UserAgentProfile2["MACOS_SAFARI"] = "macos-safari";
|
||||
UserAgentProfile2["SMARTTV_GENERIC"] = "smarttv-generic";
|
||||
UserAgentProfile2["SMARTTV_TIZEN"] = "smarttv-tizen";
|
||||
UserAgentProfile2["VR_OCULUS"] = "vr-oculus";
|
||||
UserAgentProfile2["ANDROID_KIWI_V123"] = "android-kiwi-v123";
|
||||
UserAgentProfile2["DEFAULT"] = "default";
|
||||
UserAgentProfile2["CUSTOM"] = "custom";
|
||||
})(UserAgentProfile || (UserAgentProfile = {}));
|
||||
var CHROMIUM_VERSION = "123.0.0.0";
|
||||
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {
|
||||
const match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);
|
||||
if (match) {
|
||||
CHROMIUM_VERSION = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
class UserAgent {
|
||||
static STORAGE_KEY = "better_xcloud_user_agent";
|
||||
static #config;
|
||||
static #USER_AGENTS = {
|
||||
[UserAgentProfile.WINDOWS_EDGE]: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROMIUM_VERSION} Safari/537.36 Edg/${CHROMIUM_VERSION}`,
|
||||
[UserAgentProfile.MACOS_SAFARI]: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.1",
|
||||
[UserAgentProfile.SMARTTV_GENERIC]: window.navigator.userAgent + " SmartTV",
|
||||
[UserAgentProfile.SMARTTV_TIZEN]: `Mozilla/5.0 (SMART-TV; LINUX; Tizen 7.0) AppleWebKit/537.36 (KHTML, like Gecko) ${CHROMIUM_VERSION}/7.0 TV Safari/537.36`,
|
||||
[UserAgentProfile.VR_OCULUS]: window.navigator.userAgent + " OculusBrowser VR",
|
||||
[UserAgentProfile.ANDROID_KIWI_V123]: "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36"
|
||||
};
|
||||
static init() {
|
||||
UserAgent.#config = JSON.parse(window.localStorage.getItem(UserAgent.STORAGE_KEY) || "{}");
|
||||
if (!UserAgent.#config.profile) {
|
||||
UserAgent.#config.profile = UserAgentProfile.DEFAULT;
|
||||
}
|
||||
if (!UserAgent.#config.custom) {
|
||||
UserAgent.#config.custom = "";
|
||||
}
|
||||
UserAgent.spoof();
|
||||
}
|
||||
static updateStorage(profile, custom) {
|
||||
const clonedConfig = structuredClone(UserAgent.#config);
|
||||
clonedConfig.profile = profile;
|
||||
if (typeof custom !== "undefined") {
|
||||
clonedConfig.custom = custom;
|
||||
}
|
||||
window.localStorage.setItem(UserAgent.STORAGE_KEY, JSON.stringify(clonedConfig));
|
||||
}
|
||||
static getDefault() {
|
||||
return window.navigator.orgUserAgent || window.navigator.userAgent;
|
||||
}
|
||||
static get(profile) {
|
||||
const defaultUserAgent = window.navigator.userAgent;
|
||||
switch (profile) {
|
||||
case UserAgentProfile.DEFAULT:
|
||||
return defaultUserAgent;
|
||||
case UserAgentProfile.CUSTOM:
|
||||
return UserAgent.#config.custom || defaultUserAgent;
|
||||
default:
|
||||
return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;
|
||||
}
|
||||
}
|
||||
static isSafari(mobile = false) {
|
||||
const userAgent = UserAgent.getDefault().toLowerCase();
|
||||
let result = userAgent.includes("safari") && !userAgent.includes("chrom");
|
||||
if (result && mobile) {
|
||||
result = userAgent.includes("mobile");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static isMobile() {
|
||||
const userAgent = UserAgent.getDefault().toLowerCase();
|
||||
return /iphone|ipad|android/.test(userAgent);
|
||||
}
|
||||
static spoof() {
|
||||
const profile = UserAgent.#config.profile;
|
||||
if (profile === UserAgentProfile.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
const newUserAgent = UserAgent.get(profile);
|
||||
window.navigator.orgUserAgentData = window.navigator.userAgentData;
|
||||
Object.defineProperty(window.navigator, "userAgentData", {});
|
||||
window.navigator.orgUserAgent = window.navigator.userAgent;
|
||||
Object.defineProperty(window.navigator, "userAgent", {
|
||||
value: newUserAgent
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// src/utils/global.ts
|
||||
var SCRIPT_VERSION = "4.2.0";
|
||||
var SCRIPT_HOME = "https://github.com/redphx/better-xcloud";
|
||||
var AppInterface = window.AppInterface;
|
||||
UserAgent.init();
|
||||
var userAgent = window.navigator.userAgent.toLowerCase();
|
||||
var isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent);
|
||||
var isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser");
|
||||
var browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
||||
var hasTouchSupport = !isTv && !isVr && browserHasTouchSupport;
|
||||
var STATES = {
|
||||
isPlaying: false,
|
||||
appContext: {},
|
||||
serverRegions: {},
|
||||
hasTouchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0,
|
||||
hasTouchSupport,
|
||||
browserHasTouchSupport,
|
||||
currentStream: {},
|
||||
remotePlay: {}
|
||||
};
|
||||
@ -1143,6 +1240,23 @@ var Texts = {
|
||||
"Bật tính năng phím tắt cho bộ điều khiển",
|
||||
"启用手柄快捷方式"
|
||||
],
|
||||
"enable-game-bar": [
|
||||
,
|
||||
,
|
||||
"Enable Game Bar feature",
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
"Kích hoạt tính năng Game Bar",
|
||||
,
|
||||
],
|
||||
"enable-local-co-op-support": [
|
||||
"Lokale Koop-Unterstützung aktivieren",
|
||||
"Nyalakan dukungan mode lokal co-op",
|
||||
@ -1458,7 +1572,7 @@ var Texts = {
|
||||
,
|
||||
"タッチコントローラーを隠す",
|
||||
,
|
||||
,
|
||||
"Ukryj sterowanie dotykowe",
|
||||
,
|
||||
"Скрыть сенсорный контроллер",
|
||||
,
|
||||
@ -1769,7 +1883,7 @@ var Texts = {
|
||||
"Использование этой функции при игре онлайн может рассматриваться как читерство",
|
||||
"Bu özellik çevrimiçi oyunlarda sizi hile yapıyormuşsunuz gibi gösterebilir",
|
||||
"Використання цієї функції під час гри онлайн може розглядатися як шахрайство",
|
||||
"Sử dụng chức năng này khi chơi trực tuyến có thể bị xem là gian lận",
|
||||
"Sử dụng tính năng này khi chơi trực tuyến có thể bị xem là gian lận",
|
||||
"游玩在线游戏时,使用此功能可能被视为作弊。"
|
||||
],
|
||||
"mouse-and-keyboard": [
|
||||
@ -2401,23 +2515,6 @@ var Texts = {
|
||||
"Áp dụng hiệu ứng video vào ảnh chụp màn hình",
|
||||
"为截图添加滤镜"
|
||||
],
|
||||
"screenshot-button-position": [
|
||||
"Position des Screenshot-Buttons",
|
||||
"Posisi tombol Screenshot",
|
||||
"Screenshot button's position",
|
||||
"Posición del botón de captura de pantalla",
|
||||
"Position du bouton de capture d'écran",
|
||||
"Posizione del pulsante screenshot",
|
||||
"スクリーンショットボタンの位置",
|
||||
"스크린샷 버튼 위치",
|
||||
"Pozycja przycisku zrzutu ekranu",
|
||||
"Posição do botão de captura de tela",
|
||||
"Расположение кнопки скриншота",
|
||||
"Ekran görüntüsü düğmesi konumu",
|
||||
"Позиція кнопки знімка екрана",
|
||||
"Vị trí của nút Chụp màn hình",
|
||||
"截图按钮位置"
|
||||
],
|
||||
"separate-touch-controller": [
|
||||
"Trenne Touch-Controller & Controller #1",
|
||||
"Pisahkan Kontrol sentuh & Kontroler #1",
|
||||
@ -2563,7 +2660,7 @@ var Texts = {
|
||||
,
|
||||
"タッチコントローラーを表示",
|
||||
,
|
||||
,
|
||||
"Pokaż sterowanie dotykowe",
|
||||
,
|
||||
"Показать сенсорный контроллер",
|
||||
,
|
||||
@ -2937,7 +3034,7 @@ var Texts = {
|
||||
,
|
||||
"スクリーンショットを撮影",
|
||||
,
|
||||
,
|
||||
"Zrób zrzut ekranu",
|
||||
,
|
||||
"Сделать снимок экрана",
|
||||
,
|
||||
@ -3319,6 +3416,23 @@ var Texts = {
|
||||
"Sử dụng vị trí tuyệt đối của chuột",
|
||||
"使用鼠标的绝对位置"
|
||||
],
|
||||
"user-agent-note": [
|
||||
,
|
||||
,
|
||||
"This feature may cause unexpected behavior",
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
,
|
||||
"Tính năng này có thể gây ra các hành vi không mong muốn",
|
||||
,
|
||||
],
|
||||
"user-agent-profile": [
|
||||
"User-Agent Profil",
|
||||
"Profil User-Agent",
|
||||
@ -3552,44 +3666,42 @@ var t = Translations.get;
|
||||
var refreshCurrentLocale = Translations.refreshCurrentLocale;
|
||||
refreshCurrentLocale();
|
||||
|
||||
// src/modules/game-bar/action-screenshot.ts
|
||||
class ScreenshotAction extends BaseGameBarAction {
|
||||
$content;
|
||||
constructor() {
|
||||
super();
|
||||
// src/utils/screenshot.ts
|
||||
class Screenshot {
|
||||
static #filters = "";
|
||||
static setup() {
|
||||
const currentStream = STATES.currentStream;
|
||||
currentStream.$screenshotCanvas = CE("canvas", { class: "bx-gone" });
|
||||
document.documentElement.appendChild(currentStream.$screenshotCanvas);
|
||||
const onClick = (e) => {
|
||||
BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED);
|
||||
this.takeScreenshot();
|
||||
};
|
||||
this.$content = createButton({
|
||||
style: ButtonStyle.GHOST,
|
||||
icon: BxIcon.SCREENSHOT,
|
||||
title: t("take-screenshot"),
|
||||
onClick
|
||||
});
|
||||
if (!currentStream.$screenshotCanvas) {
|
||||
currentStream.$screenshotCanvas = CE("canvas", { class: "bx-gone" });
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return this.$content;
|
||||
static updateCanvasSize(width, height) {
|
||||
const $canvas = STATES.currentStream.$screenshotCanvas;
|
||||
if ($canvas) {
|
||||
$canvas.width = width;
|
||||
$canvas.height = height;
|
||||
}
|
||||
}
|
||||
takeScreenshot(callback) {
|
||||
static updateCanvasFilters(filters) {
|
||||
Screenshot.#filters = filters;
|
||||
}
|
||||
static takeScreenshot(callback) {
|
||||
const currentStream = STATES.currentStream;
|
||||
const $video = currentStream.$video;
|
||||
const $canvas = currentStream.$screenshotCanvas;
|
||||
if (!$video || !$canvas) {
|
||||
return;
|
||||
}
|
||||
const $canvasContext = $canvas.getContext("2d", {
|
||||
const canvasContext = $canvas.getContext("2d", {
|
||||
alpha: false,
|
||||
willReadFrequently: false
|
||||
});
|
||||
$canvasContext.drawImage($video, 0, 0, $canvas.width, $canvas.height);
|
||||
canvasContext.filter = Screenshot.#filters;
|
||||
canvasContext.drawImage($video, 0, 0, $canvas.width, $canvas.height);
|
||||
if (AppInterface) {
|
||||
const data = $canvas.toDataURL("image/png").split(";base64,")[1];
|
||||
AppInterface.saveScreenshot(currentStream.titleId, data);
|
||||
$canvasContext.clearRect(0, 0, $canvas.width, $canvas.height);
|
||||
canvasContext.clearRect(0, 0, $canvas.width, $canvas.height);
|
||||
callback && callback();
|
||||
return;
|
||||
}
|
||||
@ -3601,12 +3713,33 @@ class ScreenshotAction extends BaseGameBarAction {
|
||||
});
|
||||
$anchor.click();
|
||||
URL.revokeObjectURL($anchor.href);
|
||||
$canvasContext.clearRect(0, 0, $canvas.width, $canvas.height);
|
||||
canvasContext.clearRect(0, 0, $canvas.width, $canvas.height);
|
||||
callback && callback();
|
||||
}, "image/png");
|
||||
}
|
||||
}
|
||||
|
||||
// src/modules/game-bar/action-screenshot.ts
|
||||
class ScreenshotAction extends BaseGameBarAction {
|
||||
$content;
|
||||
constructor() {
|
||||
super();
|
||||
const onClick = (e) => {
|
||||
BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED);
|
||||
Screenshot.takeScreenshot();
|
||||
};
|
||||
this.$content = createButton({
|
||||
style: ButtonStyle.GHOST,
|
||||
icon: BxIcon.SCREENSHOT,
|
||||
title: t("take-screenshot"),
|
||||
onClick
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return this.$content;
|
||||
}
|
||||
}
|
||||
|
||||
// src/utils/toast.ts
|
||||
class Toast {
|
||||
static #$wrapper;
|
||||
@ -3873,76 +4006,6 @@ class SettingElement {
|
||||
}
|
||||
}
|
||||
|
||||
// src/utils/user-agent.ts
|
||||
var UserAgentProfile;
|
||||
(function(UserAgentProfile2) {
|
||||
UserAgentProfile2["EDGE_WINDOWS"] = "edge-windows";
|
||||
UserAgentProfile2["SAFARI_MACOS"] = "safari-macos";
|
||||
UserAgentProfile2["SMARTTV"] = "smarttv";
|
||||
UserAgentProfile2["SMARTTV_TIZEN"] = "smarttv-tizen";
|
||||
UserAgentProfile2["VR_OCULUS"] = "vr-oculus";
|
||||
UserAgentProfile2["KIWI_V123"] = "kiwi-v123";
|
||||
UserAgentProfile2["DEFAULT"] = "default";
|
||||
UserAgentProfile2["CUSTOM"] = "custom";
|
||||
})(UserAgentProfile || (UserAgentProfile = {}));
|
||||
var CHROMIUM_VERSION = "123.0.0.0";
|
||||
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {
|
||||
const match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);
|
||||
if (match) {
|
||||
CHROMIUM_VERSION = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
class UserAgent {
|
||||
static #USER_AGENTS = {
|
||||
[UserAgentProfile.EDGE_WINDOWS]: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROMIUM_VERSION} Safari/537.36 Edg/${CHROMIUM_VERSION}`,
|
||||
[UserAgentProfile.SAFARI_MACOS]: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.1",
|
||||
[UserAgentProfile.SMARTTV]: window.navigator.userAgent + " SmartTV",
|
||||
[UserAgentProfile.SMARTTV_TIZEN]: `Mozilla/5.0 (SMART-TV; LINUX; Tizen 7.0) AppleWebKit/537.36 (KHTML, like Gecko) ${CHROMIUM_VERSION}/7.0 TV Safari/537.36`,
|
||||
[UserAgentProfile.VR_OCULUS]: window.navigator.userAgent + " OculusBrowser VR",
|
||||
[UserAgentProfile.KIWI_V123]: "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36"
|
||||
};
|
||||
static getDefault() {
|
||||
return window.navigator.orgUserAgent || window.navigator.userAgent;
|
||||
}
|
||||
static get(profile) {
|
||||
const defaultUserAgent = UserAgent.getDefault();
|
||||
if (profile === UserAgentProfile.CUSTOM) {
|
||||
return getPref(PrefKey.USER_AGENT_CUSTOM);
|
||||
}
|
||||
return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;
|
||||
}
|
||||
static isSafari(mobile = false) {
|
||||
const userAgent = (UserAgent.getDefault() || "").toLowerCase();
|
||||
let result = userAgent.includes("safari") && !userAgent.includes("chrom");
|
||||
if (result && mobile) {
|
||||
result = userAgent.includes("mobile");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static isMobile() {
|
||||
const userAgent = (UserAgent.getDefault() || "").toLowerCase();
|
||||
return /iphone|ipad|android/.test(userAgent);
|
||||
}
|
||||
static spoof() {
|
||||
let newUserAgent;
|
||||
const profile = getPref(PrefKey.USER_AGENT_PROFILE);
|
||||
if (profile === UserAgentProfile.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
if (!newUserAgent) {
|
||||
newUserAgent = UserAgent.get(profile);
|
||||
}
|
||||
window.navigator.orgUserAgentData = window.navigator.userAgentData;
|
||||
Object.defineProperty(window.navigator, "userAgentData", {});
|
||||
window.navigator.orgUserAgent = window.navigator.userAgent;
|
||||
Object.defineProperty(window.navigator, "userAgent", {
|
||||
value: newUserAgent
|
||||
});
|
||||
return newUserAgent;
|
||||
}
|
||||
}
|
||||
|
||||
// src/modules/stream/stream-badges.ts
|
||||
var StreamBadge;
|
||||
(function(StreamBadge2) {
|
||||
@ -4408,7 +4471,6 @@ var PrefKey;
|
||||
PrefKey2["STREAM_PREFERRED_LOCALE"] = "stream_preferred_locale";
|
||||
PrefKey2["STREAM_CODEC_PROFILE"] = "stream_codec_profile";
|
||||
PrefKey2["USER_AGENT_PROFILE"] = "user_agent_profile";
|
||||
PrefKey2["USER_AGENT_CUSTOM"] = "user_agent_custom";
|
||||
PrefKey2["STREAM_SIMPLIFY_MENU"] = "stream_simplify_menu";
|
||||
PrefKey2["STREAM_COMBINE_SOURCES"] = "stream_combine_sources";
|
||||
PrefKey2["STREAM_TOUCH_CONTROLLER"] = "stream_touch_controller";
|
||||
@ -4417,6 +4479,7 @@ var PrefKey;
|
||||
PrefKey2["STREAM_TOUCH_CONTROLLER_STYLE_STANDARD"] = "stream_touch_controller_style_standard";
|
||||
PrefKey2["STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM"] = "stream_touch_controller_style_custom";
|
||||
PrefKey2["STREAM_DISABLE_FEEDBACK_DIALOG"] = "stream_disable_feedback_dialog";
|
||||
PrefKey2["GAME_BAR_ENABLED"] = "game_bar_enabled";
|
||||
PrefKey2["LOCAL_CO_OP_ENABLED"] = "local_co_op_enabled";
|
||||
PrefKey2["CONTROLLER_ENABLE_SHORTCUTS"] = "controller_enable_shortcuts";
|
||||
PrefKey2["CONTROLLER_ENABLE_VIBRATION"] = "controller_enable_vibration";
|
||||
@ -4571,8 +4634,7 @@ class Preferences {
|
||||
}
|
||||
return options;
|
||||
})(),
|
||||
ready: () => {
|
||||
const setting = Preferences.SETTINGS[PrefKey.STREAM_CODEC_PROFILE];
|
||||
ready: (setting) => {
|
||||
const options = setting.options;
|
||||
const keys = Object.keys(options);
|
||||
if (keys.length <= 1) {
|
||||
@ -4613,8 +4675,7 @@ class Preferences {
|
||||
off: t("off")
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
ready: () => {
|
||||
const setting = Preferences.SETTINGS[PrefKey.STREAM_TOUCH_CONTROLLER];
|
||||
ready: (setting) => {
|
||||
if (setting.unsupported) {
|
||||
setting.default = "default";
|
||||
}
|
||||
@ -4670,6 +4731,10 @@ class Preferences {
|
||||
label: t("disable-post-stream-feedback-dialog"),
|
||||
default: false
|
||||
},
|
||||
[PrefKey.GAME_BAR_ENABLED]: {
|
||||
label: t("enable-game-bar"),
|
||||
default: true
|
||||
},
|
||||
[PrefKey.LOCAL_CO_OP_ENABLED]: {
|
||||
label: t("enable-local-co-op-support"),
|
||||
default: false,
|
||||
@ -4707,21 +4772,20 @@ class Preferences {
|
||||
label: t("enable-mkb"),
|
||||
default: false,
|
||||
unsupported: (() => {
|
||||
const userAgent = (window.navigator.orgUserAgent || window.navigator.userAgent || "").toLowerCase();
|
||||
return userAgent.match(/(android|iphone|ipad)/) ? t("browser-unsupported-feature") : false;
|
||||
const userAgent2 = (window.navigator.orgUserAgent || window.navigator.userAgent || "").toLowerCase();
|
||||
return userAgent2.match(/(android|iphone|ipad)/) ? t("browser-unsupported-feature") : false;
|
||||
})(),
|
||||
ready: () => {
|
||||
const pref = Preferences.SETTINGS[PrefKey.MKB_ENABLED];
|
||||
ready: (setting) => {
|
||||
let note;
|
||||
let url;
|
||||
if (pref.unsupported) {
|
||||
if (setting.unsupported) {
|
||||
note = t("browser-unsupported-feature");
|
||||
url = "https://github.com/redphx/better-xcloud/issues/206#issuecomment-1920475657";
|
||||
} else {
|
||||
note = t("mkb-disclaimer");
|
||||
url = "https://better-xcloud.github.io/mouse-and-keyboard/#disclaimer";
|
||||
}
|
||||
Preferences.SETTINGS[PrefKey.MKB_ENABLED].note = CE("a", {
|
||||
setting.note = CE("a", {
|
||||
href: url,
|
||||
target: "_blank"
|
||||
}, "⚠️ " + note);
|
||||
@ -4777,21 +4841,19 @@ class Preferences {
|
||||
},
|
||||
[PrefKey.USER_AGENT_PROFILE]: {
|
||||
label: t("user-agent-profile"),
|
||||
note: "⚠️ " + t("user-agent-note"),
|
||||
default: "default",
|
||||
options: {
|
||||
[UserAgentProfile.DEFAULT]: t("default"),
|
||||
[UserAgentProfile.EDGE_WINDOWS]: "Edge + Windows",
|
||||
[UserAgentProfile.SAFARI_MACOS]: "Safari + macOS",
|
||||
[UserAgentProfile.SMARTTV]: "Smart TV",
|
||||
[UserAgentProfile.WINDOWS_EDGE]: "Edge + Windows",
|
||||
[UserAgentProfile.MACOS_SAFARI]: "Safari + macOS",
|
||||
[UserAgentProfile.SMARTTV_GENERIC]: "Smart TV",
|
||||
[UserAgentProfile.SMARTTV_TIZEN]: "Samsung Smart TV",
|
||||
[UserAgentProfile.VR_OCULUS]: "Meta Quest VR",
|
||||
[UserAgentProfile.KIWI_V123]: "Kiwi Browser v123",
|
||||
[UserAgentProfile.ANDROID_KIWI_V123]: "Kiwi Browser v123",
|
||||
[UserAgentProfile.CUSTOM]: t("custom")
|
||||
}
|
||||
},
|
||||
[PrefKey.USER_AGENT_CUSTOM]: {
|
||||
default: ""
|
||||
},
|
||||
[PrefKey.VIDEO_CLARITY]: {
|
||||
type: SettingElementType.NUMBER_STEPPER,
|
||||
default: 0,
|
||||
@ -4941,7 +5003,7 @@ class Preferences {
|
||||
const savedPrefs = JSON.parse(savedPrefsStr);
|
||||
for (let settingId in Preferences.SETTINGS) {
|
||||
const setting = Preferences.SETTINGS[settingId];
|
||||
setting.ready && setting.ready.call(this);
|
||||
setting.ready && setting.ready.call(this, setting);
|
||||
if (setting.migrate && settingId in savedPrefs) {
|
||||
setting.migrate.call(this, savedPrefs, savedPrefs[settingId]);
|
||||
}
|
||||
@ -5016,7 +5078,6 @@ class Preferences {
|
||||
toElement(key, onChange, overrideParams = {}) {
|
||||
const setting = Preferences.SETTINGS[key];
|
||||
let currentValue = this.get(key);
|
||||
let $control;
|
||||
let type;
|
||||
if ("type" in setting) {
|
||||
type = setting.type;
|
||||
@ -5033,7 +5094,7 @@ class Preferences {
|
||||
if (params.disabled) {
|
||||
currentValue = Preferences.SETTINGS[key].default;
|
||||
}
|
||||
$control = SettingElement.render(type, key, setting, currentValue, (e, value) => {
|
||||
const $control = SettingElement.render(type, key, setting, currentValue, (e, value) => {
|
||||
this.set(key, value);
|
||||
onChange && onChange(e, value);
|
||||
}, params);
|
||||
@ -5530,7 +5591,7 @@ var cloneStreamHudButton = function($orgButton, label, svgIcon) {
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
if (STATES.hasTouchSupport) {
|
||||
if (STATES.browserHasTouchSupport) {
|
||||
$container.addEventListener("transitionstart", onTransitionStart);
|
||||
$container.addEventListener("transitionend", onTransitionEnd);
|
||||
}
|
||||
@ -6992,7 +7053,7 @@ function updateVideoPlayerCss() {
|
||||
videoCss += `filter: ${filters} !important;`;
|
||||
}
|
||||
if (getPref(PrefKey.SCREENSHOT_APPLY_FILTERS)) {
|
||||
STATES.currentStream.$screenshotCanvas.getContext("2d").filter = filters;
|
||||
Screenshot.updateCanvasFilters(filters);
|
||||
}
|
||||
const PREF_RATIO = getPref(PrefKey.VIDEO_RATIO);
|
||||
if (PREF_RATIO && PREF_RATIO !== "16:9") {
|
||||
@ -7032,7 +7093,8 @@ function setupStreamUi() {
|
||||
window.addEventListener("resize", updateVideoPlayerCss);
|
||||
setupQuickSettingsBar();
|
||||
StreamStats.render();
|
||||
GameBar.setup();
|
||||
Screenshot.setup();
|
||||
getPref(PrefKey.GAME_BAR_ENABLED) && GameBar.getInstance();
|
||||
}
|
||||
updateVideoPlayerCss();
|
||||
}
|
||||
@ -7526,12 +7588,12 @@ class XhomeInterceptor {
|
||||
const xboxTitleId = JSON.parse(opts.body).titleIds[0];
|
||||
STATES.currentStream.xboxTitleId = xboxTitleId;
|
||||
const inputConfigs = obj[0];
|
||||
let hasTouchSupport = inputConfigs.supportedTabs.length > 0;
|
||||
if (!hasTouchSupport) {
|
||||
let hasTouchSupport2 = inputConfigs.supportedTabs.length > 0;
|
||||
if (!hasTouchSupport2) {
|
||||
const supportedInputTypes = inputConfigs.supportedInputTypes;
|
||||
hasTouchSupport = supportedInputTypes.includes("NativeTouch");
|
||||
hasTouchSupport2 = supportedInputTypes.includes("NativeTouch");
|
||||
}
|
||||
if (hasTouchSupport) {
|
||||
if (hasTouchSupport2) {
|
||||
TouchController.disable();
|
||||
BxEvent.dispatch(window, BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED, {
|
||||
data: null
|
||||
@ -7861,15 +7923,15 @@ class TouchController {
|
||||
return;
|
||||
}
|
||||
let msg;
|
||||
let html15 = false;
|
||||
let html16 = false;
|
||||
if (layout.author) {
|
||||
const author = `<b>${escapeHtml(layout.author)}</b>`;
|
||||
msg = t("touch-control-layout-by", { name: author });
|
||||
html15 = true;
|
||||
html16 = true;
|
||||
} else {
|
||||
msg = t("touch-control-layout");
|
||||
}
|
||||
layoutChanged && Toast.show(msg, layout.name, { html: html15 });
|
||||
layoutChanged && Toast.show(msg, layout.name, { html: html16 });
|
||||
window.setTimeout(() => {
|
||||
window.BX_EXPOSED.touchLayoutManager.changeLayoutForScope({
|
||||
type: "showLayout",
|
||||
@ -8005,71 +8067,37 @@ class TouchControlAction extends BaseGameBarAction {
|
||||
|
||||
// src/modules/game-bar/game-bar.ts
|
||||
class GameBar {
|
||||
static #VISIBLE_DURATION = 2000;
|
||||
static #timeout;
|
||||
static #$gameBar;
|
||||
static #$container;
|
||||
static #$actions = [];
|
||||
static #beginHideTimeout() {
|
||||
GameBar.#clearHideTimeout();
|
||||
GameBar.#timeout = window.setTimeout(() => {
|
||||
GameBar.#timeout = null;
|
||||
GameBar.hideBar();
|
||||
}, GameBar.#VISIBLE_DURATION);
|
||||
}
|
||||
static #clearHideTimeout() {
|
||||
GameBar.#timeout && clearTimeout(GameBar.#timeout);
|
||||
GameBar.#timeout = null;
|
||||
}
|
||||
static enable() {
|
||||
GameBar.#$gameBar && GameBar.#$gameBar.classList.remove("bx-gone");
|
||||
}
|
||||
static disable() {
|
||||
GameBar.#$gameBar && GameBar.#$gameBar.classList.add("bx-gone");
|
||||
GameBar.hideBar();
|
||||
}
|
||||
static showBar() {
|
||||
if (!GameBar.#$container) {
|
||||
return;
|
||||
static instance;
|
||||
static getInstance() {
|
||||
if (!GameBar.instance) {
|
||||
GameBar.instance = new GameBar;
|
||||
}
|
||||
GameBar.#$container.classList.remove("bx-offscreen", "bx-hide");
|
||||
GameBar.#$container.classList.add("bx-show");
|
||||
GameBar.#beginHideTimeout();
|
||||
return GameBar.instance;
|
||||
}
|
||||
static hideBar() {
|
||||
if (!GameBar.#$container) {
|
||||
return;
|
||||
}
|
||||
GameBar.#$container.classList.remove("bx-show");
|
||||
GameBar.#$container.classList.add("bx-hide");
|
||||
}
|
||||
static reset() {
|
||||
for (const action of GameBar.#$actions) {
|
||||
action.reset();
|
||||
}
|
||||
}
|
||||
static setup() {
|
||||
static VISIBLE_DURATION = 2000;
|
||||
$gameBar;
|
||||
$container;
|
||||
timeout = null;
|
||||
actions = [];
|
||||
constructor() {
|
||||
let $container;
|
||||
const $gameBar = CE("div", { id: "bx-game-bar", class: "bx-gone" }, $container = CE("div", { class: "bx-game-bar-container bx-offscreen" }), createSvgIcon(BxIcon.CARET_RIGHT));
|
||||
GameBar.#$actions = [
|
||||
this.actions = [
|
||||
new ScreenshotAction,
|
||||
...STATES.hasTouchSupport && getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== "off" ? [new TouchControlAction] : []
|
||||
];
|
||||
for (const action of GameBar.#$actions) {
|
||||
for (const action of this.actions) {
|
||||
$container.appendChild(action.render());
|
||||
}
|
||||
$gameBar.addEventListener("click", (e) => {
|
||||
if (e.target === $gameBar) {
|
||||
if ($container.classList.contains("bx-show")) {
|
||||
GameBar.hideBar();
|
||||
} else {
|
||||
GameBar.showBar();
|
||||
}
|
||||
if (e.target !== $gameBar) {
|
||||
return;
|
||||
}
|
||||
$container.classList.contains("bx-show") ? this.hideBar() : this.showBar();
|
||||
});
|
||||
window.addEventListener(BxEvent.GAME_BAR_ACTION_ACTIVATED, GameBar.hideBar);
|
||||
$container.addEventListener("pointerover", GameBar.#clearHideTimeout);
|
||||
$container.addEventListener("pointerout", GameBar.#beginHideTimeout);
|
||||
window.addEventListener(BxEvent.GAME_BAR_ACTION_ACTIVATED, this.hideBar.bind(this));
|
||||
$container.addEventListener("pointerover", this.clearHideTimeout.bind(this));
|
||||
$container.addEventListener("pointerout", this.beginHideTimeout.bind(this));
|
||||
$container.addEventListener("transitionend", (e) => {
|
||||
const classList = $container.classList;
|
||||
if (classList.contains("bx-hide")) {
|
||||
@ -8078,8 +8106,46 @@ class GameBar {
|
||||
}
|
||||
});
|
||||
document.documentElement.appendChild($gameBar);
|
||||
GameBar.#$gameBar = $gameBar;
|
||||
GameBar.#$container = $container;
|
||||
this.$gameBar = $gameBar;
|
||||
this.$container = $container;
|
||||
}
|
||||
beginHideTimeout() {
|
||||
this.clearHideTimeout();
|
||||
this.timeout = window.setTimeout(() => {
|
||||
this.timeout = null;
|
||||
this.hideBar();
|
||||
}, GameBar.VISIBLE_DURATION);
|
||||
}
|
||||
clearHideTimeout() {
|
||||
this.timeout && clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
enable() {
|
||||
this.$gameBar && this.$gameBar.classList.remove("bx-gone");
|
||||
}
|
||||
disable() {
|
||||
this.hideBar();
|
||||
this.$gameBar && this.$gameBar.classList.add("bx-gone");
|
||||
}
|
||||
showBar() {
|
||||
if (!this.$container) {
|
||||
return;
|
||||
}
|
||||
this.$container.classList.remove("bx-offscreen", "bx-hide");
|
||||
this.$container.classList.add("bx-show");
|
||||
this.beginHideTimeout();
|
||||
}
|
||||
hideBar() {
|
||||
if (!this.$container) {
|
||||
return;
|
||||
}
|
||||
this.$container.classList.remove("bx-show");
|
||||
this.$container.classList.add("bx-hide");
|
||||
}
|
||||
reset() {
|
||||
for (const action of this.actions) {
|
||||
action.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8095,11 +8161,15 @@ var InputType;
|
||||
})(InputType || (InputType = {}));
|
||||
var BxExposed = {
|
||||
onPollingModeChanged: (mode) => {
|
||||
if (!STATES.isPlaying) {
|
||||
GameBar.disable();
|
||||
if (!getPref(PrefKey.GAME_BAR_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
mode !== "None" ? GameBar.disable() : GameBar.enable();
|
||||
const gameBar = GameBar.getInstance();
|
||||
if (!STATES.isPlaying) {
|
||||
gameBar.disable();
|
||||
return;
|
||||
}
|
||||
mode !== "None" ? gameBar.disable() : gameBar.enable();
|
||||
},
|
||||
getTitleInfo: () => STATES.currentStream.titleInfo,
|
||||
modifyTitleInfo: (titleInfo) => {
|
||||
@ -8627,6 +8697,7 @@ a.bx-button.bx-full-width {
|
||||
}
|
||||
.bx-toast.bx-hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.bx-toast-msg {
|
||||
font-size: 14px;
|
||||
@ -8885,6 +8956,7 @@ body[data-media-type=tv] .bx-stream-refresh-button {
|
||||
}
|
||||
#bx-game-bar .bx-game-bar-container.bx-hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
#bx-game-bar .bx-game-bar-container button {
|
||||
width: 60px;
|
||||
@ -9445,8 +9517,8 @@ function checkForUpdate() {
|
||||
});
|
||||
}
|
||||
function disablePwa() {
|
||||
const userAgent = (window.navigator.orgUserAgent || window.navigator.userAgent || "").toLowerCase();
|
||||
if (!userAgent) {
|
||||
const userAgent2 = (window.navigator.orgUserAgent || window.navigator.userAgent || "").toLowerCase();
|
||||
if (!userAgent2) {
|
||||
return;
|
||||
}
|
||||
if (UserAgent.isSafari(true)) {
|
||||
@ -10077,8 +10149,8 @@ function setupSettingsUi() {
|
||||
$updateAvailable.classList.remove("bx-gone");
|
||||
}
|
||||
if (!AppInterface) {
|
||||
const userAgent = UserAgent.getDefault().toLowerCase();
|
||||
if (userAgent.includes("android")) {
|
||||
const userAgent2 = UserAgent.getDefault().toLowerCase();
|
||||
if (userAgent2.includes("android")) {
|
||||
const $btn = createButton({
|
||||
label: "🔥 " + t("install-android"),
|
||||
style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE,
|
||||
@ -10140,14 +10212,17 @@ function setupSettingsUi() {
|
||||
class: "bx-settings-custom-user-agent"
|
||||
});
|
||||
$inpCustomUserAgent.addEventListener("change", (e) => {
|
||||
setPref(PrefKey.USER_AGENT_CUSTOM, e.target.value.trim());
|
||||
const profile = $control.value;
|
||||
const custom = e.target.value.trim();
|
||||
UserAgent.updateStorage(profile, custom);
|
||||
onChange(e);
|
||||
});
|
||||
$control = toPrefElement(PrefKey.USER_AGENT_PROFILE, (e) => {
|
||||
const value = e.target.value;
|
||||
let isCustom = value === UserAgentProfile.CUSTOM;
|
||||
let userAgent = UserAgent.get(value);
|
||||
$inpCustomUserAgent.value = userAgent;
|
||||
let userAgent2 = UserAgent.get(value);
|
||||
UserAgent.updateStorage(value);
|
||||
$inpCustomUserAgent.value = userAgent2;
|
||||
$inpCustomUserAgent.readOnly = !isCustom;
|
||||
$inpCustomUserAgent.disabled = !isCustom;
|
||||
onChange(e);
|
||||
@ -10249,10 +10324,11 @@ var SETTINGS_UI = {
|
||||
items: [
|
||||
PrefKey.STREAM_TARGET_RESOLUTION,
|
||||
PrefKey.STREAM_CODEC_PROFILE,
|
||||
PrefKey.GAME_FORTNITE_FORCE_CONSOLE,
|
||||
PrefKey.GAME_BAR_ENABLED,
|
||||
PrefKey.AUDIO_MIC_ON_PLAYING,
|
||||
PrefKey.STREAM_DISABLE_FEEDBACK_DIALOG,
|
||||
PrefKey.SCREENSHOT_APPLY_FILTERS,
|
||||
PrefKey.GAME_FORTNITE_FORCE_CONSOLE,
|
||||
PrefKey.AUDIO_ENABLE_VOLUME_CONTROL,
|
||||
PrefKey.STREAM_COMBINE_SOURCES
|
||||
]
|
||||
@ -10402,13 +10478,10 @@ function overridePreloadState() {
|
||||
return _state;
|
||||
},
|
||||
set: (state) => {
|
||||
const userAgent = UserAgent.spoof();
|
||||
if (userAgent) {
|
||||
try {
|
||||
state.appContext.requestInfo.userAgent = userAgent;
|
||||
} catch (e) {
|
||||
BxLogger.error(LOG_TAG5, e);
|
||||
}
|
||||
try {
|
||||
state.appContext.requestInfo.userAgent = window.navigator.userAgent;
|
||||
} catch (e) {
|
||||
BxLogger.error(LOG_TAG5, e);
|
||||
}
|
||||
if (STATES.hasTouchSupport) {
|
||||
try {
|
||||
@ -10688,11 +10761,13 @@ window.addEventListener(BxEvent.STREAM_PLAYING, (e) => {
|
||||
STATES.currentStream.$video = $video;
|
||||
STATES.isPlaying = true;
|
||||
injectStreamMenuButtons();
|
||||
GameBar.reset();
|
||||
GameBar.enable();
|
||||
GameBar.showBar();
|
||||
STATES.currentStream.$screenshotCanvas.width = $video.videoWidth;
|
||||
STATES.currentStream.$screenshotCanvas.height = $video.videoHeight;
|
||||
if (getPref(PrefKey.GAME_BAR_ENABLED)) {
|
||||
const gameBar = GameBar.getInstance();
|
||||
gameBar.reset();
|
||||
gameBar.enable();
|
||||
gameBar.showBar();
|
||||
}
|
||||
Screenshot.updateCanvasSize($video.videoWidth, $video.videoHeight);
|
||||
updateVideoPlayerCss();
|
||||
});
|
||||
window.addEventListener(BxEvent.STREAM_ERROR_PAGE, (e) => {
|
||||
@ -10713,6 +10788,6 @@ window.addEventListener(BxEvent.STREAM_STOPPED, (e) => {
|
||||
StreamStats.onStoppedPlaying();
|
||||
MouseCursorHider.stop();
|
||||
TouchController.reset();
|
||||
GameBar.disable();
|
||||
GameBar.getInstance().disable();
|
||||
});
|
||||
main();
|
||||
|
Loading…
x
Reference in New Issue
Block a user