Merge remote-tracking branch 'vendev/dev'

This commit is contained in:
Xyntho 2025-02-22 12:01:39 +05:30
commit 8e90452fae
15 changed files with 140 additions and 73 deletions

View file

@ -16,8 +16,8 @@ export default definePlugin({
{ {
find: "SCALE_DOWN:", find: "SCALE_DOWN:",
replacement: { replacement: {
match: /!\(null==(\i)\|\|0===\i\|\|null==(\i)\|\|0===\i\)/, match: /(?<="IMAGE"===\i\?)\i(?=\?)/,
replace: (_, width, height) => `!((null == ${width} || 0 === ${width}) && (null == ${height} || 0 === ${height}))` replace: "true"
} }
} }
] ]

View file

@ -85,7 +85,7 @@ export default definePlugin({
replace: "$&onRequestClose:$self.onPopoutClose," replace: "$&onRequestClose:$self.onPopoutClose,"
}, },
{ {
match: /(?<=\.avatarWrapper,)/, match: /(?<=#{intl::SET_STATUS}\),)/,
replace: "ref:$self.accountPanelRef,onContextMenu:$self.openAccountPanelContextMenu," replace: "ref:$self.accountPanelRef,onContextMenu:$self.openAccountPanelContextMenu,"
} }
] ]

View file

@ -26,10 +26,18 @@ export default definePlugin({
patches: [ patches: [
{ {
find: '"ChannelAttachButton"', find: '"ChannelAttachButton"',
replacement: { replacement: [
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,30}?\.\.\.(\i),/, {
replace: "$&onClick:$1,onContextMenu:$2.onClick,", // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
}, match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,30}?\.\.\.(\i),/,
replace: "$&onClick:$1,onContextMenu:$2.onClick,",
noWarn: true
},
{
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,100}\},(\i)\).{0,100}children:\i/,
replace: "$&,onClick:$1,onContextMenu:$2.onClick,",
},
]
}, },
], ],
}); });

View file

@ -50,12 +50,24 @@ export default definePlugin({
find: ".decorationGridItem,", find: ".decorationGridItem,",
replacement: [ replacement: [
{ {
match: /(?<==)\i=>{let{children.{20,100}decorationGridItem/, // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
replace: "$self.DecorationGridItem=$&" match: /(?<==)\i=>{let{children.{20,200}decorationGridItem/,
replace: "$self.DecorationGridItem=$&",
noWarn: true
}, },
{ {
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
match: /(?<==)\i=>{let{user:\i,avatarDecoration/, match: /(?<==)\i=>{let{user:\i,avatarDecoration/,
replace: "$self.DecorationGridDecoration=$&" replace: "$self.DecorationGridDecoration=$&",
noWarn: true
},
{
match: /(?<==)\i=>{var{children.{20,200}decorationGridItem/,
replace: "$self.DecorationGridItem=$&",
},
{
match: /(?<==)\i=>{var{user:\i,avatarDecoration/,
replace: "$self.DecorationGridDecoration=$&",
}, },
// Remove NEW label from decor avatar decorations // Remove NEW label from decor avatar decorations
{ {

View file

@ -34,7 +34,7 @@ export default definePlugin({
{ {
find: "#{intl::FRIENDS_ALL_HEADER}", find: "#{intl::FRIENDS_ALL_HEADER}",
replacement: { replacement: {
match: /toString\(\)\}\);case (\i\.\i)\.BLOCKED/, match: /toString\(\)\}\);case (\i\.\i)\.PENDING/,
replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED' replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED'
}, },
}, },
@ -50,7 +50,7 @@ export default definePlugin({
{ {
find: "#{intl::FRIENDS_SECTION_ONLINE}", find: "#{intl::FRIENDS_SECTION_ONLINE}",
replacement: { replacement: {
match: /,{id:(\i\.\i)\.BLOCKED,show:.+?className:(\i\.item)/, match: /,{id:(\i\.\i)\.PENDING,show:.+?className:(\i\.item)/,
replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}` replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}`
} }
}, },
@ -58,7 +58,7 @@ export default definePlugin({
{ {
find: '"FriendsStore"', find: '"FriendsStore"',
replacement: { replacement: {
match: /(?<=case (\i\.\i)\.BLOCKED:return (\i)\.type===\i\.\i\.BLOCKED)/, match: /(?<=case (\i\.\i)\.SUGGESTIONS:return \d+===(\i)\.type)/,
replace: ";case $1.IMPLICIT:return $2.type===5" replace: ";case $1.IMPLICIT:return $2.type===5"
}, },
}, },

View file

@ -65,10 +65,18 @@ export default definePlugin({
patches: [ patches: [
{ {
find: "{isSidebarVisible:", find: "{isSidebarVisible:",
replacement: { replacement: [
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/, {
replace: ":[$1?.startsWith('members')?$self.render():null,$2" // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
}, match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
replace: ":[$1?.startsWith('members')?$self.render():null,$2",
noWarn: true
},
{
match: /(?<=var\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
replace: ":[$1?.startsWith('members')?$self.render():null,$2",
},
],
predicate: () => settings.store.memberList predicate: () => settings.store.memberList
}, },
{ {

View file

@ -84,8 +84,14 @@ export default definePlugin({
find: ".USER_MENTION)", find: ".USER_MENTION)",
replacement: [ replacement: [
{ {
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
match: /onContextMenu:\i,color:\i,\.\.\.\i(?=,children:)(?<=user:(\i),channel:(\i).{0,500}?)/, match: /onContextMenu:\i,color:\i,\.\.\.\i(?=,children:)(?<=user:(\i),channel:(\i).{0,500}?)/,
replace: "$&,color:$self.getColorInt($1?.id,$2?.id)" replace: "$&,color:$self.getColorInt($1?.id,$2?.id)",
noWarn: true
},
{
match: /(?<=onContextMenu:\i,color:)\i(?=\},\i\),\{children)(?<=user:(\i),channel:(\i).{0,500}?)/,
replace: "$self.getColorInt($1?.id,$2?.id)",
} }
], ],
predicate: () => settings.store.chatMentions predicate: () => settings.store.chatMentions

View file

@ -173,7 +173,7 @@ export default definePlugin({
replacement: [ replacement: [
// Make the channel appear as muted if it's hidden // Make the channel appear as muted if it's hidden
{ {
match: /{channel:(\i),name:\i,muted:(\i).+?;/, match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};` replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
}, },
// Add the hidden eye icon if the channel is hidden // Add the hidden eye icon if the channel is hidden
@ -204,7 +204,7 @@ export default definePlugin({
{ {
// Hide unreads // Hide unreads
predicate: () => settings.store.hideUnreads === true, predicate: () => settings.store.hideUnreads === true,
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/, match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,.+?unread:(\i).+?)/,
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};` replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
} }
] ]
@ -485,7 +485,7 @@ export default definePlugin({
} }
}, },
{ {
find: '="NowPlayingViewStore",', find: '"NowPlayingViewStore"',
replacement: { replacement: {
// Make active now voice states on hidden channels // Make active now voice states on hidden channels
match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/, match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/,

View file

@ -27,12 +27,22 @@ export default definePlugin({
authors: [Devs.Megu], authors: [Devs.Megu],
patches: [{ patches: [{
find: "#{intl::ACTIVITY_SETTINGS}", find: "#{intl::ACTIVITY_SETTINGS}",
replacement: { replacement: [
match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+}\)}\))/, {
replace: (_, commaOrSemi, settings, elements) => "" + // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
`${commaOrSemi}${settings}?.[0]==="CHANGELOG"` + match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+}\)}\))/,
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})` replace: (_, commaOrSemi, settings, elements) => "" +
} `${commaOrSemi}${settings}?.[0]==="CHANGELOG"` +
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})`,
noWarn: true
},
{
match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+\)\)\}\))(?=\)\})/,
replace: (_, commaOrSemi, settings, elements) => "" +
`${commaOrSemi}${settings}?.[0]==="CHANGELOG"` +
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})`,
},
]
}], }],
StartupTimingPage StartupTimingPage
}); });

View file

@ -41,11 +41,20 @@ export default definePlugin({
}, },
{ {
find: '="SYSTEM_TAG"', find: '="SYSTEM_TAG"',
replacement: { replacement: [
// Add next to username (compact mode) {
match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\),(?=\i)/g, // Add next to username (compact mode)
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0])," // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
} match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\),(?=\i)/g,
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),",
noWarn: true
},
{
// Add next to username (compact mode)
match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\)\),(?=\i)/g,
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),",
},
]
} }
], ],

View file

@ -193,10 +193,18 @@ export default definePlugin({
// Avatar component used in User DMs "User Profile" popup in the right and Profiles Modal pfp // Avatar component used in User DMs "User Profile" popup in the right and Profiles Modal pfp
{ {
find: ".overlay:void 0,status:", find: ".overlay:void 0,status:",
replacement: { replacement: [
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/, {
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)}," // FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
}, match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
noWarn: true
},
{
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",.{0,100}className:\i,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
}
],
all: true all: true
}, },
// Banners // Banners

View file

@ -20,9 +20,9 @@ export function makeLazy<T>(factory: () => T, attempts = 5): () => T {
let tries = 0; let tries = 0;
let cache: T; let cache: T;
return () => { return () => {
if (!cache && attempts > tries++) { if (cache === undefined && attempts > tries++) {
cache = factory(); cache = factory();
if (!cache && attempts === tries) if (cache === undefined && attempts === tries)
console.error("Lazy factory failed:", factory); console.error("Lazy factory failed:", factory);
} }
return cache; return cache;

View file

@ -41,7 +41,12 @@ export interface PatchReplacement {
match: string | RegExp; match: string | RegExp;
/** The replacement string or function which returns the string for the patch replacement */ /** The replacement string or function which returns the string for the patch replacement */
replace: string | ReplaceFn; replace: string | ReplaceFn;
/** A function which returns whether this patch replacement should be applied */ /** Do not warn if this replacement did no changes */
noWarn?: boolean;
/**
* A function which returns whether this patch replacement should be applied.
* This is ran before patches are registered, so if this returns false, the patch will never be registered.
*/
predicate?(): boolean; predicate?(): boolean;
/** The minimum build number for this patch to be applied */ /** The minimum build number for this patch to be applied */
fromBuild?: number; fromBuild?: number;
@ -61,7 +66,10 @@ export interface Patch {
noWarn?: boolean; noWarn?: boolean;
/** Only apply this set of replacements if all of them succeed. Use this if your replacements depend on each other */ /** Only apply this set of replacements if all of them succeed. Use this if your replacements depend on each other */
group?: boolean; group?: boolean;
/** A function which returns whether this patch should be applied */ /**
* A function which returns whether this patch replacement should be applied.
* This is ran before patches are registered, so if this returns false, the patch will never be registered.
*/
predicate?(): boolean; predicate?(): boolean;
/** The minimum build number for this patch to be applied */ /** The minimum build number for this patch to be applied */
fromBuild?: number; fromBuild?: number;

View file

@ -41,7 +41,7 @@ export const Switch = waitForComponent<t.Switch>("Switch", filters.componentByCo
const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", { const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", {
Tooltip: filters.componentByCode("this.renderTooltip()]"), Tooltip: filters.componentByCode("this.renderTooltip()]"),
TooltipContainer: filters.componentByCode('="div",') TooltipContainer: filters.componentByCode('="div"')
}) as { }) as {
Tooltip: t.Tooltip, Tooltip: t.Tooltip,
TooltipContainer: t.TooltipContainer; TooltipContainer: t.TooltipContainer;

View file

@ -12,8 +12,8 @@ import { canonicalizeReplacement } from "@utils/patches";
import { Patch, PatchReplacement } from "@utils/types"; import { Patch, PatchReplacement } from "@utils/types";
import { traceFunctionWithResults } from "../debug/Tracer"; import { traceFunctionWithResults } from "../debug/Tracer";
import { _blacklistBadModules, _initWebpack, factoryListeners, findModuleId, moduleListeners, waitForSubscriptions, wreq } from "./webpack"; import { _blacklistBadModules, _initWebpack, factoryListeners, findModuleFactory, moduleListeners, waitForSubscriptions, wreq } from "./webpack";
import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, ModuleExports, PatchedModuleFactory, WebpackRequire } from "./wreq.d"; import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, PatchedModuleFactory, WebpackRequire } from "./wreq.d";
export const patches = [] as Patch[]; export const patches = [] as Patch[];
@ -27,28 +27,26 @@ export const patchTimings = [] as Array<[plugin: string, moduleId: PropertyKey,
export const getBuildNumber = makeLazy(() => { export const getBuildNumber = makeLazy(() => {
try { try {
try { function matchBuildNumber(factoryStr: string) {
if (wreq.m[128014]?.toString().includes("Trying to open a changelog for an invalid build number")) { const buildNumberMatch = factoryStr.match(/.concat\("(\d+?)"\)/);
const hardcodedGetBuildNumber = wreq(128014).b as () => number; if (buildNumberMatch == null) {
return -1;
if (typeof hardcodedGetBuildNumber === "function" && typeof hardcodedGetBuildNumber() === "number") {
return hardcodedGetBuildNumber();
}
} }
} catch { }
const moduleId = findModuleId("Trying to open a changelog for an invalid build number"); return Number(buildNumberMatch[1]);
if (moduleId == null) {
return -1;
} }
const exports = Object.values<ModuleExports>(wreq(moduleId)); const hardcodedFactoryStr = String(wreq.m[128014]);
if (exports.length !== 1 || typeof exports[0] !== "function") { if (hardcodedFactoryStr.includes("Trying to open a changelog for an invalid build number")) {
return -1; const hardcodedBuildNumber = matchBuildNumber(hardcodedFactoryStr);
if (hardcodedBuildNumber !== -1) {
return hardcodedBuildNumber;
}
} }
const buildNumber = exports[0](); const moduleFactory = findModuleFactory("Trying to open a changelog for an invalid build number");
return typeof buildNumber === "number" ? buildNumber : -1; return matchBuildNumber(String(moduleFactory));
} catch { } catch {
return -1; return -1;
} }
@ -122,12 +120,12 @@ define(Function.prototype, "m", {
return; return;
} }
patchThisInstance();
if (wreq == null && this.c != null) { if (wreq == null && this.c != null) {
logger.info("Main WebpackInstance found" + interpolateIfDefined` in ${fileName}` + ", initializing internal references to WebpackRequire"); logger.info("Main WebpackInstance found" + interpolateIfDefined` in ${fileName}` + ", initializing internal references to WebpackRequire");
_initWebpack(this as WebpackRequire); _initWebpack(this as WebpackRequire);
} }
patchThisInstance();
} }
}); });
@ -478,23 +476,23 @@ function patchFactory(moduleId: PropertyKey, originalFactory: AnyModuleFactory):
for (let i = 0; i < patches.length; i++) { for (let i = 0; i < patches.length; i++) {
const patch = patches[i]; const patch = patches[i];
const moduleMatches = typeof patch.find === "string" const buildNumber = getBuildNumber();
? code.includes(patch.find) const shouldCheckBuildNumber = buildNumber !== -1;
: (patch.find.global && (patch.find.lastIndex = 0), patch.find.test(code));
if (!moduleMatches) {
continue;
}
// Eager patches cannot retrieve the build number because this code runs before the module for it is loaded
const buildNumber = Settings.eagerPatches ? -1 : getBuildNumber();
const shouldCheckBuildNumber = !Settings.eagerPatches && buildNumber !== -1;
if ( if (
shouldCheckBuildNumber && shouldCheckBuildNumber &&
(patch.fromBuild != null && buildNumber < patch.fromBuild) || (patch.fromBuild != null && buildNumber < patch.fromBuild) ||
(patch.toBuild != null && buildNumber > patch.toBuild) (patch.toBuild != null && buildNumber > patch.toBuild)
) { ) {
patches.splice(i--, 1);
continue;
}
const moduleMatches = typeof patch.find === "string"
? code.includes(patch.find)
: (patch.find.global && (patch.find.lastIndex = 0), patch.find.test(code));
if (!moduleMatches) {
continue; continue;
} }
@ -536,7 +534,7 @@ function patchFactory(moduleId: PropertyKey, originalFactory: AnyModuleFactory):
} }
if (newCode === code) { if (newCode === code) {
if (!patch.noWarn) { if (!(patch.noWarn || replacement.noWarn)) {
logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${String(moduleId)}): ${replacement.match}`); logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${String(moduleId)}): ${replacement.match}`);
if (IS_DEV) { if (IS_DEV) {
logger.debug("Function Source:\n", code); logger.debug("Function Source:\n", code);