mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-04 22:57:19 +02:00
Update dist
This commit is contained in:
parent
bd58355ef5
commit
086afafedf
6944
dist/better-xcloud.lite.user.js
vendored
Normal file
6944
dist/better-xcloud.lite.user.js
vendored
Normal file
File diff suppressed because one or more lines are too long
483
dist/better-xcloud.user.js
vendored
483
dist/better-xcloud.user.js
vendored
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 5.7.7
|
||||
// @version 5.7.8-beta
|
||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||
// @author redphx
|
||||
// @license MIT
|
||||
@ -120,7 +120,7 @@ function deepClone(obj) {
|
||||
if (!obj) return {};
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
var SCRIPT_VERSION = "5.7.7", AppInterface = window.AppInterface;
|
||||
var SCRIPT_VERSION = "5.7.8-beta", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||
UserAgent.init();
|
||||
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, STATES = {
|
||||
supportedRegion: !0,
|
||||
@ -995,6 +995,7 @@ class BaseSettingsStore {
|
||||
let settingId;
|
||||
for (settingId in definitions) {
|
||||
const setting = definitions[settingId];
|
||||
if (typeof setting.requiredVariants === "string") setting.requiredVariants = [setting.requiredVariants];
|
||||
setting.ready && setting.ready.call(this, setting);
|
||||
}
|
||||
this.definitions = definitions, this._settings = null;
|
||||
@ -1016,7 +1017,9 @@ class BaseSettingsStore {
|
||||
debugger;
|
||||
return;
|
||||
}
|
||||
if (checkUnsupported && this.definitions[key].unsupported) return this.definitions[key].default;
|
||||
const definition = this.definitions[key];
|
||||
if (definition.requiredVariants && !definition.requiredVariants.includes(SCRIPT_VARIANT)) return definition.default;
|
||||
if (checkUnsupported && definition.unsupported) return definition.default;
|
||||
if (!(key in this.settings)) this.settings[key] = this.validateValue(key, null);
|
||||
return this.settings[key];
|
||||
}
|
||||
@ -1183,6 +1186,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
screenshot_apply_filters: {
|
||||
requiredVariants: "full",
|
||||
label: t("screenshot-apply-filters"),
|
||||
default: !1
|
||||
},
|
||||
@ -1195,12 +1199,14 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
stream_combine_sources: {
|
||||
requiredVariants: "full",
|
||||
label: t("combine-audio-video-streams"),
|
||||
default: !1,
|
||||
experimental: !0,
|
||||
note: t("combine-audio-video-streams-summary")
|
||||
},
|
||||
stream_touch_controller: {
|
||||
requiredVariants: "full",
|
||||
label: t("tc-availability"),
|
||||
default: "all",
|
||||
options: {
|
||||
@ -1214,11 +1220,13 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
stream_touch_controller_auto_off: {
|
||||
requiredVariants: "full",
|
||||
label: t("tc-auto-off"),
|
||||
default: !1,
|
||||
unsupported: !STATES.userAgent.capabilities.touch
|
||||
},
|
||||
stream_touch_controller_default_opacity: {
|
||||
requiredVariants: "full",
|
||||
type: "number-stepper",
|
||||
label: t("tc-default-opacity"),
|
||||
default: 100,
|
||||
@ -1233,6 +1241,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
unsupported: !STATES.userAgent.capabilities.touch
|
||||
},
|
||||
stream_touch_controller_style_standard: {
|
||||
requiredVariants: "full",
|
||||
label: t("tc-standard-layout-style"),
|
||||
default: "default",
|
||||
options: {
|
||||
@ -1243,6 +1252,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
unsupported: !STATES.userAgent.capabilities.touch
|
||||
},
|
||||
stream_touch_controller_style_custom: {
|
||||
requiredVariants: "full",
|
||||
label: t("tc-custom-layout-style"),
|
||||
default: "default",
|
||||
options: {
|
||||
@ -1256,14 +1266,17 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
mkb_hide_idle_cursor: {
|
||||
requiredVariants: "full",
|
||||
label: t("hide-idle-cursor"),
|
||||
default: !1
|
||||
},
|
||||
stream_disable_feedback_dialog: {
|
||||
requiredVariants: "full",
|
||||
label: t("disable-post-stream-feedback-dialog"),
|
||||
default: !1
|
||||
},
|
||||
bitrate_video_max: {
|
||||
requiredVariants: "full",
|
||||
type: "number-stepper",
|
||||
label: t("bitrate-video-maximum"),
|
||||
note: "⚠️ " + t("unexpected-behavior"),
|
||||
@ -1283,6 +1296,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
game_bar_position: {
|
||||
requiredVariants: "full",
|
||||
label: t("position"),
|
||||
default: "bottom-left",
|
||||
options: {
|
||||
@ -1292,6 +1306,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
local_co_op_enabled: {
|
||||
requiredVariants: "full",
|
||||
label: t("enable-local-co-op-support"),
|
||||
default: !1,
|
||||
note: CE("a", {
|
||||
@ -1304,13 +1319,16 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !0
|
||||
},
|
||||
controller_enable_shortcuts: {
|
||||
requiredVariants: "full",
|
||||
default: !1
|
||||
},
|
||||
controller_enable_vibration: {
|
||||
requiredVariants: "full",
|
||||
label: t("controller-vibration"),
|
||||
default: !0
|
||||
},
|
||||
controller_device_vibration: {
|
||||
requiredVariants: "full",
|
||||
label: t("device-vibration"),
|
||||
default: "off",
|
||||
options: {
|
||||
@ -1320,6 +1338,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
controller_vibration_intensity: {
|
||||
requiredVariants: "full",
|
||||
label: t("vibration-intensity"),
|
||||
type: "number-stepper",
|
||||
default: 100,
|
||||
@ -1332,6 +1351,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
mkb_enabled: {
|
||||
requiredVariants: "full",
|
||||
label: t("enable-mkb"),
|
||||
default: !1,
|
||||
unsupported: (() => {
|
||||
@ -1349,6 +1369,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
native_mkb_enabled: {
|
||||
requiredVariants: "full",
|
||||
label: t("native-mkb"),
|
||||
default: "default",
|
||||
options: {
|
||||
@ -1363,6 +1384,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
native_mkb_scroll_x_sensitivity: {
|
||||
requiredVariants: "full",
|
||||
label: t("horizontal-scroll-sensitivity"),
|
||||
type: "number-stepper",
|
||||
default: 0,
|
||||
@ -1378,6 +1400,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
native_mkb_scroll_y_sensitivity: {
|
||||
requiredVariants: "full",
|
||||
label: t("vertical-scroll-sensitivity"),
|
||||
type: "number-stepper",
|
||||
default: 0,
|
||||
@ -1393,9 +1416,11 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
mkb_default_preset_id: {
|
||||
requiredVariants: "full",
|
||||
default: 0
|
||||
},
|
||||
mkb_absolute_mouse: {
|
||||
requiredVariants: "full",
|
||||
default: !1
|
||||
},
|
||||
reduce_animations: {
|
||||
@ -1403,6 +1428,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
ui_loading_screen_game_art: {
|
||||
requiredVariants: "full",
|
||||
label: t("show-game-art"),
|
||||
default: !0
|
||||
},
|
||||
@ -1424,6 +1450,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: BX_FLAGS.DeviceInfo.deviceType !== "unknown"
|
||||
},
|
||||
ui_layout: {
|
||||
requiredVariants: "full",
|
||||
label: t("layout"),
|
||||
default: "default",
|
||||
options: {
|
||||
@ -1437,10 +1464,12 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
ui_home_context_menu_disabled: {
|
||||
requiredVariants: "full",
|
||||
label: t("disable-home-context-menu"),
|
||||
default: STATES.browser.capabilities.touch
|
||||
},
|
||||
ui_hide_sections: {
|
||||
requiredVariants: "full",
|
||||
label: t("hide-sections"),
|
||||
default: [],
|
||||
multipleOptions: {
|
||||
@ -1456,6 +1485,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
ui_game_card_show_wait_time: {
|
||||
requiredVariants: "full",
|
||||
label: t("show-wait-time-in-game-card"),
|
||||
default: !1
|
||||
},
|
||||
@ -1585,6 +1615,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
audio_enable_volume_control: {
|
||||
requiredVariants: "full",
|
||||
label: t("enable-volume-control"),
|
||||
default: !1
|
||||
},
|
||||
@ -1662,10 +1693,12 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
default: !1
|
||||
},
|
||||
xhome_enabled: {
|
||||
requiredVariants: "full",
|
||||
label: t("enable-remote-play-feature"),
|
||||
default: !1
|
||||
},
|
||||
xhome_resolution: {
|
||||
requiredVariants: "full",
|
||||
default: "1080p",
|
||||
options: {
|
||||
"1080p": "1080p",
|
||||
@ -1673,6 +1706,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
||||
}
|
||||
},
|
||||
game_fortnite_force_console: {
|
||||
requiredVariants: "full",
|
||||
label: "🎮 " + t("fortnite-force-console-version"),
|
||||
default: !1,
|
||||
note: t("fortnite-allow-stw-mode")
|
||||
@ -1699,7 +1733,7 @@ class Screenshot {
|
||||
if ($canvas) $canvas.width = width, $canvas.height = height;
|
||||
}
|
||||
static updateCanvasFilters(filters) {
|
||||
Screenshot.#canvasContext.filter = filters;
|
||||
Screenshot.#canvasContext && (Screenshot.#canvasContext.filter = filters);
|
||||
}
|
||||
static #onAnimationEnd(e) {
|
||||
e.target.classList.remove("bx-taking-screenshot");
|
||||
@ -4065,12 +4099,14 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
"stream_combine_sources"
|
||||
]
|
||||
}, {
|
||||
requiredVariants: "full",
|
||||
group: "co-op",
|
||||
label: t("local-co-op"),
|
||||
items: [
|
||||
"local_co_op_enabled"
|
||||
]
|
||||
}, {
|
||||
requiredVariants: "full",
|
||||
group: "mkb",
|
||||
label: t("mouse-and-keyboard"),
|
||||
items: [
|
||||
@ -4079,6 +4115,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
"mkb_hide_idle_cursor"
|
||||
]
|
||||
}, {
|
||||
requiredVariants: "full",
|
||||
group: "touch-control",
|
||||
label: t("touch-controller"),
|
||||
note: !STATES.userAgent.capabilities.touch ? "⚠️ " + t("device-unsupported-touch") : null,
|
||||
@ -4107,6 +4144,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
"ui_hide_sections"
|
||||
]
|
||||
}, {
|
||||
requiredVariants: "full",
|
||||
group: "game-bar",
|
||||
label: t("game-bar"),
|
||||
items: [
|
||||
@ -4193,6 +4231,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
]
|
||||
}];
|
||||
TAB_DISPLAY_ITEMS = [{
|
||||
requiredVariants: "full",
|
||||
group: "audio",
|
||||
label: t("audio"),
|
||||
helpUrl: "https://better-xcloud.github.io/ingame-features/#audio",
|
||||
@ -4309,6 +4348,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
content: MkbRemapper.INSTANCE.render()
|
||||
}];
|
||||
TAB_NATIVE_MKB_ITEMS = [{
|
||||
requiredVariants: "full",
|
||||
group: "native-mkb",
|
||||
label: t("native-mkb"),
|
||||
items: [{
|
||||
@ -4324,6 +4364,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
}]
|
||||
}];
|
||||
TAB_SHORTCUTS_ITEMS = [{
|
||||
requiredVariants: "full",
|
||||
group: "controller-shortcuts",
|
||||
label: t("controller-shortcuts"),
|
||||
content: ControllerShortcut.renderSettings()
|
||||
@ -4383,22 +4424,26 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
{
|
||||
icon: BxIcon.CONTROLLER,
|
||||
group: "controller",
|
||||
items: this.TAB_CONTROLLER_ITEMS
|
||||
items: this.TAB_CONTROLLER_ITEMS,
|
||||
requiredVariants: "full"
|
||||
},
|
||||
getPref("mkb_enabled") && {
|
||||
icon: BxIcon.VIRTUAL_CONTROLLER,
|
||||
group: "mkb",
|
||||
items: this.TAB_VIRTUAL_CONTROLLER_ITEMS
|
||||
items: this.TAB_VIRTUAL_CONTROLLER_ITEMS,
|
||||
requiredVariants: "full"
|
||||
},
|
||||
AppInterface && getPref("native_mkb_enabled") === "on" && {
|
||||
icon: BxIcon.NATIVE_MKB,
|
||||
group: "native-mkb",
|
||||
items: this.TAB_NATIVE_MKB_ITEMS
|
||||
items: this.TAB_NATIVE_MKB_ITEMS,
|
||||
requiredVariants: "full"
|
||||
},
|
||||
{
|
||||
icon: BxIcon.COMMAND,
|
||||
group: "shortcuts",
|
||||
items: this.TAB_SHORTCUTS_ITEMS
|
||||
items: this.TAB_SHORTCUTS_ITEMS,
|
||||
requiredVariants: "full"
|
||||
},
|
||||
{
|
||||
icon: BxIcon.STREAM_STATS,
|
||||
@ -4457,6 +4502,10 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
if (!(prefKey in this.suggestedSettings.default)) this.suggestedSettings.default[prefKey] = getPrefDefinition(prefKey).default;
|
||||
}
|
||||
}
|
||||
isSupportedVariant(requiredVariants) {
|
||||
if (typeof requiredVariants === "undefined") return !0;
|
||||
return requiredVariants = typeof requiredVariants === "string" ? [requiredVariants] : requiredVariants, requiredVariants.includes(SCRIPT_VARIANT);
|
||||
}
|
||||
async renderSuggestions(e) {
|
||||
const $btnSuggest = e.target.closest("div");
|
||||
$btnSuggest.toggleAttribute("bx-open");
|
||||
@ -4645,6 +4694,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
}
|
||||
let prefDefinition = null;
|
||||
if (pref) prefDefinition = getPrefDefinition(pref);
|
||||
if (prefDefinition && !this.isSupportedVariant(prefDefinition.requiredVariants)) return;
|
||||
let label = prefDefinition?.label || setting.label, note = prefDefinition?.note || setting.note;
|
||||
const experimental = prefDefinition?.experimental || setting.experimental;
|
||||
if (settingTabContent.label && setting.pref) {
|
||||
@ -4718,6 +4768,7 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
});
|
||||
for (let settingTab of this.SETTINGS_UI) {
|
||||
if (!settingTab) continue;
|
||||
if (!this.isSupportedVariant(settingTab.requiredVariants)) continue;
|
||||
if (settingTab.group !== "global" && !this.renderFullSettings) continue;
|
||||
const $svg = this.renderTab(settingTab);
|
||||
$tabs.appendChild($svg);
|
||||
@ -4727,13 +4778,17 @@ class SettingsNavigationDialog extends NavigationDialog {
|
||||
});
|
||||
for (let settingTabContent of settingTab.items) {
|
||||
if (settingTabContent === !1) continue;
|
||||
if (!this.isSupportedVariant(settingTabContent.requiredVariants)) continue;
|
||||
if (!this.renderFullSettings && settingTab.group === "global" && settingTabContent.group !== "general" && settingTabContent.group !== "footer") continue;
|
||||
let label = settingTabContent.label;
|
||||
if (label === t("better-xcloud")) label += " " + SCRIPT_VERSION, label = createButton({
|
||||
if (label === t("better-xcloud")) {
|
||||
if (label += " " + SCRIPT_VERSION, SCRIPT_VARIANT === "lite") label += " (Lite)";
|
||||
label = createButton({
|
||||
label,
|
||||
url: "https://github.com/redphx/better-xcloud/releases",
|
||||
style: 1024 | 8 | 32
|
||||
});
|
||||
}
|
||||
if (label) {
|
||||
const $title = CE("h2", {
|
||||
_nearby: {
|
||||
@ -5908,6 +5963,211 @@ class LoadingScreen {
|
||||
LoadingScreen.#$bgStyle && (LoadingScreen.#$bgStyle.textContent = ""), LoadingScreen.#$waitTimeBox && LoadingScreen.#$waitTimeBox.classList.add("bx-gone"), LoadingScreen.#waitTimeInterval && clearInterval(LoadingScreen.#waitTimeInterval), LoadingScreen.#waitTimeInterval = null;
|
||||
}
|
||||
}
|
||||
class TrueAchievements {
|
||||
static $link = createButton({
|
||||
label: t("true-achievements"),
|
||||
url: "#",
|
||||
icon: BxIcon.TRUE_ACHIEVEMENTS,
|
||||
style: 32 | 4 | 64 | 2048,
|
||||
onClick: TrueAchievements.onClick
|
||||
});
|
||||
static $button = createButton({
|
||||
label: t("true-achievements"),
|
||||
title: t("true-achievements"),
|
||||
icon: BxIcon.TRUE_ACHIEVEMENTS,
|
||||
style: 32,
|
||||
onClick: TrueAchievements.onClick
|
||||
});
|
||||
static onClick(e) {
|
||||
e.preventDefault();
|
||||
const dataset = TrueAchievements.$link.dataset;
|
||||
TrueAchievements.open(!0, dataset.xboxTitleId, dataset.id), window.BX_EXPOSED.dialogRoutes?.closeAll();
|
||||
}
|
||||
static $hiddenLink = CE("a", {
|
||||
target: "_blank"
|
||||
});
|
||||
static updateIds(xboxTitleId, id2) {
|
||||
const { $link, $button } = TrueAchievements;
|
||||
if (clearDataSet($link), clearDataSet($button), xboxTitleId) $link.dataset.xboxTitleId = xboxTitleId, $button.dataset.xboxTitleId = xboxTitleId;
|
||||
if (id2) $link.dataset.id = id2, $button.dataset.id = id2;
|
||||
}
|
||||
static injectAchievementsProgress($elm) {
|
||||
if (SCRIPT_VARIANT !== "full") return;
|
||||
const $parent = $elm.parentElement, $div = CE("div", {
|
||||
class: "bx-guide-home-achievements-progress"
|
||||
}, $elm);
|
||||
let xboxTitleId;
|
||||
try {
|
||||
const $container = $parent.closest("div[class*=AchievementsPreview-module__container]");
|
||||
if ($container) xboxTitleId = getReactProps($container).children.props.data.data.xboxTitleId;
|
||||
} catch (e) {}
|
||||
if (!xboxTitleId) xboxTitleId = TrueAchievements.getStreamXboxTitleId();
|
||||
if (typeof xboxTitleId !== "undefined") xboxTitleId = xboxTitleId.toString();
|
||||
if (TrueAchievements.updateIds(xboxTitleId), document.documentElement.dataset.xdsPlatform === "tv") $div.appendChild(TrueAchievements.$link);
|
||||
else $div.appendChild(TrueAchievements.$button);
|
||||
$parent.appendChild($div);
|
||||
}
|
||||
static injectAchievementDetailPage($parent) {
|
||||
if (SCRIPT_VARIANT !== "full") return;
|
||||
const props = getReactProps($parent);
|
||||
if (!props) return;
|
||||
try {
|
||||
const achievementList = props.children.props.data.data, $header = $parent.querySelector("div[class*=AchievementDetailHeader]"), achievementName = getReactProps($header).children[0].props.achievementName;
|
||||
let id2, xboxTitleId;
|
||||
for (let achiev of achievementList)
|
||||
if (achiev.name === achievementName) {
|
||||
id2 = achiev.id, xboxTitleId = achiev.title.id;
|
||||
break;
|
||||
}
|
||||
if (id2) TrueAchievements.updateIds(xboxTitleId, id2), $parent.appendChild(TrueAchievements.$link);
|
||||
} catch (e) {}
|
||||
}
|
||||
static getStreamXboxTitleId() {
|
||||
return STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId;
|
||||
}
|
||||
static open(override, xboxTitleId, id2) {
|
||||
if (!xboxTitleId || xboxTitleId === "undefined") xboxTitleId = TrueAchievements.getStreamXboxTitleId();
|
||||
if (AppInterface && AppInterface.openTrueAchievementsLink) {
|
||||
AppInterface.openTrueAchievementsLink(override, xboxTitleId?.toString(), id2?.toString());
|
||||
return;
|
||||
}
|
||||
let url = "https://www.trueachievements.com";
|
||||
if (xboxTitleId) {
|
||||
if (url += `/deeplink/${xboxTitleId}`, id2) url += `/${id2}`;
|
||||
}
|
||||
TrueAchievements.$hiddenLink.href = url, TrueAchievements.$hiddenLink.click();
|
||||
}
|
||||
}
|
||||
class GuideMenu {
|
||||
static #BUTTONS = {
|
||||
scriptSettings: createButton({
|
||||
label: t("better-xcloud"),
|
||||
style: 64 | 32 | 1,
|
||||
onClick: (e) => {
|
||||
window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, (e2) => {
|
||||
setTimeout(() => SettingsNavigationDialog.getInstance().show(), 50);
|
||||
}, { once: !0 }), GuideMenu.#closeGuideMenu();
|
||||
}
|
||||
}),
|
||||
closeApp: AppInterface && createButton({
|
||||
icon: BxIcon.POWER,
|
||||
label: t("close-app"),
|
||||
title: t("close-app"),
|
||||
style: 64 | 32 | 2,
|
||||
onClick: (e) => {
|
||||
AppInterface.closeApp();
|
||||
},
|
||||
attributes: {
|
||||
"data-state": "normal"
|
||||
}
|
||||
}),
|
||||
reloadPage: createButton({
|
||||
icon: BxIcon.REFRESH,
|
||||
label: t("reload-page"),
|
||||
title: t("reload-page"),
|
||||
style: 64 | 32,
|
||||
onClick: (e) => {
|
||||
if (STATES.isPlaying) confirm(t("confirm-reload-stream")) && window.location.reload();
|
||||
else window.location.reload();
|
||||
GuideMenu.#closeGuideMenu();
|
||||
}
|
||||
}),
|
||||
backToHome: createButton({
|
||||
icon: BxIcon.HOME,
|
||||
label: t("back-to-home"),
|
||||
title: t("back-to-home"),
|
||||
style: 64 | 32,
|
||||
onClick: (e) => {
|
||||
confirm(t("back-to-home-confirm")) && (window.location.href = window.location.href.substring(0, 31)), GuideMenu.#closeGuideMenu();
|
||||
},
|
||||
attributes: {
|
||||
"data-state": "playing"
|
||||
}
|
||||
})
|
||||
};
|
||||
static #$renderedButtons;
|
||||
static #closeGuideMenu() {
|
||||
if (window.BX_EXPOSED.dialogRoutes) {
|
||||
window.BX_EXPOSED.dialogRoutes.closeAll();
|
||||
return;
|
||||
}
|
||||
const $btnClose = document.querySelector("#gamepass-dialog-root button[class^=Header-module__closeButton]");
|
||||
$btnClose && $btnClose.click();
|
||||
}
|
||||
static #renderButtons() {
|
||||
if (GuideMenu.#$renderedButtons) return GuideMenu.#$renderedButtons;
|
||||
const $div = CE("div", {
|
||||
class: "bx-guide-home-buttons"
|
||||
}), buttons = [
|
||||
GuideMenu.#BUTTONS.scriptSettings,
|
||||
[
|
||||
GuideMenu.#BUTTONS.backToHome,
|
||||
GuideMenu.#BUTTONS.reloadPage,
|
||||
GuideMenu.#BUTTONS.closeApp
|
||||
]
|
||||
];
|
||||
for (let $button of buttons) {
|
||||
if (!$button) continue;
|
||||
if ($button instanceof HTMLElement) $div.appendChild($button);
|
||||
else if (Array.isArray($button)) {
|
||||
const $wrapper = CE("div", {});
|
||||
for (let $child of $button)
|
||||
$child && $wrapper.appendChild($child);
|
||||
$div.appendChild($wrapper);
|
||||
}
|
||||
}
|
||||
return GuideMenu.#$renderedButtons = $div, $div;
|
||||
}
|
||||
static #injectHome($root, isPlaying = !1) {
|
||||
{
|
||||
const $achievementsProgress = $root.querySelector("button[class*=AchievementsButton-module__progressBarContainer]");
|
||||
if ($achievementsProgress) TrueAchievements.injectAchievementsProgress($achievementsProgress);
|
||||
}
|
||||
let $target = null;
|
||||
if (isPlaying) {
|
||||
$target = $root.querySelector("a[class*=QuitGameButton]");
|
||||
const $btnXcloudHome = $root.querySelector("div[class^=HomeButtonWithDivider]");
|
||||
$btnXcloudHome && ($btnXcloudHome.style.display = "none");
|
||||
} else {
|
||||
const $dividers = $root.querySelectorAll("div[class*=Divider-module__divider]");
|
||||
if ($dividers) $target = $dividers[$dividers.length - 1];
|
||||
}
|
||||
if (!$target) return !1;
|
||||
const $buttons = GuideMenu.#renderButtons();
|
||||
$buttons.dataset.isPlaying = isPlaying.toString(), $target.insertAdjacentElement("afterend", $buttons);
|
||||
}
|
||||
static async#onShown(e) {
|
||||
if (e.where === "home") {
|
||||
const $root = document.querySelector("#gamepass-dialog-root div[role=dialog] div[role=tabpanel] div[class*=HomeLandingPage]");
|
||||
$root && GuideMenu.#injectHome($root, STATES.isPlaying);
|
||||
}
|
||||
}
|
||||
static addEventListeners() {
|
||||
window.addEventListener(BxEvent.XCLOUD_GUIDE_MENU_SHOWN, GuideMenu.#onShown);
|
||||
}
|
||||
static observe($addedElm) {
|
||||
const className = $addedElm.className;
|
||||
if (className.includes("AchievementsButton-module__progressBarContainer")) {
|
||||
TrueAchievements.injectAchievementsProgress($addedElm);
|
||||
return;
|
||||
}
|
||||
if (!className.startsWith("NavigationAnimation") && !className.startsWith("DialogRoutes") && !className.startsWith("Dialog-module__container")) return;
|
||||
{
|
||||
const $achievDetailPage = $addedElm.querySelector("div[class*=AchievementDetailPage]");
|
||||
if ($achievDetailPage) {
|
||||
TrueAchievements.injectAchievementDetailPage($achievDetailPage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
||||
if ($selectedTab) {
|
||||
let $elm = $selectedTab, index;
|
||||
for (index = 0;$elm = $elm?.previousElementSibling; index++)
|
||||
;
|
||||
if (index === 0) BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, { where: "home" });
|
||||
}
|
||||
}
|
||||
}
|
||||
var StreamBadgeIcon = {
|
||||
playtime: BxIcon.PLAYTIME,
|
||||
video: BxIcon.DISPLAY,
|
||||
@ -6929,79 +7189,6 @@ class MicrophoneAction extends BaseGameBarAction {
|
||||
this.visible = !1, this.$content.classList.add("bx-gone"), this.$content.setAttribute("data-enabled", "false");
|
||||
}
|
||||
}
|
||||
class TrueAchievements {
|
||||
static $link = createButton({
|
||||
label: t("true-achievements"),
|
||||
url: "#",
|
||||
icon: BxIcon.TRUE_ACHIEVEMENTS,
|
||||
style: 32 | 4 | 64 | 2048,
|
||||
onClick: TrueAchievements.onClick
|
||||
});
|
||||
static $button = createButton({
|
||||
label: t("true-achievements"),
|
||||
title: t("true-achievements"),
|
||||
icon: BxIcon.TRUE_ACHIEVEMENTS,
|
||||
style: 32,
|
||||
onClick: TrueAchievements.onClick
|
||||
});
|
||||
static onClick(e) {
|
||||
e.preventDefault();
|
||||
const dataset = TrueAchievements.$link.dataset;
|
||||
TrueAchievements.open(!0, dataset.xboxTitleId, dataset.id), window.BX_EXPOSED.dialogRoutes.closeAll();
|
||||
}
|
||||
static $hiddenLink = CE("a", {
|
||||
target: "_blank"
|
||||
});
|
||||
static updateIds(xboxTitleId, id2) {
|
||||
const { $link, $button } = TrueAchievements;
|
||||
if (clearDataSet($link), clearDataSet($button), xboxTitleId) $link.dataset.xboxTitleId = xboxTitleId, $button.dataset.xboxTitleId = xboxTitleId;
|
||||
if (id2) $link.dataset.id = id2, $button.dataset.id = id2;
|
||||
}
|
||||
static injectAchievementsProgress($elm) {
|
||||
const $parent = $elm.parentElement, $div = CE("div", {
|
||||
class: "bx-guide-home-achievements-progress"
|
||||
}, $elm);
|
||||
let xboxTitleId;
|
||||
try {
|
||||
const $container = $parent.closest("div[class*=AchievementsPreview-module__container]");
|
||||
if ($container) xboxTitleId = getReactProps($container).children.props.data.data.xboxTitleId;
|
||||
} catch (e) {}
|
||||
if (!xboxTitleId) xboxTitleId = TrueAchievements.getStreamXboxTitleId();
|
||||
if (typeof xboxTitleId !== "undefined") xboxTitleId = xboxTitleId.toString();
|
||||
if (TrueAchievements.updateIds(xboxTitleId), document.documentElement.dataset.xdsPlatform === "tv") $div.appendChild(TrueAchievements.$link);
|
||||
else $div.appendChild(TrueAchievements.$button);
|
||||
$parent.appendChild($div);
|
||||
}
|
||||
static injectAchievementDetailPage($parent) {
|
||||
const props = getReactProps($parent);
|
||||
if (!props) return;
|
||||
try {
|
||||
const achievementList = props.children.props.data.data, $header = $parent.querySelector("div[class*=AchievementDetailHeader]"), achievementName = getReactProps($header).children[0].props.achievementName;
|
||||
let id2, xboxTitleId;
|
||||
for (let achiev of achievementList)
|
||||
if (achiev.name === achievementName) {
|
||||
id2 = achiev.id, xboxTitleId = achiev.title.id;
|
||||
break;
|
||||
}
|
||||
if (id2) TrueAchievements.updateIds(xboxTitleId, id2), $parent.appendChild(TrueAchievements.$link);
|
||||
} catch (e) {}
|
||||
}
|
||||
static getStreamXboxTitleId() {
|
||||
return STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId;
|
||||
}
|
||||
static open(override, xboxTitleId, id2) {
|
||||
if (!xboxTitleId || xboxTitleId === "undefined") xboxTitleId = TrueAchievements.getStreamXboxTitleId();
|
||||
if (AppInterface && AppInterface.openTrueAchievementsLink) {
|
||||
AppInterface.openTrueAchievementsLink(override, xboxTitleId?.toString(), id2?.toString());
|
||||
return;
|
||||
}
|
||||
let url = "https://www.trueachievements.com";
|
||||
if (xboxTitleId) {
|
||||
if (url += `/deeplink/${xboxTitleId}`, id2) url += `/${id2}`;
|
||||
}
|
||||
TrueAchievements.$hiddenLink.href = url, TrueAchievements.$hiddenLink.click();
|
||||
}
|
||||
}
|
||||
class TrueAchievementsAction extends BaseGameBarAction {
|
||||
$content;
|
||||
constructor() {
|
||||
@ -7113,124 +7300,6 @@ class GameBar {
|
||||
action.reset();
|
||||
}
|
||||
}
|
||||
class GuideMenu {
|
||||
static #BUTTONS = {
|
||||
scriptSettings: createButton({
|
||||
label: t("better-xcloud"),
|
||||
style: 64 | 32 | 1,
|
||||
onClick: (e) => {
|
||||
window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, (e2) => {
|
||||
setTimeout(() => SettingsNavigationDialog.getInstance().show(), 50);
|
||||
}, { once: !0 }), window.BX_EXPOSED.dialogRoutes.closeAll();
|
||||
}
|
||||
}),
|
||||
closeApp: AppInterface && createButton({
|
||||
icon: BxIcon.POWER,
|
||||
label: t("close-app"),
|
||||
title: t("close-app"),
|
||||
style: 64 | 32 | 2,
|
||||
onClick: (e) => {
|
||||
AppInterface.closeApp();
|
||||
},
|
||||
attributes: {
|
||||
"data-state": "normal"
|
||||
}
|
||||
}),
|
||||
reloadPage: createButton({
|
||||
icon: BxIcon.REFRESH,
|
||||
label: t("reload-page"),
|
||||
title: t("reload-page"),
|
||||
style: 64 | 32,
|
||||
onClick: (e) => {
|
||||
if (STATES.isPlaying) confirm(t("confirm-reload-stream")) && window.location.reload();
|
||||
else window.location.reload();
|
||||
window.BX_EXPOSED.dialogRoutes.closeAll();
|
||||
}
|
||||
}),
|
||||
backToHome: createButton({
|
||||
icon: BxIcon.HOME,
|
||||
label: t("back-to-home"),
|
||||
title: t("back-to-home"),
|
||||
style: 64 | 32,
|
||||
onClick: (e) => {
|
||||
confirm(t("back-to-home-confirm")) && (window.location.href = window.location.href.substring(0, 31)), window.BX_EXPOSED.dialogRoutes.closeAll();
|
||||
},
|
||||
attributes: {
|
||||
"data-state": "playing"
|
||||
}
|
||||
})
|
||||
};
|
||||
static #$renderedButtons;
|
||||
static #renderButtons() {
|
||||
if (GuideMenu.#$renderedButtons) return GuideMenu.#$renderedButtons;
|
||||
const $div = CE("div", {
|
||||
class: "bx-guide-home-buttons"
|
||||
}), buttons = [
|
||||
GuideMenu.#BUTTONS.scriptSettings,
|
||||
[
|
||||
GuideMenu.#BUTTONS.backToHome,
|
||||
GuideMenu.#BUTTONS.reloadPage,
|
||||
GuideMenu.#BUTTONS.closeApp
|
||||
]
|
||||
];
|
||||
for (let $button of buttons) {
|
||||
if (!$button) continue;
|
||||
if ($button instanceof HTMLElement) $div.appendChild($button);
|
||||
else if (Array.isArray($button)) {
|
||||
const $wrapper = CE("div", {});
|
||||
for (let $child of $button)
|
||||
$child && $wrapper.appendChild($child);
|
||||
$div.appendChild($wrapper);
|
||||
}
|
||||
}
|
||||
return GuideMenu.#$renderedButtons = $div, $div;
|
||||
}
|
||||
static #injectHome($root, isPlaying = !1) {
|
||||
const $achievementsProgress = $root.querySelector("button[class*=AchievementsButton-module__progressBarContainer]");
|
||||
if ($achievementsProgress) TrueAchievements.injectAchievementsProgress($achievementsProgress);
|
||||
let $target = null;
|
||||
if (isPlaying) {
|
||||
$target = $root.querySelector("a[class*=QuitGameButton]");
|
||||
const $btnXcloudHome = $root.querySelector("div[class^=HomeButtonWithDivider]");
|
||||
$btnXcloudHome && ($btnXcloudHome.style.display = "none");
|
||||
} else {
|
||||
const $dividers = $root.querySelectorAll("div[class*=Divider-module__divider]");
|
||||
if ($dividers) $target = $dividers[$dividers.length - 1];
|
||||
}
|
||||
if (!$target) return !1;
|
||||
const $buttons = GuideMenu.#renderButtons();
|
||||
$buttons.dataset.isPlaying = isPlaying.toString(), $target.insertAdjacentElement("afterend", $buttons);
|
||||
}
|
||||
static async#onShown(e) {
|
||||
if (e.where === "home") {
|
||||
const $root = document.querySelector("#gamepass-dialog-root div[role=dialog] div[role=tabpanel] div[class*=HomeLandingPage]");
|
||||
$root && GuideMenu.#injectHome($root, STATES.isPlaying);
|
||||
}
|
||||
}
|
||||
static addEventListeners() {
|
||||
window.addEventListener(BxEvent.XCLOUD_GUIDE_MENU_SHOWN, GuideMenu.#onShown);
|
||||
}
|
||||
static observe($addedElm) {
|
||||
const className = $addedElm.className;
|
||||
if (className.includes("AchievementsButton-module__progressBarContainer")) {
|
||||
TrueAchievements.injectAchievementsProgress($addedElm);
|
||||
return;
|
||||
}
|
||||
if (!className.startsWith("NavigationAnimation") && !className.startsWith("DialogRoutes") && !className.startsWith("Dialog-module__container")) return;
|
||||
const $achievDetailPage = $addedElm.querySelector("div[class*=AchievementDetailPage]");
|
||||
if ($achievDetailPage) {
|
||||
TrueAchievements.injectAchievementDetailPage($achievDetailPage);
|
||||
return;
|
||||
}
|
||||
const $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
||||
if ($selectedTab) {
|
||||
let $elm = $selectedTab, index;
|
||||
for (index = 0;$elm = $elm?.previousElementSibling; index++)
|
||||
;
|
||||
if (index === 0) BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, { where: "home" });
|
||||
}
|
||||
}
|
||||
}
|
||||
class XcloudApi {
|
||||
static instance;
|
||||
static getInstance() {
|
||||
@ -7532,12 +7601,11 @@ function waitForRootDialog() {
|
||||
observer.observe(document.documentElement, { subtree: !0, childList: !0 });
|
||||
}
|
||||
function main() {
|
||||
if (waitForRootDialog(), patchRtcPeerConnection(), patchRtcCodecs(), interceptHttpRequests(), patchVideoApi(), patchCanvasContext(), AppInterface && patchPointerLockApi(), getPref("audio_enable_volume_control") && patchAudioContext(), getPref("block_tracking")) patchMeControl(), disableAdobeAudienceManager();
|
||||
if (STATES.userAgent.capabilities.touch && TouchController.updateCustomList(), overridePreloadState(), VibrationManager.initialSetup(), BX_FLAGS.CheckForUpdate && checkForUpdate(), addCss(), Toast.setup(), getPref("game_bar_position") !== "off" && GameBar.getInstance(), Screenshot.setup(), GuideMenu.addEventListeners(), StreamBadges.setupEvents(), StreamStats.setupEvents(), EmulatedMkbHandler.setupEvents(), Patcher.init(), disablePwa(), getPref("controller_show_connection_status")) window.addEventListener("gamepadconnected", (e) => showGamepadToast(e.gamepad)), window.addEventListener("gamepaddisconnected", (e) => showGamepadToast(e.gamepad));
|
||||
if (getPref("xhome_enabled")) RemotePlayManager.detect();
|
||||
if (patchRtcPeerConnection(), patchRtcCodecs(), interceptHttpRequests(), patchVideoApi(), patchCanvasContext(), AppInterface && patchPointerLockApi(), getPref("audio_enable_volume_control") && patchAudioContext(), getPref("block_tracking")) patchMeControl(), disableAdobeAudienceManager();
|
||||
if (waitForRootDialog(), addCss(), Toast.setup(), GuideMenu.addEventListeners(), StreamBadges.setupEvents(), StreamStats.setupEvents(), getPref("game_bar_position") !== "off" && GameBar.getInstance(), Screenshot.setup(), STATES.userAgent.capabilities.touch && TouchController.updateCustomList(), overridePreloadState(), VibrationManager.initialSetup(), BX_FLAGS.CheckForUpdate && checkForUpdate(), Patcher.init(), disablePwa(), getPref("xhome_enabled")) RemotePlayManager.detect();
|
||||
if (getPref("stream_touch_controller") === "all") TouchController.setup();
|
||||
if (getPref("mkb_enabled") && AppInterface) STATES.pointerServerPort = AppInterface.startPointerServer() || 9269, BxLogger.info("startPointerServer", "Port", STATES.pointerServerPort.toString());
|
||||
getPref("ui_game_card_show_wait_time") && GameTile.setup();
|
||||
if (getPref("ui_game_card_show_wait_time") && GameTile.setup(), EmulatedMkbHandler.setupEvents(), getPref("controller_show_connection_status")) window.addEventListener("gamepadconnected", (e) => showGamepadToast(e.gamepad)), window.addEventListener("gamepaddisconnected", (e) => showGamepadToast(e.gamepad));
|
||||
}
|
||||
if (window.location.pathname.includes("/auth/msa")) {
|
||||
const nativePushState = window.history.pushState;
|
||||
@ -7606,8 +7674,11 @@ window.addEventListener(BxEvent.STREAM_PLAYING, (e) => {
|
||||
const gameBar = GameBar.getInstance();
|
||||
gameBar.reset(), gameBar.enable(), gameBar.showBar();
|
||||
}
|
||||
const $video = e.$video;
|
||||
Screenshot.updateCanvasSize($video.videoWidth, $video.videoHeight), updateVideoPlayer();
|
||||
{
|
||||
const $video = e.$video;
|
||||
Screenshot.updateCanvasSize($video.videoWidth, $video.videoHeight);
|
||||
}
|
||||
updateVideoPlayer();
|
||||
});
|
||||
window.addEventListener(BxEvent.STREAM_ERROR_PAGE, (e) => {
|
||||
BxEvent.dispatch(window, BxEvent.STREAM_STOPPED);
|
||||
|
Loading…
x
Reference in New Issue
Block a user