From 3e7d9462961ba2d1291cb68b9d5618c46c568451 Mon Sep 17 00:00:00 2001 From: megumin Date: Thu, 30 Nov 2023 19:32:48 +0000 Subject: [PATCH 01/29] fix(SpotifyControls): Requests double-sending when using Spotify Connect (#2023) --- src/plugins/spotifyControls/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/spotifyControls/index.tsx b/src/plugins/spotifyControls/index.tsx index 829f7850..cfb352ef 100644 --- a/src/plugins/spotifyControls/index.tsx +++ b/src/plugins/spotifyControls/index.tsx @@ -55,13 +55,19 @@ export default definePlugin({ replace: "return [$self.renderPlayer(),$1]" } }, - // Adds POST and a Marker to the SpotifyAPI (so we can easily find it) { find: ".PLAYER_DEVICES", - replacement: { + replacement: [{ + // Adds POST and a Marker to the SpotifyAPI (so we can easily find it) match: /get:(\i)\.bind\(null,(\i\.\i)\.get\)/, replace: "post:$1.bind(null,$2.post),$&" - } + }, + { + // Spotify Connect API returns status 202 instead of 204 when skipping tracks. + // Discord rejects 202 which causes the request to send twice. This patch prevents this. + match: /202===\i\.status/, + replace: "false", + }] }, // Discord doesn't give you the repeat kind, only a boolean { From 80016180b612718e7a73b6a24169e8ccfec5e166 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:39:15 -0300 Subject: [PATCH 02/29] FixImagesQuality: no longer make gifs play when autoplay is off --- src/plugins/fixImagesQuality/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/fixImagesQuality/index.ts b/src/plugins/fixImagesQuality/index.ts index d94c8e3b..4acd9a92 100644 --- a/src/plugins/fixImagesQuality/index.ts +++ b/src/plugins/fixImagesQuality/index.ts @@ -14,10 +14,12 @@ export default definePlugin({ patches: [ { find: "handleImageLoad=", - replacement: { - match: /(?<=getSrc\(\i\){.+?format:)\i/, - replace: "null" - } + replacement: [ + { + match: /(?<=getSrc\(\i\){.+?return )\i\.SUPPORTS_WEBP.+?:(?=\i&&\(\i="png"\))/, + replace: "" + } + ] } ] }); From 9dd00fb766f6fdf74b037a76a16b43a0edf8866a Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:06:18 -0300 Subject: [PATCH 03/29] Fix SuperReactionTweaks patch --- src/plugins/superReactionTweaks/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/superReactionTweaks/index.ts b/src/plugins/superReactionTweaks/index.ts index 2652eef0..0e58eb0a 100644 --- a/src/plugins/superReactionTweaks/index.ts +++ b/src/plugins/superReactionTweaks/index.ts @@ -46,10 +46,10 @@ export default definePlugin({ } }, { - find: ".hasAvailableBurstCurrency)", + find: ".trackEmojiSearchEmpty,200", replacement: { - match: /(?<=\.useBurstReactionsExperiment.{0,20})useState\(!1\)(?=.+?(\i===\i\.EmojiIntention.REACTION))/, - replace: "useState($self.settings.store.superReactByDefault && $1)" + match: /(\.trackEmojiSearchEmpty,200(?=.+?isBurstReaction:(\i).+?(\i===\i\.EmojiIntention.REACTION)).+?\[\2,\i\]=\i\.useState\().+?\)/, + replace: (_, rest, isBurstReactionVariable, isReactionIntention) => `${rest}$self.settings.store.superReactByDefault&&${isReactionIntention})` } } ], From 08036f7af28dba4978abed93f9a7b6af5cf979cb Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 6 Dec 2023 01:37:42 -0300 Subject: [PATCH 04/29] convert non lazy finds to test with reporter --- src/plugins/muteNewGuild/index.tsx | 6 ++++-- src/plugins/webContextMenus.web/index.ts | 6 +++--- src/utils/modal.tsx | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugins/muteNewGuild/index.tsx b/src/plugins/muteNewGuild/index.tsx index 7586830b..08c558a9 100644 --- a/src/plugins/muteNewGuild/index.tsx +++ b/src/plugins/muteNewGuild/index.tsx @@ -19,7 +19,9 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { findByProps } from "@webpack"; +import { findByPropsLazy } from "@webpack"; + +const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings"); const settings = definePluginSettings({ guild: { @@ -63,7 +65,7 @@ export default definePlugin({ handleMute(guildId: string | null) { if (guildId === "@me" || guildId === "null" || guildId == null) return; - findByProps("updateGuildNotificationSettings").updateGuildNotificationSettings(guildId, + updateGuildNotificationSettings(guildId, { muted: settings.store.guild, suppress_everyone: settings.store.everyone, diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index cf50bb86..eb076dfd 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -20,9 +20,11 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { saveFile } from "@utils/web"; -import { findByProps } from "@webpack"; +import { findByPropsLazy } from "@webpack"; import { Clipboard, ComponentDispatch } from "@webpack/common"; +const ctxMenuCallbacks = findByPropsLazy("contextMenuCallbackNative"); + async function fetchImage(url: string) { const res = await fetch(url); if (res.status !== 200) return; @@ -55,7 +57,6 @@ export default definePlugin({ start() { if (settings.store.addBack) { - const ctxMenuCallbacks = findByProps("contextMenuCallbackNative"); window.removeEventListener("contextmenu", ctxMenuCallbacks.contextMenuCallbackWeb); window.addEventListener("contextmenu", ctxMenuCallbacks.contextMenuCallbackNative); this.changedListeners = true; @@ -64,7 +65,6 @@ export default definePlugin({ stop() { if (this.changedListeners) { - const ctxMenuCallbacks = findByProps("contextMenuCallbackNative"); window.removeEventListener("contextmenu", ctxMenuCallbacks.contextMenuCallbackNative); window.addEventListener("contextmenu", ctxMenuCallbacks.contextMenuCallbackWeb); } diff --git a/src/utils/modal.tsx b/src/utils/modal.tsx index 6758a1a1..b4d0f59f 100644 --- a/src/utils/modal.tsx +++ b/src/utils/modal.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { findByProps, findByPropsLazy } from "@webpack"; +import { findByPropsLazy, findExportedComponentLazy } from "@webpack"; import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react"; import { LazyComponent } from "./react"; @@ -118,7 +118,7 @@ export type ImageModal = ComponentType<{ shouldHideMediaOptions?: boolean; }>; -export const ImageModal = LazyComponent(() => findByProps("ImageModal").ImageModal as ImageModal); +export const ImageModal = findExportedComponentLazy("ImageModal") as ImageModal; export const ModalRoot = LazyComponent(() => Modals.ModalRoot); export const ModalHeader = LazyComponent(() => Modals.ModalHeader); From cf7028331c152da10d64e810238157bf6b267ec4 Mon Sep 17 00:00:00 2001 From: Syncx <47534062+Syncxv@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:55:29 +0530 Subject: [PATCH 05/29] Native Folder Support (#2031) --- scripts/build/build.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs index a2e0e002..0c2a930a 100755 --- a/scripts/build/build.mjs +++ b/scripts/build/build.mjs @@ -76,7 +76,11 @@ const globNativesPlugin = { if (!await existsAsync(dirPath)) continue; const plugins = await readdir(dirPath); for (const p of plugins) { - if (!await existsAsync(join(dirPath, p, "native.ts"))) continue; + const nativePath = join(dirPath, p, "native.ts"); + const indexNativePath = join(dirPath, p, "native/index.ts"); + + if (!(await existsAsync(nativePath)) && !(await existsAsync(indexNativePath))) + continue; const nameParts = p.split("."); const namePartsWithoutTarget = nameParts.length === 1 ? nameParts : nameParts.slice(0, -1); From 3453d0c97c880a9f12d757d1fb07c72efc077e2a Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 6 Dec 2023 14:25:53 -0700 Subject: [PATCH 06/29] feat(clearUrls): moar twitter rules (#2029) --- src/plugins/clearURLs/defaultRules.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/plugins/clearURLs/defaultRules.ts b/src/plugins/clearURLs/defaultRules.ts index e7c3ecbe..0633b717 100644 --- a/src/plugins/clearURLs/defaultRules.ts +++ b/src/plugins/clearURLs/defaultRules.ts @@ -124,6 +124,18 @@ export const defaultRules = [ "t@*.x.com", "s@*.x.com", "ref_*@*.x.com", + "t@*.fixupx.com", + "s@*.fixupx.com", + "ref_*@*.fixupx.com", + "t@*.fxtwitter.com", + "s@*.fxtwitter.com", + "ref_*@*.fxtwitter.com", + "t@*.twittpr.com", + "s@*.twittpr.com", + "ref_*@*.twittpr.com", + "t@*.fixvx.com", + "s@*.fixvx.com", + "ref_*@*.fixvx.com", "tt_medium", "tt_content", "lr@yandex.*", From c0b6d8f1c4a6c103f0a5ff4af2fad246f8d035b6 Mon Sep 17 00:00:00 2001 From: AutumnVN Date: Thu, 7 Dec 2023 04:27:06 +0700 Subject: [PATCH 07/29] devCompanion: add findComponentByCode (#2026) --- src/plugins/devCompanion.dev/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/devCompanion.dev/index.tsx b/src/plugins/devCompanion.dev/index.tsx index 2fa01f25..25fd563e 100644 --- a/src/plugins/devCompanion.dev/index.tsx +++ b/src/plugins/devCompanion.dev/index.tsx @@ -215,6 +215,9 @@ function initWs(isManual = false) { case "ModuleId": results = Object.keys(search(parsedArgs[0])); break; + case "ComponentByCode": + results = findAll(filters.componentByCode(...parsedArgs)); + break; default: return reply("Unknown Find Type " + type); } From 9a89f7b3b228a3a0ed9c4a0ac42d03e87a6aa3c8 Mon Sep 17 00:00:00 2001 From: nya <24845294+nyakowint@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:31:22 -0500 Subject: [PATCH 08/29] feat(plugin): XSOverlay (#1901) Co-authored-by: V --- src/plugins/iLoveSpam/index.ts | 2 +- src/plugins/xsOverlay.desktop/README.md | 15 ++ src/plugins/xsOverlay.desktop/index.ts | 288 ++++++++++++++++++++++++ src/plugins/xsOverlay.desktop/native.ts | 16 ++ src/utils/constants.ts | 4 +- 5 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 src/plugins/xsOverlay.desktop/README.md create mode 100644 src/plugins/xsOverlay.desktop/index.ts create mode 100644 src/plugins/xsOverlay.desktop/native.ts diff --git a/src/plugins/iLoveSpam/index.ts b/src/plugins/iLoveSpam/index.ts index 8556de42..bb0b2053 100644 --- a/src/plugins/iLoveSpam/index.ts +++ b/src/plugins/iLoveSpam/index.ts @@ -22,7 +22,7 @@ import definePlugin from "@utils/types"; export default definePlugin({ name: "iLoveSpam", description: "Do not hide messages from 'likely spammers'", - authors: [Devs.botato, Devs.Animal], + authors: [Devs.botato, Devs.Nyako], patches: [ { find: "hasFlag:{writable", diff --git a/src/plugins/xsOverlay.desktop/README.md b/src/plugins/xsOverlay.desktop/README.md new file mode 100644 index 00000000..477e30bf --- /dev/null +++ b/src/plugins/xsOverlay.desktop/README.md @@ -0,0 +1,15 @@ +# XSOverlay Notifier + +Sends Discord messages to [XSOverlay](https://store.steampowered.com/app/1173510/XSOverlay/) for easier viewing while using VR. + +## Preview + +![](https://github.com/Vendicated/Vencord/assets/24845294/205d2055-bb4a-44e4-b7e3-265391bccd40) + +![](https://github.com/Vendicated/Vencord/assets/24845294/f15eff61-2d52-4620-bcab-808ecb1606d2) + +## Usage +- Enable this plugin +- Set plugin settings as desired +- Open XSOverlay +- get ping spammed diff --git a/src/plugins/xsOverlay.desktop/index.ts b/src/plugins/xsOverlay.desktop/index.ts new file mode 100644 index 00000000..5461696e --- /dev/null +++ b/src/plugins/xsOverlay.desktop/index.ts @@ -0,0 +1,288 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import { makeRange } from "@components/PluginSettings/components"; +import { Devs } from "@utils/constants"; +import { Logger } from "@utils/Logger"; +import definePlugin, { OptionType, PluginNative } from "@utils/types"; +import { findByPropsLazy } from "@webpack"; +import { ChannelStore, GuildStore, UserStore } from "@webpack/common"; +import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general"; + +const enum ChannelTypes { + DM = 1, + GROUP_DM = 3 +} + +interface Message { + guild_id: string, + attachments: MessageAttachment[], + author: User, + channel_id: string, + components: any[], + content: string, + edited_timestamp: string, + embeds: Embed[], + sticker_items?: Sticker[], + flags: number, + id: string, + member: GuildMember, + mention_everyone: boolean, + mention_roles: string[], + mentions: Mention[], + nonce: string, + pinned: false, + referenced_message: any, + timestamp: string, + tts: boolean, + type: number; +} + +interface Mention { + avatar: string, + avatar_decoration_data: any, + discriminator: string, + global_name: string, + id: string, + public_flags: number, + username: string; +} + +interface Sticker { + t: "Sticker"; + description: string; + format_type: number; + guild_id: string; + id: string; + name: string; + tags: string; + type: number; +} + +interface Call { + channel_id: string, + guild_id: string, + message_id: string, + region: string, + ringing: string[]; +} + +const MuteStore = findByPropsLazy("isSuppressEveryoneEnabled"); +const XSLog = new Logger("XSOverlay"); + +const settings = definePluginSettings({ + ignoreBots: { + type: OptionType.BOOLEAN, + description: "Ignore messages from bots", + default: false + }, + pingColor: { + type: OptionType.STRING, + description: "User mention color", + default: "#7289da" + }, + channelPingColor: { + type: OptionType.STRING, + description: "Channel mention color", + default: "#8a2be2" + }, + soundPath: { + type: OptionType.STRING, + description: "Notification sound (default/warning/error)", + default: "default" + }, + timeout: { + type: OptionType.NUMBER, + description: "Notif duration (secs)", + default: 1.0, + }, + opacity: { + type: OptionType.SLIDER, + description: "Notif opacity", + default: 1, + markers: makeRange(0, 1, 0.1) + }, + volume: { + type: OptionType.SLIDER, + description: "Volume", + default: 0.2, + markers: makeRange(0, 1, 0.1) + }, +}); + +const Native = VencordNative.pluginHelpers.XsOverlay as PluginNative; + +export default definePlugin({ + name: "XSOverlay", + description: "Forwards discord notifications to XSOverlay, for easy viewing in VR", + authors: [Devs.Nyako], + tags: ["vr", "notify"], + settings, + flux: { + CALL_UPDATE({ call }: { call: Call; }) { + if (call?.ringing?.includes(UserStore.getCurrentUser().id)) { + const channel = ChannelStore.getChannel(call.channel_id); + sendOtherNotif("Incoming call", `${channel.name} is calling you...`); + } + }, + 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, channel)) return; + + 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"}`); + } + + if (message.mention_roles.length > 0) { + for (const roleId of message.mention_roles) { + const role = GuildStore.getGuild(channel.guild_id).roles[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]}:`); + } + } + + 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}`); + } + } + + sendMsgNotif(titleString, finalMsg, message); + } catch (err) { + XSLog.error(`Failed to catch MESSAGE_CREATE: ${err}`); + } + } + } +}); + +function sendMsgNotif(titleString: string, content: string, message: Message) { + fetch(`https://cdn.discordapp.com/avatars/${message.author.id}/${message.author.avatar}.png?size=128`).then(response => response.arrayBuffer()).then(result => { + const msgData = { + messageType: 1, + index: 0, + timeout: settings.store.timeout, + height: calculateHeight(cleanMessage(content)), + opacity: settings.store.opacity, + volume: settings.store.volume, + audioPath: settings.store.soundPath, + title: titleString, + content: content, + useBase64Icon: true, + icon: result, + sourceApp: "Vencord" + }; + Native.sendToOverlay(msgData); + }); +} + +function sendOtherNotif(content: string, titleString: string) { + const msgData = { + messageType: 1, + index: 0, + timeout: settings.store.timeout, + height: calculateHeight(cleanMessage(content)), + opacity: settings.store.opacity, + volume: settings.store.volume, + audioPath: settings.store.soundPath, + title: titleString, + content: content, + useBase64Icon: false, + icon: null, + sourceApp: "Vencord" + }; + Native.sendToOverlay(msgData); +} + +function shouldNotify(message: Message, channel: Channel) { + const currentUser = UserStore.getCurrentUser(); + if (message.author.id === currentUser.id) return false; + if (message.author.bot && settings.store.ignoreBots) return false; + if (MuteStore.allowAllMessages(channel) || message.mention_everyone && !MuteStore.isSuppressEveryoneEnabled(message.guild_id)) return true; + + return message.mentions.some(m => m.id === currentUser.id); +} + +function calculateHeight(content: string) { + if (content.length <= 100) return 100; + if (content.length <= 200) return 150; + if (content.length <= 300) return 200; + return 250; +} + +function cleanMessage(content: string) { + return content.replace(new RegExp("<[^>]*>", "g"), ""); +} diff --git a/src/plugins/xsOverlay.desktop/native.ts b/src/plugins/xsOverlay.desktop/native.ts new file mode 100644 index 00000000..82809383 --- /dev/null +++ b/src/plugins/xsOverlay.desktop/native.ts @@ -0,0 +1,16 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { createSocket, Socket } from "dgram"; + +let xsoSocket: Socket; + +export function sendToOverlay(_, data: any) { + data.icon = Buffer.from(data.icon).toString("base64"); + const json = JSON.stringify(data); + xsoSocket ??= createSocket("udp4"); + xsoSocket.send(json, 42069, "127.0.0.1"); +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 0ff7da72..daa4a74d 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -78,8 +78,8 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "Samu", id: 702973430449832038n, }, - Animal: { - name: "Animal", + Nyako: { + name: "nyako", id: 118437263754395652n }, MaiKokain: { From 613b2dc5f61fcdd6b03d1e66da89f7c8062d118b Mon Sep 17 00:00:00 2001 From: fres621 <126067139+fres621@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:54:23 +0000 Subject: [PATCH 09/29] Fix QuickMention not working in DMs (#2028) Co-authored-by: V --- src/plugins/quickMention/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/quickMention/index.tsx b/src/plugins/quickMention/index.tsx index 9720c7d3..df86e9b7 100644 --- a/src/plugins/quickMention/index.tsx +++ b/src/plugins/quickMention/index.tsx @@ -31,7 +31,7 @@ export default definePlugin({ start() { addButton("QuickMention", msg => { const channel = ChannelStore.getChannel(msg.channel_id); - if (!PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null; + if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null; return { label: "Quick Mention", From 9faa1331da67b76a50697d61c00f72f5601b8b4a Mon Sep 17 00:00:00 2001 From: philipbry <81459908+philipbry@users.noreply.github.com> Date: Wed, 6 Dec 2023 23:15:34 +0100 Subject: [PATCH 10/29] new plugin: notificationVolume (#1992) Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Co-authored-by: V --- src/plugins/notificationVolume/README.md | 3 ++ src/plugins/notificationVolume/index.ts | 35 ++++++++++++++++++++++++ src/utils/constants.ts | 4 +++ 3 files changed, 42 insertions(+) create mode 100644 src/plugins/notificationVolume/README.md create mode 100644 src/plugins/notificationVolume/index.ts diff --git a/src/plugins/notificationVolume/README.md b/src/plugins/notificationVolume/README.md new file mode 100644 index 00000000..05e5af4e --- /dev/null +++ b/src/plugins/notificationVolume/README.md @@ -0,0 +1,3 @@ +# NotificationVolume + +Set a separate volume for notifications and in-app sounds (e.g. messages, call sound, mute/unmute) helping your ears stay healthy for many years to come. diff --git a/src/plugins/notificationVolume/index.ts b/src/plugins/notificationVolume/index.ts new file mode 100644 index 00000000..50eabee7 --- /dev/null +++ b/src/plugins/notificationVolume/index.ts @@ -0,0 +1,35 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const settings = definePluginSettings({ + notificationVolume: { + type: OptionType.SLIDER, + description: "Notification volume", + markers: [0, 25, 50, 75, 100], + default: 100, + stickToMarkers: false + } +}); + +export default definePlugin({ + name: "NotificationVolume", + description: "Save your ears and set a separate volume for notifications and in-app sounds", + authors: [Devs.philipbry], + settings, + patches: [ + { + find: "_ensureAudio(){", + replacement: { + match: /onloadeddata=\(\)=>\{.\.volume=/, + replace: "$&$self.settings.store.notificationVolume/100*" + }, + }, + ], +}); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index daa4a74d..1c477b12 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -387,6 +387,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "ant0n", id: 145224646868860928n }, + philipbry: { + name: "philipbry", + id: 554994003318276106n + }, Korbo: { name: "Korbo", id: 455856406420258827n From e4942397dc0a536fcdc08f060977188d1376268b Mon Sep 17 00:00:00 2001 From: Nickyux <30734036+nmsturcke@users.noreply.github.com> Date: Wed, 6 Dec 2023 23:18:03 +0100 Subject: [PATCH 11/29] MessageClickActions: Ignore Ephemeral & Deleted Messages (#1972) Co-authored-by: V --- src/plugins/messageClickActions/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/messageClickActions/index.ts b/src/plugins/messageClickActions/index.ts index 08cee4c9..052c33f6 100644 --- a/src/plugins/messageClickActions/index.ts +++ b/src/plugins/messageClickActions/index.ts @@ -72,6 +72,7 @@ export default definePlugin({ if (event.detail < 2) return; if (settings.store.requireModifier && !event.ctrlKey && !event.shiftKey) return; if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return; + if (msg.deleted === true) return; if (isMe) { if (!settings.store.enableDoubleClickToEdit || EditStore.isEditing(channel.id, msg.id)) return; @@ -81,6 +82,9 @@ export default definePlugin({ } else { if (!settings.store.enableDoubleClickToReply) return; + const EPHEMERAL = 64; + if (msg.hasFlag(EPHEMERAL)) return; + FluxDispatcher.dispatch({ type: "CREATE_PENDING_REPLY", channel, From 920252956f60377b8aa593c217830391dfa344ff Mon Sep 17 00:00:00 2001 From: AutumnVN Date: Thu, 7 Dec 2023 05:42:40 +0700 Subject: [PATCH 12/29] shikiCodeBlocks: support file preview (#1977) --- src/plugins/shikiCodeblocks.desktop/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/shikiCodeblocks.desktop/index.ts b/src/plugins/shikiCodeblocks.desktop/index.ts index f358497d..ef1b5d3d 100644 --- a/src/plugins/shikiCodeblocks.desktop/index.ts +++ b/src/plugins/shikiCodeblocks.desktop/index.ts @@ -42,6 +42,13 @@ export default definePlugin({ match: /codeBlock:\{react\((\i),(\i),(\i)\)\{/, replace: "$&return $self.renderHighlighter($1,$2,$3);" } + }, + { + find: ".PREVIEW_NUM_LINES", + replacement: { + match: /(?<=function \i\((\i)\)\{)(?=let\{text:\i,language:)/, + replace: "return $self.renderHighlighter({lang:$1.language,content:$1.text});" + } } ], start: async () => { From fd9c675942e727570776b4018c26674d21ecc6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Han=20Seung=20Min=20-=20=ED=95=9C=EC=8A=B9=EB=AF=BC?= Date: Thu, 7 Dec 2023 08:25:13 +0900 Subject: [PATCH 13/29] fix: patch helper overflow (#2007) --- src/components/VencordSettings/PatchHelperTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VencordSettings/PatchHelperTab.tsx b/src/components/VencordSettings/PatchHelperTab.tsx index 0b869a51..35f46ef5 100644 --- a/src/components/VencordSettings/PatchHelperTab.tsx +++ b/src/components/VencordSettings/PatchHelperTab.tsx @@ -108,7 +108,7 @@ function ReplacementComponent({ module, match, replacement, setReplacementError function renderDiff() { return diff?.map(p => { const color = p.added ? "lime" : p.removed ? "red" : "grey"; - return
{p.value}
; + return
{p.value}
; }); } From 6ee50d30f6b0886aa03a2829618205f0f53542db Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 6 Dec 2023 18:26:08 -0500 Subject: [PATCH 14/29] fix(dearrow): remove > from DeArrow titles (#1999) --- src/plugins/dearrow/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/dearrow/index.tsx b/src/plugins/dearrow/index.tsx index 52cf1d53..80eb84aa 100644 --- a/src/plugins/dearrow/index.tsx +++ b/src/plugins/dearrow/index.tsx @@ -60,7 +60,7 @@ async function embedDidMount(this: Component) { if (hasTitle) { embed.dearrow.oldTitle = embed.rawTitle; - embed.rawTitle = titles[0].title; + embed.rawTitle = titles[0].title.replace(/ >(\S)/g, " $1"); } if (hasThumb) { From 34cbb22efe82484ca7fa5e655411679f9c82422a Mon Sep 17 00:00:00 2001 From: Damien Erambert Date: Wed, 6 Dec 2023 15:30:41 -0800 Subject: [PATCH 15/29] feat: add dropdown to choose vibrancy value on macOS (#1941) Co-authored-by: V --- src/api/Settings.ts | 20 ++++- src/components/VencordSettings/VencordTab.tsx | 79 +++++++++++++++++-- src/main/patcher.ts | 10 ++- 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 368f88f7..004a8988 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -38,7 +38,21 @@ export interface Settings { frameless: boolean; transparent: boolean; winCtrlQ: boolean; - macosTranslucency: boolean; + macosVibrancyStyle: + | "content" + | "fullscreen-ui" + | "header" + | "hud" + | "menu" + | "popover" + | "selection" + | "sidebar" + | "titlebar" + | "tooltip" + | "under-page" + | "window" + | undefined; + macosTranslucency: boolean | undefined; disableMinSize: boolean; winNativeTitleBar: boolean; plugins: { @@ -74,7 +88,9 @@ const DefaultSettings: Settings = { frameless: false, transparent: false, winCtrlQ: false, - macosTranslucency: false, + // Replaced by macosVibrancyStyle + macosTranslucency: undefined, + macosVibrancyStyle: undefined, disableMinSize: false, winNativeTitleBar: false, plugins: {}, diff --git a/src/components/VencordSettings/VencordTab.tsx b/src/components/VencordSettings/VencordTab.tsx index a8e9ea5b..07d777eb 100644 --- a/src/components/VencordSettings/VencordTab.tsx +++ b/src/components/VencordSettings/VencordTab.tsx @@ -48,6 +48,15 @@ function VencordSettings() { const isWindows = navigator.platform.toLowerCase().startsWith("win"); const isMac = navigator.platform.toLowerCase().startsWith("mac"); + const needsVibrancySettings = IS_DISCORD_DESKTOP && isMac; + + // One-time migration of the old setting to the new one if necessary. + React.useEffect(() => { + if (settings.macosTranslucency === true && !settings.macosVibrancyStyle) { + settings.macosVibrancyStyle = "sidebar"; + settings.macosTranslucency = undefined; + } + }, []); const Switches: Array; @@ -89,11 +98,6 @@ function VencordSettings() { title: "Disable minimum window size", note: "Requires a full restart" }, - IS_DISCORD_DESKTOP && isMac && { - key: "macosTranslucency", - title: "Enable translucent window", - note: "Requires a full restart" - } ]; return ( @@ -152,6 +156,71 @@ function VencordSettings() { + {needsVibrancySettings && <> + Window vibrancy style (requires restart) +