mirror of
https://github.com/Equicord/Equicord.git
synced 2025-02-20 15:18:50 -05:00
Fixes
This commit is contained in:
parent
65bb12c33b
commit
76746c0c4a
17 changed files with 74 additions and 548 deletions
|
@ -21,7 +21,7 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
|
|||
- Request for plugins from Discord.
|
||||
|
||||
<details>
|
||||
<summary>Extra included plugins (61 additional plugins)</summary>
|
||||
<summary>Extra included plugins (59 additional plugins)</summary>
|
||||
|
||||
- AllCallTimers by MaxHerbold and D3SOX
|
||||
- AltKrispSwitch by newwares
|
||||
|
@ -32,7 +32,6 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
|
|||
- BlockKrsip by D3SOX
|
||||
- BypassDND by Inbestigator
|
||||
- CleanChannelName by AutumnVN
|
||||
- ColorMessage by Kyuuhachi
|
||||
- CopyUserMention by Cortex and castdrian
|
||||
- CustomAppIcons by Happy Enderman and SerStars
|
||||
- DNDWhilePlaying by thororen
|
||||
|
@ -70,7 +69,6 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
|
|||
- Search by JacobTm and thororen
|
||||
- SearchFix by Jaxx
|
||||
- Sekai Stickers by MaiKokain
|
||||
- ServerProfilesToolbox by D3SOX
|
||||
- ShowBadgesInChat by Inbestigator and KrystalSkull
|
||||
- Slap by Korbo
|
||||
- SoundBoardLogger by Moxxie, fres, echo, thororen
|
||||
|
|
|
@ -15,7 +15,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ",setNoiseCancellation(",
|
||||
replacement: {
|
||||
match: /(}\),)(.{1,2}\.default\.dispatch\({type:"AUDIO_SET_NOISE_SUPPRESSION",)/,
|
||||
match: /(}\),)(.{1,2}\.\i\.dispatch\({type:"AUDIO_SET_NOISE_SUPPRESSION",)/,
|
||||
replace: "$1!$self.shouldCancelSuppression(arguments)&&$2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,14 +57,14 @@ export default definePlugin({
|
|||
predicate: () => settings.store.dms,
|
||||
},
|
||||
{ // Above DMs, keyboard nav
|
||||
find: ".default.hasLibraryApplication()&&!",
|
||||
find: ".hasLibraryApplication()&&!",
|
||||
replacement: [
|
||||
{
|
||||
match: /\i\.Routes\.APPLICATION_STORE,/,
|
||||
match: /\i\.\i\.APPLICATION_STORE,/,
|
||||
replace: "/*$&*/",
|
||||
},
|
||||
{
|
||||
match: /\i\.Routes\.COLLECTIBLES_SHOP,/,
|
||||
match: /\i\.\i\.COLLECTIBLES_SHOP,/,
|
||||
replace: "/*$&*/",
|
||||
},
|
||||
],
|
||||
|
@ -87,9 +87,9 @@ export default definePlugin({
|
|||
predicate: () => settings.store.gift,
|
||||
},
|
||||
{ // Emoji list
|
||||
find: "useEmojiGrid:function()",
|
||||
find: /\i\.\i\i\.getEmojiUnavailableReason/,
|
||||
replacement: {
|
||||
match: /(\w+)=!\w+&&\w+.default.isEmojiCategoryNitroLocked\(\{[^}]*\}\);/,
|
||||
match: /(\w+)=!\w+&&\w+.\i.isEmojiCategoryNitroLocked\(\{[^}]*\}\);/,
|
||||
replace: "$&$1||"
|
||||
},
|
||||
predicate: () => settings.store.emojiList,
|
||||
|
|
|
@ -255,7 +255,7 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
// Show all activities in the profile panel
|
||||
find: /.UserProfileTypes.PANEL,themeOverride:\i\i/,
|
||||
find: /\i\.\i\i\.PANEL,themeOverride:\i\i,/,
|
||||
replacement: {
|
||||
match: /(?<=\(0,\i\.jsx\)\()\i\.\i(?=,{activity:.+?,user:\i,channelId:\i.id,)/,
|
||||
replace: "$self.showAllActivitiesComponent"
|
||||
|
|
|
@ -9,8 +9,8 @@ import "./style.css";
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { extractAndLoadChunksLazy, findByPropsLazy, findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
||||
import { useEffect, useState } from "@webpack/common";
|
||||
import { extractAndLoadChunksLazy, findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
||||
import { NavigationRouter, useEffect, useState } from "@webpack/common";
|
||||
|
||||
|
||||
const LinkButton = findExportedComponentLazy("LinkButton"); // let {route: e, selected: t, icon: n, iconClassName: a, interactiveClassName: s, text: r, children: o, locationState: d, onClick: f, className: p, role: m, "aria-posinset": C, "aria-setsize": g, ...E} = this.props;
|
||||
|
@ -20,7 +20,6 @@ const QuestsComponent = findComponentByCodeLazy(".questsContainer"); // No nesse
|
|||
const questsStore = findStoreLazy("QuestsStore");
|
||||
|
||||
const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\).{0,50}"UserSettings"/);
|
||||
const nav: NavigationSettings = findByPropsLazy("transitionTo", "transitionToGuild", "getHistory");
|
||||
|
||||
|
||||
// Routes used in this plugin (in case someone wants to add new ones)
|
||||
|
@ -82,14 +81,10 @@ const QuestButtonComponent = () => {
|
|||
|
||||
const redirectRoute = (ev: BeforeUnloadEvent) => {
|
||||
const paths = Array.from(routes.keys());
|
||||
const path = nav.getHistory().location.pathname;
|
||||
|
||||
if (paths.includes(path)) {
|
||||
const data = routes.get(path);
|
||||
ev.preventDefault();
|
||||
nav.transitionTo(data?.redirectTo ?? "/channels/@me");
|
||||
setTimeout(() => window.location.reload(), 0);
|
||||
}
|
||||
ev.preventDefault();
|
||||
NavigationRouter.transitionTo("/quests/@me");
|
||||
setTimeout(() => window.location.reload(), 0);
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
|
@ -110,23 +105,23 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{ // Add new quest button
|
||||
find: "\"discord-shop\"",
|
||||
find: "\"discord-shop\"),",
|
||||
replacement: {
|
||||
match: /"discord-shop"\),/,
|
||||
replace: "$&,$self.QuestButtonComponent(),"
|
||||
}
|
||||
},
|
||||
{ // Add new route
|
||||
find: "Routes.MESSAGE_REQUESTS,render:",
|
||||
find: ".MESSAGE_REQUESTS,render:",
|
||||
replacement: {
|
||||
match: /\((0,.{0,10}\.jsx\)\(.{0,10}\.default,){path:.{0,10}\.Routes\.MESSAGE_REQUESTS,.{0,100}?\),/,
|
||||
match: /\((0,.{0,10}\.jsx\)\(.{0,10}\.\i,){path:.{0,10}\.\i\.MESSAGE_REQUESTS,.{0,100}?\),/,
|
||||
replace: "$&...$self.routes.map(r => (($1r))),"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'on("LAUNCH_APPLICATION"',
|
||||
replacement: {
|
||||
match: /path:\[.{0,500}Routes\.MESSAGE_REQUESTS,/,
|
||||
match: /path:\[.{0,500}\i\.MESSAGE_REQUESTS,/,
|
||||
replace: "$&...$self.paths,"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import * as Styles from "@api/Styles";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
||||
const AuthorStore = findByPropsLazy("useNullableMessageAuthor", "useNullableMessageAuthor");
|
||||
|
||||
import style from "./style.css?managed";
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
saturation: {
|
||||
type: OptionType.SLIDER,
|
||||
description: "Message color saturation",
|
||||
markers: makeRange(0, 100, 10),
|
||||
default: 20,
|
||||
onChange() {
|
||||
updateStyle();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function updateStyle() {
|
||||
(Styles.requireStyle(style).dom!.sheet!.cssRules[0] as CSSStyleRule)
|
||||
.style.setProperty("--98-message-color-saturation", `${settings.store.saturation}`);
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "ColorMessage",
|
||||
description: "Colors message content with author's role color",
|
||||
authors: [Devs.Kyuuhachi],
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: 'default.Messages.MESSAGE_EDITED,")"',
|
||||
replacement: {
|
||||
match: /id:\(0,\w+.getMessageContentId\)\((\w+)\),/,
|
||||
replace: '$&style:{"--98-message-color":$self.getMessageColor($1)},'
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
getMessageColor(messageId: string) {
|
||||
return AuthorStore.default(messageId).colorString;
|
||||
},
|
||||
|
||||
start() {
|
||||
Styles.enableStyle(style);
|
||||
updateStyle();
|
||||
},
|
||||
stop() {
|
||||
Styles.disableStyle(style);
|
||||
},
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
/* stylelint-disable custom-property-pattern */
|
||||
:root {
|
||||
--98-message-color-saturation: /*DYNAMIC*/;
|
||||
}
|
||||
|
||||
div[class*="messageContent_"] {
|
||||
color: color-mix(
|
||||
in lab,
|
||||
var(--98-message-color, var(--text-normal)) calc(var(--98-message-color-saturation) * 1%),
|
||||
var(--text-normal)
|
||||
)
|
||||
}
|
|
@ -62,8 +62,8 @@ export default definePlugin({
|
|||
{
|
||||
find: "fetchRelationships(){",
|
||||
replacement: {
|
||||
match: /\.then\(e=>o\.default\.dispatch\({type:"LOAD_RELATIONSHIPS_SUCCESS",relationships:e\.body}\)/,
|
||||
replace: ".then(e=>{o.default.dispatch({type:\"LOAD_RELATIONSHIPS_SUCCESS\",relationships:e.body}); $self.getContacts(e.body)}"
|
||||
match: /\.then\(\i=>\i\.\i\.dispatch\({type:"LOAD_RELATIONSHIPS_SUCCESS",relationships:(\i\.body)}\);/,
|
||||
replace: "$&$self.getContacts($2)}"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@ import "./style.css";
|
|||
|
||||
import { DataStore } from "@api/index";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { DeleteIcon } from "@components/Icons";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
|
@ -15,31 +16,32 @@ import { Margins } from "@utils/margins";
|
|||
import { useForceUpdater } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
import { Button, ChannelStore, Forms, SearchableSelect, SelectedChannelStore, TabBar, TextInput, UserStore, UserUtils, useState } from "@webpack/common";
|
||||
import { Button, ChannelStore, Forms, SearchableSelect, SelectedChannelStore, TabBar, TextInput, UserStore, useState } from "@webpack/common";
|
||||
import { Message, User } from "discord-types/general/index.js";
|
||||
|
||||
let keywordEntries: Array<{ regex: string, listIds: Array<string>, listType: ListType; }> = [];
|
||||
let currentUser: User;
|
||||
let keywordLog: Array<any> = [];
|
||||
|
||||
const MenuHeader = findByCodeLazy(".useInDesktopNotificationCenterExperiment)()?");
|
||||
const Popout = findByCodeLazy("let{analyticsName:");
|
||||
const MenuHeader = findByCodeLazy(".sv)()?(0,");
|
||||
const Popout = findByCodeLazy(".loadingMore&&null==");
|
||||
const recentMentionsPopoutClass = findByPropsLazy("recentMentionsPopout");
|
||||
const createMessageRecord = findByCodeLazy("THREAD_CREATED?[]:(0,");
|
||||
const KEYWORD_ENTRIES_KEY = "KeywordNotify_keywordEntries";
|
||||
const KEYWORD_LOG_KEY = "KeywordNotify_log";
|
||||
|
||||
const { createMessageRecord } = findByPropsLazy("createMessageRecord", "updateMessageRecord");
|
||||
const cl = classNameFactory("vc-keywordnotify-");
|
||||
|
||||
async function addKeywordEntry(updater: () => void) {
|
||||
async function addKeywordEntry(forceUpdate: () => void) {
|
||||
keywordEntries.push({ regex: "", listIds: [], listType: ListType.BlackList });
|
||||
await DataStore.set(KEYWORD_ENTRIES_KEY, keywordEntries);
|
||||
updater();
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
async function removeKeywordEntry(idx: number, updater: () => void) {
|
||||
async function removeKeywordEntry(idx: number, forceUpdate: () => void) {
|
||||
keywordEntries.splice(idx, 1);
|
||||
await DataStore.set(KEYWORD_ENTRIES_KEY, keywordEntries);
|
||||
updater();
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
function safeMatchesRegex(s: string, r: string) {
|
||||
|
@ -50,7 +52,6 @@ function safeMatchesRegex(s: string, r: string) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
enum ListType {
|
||||
BlackList = "BlackList",
|
||||
Whitelist = "Whitelist"
|
||||
|
@ -90,7 +91,7 @@ function Collapsible({ title, children }) {
|
|||
onClick={() => setIsOpen(!isOpen)}
|
||||
look={Button.Looks.BLANK}
|
||||
size={Button.Sizes.ICON}
|
||||
className="keywordnotify-collapsible">
|
||||
className={cl("collapsible")}>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<div style={{ marginLeft: "auto", color: "var(--text-muted)", paddingRight: "5px" }}>{isOpen ? "▼" : "▶"}</div>
|
||||
<Forms.FormTitle tag="h4">{title}</Forms.FormTitle>
|
||||
|
@ -130,7 +131,7 @@ function ListedIds({ listIds, setListIds }) {
|
|||
}}
|
||||
look={Button.Looks.BLANK}
|
||||
size={Button.Sizes.ICON}
|
||||
className="keywordnotify-delete">
|
||||
className={cl("delete")}>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
</Flex>
|
||||
|
@ -200,18 +201,18 @@ function KeywordEntries() {
|
|||
onClick={() => removeKeywordEntry(i, update)}
|
||||
look={Button.Looks.BLANK}
|
||||
size={Button.Sizes.ICON}
|
||||
className="keywordnotify-delete">
|
||||
className={cl("delete")}>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
</Flex>
|
||||
<Forms.FormDivider className={Margins.top8 + " " + Margins.bottom8} />
|
||||
<Forms.FormDivider className={[Margins.top8, Margins.bottom8].join(" ")} />
|
||||
<Forms.FormTitle tag="h5">Whitelist/Blacklist</Forms.FormTitle>
|
||||
<Flex flexDirection="row">
|
||||
<div style={{ flexGrow: 1 }}>
|
||||
<ListedIds listIds={values[i].listIds} setListIds={e => setListIds(i, e)} />
|
||||
</div>
|
||||
</Flex>
|
||||
<div className={Margins.top8 + " " + Margins.bottom8} />
|
||||
<div className={[Margins.top8, Margins.bottom8].join(" ")} />
|
||||
<Flex flexDirection="row">
|
||||
<Button onClick={() => {
|
||||
values[i].listIds.push("");
|
||||
|
@ -254,7 +255,7 @@ export default definePlugin({
|
|||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: "}_dispatch(",
|
||||
find: "Dispatch.dispatch(...) called without an action type",
|
||||
replacement: {
|
||||
match: /}_dispatch\((\i),\i\){/,
|
||||
replace: "$&$1=$self.modify($1);"
|
||||
|
@ -268,9 +269,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: "InboxTab.TODOS?(",
|
||||
find: "location:\"RecentsPopout\"",
|
||||
replacement: {
|
||||
match: /:\i&&(\i)===\i\.InboxTab\.TODOS.{1,50}setTab:(\i),onJump:(\i),closePopout:(\i)/,
|
||||
match: /:(\i)===\i\.\i\.MENTIONS\?\(0,.+?setTab:(\i),onJump:(\i),badgeState:\i,closePopout:(\i)/,
|
||||
replace: ": $1 === 5 ? $self.tryKeywordMenu($2, $3, $4) $&"
|
||||
}
|
||||
},
|
||||
|
@ -280,12 +281,19 @@ export default definePlugin({
|
|||
match: /function (\i)\(\i\){let{message:\i,gotoMessage/,
|
||||
replace: "$self.renderMsg = $1; $&"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: ".guildFilter:null",
|
||||
replacement: {
|
||||
match: /onClick:\(\)=>(\i\.\i\.deleteRecentMention\((\i)\.id\))/,
|
||||
replace: "onClick: () => $2._keyword ? $self.deleteKeyword($2.id) : $1"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
async start() {
|
||||
keywordEntries = await DataStore.get(KEYWORD_ENTRIES_KEY) ?? [];
|
||||
currentUser = await UserUtils.getUser(UserStore.getCurrentUser().id);
|
||||
currentUser = UserStore.getCurrentUser();
|
||||
this.onUpdate = () => null;
|
||||
|
||||
(await DataStore.get(KEYWORD_LOG_KEY) ?? []).map(e => JSON.parse(e)).forEach(e => {
|
||||
|
@ -353,6 +361,10 @@ export default definePlugin({
|
|||
if (m == null || keywordLog.some(e => e.id === m.id))
|
||||
return;
|
||||
|
||||
DataStore.get(KEYWORD_LOG_KEY).then(log => {
|
||||
DataStore.set(KEYWORD_LOG_KEY, [...log, JSON.stringify(m)]);
|
||||
});
|
||||
|
||||
const thing = createMessageRecord(m);
|
||||
keywordLog.push(thing);
|
||||
keywordLog.sort((a, b) => b.timestamp - a.timestamp);
|
||||
|
@ -363,6 +375,10 @@ export default definePlugin({
|
|||
this.onUpdate();
|
||||
},
|
||||
|
||||
deleteKeyword(id) {
|
||||
keywordLog = keywordLog.filter(e => e.id !== id);
|
||||
this.onUpdate();
|
||||
},
|
||||
|
||||
keywordTabBar() {
|
||||
return (
|
||||
|
@ -381,33 +397,23 @@ export default definePlugin({
|
|||
|
||||
const [tempLogs, setKeywordLog] = useState(keywordLog);
|
||||
this.onUpdate = () => {
|
||||
const newLog = [...keywordLog];
|
||||
const newLog = Array.from(keywordLog);
|
||||
setKeywordLog(newLog);
|
||||
|
||||
DataStore.set(KEYWORD_LOG_KEY, newLog.map(e => JSON.stringify(e)));
|
||||
};
|
||||
|
||||
const onDelete = m => {
|
||||
keywordLog = keywordLog.filter(e => e.id !== m.id);
|
||||
this.onUpdate();
|
||||
};
|
||||
|
||||
const messageRender = (e, t) => {
|
||||
console.log(this);
|
||||
e._keyword = true;
|
||||
|
||||
e.customRenderedContent = {
|
||||
content: highlightKeywords(e.content, keywordEntries.map(e => e.regex))
|
||||
};
|
||||
|
||||
const msg = this.renderMsg({
|
||||
message: e,
|
||||
gotoMessage: t,
|
||||
dismissible: true
|
||||
});
|
||||
|
||||
if (msg == null)
|
||||
return [null];
|
||||
|
||||
msg.props.children[0].props.children.props.onClick = () => onDelete(e);
|
||||
msg.props.children[1].props.children[1].props.message.customRenderedContent = {
|
||||
content: highlightKeywords(e.content, keywordEntries.map(e => e.regex))
|
||||
};
|
||||
|
||||
return [msg];
|
||||
};
|
||||
|
||||
|
@ -420,7 +426,7 @@ export default definePlugin({
|
|||
channel={channel}
|
||||
onJump={onJump}
|
||||
onFetch={() => null}
|
||||
onCloseMessage={onDelete}
|
||||
onCloseMessage={this.deleteKeyword}
|
||||
loadMore={() => null}
|
||||
messages={tempLogs}
|
||||
renderEmptyState={() => null}
|
||||
|
|
|
@ -38,7 +38,7 @@ const { Spinner } = proxyLazy(() => Forms as any as {
|
|||
SpinnerTypes: typeof SpinnerTypes;
|
||||
});
|
||||
|
||||
const ChannelMessage = findComponentByCodeLazy("renderSimpleAccessories)") as ComponentType<any>;
|
||||
const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hideAccessories");
|
||||
|
||||
export default definePlugin({
|
||||
name: "MessageLinkTooltip",
|
||||
|
@ -49,7 +49,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ',className:"channelMention",children:[',
|
||||
replacement: {
|
||||
match: /(?<=\.jsxs\)\()(\i\.default)/,
|
||||
match: /(?<=\.jsxs\)\()(\i\.\i)/,
|
||||
replace: "$self.wrapComponent(arguments[0], $1)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* 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";
|
||||
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import {
|
||||
Button,
|
||||
Clipboard,
|
||||
GuildMemberStore,
|
||||
Text,
|
||||
Toasts,
|
||||
UserProfileStore,
|
||||
UserStore
|
||||
} from "@webpack/common";
|
||||
import { GuildMember } from "discord-types/general";
|
||||
|
||||
const SummaryItem = findComponentByCodeLazy("borderType", "showBorder", "hideDivider");
|
||||
|
||||
interface SavedProfile {
|
||||
nick: string | null;
|
||||
pronouns: string | null;
|
||||
bio: string | null;
|
||||
themeColors: number[] | undefined;
|
||||
banner: string | undefined;
|
||||
avatar: string | undefined;
|
||||
profileEffectId: string | undefined;
|
||||
avatarDecoration: string | undefined;
|
||||
}
|
||||
|
||||
const savedProfile: SavedProfile = {
|
||||
nick: null,
|
||||
pronouns: null,
|
||||
bio: null,
|
||||
themeColors: undefined,
|
||||
banner: undefined,
|
||||
avatar: undefined,
|
||||
profileEffectId: undefined,
|
||||
avatarDecoration: undefined,
|
||||
};
|
||||
|
||||
const {
|
||||
setPendingAvatar,
|
||||
setPendingBanner,
|
||||
setPendingBio,
|
||||
setPendingNickname,
|
||||
setPendingPronouns,
|
||||
setPendingThemeColors,
|
||||
setPendingProfileEffectId,
|
||||
setPendingAvatarDecoration,
|
||||
}: {
|
||||
setPendingAvatar: (a: string | undefined) => void;
|
||||
setPendingBanner: (a: string | undefined) => void;
|
||||
setPendingBio: (a: string | null) => void;
|
||||
setPendingNickname: (a: string | null) => void;
|
||||
setPendingPronouns: (a: string | null) => void;
|
||||
setPendingThemeColors: (a: number[] | undefined) => void;
|
||||
setPendingProfileEffectId: (a: string | undefined) => void;
|
||||
setPendingAvatarDecoration: (a: string | undefined) => void;
|
||||
} = findByPropsLazy("setPendingNickname", "setPendingPronouns");
|
||||
|
||||
export default definePlugin({
|
||||
name: "ServerProfilesToolbox",
|
||||
authors: [Devs.D3SOX],
|
||||
description: "Adds a copy/paste/reset button to the server profiles editor",
|
||||
|
||||
patchServerProfiles({ guildId }: { guildId: string; }) {
|
||||
const currentUser = UserStore.getCurrentUser();
|
||||
const premiumType = currentUser.premiumType ?? 0;
|
||||
|
||||
const copy = () => {
|
||||
const profile = UserProfileStore.getGuildMemberProfile(currentUser.id, guildId);
|
||||
const nick = GuildMemberStore.getNick(guildId, currentUser.id);
|
||||
const selfMember = GuildMemberStore.getMember(guildId, currentUser.id) as GuildMember & { avatarDecoration: string | undefined; };
|
||||
savedProfile.nick = nick ?? "";
|
||||
savedProfile.pronouns = profile.pronouns;
|
||||
savedProfile.bio = profile.bio;
|
||||
savedProfile.themeColors = profile.themeColors;
|
||||
savedProfile.banner = profile.banner;
|
||||
savedProfile.avatar = selfMember.avatar;
|
||||
savedProfile.profileEffectId = profile.profileEffectId;
|
||||
savedProfile.avatarDecoration = selfMember.avatarDecoration;
|
||||
};
|
||||
|
||||
const paste = () => {
|
||||
setPendingNickname(savedProfile.nick);
|
||||
setPendingPronouns(savedProfile.pronouns);
|
||||
if (premiumType === 2) {
|
||||
setPendingBio(savedProfile.bio);
|
||||
setPendingThemeColors(savedProfile.themeColors);
|
||||
setPendingBanner(savedProfile.banner);
|
||||
setPendingAvatar(savedProfile.avatar);
|
||||
setPendingProfileEffectId(savedProfile.profileEffectId);
|
||||
setPendingAvatarDecoration(savedProfile.avatarDecoration);
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setPendingNickname(null);
|
||||
setPendingPronouns("");
|
||||
if (premiumType === 2) {
|
||||
setPendingBio(null);
|
||||
setPendingThemeColors([]);
|
||||
setPendingBanner(undefined);
|
||||
setPendingAvatar(undefined);
|
||||
setPendingProfileEffectId(undefined);
|
||||
setPendingAvatarDecoration(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const copyToClipboard = () => {
|
||||
copy();
|
||||
Clipboard.copy(JSON.stringify(savedProfile));
|
||||
};
|
||||
|
||||
const pasteFromClipboard = async () => {
|
||||
try {
|
||||
const clip = await navigator.clipboard.readText();
|
||||
if (!clip) {
|
||||
Toasts.show({
|
||||
message: "Clipboard is empty",
|
||||
type: Toasts.Type.FAILURE,
|
||||
id: Toasts.genId(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const clipboardProfile: SavedProfile = JSON.parse(clip);
|
||||
|
||||
if (!("nick" in clipboardProfile)) {
|
||||
Toasts.show({
|
||||
message: "Data is not in correct format",
|
||||
type: Toasts.Type.FAILURE,
|
||||
id: Toasts.genId(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Object.assign(savedProfile, JSON.parse(clip));
|
||||
paste();
|
||||
} catch (e) {
|
||||
Toasts.show({
|
||||
message: `Failed to read clipboard data: ${e}`,
|
||||
type: Toasts.Type.FAILURE,
|
||||
id: Toasts.genId(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return <SummaryItem title="Server Profiles Toolbox" hideDivider={false} forcedDivider>
|
||||
<div style={{ display: "flex", alignItems: "center", flexDirection: "column", gap: "5px" }}>
|
||||
<Text variant="text-md/normal">
|
||||
Use the following buttons to mange the currently selected server
|
||||
</Text>
|
||||
<div style={{ display: "flex", gap: "5px" }}>
|
||||
<Button onClick={copy}>
|
||||
Copy profile
|
||||
</Button>
|
||||
<Button onClick={paste}>
|
||||
Paste profile
|
||||
</Button>
|
||||
<Button onClick={reset}>
|
||||
Reset profile
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ display: "flex", gap: "5px" }}>
|
||||
<Button onClick={copyToClipboard}>
|
||||
Copy to clipboard
|
||||
</Button>
|
||||
<Button onClick={pasteFromClipboard}>
|
||||
Paste from clipboard
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</SummaryItem>;
|
||||
},
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: ".PROFILE_CUSTOMIZATION_GUILD_SELECT_TITLE",
|
||||
replacement: {
|
||||
match: /return\(0(.{10,350})\}\)\}\)\}/,
|
||||
replace: "return [(0$1})}),$self.patchServerProfiles(e)]}"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
});
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { closeModal, ModalCloseButton,ModalContent, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { find, findByPropsLazy } from "@webpack";
|
||||
import { Button, Clickable, Forms, GuildStore, PermissionsBits, PermissionStore, Popout, SearchableSelect, showToast, Text, TextInput, Toasts, useMemo, UserStore, useState } from "@webpack/common";
|
||||
import { Guild } from "discord-types/general";
|
||||
import { HtmlHTMLAttributes } from "react";
|
||||
|
||||
import { cl, getEmojiUrl,SoundEvent } from "../utils";
|
||||
|
||||
export function openCloneSoundModal(item) {
|
||||
const key = openModal(props =>
|
||||
<ModalRoot {...props}>
|
||||
<CloneSoundModal item={item} closeModal={() => closeModal(key)} />
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
|
||||
// Thanks https://github.com/Vendicated/Vencord/blob/ea11f2244fde469ce308f8a4e7224430be62f8f1/src/plugins/emoteCloner/index.tsx#L173-L177
|
||||
const getFontSize = (s: string, small: boolean = false) => {
|
||||
const sizes = [20, 20, 18, 18, 16, 14, 12];
|
||||
return sizes[s.length + (small ? 1 : 0)] ?? 8;
|
||||
};
|
||||
|
||||
function GuildAcronym({ acronym, small, style = {} }) {
|
||||
return (
|
||||
<Flex style={{ alignItems: "center", justifyContent: "center", overflow: "hidden", fontSize: getFontSize(acronym, small), ...style }}>
|
||||
<Text>{acronym}</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function CustomInput({ children, className = "", ...props }: HtmlHTMLAttributes<HTMLDivElement>) {
|
||||
return <div className={classes(cl("clone-input"), className)} {...props}>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
|
||||
const EmojiPicker = LazyComponent(() => find(e => e.default?.type?.render?.toString?.().includes?.(".updateNewlyAddedLastSeen)")).default);
|
||||
|
||||
const sounds = findByPropsLazy("uploadSound", "updateSound");
|
||||
|
||||
export function CloneSoundModal({ item, closeModal }: { item: SoundEvent, closeModal: () => void; }) {
|
||||
const ownedGuilds = useMemo(() => {
|
||||
return Object.values(GuildStore.getGuilds()).filter(guild =>
|
||||
guild.ownerId === UserStore.getCurrentUser().id ||
|
||||
(PermissionStore.getGuildPermissions({ id: guild.id }) & PermissionsBits.CREATE_GUILD_EXPRESSIONS) === PermissionsBits.CREATE_GUILD_EXPRESSIONS);
|
||||
}, []);
|
||||
|
||||
const [selectedGuild, setSelectedGuild] = useState<Guild | null>(null);
|
||||
const [soundName, setSoundName] = useState<string | undefined>(undefined);
|
||||
const [soundEmoji, setSoundEmoji] = useState<any | undefined>(undefined);
|
||||
const [loadingButton, setLoadingButton] = useState<boolean>(false);
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
const isEmojiValid = soundEmoji?.guildId ? soundEmoji.guildId === selectedGuild?.id : true;
|
||||
|
||||
const styles = {
|
||||
selected: { height: "24px", width: "24px" },
|
||||
nonselected: { width: "36px", height: "36px", marginTop: "4px" }
|
||||
};
|
||||
const getStyle = key => key === "selected" ? styles.selected : styles.nonselected;
|
||||
|
||||
function onSelectEmoji(emoji) {
|
||||
setShow(false);
|
||||
setSoundEmoji(emoji);
|
||||
}
|
||||
|
||||
return <>
|
||||
<ModalHeader>
|
||||
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
||||
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>Clone Sound</Text>
|
||||
<ModalCloseButton onClick={closeModal} />
|
||||
</Flex>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<Forms.FormTitle className={Margins.top16}>Cloning Sound</Forms.FormTitle>
|
||||
<CustomInput style={{ display: "flex", flexDirection: "row", gap: "10px", alignItems: "center" }} className={Margins.bottom16}>
|
||||
<img src={getEmojiUrl(item.emoji)} width="24" height="24" />
|
||||
<Text>{item.soundId}</Text>
|
||||
</CustomInput>
|
||||
<Forms.FormTitle required={true} aria-required="true">Add to server:</Forms.FormTitle>
|
||||
<SearchableSelect
|
||||
options={
|
||||
ownedGuilds.map(guild => ({
|
||||
label: guild.name,
|
||||
value: guild
|
||||
}))
|
||||
}
|
||||
|
||||
placeholder="Select a server"
|
||||
value={selectedGuild ? ({
|
||||
label: selectedGuild.name,
|
||||
value: selectedGuild,
|
||||
key: "selected"
|
||||
}) : undefined}
|
||||
|
||||
onChange={v => setSelectedGuild(v)}
|
||||
closeOnSelect={true}
|
||||
renderOptionPrefix={v => v ? (
|
||||
v.value.icon ?
|
||||
<img width={36} height={36} src={v.value.getIconURL(96, true)} style={{ borderRadius: "50%", ...getStyle(v.key) }} /> :
|
||||
<GuildAcronym acronym={v.value.acronym} style={getStyle(v.key)} small={v.key === "selected"} />
|
||||
) : null}
|
||||
/>
|
||||
<Flex flexDirection="row" style={{ gap: "10px", justifyContent: "space-between" }} className={classes(Margins.top16, Margins.bottom16)}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Forms.FormTitle required={true} aria-required="true">Sound Name</Forms.FormTitle>
|
||||
<TextInput value={soundName} onChange={v => setSoundName(v)} placeholder="Sound Name" />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Forms.FormTitle>Related Emoji</Forms.FormTitle>
|
||||
<Popout
|
||||
position="bottom"
|
||||
align="right"
|
||||
animation={Popout.Animation.NONE}
|
||||
shouldShow={show}
|
||||
onRequestClose={() => setShow(false)}
|
||||
renderPopout={() => <EmojiPicker pickerIntention={2} channel={{ getGuildId: () => selectedGuild?.id }} onSelectEmoji={onSelectEmoji} />}
|
||||
>
|
||||
{() => (
|
||||
<Clickable onClick={() => setShow(v => !v)}>
|
||||
<CustomInput style={{ display: "flex", flexDirection: "row", gap: "10px", alignItems: "center", cursor: "pointer" }}>
|
||||
{soundEmoji ?
|
||||
<>
|
||||
<img src={getEmojiUrl({ name: soundEmoji.surrogates, id: soundEmoji.id })} width="24" height="24" style={{ cursor: "pointer" }} />
|
||||
<Text style={{ color: "var(--text-muted)", cursor: "pointer" }}>:{soundEmoji.name ? soundEmoji.name.split("~")[0] : soundEmoji.uniqueName}:</Text>
|
||||
</> :
|
||||
<>
|
||||
<img src={getEmojiUrl({ name: "😊" })} width="24" height="24" style={{ filter: "grayscale(100%)", cursor: "pointer" }} />
|
||||
<Text style={{ color: "var(--text-muted)", cursor: "pointer" }}>Click to Select</Text>
|
||||
</>
|
||||
}
|
||||
</CustomInput>
|
||||
</Clickable>
|
||||
)}
|
||||
</Popout>
|
||||
</div>
|
||||
</Flex>
|
||||
{!isEmojiValid && <Forms.FormText style={{ color: "var(--text-danger)" }} className={Margins.bottom16}>You can't use that emoji in that server</Forms.FormText>}
|
||||
<Button onClick={() => {
|
||||
setLoadingButton(true);
|
||||
fetch(`https://cdn.discordapp.com/soundboard-sounds/${item.soundId}`).then(function (response) {
|
||||
if (!response.body) {
|
||||
setLoadingButton(false);
|
||||
showToast("Error fetching the sound", Toasts.Type.FAILURE);
|
||||
return;
|
||||
}
|
||||
response.body.getReader().read().then(function (result) {
|
||||
if (!result.value) {
|
||||
setLoadingButton(false);
|
||||
showToast("Error reading the sound content", Toasts.Type.FAILURE);
|
||||
return;
|
||||
}
|
||||
return btoa(String.fromCharCode(...result.value));
|
||||
}).then(function (b64) {
|
||||
|
||||
sounds.uploadSound({
|
||||
guildId: selectedGuild?.id,
|
||||
name: soundName,
|
||||
sound: `data:audio/ogg;base64,${b64}`,
|
||||
...(soundEmoji.id ? { emojiId: soundEmoji.id } : { emojiName: soundEmoji.surrogates }),
|
||||
volume: 1
|
||||
}).then(() => {
|
||||
showToast(`Sound added to ${selectedGuild?.name}`, Toasts.Type.SUCCESS);
|
||||
closeModal();
|
||||
}).catch(() => {
|
||||
setLoadingButton(false);
|
||||
showToast("Error while adding sound", Toasts.Type.FAILURE);
|
||||
});
|
||||
|
||||
});
|
||||
}).catch(e => {
|
||||
setLoadingButton(false);
|
||||
showToast("Error fetching the sound", Toasts.Type.FAILURE);
|
||||
return;
|
||||
});
|
||||
}}
|
||||
disabled={(!(selectedGuild && soundName && isEmojiValid)) || loadingButton}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
style={{ width: "100%" }}
|
||||
className={Margins.bottom16}>Add to Server</Button>
|
||||
</ModalContent>
|
||||
</>;
|
||||
}
|
|
@ -13,8 +13,7 @@ import { Button, Clickable, ContextMenuApi, FluxDispatcher, Forms, Menu, Text, T
|
|||
import { User } from "discord-types/general";
|
||||
|
||||
import { clearLoggedSounds, getLoggedSounds } from "../store";
|
||||
import { addListener, AvatarStyles, cl, downloadAudio, getEmojiUrl, getSoundboardVolume, playSound, removeListener, SoundLogEntry, UserSummaryItem } from "../utils";
|
||||
import { openCloneSoundModal } from "./CloneSoundModal";
|
||||
import { addListener, AvatarStyles, cl, downloadAudio, getEmojiUrl, playSound, removeListener, SoundLogEntry, UserSummaryItem } from "../utils";
|
||||
import { openMoreUsersModal } from "./MoreUsersModal";
|
||||
import { openUserModal } from "./UserModal";
|
||||
|
||||
|
@ -100,13 +99,6 @@ export default function SoundBoardLog({ data, closeModal }) {
|
|||
navId="soundboardlogger-sound-menu"
|
||||
onClose={() => FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" })}
|
||||
>
|
||||
<Menu.MenuGroup label="Extra buttons">
|
||||
<Menu.MenuItem
|
||||
id={label("clone")}
|
||||
label="Clone sound"
|
||||
action={() => openCloneSoundModal(item)}
|
||||
/>
|
||||
</Menu.MenuGroup>
|
||||
</Menu.Menu>
|
||||
);
|
||||
}
|
||||
|
@ -164,7 +156,7 @@ export default function SoundBoardLog({ data, closeModal }) {
|
|||
<Flex flexDirection="row" className={cl("sound-buttons")}>
|
||||
<Button color={Button.Colors.PRIMARY} size={Button.Sizes.SMALL} onClick={() => downloadAudio(item.soundId)}>Download</Button>
|
||||
<Button color={Button.Colors.GREEN} size={Button.Sizes.SMALL} onClick={() => copyWithToast(item.soundId, "ID copied to clipboard!")}>Copy ID</Button>
|
||||
<Tooltip text={`Soundboard volume: ${Math.floor(getSoundboardVolume())}%`}>
|
||||
<Tooltip text={"Soundboard volume: currently broken"}>
|
||||
{({ onMouseEnter, onMouseLeave }) =>
|
||||
<Button color={Button.Colors.BRAND} size={Button.Sizes.SMALL} onClick={() => playSound(item.soundId)} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>Play Sound</Button>
|
||||
}
|
||||
|
|
|
@ -39,14 +39,9 @@ export function getEmojiUrl(emoji) {
|
|||
return emoji.id ? `https://cdn.discordapp.com/emojis/${emoji.id}.png?size=32` : getURL(emoji.name);
|
||||
}
|
||||
|
||||
const v1 = findByPropsLazy("amplitudeToPerceptual");
|
||||
const v2 = findByPropsLazy("getAmplitudinalSoundboardVolume");
|
||||
|
||||
export const getSoundboardVolume = () => v1.amplitudeToPerceptual(v2.getAmplitudinalSoundboardVolume());
|
||||
|
||||
export const playSound = id => {
|
||||
const audio = new Audio(`https://cdn.discordapp.com/soundboard-sounds/${id}`);
|
||||
audio.volume = getSoundboardVolume() / 100;
|
||||
audio.volume = 75 / 100;
|
||||
audio.play();
|
||||
};
|
||||
|
||||
|
|
|
@ -62,9 +62,6 @@ function Watching({ userIds, guildId }: WatchingProps): JSX.Element {
|
|||
}
|
||||
|
||||
const ApplicationStreamingStore = findStoreLazy("ApplicationStreamingStore");
|
||||
const { encodeStreamKey }: {
|
||||
encodeStreamKey: (any) => string;
|
||||
} = findByPropsLazy("encodeStreamKey");
|
||||
|
||||
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
||||
|
@ -80,8 +77,8 @@ export default definePlugin({
|
|||
{
|
||||
find: ".Masks.STATUS_SCREENSHARE,width:32",
|
||||
replacement: {
|
||||
match: /default:function\(\)\{return (\i)\}/,
|
||||
replace: "default:function(){return $self.component({OriginalComponent:$1})}"
|
||||
match: /(\i):function\(\)\{return (\i)\}/,
|
||||
replace: "$1:function(){return $self.component({OriginalComponent:$2})}"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -98,7 +95,7 @@ export default definePlugin({
|
|||
|
||||
if (!stream) return <div {...props}>{props.children}</div>;
|
||||
|
||||
const userIds = ApplicationStreamingStore.getViewerIds(encodeStreamKey(stream));
|
||||
const userIds = ApplicationStreamingStore.getViewerIds(stream);
|
||||
|
||||
let missingUsers = 0;
|
||||
const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false));
|
||||
|
@ -160,7 +157,7 @@ export default definePlugin({
|
|||
component: function ({ OriginalComponent }) {
|
||||
return (props: any) => {
|
||||
const stream = useStateFromStores([ApplicationStreamingStore], () => ApplicationStreamingStore.getCurrentUserActiveStream());
|
||||
const viewers = ApplicationStreamingStore.getViewerIds(encodeStreamKey(stream));
|
||||
const viewers = ApplicationStreamingStore.getViewerIds(stream);
|
||||
return <Tooltip text={<Watching userIds={viewers} guildId={stream.guildId} />}>
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
|
|
|
@ -20,7 +20,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".Messages.SUPPRESS_ALL_EMBEDS",
|
||||
replacement: {
|
||||
match: /case (\i\.MessageEmbedTypes\.VIDEO):(case \i\.MessageEmbedTypes\.\i:)*break;default:(\i)=(?:(this\.renderDescription)\(\))\}/,
|
||||
match: /case (\i\.\i\.VIDEO):(case \i\.\i\.\i:)*break;default:(\i)=(?:(this\.renderDescription)\(\))\}/,
|
||||
replace: "$2 break; case $1: $3 = $self.ToggleableDescriptionWrapper({ embed: this.props.embed, original: $4.bind(this) }); break; default: $3 = $4() }"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,15 +65,15 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: "Messages.USER_PROFILE_MUTUAL_GUILDS_PLACEHOLDER).with",
|
||||
find: /Messages\.USER_PROFILE_MUTUAL_GUILDS_PLACEHOLDER\)\.with\(0,\(\)=>\i\.\i\.Messages\.USER_PROFILE_NO_MUTUAL_SERVERS/,
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
match: /(user:(\i),.+?=\i,)(.+?)(\i\.push)(.+?UserProfileSections\.MUTUAL_GUILDS,text:.{0,250}}\)\)}\))/,
|
||||
match: /(user:(\i),.+?=\i,)(.+?)(\i\.push)(.+?\i\.MUTUAL_GUILDS,text:.{0,250}}\)\)}\))/,
|
||||
replace: '$1vencordMutualGroupsTabLabel=$self.useGDMCount($2.id),$3$5,$4({section:"MUTUAL_GDMS",text:vencordMutualGroupsTabLabel})'
|
||||
},
|
||||
{
|
||||
match: /(?<=(\i)===\i\.UserProfileSections\.MUTUAL_GUILDS?.{0,150}\}\):)/,
|
||||
match: /(?<=(\i)===\i\.\i\i\.MUTUAL_GUILDS?.{0,150}\}\):)/,
|
||||
replace: '$1==="MUTUAL_GDMS"?$self.renderMutualGDMs(arguments[0]):'
|
||||
},
|
||||
]
|
||||
|
|
Loading…
Add table
Reference in a new issue