diff --git a/src/index.ts b/src/index.ts index 41fe0be..9d82ec4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,7 @@ import { Patcher } from "@modules/patcher"; import { RemotePlay } from "@modules/remote-play"; import { onHistoryChanged, patchHistoryMethod } from "@utils/history"; import { VibrationManager } from "@modules/vibration-manager"; -import { PreloadedState } from "@utils/titles-info"; +import { overridePreloadState } from "@utils/preload-state"; import { patchAudioContext, patchCanvasContext, patchMeControl, patchRtcCodecs, patchRtcPeerConnection, patchVideoApi } from "@utils/monkey-patches"; import { STATES } from "@utils/global"; import { injectStreamMenuButtons } from "@modules/stream/stream-ui"; @@ -220,7 +220,7 @@ function main() { getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && patchAudioContext(); getPref(PrefKey.BLOCK_TRACKING) && patchMeControl(); - PreloadedState.override(); + overridePreloadState(); VibrationManager.initialSetup(); diff --git a/src/modules/patcher.ts b/src/modules/patcher.ts index 59f2620..2a92787 100644 --- a/src/modules/patcher.ts +++ b/src/modules/patcher.ts @@ -3,7 +3,7 @@ import { BX_FLAGS } from "@utils/bx-flags"; import { getPref, PrefKey } from "@utils/preferences"; import { VibrationManager } from "@modules/vibration-manager"; import { BxLogger } from "@utils/bx-logger"; -import { hashCode } from "@/utils/utils"; +import { hashCode } from "@utils/utils"; type PatchArray = (keyof typeof PATCHES)[]; diff --git a/src/modules/touch-controller.ts b/src/modules/touch-controller.ts index 8aca644..dfbc082 100644 --- a/src/modules/touch-controller.ts +++ b/src/modules/touch-controller.ts @@ -10,6 +10,8 @@ import { BxLogger } from "@utils/bx-logger"; const LOG_TAG = 'TouchController'; +export const GALLERY_TOUCH_GAMES = '9c86f07a-f3e8-45ad-82a0-a1f759597059'; + export class TouchController { static readonly #EVENT_SHOW_DEFAULT_CONTROLLER = new MessageEvent('message', { data: '{"content":"{\\"layoutId\\":\\"\\"}","target":"/streaming/touchcontrols/showlayoutv2","type":"Message"}', @@ -184,6 +186,18 @@ export class TouchController { }, delay); } + static updateCustomList() { + NATIVE_FETCH('https://raw.githubusercontent.com/redphx/better-xcloud/gh-pages/touch-layouts/ids.json') + .then(response => response.json()) + .then(json => { + window.localStorage.setItem('better_xcloud_custom_touch_layouts', JSON.stringify(json)); + }); + } + + static getCustomList(): string[] { + return JSON.parse(window.localStorage.getItem('better_xcloud_custom_touch_layouts') || '[]'); + } + static setup() { // Function for testing touch control window.BX_EXPOSED.test_touch_control = (layout: any) => { diff --git a/src/utils/network.ts b/src/utils/network.ts index 5acb8d6..40e3f6f 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -4,7 +4,7 @@ import { LoadingScreen } from "@modules/loading-screen"; import { PrefKey, getPref } from "@utils/preferences"; import { RemotePlay } from "@modules/remote-play"; import { StreamBadges } from "@modules/stream/stream-badges"; -import { TouchController } from "@modules/touch-controller"; +import { GALLERY_TOUCH_GAMES, TouchController } from "@modules/touch-controller"; import { STATES } from "@utils/global"; import { getPreferredServerRegion } from "@utils/region"; @@ -549,6 +549,20 @@ export function interceptHttpRequests() { BxEvent.dispatch(window, BxEvent.STREAM_STARTING); } + // Add list of games with custom layouts to the official list + if (url.includes('catalog.gamepass.com') && url.includes(GALLERY_TOUCH_GAMES)) { + const response = await NATIVE_FETCH(request, init); + const obj = await response.clone().json(); + + try { + const customList = TouchController.getCustomList().map(item => ({ id: item })); + obj.push(...customList); + } catch (e) {} + + response.json = () => Promise.resolve(obj); + return response; + } + let requestType: RequestType; if (url.includes('/sessions/home') || url.includes('xhome.') || (STATES.remotePlay.isPlaying && url.endsWith('/inputconfigs'))) { requestType = RequestType.XHOME; diff --git a/src/utils/preload-state.ts b/src/utils/preload-state.ts new file mode 100644 index 0000000..8b1db1e --- /dev/null +++ b/src/utils/preload-state.ts @@ -0,0 +1,46 @@ +import { STATES } from "@utils/global"; +import { UserAgent } from "@utils/user-agent"; +import { BxLogger } from "./bx-logger"; +import { GALLERY_TOUCH_GAMES, TouchController } from "@modules/touch-controller"; + +const LOG_TAG = 'PreloadState'; + +export function overridePreloadState() { + let _state: any; + + Object.defineProperty(window, '__PRELOADED_STATE__', { + configurable: true, + get: () => { + // @ts-ignore + return _state; + }, + set: state => { + // Override User-Agent + const userAgent = UserAgent.spoof(); + if (userAgent) { + try { + // @ts-ignore + state.appContext.requestInfo.userAgent = userAgent; + } catch (e) { + BxLogger.error(LOG_TAG, e); + } + } + + // Add list of games with custom layouts to the official list + if (STATES.hasTouchSupport) { + TouchController.updateCustomList(); + const customList = TouchController.getCustomList(); + + try { + state.xcloud.sigls[GALLERY_TOUCH_GAMES]?.data.products.push(...customList); + } catch (e) { + BxLogger.error(LOG_TAG, e); + } + } + + // @ts-ignore + _state = state; + STATES.appContext = structuredClone(state.appContext); + } + }); +} diff --git a/src/utils/titles-info.ts b/src/utils/titles-info.ts deleted file mode 100644 index b2c74c1..0000000 --- a/src/utils/titles-info.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { STATES } from "@utils/global"; -import { UserAgent } from "@utils/user-agent"; - - -export class PreloadedState { - static override() { - Object.defineProperty(window, '__PRELOADED_STATE__', { - configurable: true, - get: () => { - // Override User-Agent - const userAgent = UserAgent.spoof(); - if (userAgent) { - (this as any)._state.appContext.requestInfo.userAgent = userAgent; - } - - return (this as any)._state; - }, - set: state => { - (this as any)._state = state; - STATES.appContext = structuredClone(state.appContext); - } - }); - } -}