mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-11 08:41:45 +02:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
2f280cf6e9 | |||
24c3588f1a | |||
330b7362ed | |||
5d177bd76c | |||
f18c5c14ed | |||
d0ceed00f8 | |||
fce8af4b3b |
12
dist/better-xcloud.lite.user.js
vendored
12
dist/better-xcloud.lite.user.js
vendored
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud (Lite)
|
// @name Better xCloud (Lite)
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.4
|
// @version 5.9.7
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -105,7 +105,7 @@ class UserAgent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var SCRIPT_VERSION = "5.9.4", SCRIPT_VARIANT = "lite", AppInterface = window.AppInterface;
|
var SCRIPT_VERSION = "5.9.7", SCRIPT_VARIANT = "lite", AppInterface = window.AppInterface;
|
||||||
UserAgent.init();
|
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, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
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, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
||||||
supportedRegion: !0,
|
supportedRegion: !0,
|
||||||
@ -504,6 +504,7 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
||||||
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
||||||
server: "Server",
|
server: "Server",
|
||||||
|
"server-locations": "Server locations",
|
||||||
settings: "Settings",
|
settings: "Settings",
|
||||||
"settings-reload": "Reload page to reflect changes",
|
"settings-reload": "Reload page to reflect changes",
|
||||||
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
||||||
@ -1148,6 +1149,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
|||||||
},
|
},
|
||||||
server_region: {
|
server_region: {
|
||||||
label: t("region"),
|
label: t("region"),
|
||||||
|
note: CE("a", { target: "_blank", href: "https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022" }, t("server-locations")),
|
||||||
default: "default"
|
default: "default"
|
||||||
},
|
},
|
||||||
server_bypass_restriction: {
|
server_bypass_restriction: {
|
||||||
@ -4895,6 +4897,8 @@ class GuideMenu {
|
|||||||
}
|
}
|
||||||
observe($addedElm) {
|
observe($addedElm) {
|
||||||
let className = $addedElm.className;
|
let className = $addedElm.className;
|
||||||
|
if (!className) className = $addedElm.firstElementChild?.className ?? "";
|
||||||
|
if (!className || className.startsWith("bx-")) return;
|
||||||
if (!className.startsWith("NavigationAnimation") && !className.startsWith("DialogRoutes") && !className.startsWith("Dialog-module__container")) return;
|
if (!className.startsWith("NavigationAnimation") && !className.startsWith("DialogRoutes") && !className.startsWith("Dialog-module__container")) return;
|
||||||
let $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
let $selectedTab = $addedElm.querySelector("div[class^=NavigationMenu] button[aria-selected=true");
|
||||||
if ($selectedTab) {
|
if ($selectedTab) {
|
||||||
@ -5284,7 +5288,7 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
if (STATES.userAgent.capabilities.touch && url.includes("catalog.gamepass.com/sigls/")) {
|
if (STATES.userAgent.capabilities.touch && url.includes("catalog.gamepass.com/sigls/")) {
|
||||||
let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();
|
let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();
|
||||||
if (url.includes("29a81209-df6f-41fd-a528-2ae6b91f719c")) for (let i = 1;i < obj.length; i++)
|
if (url.includes("ce573635-7c18-4d0c-9d68-90b932393470")) for (let i = 1;i < obj.length; i++)
|
||||||
gamepassAllGames.push(obj[i].id);
|
gamepassAllGames.push(obj[i].id);
|
||||||
else if (!1) try {} catch (e) {}
|
else if (!1) try {} catch (e) {}
|
||||||
return response.json = () => Promise.resolve(obj), response;
|
return response.json = () => Promise.resolve(obj), response;
|
||||||
@ -5956,7 +5960,7 @@ class RootDialogObserver {
|
|||||||
if (mutation.type !== "childList") continue;
|
if (mutation.type !== "childList") continue;
|
||||||
if (BX_FLAGS.Debug && BxLogger.warning("RootDialog", "added", mutation.addedNodes), mutation.addedNodes.length === 1) {
|
if (BX_FLAGS.Debug && BxLogger.warning("RootDialog", "added", mutation.addedNodes), mutation.addedNodes.length === 1) {
|
||||||
let $addedElm = mutation.addedNodes[0];
|
let $addedElm = mutation.addedNodes[0];
|
||||||
if ($addedElm instanceof HTMLElement && $addedElm.className) RootDialogObserver.handleAddedElement($root, $addedElm);
|
if ($addedElm instanceof HTMLElement) RootDialogObserver.handleAddedElement($root, $addedElm);
|
||||||
}
|
}
|
||||||
let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0);
|
let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0);
|
||||||
if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED);
|
if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED);
|
||||||
|
2
dist/better-xcloud.meta.js
vendored
2
dist/better-xcloud.meta.js
vendored
@ -1,5 +1,5 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.4
|
// @version 5.9.7
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
20
dist/better-xcloud.user.js
vendored
20
dist/better-xcloud.user.js
vendored
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.4
|
// @version 5.9.7
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -107,7 +107,7 @@ class UserAgent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var SCRIPT_VERSION = "5.9.4", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
var SCRIPT_VERSION = "5.9.7", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||||
UserAgent.init();
|
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, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
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, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
||||||
supportedRegion: !0,
|
supportedRegion: !0,
|
||||||
@ -527,6 +527,7 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
||||||
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
||||||
server: "Server",
|
server: "Server",
|
||||||
|
"server-locations": "Server locations",
|
||||||
settings: "Settings",
|
settings: "Settings",
|
||||||
"settings-reload": "Reload page to reflect changes",
|
"settings-reload": "Reload page to reflect changes",
|
||||||
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
||||||
@ -1171,6 +1172,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
|||||||
},
|
},
|
||||||
server_region: {
|
server_region: {
|
||||||
label: t("region"),
|
label: t("region"),
|
||||||
|
note: CE("a", { target: "_blank", href: "https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022" }, t("server-locations")),
|
||||||
default: "default"
|
default: "default"
|
||||||
},
|
},
|
||||||
server_bypass_restriction: {
|
server_bypass_restriction: {
|
||||||
@ -4397,9 +4399,9 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) {
|
|||||||
},
|
},
|
||||||
guideAchievementsDefaultLocked(str) {
|
guideAchievementsDefaultLocked(str) {
|
||||||
let index = str.indexOf("FilterButton-module__container");
|
let index = str.indexOf("FilterButton-module__container");
|
||||||
if (index >= 0 && (index = PatcherUtils.lastIndexOf(str, ".All", index, 150)), index < 0) return !1;
|
if (index >= 0 && (index = PatcherUtils.lastIndexOf(str, '"All"', index, 150)), index < 0) return !1;
|
||||||
if (str = PatcherUtils.replaceWith(str, index, ".All", ".Locked"), index = str.indexOf('"Guide_Achievements_Unlocked_Empty","Guide_Achievements_Locked_Empty"'), index >= 0 && (index = PatcherUtils.indexOf(str, ".All", index, 250)), index < 0) return !1;
|
if (str = PatcherUtils.replaceWith(str, index, '"All"', '"Locked"'), index = str.indexOf('"Guide_Achievements_Unlocked_Empty","Guide_Achievements_Locked_Empty"'), index >= 0 && (index = PatcherUtils.indexOf(str, '"All"', index, 250)), index < 0) return !1;
|
||||||
return str = PatcherUtils.replaceWith(str, index, ".All", ".Locked"), str;
|
return str = PatcherUtils.replaceWith(str, index, '"All"', '"Locked"'), str;
|
||||||
},
|
},
|
||||||
disableTouchContextMenu(str) {
|
disableTouchContextMenu(str) {
|
||||||
let index = str.indexOf('"ContextualCardActions-module__container');
|
let index = str.indexOf('"ContextualCardActions-module__container');
|
||||||
@ -5793,7 +5795,7 @@ var BxExposed = {
|
|||||||
try {
|
try {
|
||||||
let sigls = state.xcloud.sigls;
|
let sigls = state.xcloud.sigls;
|
||||||
if (STATES.userAgent.capabilities.touch) {
|
if (STATES.userAgent.capabilities.touch) {
|
||||||
let customList = TouchController.getCustomList(), allGames = sigls["29a81209-df6f-41fd-a528-2ae6b91f719c"].data.products;
|
let customList = TouchController.getCustomList(), allGames = sigls["ce573635-7c18-4d0c-9d68-90b932393470"].data.products;
|
||||||
customList = customList.filter((id2) => allGames.includes(id2)), sigls["9c86f07a-f3e8-45ad-82a0-a1f759597059"]?.data.products.push(...customList);
|
customList = customList.filter((id2) => allGames.includes(id2)), sigls["9c86f07a-f3e8-45ad-82a0-a1f759597059"]?.data.products.push(...customList);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -6514,6 +6516,8 @@ class GuideMenu {
|
|||||||
}
|
}
|
||||||
observe($addedElm) {
|
observe($addedElm) {
|
||||||
let className = $addedElm.className;
|
let className = $addedElm.className;
|
||||||
|
if (!className) className = $addedElm.firstElementChild?.className ?? "";
|
||||||
|
if (!className || className.startsWith("bx-")) return;
|
||||||
if (className.includes("AchievementsButton-module__progressBarContainer")) {
|
if (className.includes("AchievementsButton-module__progressBarContainer")) {
|
||||||
TrueAchievements.getInstance().injectAchievementsProgress($addedElm);
|
TrueAchievements.getInstance().injectAchievementsProgress($addedElm);
|
||||||
return;
|
return;
|
||||||
@ -6911,7 +6915,7 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
if (STATES.userAgent.capabilities.touch && url.includes("catalog.gamepass.com/sigls/")) {
|
if (STATES.userAgent.capabilities.touch && url.includes("catalog.gamepass.com/sigls/")) {
|
||||||
let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();
|
let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();
|
||||||
if (url.includes("29a81209-df6f-41fd-a528-2ae6b91f719c")) for (let i = 1;i < obj.length; i++)
|
if (url.includes("ce573635-7c18-4d0c-9d68-90b932393470")) for (let i = 1;i < obj.length; i++)
|
||||||
gamepassAllGames.push(obj[i].id);
|
gamepassAllGames.push(obj[i].id);
|
||||||
else if (url.includes("9c86f07a-f3e8-45ad-82a0-a1f759597059")) try {
|
else if (url.includes("9c86f07a-f3e8-45ad-82a0-a1f759597059")) try {
|
||||||
let customList = TouchController.getCustomList();
|
let customList = TouchController.getCustomList();
|
||||||
@ -7924,7 +7928,7 @@ class RootDialogObserver {
|
|||||||
if (mutation.type !== "childList") continue;
|
if (mutation.type !== "childList") continue;
|
||||||
if (BX_FLAGS.Debug && BxLogger.warning("RootDialog", "added", mutation.addedNodes), mutation.addedNodes.length === 1) {
|
if (BX_FLAGS.Debug && BxLogger.warning("RootDialog", "added", mutation.addedNodes), mutation.addedNodes.length === 1) {
|
||||||
let $addedElm = mutation.addedNodes[0];
|
let $addedElm = mutation.addedNodes[0];
|
||||||
if ($addedElm instanceof HTMLElement && $addedElm.className) RootDialogObserver.handleAddedElement($root, $addedElm);
|
if ($addedElm instanceof HTMLElement) RootDialogObserver.handleAddedElement($root, $addedElm);
|
||||||
}
|
}
|
||||||
let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0);
|
let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0);
|
||||||
if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED);
|
if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export enum GamePassCloudGallery {
|
export enum GamePassCloudGallery {
|
||||||
ALL = '29a81209-df6f-41fd-a528-2ae6b91f719c',
|
ALL = 'ce573635-7c18-4d0c-9d68-90b932393470',
|
||||||
MOST_POPULAR = 'e7590b22-e299-44db-ae22-25c61405454c',
|
MOST_POPULAR = 'e7590b22-e299-44db-ae22-25c61405454c',
|
||||||
NATIVE_MKB = '8fa264dd-124f-4af3-97e8-596fcdf4b486',
|
NATIVE_MKB = '8fa264dd-124f-4af3-97e8-596fcdf4b486',
|
||||||
TOUCH = '9c86f07a-f3e8-45ad-82a0-a1f759597059',
|
TOUCH = '9c86f07a-f3e8-45ad-82a0-a1f759597059',
|
||||||
|
@ -942,20 +942,20 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) {
|
|||||||
// Set Achievements list's filter default to "Locked"
|
// Set Achievements list's filter default to "Locked"
|
||||||
guideAchievementsDefaultLocked(str: string) {
|
guideAchievementsDefaultLocked(str: string) {
|
||||||
let index = str.indexOf('FilterButton-module__container');
|
let index = str.indexOf('FilterButton-module__container');
|
||||||
index >= 0 && (index = PatcherUtils.lastIndexOf(str, '.All', index, 150));
|
index >= 0 && (index = PatcherUtils.lastIndexOf(str, '"All"', index, 150));
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = PatcherUtils.replaceWith(str, index, '.All', '.Locked');
|
str = PatcherUtils.replaceWith(str, index, '"All"', '"Locked"');
|
||||||
|
|
||||||
index = str.indexOf('"Guide_Achievements_Unlocked_Empty","Guide_Achievements_Locked_Empty"');
|
index = str.indexOf('"Guide_Achievements_Unlocked_Empty","Guide_Achievements_Locked_Empty"');
|
||||||
index >= 0 && (index = PatcherUtils.indexOf(str, '.All', index, 250));
|
index >= 0 && (index = PatcherUtils.indexOf(str, '"All"', index, 250));
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = PatcherUtils.replaceWith(str, index, '.All', '.Locked');
|
str = PatcherUtils.replaceWith(str, index, '"All"', '"Locked"');
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -178,7 +178,16 @@ export class GuideMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
observe($addedElm: HTMLElement) {
|
observe($addedElm: HTMLElement) {
|
||||||
const className = $addedElm.className;
|
let className = $addedElm.className;
|
||||||
|
|
||||||
|
// Fix custom buttons disappearing in Guide Menu (#551)
|
||||||
|
if (!className) {
|
||||||
|
className = $addedElm.firstElementChild?.className ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!className || className.startsWith('bx-')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TrueAchievements
|
// TrueAchievements
|
||||||
if (isFullVersion() && className.includes('AchievementsButton-module__progressBarContainer')) {
|
if (isFullVersion() && className.includes('AchievementsButton-module__progressBarContainer')) {
|
||||||
|
@ -79,7 +79,7 @@ export class RootDialogObserver {
|
|||||||
BX_FLAGS.Debug && BxLogger.warning('RootDialog', 'added', mutation.addedNodes);
|
BX_FLAGS.Debug && BxLogger.warning('RootDialog', 'added', mutation.addedNodes);
|
||||||
if (mutation.addedNodes.length === 1) {
|
if (mutation.addedNodes.length === 1) {
|
||||||
const $addedElm = mutation.addedNodes[0];
|
const $addedElm = mutation.addedNodes[0];
|
||||||
if ($addedElm instanceof HTMLElement && $addedElm.className) {
|
if ($addedElm instanceof HTMLElement) {
|
||||||
RootDialogObserver.handleAddedElement($root, $addedElm);
|
RootDialogObserver.handleAddedElement($root, $addedElm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ export class GlobalSettingsStorage extends BaseSettingsStorage {
|
|||||||
},
|
},
|
||||||
[PrefKey.SERVER_REGION]: {
|
[PrefKey.SERVER_REGION]: {
|
||||||
label: t('region'),
|
label: t('region'),
|
||||||
|
note: CE('a', {target: '_blank', href: 'https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022'}, t('server-locations')),
|
||||||
default: 'default',
|
default: 'default',
|
||||||
},
|
},
|
||||||
[PrefKey.SERVER_BYPASS_RESTRICTION]: {
|
[PrefKey.SERVER_BYPASS_RESTRICTION]: {
|
||||||
|
@ -272,6 +272,7 @@ const Texts = {
|
|||||||
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
"separate-touch-controller": "Separate Touch controller & Controller #1",
|
||||||
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
"separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",
|
||||||
"server": "Server",
|
"server": "Server",
|
||||||
|
"server-locations": "Server locations",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"settings-reload": "Reload page to reflect changes",
|
"settings-reload": "Reload page to reflect changes",
|
||||||
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
"settings-reload-note": "Settings in this tab only go into effect on the next page load",
|
||||||
|
Reference in New Issue
Block a user