From a11ccde40fdba6157da006542d6709c1488b5c4c Mon Sep 17 00:00:00 2001 From: Vendicated Date: Wed, 23 Oct 2024 03:57:46 +0200 Subject: [PATCH 1/6] Fix ViewIcons & plugins that use image modals Co-Authored-By: sadan <117494111+sadan4@users.noreply.github.com> --- src/plugins/_api/dynamicImageModalApi.ts | 24 ++++++++++++ src/plugins/betterRoleContext/index.tsx | 6 ++- src/plugins/biggerStreamPreview/index.tsx | 6 ++- src/plugins/serverInfo/GuildInfoModal.tsx | 21 ++++++++-- .../spotifyControls/PlayerComponent.tsx | 6 ++- src/plugins/viewIcons/index.tsx | 39 +++++++++++-------- src/utils/discord.css | 3 ++ src/utils/discord.tsx | 38 +++++++++--------- src/utils/modal.tsx | 25 ++++++------ 9 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 src/plugins/_api/dynamicImageModalApi.ts create mode 100644 src/utils/discord.css diff --git a/src/plugins/_api/dynamicImageModalApi.ts b/src/plugins/_api/dynamicImageModalApi.ts new file mode 100644 index 00000000..2ce51400 --- /dev/null +++ b/src/plugins/_api/dynamicImageModalApi.ts @@ -0,0 +1,24 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; + + +export default definePlugin({ + name: "DynamicImageModalAPI", + authors: [Devs.sadan, Devs.Nuckyz], + description: "Allows you to omit either width or height when opening an image modal", + patches: [ + { + find: "SCALE_DOWN:", + replacement: { + match: /!\(null==(\i)\|\|0===\i\|\|null==(\i)\|\|0===\i\)/, + replace: (_, width, height) => `!((null == ${width} || 0 === ${width}) && (null == ${height} || 0 === ${height}))` + } + } + ] +}); diff --git a/src/plugins/betterRoleContext/index.tsx b/src/plugins/betterRoleContext/index.tsx index bf4cf0f3..1029c07e 100644 --- a/src/plugins/betterRoleContext/index.tsx +++ b/src/plugins/betterRoleContext/index.tsx @@ -99,7 +99,11 @@ export default definePlugin({ id="vc-view-role-icon" label="View Role Icon" action={() => { - openImageModal(`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${role.id}/${role.icon}.${settings.store.roleIconFileFormat}`); + openImageModal({ + url: `${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${role.id}/${role.icon}.${settings.store.roleIconFileFormat}`, + height: 128, + width: 128 + }); }} icon={ImageIcon} /> diff --git a/src/plugins/biggerStreamPreview/index.tsx b/src/plugins/biggerStreamPreview/index.tsx index 8cca912b..92b6f57f 100644 --- a/src/plugins/biggerStreamPreview/index.tsx +++ b/src/plugins/biggerStreamPreview/index.tsx @@ -57,7 +57,11 @@ export const handleViewPreview = async ({ guildId, channelId, ownerId }: Applica const previewUrl = await ApplicationStreamPreviewStore.getPreviewURL(guildId, channelId, ownerId); if (!previewUrl) return; - openImageModal(previewUrl); + openImageModal({ + url: previewUrl, + height: 720, + width: 1280 + }); }; export const addViewStreamContext: NavContextMenuPatchCallback = (children, { userId }: { userId: string | bigint; }) => { diff --git a/src/plugins/serverInfo/GuildInfoModal.tsx b/src/plugins/serverInfo/GuildInfoModal.tsx index fb8df2ce..a0d138cd 100644 --- a/src/plugins/serverInfo/GuildInfoModal.tsx +++ b/src/plugins/serverInfo/GuildInfoModal.tsx @@ -80,7 +80,10 @@ function GuildInfoModal({ guild }: GuildProps) { className={cl("banner")} src={bannerUrl} alt="" - onClick={() => openImageModal(bannerUrl)} + onClick={() => openImageModal({ + url: bannerUrl, + width: 1024 + })} /> )} @@ -89,7 +92,11 @@ function GuildInfoModal({ guild }: GuildProps) { ? openImageModal(iconUrl)} + onClick={() => openImageModal({ + url: iconUrl, + height: 512, + width: 512, + })} /> :
{guild.acronym}
} @@ -151,7 +158,15 @@ function Owner(guildId: string, owner: User) { return (
- openImageModal(ownerAvatarUrl)} /> + openImageModal({ + url: ownerAvatarUrl, + height: 512, + width: 512 + })} + /> {Parser.parse(`<@${owner.id}>`)}
); diff --git a/src/plugins/spotifyControls/PlayerComponent.tsx b/src/plugins/spotifyControls/PlayerComponent.tsx index aef0c736..6eb901b5 100644 --- a/src/plugins/spotifyControls/PlayerComponent.tsx +++ b/src/plugins/spotifyControls/PlayerComponent.tsx @@ -229,7 +229,11 @@ function AlbumContextMenu({ track }: { track: Track; }) { id="view-cover" label="View Album Cover" // trolley - action={() => openImageModal(track.album.image.url)} + action={() => openImageModal({ + url: track.album.image.url, + height: 512, + width: 512 + })} icon={ImageIcon} /> openImage(url, 512, 512); +const openBanner = (url: string) => openImage(url, 1024); + +function openImage(url: string, width: number, height?: number) { const format = url.startsWith("/") ? "png" : settings.store.format; const u = new URL(url, window.location.href); @@ -76,11 +79,13 @@ function openImage(url: string) { url = u.toString(); u.searchParams.set("size", "4096"); - const originalUrl = u.toString(); + const original = u.toString(); - openImageModal(url, { - original: originalUrl, - height: 256 + openImageModal({ + url, + original, + width, + height }); } @@ -93,14 +98,14 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U openImage(IconUtils.getUserAvatarURL(user, true))} + action={() => openAvatar(IconUtils.getUserAvatarURL(user, true))} icon={ImageIcon} /> {memberAvatar && ( openImage(IconUtils.getGuildMemberAvatarURLSimple({ + action={() => openAvatar(IconUtils.getGuildMemberAvatarURLSimple({ userId: user.id, avatar: memberAvatar, guildId: guildId!, @@ -126,7 +131,7 @@ const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildCon id="view-icon" label="View Icon" action={() => - openImage(IconUtils.getGuildIconURL({ + openAvatar(IconUtils.getGuildIconURL({ id, icon, canAnimate: true @@ -140,7 +145,7 @@ const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildCon id="view-banner" label="View Banner" action={() => - openImage(IconUtils.getGuildBannerURL(guild, true)!) + openBanner(IconUtils.getGuildBannerURL(guild, true)!) } icon={ImageIcon} /> @@ -158,7 +163,7 @@ const GroupDMContext: NavContextMenuPatchCallback = (children, { channel }: Grou id="view-group-channel-icon" label="View Icon" action={() => - openImage(IconUtils.getChannelIconURL(channel)!) + openAvatar(IconUtils.getChannelIconURL(channel)!) } icon={ImageIcon} /> @@ -171,10 +176,12 @@ export default definePlugin({ authors: [Devs.Ven, Devs.TheKodeToad, Devs.Nuckyz, Devs.nyx], description: "Makes avatars and banners in user profiles clickable, adds View Icon/Banner entries in the user, server and group channel context menu.", tags: ["ImageUtilities"], + dependencies: ["DynamicImageModalAPI"], settings, - openImage, + openAvatar, + openBanner, contextMenus: { "user-context": UserContext, @@ -188,7 +195,7 @@ export default definePlugin({ find: ".overlay:void 0,status:", replacement: { match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/, - replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openImage($1)}," + replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)}," }, all: true }, @@ -197,7 +204,7 @@ export default definePlugin({ find: 'backgroundColor:"COMPLETE"', replacement: { match: /(\.banner,.+?),style:{(?=.+?backgroundImage:null!=(\i)\?"url\("\.concat\(\2,)/, - replace: (_, rest, bannerSrc) => `${rest},onClick:()=>${bannerSrc}!=null&&$self.openImage(${bannerSrc}),style:{cursor:${bannerSrc}!=null?"pointer":void 0,` + replace: (_, rest, bannerSrc) => `${rest},onClick:()=>${bannerSrc}!=null&&$self.openBanner(${bannerSrc}),style:{cursor:${bannerSrc}!=null?"pointer":void 0,` } }, // Group DMs top small & large icon @@ -205,7 +212,7 @@ export default definePlugin({ find: /\.recipients\.length>=2(?! `${m},onClick:()=>$self.openImage(${iconUrl})` + replace: (m, iconUrl) => `${m},onClick:()=>$self.openAvatar(${iconUrl})` } }, // User DMs top small icon @@ -213,7 +220,7 @@ export default definePlugin({ find: ".cursorPointer:null,children", replacement: { match: /.Avatar,.+?src:(.+?\))(?=[,}])/, - replace: (m, avatarUrl) => `${m},onClick:()=>$self.openImage(${avatarUrl})` + replace: (m, avatarUrl) => `${m},onClick:()=>$self.openAvatar(${avatarUrl})` } }, // User Dms top large icon @@ -221,7 +228,7 @@ export default definePlugin({ find: 'experimentLocation:"empty_messages"', replacement: { match: /.Avatar,.+?src:(.+?\))(?=[,}])/, - replace: (m, avatarUrl) => `${m},onClick:()=>$self.openImage(${avatarUrl})` + replace: (m, avatarUrl) => `${m},onClick:()=>$self.openAvatar(${avatarUrl})` } } ] diff --git a/src/utils/discord.css b/src/utils/discord.css new file mode 100644 index 00000000..9b03bf7b --- /dev/null +++ b/src/utils/discord.css @@ -0,0 +1,3 @@ +.vc-position-inherit { + position: inherit; +} diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index 4c7cc38a..099a1e53 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -16,11 +16,13 @@ * along with this program. If not, see . */ +import "./discord.css"; + import { MessageObject } from "@api/MessageEvents"; -import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, InviteActions, MaskedLink, MessageActions, ModalImageClasses, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; +import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, InviteActions, MessageActions, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; import { Channel, Guild, Message, User } from "discord-types/general"; -import { ImageModal, ModalRoot, ModalSize, openModal } from "./modal"; +import { ImageModal, ImageModalItem, openModal } from "./modal"; /** * Open the invite modal @@ -108,25 +110,23 @@ export function sendMessage( return MessageActions.sendMessage(channelId, messageData, waitForChannelReady, extra); } -export function openImageModal(url: string, props?: Partial>): string { +/** + * You must specify either height or width + */ +export function openImageModal(props: Omit): string { return openModal(modalProps => ( - - } - // Don't render forward message button - renderForwardComponent={() => null} - shouldHideMediaOptions={false} - shouldAnimate - {...props} - /> - + fit="vc-position-inherit" + items={[{ + type: "IMAGE", + original: props.url, + ...props, + }]} + onClose={modalProps.onClose} + shouldHideMediaOptions={false} + shouldAnimate + /> )); } diff --git a/src/utils/modal.tsx b/src/utils/modal.tsx index 79f77708..7459379e 100644 --- a/src/utils/modal.tsx +++ b/src/utils/modal.tsx @@ -101,25 +101,24 @@ export const Modals = findByPropsLazy("ModalRoot", "ModalCloseButton") as { }>; }; -export type ImageModal = ComponentType<{ - className?: string; - src: string; - placeholder: string; - original: string; +export interface ImageModalItem { + type: "IMAGE" | "VIDEO"; + url: string; width?: number; height?: number; - animated?: boolean; - responsive?: boolean; - renderLinkComponent(props: any): ReactNode; - renderForwardComponent(props: any): ReactNode; - maxWidth?: number; - maxHeight?: number; - shouldAnimate?: boolean; + original?: string; +} + +export type ImageModal = ComponentType<{ + className?: string; + fit?: string; onClose?(): void; shouldHideMediaOptions?: boolean; + shouldAnimate?: boolean; + items: ImageModalItem[]; }>; -export const ImageModal = findComponentByCodeLazy(".MEDIA_MODAL_CLOSE", "responsive") as ImageModal; +export const ImageModal = findComponentByCodeLazy(".MEDIA_MODAL_CLOSE") as ImageModal; export const ModalRoot = LazyComponent(() => Modals.ModalRoot); export const ModalHeader = LazyComponent(() => Modals.ModalHeader); From 0af820c87457a8fafc0e572f241b71ddb1772e1a Mon Sep 17 00:00:00 2001 From: Vendicated Date: Wed, 23 Oct 2024 04:22:11 +0200 Subject: [PATCH 2/6] Fix ImageZoom Also fixes the image modal being off centre when having the plugin enabled Co-Authored-By: sadan <117494111+sadan4@users.noreply.github.com> --- src/plugins/imageZoom/index.tsx | 17 +++------------ src/plugins/imageZoom/styles.css | 9 -------- src/plugins/serverInfo/index.tsx | 2 ++ .../spotifyControls/PlayerComponent.tsx | 6 +----- src/utils/discord.css | 21 +++++++++++++++++++ src/utils/discord.tsx | 1 + 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx index da01f1a7..adb0ab22 100644 --- a/src/plugins/imageZoom/index.tsx +++ b/src/plugins/imageZoom/index.tsx @@ -156,14 +156,10 @@ export default definePlugin({ patches: [ { - find: "Messages.OPEN_IN_BROWSER", + find: ".contain,SCALE_DOWN:", replacement: { - // there are 2 image thingies. one for carosuel and one for the single image. - // so thats why i added global flag. - // also idk if this patch is good, should it be more specific? - // https://regex101.com/r/xfvNvV/1 - match: /return.{1,200}\.wrapper.{1,200}src:\i,/g, - replace: `$&id: '${ELEMENT_ID}',` + match: /\.slide,\i\),/g, + replace: `$&id:"${ELEMENT_ID}",` } }, @@ -185,13 +181,6 @@ export default definePlugin({ replace: "$&$self.unMountMagnifier();" } ] - }, - { - find: ".carouselModal", - replacement: { - match: /(?<=\.carouselModal.{0,100}onClick:)\i,/, - replace: "()=>{}," - } } ], diff --git a/src/plugins/imageZoom/styles.css b/src/plugins/imageZoom/styles.css index c3776d90..63a51e29 100644 --- a/src/plugins/imageZoom/styles.css +++ b/src/plugins/imageZoom/styles.css @@ -23,12 +23,3 @@ /* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */ } - -/* make the carousel take up less space so we can click the backdrop and exit out of it */ -[class*="modalCarouselWrapper_"] { - top: 0 !important; -} - -[class*="carouselModal_"] { - height: 0 !important; -} diff --git a/src/plugins/serverInfo/index.tsx b/src/plugins/serverInfo/index.tsx index be3172f0..a6dd6edf 100644 --- a/src/plugins/serverInfo/index.tsx +++ b/src/plugins/serverInfo/index.tsx @@ -30,7 +30,9 @@ export default definePlugin({ name: "ServerInfo", description: "Allows you to view info about a server", authors: [Devs.Ven, Devs.Nuckyz], + dependencies: ["DynamicImageModalAPI"], tags: ["guild", "info", "ServerProfile"], + contextMenus: { "guild-context": Patch, "guild-header-popout": Patch diff --git a/src/plugins/spotifyControls/PlayerComponent.tsx b/src/plugins/spotifyControls/PlayerComponent.tsx index 6eb901b5..41e09c16 100644 --- a/src/plugins/spotifyControls/PlayerComponent.tsx +++ b/src/plugins/spotifyControls/PlayerComponent.tsx @@ -229,11 +229,7 @@ function AlbumContextMenu({ track }: { track: Track; }) { id="view-cover" label="View Album Cover" // trolley - action={() => openImageModal({ - url: track.album.image.url, - height: 512, - width: 512 - })} + action={() => openImageModal(track.album.image)} icon={ImageIcon} /> ): string { return openModal(modalProps => ( Date: Tue, 22 Oct 2024 22:28:30 -0400 Subject: [PATCH 3/6] fix MutualGroupDMs (#2964) Co-authored-by: v --- src/plugins/mutualGroupDMs/index.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index ec52b406..a4f690af 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -28,7 +28,7 @@ const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel"); const UserUtils = findByPropsLazy("getGlobalName"); const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds"); -const ExpandableList = findComponentByCodeLazy(".mutualFriendItem]"); +const ExpandableList = findComponentByCodeLazy('"PRESS_SECTION"'); const GuildLabelClasses = findByPropsLazy("guildNick", "guildAvatarWithoutIcon"); function getGroupDMName(channel: Channel) { @@ -142,16 +142,15 @@ export default definePlugin({ const mutualGDms = getMutualGroupDms(user.id); if (mutualGDms.length === 0) return null; - const header = getMutualGDMCountText(user); return ( <> {Divider} { })} + listClassName={listStyle} + header={"Mutual Groups"} + isLoading={false} + items={renderClickableGDMs(mutualGDms, () => { })} /> ); From 7f8e241b9cd3cfca48a5186bdd735c999df56171 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Wed, 23 Oct 2024 04:33:17 +0200 Subject: [PATCH 4/6] "fix" OpenInApp --- src/plugins/openInApp/index.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/plugins/openInApp/index.ts b/src/plugins/openInApp/index.ts index 576980cb..1e4f3041 100644 --- a/src/plugins/openInApp/index.ts +++ b/src/plugins/openInApp/index.ts @@ -91,15 +91,6 @@ export default definePlugin({ replace: "async function $1 if(await $self.handleLink(...arguments)) return;" } }, - // Make Spotify profile activity links open in app on web - { - find: "WEB_OPEN(", - predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify, - replacement: { - match: /\i\.\i\.isProtocolRegistered\(\)(.{0,100})window.open/g, - replace: "true$1VencordNative.native.openExternal" - } - }, { find: "no artist ids in metadata", predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify, From 5afc24b41acfd854a40c8e66847cfcba7657d55c Mon Sep 17 00:00:00 2001 From: Aiden Date: Tue, 22 Oct 2024 19:39:43 -0700 Subject: [PATCH 5/6] ArmCord -> Legcord (#2948) --- src/plugins/_core/settings.tsx | 2 +- src/plugins/_core/supportHelper.tsx | 2 +- src/plugins/arRPC.web/index.tsx | 4 ++-- src/plugins/webKeybinds.web/index.ts | 2 +- src/utils/constants.ts | 4 ++++ 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/_core/settings.tsx b/src/plugins/_core/settings.tsx index be220db1..329c389c 100644 --- a/src/plugins/_core/settings.tsx +++ b/src/plugins/_core/settings.tsx @@ -197,7 +197,7 @@ export default definePlugin({ }, get electronVersion() { - return VencordNative.native.getVersions().electron || window.armcord?.electron || null; + return VencordNative.native.getVersions().electron || window.legcord?.electron || null; }, get chromiumVersion() { diff --git a/src/plugins/_core/supportHelper.tsx b/src/plugins/_core/supportHelper.tsx index d0ebdb33..cb8d1d05 100644 --- a/src/plugins/_core/supportHelper.tsx +++ b/src/plugins/_core/supportHelper.tsx @@ -77,7 +77,7 @@ async function generateDebugInfoMessage() { const client = (() => { if (IS_DISCORD_DESKTOP) return `Discord Desktop v${DiscordNative.app.getVersion()}`; if (IS_VESKTOP) return `Vesktop v${VesktopNative.app.getVersion()}`; - if ("armcord" in window) return `ArmCord v${window.armcord.version}`; + if ("legcord" in window) return `Legcord v${window.legcord.version}`; // @ts-expect-error const name = typeof unsafeWindow !== "undefined" ? "UserScript" : "Web"; diff --git a/src/plugins/arRPC.web/index.tsx b/src/plugins/arRPC.web/index.tsx index df307e75..61e048dc 100644 --- a/src/plugins/arRPC.web/index.tsx +++ b/src/plugins/arRPC.web/index.tsx @@ -73,8 +73,8 @@ export default definePlugin({ }, async start() { - // ArmCord comes with its own arRPC implementation, so this plugin just confuses users - if ("armcord" in window) return; + // Legcord comes with its own arRPC implementation, so this plugin just confuses users + if ("legcord" in window) return; if (ws) ws.close(); ws = new WebSocket("ws://127.0.0.1:1337"); // try to open WebSocket diff --git a/src/plugins/webKeybinds.web/index.ts b/src/plugins/webKeybinds.web/index.ts index 1c43dc0c..a7435c95 100644 --- a/src/plugins/webKeybinds.web/index.ts +++ b/src/plugins/webKeybinds.web/index.ts @@ -25,7 +25,7 @@ const KeyBinds = findByPropsLazy("JUMP_TO_GUILD", "SERVER_NEXT"); export default definePlugin({ name: "WebKeybinds", - description: "Re-adds keybinds missing in the web version of Discord: ctrl+t, ctrl+shift+t, ctrl+tab, ctrl+shift+tab, ctrl+1-9, ctrl+,. Only works fully on Vesktop/ArmCord, not inside your browser", + description: "Re-adds keybinds missing in the web version of Discord: ctrl+t, ctrl+shift+t, ctrl+tab, ctrl+shift+tab, ctrl+1-9, ctrl+,. Only works fully on Vesktop/Legcord, not inside your browser", authors: [Devs.Ven], enabledByDefault: true, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 6653e630..70eca56f 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -575,6 +575,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "RamziAH", id: 1279957227612147747n, }, + SomeAspy: { + name: "SomeAspy", + id: 516750892372852754n, + }, } satisfies Record); // iife so #__PURE__ works correctly From e6204312107f261b8ce30882a9732521946e3d5a Mon Sep 17 00:00:00 2001 From: Vendicated Date: Wed, 23 Oct 2024 04:47:29 +0200 Subject: [PATCH 6/6] bump to v1.10.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a41fe162..9d5ad3e5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.10.4", + "version": "1.10.5", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": {