diff --git a/dist/better-xcloud.lite.user.js b/dist/better-xcloud.lite.user.js index dc568d6..320fa67 100755 --- a/dist/better-xcloud.lite.user.js +++ b/dist/better-xcloud.lite.user.js @@ -407,6 +407,7 @@ var SUPPORTED_LANGUAGES = { "how-to-fix": "How to fix", "how-to-improve-app-performance": "How to improve app's performance", ignore: "Ignore", + "image-quality": "Image quality", import: "Import", "in-game-controller-customization": "In-game controller customization", "in-game-controller-shortcuts": "In-game controller shortcuts", @@ -1437,6 +1438,20 @@ class GlobalSettingsStorage extends BaseSettingsStore { label: t("hide-system-menu-icon"), default: !1 }, + "ui.imageQuality": { + label: t("image-quality"), + default: 90, + min: 10, + max: 90, + params: { + steps: 10, + exactTicks: 20, + customTextValue(value, min, max) { + if (value === 90) return t("default"); + return value + "%"; + } + } + }, "stream.video.combineAudio": { requiredVariants: "full", label: t("combine-audio-video-streams"), @@ -4369,6 +4384,7 @@ class SettingsDialog extends NavigationDialog { label: t("ui"), items: [ "ui.layout", + "ui.imageQuality", "ui.gameCard.waitTime.show", "ui.controllerStatus.show", "ui.streamMenu.simplify", diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js index 016eee9..b3321ed 100755 --- a/dist/better-xcloud.user.js +++ b/dist/better-xcloud.user.js @@ -439,6 +439,7 @@ var SUPPORTED_LANGUAGES = { "how-to-fix": "How to fix", "how-to-improve-app-performance": "How to improve app's performance", ignore: "Ignore", + "image-quality": "Image quality", import: "Import", "in-game-controller-customization": "In-game controller customization", "in-game-controller-shortcuts": "In-game controller shortcuts", @@ -1509,6 +1510,20 @@ class GlobalSettingsStorage extends BaseSettingsStore { label: t("hide-system-menu-icon"), default: !1 }, + "ui.imageQuality": { + label: t("image-quality"), + default: 90, + min: 10, + max: 90, + params: { + steps: 10, + exactTicks: 20, + customTextValue(value, min, max) { + if (value === 90) return t("default"); + return value + "%"; + } + } + }, "stream.video.combineAudio": { requiredVariants: "full", label: t("combine-audio-video-streams"), @@ -4857,6 +4872,15 @@ ${subsVar} = subs; supportedInputIcons: supportedInputIconsVar }); return str = PatcherUtils.insertAt(str, returnIndex, newCode), str; + }, + setImageQuality(str) { + let index = str.indexOf("const{size:{width:"); + if (index > -1 && (index = PatcherUtils.indexOf(str, "=new URLSearchParams", index, 500)), index < 0) return !1; + let paramVar = PatcherUtils.getVariableNameBefore(str, index); + if (!paramVar) return !1; + index = PatcherUtils.indexOf(str, "return", index, 200); + let newCode = `${paramVar}.set('q', ${getPref("ui.imageQuality")});`; + return str = PatcherUtils.insertAt(str, index, newCode), str; } }, PATCH_ORDERS = PatcherUtils.filterPatches([ ...AppInterface && getPref("nativeMkb.mode") === "on" ? [ @@ -4866,6 +4890,7 @@ ${subsVar} = subs; ] : [], "exposeReactCreateComponent", "gameCardCustomIcons", + getPref("ui.imageQuality") < 90 && "setImageQuality", "modifyPreloadedState", "optimizeGameSlugGenerator", "detectBrowserRouterReady", @@ -6488,6 +6513,7 @@ class SettingsDialog extends NavigationDialog { label: t("ui"), items: [ "ui.layout", + "ui.imageQuality", "ui.gameCard.waitTime.show", "ui.controllerStatus.show", "ui.streamMenu.simplify", diff --git a/src/enums/pref-keys.ts b/src/enums/pref-keys.ts index d1893c8..dc93a99 100755 --- a/src/enums/pref-keys.ts +++ b/src/enums/pref-keys.ts @@ -86,6 +86,7 @@ export const enum PrefKey { UI_SKIP_SPLASH_VIDEO = 'ui.splashVideo.skip', UI_HIDE_SYSTEM_MENU_ICON = 'ui.systemMenu.hideHandle', UI_REDUCE_ANIMATIONS = 'ui.reduceAnimations', + UI_IMAGE_QUALITY = 'ui.imageQuality', VIDEO_PLAYER_TYPE = 'video.player.type', VIDEO_POWER_PREFERENCE = 'video.player.powerPreference', @@ -172,6 +173,7 @@ export type PrefTypeMap = { [PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME]: boolean, [PrefKey.UI_HIDE_SECTIONS]: UiSection[], [PrefKey.UI_HIDE_SYSTEM_MENU_ICON]: boolean, + [PrefKey.UI_IMAGE_QUALITY]: number, [PrefKey.UI_LAYOUT]: UiLayout, [PrefKey.UI_REDUCE_ANIMATIONS]: boolean, [PrefKey.UI_SCROLLBAR_HIDE]: boolean, diff --git a/src/modules/patcher/patcher.ts b/src/modules/patcher/patcher.ts index 8a8c801..2cb653d 100755 --- a/src/modules/patcher/patcher.ts +++ b/src/modules/patcher/patcher.ts @@ -1081,6 +1081,28 @@ ${subsVar} = subs; return str; }, */ + + // 27.0.6-hotfix.1, 78831.js + setImageQuality(str: string) { + let index = str.indexOf('const{size:{width:'); + index > -1 && (index = PatcherUtils.indexOf(str, '=new URLSearchParams', index, 500)); + if (index < 0) { + return false; + } + + const paramVar = PatcherUtils.getVariableNameBefore(str, index); + if (!paramVar) { + return false; + } + + // Find "return" keyword + index = PatcherUtils.indexOf(str, 'return', index, 200); + + const newCode = `${paramVar}.set('q', ${getPref(PrefKey.UI_IMAGE_QUALITY)});`; + str = PatcherUtils.insertAt(str, index, newCode); + + return str; + }, }; let PATCH_ORDERS = PatcherUtils.filterPatches([ @@ -1094,6 +1116,8 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([ 'gameCardCustomIcons', // 'gameCardPassTitle', + getPref(PrefKey.UI_IMAGE_QUALITY) < 90 && 'setImageQuality', + 'modifyPreloadedState', 'optimizeGameSlugGenerator', diff --git a/src/modules/ui/dialog/settings-dialog.ts b/src/modules/ui/dialog/settings-dialog.ts index 346c590..5695bcb 100755 --- a/src/modules/ui/dialog/settings-dialog.ts +++ b/src/modules/ui/dialog/settings-dialog.ts @@ -274,6 +274,7 @@ export class SettingsDialog extends NavigationDialog { label: t('ui'), items: [ PrefKey.UI_LAYOUT, + PrefKey.UI_IMAGE_QUALITY, PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME, PrefKey.UI_CONTROLLER_SHOW_STATUS, PrefKey.UI_SIMPLIFY_STREAM_MENU, diff --git a/src/utils/settings-storages/global-settings-storage.ts b/src/utils/settings-storages/global-settings-storage.ts index 002b3d4..f2ba541 100755 --- a/src/utils/settings-storages/global-settings-storage.ts +++ b/src/utils/settings-storages/global-settings-storage.ts @@ -192,6 +192,23 @@ export class GlobalSettingsStorage extends BaseSettingsStorage { label: t('hide-system-menu-icon'), default: false, }, + [PrefKey.UI_IMAGE_QUALITY]: { + label: t('image-quality'), + default: 90, + min: 10, + max: 90, + params: { + steps: 10, + exactTicks: 20, + customTextValue(value, min, max) { + if (value === 90) { + return t('default'); + } + + return value + '%'; + }, + }, + }, [PrefKey.STREAM_COMBINE_SOURCES]: { requiredVariants: 'full', diff --git a/src/utils/translation.ts b/src/utils/translation.ts index 38eedf5..3ed0c80 100755 --- a/src/utils/translation.ts +++ b/src/utils/translation.ts @@ -151,6 +151,7 @@ const Texts = { "how-to-fix": "How to fix", "how-to-improve-app-performance": "How to improve app's performance", "ignore": "Ignore", + "image-quality": "Image quality", "import": "Import", "in-game-controller-customization": "In-game controller customization", "in-game-controller-shortcuts": "In-game controller shortcuts",