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

This commit is contained in:
thororen1234 2025-01-31 13:44:46 -05:00
commit e4fcd54183
17 changed files with 86 additions and 133 deletions

View file

@ -16,6 +16,7 @@ export default definePlugin({
{
find: '"sticker")',
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(\i\.isDM.+?(\i)\.push)/,
replace: (m, not, children) => not
? `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),true)&&`

View file

@ -37,12 +37,9 @@ export default definePlugin({
{
find: ".handleSendMessage,onResize",
replacement: {
// props.chatInputType...then((function(isMessageValid)... var parsedMessage = b.c.parse(channel,... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply);
// Lookbehind: validateMessage)({openWarningPopout:..., type: i.props.chatInputType, content: t, stickers: r, ...}).then((function(isMessageValid)
match: /(\{openWarningPopout:.{0,100}type:this.props.chatInputType.+?\.then\()(\i=>\{.+?let (\i)=\i\.\i\.parse\((\i),.+?let (\i)=\i\.\i\.getSendMessageOptions\(\{.+?\}\);)(?<=\)\(({.+?})\)\.then.+?)/,
// props.chatInputType...then((async function(isMessageValid)... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply); if(await Vencord.api...) return { shoudClear:true, shouldRefocus:true };
replace: (_, rest1, rest2, parsedMessage, channel, replyOptions, extra) => "" +
`${rest1}async ${rest2}` +
// https://regex101.com/r/hBlXpl/1
match: /let (\i)=\i\.\i\.parse\((\i),.+?let (\i)=\i\.\i\.getSendMessageOptions\(\{.+?\}\);(?<=\)\(({.+?})\)\.then.+?)/,
replace: (m, parsedMessage, channel, replyOptions, extra) => m +
`if(await Vencord.Api.MessageEvents._handlePreSend(${channel}.id,${parsedMessage},${extra},${replyOptions}))` +
"return{shouldClear:false,shouldRefocus:true};"
}
@ -52,8 +49,7 @@ export default definePlugin({
replacement: {
match: /let\{id:\i}=(\i),{id:\i}=(\i);return \i\.useCallback\((\i)=>\{/,
replace: (m, message, channel, event) =>
// the message param is shadowed by the event param, so need to alias them
`const vcMsg=${message},vcChan=${channel};${m}Vencord.Api.MessageEvents._handleClick(vcMsg, vcChan, ${event});`
`const vcMsg=${message},vcChan=${channel};${m}Vencord.Api.MessageEvents._handleClick(vcMsg,vcChan,${event});`
}
}
]

View file

@ -64,6 +64,7 @@ export default definePlugin({
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
},
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?(?:function\(\){return |\(\)=>))\2/,
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
}

View file

@ -44,6 +44,7 @@ export default definePlugin({
{
find: ".selectPreviousCommandOption(",
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=(\i)\.which(?:!==|===)\i\.\i.ENTER(\|\||&&)).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=(?:\|\||&&)\(\i\.preventDefault)/,
replace: (_, event, condition, codeblock) => `${condition === "||" ? "!" : ""}$self.shouldSubmit(${event},${codeblock})`
}

View file

@ -264,6 +264,7 @@ export default definePlugin({
},
{
// Disallow the emoji for premium locked if the intention doesn't allow it
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?(\i\.\i\.canUseEmojisEverywhere\(\i\))/,
replace: (m, not) => not
? `(${m}&&!${IS_BYPASSEABLE_INTENTION})`

View file

@ -50,9 +50,9 @@ export default definePlugin({
{
find: "#{intl::FRIENDS_SECTION_ONLINE}",
replacement: {
match: /(\{id:\i\.\i\i)\.BLOCKED,.{0,150}(\i)\.item/,
replace: "$1.IMPLICIT,show:!0,content:\"Implicit\",className:$2.item},$&"
},
match: /,{id:(\i\.\i)\.BLOCKED,show:.+?className:(\i\.item)/,
replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}`
}
},
// Sections content
{

View file

@ -23,11 +23,11 @@ import definePlugin, { OptionType } from "@utils/types";
import { useMemo } from "@webpack/common";
// Calculate a CSS color string based on the user ID
function calculateNameColorForUser(id: string) {
function calculateNameColorForUser(id?: string) {
const { lightness } = settings.use(["lightness"]);
const idHash = useMemo(() => h64(id), [id]);
const idHash = useMemo(() => id ? h64(id) : null, [id]);
return `hsl(${idHash % 360n}, 100%, ${lightness}%)`;
return idHash && `hsl(${idHash % 360n}, 100%, ${lightness}%)`;
}
const settings = definePluginSettings({
@ -70,16 +70,10 @@ export default definePlugin({
calculateNameColorForMessageContext(context: any) {
const id = context?.message?.author?.id;
if (id == null) {
return null;
}
return calculateNameColorForUser(id);
},
calculateNameColorForListContext(context: any) {
const id = context?.user?.id;
if (id == null) {
return null;
}
return calculateNameColorForUser(id);
}
});

View file

@ -94,7 +94,7 @@ export default definePlugin({
settings,
async start() {
// TODO: Remove DataStore tags migration once enough time has passed
// TODO(OptionType.CUSTOM Related): Remove DataStore tags migration once enough time has passed
const oldTags = await DataStore.get<Tag[]>(DATA_KEY);
if (oldTags != null) {
// @ts-ignore

View file

@ -1,42 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { getUserSettingLazy } from "@api/UserSettings";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
const DisableStreamPreviews = getUserSettingLazy<boolean>("voiceAndVideo", "disableStreamPreviews")!;
// @TODO: Delete this plugin in the future
export default definePlugin({
name: "NoScreensharePreview",
description: "Disables screenshare previews from being sent.",
authors: [Devs.Nuckyz],
start() {
if (!DisableStreamPreviews.getSetting()) {
DisableStreamPreviews.updateSetting(true);
}
},
stop() {
if (DisableStreamPreviews.getSetting()) {
DisableStreamPreviews.updateSetting(false);
}
}
});

View file

@ -25,9 +25,9 @@ export default definePlugin({
settings,
patches: [
{
find: "_ensureAudio(){",
find: "ensureAudio(){",
replacement: {
match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/,
match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/g,
replace: "$self.settings.store.notificationVolume/100*"
},
},

View file

@ -100,6 +100,7 @@ export default definePlugin({
replace: "true"
},
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?\(0,\i\.isDesktop\)\(\)/,
replace: (_, not) => not ? "false" : "true"
}

View file

@ -46,6 +46,7 @@ export default definePlugin({
find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}",
replacement: [
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /{(?:\i:(?:function\(\){return |\(\)=>)\i}?,?){2}}/,
replace: m => m.replaceAll(canonicalizeMatch(/(function\(\){return |\(\)=>)\i/g), "$1()=>Promise.resolve(true)")
}

View file

@ -155,7 +155,7 @@ export function moveChannel(channelId: string, direction: -1 | 1) {
swapElementsInArray(category.channels, a, b);
}
// TODO: Remove DataStore PinnedDms migration once enough time has passed
// TODO(OptionType.CUSTOM Related): Remove DataStore PinnedDms migration once enough time has passed
async function migrateData() {
if (Settings.plugins.PinDMs.dmSectioncollapsed != null) {
settings.store.dmSectionCollapsed = Settings.plugins.PinDMs.dmSectioncollapsed;

View file

@ -122,6 +122,7 @@ export default definePlugin({
},
{
// Prevent Discord from trying to connect to hidden voice channels
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?=(\|\||&&)\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
replace: (_, condition, channel) => condition === "||"
? `||$self.isHiddenChannel(${channel})`
@ -138,6 +139,7 @@ export default definePlugin({
{
find: ".AUDIENCE),{isSubscriptionGated",
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
replace: (m, not, channel) => not
? `${m}&&!$self.isHiddenChannel(${channel})`
@ -204,6 +206,7 @@ export default definePlugin({
},
// Make voice channels also appear as muted if they are muted
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)(if\()?(\i)(?:\)return |\?)(\i\.MUTED)/,
replace: (_, otherClasses, isIf, isMuted, mutedClassExpression) => isIf
? `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""`
@ -222,6 +225,7 @@ export default definePlugin({
predicate: () => settings.store.channelStyle !== ChannelStyle.Unread && settings.store.channelStyle !== ChannelStyle.MutedUnread,
replacement: [
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=\.LOCKED(?:;if\(|:))(?<={channel:(\i).+?)/,
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
},

View file

@ -246,7 +246,7 @@ export default definePlugin({
},
async start() {
// TODO: Remove DataStore rules migrations once enough time has passed
// TODO(OptionType.CUSTOM Related): Remove DataStore rules migrations once enough time has passed
const oldStringRules = await DataStore.get<Rule[]>(STRING_RULES_KEY);
if (oldStringRules != null) {
settings.store.stringRules = oldStringRules;

View file

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { patches } from "@plugins";
import { WEBPACK_CHUNK } from "@utils/constants";
import { Logger } from "@utils/Logger";
import { canonicalizeReplacement } from "@utils/patches";
@ -25,7 +24,8 @@ import { reporterData } from "debug/reporterData";
import { WebpackInstance } from "discord-types/other";
import { traceFunction } from "../debug/Tracer";
import { _initWebpack, beforeInitListeners, factoryListeners, moduleListeners, subscriptions, wreq } from ".";
import { patches } from "../plugins";
import { _initWebpack, _shouldIgnoreModule, beforeInitListeners, factoryListeners, moduleListeners, subscriptions, wreq } from ".";
const logger = new Logger("WebpackInterceptor", "#8caaee");
@ -174,35 +174,9 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
if (!exports) return;
if (require.c) {
let shouldMakeNonEnumerable = false;
const shouldIgnoreModule = _shouldIgnoreModule(exports);
nonEnumerableChecking: {
// There are (at the time of writing) 11 modules exporting the window,
// and also modules exporting DOMTokenList, which breaks webpack finding
// Make these non enumerable to improve search performance and avoid erros
if (exports === window || exports[Symbol.toStringTag] === "DOMTokenList") {
shouldMakeNonEnumerable = true;
break nonEnumerableChecking;
}
if (typeof exports !== "object") {
break nonEnumerableChecking;
}
if (exports.default === window || exports.default?.[Symbol.toStringTag] === "DOMTokenList") {
shouldMakeNonEnumerable = true;
break nonEnumerableChecking;
}
for (const nested in exports) {
if (exports[nested] === window || exports[nested]?.[Symbol.toStringTag] === "DOMTokenList") {
shouldMakeNonEnumerable = true;
break nonEnumerableChecking;
}
}
}
if (shouldMakeNonEnumerable) {
if (shouldIgnoreModule) {
Object.defineProperty(require.c, id, {
value: require.c[id],
enumerable: false,
@ -227,17 +201,16 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
if (exports && filter(exports)) {
subscriptions.delete(filter);
callback(exports, id);
} else if (typeof exports === "object") {
if (exports.default && filter(exports.default)) {
}
if (typeof exports !== "object") {
continue;
}
for (const exportKey in exports) {
if (exports[exportKey] && filter(exports[exportKey])) {
subscriptions.delete(filter);
callback(exports.default, id);
} else {
for (const nested in exports) {
if (exports[nested] && filter(exports[nested])) {
subscriptions.delete(filter);
callback(exports[nested], id);
}
}
callback(exports[exportKey], id);
}
}
} catch (err) {

View file

@ -71,13 +71,16 @@ export const filters = {
componentByCode: (...code: CodeFilter): FilterFn => {
const filter = filters.byCode(...code);
return m => {
if (filter(m)) return true;
if (!m.$$typeof) return false;
if (m.type)
return m.type.render
? filter(m.type.render) // memo + forwardRef
: filter(m.type); // memo
if (m.render) return filter(m.render); // forwardRef
let inner = m;
while (inner != null) {
if (filter(inner)) return true;
else if (!inner.$$typeof) return false;
else if (inner.type) inner = inner.type; // memos
else if (inner.render) inner = inner.render; // forwardRefs
else return false;
}
return false;
};
}
@ -95,6 +98,38 @@ export function _initWebpack(webpackRequire: WebpackInstance) {
cache = webpackRequire.c;
}
// Credits to Zerebos for implementing this in BD, thus giving the idea for us to implement it too
const TypedArray = Object.getPrototypeOf(Int8Array);
function _shouldIgnoreValue(value: any) {
if (value == null) return true;
if (value === window) return true;
if (value === document || value === document.documentElement) return true;
if (value[Symbol.toStringTag] === "DOMTokenList") return true;
if (value instanceof TypedArray) return true;
return false;
}
export function _shouldIgnoreModule(exports: any) {
if (_shouldIgnoreValue(exports)) {
return true;
}
if (typeof exports !== "object") {
return false;
}
let allNonEnumerable = true;
for (const exportKey in exports) {
if (!_shouldIgnoreValue(exports[exportKey])) {
allNonEnumerable = false;
}
}
return allNonEnumerable;
}
let devToolsOpen = false;
if (IS_DEV && IS_DISCORD_DESKTOP) {
// At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed
@ -121,7 +156,7 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
for (const key in cache) {
const mod = cache[key];
if (!mod.loaded || !mod?.exports) continue;
if (!mod?.loaded || mod.exports == null) continue;
if (filter(mod.exports)) {
return isWaitFor ? [mod.exports, key] : mod.exports;
@ -129,11 +164,6 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
if (typeof mod.exports !== "object") continue;
if (mod.exports.default && filter(mod.exports.default)) {
const found = mod.exports.default;
return isWaitFor ? [found, key] : found;
}
for (const nestedMod in mod.exports) {
const nested = mod.exports[nestedMod];
if (nested && filter(nested)) {
@ -156,16 +186,15 @@ export function findAll(filter: FilterFn) {
const ret = [] as any[];
for (const key in cache) {
const mod = cache[key];
if (!mod.loaded || !mod?.exports) continue;
if (!mod?.loaded || mod.exports == null) continue;
if (filter(mod.exports))
ret.push(mod.exports);
else if (typeof mod.exports !== "object")
if (typeof mod.exports !== "object")
continue;
if (mod.exports.default && filter(mod.exports.default))
ret.push(mod.exports.default);
else for (const nestedMod in mod.exports) {
for (const nestedMod in mod.exports) {
const nested = mod.exports[nestedMod];
if (nested && filter(nested)) ret.push(nested);
}
@ -204,7 +233,7 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns
outer:
for (const key in cache) {
const mod = cache[key];
if (!mod.loaded || !mod?.exports) continue;
if (!mod?.loaded || mod.exports == null) continue;
for (let j = 0; j < length; j++) {
const filter = filters[j];
@ -221,13 +250,6 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns
if (typeof mod.exports !== "object")
continue;
if (mod.exports.default && filter(mod.exports.default)) {
results[j] = mod.exports.default;
filters[j] = undefined;
if (++found === length) break outer;
break;
}
for (const nestedMod in mod.exports) {
const nested = mod.exports[nestedMod];
if (nested && filter(nested)) {