Merge branch 'main' of https://github.com/Vendicated/Vencord
This commit is contained in:
commit
80866a609b
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.10.6",
|
"version": "1.10.7",
|
||||||
"description": "The cutest Discord client mod",
|
"description": "The cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -225,7 +225,7 @@ page.on("console", async e => {
|
||||||
plugin,
|
plugin,
|
||||||
type,
|
type,
|
||||||
id,
|
id,
|
||||||
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
|
match: regex.replace(/\(\?:\[A-Za-z_\$\]\[\\w\$\]\*\)/g, "\\i"),
|
||||||
error: await maybeGetError(e.args()[3])
|
error: await maybeGetError(e.args()[3])
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ function FullPatchInput({ setFind, setParsedFind, setMatch, setReplacement }: Fu
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = (0, eval)(`(${fullPatch})`) as Patch;
|
const parsed = (0, eval)(`([${fullPatch}][0])`) as Patch;
|
||||||
|
|
||||||
if (!parsed.find) throw new Error("No 'find' field");
|
if (!parsed.find) throw new Error("No 'find' field");
|
||||||
if (!parsed.replacement) throw new Error("No 'replacement' field");
|
if (!parsed.replacement) throw new Error("No 'replacement' field");
|
||||||
|
|
|
@ -27,7 +27,12 @@ export async function loadLazyChunks() {
|
||||||
|
|
||||||
const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/g);
|
const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/g);
|
||||||
|
|
||||||
|
const foundCssDebuggingLoad = false;
|
||||||
|
|
||||||
async function searchAndLoadLazyChunks(factoryCode: string) {
|
async function searchAndLoadLazyChunks(factoryCode: string) {
|
||||||
|
// Workaround to avoid loading the CSS debugging chunk which turns the app pink
|
||||||
|
const hasCssDebuggingLoad = foundCssDebuggingLoad ? false : factoryCode.includes(".cssDebuggingEnabled&&");
|
||||||
|
|
||||||
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
||||||
const validChunkGroups = new Set<[chunkIds: number[], entryPoint: number]>();
|
const validChunkGroups = new Set<[chunkIds: number[], entryPoint: number]>();
|
||||||
|
|
||||||
|
@ -43,6 +48,16 @@ export async function loadLazyChunks() {
|
||||||
let invalidChunkGroup = false;
|
let invalidChunkGroup = false;
|
||||||
|
|
||||||
for (const id of chunkIds) {
|
for (const id of chunkIds) {
|
||||||
|
if (hasCssDebuggingLoad) {
|
||||||
|
if (chunkIds.length > 1) {
|
||||||
|
throw new Error("Found multiple chunks in factory that loads the CSS debugging chunk");
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidChunks.add(id);
|
||||||
|
invalidChunkGroup = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (wreq.u(id) == null || wreq.u(id) === "undefined.js") continue;
|
if (wreq.u(id) == null || wreq.u(id) === "undefined.js") continue;
|
||||||
|
|
||||||
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
||||||
|
|
|
@ -59,15 +59,7 @@ export default definePlugin({
|
||||||
replace: "$&return;"
|
replace: "$&return;"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
find: ".installedLogHooks)",
|
|
||||||
replacement: {
|
|
||||||
// if getDebugLogging() returns false, the hooks don't get installed.
|
|
||||||
match: "getDebugLogging(){",
|
|
||||||
replace: "getDebugLogging(){return false;"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
startAt: StartAt.Init,
|
startAt: StartAt.Init,
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default definePlugin({
|
||||||
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /({(?=.+?function (\i).{0,120}(\i)=\i\.useMemo.{0,60}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
||||||
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -28,10 +28,18 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: 'action:"EXPAND_ROLES"',
|
find: 'action:"EXPAND_ROLES"',
|
||||||
replacement: {
|
replacement: [
|
||||||
match: /(roles:\i(?=.+?(\i)\(!0\)[,;]\i\({action:"EXPAND_ROLES"}\)).+?\[\i,\2\]=\i\.useState\()!1\)/,
|
{
|
||||||
replace: (_, rest, setExpandedRoles) => `${rest}!0)`
|
match: /(roles:\i(?=.+?(\i)\(!0\)[,;]\i\({action:"EXPAND_ROLES"}\)).+?\[\i,\2\]=\i\.useState\()!1\)/,
|
||||||
}
|
replace: (_, rest, setExpandedRoles) => `${rest}!0)`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Fix not calculating non-expanded roles because the above patch makes the default "expanded",
|
||||||
|
// which makes the collapse button never show up and calculation never occur
|
||||||
|
match: /(?<=useLayoutEffect\(\(\)=>{if\()\i/,
|
||||||
|
replace: isExpanded => "false"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -275,16 +275,16 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
makeGuildsBarGuildListFilter(isBetterFolders: boolean) {
|
makeGuildsBarGuildListFilter(isBetterFolders: boolean) {
|
||||||
try {
|
|
||||||
return child => {
|
return child => {
|
||||||
if (isBetterFolders) {
|
if (isBetterFolders) {
|
||||||
return child?.props?.["aria-label"] === getIntlMessage("SERVERS");
|
try {
|
||||||
|
return child?.props?.["aria-label"] === getIntlMessage("SERVERS");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
} catch {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
makeGuildsBarTreeFilter(isBetterFolders: boolean) {
|
makeGuildsBarTreeFilter(isBetterFolders: boolean) {
|
||||||
|
|
|
@ -130,6 +130,27 @@ export default definePlugin({
|
||||||
replace: ""
|
replace: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Zustand section
|
||||||
|
{
|
||||||
|
find: "[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.",
|
||||||
|
replacement: [
|
||||||
|
{
|
||||||
|
match: /&&console\.warn\("\[DEPRECATED\] Passing a vanilla store will be unsupported in a future version\. Instead use `import { useStore } from 'zustand'`\."\)/,
|
||||||
|
replace: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /console\.warn\("\[DEPRECATED\] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`\. They can be imported from 'zustand\/traditional'\. https:\/\/github\.com\/pmndrs\/zustand\/discussions\/1937"\),/,
|
||||||
|
replace: ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.",
|
||||||
|
replacement: {
|
||||||
|
match: /console\.warn\("\[DEPRECATED\] `getStorage`, `serialize` and `deserialize` options are deprecated\. Use `storage` option instead\."\),/,
|
||||||
|
replace: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
// Patches discords generic logger function
|
// Patches discords generic logger function
|
||||||
{
|
{
|
||||||
find: "Σ:",
|
find: "Σ:",
|
||||||
|
@ -147,5 +168,5 @@ export default definePlugin({
|
||||||
replace: "$self.NoopLogger()"
|
replace: "$self.NoopLogger()"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -93,7 +93,7 @@ export const useAuthorizationStore = proxyLazy(() => zustandCreate(
|
||||||
} as AuthorizationState),
|
} as AuthorizationState),
|
||||||
{
|
{
|
||||||
name: "decor-auth",
|
name: "decor-auth",
|
||||||
getStorage: () => indexedDBStorage,
|
storage: indexedDBStorage,
|
||||||
partialize: state => ({ tokens: state.tokens }),
|
partialize: state => ({ tokens: state.tokens }),
|
||||||
onRehydrateStorage: () => state => state?.init()
|
onRehydrateStorage: () => state => state?.init()
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,24 +95,39 @@ export const useUsersDecorationsStore = proxyLazy(() => zustandCreate((set: any,
|
||||||
} as UsersDecorationsState)));
|
} as UsersDecorationsState)));
|
||||||
|
|
||||||
export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | null | undefined {
|
export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | null | undefined {
|
||||||
const [decorAvatarDecoration, setDecorAvatarDecoration] = useState<string | null>(user ? useUsersDecorationsStore.getState().getAsset(user.id) ?? null : null);
|
try {
|
||||||
|
const [decorAvatarDecoration, setDecorAvatarDecoration] = useState<string | null>(user ? useUsersDecorationsStore.getState().getAsset(user.id) ?? null : null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const destructor = useUsersDecorationsStore.subscribe(
|
const destructor = (() => {
|
||||||
state => {
|
try {
|
||||||
if (!user) return;
|
return useUsersDecorationsStore.subscribe(
|
||||||
const newDecorAvatarDecoration = state.getAsset(user.id);
|
state => {
|
||||||
if (!newDecorAvatarDecoration) return;
|
if (!user) return;
|
||||||
if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration);
|
const newDecorAvatarDecoration = state.getAsset(user.id);
|
||||||
}
|
if (!newDecorAvatarDecoration) return;
|
||||||
);
|
if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return () => { };
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
if (user) {
|
try {
|
||||||
const { fetch: fetchUserDecorAvatarDecoration } = useUsersDecorationsStore.getState();
|
if (user) {
|
||||||
fetchUserDecorAvatarDecoration(user.id);
|
const { fetch: fetchUserDecorAvatarDecoration } = useUsersDecorationsStore.getState();
|
||||||
}
|
fetchUserDecorAvatarDecoration(user.id);
|
||||||
return destructor;
|
}
|
||||||
}, []);
|
} catch { }
|
||||||
|
|
||||||
return decorAvatarDecoration ? { asset: decorAvatarDecoration, skuId: SKU_ID } : null;
|
return destructor;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return decorAvatarDecoration ? { asset: decorAvatarDecoration, skuId: SKU_ID } : null;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,11 @@ import { addPreEditListener, addPreSendListener, removePreEditListener, removePr
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||||
import { getCurrentGuild } from "@utils/discord";
|
import { getCurrentGuild, getEmojiURL } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType, Patch } from "@utils/types";
|
import definePlugin, { OptionType, Patch } from "@utils/types";
|
||||||
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
||||||
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, IconUtils, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||||
import type { Emoji } from "@webpack/types";
|
import type { Emoji } from "@webpack/types";
|
||||||
import type { Message } from "discord-types/general";
|
import type { Message } from "discord-types/general";
|
||||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||||
|
@ -920,7 +920,7 @@ export default definePlugin({
|
||||||
|
|
||||||
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
||||||
|
|
||||||
const url = new URL(IconUtils.getEmojiURL({ id: emoji.id, animated: emoji.animated, size: s.emojiSize }));
|
const url = new URL(getEmojiURL(emoji.id, emoji.animated, s.emojiSize));
|
||||||
url.searchParams.set("size", s.emojiSize.toString());
|
url.searchParams.set("size", s.emojiSize.toString());
|
||||||
url.searchParams.set("name", emoji.name);
|
url.searchParams.set("name", emoji.name);
|
||||||
|
|
||||||
|
@ -953,7 +953,7 @@ export default definePlugin({
|
||||||
|
|
||||||
hasBypass = true;
|
hasBypass = true;
|
||||||
|
|
||||||
const url = new URL(IconUtils.getEmojiURL({ id: emoji.id, animated: emoji.animated, size: s.emojiSize }));
|
const url = new URL(getEmojiURL(emoji.id, emoji.animated, s.emojiSize));
|
||||||
url.searchParams.set("size", s.emojiSize.toString());
|
url.searchParams.set("size", s.emojiSize.toString());
|
||||||
url.searchParams.set("name", emoji.name);
|
url.searchParams.set("name", emoji.name);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { getIntlMessage } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
import { findByPropsLazy } from "@webpack";
|
||||||
import { ChannelStore, FluxDispatcher, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
|
import { ChannelStore, FluxDispatcher, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@ interface MLMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
|
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
|
||||||
const getMessage = findByCodeLazy('replace(/^\\n+|\\n+$/g,"")');
|
|
||||||
|
|
||||||
function addDeleteStyle() {
|
function addDeleteStyle() {
|
||||||
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
|
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
|
||||||
|
@ -312,35 +311,33 @@ export default definePlugin({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
Messages: {
|
// DELETED_MESSAGE_COUNT: getMessage("{count, plural, =0 {No deleted messages} one {{count} deleted message} other {{count} deleted messages}}")
|
||||||
// DELETED_MESSAGE_COUNT: getMessage("{count, plural, =0 {No deleted messages} one {{count} deleted message} other {{count} deleted messages}}")
|
// TODO: Find a better way to generate intl messages
|
||||||
// TODO: find a better way to generate intl messages
|
DELETED_MESSAGE_COUNT: () => ({
|
||||||
DELETED_MESSAGE_COUNT: () => ({
|
ast: [[
|
||||||
ast: [[
|
6,
|
||||||
6,
|
"count",
|
||||||
"count",
|
{
|
||||||
{
|
"=0": ["No deleted messages"],
|
||||||
"=0": ["No deleted messages"],
|
one: [
|
||||||
one: [
|
[
|
||||||
[
|
1,
|
||||||
1,
|
"count"
|
||||||
"count"
|
|
||||||
],
|
|
||||||
" deleted message"
|
|
||||||
],
|
],
|
||||||
other: [
|
" deleted message"
|
||||||
[
|
],
|
||||||
1,
|
other: [
|
||||||
"count"
|
[
|
||||||
],
|
1,
|
||||||
" deleted messages"
|
"count"
|
||||||
]
|
],
|
||||||
},
|
" deleted messages"
|
||||||
0,
|
]
|
||||||
"cardinal"
|
},
|
||||||
]]
|
0,
|
||||||
})
|
"cardinal"
|
||||||
},
|
]]
|
||||||
|
}),
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -531,7 +528,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\?.*?:/,
|
match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\?.*?:/,
|
||||||
replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.Messages.DELETED_MESSAGE_COUNT:',
|
replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.DELETED_MESSAGE_COUNT:',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
predicate: () => Settings.plugins.MessageLogger.collapseDeleted
|
predicate: () => Settings.plugins.MessageLogger.collapseDeleted
|
||||||
|
|
|
@ -28,8 +28,8 @@ import { Message } from "discord-types/general";
|
||||||
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
||||||
|
|
||||||
interface MessageDeleteProps {
|
interface MessageDeleteProps {
|
||||||
// i18n message i18n.t["+FcYMz"] if deleted, with args
|
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
||||||
collapsedReason: () => any
|
collapsedReason: () => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
|
|
|
@ -20,7 +20,7 @@ const settings = definePluginSettings({
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "NoMosaic",
|
name: "NoMosaic",
|
||||||
authors: [Devs.AutumnVN],
|
authors: [Devs.AutumnVN],
|
||||||
description: "Removes Discord new image mosaic",
|
description: "Removes Discord image mosaic",
|
||||||
tags: ["image", "mosaic", "media"],
|
tags: ["image", "mosaic", "media"],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
@ -29,8 +29,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '=>"IMAGE"===',
|
find: '=>"IMAGE"===',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i;/,
|
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i(?:\|\|("VISUAL_PLACEHOLDER"===\i))?;/,
|
||||||
replace: "=>false;"
|
replace: (_, visualPlaceholderPred) => visualPlaceholderPred != null ? `=>${visualPlaceholderPred};` : "=>false;"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,8 @@ async function runMigrations() {
|
||||||
|
|
||||||
export async function syncAndRunChecks() {
|
export async function syncAndRunChecks() {
|
||||||
await runMigrations();
|
await runMigrations();
|
||||||
|
if (UserStore.getCurrentUser() == null) return;
|
||||||
|
|
||||||
const [oldGuilds, oldGroups, oldFriends] = await DataStore.getMany([
|
const [oldGuilds, oldGroups, oldFriends] = await DataStore.getMany([
|
||||||
guildsKey(),
|
guildsKey(),
|
||||||
groupsKey(),
|
groupsKey(),
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { Devs } from "@utils/constants";
|
||||||
import { getIntlMessage } from "@utils/discord";
|
import { getIntlMessage } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
import { findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
||||||
import { ChannelStore, GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
||||||
|
|
||||||
import { buildSeveralUsers } from "../typingTweaks";
|
import { buildSeveralUsers } from "../typingTweaks";
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ function getDisplayName(guildId: string, userId: string) {
|
||||||
return GuildMemberStore.getNick(guildId, userId) ?? (user as any).globalName ?? user.username;
|
return GuildMemberStore.getNick(guildId, userId) ?? (user as any).globalName ?? user.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TypingIndicator({ channelId }: { channelId: string; }) {
|
function TypingIndicator({ channelId, guildId }: { channelId: string; guildId: string; }) {
|
||||||
const typingUsers: Record<string, number> = useStateFromStores(
|
const typingUsers: Record<string, number> = useStateFromStores(
|
||||||
[TypingStore],
|
[TypingStore],
|
||||||
() => ({ ...TypingStore.getTypingUsers(channelId) as Record<string, number> }),
|
() => ({ ...TypingStore.getTypingUsers(channelId) as Record<string, number> }),
|
||||||
|
@ -57,7 +57,6 @@ function TypingIndicator({ channelId }: { channelId: string; }) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const currentChannelId: string = useStateFromStores([SelectedChannelStore], () => SelectedChannelStore.getChannelId());
|
const currentChannelId: string = useStateFromStores([SelectedChannelStore], () => SelectedChannelStore.getChannelId());
|
||||||
const guildId = ChannelStore.getChannel(channelId).guild_id;
|
|
||||||
|
|
||||||
if (!settings.store.includeMutedChannels) {
|
if (!settings.store.includeMutedChannels) {
|
||||||
const isChannelMuted = UserGuildSettingsStore.isChannelMuted(guildId, channelId);
|
const isChannelMuted = UserGuildSettingsStore.isChannelMuted(guildId, channelId);
|
||||||
|
@ -165,7 +164,7 @@ export default definePlugin({
|
||||||
find: "UNREAD_IMPORTANT:",
|
find: "UNREAD_IMPORTANT:",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\.name\),.{0,120}\.children.+?:null(?<=,channel:(\i).+?)/,
|
match: /\.name\),.{0,120}\.children.+?:null(?<=,channel:(\i).+?)/,
|
||||||
replace: "$&,$self.TypingIndicator($1.id)"
|
replace: "$&,$self.TypingIndicator($1.id,$1.getGuildId())"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Theads
|
// Theads
|
||||||
|
@ -174,14 +173,14 @@ export default definePlugin({
|
||||||
find: "M11 9H4C2.89543 9 2 8.10457 2 7V1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1V7C0 9.20914 1.79086 11 4 11H11C11.5523 11 12 10.5523 12 10C12 9.44771 11.5523 9 11 9Z",
|
find: "M11 9H4C2.89543 9 2 8.10457 2 7V1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1V7C0 9.20914 1.79086 11 4 11H11C11.5523 11 12 10.5523 12 10C12 9.44771 11.5523 9 11 9Z",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /mentionsCount:\i.+?null(?<=channel:(\i).+?)/,
|
match: /mentionsCount:\i.+?null(?<=channel:(\i).+?)/,
|
||||||
replace: "$&,$self.TypingIndicator($1.id)"
|
replace: "$&,$self.TypingIndicator($1.id,$1.getGuildId())"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
TypingIndicator: (channelId: string) => (
|
TypingIndicator: (channelId: string, guildId: string) => (
|
||||||
<ErrorBoundary noop>
|
<ErrorBoundary noop>
|
||||||
<TypingIndicator channelId={channelId} />
|
<TypingIndicator channelId={channelId} guildId={guildId} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
|
@ -129,14 +129,22 @@ export default definePlugin({
|
||||||
buildSeveralUsers,
|
buildSeveralUsers,
|
||||||
|
|
||||||
mutateChildren(props: any, users: User[], children: any) {
|
mutateChildren(props: any, users: User[], children: any) {
|
||||||
if (!Array.isArray(children)) return children;
|
try {
|
||||||
|
if (!Array.isArray(children)) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
let element = 0;
|
let element = 0;
|
||||||
|
|
||||||
return children.map(c =>
|
return children.map(c =>
|
||||||
c.type === "strong"
|
c.type === "strong" || (typeof c !== "string" && !React.isValidElement(c))
|
||||||
? <TypingUser {...props} user={users[element++]} />
|
? <TypingUser {...props} user={users[element++]} />
|
||||||
: c
|
: c
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -209,10 +209,11 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Group DMs top small & large icon
|
// Group DMs top small & large icon
|
||||||
{
|
{
|
||||||
find: /\.recipients\.length>=2(?!<isMultiUserDM.{0,50})/,
|
find: '["aria-hidden"],"aria-label":',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /null==\i\.icon\?.+?src:(\(0,\i\.\i\).+?\))(?=[,}])/,
|
match: /null==\i\.icon\?.+?src:(\(0,\i\.\i\).+?\))(?=[,}])/,
|
||||||
replace: (m, iconUrl) => `${m},onClick:()=>$self.openAvatar(${iconUrl})`
|
// We have to check that icon is not an unread GDM in the server bar
|
||||||
|
replace: (m, iconUrl) => `${m},onClick:()=>arguments[0]?.size!=="SIZE_48"&&$self.openAvatar(${iconUrl})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// User DMs top small icon
|
// User DMs top small icon
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import "./discord.css";
|
import "./discord.css";
|
||||||
|
|
||||||
import { MessageObject } from "@api/MessageEvents";
|
import { MessageObject } from "@api/MessageEvents";
|
||||||
import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, InviteActions, MessageActions, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
|
import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
|
||||||
import { Channel, Guild, Message, User } from "discord-types/general";
|
import { Channel, Guild, Message, User } from "discord-types/general";
|
||||||
import { Except } from "type-fest";
|
import { Except } from "type-fest";
|
||||||
|
|
||||||
|
@ -212,3 +212,14 @@ export async function fetchUserProfile(id: string, options?: FetchUserProfileOpt
|
||||||
export function getUniqueUsername(user: User) {
|
export function getUniqueUsername(user: User) {
|
||||||
return user.discriminator === "0" ? user.username : user.tag;
|
return user.discriminator === "0" ? user.username : user.tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL for an emoji. This function always returns a gif URL for animated emojis, instead of webp
|
||||||
|
* @param id The emoji id
|
||||||
|
* @param animated Whether the emoji is animated
|
||||||
|
* @param size The size for the emoji
|
||||||
|
*/
|
||||||
|
export function getEmojiURL(id: string, animated: boolean, size: number) {
|
||||||
|
const url = IconUtils.getEmojiURL({ id, animated, size });
|
||||||
|
return animated ? url.replace(".webp", ".gif") : url;
|
||||||
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ import { Patch, PatchReplacement, ReplaceFn } from "./types";
|
||||||
|
|
||||||
export function canonicalizeMatch<T extends RegExp | string>(match: T): T {
|
export function canonicalizeMatch<T extends RegExp | string>(match: T): T {
|
||||||
let partialCanon = typeof match === "string" ? match : match.source;
|
let partialCanon = typeof match === "string" ? match : match.source;
|
||||||
partialCanon = partialCanon.replaceAll(/#{intl::([A-Za-z_$][\w$]*)}/g, (_, key) => {
|
partialCanon = partialCanon.replaceAll(/#{intl::([\w$+/]*)(?:::(\w+))?}/g, (_, key, modifier) => {
|
||||||
const hashed = runtimeHashMessageKey(key);
|
const hashed = modifier === "raw" ? key : runtimeHashMessageKey(key);
|
||||||
|
|
||||||
const isString = typeof match === "string";
|
const isString = typeof match === "string";
|
||||||
const hasSpecialChars = !Number.isNaN(Number(hashed[0])) || hashed.includes("+") || hashed.includes("/");
|
const hasSpecialChars = !Number.isNaN(Number(hashed[0])) || hashed.includes("+") || hashed.includes("/");
|
||||||
|
@ -40,7 +40,7 @@ export function canonicalizeMatch<T extends RegExp | string>(match: T): T {
|
||||||
return partialCanon as T;
|
return partialCanon as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canonSource = partialCanon.replaceAll(String.raw`\i`, String.raw`(?:[A-Za-z_$][\w$]*)`);
|
const canonSource = partialCanon.replaceAll("\\i", String.raw`(?:[A-Za-z_$][\w$]*)`);
|
||||||
return new RegExp(canonSource, match.flags) as T;
|
return new RegExp(canonSource, match.flags) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,9 +163,13 @@ waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m);
|
||||||
|
|
||||||
export const PermissionsBits: t.PermissionsBits = findLazy(m => typeof m.ADMINISTRATOR === "bigint");
|
export const PermissionsBits: t.PermissionsBits = findLazy(m => typeof m.ADMINISTRATOR === "bigint");
|
||||||
|
|
||||||
export const zustandCreate = findByCodeLazy("will be removed in v4");
|
export const { zustandCreate } = mapMangledModuleLazy(["useSyncExternalStoreWithSelector:", "Object.assign", /(\i)\?(\i)\(\1\):\2/], {
|
||||||
|
zustandCreate: filters.byCode(/(\i)\?(\i)\(\1\):\2/)
|
||||||
|
});
|
||||||
|
|
||||||
export const zustandPersist = findByCodeLazy("[zustand persist middleware]");
|
export const { zustandPersist } = mapMangledModuleLazy(".onRehydrateStorage)?", {
|
||||||
|
zustandPersist: filters.byCode(/(\(\i,\i\))=>.+?\i\1/)
|
||||||
|
});
|
||||||
|
|
||||||
export const MessageActions = findByPropsLazy("editMessage", "sendMessage");
|
export const MessageActions = findByPropsLazy("editMessage", "sendMessage");
|
||||||
export const MessageCache = findByPropsLazy("clearCache", "_channelMessages");
|
export const MessageCache = findByPropsLazy("clearCache", "_channelMessages");
|
||||||
|
@ -181,7 +185,7 @@ export const ExpressionPickerStore: t.ExpressionPickerStore = mapMangledModuleLa
|
||||||
toggleExpressionPicker: filters.byCode(/getState\(\)\.activeView===\i\?\i\(\):\i\(/),
|
toggleExpressionPicker: filters.byCode(/getState\(\)\.activeView===\i\?\i\(\):\i\(/),
|
||||||
setExpressionPickerView: filters.byCode(/setState\({activeView:\i,lastActiveView:/),
|
setExpressionPickerView: filters.byCode(/setState\({activeView:\i,lastActiveView:/),
|
||||||
setSearchQuery: filters.byCode("searchQuery:"),
|
setSearchQuery: filters.byCode("searchQuery:"),
|
||||||
useExpressionPickerStore: filters.byCode("Object.is")
|
useExpressionPickerStore: filters.byCode(/\(\i,\i=\i\)=>/)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PopoutActions: t.PopoutActions = mapMangledModuleLazy('type:"POPOUT_WINDOW_OPEN"', {
|
export const PopoutActions: t.PopoutActions = mapMangledModuleLazy('type:"POPOUT_WINDOW_OPEN"', {
|
||||||
|
|
Loading…
Reference in a new issue