mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-28 18:31:44 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
f71904c30b | |||
3a16187504 | |||
00ebb3f672 | |||
ebb4d3c141 | |||
902918d7fb | |||
b780e4e63b | |||
32889e0cf1 | |||
d8b9fcc951 | |||
c7734245ae | |||
35e7fdacb5 | |||
504f16b802 | |||
a3a7a57b51 |
2
dist/better-xcloud.meta.js
vendored
2
dist/better-xcloud.meta.js
vendored
@ -1,5 +1,5 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 4.7.0
|
||||
// @version 4.7.1
|
||||
// ==/UserScript==
|
||||
|
142
dist/better-xcloud.user.js
vendored
142
dist/better-xcloud.user.js
vendored
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 4.7.0
|
||||
// @version 4.7.1
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -104,23 +104,23 @@ class UserAgent {
|
||||
}
|
||||
|
||||
// src/utils/global.ts
|
||||
var SCRIPT_VERSION = "4.7.0";
|
||||
var SCRIPT_HOME = "https://github.com/redphx/better-xcloud";
|
||||
var SCRIPT_VERSION = "4.7.1";
|
||||
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 userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport;
|
||||
var STATES = {
|
||||
isPlaying: false,
|
||||
appContext: {},
|
||||
serverRegions: {},
|
||||
hasTouchSupport,
|
||||
userAgentHasTouchSupport,
|
||||
browserHasTouchSupport,
|
||||
currentStream: {},
|
||||
remotePlay: {}
|
||||
remotePlay: {},
|
||||
pointerServerPort: 9269
|
||||
};
|
||||
|
||||
// src/utils/bx-event.ts
|
||||
@ -171,8 +171,8 @@ var XcloudEvent;
|
||||
event[key] = data[key];
|
||||
}
|
||||
}
|
||||
AppInterface && AppInterface.onEvent(eventName);
|
||||
target.dispatchEvent(event);
|
||||
AppInterface && AppInterface.onEvent(eventName);
|
||||
}
|
||||
BxEvent.dispatch = dispatch;
|
||||
})(BxEvent || (BxEvent = {}));
|
||||
@ -189,7 +189,8 @@ var DEFAULT_FLAGS = {
|
||||
EnableXcloudLogging: false,
|
||||
SafariWorkaround: true,
|
||||
UseDevTouchLayout: false,
|
||||
ForceNativeMkbTitles: []
|
||||
ForceNativeMkbTitles: [],
|
||||
FeatureGates: null
|
||||
};
|
||||
var BX_FLAGS = Object.assign(DEFAULT_FLAGS, window.BX_FLAGS || {});
|
||||
try {
|
||||
@ -1590,7 +1591,7 @@ class Preferences {
|
||||
all: t("tc-all-games"),
|
||||
off: t("off")
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
ready: (setting) => {
|
||||
if (setting.unsupported) {
|
||||
setting.default = "default";
|
||||
@ -1600,7 +1601,7 @@ class Preferences {
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF]: {
|
||||
label: t("tc-auto-off"),
|
||||
default: false,
|
||||
unsupported: !STATES.hasTouchSupport
|
||||
unsupported: !STATES.userAgentHasTouchSupport
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_DEFAULT_OPACITY]: {
|
||||
type: SettingElementType.NUMBER_STEPPER,
|
||||
@ -1614,7 +1615,7 @@ class Preferences {
|
||||
ticks: 10,
|
||||
hideSlider: true
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport
|
||||
unsupported: !STATES.userAgentHasTouchSupport
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: {
|
||||
label: t("tc-standard-layout-style"),
|
||||
@ -1624,7 +1625,7 @@ class Preferences {
|
||||
white: t("tc-all-white"),
|
||||
muted: t("tc-muted-colors")
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport
|
||||
unsupported: !STATES.userAgentHasTouchSupport
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM]: {
|
||||
label: t("tc-custom-layout-style"),
|
||||
@ -1633,7 +1634,7 @@ class Preferences {
|
||||
default: t("default"),
|
||||
muted: t("tc-muted-colors")
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport
|
||||
unsupported: !STATES.userAgentHasTouchSupport
|
||||
},
|
||||
[PrefKey.STREAM_SIMPLIFY_MENU]: {
|
||||
label: t("simplify-stream-menu"),
|
||||
@ -1842,7 +1843,7 @@ class Preferences {
|
||||
},
|
||||
[PrefKey.UI_HOME_CONTEXT_MENU_DISABLED]: {
|
||||
label: t("disable-home-context-menu"),
|
||||
default: false
|
||||
default: STATES.browserHasTouchSupport
|
||||
},
|
||||
[PrefKey.BLOCK_SOCIAL_FEATURES]: {
|
||||
label: t("disable-social-features"),
|
||||
@ -2968,7 +2969,6 @@ var PointerAction;
|
||||
})(PointerAction || (PointerAction = {}));
|
||||
|
||||
class PointerClient {
|
||||
static #PORT = 9269;
|
||||
static instance;
|
||||
static getInstance() {
|
||||
if (!PointerClient.instance) {
|
||||
@ -2978,9 +2978,12 @@ class PointerClient {
|
||||
}
|
||||
#socket;
|
||||
#mkbHandler;
|
||||
start(mkbHandler) {
|
||||
start(port, mkbHandler) {
|
||||
if (!port) {
|
||||
throw new Error("PointerServer port is 0");
|
||||
}
|
||||
this.#mkbHandler = mkbHandler;
|
||||
this.#socket = new WebSocket(`ws://localhost:${PointerClient.#PORT}`);
|
||||
this.#socket = new WebSocket(`ws://localhost:${port}`);
|
||||
this.#socket.binaryType = "arraybuffer";
|
||||
this.#socket.addEventListener("open", (event) => {
|
||||
BxLogger.info(LOG_TAG, "connected");
|
||||
@ -3159,7 +3162,7 @@ class NativeMkbHandler extends MkbHandler {
|
||||
this.#inputSink = window.BX_EXPOSED.inputSink;
|
||||
this.#updateInputConfigurationAsync(false);
|
||||
try {
|
||||
this.#pointerClient.start(this);
|
||||
this.#pointerClient.start(STATES.pointerServerPort, this);
|
||||
} catch (e) {
|
||||
Toast.show("Cannot enable Mouse & Keyboard feature");
|
||||
}
|
||||
@ -3313,7 +3316,7 @@ class WebSocketMouseDataProvider extends MouseDataProvider {
|
||||
this.#pointerClient = PointerClient.getInstance();
|
||||
this.#connected = false;
|
||||
try {
|
||||
this.#pointerClient.start(this.mkbHandler);
|
||||
this.#pointerClient.start(STATES.pointerServerPort, this.mkbHandler);
|
||||
this.#connected = true;
|
||||
} catch (e) {
|
||||
Toast.show("Cannot enable Mouse & Keyboard feature");
|
||||
@ -3837,6 +3840,9 @@ class StreamUiShortcut {
|
||||
|
||||
// src/utils/utils.ts
|
||||
function checkForUpdate() {
|
||||
if (SCRIPT_VERSION.includes("beta")) {
|
||||
return;
|
||||
}
|
||||
const CHECK_INTERVAL_SECONDS = 7200;
|
||||
const currentVersion = getPref(PrefKey.CURRENT_VERSION);
|
||||
const lastCheck = getPref(PrefKey.LAST_UPDATE_CHECK);
|
||||
@ -4221,14 +4227,14 @@ var BxExposed = {
|
||||
modifyTitleInfo: (titleInfo) => {
|
||||
titleInfo = structuredClone(titleInfo);
|
||||
let supportedInputTypes = titleInfo.details.supportedInputTypes;
|
||||
if (BX_FLAGS.ForceNativeMkbTitles.includes(titleInfo.details.productId)) {
|
||||
if (BX_FLAGS.ForceNativeMkbTitles?.includes(titleInfo.details.productId)) {
|
||||
supportedInputTypes.push(InputType.MKB);
|
||||
}
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === "off") {
|
||||
supportedInputTypes = supportedInputTypes.filter((i) => i !== InputType.MKB);
|
||||
}
|
||||
titleInfo.details.hasMkbSupport = supportedInputTypes.includes(InputType.MKB);
|
||||
if (STATES.hasTouchSupport) {
|
||||
if (STATES.userAgentHasTouchSupport) {
|
||||
let touchControllerAvailability = getPref(PrefKey.STREAM_TOUCH_CONTROLLER);
|
||||
if (touchControllerAvailability !== "off" && getPref(PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF)) {
|
||||
const gamepads = window.navigator.getGamepads();
|
||||
@ -5333,7 +5339,7 @@ var setupStreamSettingsDialog = function() {
|
||||
}
|
||||
]
|
||||
},
|
||||
STATES.hasTouchSupport && {
|
||||
STATES.userAgentHasTouchSupport && {
|
||||
group: "touch-controller",
|
||||
label: t("touch-controller"),
|
||||
items: [
|
||||
@ -5899,6 +5905,20 @@ var GamePassCloudGallery;
|
||||
GamePassCloudGallery2["TOUCH"] = "9c86f07a-f3e8-45ad-82a0-a1f759597059";
|
||||
})(GamePassCloudGallery || (GamePassCloudGallery = {}));
|
||||
|
||||
// src/utils/feature-gates.ts
|
||||
var FeatureGates = {
|
||||
PwaPrompt: false
|
||||
};
|
||||
if (getPref(PrefKey.UI_HOME_CONTEXT_MENU_DISABLED)) {
|
||||
FeatureGates["EnableHomeContextMenu"] = false;
|
||||
}
|
||||
if (getPref(PrefKey.BLOCK_SOCIAL_FEATURES)) {
|
||||
FeatureGates["EnableGuideChatTab"] = false;
|
||||
}
|
||||
if (BX_FLAGS.FeatureGates) {
|
||||
FeatureGates = Object.assign(BX_FLAGS.FeatureGates, FeatureGates);
|
||||
}
|
||||
|
||||
// src/utils/network.ts
|
||||
var clearApplicationInsightsBuffers = function() {
|
||||
window.sessionStorage.removeItem("AI_buffer");
|
||||
@ -6042,12 +6062,8 @@ function interceptHttpRequests() {
|
||||
try {
|
||||
const response = await NATIVE_FETCH(request, init);
|
||||
const json = await response.json();
|
||||
const overrideTreatments = {};
|
||||
if (getPref(PrefKey.UI_HOME_CONTEXT_MENU_DISABLED)) {
|
||||
overrideTreatments["EnableHomeContextMenu"] = false;
|
||||
}
|
||||
for (const key in overrideTreatments) {
|
||||
json.exp.treatments[key] = overrideTreatments[key];
|
||||
for (const key in FeatureGates) {
|
||||
json.exp.treatments[key] = FeatureGates[key];
|
||||
}
|
||||
response.json = () => Promise.resolve(json);
|
||||
return response;
|
||||
@ -6055,7 +6071,7 @@ function interceptHttpRequests() {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
if (STATES.hasTouchSupport && url.includes("catalog.gamepass.com/sigls/")) {
|
||||
if (STATES.userAgentHasTouchSupport && url.includes("catalog.gamepass.com/sigls/")) {
|
||||
const response = await NATIVE_FETCH(request, init);
|
||||
const obj = await response.clone().json();
|
||||
if (url.includes(GamePassCloudGallery.ALL)) {
|
||||
@ -6149,12 +6165,12 @@ class XhomeInterceptor {
|
||||
const xboxTitleId = JSON.parse(opts.body).titleIds[0];
|
||||
STATES.currentStream.xboxTitleId = xboxTitleId;
|
||||
const inputConfigs = obj[0];
|
||||
let hasTouchSupport2 = inputConfigs.supportedTabs.length > 0;
|
||||
if (!hasTouchSupport2) {
|
||||
let hasTouchSupport = inputConfigs.supportedTabs.length > 0;
|
||||
if (!hasTouchSupport) {
|
||||
const supportedInputTypes = inputConfigs.supportedInputTypes;
|
||||
hasTouchSupport2 = supportedInputTypes.includes(InputType.NATIVE_TOUCH) || supportedInputTypes.includes(InputType.CUSTOM_TOUCH_OVERLAY);
|
||||
hasTouchSupport = supportedInputTypes.includes(InputType.NATIVE_TOUCH) || supportedInputTypes.includes(InputType.CUSTOM_TOUCH_OVERLAY);
|
||||
}
|
||||
if (hasTouchSupport2) {
|
||||
if (hasTouchSupport) {
|
||||
TouchController.disable();
|
||||
BxEvent.dispatch(window, BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED, {
|
||||
data: null
|
||||
@ -6340,7 +6356,7 @@ class XcloudInterceptor {
|
||||
overrides.inputConfiguration = overrides.inputConfiguration || {};
|
||||
overrides.inputConfiguration.enableVibration = true;
|
||||
let overrideMkb = null;
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === "on" || BX_FLAGS.ForceNativeMkbTitles.includes(STATES.currentStream.titleInfo.details.productId)) {
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === "on" || BX_FLAGS.ForceNativeMkbTitles?.includes(STATES.currentStream.titleInfo.details.productId)) {
|
||||
overrideMkb = true;
|
||||
}
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === "off") {
|
||||
@ -8023,10 +8039,9 @@ if (!!window.BX_REMOTE_PLAY_CONFIG) {
|
||||
return false;
|
||||
}
|
||||
const endIndex = str2.indexOf("},", index);
|
||||
const newSettings = [
|
||||
"PwaPrompt: false"
|
||||
];
|
||||
const newCode = newSettings.join(",");
|
||||
let newSettings = JSON.stringify(FeatureGates);
|
||||
newSettings = newSettings.substring(1, newSettings.length - 1);
|
||||
const newCode = newSettings;
|
||||
str2 = str2.substring(0, endIndex) + "," + newCode + str2.substring(endIndex);
|
||||
return str2;
|
||||
},
|
||||
@ -8356,7 +8371,7 @@ var PATCH_ORDERS = [
|
||||
"remotePlayKeepAlive",
|
||||
"remotePlayDirectConnectUrl",
|
||||
"remotePlayDisableAchievementToast",
|
||||
STATES.hasTouchSupport && "patchUpdateInputConfigurationAsync"
|
||||
STATES.userAgentHasTouchSupport && "patchUpdateInputConfigurationAsync"
|
||||
] : [],
|
||||
...BX_FLAGS.EnableXcloudLogging ? [
|
||||
"enableConsoleLogging",
|
||||
@ -8371,7 +8386,7 @@ var PLAYING_PATCH_ORDERS = [
|
||||
getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && !getPref(PrefKey.STREAM_COMBINE_SOURCES) && "patchAudioMediaStream",
|
||||
getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && getPref(PrefKey.STREAM_COMBINE_SOURCES) && "patchCombinedAudioVideoMediaStream",
|
||||
getPref(PrefKey.STREAM_DISABLE_FEEDBACK_DIALOG) && "skipFeedbackDialog",
|
||||
...STATES.hasTouchSupport ? [
|
||||
...STATES.userAgentHasTouchSupport ? [
|
||||
getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === "all" && "patchShowSensorControls",
|
||||
getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === "all" && "exposeTouchLayoutManager",
|
||||
(getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === "off" || getPref(PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF)) && "disableTakRenderer",
|
||||
@ -8560,7 +8575,7 @@ function setupSettingsUi() {
|
||||
let $updateAvailable;
|
||||
const $wrapper = CE("div", { class: "bx-settings-wrapper" }, CE("div", { class: "bx-settings-title-wrapper" }, CE("a", {
|
||||
class: "bx-settings-title",
|
||||
href: SCRIPT_HOME,
|
||||
href: "https://github.com/redphx/better-xcloud/releases",
|
||||
target: "_blank"
|
||||
}, "Better xCloud " + SCRIPT_VERSION), createButton({
|
||||
icon: BxIcon.QUESTION,
|
||||
@ -8570,11 +8585,11 @@ function setupSettingsUi() {
|
||||
})));
|
||||
$updateAvailable = CE("a", {
|
||||
class: "bx-settings-update bx-gone",
|
||||
href: "https://github.com/redphx/better-xcloud/releases",
|
||||
href: "https://github.com/redphx/better-xcloud/releases/latest",
|
||||
target: "_blank"
|
||||
});
|
||||
$wrapper.appendChild($updateAvailable);
|
||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
||||
if (!SCRIPT_VERSION.includes("beta") && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
||||
$updateAvailable.textContent = `🌟 Version ${PREF_LATEST_VERSION} available`;
|
||||
$updateAvailable.classList.remove("bx-gone");
|
||||
}
|
||||
@ -8811,8 +8826,8 @@ var SETTINGS_UI = {
|
||||
]
|
||||
},
|
||||
[t("touch-controller")]: {
|
||||
note: !STATES.hasTouchSupport ? "⚠️ " + t("device-unsupported-touch") : null,
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
note: !STATES.userAgentHasTouchSupport ? "⚠️ " + t("device-unsupported-touch") : null,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
items: [
|
||||
PrefKey.STREAM_TOUCH_CONTROLLER,
|
||||
PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF,
|
||||
@ -8884,7 +8899,7 @@ var injectSettingsButton = function($parent) {
|
||||
document.activeElement && document.activeElement.blur();
|
||||
}
|
||||
});
|
||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||
if (!SCRIPT_VERSION.includes("beta") && PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||
$settingsBtn.setAttribute("data-update-available", "true");
|
||||
}
|
||||
$headerFragment.appendChild($settingsBtn);
|
||||
@ -8950,7 +8965,7 @@ function overridePreloadState() {
|
||||
} catch (e) {
|
||||
BxLogger.error(LOG_TAG6, e);
|
||||
}
|
||||
if (STATES.hasTouchSupport) {
|
||||
if (STATES.userAgentHasTouchSupport) {
|
||||
try {
|
||||
const sigls = state.xcloud.sigls;
|
||||
if (GamePassCloudGallery.TOUCH in sigls) {
|
||||
@ -9050,10 +9065,10 @@ function patchVideoApi() {
|
||||
}
|
||||
return nativePlay.apply(this);
|
||||
}
|
||||
if (!!this.src) {
|
||||
return nativePlay.apply(this);
|
||||
const $parent = this.parentElement;
|
||||
if (!this.src && $parent.dataset.testid === "media-container") {
|
||||
this.addEventListener("playing", showFunc);
|
||||
}
|
||||
this.addEventListener("playing", showFunc);
|
||||
return nativePlay.apply(this);
|
||||
};
|
||||
}
|
||||
@ -9339,7 +9354,7 @@ class GameBar {
|
||||
const $gameBar = CE("div", { id: "bx-game-bar", class: "bx-gone", "data-position": position }, $container = CE("div", { class: "bx-game-bar-container bx-offscreen" }), createSvgIcon(position === "bottom-left" ? BxIcon.CARET_RIGHT : BxIcon.CARET_LEFT));
|
||||
this.actions = [
|
||||
new ScreenshotAction,
|
||||
...STATES.hasTouchSupport && getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== "off" ? [new TouchControlAction] : [],
|
||||
...STATES.userAgentHasTouchSupport && getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== "off" ? [new TouchControlAction] : [],
|
||||
new MicrophoneAction
|
||||
];
|
||||
if (position === "bottom-right") {
|
||||
@ -9513,14 +9528,16 @@ var observeRootDialog = function($root) {
|
||||
const $addedElm = mutation.addedNodes[0];
|
||||
if ($addedElm instanceof HTMLElement && $addedElm.className) {
|
||||
if ($addedElm.className.startsWith("NavigationAnimation") || $addedElm.className.startsWith("DialogRoutes") || $addedElm.className.startsWith("Dialog-module__container")) {
|
||||
const $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
||||
if ($selectedTab) {
|
||||
let $elm = $selectedTab;
|
||||
let index;
|
||||
for (index = 0;$elm = $elm?.previousElementSibling; index++)
|
||||
;
|
||||
if (index === 0) {
|
||||
BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, { where: GuideMenuTab.HOME });
|
||||
if (document.querySelector("#gamepass-dialog-root div[class*=GuideDialog]")) {
|
||||
const $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
||||
if ($selectedTab) {
|
||||
let $elm = $selectedTab;
|
||||
let index;
|
||||
for (index = 0;$elm = $elm?.previousElementSibling; index++)
|
||||
;
|
||||
if (index === 0) {
|
||||
BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, { where: GuideMenuTab.HOME });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9561,7 +9578,7 @@ var main = function() {
|
||||
AppInterface && patchPointerLockApi();
|
||||
getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && patchAudioContext();
|
||||
getPref(PrefKey.BLOCK_TRACKING) && patchMeControl();
|
||||
STATES.hasTouchSupport && TouchController.updateCustomList();
|
||||
STATES.userAgentHasTouchSupport && TouchController.updateCustomList();
|
||||
overridePreloadState();
|
||||
VibrationManager.initialSetup();
|
||||
BX_FLAGS.CheckForUpdate && checkForUpdate();
|
||||
@ -9583,7 +9600,10 @@ var main = function() {
|
||||
if (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === "all") {
|
||||
TouchController.setup();
|
||||
}
|
||||
getPref(PrefKey.MKB_ENABLED) && AppInterface && AppInterface.startPointerServer();
|
||||
if (getPref(PrefKey.MKB_ENABLED) && AppInterface) {
|
||||
STATES.pointerServerPort = AppInterface.startPointerServer() || 9269;
|
||||
BxLogger.info("startPointerServer", "Port", STATES.pointerServerPort.toString());
|
||||
}
|
||||
};
|
||||
if (window.location.pathname.includes("/auth/msa")) {
|
||||
window.addEventListener("load", (e) => {
|
||||
|
26
src/index.ts
26
src/index.ts
@ -219,15 +219,18 @@ function observeRootDialog($root: HTMLElement) {
|
||||
const $addedElm = mutation.addedNodes[0];
|
||||
if ($addedElm instanceof HTMLElement && $addedElm.className) {
|
||||
if ($addedElm.className.startsWith('NavigationAnimation') || $addedElm.className.startsWith('DialogRoutes') || $addedElm.className.startsWith('Dialog-module__container')) {
|
||||
// Find navigation bar
|
||||
const $selectedTab = $addedElm.querySelector('div[class^=NavigationMenu] button[aria-selected=true');
|
||||
if ($selectedTab) {
|
||||
let $elm: Element | null = $selectedTab;
|
||||
let index;
|
||||
for (index = 0; ($elm = $elm?.previousElementSibling); index++);
|
||||
// Make sure it's Guide dialog
|
||||
if (document.querySelector('#gamepass-dialog-root div[class*=GuideDialog]')) {
|
||||
// Find navigation bar
|
||||
const $selectedTab = $addedElm.querySelector('div[class^=NavigationMenu] button[aria-selected=true');
|
||||
if ($selectedTab) {
|
||||
let $elm: Element | null = $selectedTab;
|
||||
let index;
|
||||
for (index = 0; ($elm = $elm?.previousElementSibling); index++);
|
||||
|
||||
if (index === 0) {
|
||||
BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, {where: GuideMenuTab.HOME});
|
||||
if (index === 0) {
|
||||
BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, {where: GuideMenuTab.HOME});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,7 +280,7 @@ function main() {
|
||||
getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && patchAudioContext();
|
||||
getPref(PrefKey.BLOCK_TRACKING) && patchMeControl();
|
||||
|
||||
STATES.hasTouchSupport && TouchController.updateCustomList();
|
||||
STATES.userAgentHasTouchSupport && TouchController.updateCustomList();
|
||||
overridePreloadState();
|
||||
|
||||
VibrationManager.initialSetup();
|
||||
@ -314,7 +317,10 @@ function main() {
|
||||
}
|
||||
|
||||
// Start PointerProviderServer
|
||||
(getPref(PrefKey.MKB_ENABLED)) && AppInterface && AppInterface.startPointerServer();
|
||||
if (getPref(PrefKey.MKB_ENABLED) && AppInterface) {
|
||||
STATES.pointerServerPort = AppInterface.startPointerServer() || 9269;
|
||||
BxLogger.info('startPointerServer', 'Port', STATES.pointerServerPort.toString());
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
@ -41,7 +41,7 @@ export class GameBar {
|
||||
|
||||
this.actions = [
|
||||
new ScreenshotAction(),
|
||||
...(STATES.hasTouchSupport && (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== 'off') ? [new TouchControlAction()] : []),
|
||||
...(STATES.userAgentHasTouchSupport && (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== 'off') ? [new TouchControlAction()] : []),
|
||||
new MicrophoneAction(),
|
||||
];
|
||||
|
||||
|
@ -33,7 +33,7 @@ class WebSocketMouseDataProvider extends MouseDataProvider {
|
||||
this.#pointerClient = PointerClient.getInstance();
|
||||
this.#connected = false;
|
||||
try {
|
||||
this.#pointerClient.start(this.mkbHandler);
|
||||
this.#pointerClient.start(STATES.pointerServerPort, this.mkbHandler);
|
||||
this.#connected = true;
|
||||
} catch (e) {
|
||||
Toast.show('Cannot enable Mouse & Keyboard feature');
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Toast } from "@/utils/toast";
|
||||
import { PointerClient } from "./pointer-client";
|
||||
import { AppInterface } from "@/utils/global";
|
||||
import { AppInterface, STATES } from "@/utils/global";
|
||||
import { MkbHandler } from "./base-mkb-handler";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
@ -149,7 +149,7 @@ export class NativeMkbHandler extends MkbHandler {
|
||||
this.#updateInputConfigurationAsync(false);
|
||||
|
||||
try {
|
||||
this.#pointerClient.start(this);
|
||||
this.#pointerClient.start(STATES.pointerServerPort, this);
|
||||
} catch (e) {
|
||||
Toast.show('Cannot enable Mouse & Keyboard feature');
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ enum PointerAction {
|
||||
|
||||
|
||||
export class PointerClient {
|
||||
static #PORT = 9269;
|
||||
|
||||
private static instance: PointerClient;
|
||||
public static getInstance(): PointerClient {
|
||||
if (!PointerClient.instance) {
|
||||
@ -28,11 +26,15 @@ export class PointerClient {
|
||||
#socket: WebSocket | undefined | null;
|
||||
#mkbHandler: MkbHandler | undefined;
|
||||
|
||||
start(mkbHandler: MkbHandler) {
|
||||
start(port: number, mkbHandler: MkbHandler) {
|
||||
if (!port) {
|
||||
throw new Error('PointerServer port is 0');
|
||||
}
|
||||
|
||||
this.#mkbHandler = mkbHandler;
|
||||
|
||||
// Create WebSocket connection.
|
||||
this.#socket = new WebSocket(`ws://localhost:${PointerClient.#PORT}`);
|
||||
this.#socket = new WebSocket(`ws://localhost:${port}`);
|
||||
this.#socket.binaryType = 'arraybuffer';
|
||||
|
||||
// Connection opened
|
||||
|
@ -11,6 +11,7 @@ import codeLocalCoOpEnable from "./patches/local-co-op-enable.js" with { type: "
|
||||
import codeRemotePlayEnable from "./patches/remote-play-enable.js" with { type: "text" };
|
||||
import codeRemotePlayKeepAlive from "./patches/remote-play-keep-alive.js" with { type: "text" };
|
||||
import codeVibrationAdjust from "./patches/vibration-adjust.js" with { type: "text" };
|
||||
import { FeatureGates } from "@/utils/feature-gates.js";
|
||||
|
||||
type PatchArray = (keyof typeof PATCHES)[];
|
||||
|
||||
@ -228,12 +229,10 @@ if (!!window.BX_REMOTE_PLAY_CONFIG) {
|
||||
// Find the next "},"
|
||||
const endIndex = str.indexOf('},', index);
|
||||
|
||||
const newSettings = [
|
||||
// 'EnableStreamGate: false',
|
||||
'PwaPrompt: false',
|
||||
];
|
||||
let newSettings = JSON.stringify(FeatureGates);
|
||||
newSettings = newSettings.substring(1, newSettings.length - 1);
|
||||
|
||||
const newCode = newSettings.join(',');
|
||||
const newCode = newSettings;
|
||||
|
||||
str = str.substring(0, endIndex) + ',' + newCode + str.substring(endIndex);
|
||||
return str;
|
||||
@ -672,7 +671,7 @@ let PATCH_ORDERS: PatchArray = [
|
||||
'remotePlayKeepAlive',
|
||||
'remotePlayDirectConnectUrl',
|
||||
'remotePlayDisableAchievementToast',
|
||||
STATES.hasTouchSupport && 'patchUpdateInputConfigurationAsync',
|
||||
STATES.userAgentHasTouchSupport && 'patchUpdateInputConfigurationAsync',
|
||||
] : []),
|
||||
|
||||
...(BX_FLAGS.EnableXcloudLogging ? [
|
||||
@ -698,7 +697,7 @@ let PLAYING_PATCH_ORDERS: PatchArray = [
|
||||
// Skip feedback dialog
|
||||
getPref(PrefKey.STREAM_DISABLE_FEEDBACK_DIALOG) && 'skipFeedbackDialog',
|
||||
|
||||
...(STATES.hasTouchSupport ? [
|
||||
...(STATES.userAgentHasTouchSupport ? [
|
||||
getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === 'all' && 'patchShowSensorControls',
|
||||
getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === 'all' && 'exposeTouchLayoutManager',
|
||||
(getPref(PrefKey.STREAM_TOUCH_CONTROLLER) === 'off' || getPref(PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF)) && 'disableTakRenderer',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { STATES, AppInterface, SCRIPT_HOME, SCRIPT_VERSION } from "@utils/global";
|
||||
import { STATES, AppInterface, SCRIPT_VERSION } from "@utils/global";
|
||||
import { CE, createButton, ButtonStyle } from "@utils/html";
|
||||
import { BxIcon } from "@utils/bx-icon";
|
||||
import { getPreferredServerRegion } from "@utils/region";
|
||||
@ -62,8 +62,8 @@ const SETTINGS_UI = {
|
||||
},
|
||||
|
||||
[t('touch-controller')]: {
|
||||
note: !STATES.hasTouchSupport ? '⚠️ ' + t('device-unsupported-touch') : null,
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
note: !STATES.userAgentHasTouchSupport ? '⚠️ ' + t('device-unsupported-touch') : null,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
items: [
|
||||
PrefKey.STREAM_TOUCH_CONTROLLER,
|
||||
PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF,
|
||||
@ -130,7 +130,7 @@ export function setupSettingsUi() {
|
||||
CE<HTMLElement>('div', {'class': 'bx-settings-title-wrapper'},
|
||||
CE('a', {
|
||||
'class': 'bx-settings-title',
|
||||
'href': SCRIPT_HOME,
|
||||
'href': 'https://github.com/redphx/better-xcloud/releases',
|
||||
'target': '_blank',
|
||||
}, 'Better xCloud ' + SCRIPT_VERSION),
|
||||
createButton({
|
||||
@ -143,14 +143,14 @@ export function setupSettingsUi() {
|
||||
);
|
||||
$updateAvailable = CE('a', {
|
||||
'class': 'bx-settings-update bx-gone',
|
||||
'href': 'https://github.com/redphx/better-xcloud/releases',
|
||||
'href': 'https://github.com/redphx/better-xcloud/releases/latest',
|
||||
'target': '_blank',
|
||||
});
|
||||
|
||||
$wrapper.appendChild($updateAvailable);
|
||||
|
||||
// Show new version indicator
|
||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
||||
if (!SCRIPT_VERSION.includes('beta') && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
||||
$updateAvailable.textContent = `🌟 Version ${PREF_LATEST_VERSION} available`;
|
||||
$updateAvailable.classList.remove('bx-gone');
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ function injectSettingsButton($parent?: HTMLElement) {
|
||||
});
|
||||
|
||||
// Show new update status
|
||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||
if (!SCRIPT_VERSION.includes('beta') && PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||
$settingsBtn.setAttribute('data-update-available', 'true');
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ function setupStreamSettingsDialog() {
|
||||
],
|
||||
},
|
||||
|
||||
STATES.hasTouchSupport && {
|
||||
STATES.userAgentHasTouchSupport && {
|
||||
group: 'touch-controller',
|
||||
label: t('touch-controller'),
|
||||
items: [
|
||||
|
4
src/types/index.d.ts
vendored
4
src/types/index.d.ts
vendored
@ -28,7 +28,7 @@ type BxStates = {
|
||||
appContext: any | null;
|
||||
serverRegions: any;
|
||||
|
||||
hasTouchSupport: boolean;
|
||||
userAgentHasTouchSupport: boolean;
|
||||
browserHasTouchSupport: boolean;
|
||||
|
||||
currentStream: Partial<{
|
||||
@ -51,6 +51,8 @@ type BxStates = {
|
||||
serverId: string;
|
||||
};
|
||||
}>;
|
||||
|
||||
pointerServerPort: number;
|
||||
}
|
||||
|
||||
type DualEnum = {[index: string]: number} & {[index: number]: string};
|
||||
|
@ -66,8 +66,8 @@ export namespace BxEvent {
|
||||
}
|
||||
}
|
||||
|
||||
AppInterface && AppInterface.onEvent(eventName);
|
||||
target.dispatchEvent(event);
|
||||
AppInterface && AppInterface.onEvent(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ export const BxExposed = {
|
||||
|
||||
let supportedInputTypes = titleInfo.details.supportedInputTypes;
|
||||
|
||||
if (BX_FLAGS.ForceNativeMkbTitles.includes(titleInfo.details.productId)) {
|
||||
if (BX_FLAGS.ForceNativeMkbTitles?.includes(titleInfo.details.productId)) {
|
||||
supportedInputTypes.push(InputType.MKB);
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ export const BxExposed = {
|
||||
|
||||
titleInfo.details.hasMkbSupport = supportedInputTypes.includes(InputType.MKB);
|
||||
|
||||
if (STATES.hasTouchSupport) {
|
||||
if (STATES.userAgentHasTouchSupport) {
|
||||
let touchControllerAvailability = getPref(PrefKey.STREAM_TOUCH_CONTROLLER);
|
||||
|
||||
// Disable touch control when gamepad found
|
||||
|
@ -8,6 +8,7 @@ type BxFlags = Partial<{
|
||||
UseDevTouchLayout: boolean;
|
||||
|
||||
ForceNativeMkbTitles: string[];
|
||||
FeatureGates: {[key: string]: boolean} | null,
|
||||
}>
|
||||
|
||||
// Setup flags
|
||||
@ -21,9 +22,10 @@ const DEFAULT_FLAGS: BxFlags = {
|
||||
UseDevTouchLayout: false,
|
||||
|
||||
ForceNativeMkbTitles: [],
|
||||
FeatureGates: null,
|
||||
}
|
||||
|
||||
export const BX_FLAGS = Object.assign(DEFAULT_FLAGS, window.BX_FLAGS || {});
|
||||
export const BX_FLAGS: BxFlags = Object.assign(DEFAULT_FLAGS, window.BX_FLAGS || {});
|
||||
try {
|
||||
delete window.BX_FLAGS;
|
||||
} catch (e) {}
|
||||
|
20
src/utils/feature-gates.ts
Normal file
20
src/utils/feature-gates.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { BX_FLAGS } from "./bx-flags";
|
||||
import { getPref, PrefKey } from "./preferences";
|
||||
|
||||
export let FeatureGates: {[key: string]: boolean} = {
|
||||
'PwaPrompt': false,
|
||||
};
|
||||
|
||||
// Disable context menu in Home page
|
||||
if (getPref(PrefKey.UI_HOME_CONTEXT_MENU_DISABLED)) {
|
||||
FeatureGates['EnableHomeContextMenu'] = false;
|
||||
}
|
||||
|
||||
// Disable chat feature
|
||||
if (getPref(PrefKey.BLOCK_SOCIAL_FEATURES)) {
|
||||
FeatureGates['EnableGuideChatTab'] = false;
|
||||
}
|
||||
|
||||
if (BX_FLAGS.FeatureGates) {
|
||||
FeatureGates = Object.assign(BX_FLAGS.FeatureGates, FeatureGates);
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import { UserAgent } from "./user-agent";
|
||||
|
||||
export const SCRIPT_VERSION = Bun.env.SCRIPT_VERSION;
|
||||
export const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
|
||||
export const SCRIPT_VERSION = Bun.env.SCRIPT_VERSION!;
|
||||
|
||||
export const AppInterface = window.AppInterface;
|
||||
|
||||
@ -11,15 +10,17 @@ const userAgent = window.navigator.userAgent.toLowerCase();
|
||||
const isTv = userAgent.includes('smart-tv') || userAgent.includes('smarttv') || /\baft.*\b/.test(userAgent);
|
||||
const isVr = window.navigator.userAgent.includes('VR') && window.navigator.userAgent.includes('OculusBrowser');
|
||||
const browserHasTouchSupport = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
||||
const hasTouchSupport = !isTv && !isVr && browserHasTouchSupport;
|
||||
const userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport;
|
||||
|
||||
export const STATES: BxStates = {
|
||||
isPlaying: false,
|
||||
appContext: {},
|
||||
serverRegions: {},
|
||||
hasTouchSupport: hasTouchSupport,
|
||||
userAgentHasTouchSupport: userAgentHasTouchSupport,
|
||||
browserHasTouchSupport: browserHasTouchSupport,
|
||||
|
||||
currentStream: {},
|
||||
remotePlay: {},
|
||||
|
||||
pointerServerPort: 9269,
|
||||
};
|
||||
|
@ -35,12 +35,12 @@ export function patchVideoApi() {
|
||||
return nativePlay.apply(this);
|
||||
}
|
||||
|
||||
if (!!this.src) {
|
||||
return nativePlay.apply(this);
|
||||
const $parent = this.parentElement!!;
|
||||
// Video tag is stream player
|
||||
if (!this.src && $parent.dataset.testid === 'media-container') {
|
||||
this.addEventListener('playing', showFunc);
|
||||
}
|
||||
|
||||
this.addEventListener('playing', showFunc);
|
||||
|
||||
return nativePlay.apply(this);
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import { STATES } from "@utils/global";
|
||||
import { getPreferredServerRegion } from "@utils/region";
|
||||
import { GamePassCloudGallery } from "./gamepass-gallery";
|
||||
import { InputType } from "./bx-exposed";
|
||||
import { FeatureGates } from "./feature-gates";
|
||||
|
||||
enum RequestType {
|
||||
XCLOUD = 'xcloud',
|
||||
@ -440,7 +441,7 @@ class XcloudInterceptor {
|
||||
|
||||
let overrideMkb: boolean | null = null;
|
||||
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === 'on' || BX_FLAGS.ForceNativeMkbTitles.includes(STATES.currentStream.titleInfo!.details.productId)) {
|
||||
if (getPref(PrefKey.NATIVE_MKB_ENABLED) === 'on' || BX_FLAGS.ForceNativeMkbTitles?.includes(STATES.currentStream.titleInfo!.details.productId)) {
|
||||
overrideMkb = true;
|
||||
}
|
||||
|
||||
@ -578,14 +579,8 @@ export function interceptHttpRequests() {
|
||||
const response = await NATIVE_FETCH(request, init);
|
||||
const json = await response.json();
|
||||
|
||||
const overrideTreatments: {[key: string]: boolean} = {};
|
||||
|
||||
if (getPref(PrefKey.UI_HOME_CONTEXT_MENU_DISABLED)) {
|
||||
overrideTreatments['EnableHomeContextMenu'] = false;
|
||||
}
|
||||
|
||||
for (const key in overrideTreatments) {
|
||||
json.exp.treatments[key] = overrideTreatments[key]
|
||||
for (const key in FeatureGates) {
|
||||
json.exp.treatments[key] = FeatureGates[key]
|
||||
}
|
||||
|
||||
response.json = () => Promise.resolve(json);
|
||||
@ -596,7 +591,7 @@ export function interceptHttpRequests() {
|
||||
}
|
||||
|
||||
// Add list of games with custom layouts to the official list
|
||||
if (STATES.hasTouchSupport && url.includes('catalog.gamepass.com/sigls/')) {
|
||||
if (STATES.userAgentHasTouchSupport && url.includes('catalog.gamepass.com/sigls/')) {
|
||||
const response = await NATIVE_FETCH(request, init);
|
||||
const obj = await response.clone().json();
|
||||
|
||||
|
@ -263,7 +263,7 @@ export class Preferences {
|
||||
all: t('tc-all-games'),
|
||||
off: t('off'),
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
ready: (setting: PreferenceSetting) => {
|
||||
if (setting.unsupported) {
|
||||
setting.default = 'default';
|
||||
@ -273,7 +273,7 @@ export class Preferences {
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF]: {
|
||||
label: t('tc-auto-off'),
|
||||
default: false,
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_DEFAULT_OPACITY]: {
|
||||
type: SettingElementType.NUMBER_STEPPER,
|
||||
@ -287,7 +287,7 @@ export class Preferences {
|
||||
ticks: 10,
|
||||
hideSlider: true,
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD]: {
|
||||
label: t('tc-standard-layout-style'),
|
||||
@ -297,7 +297,7 @@ export class Preferences {
|
||||
white: t('tc-all-white'),
|
||||
muted: t('tc-muted-colors'),
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
},
|
||||
[PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM]: {
|
||||
label: t('tc-custom-layout-style'),
|
||||
@ -306,7 +306,7 @@ export class Preferences {
|
||||
default: t('default'),
|
||||
muted: t('tc-muted-colors'),
|
||||
},
|
||||
unsupported: !STATES.hasTouchSupport,
|
||||
unsupported: !STATES.userAgentHasTouchSupport,
|
||||
},
|
||||
|
||||
[PrefKey.STREAM_SIMPLIFY_MENU]: {
|
||||
@ -544,7 +544,7 @@ export class Preferences {
|
||||
|
||||
[PrefKey.UI_HOME_CONTEXT_MENU_DISABLED]: {
|
||||
label: t('disable-home-context-menu'),
|
||||
default: false,
|
||||
default: STATES.browserHasTouchSupport,
|
||||
},
|
||||
|
||||
[PrefKey.BLOCK_SOCIAL_FEATURES]: {
|
||||
|
@ -24,7 +24,7 @@ export function overridePreloadState() {
|
||||
}
|
||||
|
||||
// Add list of games with custom layouts to the official list
|
||||
if (STATES.hasTouchSupport) {
|
||||
if (STATES.userAgentHasTouchSupport) {
|
||||
try {
|
||||
const sigls = state.xcloud.sigls;
|
||||
if (GamePassCloudGallery.TOUCH in sigls) {
|
||||
|
@ -7,6 +7,11 @@ import { Translations } from "./translation";
|
||||
* Check for update
|
||||
*/
|
||||
export function checkForUpdate() {
|
||||
// Don't check update for beta version
|
||||
if (SCRIPT_VERSION.includes('beta')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const CHECK_INTERVAL_SECONDS = 2 * 3600; // check every 2 hours
|
||||
|
||||
const currentVersion = getPref(PrefKey.CURRENT_VERSION);
|
||||
|
Reference in New Issue
Block a user