mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-06 23:57:19 +02:00
Update dist
This commit is contained in:
parent
f6ee79770c
commit
438afe086a
686
dist/better-xcloud.user.js
vendored
686
dist/better-xcloud.user.js
vendored
@ -4797,7 +4797,7 @@ var BxExposed = {
|
|||||||
supportedInputTypes = supportedInputTypes.filter((i) => i !== InputType.CUSTOM_TOUCH_OVERLAY && i !== InputType.GENERIC_TOUCH);
|
supportedInputTypes = supportedInputTypes.filter((i) => i !== InputType.CUSTOM_TOUCH_OVERLAY && i !== InputType.GENERIC_TOUCH);
|
||||||
}
|
}
|
||||||
titleInfo.details.hasMkbSupport = supportedInputTypes.includes(InputType.MKB);
|
titleInfo.details.hasMkbSupport = supportedInputTypes.includes(InputType.MKB);
|
||||||
titleInfo.details.hasTouchSupport = supportedInputTypes.includes(InputType.NATIVE_TOUCH) && !supportedInputTypes.includes(InputType.CUSTOM_TOUCH_OVERLAY) && !supportedInputTypes.includes(InputType.GENERIC_TOUCH);
|
titleInfo.details.hasTouchSupport = supportedInputTypes.includes(InputType.NATIVE_TOUCH) || supportedInputTypes.includes(InputType.CUSTOM_TOUCH_OVERLAY) || supportedInputTypes.includes(InputType.GENERIC_TOUCH);
|
||||||
if (!titleInfo.details.hasTouchSupport && touchControllerAvailability === "all") {
|
if (!titleInfo.details.hasTouchSupport && touchControllerAvailability === "all") {
|
||||||
titleInfo.details.hasFakeTouchSupport = true;
|
titleInfo.details.hasFakeTouchSupport = true;
|
||||||
supportedInputTypes.push(InputType.GENERIC_TOUCH);
|
supportedInputTypes.push(InputType.GENERIC_TOUCH);
|
||||||
@ -9148,324 +9148,6 @@ class MouseCursorHider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/modules/ui/global-settings.ts
|
|
||||||
function setupSettingsUi() {
|
|
||||||
if (document.querySelector(".bx-settings-container")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const PREF_PREFERRED_REGION = getPreferredServerRegion();
|
|
||||||
const PREF_LATEST_VERSION = getPref(PrefKey.LATEST_VERSION);
|
|
||||||
let $reloadBtnWrapper;
|
|
||||||
const $container = CE("div", {
|
|
||||||
class: "bx-settings-container bx-gone"
|
|
||||||
});
|
|
||||||
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,
|
|
||||||
target: "_blank"
|
|
||||||
}, "Better xCloud " + SCRIPT_VERSION), createButton({ icon: BxIcon.QUESTION, label: t("help"), url: "https://better-xcloud.github.io/features/" })));
|
|
||||||
$updateAvailable = CE("a", {
|
|
||||||
class: "bx-settings-update bx-gone",
|
|
||||||
href: "https://github.com/redphx/better-xcloud/releases",
|
|
||||||
target: "_blank"
|
|
||||||
});
|
|
||||||
$wrapper.appendChild($updateAvailable);
|
|
||||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
|
||||||
$updateAvailable.textContent = `🌟 Version ${PREF_LATEST_VERSION} available`;
|
|
||||||
$updateAvailable.classList.remove("bx-gone");
|
|
||||||
}
|
|
||||||
if (!AppInterface) {
|
|
||||||
const userAgent = UserAgent.getDefault().toLowerCase();
|
|
||||||
if (userAgent.includes("android")) {
|
|
||||||
const $btn = createButton({
|
|
||||||
label: "🔥 " + t("install-android"),
|
|
||||||
style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE,
|
|
||||||
url: "https://better-xcloud.github.io/android"
|
|
||||||
});
|
|
||||||
$wrapper.appendChild($btn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onChange = (e) => {
|
|
||||||
if (!$reloadBtnWrapper) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$reloadBtnWrapper.classList.remove("bx-gone");
|
|
||||||
if (e.target.id === "bx_setting_" + PrefKey.BETTER_XCLOUD_LOCALE) {
|
|
||||||
refreshCurrentLocale();
|
|
||||||
const $btn = $reloadBtnWrapper.firstElementChild;
|
|
||||||
$btn.textContent = t("settings-reloading");
|
|
||||||
$btn.click();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (let groupLabel in SETTINGS_UI) {
|
|
||||||
const $group = CE("span", { class: "bx-settings-group-label" }, groupLabel);
|
|
||||||
if (SETTINGS_UI[groupLabel].note) {
|
|
||||||
const $note = CE("b", {}, SETTINGS_UI[groupLabel].note);
|
|
||||||
$group.appendChild($note);
|
|
||||||
}
|
|
||||||
$wrapper.appendChild($group);
|
|
||||||
if (SETTINGS_UI[groupLabel].unsupported) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const settingItems = SETTINGS_UI[groupLabel].items;
|
|
||||||
for (let settingId of settingItems) {
|
|
||||||
if (!settingId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const setting = Preferences.SETTINGS[settingId];
|
|
||||||
if (!setting) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let settingLabel = setting.label;
|
|
||||||
let settingNote = setting.note || "";
|
|
||||||
if (setting.experimental) {
|
|
||||||
settingLabel = "🧪 " + settingLabel;
|
|
||||||
if (!settingNote) {
|
|
||||||
settingNote = t("experimental");
|
|
||||||
} else {
|
|
||||||
settingNote = `${t("experimental")}: ${settingNote}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let $control;
|
|
||||||
let $inpCustomUserAgent;
|
|
||||||
let labelAttrs = {};
|
|
||||||
if (settingId === PrefKey.USER_AGENT_PROFILE) {
|
|
||||||
let defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent;
|
|
||||||
$inpCustomUserAgent = CE("input", {
|
|
||||||
type: "text",
|
|
||||||
placeholder: defaultUserAgent,
|
|
||||||
class: "bx-settings-custom-user-agent"
|
|
||||||
});
|
|
||||||
$inpCustomUserAgent.addEventListener("change", (e) => {
|
|
||||||
setPref(PrefKey.USER_AGENT_CUSTOM, e.target.value.trim());
|
|
||||||
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;
|
|
||||||
$inpCustomUserAgent.readOnly = !isCustom;
|
|
||||||
$inpCustomUserAgent.disabled = !isCustom;
|
|
||||||
onChange(e);
|
|
||||||
});
|
|
||||||
} else if (settingId === PrefKey.SERVER_REGION) {
|
|
||||||
let selectedValue;
|
|
||||||
$control = CE("select", { id: `bx_setting_${settingId}` });
|
|
||||||
$control.name = $control.id;
|
|
||||||
$control.addEventListener("change", (e) => {
|
|
||||||
setPref(settingId, e.target.value);
|
|
||||||
onChange(e);
|
|
||||||
});
|
|
||||||
selectedValue = PREF_PREFERRED_REGION;
|
|
||||||
setting.options = {};
|
|
||||||
for (let regionName in STATES.serverRegions) {
|
|
||||||
const region4 = STATES.serverRegions[regionName];
|
|
||||||
let value = regionName;
|
|
||||||
let label = `${region4.shortName} - ${regionName}`;
|
|
||||||
if (region4.isDefault) {
|
|
||||||
label += ` (${t("default")})`;
|
|
||||||
value = "default";
|
|
||||||
if (selectedValue === regionName) {
|
|
||||||
selectedValue = "default";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setting.options[value] = label;
|
|
||||||
}
|
|
||||||
for (let value in setting.options) {
|
|
||||||
const label = setting.options[value];
|
|
||||||
const $option = CE("option", { value }, label);
|
|
||||||
$control.appendChild($option);
|
|
||||||
}
|
|
||||||
$control.value = selectedValue;
|
|
||||||
} else {
|
|
||||||
if (settingId === PrefKey.BETTER_XCLOUD_LOCALE) {
|
|
||||||
$control = toPrefElement(settingId, (e) => {
|
|
||||||
localStorage.setItem("better_xcloud_locale", e.target.value);
|
|
||||||
onChange(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$control = toPrefElement(settingId, onChange);
|
|
||||||
}
|
|
||||||
labelAttrs = { for: $control.id, tabindex: 0 };
|
|
||||||
}
|
|
||||||
if (setting.unsupported) {
|
|
||||||
$control.disabled = true;
|
|
||||||
}
|
|
||||||
const $label = CE("label", labelAttrs, settingLabel);
|
|
||||||
if (settingNote) {
|
|
||||||
$label.appendChild(CE("b", {}, settingNote));
|
|
||||||
}
|
|
||||||
const $elm = CE("div", { class: "bx-settings-row" }, $label, $control);
|
|
||||||
$wrapper.appendChild($elm);
|
|
||||||
if (settingId === PrefKey.USER_AGENT_PROFILE) {
|
|
||||||
$wrapper.appendChild($inpCustomUserAgent);
|
|
||||||
$control.dispatchEvent(new Event("change"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const $reloadBtn = createButton({
|
|
||||||
label: t("settings-reload"),
|
|
||||||
style: ButtonStyle.DANGER | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH,
|
|
||||||
onClick: (e) => {
|
|
||||||
window.location.reload();
|
|
||||||
$reloadBtn.disabled = true;
|
|
||||||
$reloadBtn.textContent = t("settings-reloading");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$reloadBtn.setAttribute("tabindex", "0");
|
|
||||||
$reloadBtnWrapper = CE("div", { class: "bx-settings-reload-button-wrapper bx-gone" }, $reloadBtn);
|
|
||||||
$wrapper.appendChild($reloadBtnWrapper);
|
|
||||||
const $donationLink = CE("a", { class: "bx-donation-link", href: "https://ko-fi.com/redphx", target: "_blank" }, `❤️ ${t("support-better-xcloud")}`);
|
|
||||||
$wrapper.appendChild($donationLink);
|
|
||||||
try {
|
|
||||||
const appVersion = document.querySelector("meta[name=gamepass-app-version]").content;
|
|
||||||
const appDate = new Date(document.querySelector("meta[name=gamepass-app-date]").content).toISOString().substring(0, 10);
|
|
||||||
$wrapper.appendChild(CE("div", { class: "bx-settings-app-version" }, `xCloud website version ${appVersion} (${appDate})`));
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
$container.appendChild($wrapper);
|
|
||||||
const $pageContent = document.getElementById("PageContent");
|
|
||||||
$pageContent?.parentNode?.insertBefore($container, $pageContent);
|
|
||||||
}
|
|
||||||
var SETTINGS_UI = {
|
|
||||||
"Better xCloud": {
|
|
||||||
items: [
|
|
||||||
PrefKey.BETTER_XCLOUD_LOCALE,
|
|
||||||
PrefKey.REMOTE_PLAY_ENABLED
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("server")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.SERVER_REGION,
|
|
||||||
PrefKey.STREAM_PREFERRED_LOCALE,
|
|
||||||
PrefKey.PREFER_IPV6_SERVER
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("stream")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.STREAM_TARGET_RESOLUTION,
|
|
||||||
PrefKey.STREAM_CODEC_PROFILE,
|
|
||||||
PrefKey.GAME_FORTNITE_FORCE_CONSOLE,
|
|
||||||
PrefKey.AUDIO_MIC_ON_PLAYING,
|
|
||||||
PrefKey.STREAM_DISABLE_FEEDBACK_DIALOG,
|
|
||||||
PrefKey.SCREENSHOT_BUTTON_POSITION,
|
|
||||||
PrefKey.SCREENSHOT_APPLY_FILTERS,
|
|
||||||
PrefKey.AUDIO_ENABLE_VOLUME_CONTROL,
|
|
||||||
PrefKey.STREAM_COMBINE_SOURCES
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("local-co-op")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.LOCAL_CO_OP_ENABLED
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("mouse-and-keyboard")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.MKB_ENABLED,
|
|
||||||
PrefKey.MKB_HIDE_IDLE_CURSOR
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("touch-controller")]: {
|
|
||||||
note: !STATES.hasTouchSupport ? "⚠️ " + t("device-unsupported-touch") : null,
|
|
||||||
unsupported: !STATES.hasTouchSupport,
|
|
||||||
items: [
|
|
||||||
PrefKey.STREAM_TOUCH_CONTROLLER,
|
|
||||||
PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF,
|
|
||||||
PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD,
|
|
||||||
PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("loading-screen")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.UI_LOADING_SCREEN_GAME_ART,
|
|
||||||
PrefKey.UI_LOADING_SCREEN_WAIT_TIME,
|
|
||||||
PrefKey.UI_LOADING_SCREEN_ROCKET
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("ui")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.UI_LAYOUT,
|
|
||||||
PrefKey.STREAM_SIMPLIFY_MENU,
|
|
||||||
PrefKey.SKIP_SPLASH_VIDEO,
|
|
||||||
!AppInterface && PrefKey.UI_SCROLLBAR_HIDE,
|
|
||||||
PrefKey.HIDE_DOTS_ICON,
|
|
||||||
PrefKey.REDUCE_ANIMATIONS
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("other")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.BLOCK_SOCIAL_FEATURES,
|
|
||||||
PrefKey.BLOCK_TRACKING
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[t("advanced")]: {
|
|
||||||
items: [
|
|
||||||
PrefKey.USER_AGENT_PROFILE
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// src/modules/ui/header.ts
|
|
||||||
var injectSettingsButton = function($parent) {
|
|
||||||
if (!$parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const PREF_PREFERRED_REGION = getPreferredServerRegion(true);
|
|
||||||
const PREF_LATEST_VERSION = getPref(PrefKey.LATEST_VERSION);
|
|
||||||
const $headerFragment = document.createDocumentFragment();
|
|
||||||
if (getPref(PrefKey.REMOTE_PLAY_ENABLED)) {
|
|
||||||
const $remotePlayBtn = createButton({
|
|
||||||
classes: ["bx-header-remote-play-button"],
|
|
||||||
icon: BxIcon.REMOTE_PLAY,
|
|
||||||
title: t("remote-play"),
|
|
||||||
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
|
||||||
onClick: (e) => {
|
|
||||||
RemotePlay.togglePopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$headerFragment.appendChild($remotePlayBtn);
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
|
||||||
$settingsBtn.setAttribute("data-update-available", "true");
|
|
||||||
}
|
|
||||||
$headerFragment.appendChild($settingsBtn);
|
|
||||||
$parent.appendChild($headerFragment);
|
|
||||||
};
|
|
||||||
function checkHeader() {
|
|
||||||
const $button = document.querySelector(".bx-header-settings-button");
|
|
||||||
if (!$button) {
|
|
||||||
const $rightHeader = document.querySelector("#PageContent div[class*=EdgewaterHeader-module__rightSectionSpacing]");
|
|
||||||
injectSettingsButton($rightHeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function watchHeader() {
|
|
||||||
const $header = document.querySelector("#PageContent header");
|
|
||||||
if (!$header) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let timeout;
|
|
||||||
const observer = new MutationObserver((mutationList) => {
|
|
||||||
timeout && clearTimeout(timeout);
|
|
||||||
timeout = window.setTimeout(checkHeader, 2000);
|
|
||||||
});
|
|
||||||
observer.observe($header, { subtree: true, childList: true });
|
|
||||||
checkHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/utils/utils.ts
|
// src/utils/utils.ts
|
||||||
function checkForUpdate() {
|
function checkForUpdate() {
|
||||||
const CHECK_INTERVAL_SECONDS = 7200;
|
const CHECK_INTERVAL_SECONDS = 7200;
|
||||||
@ -9920,33 +9602,33 @@ class Patcher {
|
|||||||
return nativeBind.apply(newFunc, arguments);
|
return nativeBind.apply(newFunc, arguments);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
static length() {
|
|
||||||
return PATCH_ORDERS.length;
|
|
||||||
}
|
|
||||||
static patch(item) {
|
static patch(item) {
|
||||||
let patchesToCheck;
|
let patchesToCheck;
|
||||||
let appliedPatches;
|
let appliedPatches;
|
||||||
const caches = {};
|
const patchesMap = {};
|
||||||
for (let id in item[1]) {
|
for (let id in item[1]) {
|
||||||
appliedPatches = [];
|
appliedPatches = [];
|
||||||
const cachedPatches = PatcherCache.getPatches(id);
|
const cachedPatches = PatcherCache.getPatches(id);
|
||||||
if (cachedPatches) {
|
if (cachedPatches) {
|
||||||
patchesToCheck = cachedPatches;
|
patchesToCheck = cachedPatches.slice(0);
|
||||||
patchesToCheck.push(...PATCH_ORDERS);
|
patchesToCheck.push(...PATCH_ORDERS);
|
||||||
} else {
|
} else {
|
||||||
patchesToCheck = PATCH_ORDERS;
|
patchesToCheck = PATCH_ORDERS.slice(0);
|
||||||
}
|
}
|
||||||
if (!patchesToCheck.length) {
|
if (!patchesToCheck.length) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const func = item[1][id];
|
const func = item[1][id];
|
||||||
let str = func.toString();
|
let str = func.toString();
|
||||||
for (let groupIndex = 0;groupIndex < patchesToCheck.length; groupIndex++) {
|
let modified = false;
|
||||||
const patchName = patchesToCheck[groupIndex];
|
for (let patchIndex = 0;patchIndex < patchesToCheck.length; patchIndex++) {
|
||||||
let modified = false;
|
const patchName = patchesToCheck[patchIndex];
|
||||||
if (appliedPatches.indexOf(patchName) > -1) {
|
if (appliedPatches.indexOf(patchName) > -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!PATCHES[patchName]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const patchedStr = PATCHES[patchName].call(null, str);
|
const patchedStr = PATCHES[patchName].call(null, str);
|
||||||
if (!patchedStr) {
|
if (!patchedStr) {
|
||||||
continue;
|
continue;
|
||||||
@ -9955,19 +9637,19 @@ class Patcher {
|
|||||||
str = patchedStr;
|
str = patchedStr;
|
||||||
BxLogger.info(LOG_TAG4, `Applied "${patchName}" patch`);
|
BxLogger.info(LOG_TAG4, `Applied "${patchName}" patch`);
|
||||||
appliedPatches.push(patchName);
|
appliedPatches.push(patchName);
|
||||||
patchesToCheck.splice(groupIndex, 1);
|
patchesToCheck.splice(patchIndex, 1);
|
||||||
groupIndex--;
|
patchIndex--;
|
||||||
PATCH_ORDERS = PATCH_ORDERS.filter((item2) => item2 != patchName);
|
PATCH_ORDERS = PATCH_ORDERS.filter((item2) => item2 != patchName);
|
||||||
if (modified) {
|
}
|
||||||
item[1][id] = eval(str);
|
if (modified) {
|
||||||
}
|
item[1][id] = eval(str);
|
||||||
}
|
}
|
||||||
if (appliedPatches.length) {
|
if (appliedPatches.length) {
|
||||||
caches[id] = appliedPatches;
|
patchesMap[id] = appliedPatches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Object.keys(caches).length) {
|
if (Object.keys(patchesMap).length) {
|
||||||
PatcherCache.saveToCache(caches);
|
PatcherCache.saveToCache(patchesMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static init() {
|
static init() {
|
||||||
@ -9986,13 +9668,18 @@ class PatcherCache {
|
|||||||
const sig = hashCode(scriptVersion + webVersion + patches);
|
const sig = hashCode(scriptVersion + webVersion + patches);
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
static clear() {
|
||||||
|
window.localStorage.removeItem(PatcherCache.#KEY_CACHE);
|
||||||
|
PatcherCache.#CACHE = {};
|
||||||
|
}
|
||||||
static checkSignature() {
|
static checkSignature() {
|
||||||
const storedSig = window.localStorage.getItem(PatcherCache.#KEY_SIGNATURE) || 0;
|
const storedSig = window.localStorage.getItem(PatcherCache.#KEY_SIGNATURE) || 0;
|
||||||
const currentSig = PatcherCache.#getSignature();
|
const currentSig = PatcherCache.#getSignature();
|
||||||
if (currentSig !== parseInt(storedSig)) {
|
if (currentSig !== parseInt(storedSig)) {
|
||||||
BxLogger.warning(LOG_TAG4, "Signature changed");
|
BxLogger.warning(LOG_TAG4, "Signature changed");
|
||||||
window.localStorage.setItem(PatcherCache.#KEY_CACHE, "{}");
|
|
||||||
window.localStorage.setItem(PatcherCache.#KEY_SIGNATURE, currentSig.toString());
|
window.localStorage.setItem(PatcherCache.#KEY_SIGNATURE, currentSig.toString());
|
||||||
|
PatcherCache.clear();
|
||||||
|
window.location.reload(true);
|
||||||
} else {
|
} else {
|
||||||
BxLogger.info(LOG_TAG4, "Signature unchanged");
|
BxLogger.info(LOG_TAG4, "Signature unchanged");
|
||||||
}
|
}
|
||||||
@ -10018,9 +9705,9 @@ class PatcherCache {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
PatcherCache.#CACHE[id2] = patchNames;
|
PatcherCache.#CACHE[id2] = patchNames;
|
||||||
} else {
|
} else {
|
||||||
for (const patchName2 of patchNames) {
|
for (const patchName of patchNames) {
|
||||||
if (!data.includes(patchName2)) {
|
if (!data.includes(patchName)) {
|
||||||
data.push(patchName2);
|
data.push(patchName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10048,6 +9735,325 @@ document.addEventListener("readystatechange", (e) => {
|
|||||||
});
|
});
|
||||||
PatcherCache.init();
|
PatcherCache.init();
|
||||||
|
|
||||||
|
// src/modules/ui/global-settings.ts
|
||||||
|
function setupSettingsUi() {
|
||||||
|
if (document.querySelector(".bx-settings-container")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const PREF_PREFERRED_REGION = getPreferredServerRegion();
|
||||||
|
const PREF_LATEST_VERSION = getPref(PrefKey.LATEST_VERSION);
|
||||||
|
let $reloadBtnWrapper;
|
||||||
|
const $container = CE("div", {
|
||||||
|
class: "bx-settings-container bx-gone"
|
||||||
|
});
|
||||||
|
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,
|
||||||
|
target: "_blank"
|
||||||
|
}, "Better xCloud " + SCRIPT_VERSION), createButton({ icon: BxIcon.QUESTION, label: t("help"), url: "https://better-xcloud.github.io/features/" })));
|
||||||
|
$updateAvailable = CE("a", {
|
||||||
|
class: "bx-settings-update bx-gone",
|
||||||
|
href: "https://github.com/redphx/better-xcloud/releases",
|
||||||
|
target: "_blank"
|
||||||
|
});
|
||||||
|
$wrapper.appendChild($updateAvailable);
|
||||||
|
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
|
||||||
|
$updateAvailable.textContent = `🌟 Version ${PREF_LATEST_VERSION} available`;
|
||||||
|
$updateAvailable.classList.remove("bx-gone");
|
||||||
|
}
|
||||||
|
if (!AppInterface) {
|
||||||
|
const userAgent = UserAgent.getDefault().toLowerCase();
|
||||||
|
if (userAgent.includes("android")) {
|
||||||
|
const $btn = createButton({
|
||||||
|
label: "🔥 " + t("install-android"),
|
||||||
|
style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE,
|
||||||
|
url: "https://better-xcloud.github.io/android"
|
||||||
|
});
|
||||||
|
$wrapper.appendChild($btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onChange = (e) => {
|
||||||
|
if (!$reloadBtnWrapper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$reloadBtnWrapper.classList.remove("bx-gone");
|
||||||
|
PatcherCache.clear();
|
||||||
|
if (e.target.id === "bx_setting_" + PrefKey.BETTER_XCLOUD_LOCALE) {
|
||||||
|
refreshCurrentLocale();
|
||||||
|
const $btn = $reloadBtnWrapper.firstElementChild;
|
||||||
|
$btn.textContent = t("settings-reloading");
|
||||||
|
$btn.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (let groupLabel in SETTINGS_UI) {
|
||||||
|
const $group = CE("span", { class: "bx-settings-group-label" }, groupLabel);
|
||||||
|
if (SETTINGS_UI[groupLabel].note) {
|
||||||
|
const $note = CE("b", {}, SETTINGS_UI[groupLabel].note);
|
||||||
|
$group.appendChild($note);
|
||||||
|
}
|
||||||
|
$wrapper.appendChild($group);
|
||||||
|
if (SETTINGS_UI[groupLabel].unsupported) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const settingItems = SETTINGS_UI[groupLabel].items;
|
||||||
|
for (let settingId of settingItems) {
|
||||||
|
if (!settingId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const setting = Preferences.SETTINGS[settingId];
|
||||||
|
if (!setting) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let settingLabel = setting.label;
|
||||||
|
let settingNote = setting.note || "";
|
||||||
|
if (setting.experimental) {
|
||||||
|
settingLabel = "🧪 " + settingLabel;
|
||||||
|
if (!settingNote) {
|
||||||
|
settingNote = t("experimental");
|
||||||
|
} else {
|
||||||
|
settingNote = `${t("experimental")}: ${settingNote}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let $control;
|
||||||
|
let $inpCustomUserAgent;
|
||||||
|
let labelAttrs = {};
|
||||||
|
if (settingId === PrefKey.USER_AGENT_PROFILE) {
|
||||||
|
let defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent;
|
||||||
|
$inpCustomUserAgent = CE("input", {
|
||||||
|
type: "text",
|
||||||
|
placeholder: defaultUserAgent,
|
||||||
|
class: "bx-settings-custom-user-agent"
|
||||||
|
});
|
||||||
|
$inpCustomUserAgent.addEventListener("change", (e) => {
|
||||||
|
setPref(PrefKey.USER_AGENT_CUSTOM, e.target.value.trim());
|
||||||
|
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;
|
||||||
|
$inpCustomUserAgent.readOnly = !isCustom;
|
||||||
|
$inpCustomUserAgent.disabled = !isCustom;
|
||||||
|
onChange(e);
|
||||||
|
});
|
||||||
|
} else if (settingId === PrefKey.SERVER_REGION) {
|
||||||
|
let selectedValue;
|
||||||
|
$control = CE("select", { id: `bx_setting_${settingId}` });
|
||||||
|
$control.name = $control.id;
|
||||||
|
$control.addEventListener("change", (e) => {
|
||||||
|
setPref(settingId, e.target.value);
|
||||||
|
onChange(e);
|
||||||
|
});
|
||||||
|
selectedValue = PREF_PREFERRED_REGION;
|
||||||
|
setting.options = {};
|
||||||
|
for (let regionName in STATES.serverRegions) {
|
||||||
|
const region4 = STATES.serverRegions[regionName];
|
||||||
|
let value = regionName;
|
||||||
|
let label = `${region4.shortName} - ${regionName}`;
|
||||||
|
if (region4.isDefault) {
|
||||||
|
label += ` (${t("default")})`;
|
||||||
|
value = "default";
|
||||||
|
if (selectedValue === regionName) {
|
||||||
|
selectedValue = "default";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setting.options[value] = label;
|
||||||
|
}
|
||||||
|
for (let value in setting.options) {
|
||||||
|
const label = setting.options[value];
|
||||||
|
const $option = CE("option", { value }, label);
|
||||||
|
$control.appendChild($option);
|
||||||
|
}
|
||||||
|
$control.value = selectedValue;
|
||||||
|
} else {
|
||||||
|
if (settingId === PrefKey.BETTER_XCLOUD_LOCALE) {
|
||||||
|
$control = toPrefElement(settingId, (e) => {
|
||||||
|
localStorage.setItem("better_xcloud_locale", e.target.value);
|
||||||
|
onChange(e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$control = toPrefElement(settingId, onChange);
|
||||||
|
}
|
||||||
|
labelAttrs = { for: $control.id, tabindex: 0 };
|
||||||
|
}
|
||||||
|
if (setting.unsupported) {
|
||||||
|
$control.disabled = true;
|
||||||
|
}
|
||||||
|
const $label = CE("label", labelAttrs, settingLabel);
|
||||||
|
if (settingNote) {
|
||||||
|
$label.appendChild(CE("b", {}, settingNote));
|
||||||
|
}
|
||||||
|
const $elm = CE("div", { class: "bx-settings-row" }, $label, $control);
|
||||||
|
$wrapper.appendChild($elm);
|
||||||
|
if (settingId === PrefKey.USER_AGENT_PROFILE) {
|
||||||
|
$wrapper.appendChild($inpCustomUserAgent);
|
||||||
|
$control.dispatchEvent(new Event("change"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const $reloadBtn = createButton({
|
||||||
|
label: t("settings-reload"),
|
||||||
|
style: ButtonStyle.DANGER | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH,
|
||||||
|
onClick: (e) => {
|
||||||
|
window.location.reload();
|
||||||
|
$reloadBtn.disabled = true;
|
||||||
|
$reloadBtn.textContent = t("settings-reloading");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$reloadBtn.setAttribute("tabindex", "0");
|
||||||
|
$reloadBtnWrapper = CE("div", { class: "bx-settings-reload-button-wrapper bx-gone" }, $reloadBtn);
|
||||||
|
$wrapper.appendChild($reloadBtnWrapper);
|
||||||
|
const $donationLink = CE("a", { class: "bx-donation-link", href: "https://ko-fi.com/redphx", target: "_blank" }, `❤️ ${t("support-better-xcloud")}`);
|
||||||
|
$wrapper.appendChild($donationLink);
|
||||||
|
try {
|
||||||
|
const appVersion = document.querySelector("meta[name=gamepass-app-version]").content;
|
||||||
|
const appDate = new Date(document.querySelector("meta[name=gamepass-app-date]").content).toISOString().substring(0, 10);
|
||||||
|
$wrapper.appendChild(CE("div", { class: "bx-settings-app-version" }, `xCloud website version ${appVersion} (${appDate})`));
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
$container.appendChild($wrapper);
|
||||||
|
const $pageContent = document.getElementById("PageContent");
|
||||||
|
$pageContent?.parentNode?.insertBefore($container, $pageContent);
|
||||||
|
}
|
||||||
|
var SETTINGS_UI = {
|
||||||
|
"Better xCloud": {
|
||||||
|
items: [
|
||||||
|
PrefKey.BETTER_XCLOUD_LOCALE,
|
||||||
|
PrefKey.REMOTE_PLAY_ENABLED
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("server")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.SERVER_REGION,
|
||||||
|
PrefKey.STREAM_PREFERRED_LOCALE,
|
||||||
|
PrefKey.PREFER_IPV6_SERVER
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("stream")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.STREAM_TARGET_RESOLUTION,
|
||||||
|
PrefKey.STREAM_CODEC_PROFILE,
|
||||||
|
PrefKey.GAME_FORTNITE_FORCE_CONSOLE,
|
||||||
|
PrefKey.AUDIO_MIC_ON_PLAYING,
|
||||||
|
PrefKey.STREAM_DISABLE_FEEDBACK_DIALOG,
|
||||||
|
PrefKey.SCREENSHOT_BUTTON_POSITION,
|
||||||
|
PrefKey.SCREENSHOT_APPLY_FILTERS,
|
||||||
|
PrefKey.AUDIO_ENABLE_VOLUME_CONTROL,
|
||||||
|
PrefKey.STREAM_COMBINE_SOURCES
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("local-co-op")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.LOCAL_CO_OP_ENABLED
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("mouse-and-keyboard")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.MKB_ENABLED,
|
||||||
|
PrefKey.MKB_HIDE_IDLE_CURSOR
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("touch-controller")]: {
|
||||||
|
note: !STATES.hasTouchSupport ? "⚠️ " + t("device-unsupported-touch") : null,
|
||||||
|
unsupported: !STATES.hasTouchSupport,
|
||||||
|
items: [
|
||||||
|
PrefKey.STREAM_TOUCH_CONTROLLER,
|
||||||
|
PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF,
|
||||||
|
PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_STANDARD,
|
||||||
|
PrefKey.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("loading-screen")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.UI_LOADING_SCREEN_GAME_ART,
|
||||||
|
PrefKey.UI_LOADING_SCREEN_WAIT_TIME,
|
||||||
|
PrefKey.UI_LOADING_SCREEN_ROCKET
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("ui")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.UI_LAYOUT,
|
||||||
|
PrefKey.STREAM_SIMPLIFY_MENU,
|
||||||
|
PrefKey.SKIP_SPLASH_VIDEO,
|
||||||
|
!AppInterface && PrefKey.UI_SCROLLBAR_HIDE,
|
||||||
|
PrefKey.HIDE_DOTS_ICON,
|
||||||
|
PrefKey.REDUCE_ANIMATIONS
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("other")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.BLOCK_SOCIAL_FEATURES,
|
||||||
|
PrefKey.BLOCK_TRACKING
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[t("advanced")]: {
|
||||||
|
items: [
|
||||||
|
PrefKey.USER_AGENT_PROFILE
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// src/modules/ui/header.ts
|
||||||
|
var injectSettingsButton = function($parent) {
|
||||||
|
if (!$parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const PREF_PREFERRED_REGION = getPreferredServerRegion(true);
|
||||||
|
const PREF_LATEST_VERSION = getPref(PrefKey.LATEST_VERSION);
|
||||||
|
const $headerFragment = document.createDocumentFragment();
|
||||||
|
if (getPref(PrefKey.REMOTE_PLAY_ENABLED)) {
|
||||||
|
const $remotePlayBtn = createButton({
|
||||||
|
classes: ["bx-header-remote-play-button"],
|
||||||
|
icon: BxIcon.REMOTE_PLAY,
|
||||||
|
title: t("remote-play"),
|
||||||
|
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
|
||||||
|
onClick: (e) => {
|
||||||
|
RemotePlay.togglePopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$headerFragment.appendChild($remotePlayBtn);
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
|
||||||
|
$settingsBtn.setAttribute("data-update-available", "true");
|
||||||
|
}
|
||||||
|
$headerFragment.appendChild($settingsBtn);
|
||||||
|
$parent.appendChild($headerFragment);
|
||||||
|
};
|
||||||
|
function checkHeader() {
|
||||||
|
const $button = document.querySelector(".bx-header-settings-button");
|
||||||
|
if (!$button) {
|
||||||
|
const $rightHeader = document.querySelector("#PageContent div[class*=EdgewaterHeader-module__rightSectionSpacing]");
|
||||||
|
injectSettingsButton($rightHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function watchHeader() {
|
||||||
|
const $header = document.querySelector("#PageContent header");
|
||||||
|
if (!$header) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let timeout;
|
||||||
|
const observer = new MutationObserver((mutationList) => {
|
||||||
|
timeout && clearTimeout(timeout);
|
||||||
|
timeout = window.setTimeout(checkHeader, 2000);
|
||||||
|
});
|
||||||
|
observer.observe($header, { subtree: true, childList: true });
|
||||||
|
checkHeader();
|
||||||
|
}
|
||||||
|
|
||||||
// src/utils/history.ts
|
// src/utils/history.ts
|
||||||
function patchHistoryMethod(type) {
|
function patchHistoryMethod(type) {
|
||||||
const orig = window.history[type];
|
const orig = window.history[type];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user