Merge branch 'dev'
This commit is contained in:
commit
96684e1aca
5 changed files with 251 additions and 5 deletions
|
|
@ -11,7 +11,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
### Extra included plugins
|
||||
|
||||
<details>
|
||||
<summary>192 additional plugins</summary>
|
||||
<summary>193 additional plugins</summary>
|
||||
|
||||
### All Platforms
|
||||
|
||||
|
|
@ -60,6 +60,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
- Equissant by SomeAspy & thororen
|
||||
- ExpandedUserTags by Cyn, TheSun, RyanCaoDev, LordElias, AutumnVN, hen
|
||||
- ExportContacts by dat_insanity
|
||||
- ExportMessages by veygax
|
||||
- FakeProfileThemesAndEffects by ryan
|
||||
- CopyProfileColors by Crxa
|
||||
- FastDeleteChannels by thororen
|
||||
|
|
|
|||
102
src/equicordplugins/equicordHelper/utils.tsx
Normal file
102
src/equicordplugins/equicordHelper/utils.tsx
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { showNotice } from "@api/Notices";
|
||||
import { Alerts, Toasts } from "@webpack/common";
|
||||
import { Settings } from "Vencord";
|
||||
|
||||
function showErrorToast(message: string) {
|
||||
Toasts.show({
|
||||
message,
|
||||
type: Toasts.Type.FAILURE,
|
||||
id: Toasts.genId(),
|
||||
options: {
|
||||
position: Toasts.Position.BOTTOM
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function restartPrompt(): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
Alerts.show({
|
||||
title: "Restart Required",
|
||||
body: (
|
||||
<>
|
||||
<p style={{ textAlign: "center" }}>
|
||||
Some plugins require a restart to fully disable.
|
||||
</p>
|
||||
<p style={{ textAlign: "center" }}>Would you like to restart now?</p>
|
||||
</>
|
||||
),
|
||||
confirmText: "Restart Now",
|
||||
cancelText: "Later",
|
||||
onConfirm: () => resolve(true),
|
||||
onCancel: () => resolve(false),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function toggleEnabled(name: string) {
|
||||
let restartNeeded = false;
|
||||
function onRestartNeeded() {
|
||||
restartNeeded = true;
|
||||
}
|
||||
|
||||
async function beforeReturn(settings: any, wasEnabled: boolean) {
|
||||
if (restartNeeded) {
|
||||
const confirmed = await restartPrompt();
|
||||
if (!confirmed) return false;
|
||||
|
||||
settings.enabled = !wasEnabled;
|
||||
location.reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const plugin = Vencord.Plugins.plugins[name];
|
||||
const settings = Settings.plugins[plugin.name];
|
||||
const isEnabled = () => settings.enabled ?? false;
|
||||
const wasEnabled = isEnabled();
|
||||
|
||||
if (!wasEnabled) {
|
||||
const { restartNeeded, failures } = Vencord.Plugins.startDependenciesRecursive(plugin);
|
||||
if (failures.length) {
|
||||
console.error(`Failed to start dependencies for ${plugin.name}: ${failures.join(", ")}`);
|
||||
showNotice("Failed to start dependencies: " + failures.join(", "), "Close", () => null);
|
||||
return false;
|
||||
} else if (restartNeeded) {
|
||||
settings.enabled = true;
|
||||
onRestartNeeded();
|
||||
return await beforeReturn(settings, wasEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.patches?.length) {
|
||||
onRestartNeeded();
|
||||
return await beforeReturn(settings, wasEnabled);
|
||||
}
|
||||
|
||||
if (wasEnabled && !plugin.started) {
|
||||
settings.enabled = !wasEnabled;
|
||||
return await beforeReturn(settings, wasEnabled);
|
||||
}
|
||||
|
||||
const result = wasEnabled ? Vencord.Plugins.stopPlugin(plugin) : Vencord.Plugins.startPlugin(plugin);
|
||||
|
||||
if (!result) {
|
||||
settings.enabled = false;
|
||||
const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`;
|
||||
console.error(msg);
|
||||
showErrorToast(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.enabled = !wasEnabled;
|
||||
return await beforeReturn(settings, wasEnabled);
|
||||
}
|
||||
113
src/equicordplugins/exportMessages/index.tsx
Normal file
113
src/equicordplugins/exportMessages/index.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { showItemInFolder } from "@utils/native";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { saveFile } from "@utils/web";
|
||||
import { Menu } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
openFileAfterExport: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Open the exported file in the default file handler after export",
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
function formatMessage(message: Message) {
|
||||
const { author } = message;
|
||||
const timestamp = new Date(message.timestamp.toString()).toLocaleString();
|
||||
|
||||
let content = `[${timestamp}] ${author.username}`;
|
||||
if (author.discriminator !== "0") {
|
||||
content += `#${author.discriminator}`;
|
||||
}
|
||||
content += `: ${message.content}`;
|
||||
|
||||
if (message.attachments?.length > 0) {
|
||||
content += "\n Attachments:";
|
||||
message.attachments.forEach(attachment => {
|
||||
content += `\n - ${attachment.filename} (${attachment.url})`;
|
||||
});
|
||||
}
|
||||
|
||||
if (message.embeds?.length > 0) {
|
||||
content += "\n Embeds:";
|
||||
message.embeds.forEach(embed => {
|
||||
if (embed.rawTitle) content += `\n Title: ${embed.rawTitle}`;
|
||||
if (embed.rawDescription) content += `\n Description: ${embed.rawDescription}`;
|
||||
if (embed.url) content += `\n URL: ${embed.url}`;
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
async function exportMessage(message: Message) {
|
||||
const timestamp = new Date(message.timestamp.toString()).toISOString().split("T")[0];
|
||||
const filename = `message-${message.id}-${timestamp}.txt`;
|
||||
|
||||
const content = formatMessage(message);
|
||||
|
||||
try {
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
const data = new TextEncoder().encode(content);
|
||||
const result = await DiscordNative.fileManager.saveWithDialog(data, filename);
|
||||
|
||||
if (result && settings.store.openFileAfterExport) {
|
||||
showItemInFolder(result);
|
||||
}
|
||||
} else {
|
||||
const file = new File([content], filename, { type: "text/plain" });
|
||||
saveFile(file);
|
||||
}
|
||||
|
||||
showNotification({
|
||||
title: "Export Messages",
|
||||
body: `Message exported successfully as ${filename}`,
|
||||
icon: "📄"
|
||||
});
|
||||
} catch (error) {
|
||||
showNotification({
|
||||
title: "Export Messages",
|
||||
body: "Failed to export message",
|
||||
icon: "❌"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const messageContextMenuPatch = (children: Array<React.ReactElement<any> | null>, props: { message: Message; }) => {
|
||||
const { message } = props;
|
||||
|
||||
if (!message) return;
|
||||
|
||||
children.push(
|
||||
<Menu.MenuItem
|
||||
id="export-message"
|
||||
label="Export Message"
|
||||
icon={() => (
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" />
|
||||
</svg>
|
||||
)}
|
||||
action={() => exportMessage(message)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "ExportMessages",
|
||||
description: "Allows you to export any message to a file",
|
||||
authors: [EquicordDevs.veygax],
|
||||
settings,
|
||||
contextMenus: {
|
||||
"message": messageContextMenuPatch
|
||||
}
|
||||
});
|
||||
|
|
@ -22,6 +22,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
|||
import { Flex } from "@components/Flex";
|
||||
import { Link } from "@components/Link";
|
||||
import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
|
||||
import { toggleEnabled } from "@equicordplugins/equicordHelper/utils";
|
||||
import { CONTRIB_ROLE_ID, Devs, DONOR_ROLE_ID, EQUCORD_HELPERS, EQUIBOP_CONTRIB_ROLE_ID, EQUICORD_TEAM, GUILD_ID, SUPPORT_CHANNEL_ID, SUPPORT_CHANNEL_IDS, VC_CONTRIB_ROLE_ID, VC_DONOR_ROLE_ID, VC_GUILD_ID, VC_REGULAR_ROLE_ID, VC_SUPPORT_CHANNEL_IDS, VENCORD_CONTRIB_ROLE_ID } from "@utils/constants";
|
||||
import { sendMessage } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
|
@ -295,11 +296,14 @@ export default definePlugin({
|
|||
|
||||
const shouldAddUpdateButton =
|
||||
!IS_UPDATER_DISABLED
|
||||
&& (
|
||||
(props.channel.id === SUPPORT_CHANNEL_ID && equicordSupport)
|
||||
)
|
||||
&& ((props.channel.id === SUPPORT_CHANNEL_ID && equicordSupport))
|
||||
&& props.message.content?.includes("update");
|
||||
|
||||
const matchedPlugins = Object.keys(Vencord.Plugins.plugins).filter(name => (props.message.content?.toLowerCase() ?? "").includes(name.toLowerCase()));
|
||||
const matchedPlugin = matchedPlugins.sort((a, b) => b.length - a.length)[0];
|
||||
const equicordGuild = ChannelStore.getChannel(props.channel.id)?.guild_id === GUILD_ID;
|
||||
const shouldAddPluginButtons = equicordGuild && equicordSupport && matchedPlugin;
|
||||
|
||||
if (shouldAddUpdateButton) {
|
||||
buttons.push(
|
||||
<Button
|
||||
|
|
@ -322,6 +326,28 @@ export default definePlugin({
|
|||
);
|
||||
}
|
||||
|
||||
if (shouldAddPluginButtons && matchedPlugin) {
|
||||
const isEnabled = Vencord.Plugins.isPluginEnabled(matchedPlugin);
|
||||
|
||||
buttons.push(
|
||||
<Button
|
||||
key="vc-plugin-toggle"
|
||||
color={isEnabled ? Button.Colors.RED : Button.Colors.GREEN}
|
||||
onClick={async () => {
|
||||
try {
|
||||
const success = await toggleEnabled(matchedPlugin);
|
||||
if (success) showToast(`${isEnabled ? "Disabled" : "Enabled"} ${matchedPlugin}`, Toasts.Type.SUCCESS);
|
||||
} catch (e) {
|
||||
new Logger(this.name).error("Error while toggling:", e);
|
||||
showToast(`Failed to toggle ${matchedPlugin}`, Toasts.Type.FAILURE);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{`${isEnabled ? "Disable" : "Enable"} ${matchedPlugin}`}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
if (props.channel.id === SUPPORT_CHANNEL_ID && PermissionStore.can(PermissionsBits.SEND_MESSAGES, props.channel)) {
|
||||
if (props.message.content.includes("/equicord-debug") || props.message.content.includes("/equicord-plugins")) {
|
||||
buttons.push(
|
||||
|
|
@ -382,7 +408,7 @@ export default definePlugin({
|
|||
<Card className={`vc-plugins-restart-card ${Margins.top8}`}>
|
||||
Please do not private message plugin developers for support!
|
||||
<br />
|
||||
Instead, use the support channel: {Parser.parse("https://discord.com/channels/1173279886065029291/1173342942858055721")}
|
||||
Instead, use the support channel: {Parser.parse("https://discord.com/channels/1173279886065029291/1297590739911573585")}
|
||||
{!ChannelStore.getChannel(SUPPORT_CHANNEL_ID) && " (Click the link to join)"}
|
||||
</Card>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1096,6 +1096,10 @@ export const EquicordDevs = Object.freeze({
|
|||
name: "Suffocate",
|
||||
id: 772601756776923187n
|
||||
},
|
||||
veygax: {
|
||||
name: "veygax",
|
||||
id: 1119938236245094521n
|
||||
}
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
// iife so #__PURE__ works correctly
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue