diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js
index fa021e6..edadcf9 100644
--- a/dist/better-xcloud.user.js
+++ b/dist/better-xcloud.user.js
@@ -1,7 +1,7 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
-// @version 5.6.2-beta
+// @version 5.6.3-beta
// @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx
// @license MIT
@@ -138,7 +138,7 @@ function deepClone(obj) {
return {};
return JSON.parse(JSON.stringify(obj));
}
-var SCRIPT_VERSION = "5.6.2-beta", AppInterface = window.AppInterface;
+var SCRIPT_VERSION = "5.6.3-beta", 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,
@@ -590,6 +590,7 @@ var SUPPORTED_LANGUAGES = {
],
"touch-controller": "Touch controller",
"transparent-background": "Transparent background",
+ "true-achievements": "TrueAchievements",
ui: "UI",
"unexpected-behavior": "May cause unexpected behavior",
"united-states": "United States",
@@ -1821,12 +1822,12 @@ class Screenshot {
streamPlayer.getWebGL2Player().drawFrame();
if (canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height), AppInterface) {
const data = $canvas.toDataURL("image/png").split(";base64,")[1];
- AppInterface.saveScreenshot(currentStream.titleId, data), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();
+ AppInterface.saveScreenshot(currentStream.titleSlug, data), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();
return;
}
$canvas && $canvas.toBlob((blob) => {
const now = +new Date, $anchor = CE("a", {
- download: `${currentStream.titleId}-${now}.png`,
+ download: `${currentStream.titleSlug}-${now}.png`,
href: URL.createObjectURL(blob)
});
$anchor.click(), URL.revokeObjectURL($anchor.href), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();
@@ -2753,70 +2754,73 @@ class NavigationDialogManager {
}
}
-var better_xcloud_default = "\n";
+var better_xcloud_default = "";
-var close_default = "\n";
+var true_achievements_default = "";
-var command_default = "\n";
+var close_default = "";
-var controller_default = "\n";
+var command_default = "";
-var copy_default = "\n";
+var controller_default = "";
-var create_shortcut_default = "\n";
+var copy_default = "";
-var cursor_text_default = "\n";
+var create_shortcut_default = "";
-var display_default = "\n";
+var cursor_text_default = "";
-var home_default = "\n";
+var display_default = "";
-var native_mkb_default = "\n";
+var home_default = "";
-var new_default = "\n";
+var native_mkb_default = "";
-var question_default = "\n";
+var new_default = "";
-var refresh_default = "\n";
+var question_default = "";
-var remote_play_default = "\n";
+var refresh_default = "";
-var stream_settings_default = "\n";
+var remote_play_default = "";
-var stream_stats_default = "\n";
+var stream_settings_default = "";
-var touch_control_disable_default = "\n";
+var stream_stats_default = "";
-var touch_control_enable_default = "\n";
+var touch_control_disable_default = "";
-var trash_default = "\n";
+var touch_control_enable_default = "";
-var virtual_controller_default = "\n";
+var trash_default = "";
-var caret_left_default = "\n";
+var virtual_controller_default = "";
-var caret_right_default = "\n";
+var caret_left_default = "";
-var camera_default = "\n";
+var caret_right_default = "";
-var microphone_default = "\n";
+var camera_default = "";
-var microphone_slash_default = "\n";
+var microphone_default = "";
-var battery_full_default = "\n";
+var microphone_slash_default = "";
-var clock_default = "\n";
+var battery_full_default = "";
-var cloud_default = "\n";
+var clock_default = "";
-var download_default = "\n";
+var cloud_default = "";
-var speaker_high_default = "\n";
+var download_default = "";
-var upload_default = "\n";
+var speaker_high_default = "";
+
+var upload_default = "";
var BxIcon = {
BETTER_XCLOUD: better_xcloud_default,
+ TRUE_ACHIEVEMENTS: true_achievements_default,
STREAM_SETTINGS: stream_settings_default,
STREAM_STATS: stream_stats_default,
CLOSE: close_default,
@@ -3223,6 +3227,9 @@ async function copyToClipboard(text, showToast = !0) {
}
return !1;
}
+function productTitleToSlug(title) {
+ return title.replace(/[;,/?:@&=+_`~$%#^*()!^™\xae\xa9]/g, "").replace(/ {2,}/g, " ").trim().substr(0, 50).replace(/ /g, "-").toLowerCase();
+}
class SoundShortcut {
static adjustGainNodeVolume(amount) {
@@ -7677,6 +7684,44 @@ class MicrophoneAction extends BaseGameBarAction {
}
}
+class TrueAchievements {
+ static open() {
+ if (AppInterface)
+ ;
+ else {
+ let xboxTitleId;
+ xboxTitleId = STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId;
+ let url = "https://www.trueachievements.com";
+ if (xboxTitleId)
+ url += `/deeplink/${xboxTitleId}/1`;
+ CE("a", {
+ class: "bx-hidden bx-offscreen",
+ href: url,
+ target: "_blank"
+ }, "").click();
+ }
+ }
+}
+
+class TrueAchievementsAction extends BaseGameBarAction {
+ $content;
+ constructor() {
+ super();
+ const onClick = (e) => {
+ BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED), TrueAchievements.open();
+ };
+ this.$content = createButton({
+ style: 4,
+ icon: BxIcon.TRUE_ACHIEVEMENTS,
+ title: t("true-achievements"),
+ onClick
+ });
+ }
+ render() {
+ return this.$content;
+ }
+}
+
class GameBar {
static instance;
static getInstance() {
@@ -7695,6 +7740,7 @@ class GameBar {
if (this.actions = [
new ScreenshotAction,
...STATES.userAgent.capabilities.touch && getPref("stream_touch_controller") !== "off" ? [new TouchControlAction] : [],
+ new TrueAchievementsAction,
new MicrophoneAction
], position === "bottom-right")
this.actions.reverse();
@@ -7757,13 +7803,6 @@ class GuideMenu {
}, { once: !0 }), window.BX_EXPOSED.dialogRoutes.closeAll();
}
}),
- appSettings: createButton({
- label: t("app-settings"),
- style: 64 | 32,
- onClick: (e) => {
- window.BX_EXPOSED.dialogRoutes.closeAll(), AppInterface.openAppSettings && AppInterface.openAppSettings();
- }
- }),
closeApp: createButton({
label: t("close-app"),
style: 64 | 32 | 2,
@@ -7789,11 +7828,18 @@ class GuideMenu {
label: t("back-to-home"),
style: 64 | 32,
onClick: (e) => {
- confirm(t("back-to-home-confirm")) && (window.location.href = window.location.href.substring(0, 31));
+ confirm(t("back-to-home-confirm")) && (window.location.href = window.location.href.substring(0, 31)), window.BX_EXPOSED.dialogRoutes.closeAll();
},
attributes: {
"data-state": "playing"
}
+ }),
+ trueAchievements: createButton({
+ label: t("true-achievements"),
+ style: 64 | 32,
+ onClick: (e) => {
+ TrueAchievements.open(), window.BX_EXPOSED.dialogRoutes.closeAll();
+ }
})
};
static #$renderedButtons;
@@ -7804,6 +7850,7 @@ class GuideMenu {
class: "bx-guide-home-buttons"
}), buttons = [
GuideMenu.#BUTTONS.scriptSettings,
+ GuideMenu.#BUTTONS.trueAchievements,
GuideMenu.#BUTTONS.reloadPage,
GuideMenu.#BUTTONS.backToHome,
AppInterface && GuideMenu.#BUTTONS.closeApp
@@ -8123,6 +8170,20 @@ class StreamUiHandler {
}
}
+class XboxApi {
+ static CACHED_TITLES = {};
+ static async getProductTitle(xboxTitleId) {
+ if (xboxTitleId = xboxTitleId.toString(), XboxApi.CACHED_TITLES[xboxTitleId])
+ return XboxApi.CACHED_TITLES[xboxTitleId];
+ try {
+ const url = `https://displaycatalog.mp.microsoft.com/v7.0/products/lookup?market=US&languages=en&value=${xboxTitleId}&alternateId=XboxTitleId&fieldsTemplate=browse`, productTitle = (await (await NATIVE_FETCH(url)).json()).Products[0].LocalizedProperties[0].ProductTitle;
+ return XboxApi.CACHED_TITLES[xboxTitleId] = productTitle, productTitle;
+ } catch (e) {
+ }
+ return null;
+ }
+}
+
function unload() {
if (!STATES.isPlaying)
return;
@@ -8243,12 +8304,10 @@ window.addEventListener(BxEvent.XCLOUD_SERVERS_READY, (e) => {
STATES.isSignedIn = !0, window.setTimeout(HeaderSection.watchHeader, 2000);
});
window.addEventListener(BxEvent.STREAM_LOADING, (e) => {
- if (window.location.pathname.includes("/launch/")) {
- const matches = /\/launch\/(?[^\/]+)\/(?\w+)/.exec(window.location.pathname);
- if (matches?.groups)
- STATES.currentStream.titleId = matches.groups.title_id, STATES.currentStream.productId = matches.groups.product_id;
- } else
- STATES.currentStream.titleId = "remote-play", STATES.currentStream.productId = "";
+ if (window.location.pathname.includes("/launch/") && STATES.currentStream.titleInfo)
+ STATES.currentStream.titleSlug = productTitleToSlug(STATES.currentStream.titleInfo.product.title);
+ else
+ STATES.currentStream.titleSlug = "remote-play";
});
getPref("ui_loading_screen_game_art") && window.addEventListener(BxEvent.TITLE_INFO_READY, LoadingScreen.setup);
window.addEventListener(BxEvent.STREAM_STARTING, (e) => {
@@ -8270,6 +8329,23 @@ window.addEventListener(BxEvent.XCLOUD_RENDERING_COMPONENT, (e) => {
if (e.component === "product-details")
ProductDetailsPage.injectShortcutButton();
});
+window.addEventListener(BxEvent.DATA_CHANNEL_CREATED, (e) => {
+ const dataChannel = e.dataChannel;
+ if (!dataChannel || dataChannel.label !== "message")
+ return;
+ dataChannel.addEventListener("message", async (msg) => {
+ if (msg.origin === "better-xcloud" || typeof msg.data !== "string")
+ return;
+ if (msg.data.includes("/titleinfo")) {
+ const json = JSON.parse(JSON.parse(msg.data).content), xboxTitleId = parseInt(json.titleid, 16);
+ if (STATES.currentStream.xboxTitleId = xboxTitleId, STATES.currentStream.titleSlug = "remote-play", STATES.remotePlay.isPlaying && json.focused) {
+ const productTitle = await XboxApi.getProductTitle(xboxTitleId);
+ if (productTitle)
+ STATES.currentStream.titleSlug = productTitleToSlug(productTitle);
+ }
+ }
+ });
+});
window.addEventListener(BxEvent.STREAM_STOPPED, unload);
window.addEventListener("pagehide", (e) => {
BxEvent.dispatch(window, BxEvent.STREAM_STOPPED);