Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
3870d89e07
27 changed files with 214 additions and 137 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "equicord",
|
||||
"private": "true",
|
||||
"version": "1.14.9.2",
|
||||
"version": "1.14.10.0",
|
||||
"description": "The other cutest Discord client mod",
|
||||
"homepage": "https://github.com/Equicord/Equicord#readme",
|
||||
"bugs": {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ export function isPluginRequired(p: string) {
|
|||
}
|
||||
|
||||
export function addPatch(newPatch: Omit<Patch, "plugin">, pluginName: string, pluginPath = `Vencord.Plugins.plugins[${JSON.stringify(pluginName)}]`) {
|
||||
// TODO: this causes crashes
|
||||
if (pluginName === "Vesktop" && newPatch.find === ".STREAMING_AUTO_STREAMER_MODE,") return;
|
||||
|
||||
const patch = newPatch as Patch;
|
||||
patch.plugin = pluginName;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,10 @@ export async function loadLazyChunks() {
|
|||
|
||||
async function searchAndLoadLazyChunks(factoryCode: string) {
|
||||
// Workaround to avoid loading the CSS debugging chunk which turns the app pink
|
||||
const hasCssDebuggingLoad = foundCssDebuggingLoad ? false : (foundCssDebuggingLoad = factoryCode.includes(".cssDebuggingEnabled&&"));
|
||||
// const hasCssDebuggingLoad = foundCssDebuggingLoad ? false : (foundCssDebuggingLoad = factoryCode.includes(".cssDebuggingEnabled&&"));
|
||||
|
||||
// Disabled for now since this causes lots of chunks concatenated into the same module get marked as invalid, and thus not loaded.
|
||||
const hasCssDebuggingLoad = foundCssDebuggingLoad = false;
|
||||
|
||||
const lazyChunks = factoryCode.matchAll(hasCssDebuggingLoad ? CompleteLazyChunkRegex : PartialLazyChunkRegex);
|
||||
const validChunkGroups = new Set<[chunkIds: PropertyKey[], entryPoint: PropertyKey]>();
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ async function runReporter() {
|
|||
|
||||
await loadLazyChunksDone;
|
||||
|
||||
// Manually require all modules to make sure all lazily required modules are patched
|
||||
for (const moduleId of Object.keys(Webpack.wreq.m)) {
|
||||
try {
|
||||
Webpack.wreq(moduleId);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (IS_REPORTER && IS_WEB && !IS_VESKTOP && !IS_EQUIBOP) {
|
||||
console.log("[REPORTER_META]", {
|
||||
buildNumber: getBuildNumber(),
|
||||
|
|
@ -55,7 +62,7 @@ async function runReporter() {
|
|||
}
|
||||
|
||||
for (const [plugin, moduleId, match, totalTime] of patchTimings) {
|
||||
if (totalTime > 5) {
|
||||
if (totalTime > 10) {
|
||||
new Logger("WebpackPatcher").warn(`Patch by ${plugin} took ${Math.round(totalTime * 100) / 100}ms (Module id is ${String(moduleId)}): ${match}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
src/plugins/_core/concatenatedComponentExtractor.tsx
Normal file
37
src/plugins/_core/concatenatedComponentExtractor.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2026 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { setColorPicker, setCreateScroller } from "@webpack/common";
|
||||
|
||||
export default definePlugin({
|
||||
name: "ConcatenatedComponentExtractor",
|
||||
description: "Extract components that have been concatenated by the bundler",
|
||||
authors: [Devs.sadan],
|
||||
|
||||
required: true,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}),focusProps:",
|
||||
replacement: {
|
||||
match: /(?=function (\i)\(\i\)\{let\{onChange:\i,onClose:\i,[^}]+?showEyeDropper:)/,
|
||||
replace: "$self.setColorPicker($1);"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: /="ltr",orientation:\i="vertical"[^}]+?customTheme:/,
|
||||
replacement: {
|
||||
match: /(?=function (\i)\(\i,\i,\i\)\{.{0,20}?return \i\.forwardRef\(function\(\i,\i\)\{let\{[^}]+?="ltr",orientation:)/,
|
||||
replace: "$self.setCreateScroller($1);"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
setCreateScroller,
|
||||
setColorPicker,
|
||||
});
|
||||
|
|
@ -326,7 +326,7 @@ export default definePlugin({
|
|||
{
|
||||
// Modify the expanded prop to use the boolean if the above patch fails, or check if the folder is expanded from the list if it succeeds
|
||||
// Also export the list of expanded folders to the child folder component if the patch above succeeds, else export undefined
|
||||
match: /(?<=folderNode:(\i),expanded:)\i(?=,)/,
|
||||
match: /(?<=\(0,\i\.jsxs?\)\(\i,\{folderNode:(\i),expanded:)\i(?=,)/,
|
||||
replace: (isExpandedOrExpandedIds, folderNote) => ""
|
||||
+ `typeof ${isExpandedOrExpandedIds}==="boolean"?${isExpandedOrExpandedIds}:${isExpandedOrExpandedIds}.has(${folderNote}.id),`
|
||||
+ `betterFoldersExpandedIds:${isExpandedOrExpandedIds} instanceof Set?${isExpandedOrExpandedIds}:void 0`
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ export default definePlugin({
|
|||
predicate: () => settings.store.organizeMenu,
|
||||
replacement: [
|
||||
{
|
||||
match: /children:\[(\i),(?<=\1=.{0,30}\.openUserSettings.+?)/,
|
||||
match: /children:\[(\i),(?<=\1=(?:function|.{0,30}\.openUserSettings).+?)/, // TODO .{0,30}\.openUserSettings is stable compat
|
||||
replace: "children:[$self.transformSettingsEntries($1),",
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ export default definePlugin({
|
|||
{
|
||||
find: "#{intl::PREMIUM_MESSAGE_LENGTH_UPSELL_TOOLTIP}",
|
||||
replacement: {
|
||||
match: /(?<=\.CHANNEL_TEXT_AREA.{0,50}\i\]\)),\i\?.*?\}\)\]\}\)/,
|
||||
replace: ""
|
||||
match: /(?<=\.PREMIUM_UPSELL\);)(?=.{0,50}\.PREMIUM_UPSELL_VIEWED)/,
|
||||
replace: "return null;"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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, IS_MAC } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "CtrlEnterSend",
|
||||
authors: [Devs.UlyssesZhan],
|
||||
description: "Use Ctrl+Enter to send messages (customizable)",
|
||||
tags: ["Shortcuts", "Chat"],
|
||||
settings: definePluginSettings({
|
||||
submitRule: {
|
||||
description: "The way to send a message",
|
||||
type: OptionType.SELECT,
|
||||
options: [
|
||||
{
|
||||
label: "Ctrl+Enter (Enter or Shift+Enter for new line) (cmd+enter on macOS)",
|
||||
value: "ctrl+enter"
|
||||
},
|
||||
{
|
||||
label: "Shift+Enter (Enter for new line)",
|
||||
value: "shift+enter"
|
||||
},
|
||||
{
|
||||
label: "Enter (Shift+Enter for new line; Discord default)",
|
||||
value: "enter"
|
||||
}
|
||||
],
|
||||
default: "ctrl+enter"
|
||||
},
|
||||
sendMessageInTheMiddleOfACodeBlock: {
|
||||
description: "Whether to send a message in the middle of a code block",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
}
|
||||
}),
|
||||
patches: [
|
||||
// Only one of the two patches will be at effect; Discord often updates to switch between them.
|
||||
// See: https://discord.com/channels/1015060230222131221/1032770730703716362/1261398512017477673
|
||||
{
|
||||
find: ".selectPreviousCommandOption(",
|
||||
replacement: {
|
||||
match: /(?<=(\i)\.key!==\i\.\i.ENTER\|\|).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=\|\|\(\i\.preventDefault)/,
|
||||
replace: "!$self.shouldSubmit($1,$2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "!this.hasOpenCodeBlock()",
|
||||
replacement: {
|
||||
match: /!(\i).shiftKey&&!(this.hasOpenCodeBlock\(\))&&\(.{0,100}?\)/,
|
||||
replace: "$self.shouldSubmit($1, $2)"
|
||||
}
|
||||
}
|
||||
],
|
||||
shouldSubmit(event: KeyboardEvent, codeblock: boolean): boolean {
|
||||
let result = false;
|
||||
switch (this.settings.store.submitRule) {
|
||||
case "shift+enter":
|
||||
result = event.shiftKey;
|
||||
break;
|
||||
case "ctrl+enter":
|
||||
result = IS_MAC ? event.metaKey : event.ctrlKey;
|
||||
break;
|
||||
case "enter":
|
||||
result = !event.shiftKey && !event.ctrlKey;
|
||||
break;
|
||||
}
|
||||
if (!this.settings.store.sendMessageInTheMiddleOfACodeBlock) {
|
||||
result &&= !codeblock;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
|
@ -16,7 +16,7 @@ import { useAuthorizationStore } from "./lib/stores/AuthorizationStore";
|
|||
import { useCurrentUserDecorationsStore } from "./lib/stores/CurrentUserDecorationsStore";
|
||||
import { useUserDecorAvatarDecoration, useUsersDecorationsStore } from "./lib/stores/UsersDecorationsStore";
|
||||
import { settings } from "./settings";
|
||||
import { setDecorationGridDecoration, setDecorationGridItem } from "./ui/components";
|
||||
import { setAvatarDecorationModalPreview, setDecorationGridDecoration, setDecorationGridItem } from "./ui/components";
|
||||
import DecorSection from "./ui/components/DecorSection";
|
||||
|
||||
export interface AvatarDecoration {
|
||||
|
|
@ -60,7 +60,7 @@ export default definePlugin({
|
|||
},
|
||||
// Remove NEW label from decor avatar decorations
|
||||
{
|
||||
match: /(?<=\.\i\.PURCHASE)(?=,)(?<=avatarDecoration:(\i).+?)/,
|
||||
match: /(?<=\i\.PURCHASE)(?=,)(?<=avatarDecoration:(\i).+?)/,
|
||||
replace: "||$1.skuId===$self.SKU_ID"
|
||||
}
|
||||
]
|
||||
|
|
@ -111,10 +111,16 @@ export default definePlugin({
|
|||
// Patch avatar decoration preview to display Decor avatar decorations as if they are purchased
|
||||
{
|
||||
find: "#{intl::PREMIUM_UPSELL_PROFILE_AVATAR_DECO_INLINE_UPSELL_DESCRIPTION}",
|
||||
replacement: {
|
||||
match: /(#{intl::PREMIUM_UPSELL_PROFILE_AVATAR_DECO_INLINE_UPSELL_DESCRIPTION}.+?return null!=(\i)&&\()(null==\i)/,
|
||||
replace: (_, rest, avatarDecoration, hasPurchase) => `${rest}(${avatarDecoration}.skuId!==$self.SKU_ID&&${avatarDecoration}.skuId!==$self.RAW_SKU_ID&&${hasPurchase})`
|
||||
}
|
||||
replacement: [
|
||||
{
|
||||
match: /(#{intl::PREMIUM_UPSELL_PROFILE_AVATAR_DECO_INLINE_UPSELL_DESCRIPTION}.+?return null!=(\i)&&\()(null==\i)/,
|
||||
replace: (_, rest, avatarDecoration, hasPurchase) => `${rest}(${avatarDecoration}.skuId!==$self.SKU_ID&&${avatarDecoration}.skuId!==$self.RAW_SKU_ID&&${hasPurchase})`
|
||||
},
|
||||
{
|
||||
match: /(?<==)\i=>{let{user:\i,guildId:\i,avatarDecoration:/,
|
||||
replace: "$self.AvatarDecorationModalPreview=$&"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
settings,
|
||||
|
|
@ -138,6 +144,10 @@ export default definePlugin({
|
|||
setDecorationGridDecoration(e);
|
||||
},
|
||||
|
||||
set AvatarDecorationModalPreview(e: any) {
|
||||
setAvatarDecorationModalPreview(e);
|
||||
},
|
||||
|
||||
SKU_ID,
|
||||
RAW_SKU_ID,
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import { AvatarDecoration } from "@plugins/decor";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import type { ComponentType, HTMLProps, PropsWithChildren } from "react";
|
||||
|
||||
type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & {
|
||||
|
|
@ -16,7 +15,8 @@ type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTM
|
|||
export let DecorationGridItem: DecorationGridItemComponent;
|
||||
export const setDecorationGridItem = v => DecorationGridItem = v;
|
||||
|
||||
export const AvatarDecorationModalPreview = findComponentByCodeLazy("#{intl::PREMIUM_UPSELL_PROFILE_AVATAR_DECO_INLINE_UPSELL_DESCRIPTION}");
|
||||
export let AvatarDecorationModalPreview: ComponentType<any> = () => null;
|
||||
export const setAvatarDecorationModalPreview = v => AvatarDecorationModalPreview = v;
|
||||
|
||||
type DecorationGridDecorationComponent = React.ComponentType<HTMLProps<HTMLDivElement> & {
|
||||
avatarDecoration: AvatarDecoration;
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ import { Paragraph } from "@components/Paragraph";
|
|||
import { Devs, IS_MAC } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy, findLazy } from "@webpack";
|
||||
import { React } from "@webpack/common";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Forms, React } from "@webpack/common";
|
||||
|
||||
import hideBugReport from "./hideBugReport.css?managed";
|
||||
|
||||
const KbdStyles = findByPropsLazy("key", "combo");
|
||||
const BugReporterExperiment = findLazy(m => m?.definition?.name === "2026-01-bug-reporter");
|
||||
let BugReporterExperiment: any;
|
||||
|
||||
const modKey = IS_MAC ? "cmd" : "ctrl";
|
||||
const altKey = IS_MAC ? "opt" : "alt";
|
||||
|
|
@ -146,9 +146,20 @@ export default definePlugin({
|
|||
replace: "{return($1)||($self.matchExperiment(arguments[0].url,$2.label))}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: "2026-01-bug-reporter",
|
||||
replacement: {
|
||||
match: /(?<==)(?=\(0,\i\(.+?\)\.\i\)\({name:"2026-01-bug-reporter")/,
|
||||
replace: "$self.BugReporterExperiment="
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
set BugReporterExperiment(value: any) {
|
||||
BugReporterExperiment = value;
|
||||
},
|
||||
|
||||
matchExperiment(url: string, label: string): boolean {
|
||||
const items = url.split("/");
|
||||
const labelCleaned = label.replace(/[^a-zA-Z0-9]+/g, "").toLowerCase();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default definePlugin({
|
|||
patches: [
|
||||
// DM User Sidebar
|
||||
{
|
||||
find: ".SIDEBAR}),nicknameIcons",
|
||||
find: "#{intl::PREMIUM_GIFTING_BUTTON}),action:",
|
||||
replacement: {
|
||||
match: /#{intl::USER_PROFILE_MEMBER_SINCE}\),.{0,100}userId:(\i\.id)}\)}\)/,
|
||||
replace: "$&,$self.FriendsSinceComponent({userId:$1,isSidebar:true})"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Channel, Message } from "@vencord/discord-types";
|
||||
import { findLazy } from "@webpack";
|
||||
import { ContextMenuApi, FluxDispatcher, Menu, MessageActions } from "@webpack/common";
|
||||
|
||||
enum GreetMode {
|
||||
|
|
@ -42,7 +41,7 @@ const settings = definePluginSettings({
|
|||
unholyMultiGreetEnabled?: boolean;
|
||||
}>();
|
||||
|
||||
const WELCOME_STICKERS = findLazy(m => Array.isArray(m) && m[0]?.name === "Wave");
|
||||
let WELCOME_STICKERS: any;
|
||||
|
||||
function greet(channel: Channel, message: Message, stickers: string[]) {
|
||||
const options = MessageActions.getSendMessageOptionsForReply({
|
||||
|
|
@ -164,9 +163,20 @@ export default definePlugin({
|
|||
match: /className:\i\.\i,(?=.{0,40}?"sticker")(?<={channel:\i,message:\i}=(\i).+?)/,
|
||||
replace: "$&onContextMenu:(vcEvent)=>$self.pickSticker(vcEvent, $1),"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: '"Wumpus waves hello"',
|
||||
replacement: {
|
||||
match: /(?<==)(?=\[{id:"749054660769218631",format_type:\d,description:"Wumpus waves hello")/,
|
||||
replace: "$self.WELCOME_STICKERS="
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
set WELCOME_STICKERS(value: any) {
|
||||
WELCOME_STICKERS = value;
|
||||
},
|
||||
|
||||
pickSticker(
|
||||
event: React.UIEvent,
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ export default definePlugin({
|
|||
replace: `id:"${ELEMENT_ID}",$&`
|
||||
},
|
||||
{
|
||||
match: /(?<=null!=(\i)\?.{0,20})\i\.\i,{children:\1/,
|
||||
match: /(?<=null!=(\i)\?.{0,20})\i(?:\.\i)?,{children:\1/, // TODO: (?:\.\i)? is stable compat
|
||||
replace: "'div',{onClick:e=>e.stopPropagation(),children:$1"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".REQUEST_GUILD_MEMBERS,",
|
||||
replacement: {
|
||||
match: /\.send\(\i\.\i\.REQUEST_GUILD_MEMBERS,{/,
|
||||
match: /\.send\(\i\.REQUEST_GUILD_MEMBERS,{/,
|
||||
replace: "$&nonce:arguments[1].nonce,"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import {
|
|||
RestAPI,
|
||||
UserStore
|
||||
} from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
import { ComponentType, JSX } from "react";
|
||||
|
||||
const messageCache = new Map<string, {
|
||||
message?: Message;
|
||||
|
|
@ -48,8 +48,8 @@ const messageCache = new Map<string, {
|
|||
}>();
|
||||
|
||||
const Embed = findComponentLazy(m => m.prototype?.renderSuppressButton);
|
||||
const AutoModEmbed = findComponentByCodeLazy("withFooter", "childrenMessageContent:");
|
||||
const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hideAccessories");
|
||||
let AutoModEmbed: ComponentType<any> = () => null;
|
||||
|
||||
const SearchResultClasses = findCssClassesLazy("message", "searchResult");
|
||||
const EmbedClasses = findCssClassesLazy("embedAuthorIcon", "embedAuthor", "embedAuthor", "embedMargin");
|
||||
|
|
@ -370,6 +370,20 @@ export default definePlugin({
|
|||
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "!1,withFooter:",
|
||||
replacement: {
|
||||
match: /(?=function (\i)\(\i\){let{message:\i,channel:\i,[^}]+?withFooter:)/,
|
||||
replace: "$self.AutoModEmbed=$1;"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
set AutoModEmbed(value: any) {
|
||||
AutoModEmbed = value;
|
||||
},
|
||||
|
||||
start() {
|
||||
addMessageAccessory("MessageLinkEmbeds", props => {
|
||||
if (!messageLinkRegex.test(props.message.content))
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ import { isNonNullish } from "@utils/guards";
|
|||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Channel, User } from "@vencord/discord-types";
|
||||
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
|
||||
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
import { findByPropsLazy, findCssClassesLazy } from "@webpack";
|
||||
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, Text, useMemo, UserStore } from "@webpack/common";
|
||||
import { ComponentType, JSX } from "react";
|
||||
|
||||
const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
|
||||
const UserUtils = findByPropsLazy("getGlobalName");
|
||||
|
|
@ -35,7 +35,8 @@ const UserUtils = findByPropsLazy("getGlobalName");
|
|||
const ProfileListClasses = findCssClassesLazy("empty", "textContainer", "connectionIcon");
|
||||
const TabBarClasses = findCssClassesLazy("tabPanelScroller", "tabBarPanel");
|
||||
const MutualsListClasses = findCssClassesLazy("row", "icon", "name", "details");
|
||||
const ExpandableList = findComponentByCodeLazy('action:"PRESS_SECTION"', '"section"');
|
||||
|
||||
let ExpandableList: ComponentType<any> = () => null;
|
||||
|
||||
function getGroupDMName(channel: Channel) {
|
||||
return channel.name ||
|
||||
|
|
@ -140,11 +141,19 @@ export default definePlugin({
|
|||
match: /\.openUserProfileModal.+?\)}\)}\)(?<=,(\i)&&(\i)&&(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.\i}\)).{0,50}?"MUTUAL_FRIENDS".+?)/,
|
||||
replace: (m, hasMutualGuilds, hasMutualFriends, Divider, classes) => "" +
|
||||
`${m},$self.renderDMPageList({user:arguments[0].user,hasDivider:${hasMutualGuilds}||${hasMutualFriends},Divider:${Divider},listStyle:${classes}.list})`
|
||||
},
|
||||
{
|
||||
match: /(?=function (\i)\(\i\){let{section:\i,header:\i[^}]+?onExpand:)/,
|
||||
replace: "$self.ExpandableList=$1;"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
set ExpandableList(value: any) {
|
||||
ExpandableList = value;
|
||||
},
|
||||
|
||||
getMutualGroupDms(userId: string) {
|
||||
try {
|
||||
return getMutualGroupDms(userId);
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import { Devs } from "@utils/constants";
|
||||
import { hasGuildFeature } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, GuildStore } from "@webpack/common";
|
||||
|
||||
const SummaryStore = findByPropsLazy("allSummaries", "findSummary");
|
||||
const createSummaryFromServer = findByCodeLazy(".people)),startId:", ".type}");
|
||||
|
||||
const settings = definePluginSettings({
|
||||
summaryExpiryThresholdDays: {
|
||||
|
|
@ -39,7 +38,7 @@ interface Summary {
|
|||
unsafe: boolean;
|
||||
}
|
||||
|
||||
interface ChannelSummaries {
|
||||
interface ChannelSummary {
|
||||
type: string;
|
||||
channel_id: string;
|
||||
guild_id: string;
|
||||
|
|
@ -48,6 +47,21 @@ interface ChannelSummaries {
|
|||
// custom property
|
||||
time?: number;
|
||||
}
|
||||
// TODO: these types are wrong and evil and incorrect
|
||||
function createChannelSummaryFromServer(s: Summary, channelId: string): ChannelSummary {
|
||||
return {
|
||||
id: s.id,
|
||||
topic: s.topic,
|
||||
summShort: s.summ_short,
|
||||
people: Array.from(new Set(s.people)),
|
||||
startId: s.start_id,
|
||||
endId: s.end_id,
|
||||
count: s.count,
|
||||
channelId,
|
||||
source: s.source,
|
||||
type: s.type as any,
|
||||
} as any as ChannelSummary;
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "Summaries",
|
||||
|
|
@ -71,9 +85,13 @@ export default definePlugin({
|
|||
}
|
||||
}
|
||||
],
|
||||
|
||||
flux: {
|
||||
CONVERSATION_SUMMARY_UPDATE(data) {
|
||||
const incomingSummaries: ChannelSummaries[] = data.summaries.map((summary: any) => ({ ...createSummaryFromServer(summary), time: Date.now() }));
|
||||
const incomingSummaries: ChannelSummary[] = data.summaries.map((summary: any) => ({
|
||||
...createChannelSummaryFromServer(summary, undefined!),
|
||||
time: Date.now()
|
||||
}));
|
||||
|
||||
// idk if this is good for performance but it doesnt seem to be a problem in my experience
|
||||
DataStore.update("summaries-data", summaries => {
|
||||
|
|
|
|||
|
|
@ -167,7 +167,8 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: /\.POPOUT,onClose:\i}\),nicknameIcons:.+?\.isProvisional/,
|
||||
// Same find as ReviewDB
|
||||
find: "#{intl::XcTHmQ::raw}",
|
||||
replacement: {
|
||||
match: /userId:\i\.id,guild:\i\}\)(?=])/,
|
||||
replace: "$&,$self.profilePopoutComponent(arguments[0])"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ import { classes } from "@utils/misc";
|
|||
import { formatDuration } from "@utils/text";
|
||||
import type { Channel, RoleOrUserPermission } from "@vencord/discord-types";
|
||||
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
|
||||
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
|
||||
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
|
||||
import { ComponentType } from "react";
|
||||
|
||||
import { cl, settings } from "..";
|
||||
|
||||
|
|
@ -66,9 +67,11 @@ const enum ChannelFlags {
|
|||
}
|
||||
|
||||
const ChatScrollClasses = findCssClassesLazy("auto", "managedReactiveScroller", "customTheme");
|
||||
const ChannelBeginHeader = findComponentByCodeLazy("#{intl::ROLE_REQUIRED_SINGLE_USER_MESSAGE}");
|
||||
const TagComponent = findComponentByCodeLazy("#{intl::FORUM_TAG_A11Y_FILTER_BY_TAG}");
|
||||
|
||||
let ChannelBeginHeader: ComponentType<any> = () => null;
|
||||
export const setChannelBeginHeader = v => ChannelBeginHeader = v;
|
||||
|
||||
const EmojiParser = findByPropsLazy("convertSurrogateToName");
|
||||
const EmojiUtils = findByPropsLazy("getURL", "getEmojiColors");
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import definePlugin, { OptionType } from "@utils/types";
|
|||
import type { Channel, Role } from "@vencord/discord-types";
|
||||
import { ChannelStore, PermissionsBits, PermissionStore, Tooltip } from "@webpack/common";
|
||||
|
||||
import HiddenChannelLockScreen from "./components/HiddenChannelLockScreen";
|
||||
import HiddenChannelLockScreen, { setChannelBeginHeader } from "./components/HiddenChannelLockScreen";
|
||||
|
||||
export const cl = classNameFactory("vc-shc-");
|
||||
|
||||
|
|
@ -499,9 +499,20 @@ export default definePlugin({
|
|||
match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/,
|
||||
replace: "$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "#{intl::ROLE_REQUIRED_SINGLE_USER_MESSAGE}",
|
||||
replacement: {
|
||||
match: /(?=function (\i)\(\i\){let{channel:.{0,200}?getSortedRoles\()/,
|
||||
replace: "$self.ChannelBeginHeader=$1;"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
set ChannelBeginHeader(value: any) {
|
||||
setChannelBeginHeader(value);
|
||||
},
|
||||
|
||||
swapViewChannelWithConnectPermission(mergedPermissions: bigint, channel: Channel) {
|
||||
if (!PermissionStore.can(PermissionsBits.CONNECT, channel)) {
|
||||
mergedPermissions &= ~PermissionsBits.VIEW_CHANNEL;
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ export default definePlugin({
|
|||
tags: ["Voice"],
|
||||
authors: [Devs.Ven, Devs.D3SOX, Devs.sadan],
|
||||
patches: [
|
||||
...[
|
||||
".handleVoiceStatusClick", // voice channels
|
||||
".handleClickChat" // stage channels
|
||||
].map(find => ({
|
||||
find,
|
||||
// Stage Channels & Voice Channels
|
||||
// the find is for stage channels, but it also handles voice
|
||||
// channels because they're both in the same concatenated module
|
||||
// the find for voice channels was `.handleVoiceStatusClick`
|
||||
{
|
||||
find: ".handleClickChat",
|
||||
// hack: these are not React onClick, it is a custom prop handled by Discord
|
||||
// thus, replacing this with onDoubleClick won't work, and you also cannot check
|
||||
// e.detail since instead of the event they pass the channel.
|
||||
|
|
@ -46,10 +47,10 @@ export default definePlugin({
|
|||
replace: "onClick:()=>{$self.schedule(()=>{this.handleClick()},this)",
|
||||
},
|
||||
]
|
||||
})),
|
||||
},
|
||||
{
|
||||
// channel mentions
|
||||
find: 'className:"channelMention",children',
|
||||
find: 'className:"channelMention",children:[null!=',
|
||||
replacement: {
|
||||
match: /onClick:(\i)(?=,.{0,30}className:"channelMention".+?(\i)\.inContent)/,
|
||||
replace: (_, onClick, props) => ""
|
||||
|
|
|
|||
|
|
@ -17,18 +17,19 @@
|
|||
*/
|
||||
|
||||
import { useTimer } from "@utils/react";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import { ComponentType } from "react";
|
||||
|
||||
|
||||
import { cl } from "..";
|
||||
|
||||
const PREVIEW_IDLE_LABEL = "----";
|
||||
const PREVIEW_RECORDING_LABEL = "RECORDING";
|
||||
|
||||
interface VoiceMessageProps {
|
||||
export interface VoiceMessageProps {
|
||||
src: string;
|
||||
waveform: string;
|
||||
}
|
||||
const VoiceMessage = findComponentByCodeLazy<VoiceMessageProps>("waveform:", "onVolumeChange");
|
||||
export let VoiceMessage: ComponentType<VoiceMessageProps> = () => null;
|
||||
|
||||
export type VoicePreviewOptions = {
|
||||
src?: string;
|
||||
|
|
|
|||
|
|
@ -275,6 +275,19 @@ export default definePlugin({
|
|||
tags: ["Voice"],
|
||||
authors: [Devs.Ven, Devs.Vap, Devs.Nickyux],
|
||||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: "#{intl::3XohGn::raw}",
|
||||
replacement: {
|
||||
match: /(?<=\i=)(?=\i\.memo\(.{0,50}?=1,onVolumeChange:[^}]+?waveform:[^}]+?playbackCacheKey:)/,
|
||||
replace: "$self.VoiceMessage=",
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
set VoiceMessage(value) {
|
||||
VoiceMessage = value;
|
||||
},
|
||||
contextMenus: {
|
||||
"channel-attach": ctxMenuPatch
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,7 @@ export const Tooltip = waitForComponent<t.Tooltip>("Tooltip", m => m.prototype?.
|
|||
export const TooltipContainer = TooltipContainerComponent as never;
|
||||
|
||||
export const TextInput = waitForComponent<t.TextInput>("TextInput", filters.componentByCode("#{intl::MAXIMUM_LENGTH_ERROR}", '"input"'));
|
||||
export const ManaTextArea = waitForComponent("ManaTextArea", filters.componentByCode('"data-mana-component":"text-area"'));
|
||||
export const TextArea = ManaTextArea;
|
||||
export const TextArea = waitForComponent<t.TextArea>("TextArea", filters.componentByCode('"data-mana-component":"text-area"'));
|
||||
export const Select = waitForComponent<t.Select>("Select", filters.componentByCode('selectionMode:"single",onSelectionChange:', "isSelected:"));
|
||||
export const SearchableSelect = waitForComponent<t.SearchableSelect>("SearchableSelect", filters.componentByCode('?"multiple":"single",required:'));
|
||||
export const Slider = waitForComponent<t.Slider>("Slider", filters.componentByCode("markDash", "this.renderMark("));
|
||||
|
|
@ -70,12 +69,21 @@ export const Paginator = waitForComponent<t.Paginator>("Paginator", filters.comp
|
|||
export const Clickable = waitForComponent<t.Clickable>("Clickable", filters.componentByCode("this.context?this.renderNonInteractive():"));
|
||||
export const Avatar = waitForComponent<t.Avatar>("Avatar", filters.componentByCode(".size-1.375*"));
|
||||
|
||||
export const ColorPicker = waitForComponent<t.ColorPicker>("ColorPicker", filters.componentByCode("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", "showEyeDropper"));
|
||||
export let ColorPicker: t.ColorPicker = () => null;
|
||||
export function setColorPicker(component: t.ColorPicker) {
|
||||
ColorPicker = component;
|
||||
}
|
||||
|
||||
|
||||
export const UserSummaryItem = waitForComponent("UserSummaryItem", filters.componentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
||||
|
||||
export let createScroller: (scrollbarClassName: string, fadeClassName: string, customThemeClassName: string) => t.ScrollerThin;
|
||||
export let createScroller: ((scrollbarClassName: string, fadeClassName: string, customThemeClassName: string) => t.ScrollerThin) | undefined;
|
||||
export function setCreateScroller(cs: NonNullable<typeof createScroller>) {
|
||||
createScroller = cs;
|
||||
}
|
||||
|
||||
export let createListScroller: (scrollBarClassName: string, fadeClassName: string, someOtherClassIdkMan: string, resizeObserverClass: typeof ResizeObserver) => t.ListScrollerThin;
|
||||
waitFor(filters.byCode("getScrollerNode:", "resizeObserver:", "sectionHeight:"), m => createListScroller = m);
|
||||
|
||||
const listScrollerClassnames = ["thin", "auto", "fade"] as const;
|
||||
export const scrollerClasses = findCssClassesLazy("thin", "auto", "fade", "customTheme", "none");
|
||||
|
|
@ -89,12 +97,9 @@ export const listScrollerClasses = proxyLazyWebpack(() => {
|
|||
return mapMangledCssClasses(mod, listScrollerClassnames);
|
||||
});
|
||||
|
||||
waitFor(filters.byCode('="ltr",orientation:', "customTheme:", "forwardRef"), m => createScroller = m);
|
||||
waitFor(filters.byCode("getScrollerNode:", "resizeObserver:", "sectionHeight:"), m => createListScroller = m);
|
||||
|
||||
export const ScrollerNone = LazyComponent(() => createScroller(scrollerClasses.none, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||
export const ScrollerThin = LazyComponent(() => createScroller(scrollerClasses.thin, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||
export const ScrollerAuto = LazyComponent(() => createScroller(scrollerClasses.auto, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||
export const ScrollerNone = LazyComponent(() => createScroller?.(scrollerClasses.none, scrollerClasses.fade, scrollerClasses.customTheme)!);
|
||||
export const ScrollerThin = LazyComponent(() => createScroller?.(scrollerClasses.thin, scrollerClasses.fade, scrollerClasses.customTheme)!);
|
||||
export const ScrollerAuto = LazyComponent(() => createScroller?.(scrollerClasses.auto, scrollerClasses.fade, scrollerClasses.customTheme)!);
|
||||
|
||||
export const ListScrollerThin = LazyComponent(() => createListScroller(listScrollerClasses.thin, listScrollerClasses.fade, "", ResizeObserver));
|
||||
export const ListScrollerAuto = LazyComponent(() => createListScroller(listScrollerClasses.auto, listScrollerClasses.fade, "", ResizeObserver));
|
||||
|
|
|
|||
|
|
@ -307,7 +307,6 @@ function proxyFactoryAndUpdateExisting(moduleFactories: AnyWebpackRequire["m"],
|
|||
*/
|
||||
function updateExistingFactory(moduleFactories: AnyWebpackRequire["m"], moduleId: PropertyKey, newFactory: AnyModuleFactory, newProxiedFactory: AnyModuleFactory, ignoreExistingInTarget: boolean) {
|
||||
let existingFactory: AnyModuleFactory | undefined;
|
||||
let moduleFactoriesWithFactory: AnyWebpackRequire["m"] | undefined;
|
||||
for (const wreq of allWebpackInstances) {
|
||||
const instanceModuleFactories = wreq.m[SYM_ORIGINAL_MODULE_FACTORIES] ?? wreq.m;
|
||||
|
||||
|
|
@ -317,7 +316,6 @@ function updateExistingFactory(moduleFactories: AnyWebpackRequire["m"], moduleId
|
|||
|
||||
if (Object.hasOwn(wreq.m, moduleId)) {
|
||||
existingFactory = wreq.m[moduleId]; // Must use wreq.m here instead of instanceModuleFactories to use our proxy in case the module factories are already proxied.
|
||||
moduleFactoriesWithFactory = instanceModuleFactories;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue