)` +
- `${settings.additionalInfo} - ${Intl.DateTimeFormat("en-GB", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
- Client: `${RELEASE_CHANNEL} ~ ${client}`,
- Platform: window.navigator.platform
- };
-
- if (IS_DISCORD_DESKTOP) {
- info["Last Crash Reason"] = (await DiscordNative.processUtils.getLastCrash())?.rendererCrashReason ?? "N/A";
- }
-
- const debugInfo = `
->>> ${Object.entries(info).map(([k, v]) => `**${k}**: ${v}`).join("\n")}
-
-Enabled Plugins (${enabledPlugins.length}):
-${makeCodeblock(enabledPlugins.join(", "))}
-`;
-
- return {
- content: debugInfo.trim().replaceAll("```\n", "```")
- };
+ commands: [
+ {
+ name: "vencord-debug",
+ description: "Send Vencord debug info",
+ predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
+ execute: async () => ({ content: await generateDebugInfoMessage() })
+ },
+ {
+ name: "vencord-plugins",
+ description: "Send Vencord plugin list",
+ predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
+ execute: () => ({ content: generatePluginList() })
}
- }],
+ ],
flux: {
async CHANNEL_SELECT({ channelId }) {
@@ -115,24 +169,25 @@ ${makeCodeblock(enabledPlugins.join(", "))}
const selfId = UserStore.getCurrentUser()?.id;
if (!selfId || isPluginDev(selfId)) return;
- if (isOutdated) {
- return Alerts.show({
- title: "Hold on!",
- body:
- You are using an outdated version of Vencord! Chances are, your issue is already fixed.
-
- Please first update before asking for support!
-
-
,
- onCancel: () => openUpdaterModal!(),
- cancelText: "View Updates",
- confirmText: "Update & Restart Now",
- async onConfirm() {
- await update();
- relaunch();
- },
- secondaryConfirmText: "I know what I'm doing or I can't update"
- });
+ if (!IS_UPDATER_DISABLED) {
+ await checkForUpdatesOnce().catch(() => { });
+
+ if (isOutdated) {
+ return Alerts.show({
+ title: "Hold on!",
+ body:
+ You are using an outdated version of Vencord! Chances are, your issue is already fixed.
+
+ Please first update before asking for support!
+
+
,
+ onCancel: () => openUpdaterModal!(),
+ cancelText: "View Updates",
+ confirmText: "Update & Restart Now",
+ onConfirm: forceUpdate,
+ secondaryConfirmText: "I know what I'm doing or I can't update"
+ });
+ }
}
// @ts-ignore outdated type
@@ -148,8 +203,7 @@ ${makeCodeblock(enabledPlugins.join(", "))}
Please either switch to an officially supported version of Vencord, or
contact your package maintainer for support instead.
- ,
- onCloseCallback: () => setTimeout(() => NavigationRouter.back(), 50)
+
});
}
@@ -163,8 +217,7 @@ ${makeCodeblock(enabledPlugins.join(", "))}
Please either switch to an officially supported version of Vencord, or
contact your package maintainer for support instead.
- ,
- onCloseCallback: () => setTimeout(() => NavigationRouter.back(), 50)
+
});
}
}
@@ -172,7 +225,7 @@ ${makeCodeblock(enabledPlugins.join(", "))}
ContributorDmWarningCard: ErrorBoundary.wrap(({ userId }) => {
if (!isPluginDev(userId)) return null;
- if (RelationshipStore.isFriend(userId)) return null;
+ if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
return (
@@ -182,5 +235,86 @@ ${makeCodeblock(enabledPlugins.join(", "))}
{!ChannelStore.getChannel(SUPPORT_CHANNEL_ID) && " (Click the link to join)"}
);
- }, { noop: true })
+ }, { noop: true }),
+
+ start() {
+ addAccessory("vencord-debug", props => {
+ const buttons = [] as JSX.Element[];
+
+ const shouldAddUpdateButton =
+ !IS_UPDATER_DISABLED
+ && (
+ (props.channel.id === KNOWN_ISSUES_CHANNEL_ID) ||
+ (props.channel.id === SUPPORT_CHANNEL_ID && props.message.author.id === VENBOT_USER_ID)
+ )
+ && props.message.content?.includes("update");
+
+ if (shouldAddUpdateButton) {
+ buttons.push(
+
+ );
+ }
+
+ if (props.channel.id === SUPPORT_CHANNEL_ID) {
+ if (props.message.content.includes("/vencord-debug") || props.message.content.includes("/vencord-plugins")) {
+ buttons.push(
+ ,
+
+ );
+ }
+
+ if (props.message.author.id === VENBOT_USER_ID) {
+ const match = CodeBlockRe.exec(props.message.content || props.message.embeds[0]?.rawDescription || "");
+ if (match) {
+ buttons.push(
+
+ );
+ }
+ }
+ }
+
+ return buttons.length
+ ? {buttons}
+ : null;
+ });
+ },
});
diff --git a/src/plugins/index.ts b/src/plugins/index.ts
index 29420d0c0..9268051ff 100644
--- a/src/plugins/index.ts
+++ b/src/plugins/index.ts
@@ -169,7 +169,18 @@ export function subscribePluginFluxEvents(p: Plugin, fluxDispatcher: typeof Flux
logger.debug("Subscribing to flux events of plugin", p.name);
for (const [event, handler] of Object.entries(p.flux)) {
- fluxDispatcher.subscribe(event as FluxEvents, handler);
+ const wrappedHandler = p.flux[event] = function () {
+ try {
+ const res = handler.apply(p, arguments as any);
+ return res instanceof Promise
+ ? res.catch(e => logger.error(`${p.name}: Error while handling ${event}\n`, e))
+ : res;
+ } catch (e) {
+ logger.error(`${p.name}: Error while handling ${event}\n`, e);
+ }
+ };
+
+ fluxDispatcher.subscribe(event as FluxEvents, wrappedHandler);
}
}
}
diff --git a/src/plugins/seeSummaries/index.tsx b/src/plugins/seeSummaries/index.tsx
index 9654c8684..a08393194 100644
--- a/src/plugins/seeSummaries/index.tsx
+++ b/src/plugins/seeSummaries/index.tsx
@@ -12,7 +12,7 @@ import { findByCode, findByProps } from "@webpack";
import { ChannelStore, GuildStore } from "@webpack/common";
const SummaryStore = findByProps("allSummaries", "findSummary");
-const createSummaryFromServer = findByCode(".people)),startId:");
+const createSummaryFromServer = findByCode(".people)),startId:", ".type}");
const settings = definePluginSettings({
summaryExpiryThresholdDays: {
diff --git a/src/plugins/xsOverlay.desktop/index.ts b/src/plugins/xsOverlay.desktop/index.ts
index 75e942cba..2e28365d4 100644
--- a/src/plugins/xsOverlay.desktop/index.ts
+++ b/src/plugins/xsOverlay.desktop/index.ts
@@ -154,104 +154,99 @@ export default definePlugin({
}
},
MESSAGE_CREATE({ message, optimistic }: { message: Message; optimistic: boolean; }) {
- // Apparently without this try/catch, discord's socket connection dies if any part of this errors
- try {
- if (optimistic) return;
- const channel = ChannelStore.getChannel(message.channel_id);
- if (!shouldNotify(message, message.channel_id)) return;
+ if (optimistic) return;
+ const channel = ChannelStore.getChannel(message.channel_id);
+ if (!shouldNotify(message, message.channel_id)) return;
- const pingColor = settings.store.pingColor.replaceAll("#", "").trim();
- const channelPingColor = settings.store.channelPingColor.replaceAll("#", "").trim();
- let finalMsg = message.content;
- let titleString = "";
+ const pingColor = settings.store.pingColor.replaceAll("#", "").trim();
+ const channelPingColor = settings.store.channelPingColor.replaceAll("#", "").trim();
+ let finalMsg = message.content;
+ let titleString = "";
- if (channel.guild_id) {
- const guild = GuildStore.getGuild(channel.guild_id);
- titleString = `${message.author.username} (${guild.name}, #${channel.name})`;
- }
-
-
- switch (channel.type) {
- case ChannelTypes.DM:
- titleString = message.author.username.trim();
- break;
- case ChannelTypes.GROUP_DM:
- const channelName = channel.name.trim() ?? channel.rawRecipients.map(e => e.username).join(", ");
- titleString = `${message.author.username} (${channelName})`;
- break;
- }
-
- if (message.referenced_message) {
- titleString += " (reply)";
- }
-
- if (message.embeds.length > 0) {
- finalMsg += " [embed] ";
- if (message.content === "") {
- finalMsg = "sent message embed(s)";
- }
- }
-
- if (message.sticker_items) {
- finalMsg += " [sticker] ";
- if (message.content === "") {
- finalMsg = "sent a sticker";
- }
- }
-
- const images = message.attachments.filter(e =>
- typeof e?.content_type === "string"
- && e?.content_type.startsWith("image")
- );
-
-
- images.forEach(img => {
- finalMsg += ` [image: ${img.filename}] `;
- });
-
- message.attachments.filter(a => a && !a.content_type?.startsWith("image")).forEach(a => {
- finalMsg += ` [attachment: ${a.filename}] `;
- });
-
- // make mentions readable
- if (message.mentions.length > 0) {
- finalMsg = finalMsg.replace(/<@!?(\d{17,20})>/g, (_, id) => `@${UserStore.getUser(id)?.username || "unknown-user"}`);
- }
-
- // color role mentions (unity styling btw lol)
- if (message.mention_roles.length > 0) {
- for (const roleId of message.mention_roles) {
- const role = GuildStore.getRole(channel.guild_id, roleId);
- if (!role) continue;
- const roleColor = role.colorString ?? `#${pingColor}`;
- finalMsg = finalMsg.replace(`<@&${roleId}>`, `@${role.name}`);
- }
- }
-
- // make emotes and channel mentions readable
- const emoteMatches = finalMsg.match(new RegExp("()", "g"));
- const channelMatches = finalMsg.match(new RegExp("<(#\\d+)>", "g"));
-
- if (emoteMatches) {
- for (const eMatch of emoteMatches) {
- finalMsg = finalMsg.replace(new RegExp(`${eMatch}`, "g"), `:${eMatch.split(":")[1]}:`);
- }
- }
-
- // color channel mentions
- if (channelMatches) {
- for (const cMatch of channelMatches) {
- let channelId = cMatch.split("<#")[1];
- channelId = channelId.substring(0, channelId.length - 1);
- finalMsg = finalMsg.replace(new RegExp(`${cMatch}`, "g"), `#${ChannelStore.getChannel(channelId).name}`);
- }
- }
-
- if (shouldIgnoreForChannelType(channel)) return;
- sendMsgNotif(titleString, finalMsg, message);
- } catch (err) {
- XSLog.error(`Failed to catch MESSAGE_CREATE: ${err}`);
+ if (channel.guild_id) {
+ const guild = GuildStore.getGuild(channel.guild_id);
+ titleString = `${message.author.username} (${guild.name}, #${channel.name})`;
}
+
+
+ switch (channel.type) {
+ case ChannelTypes.DM:
+ titleString = message.author.username.trim();
+ break;
+ case ChannelTypes.GROUP_DM:
+ const channelName = channel.name.trim() ?? channel.rawRecipients.map(e => e.username).join(", ");
+ titleString = `${message.author.username} (${channelName})`;
+ break;
+ }
+
+ if (message.referenced_message) {
+ titleString += " (reply)";
+ }
+
+ if (message.embeds.length > 0) {
+ finalMsg += " [embed] ";
+ if (message.content === "") {
+ finalMsg = "sent message embed(s)";
+ }
+ }
+
+ if (message.sticker_items) {
+ finalMsg += " [sticker] ";
+ if (message.content === "") {
+ finalMsg = "sent a sticker";
+ }
+ }
+
+ const images = message.attachments.filter(e =>
+ typeof e?.content_type === "string"
+ && e?.content_type.startsWith("image")
+ );
+
+
+ images.forEach(img => {
+ finalMsg += ` [image: ${img.filename}] `;
+ });
+
+ message.attachments.filter(a => a && !a.content_type?.startsWith("image")).forEach(a => {
+ finalMsg += ` [attachment: ${a.filename}] `;
+ });
+
+ // make mentions readable
+ if (message.mentions.length > 0) {
+ finalMsg = finalMsg.replace(/<@!?(\d{17,20})>/g, (_, id) => `@${UserStore.getUser(id)?.username || "unknown-user"}`);
+ }
+
+ // color role mentions (unity styling btw lol)
+ if (message.mention_roles.length > 0) {
+ for (const roleId of message.mention_roles) {
+ const role = GuildStore.getRole(channel.guild_id, roleId);
+ if (!role) continue;
+ const roleColor = role.colorString ?? `#${pingColor}`;
+ finalMsg = finalMsg.replace(`<@&${roleId}>`, `@${role.name}`);
+ }
+ }
+
+ // make emotes and channel mentions readable
+ const emoteMatches = finalMsg.match(new RegExp("()", "g"));
+ const channelMatches = finalMsg.match(new RegExp("<(#\\d+)>", "g"));
+
+ if (emoteMatches) {
+ for (const eMatch of emoteMatches) {
+ finalMsg = finalMsg.replace(new RegExp(`${eMatch}`, "g"), `:${eMatch.split(":")[1]}:`);
+ }
+ }
+
+ // color channel mentions
+ if (channelMatches) {
+ for (const cMatch of channelMatches) {
+ let channelId = cMatch.split("<#")[1];
+ channelId = channelId.substring(0, channelId.length - 1);
+ finalMsg = finalMsg.replace(new RegExp(`${cMatch}`, "g"), `#${ChannelStore.getChannel(channelId).name}`);
+ }
+ }
+
+ if (shouldIgnoreForChannelType(channel)) return;
+ sendMsgNotif(titleString, finalMsg, message);
}
}
});
diff --git a/src/utils/misc.tsx b/src/utils/misc.ts
similarity index 92%
rename from src/utils/misc.tsx
rename to src/utils/misc.ts
index fb08c93f6..7d6b4affc 100644
--- a/src/utils/misc.tsx
+++ b/src/utils/misc.ts
@@ -99,3 +99,14 @@ export const isPluginDev = (id: string) => Object.hasOwn(DevsById, id);
export function pluralise(amount: number, singular: string, plural = singular + "s") {
return amount === 1 ? `${amount} ${singular}` : `${amount} ${plural}`;
}
+
+export function tryOrElse(func: () => T, fallback: T): T {
+ try {
+ const res = func();
+ return res instanceof Promise
+ ? res.catch(() => fallback) as T
+ : res;
+ } catch {
+ return fallback;
+ }
+}
diff --git a/src/utils/text.ts b/src/utils/text.ts
index 63f600742..2e85af4ef 100644
--- a/src/utils/text.ts
+++ b/src/utils/text.ts
@@ -131,3 +131,18 @@ export function makeCodeblock(text: string, language?: string) {
const chars = "```";
return `${chars}${language || ""}\n${text.replaceAll("```", "\\`\\`\\`")}\n${chars}`;
}
+
+export function stripIndent(strings: TemplateStringsArray, ...values: any[]) {
+ const string = String.raw({ raw: strings }, ...values);
+
+ const match = string.match(/^[ \t]*(?=\S)/gm);
+ if (!match) return string.trim();
+
+ const minIndent = match.reduce((r, a) => Math.min(r, a.length), Infinity);
+ return string.replace(new RegExp(`^[ \\t]{${minIndent}}`, "gm"), "").trim();
+}
+
+export const ZWSP = "\u200b";
+export function toInlineCode(s: string) {
+ return "``" + ZWSP + s.replaceAll("`", ZWSP + "`" + ZWSP) + ZWSP + "``";
+}
diff --git a/src/utils/types.ts b/src/utils/types.ts
index a94c3f28f..6360f93ac 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -128,7 +128,7 @@ export interface PluginDef {
* Allows you to subscribe to Flux events
*/
flux?: {
- [E in FluxEvents]?: (event: any) => void;
+ [E in FluxEvents]?: (event: any) => void | Promise;
};
/**
* Allows you to manipulate context menus