Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
thororen1234 2026-04-23 07:50:05 -04:00
commit 93290c2e19
No known key found for this signature in database
11 changed files with 116 additions and 53 deletions

View file

@ -1,7 +1,7 @@
{
"name": "equicord",
"private": "true",
"version": "1.14.7.1",
"version": "1.14.9.0",
"description": "The other cutest Discord client mod",
"homepage": "https://github.com/Equicord/Equicord#readme",
"bugs": {

View file

@ -131,6 +131,8 @@ interface ContextMenuProps {
}
export function _usePatchContextMenu(props: ContextMenuProps) {
if (!Menu.MenuItem) return props; // Prevent crashes in case we fail to acquire menu items for some reason
props = {
...props,
children: cloneMenuChildren(props.children),

View file

@ -7,6 +7,7 @@
import { Devs } from "@utils/constants";
import { canonicalizeMatch } from "@utils/patches";
import definePlugin from "@utils/types";
import { Menu } from "@webpack/common";
// duplicate values have multiple branches with different types. Just include all to be safe
const nameMap = {
@ -31,38 +32,40 @@ export default definePlugin({
{
find: "Menu API only allows Items",
replacement: {
match: /function.{0,80}type===(\i\.\i)\).{0,50}navigable:.+?Menu API/s,
replace: (m, mod) => {
const nameAssignments = [] as string[];
match: /(?<=(\(\i\.type===(\i\.\i)\).{0,50}?navigable:.+Menu API).+?)}$/s,
replace: (_, m) => {
const registerCalls = [] as string[];
// if (t.type === m.MenuItem)
const typeCheckRe = canonicalizeMatch(/\(\i\.type===(\i\.\i)\)/g);
// push({type:"item"})
const pushTypeRe = /type:"(\w+)"/g;
const typeCheckRe = canonicalizeMatch(/\(\i\.type===(\i\.\i)\)/g); // if (t.type === m.MenuItem)
const pushTypeRe = /type:"(\w+)"/g; // push({type:"item"})
let typeMatch: RegExpExecArray | null;
// for each if (t.type === ...)
while ((typeMatch = typeCheckRe.exec(m)) !== null) {
// extract the current menu item
const item = typeMatch[1];
const component = typeMatch[1];
// Set the starting index of the second regex to that of the first to start
// matching from after the if
pushTypeRe.lastIndex = typeCheckRe.lastIndex;
// extract the first type: "..."
const type = pushTypeRe.exec(m)?.[1];
if (type && type in nameMap) {
const name = nameMap[type];
nameAssignments.push(`Object.defineProperty(${item},"name",{value:"${name}"})`);
registerCalls.push(`$self.registerMenuItem("${name}",${component})`);
}
}
if (nameAssignments.length < 6) {
console.warn("[MenuItemDemanglerAPI] Expected to at least remap 6 items, only remapped", nameAssignments.length);
if (registerCalls.length < 6) {
console.warn("[MenuItemDemanglerAPI] Expected to remap 6 items, only remapped", registerCalls.length);
}
// Merge all our redefines with the actual module
return `${nameAssignments.join(";")};${m}`;
return `${registerCalls.join(";")};}`;
},
},
},
],
registerMenuItem(name: string, component: any) {
Object.defineProperty(component, "name", { value: name });
Menu[name] = component;
}
});

View file

@ -86,14 +86,14 @@ export default definePlugin({
// It has everything it needs preloaded, so, it doesn't include any chunk loading functionality.
// Because of that, its WebpackInstance doesnt export wreq.m or wreq.c
// To circuvent this and disable Sentry we are gonna hook when wreq.g of its WebpackInstance is set.
// To circuvent this and disable Sentry we are gonna hook when wreq.d of its WebpackInstance is set.
// When that happens we are gonna forcefully throw an error and abort everything.
Object.defineProperty(Function.prototype, "g", {
Object.defineProperty(Function.prototype, "d", {
configurable: true,
set(this: WebpackRequire, globalObj: WebpackRequire["g"]) {
Object.defineProperty(this, "g", {
value: globalObj,
set(this: WebpackRequire, esmDeclareFunc: WebpackRequire["d"]) {
Object.defineProperty(this, "d", {
value: esmDeclareFunc,
configurable: true,
enumerable: true,
writable: true
@ -123,7 +123,7 @@ export default definePlugin({
new Logger("NoTrack", "#8caaee").info("Disabling Sentry by erroring its WebpackInstance");
Reflect.deleteProperty(Function.prototype, "g");
Reflect.deleteProperty(Function.prototype, "d");
Reflect.deleteProperty(window, "DiscordSentry");
throw new Error("Sentry successfully disabled");
@ -136,7 +136,7 @@ export default definePlugin({
set() {
new Logger("NoTrack", "#8caaee").error("Failed to disable Sentry. Falling back to deleting window.DiscordSentry");
Reflect.deleteProperty(Function.prototype, "g");
Reflect.deleteProperty(Function.prototype, "d");
Reflect.deleteProperty(window, "DiscordSentry");
}
});

View file

@ -127,7 +127,7 @@ export default definePlugin({
replace: "$&.replace(/^./, c => c.toUpperCase())"
},
{
match: /"text-xxs\/normal".{0,300}?(?=null!=(\i)&&(.{0,20}\i\.Text.{0,200}?,children:).{0,15}?("span"),({className:\i\.\i,children:\["Build Override: ",\1\.id\]\})\)\}\))/,
match: /"text-xxs\/normal".{0,300}?(?=null!=(\i)&&(.{0,20}\i\.\i.{0,200}?,children:).{0,15}?("span"),({className:\i\.\i,children:\["Build Override: ",\1\.id\]\})\)\}\))/,
replace: (m, _buildOverride, makeRow, component, props) => {
props = props.replace(/children:\[.+\]/, "");
return `${m},$self.makeInfoElements(${component},${props}).map(e=>${makeRow}e})),`;

View file

@ -45,7 +45,7 @@ export default definePlugin({
{
find: ".selectPreviousCommandOption(",
replacement: {
match: /(?<=(\i)\.(?:key|which)!==\i\.\i.ENTER\|\|).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=\|\|\(\i\.preventDefault)/,
match: /(?<=(\i)\.key!==\i\.\i.ENTER\|\|).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=\|\|\(\i\.preventDefault)/,
replace: "!$self.shouldSubmit($1,$2)"
}
},

View file

@ -171,6 +171,7 @@ function makeBypassPatches(): Omit<Patch, "plugin"> {
replacement: mapping.map(({ func, predicate }) => ({
match: new RegExp(String.raw`(?<=${func}:)\i`),
replace: "() => true",
noWarn: true,
predicate
}))
};
@ -186,8 +187,36 @@ export default definePlugin({
settings,
patches: [
// General bypass patches
// TODO: remove
makeBypassPatches(),
{
find: "canUseCustomStickersEverywhere:",
replacement: [
{
match: /(?<=canUseCustomStickersEverywhere:function\(\i\)\{)/,
replace: "return true;",
predicate: () => settings.store.enableStickerBypass
},
{
match: /(?<=canUseHighVideoUploadQuality:function\(\i\)\{)/,
replace: "return true;",
predicate: () => settings.store.enableStreamQualityBypass
},
{
match: /(?<=canStreamQuality:function\(\i,\i\)\{)/,
replace: "return true;",
predicate: () => settings.store.enableStreamQualityBypass
},
{
match: /(?<=canUseClientThemes:function\(\i\)\{)/,
replace: "return true;"
},
{
match: /(?<=canUsePremiumAppIcons:function\(\i\)\{)/,
replace: "return true;"
}
],
},
// Patch the emoji picker in voice calls to not be bypassed by fake nitro
{
find: '.getByName("fork_and_knife")',
@ -260,8 +289,13 @@ export default definePlugin({
replacement: [
{
// Overwrite incoming connection settings proto with our local settings
match: /(?<=CONNECTION_OPEN:function\((\i)\){)/,
replace: (_, props) => `$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
},
{
match: /function (\i)\((\i)\){(?=.*CONNECTION_OPEN:\1)/,
replace: (m, funcName, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
replace: (m, funcName, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`,
noWarn: true
},
{
// Overwrite non local proto changes with our local settings
@ -358,7 +392,7 @@ export default definePlugin({
predicate: () => settings.store.transformEmojis,
replacement: {
// Add the fake nitro emoji notice
match: /(?<=emojiDescription:)(\i)(?<=\1=\i\((\i)\).+?)/,
match: /(?<=emojiDescription:)(\i)(?<=\1=\(\i=>\{.+?\}\)\((\i)\)[,;].+?)/,
replace: (_, reactNode, props) => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!${props}?.fakeNitroNode?.fake)`
}
},

View file

@ -667,11 +667,20 @@ export default definePlugin({
patches: [
{
// MessageStore
find: '"MessageStore"',
replacement: [
{
// Add deleted=true to all target messages in the MESSAGE_DELETE event
match: /(?<=MESSAGE_DELETE:function\((\i)\)\{)(?=let.{0,100}(\i\.\i)\.getOrCreate)/,
replace: `
let cache = $2.getOrCreate($1.channelId);
cache = $self.handleDelete(cache, $1, false);
$2.commit(cache);
return;
`
},
{
noWarn: true,
match: /function (?=.+?MESSAGE_DELETE:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
replace:
"function $1($2){" +
@ -682,7 +691,17 @@ export default definePlugin({
},
{
// Add deleted=true to all target messages in the MESSAGE_DELETE_BULK event
match: /(?<=MESSAGE_DELETE_BULK:function\((\i)\){)(?=let.{0,100}(\i\.\i)\.getOrCreate)/,
replace: `
let cache = $2.getOrCreate($1.channelId);
cache = $self.handleDelete(cache, $1, true);
$2.commit(cache);
return;
`
},
{
match: /function (?=.+?MESSAGE_DELETE_BULK:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
noWarn: true,
replace:
"function $1($2){" +
" var cache = $3getOrCreate($2.channelId);" +
@ -692,6 +711,20 @@ export default definePlugin({
},
{
// Add current cached content + new edit time to cached message's editHistory
match: /(MESSAGE_UPDATE:function\((\i)\).+?)\.update\((\i)/,
replace: `
$1
.update($3, m =>
(($2.message.flags & 64) === 64 || $self.shouldIgnore($2.message, true)) ? m :
$2.message.edited_timestamp && $2.message.content !== m.content ?
m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :
m
)
.update($3
`
},
{
noWarn: true,
match: /(function (\i)\((\i)\).+?)\.update\((\i)(?=.*MESSAGE_UPDATE:\2)/,
replace: "$1" +
".update($4,m =>" +
@ -813,13 +846,23 @@ export default definePlugin({
// ReferencedMessageStore
find: '"ReferencedMessageStore"',
replacement: [
{
match: /(?<=MESSAGE_DELETE:function\(\i\)\{)/,
replace: "return;"
},
{
match: /(?<=MESSAGE_DELETE_BULK:function\(\i\)\{)/,
replace: "return;"
},
{
match: /MESSAGE_DELETE:\i,/,
replace: "MESSAGE_DELETE:()=>{},"
replace: "MESSAGE_DELETE:()=>{},",
noWarn: true
},
{
match: /MESSAGE_DELETE_BULK:\i,/,
replace: "MESSAGE_DELETE_BULK:()=>{},"
replace: "MESSAGE_DELETE_BULK:()=>{},",
noWarn: true
}
]
},

View file

@ -38,7 +38,7 @@ const settings = definePluginSettings({
export default definePlugin({
name: "SpotifyCrack",
description: "Free listen along, no auto-pausing in voice chat, and allows activity to continue playing when idling",
tags: ["Media", "Utility"],
tags: ["Media", "Utility", "Activity"],
authors: [Devs.Cyn, Devs.Nuckyz],
settings,

View file

@ -28,7 +28,7 @@ import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, useEffect, use
let Scroll: any = null;
const queue = new Queue();
let reactions: Record<string, ReactionCacheEntry>;
let reactions: Record<string, ReactionCacheEntry> = {};
function fetchReactions(msg: Message, emoji: ReactionEmoji, type: number) {
const key = emoji.name + (emoji.id ? `:${emoji.id}` : "");

View file

@ -17,29 +17,10 @@
*/
import type * as t from "@vencord/discord-types";
import { filters, mapMangledModuleLazy, waitFor, wreq } from "@webpack";
import { filters, mapMangledModuleLazy, waitFor } from "@webpack";
export const Menu = {} as t.Menu;
// Relies on .name properties added by the MenuItemDemanglerAPI
waitFor(m => m.name === "MenuCheckboxItem", (_, id) => {
// We have to do this manual require by ID because m in this case is the MenuCheckBoxItem instead of the entire module
const exports = wreq(id);
for (const exportKey in exports) {
// Some exports might have not been initialized yet due to circular imports, so try catch it.
try {
var exportValue = exports[exportKey];
} catch {
continue;
}
if (typeof exportValue === "function" && exportValue.name.startsWith("Menu")) {
Menu[exportValue.name] = exportValue;
}
}
});
waitFor(filters.componentByCode('path:["empty"]'), m => Menu.Menu = m);
waitFor(filters.componentByCode("SLIDER)", "handleSize:16"), m => Menu.MenuSliderControl = m);
waitFor(filters.componentByCode(".SEARCH)", ".focus()", "query:"), m => Menu.MenuSearchControl = m);