mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-25 16:56:23 +00:00
Merge branch 'main' into plugin/memberListActivities
This commit is contained in:
commit
896421a9fa
30 changed files with 411 additions and 176 deletions
|
@ -62,7 +62,7 @@ function GM_fetch(url, opt) {
|
|||
resp.arrayBuffer = () => blobTo("arrayBuffer", blob);
|
||||
resp.text = () => blobTo("text", blob);
|
||||
resp.json = async () => JSON.parse(await blobTo("text", blob));
|
||||
resp.headers = new Headers(parseHeaders(resp.responseHeaders));
|
||||
resp.headers = parseHeaders(resp.responseHeaders);
|
||||
resp.ok = resp.status >= 200 && resp.status < 300;
|
||||
resolve(resp);
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.6.9",
|
||||
"version": "1.7.0",
|
||||
"description": "The cutest Discord client mod",
|
||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||
"bugs": {
|
||||
|
|
|
@ -428,10 +428,11 @@ function runTime(token: string) {
|
|||
|
||||
if (searchType === "findComponent") method = "find";
|
||||
if (searchType === "findExportedComponent") method = "findByProps";
|
||||
if (searchType === "waitFor" || searchType === "waitForComponent" || searchType === "waitForStore") {
|
||||
if (searchType === "waitFor" || searchType === "waitForComponent") {
|
||||
if (typeof args[0] === "string") method = "findByProps";
|
||||
else method = "find";
|
||||
}
|
||||
if (searchType === "waitForStore") method = "findStore";
|
||||
|
||||
try {
|
||||
let result: any;
|
||||
|
|
|
@ -74,7 +74,7 @@ export interface MessageExtra {
|
|||
}
|
||||
|
||||
export type SendListener = (channelId: string, messageObj: MessageObject, extra: MessageExtra) => Promisable<void | { cancel: boolean; }>;
|
||||
export type EditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable<void>;
|
||||
export type EditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable<void | { cancel: boolean; }>;
|
||||
|
||||
const sendListeners = new Set<SendListener>();
|
||||
const editListeners = new Set<EditListener>();
|
||||
|
@ -84,7 +84,7 @@ export async function _handlePreSend(channelId: string, messageObj: MessageObjec
|
|||
for (const listener of sendListeners) {
|
||||
try {
|
||||
const result = await listener(channelId, messageObj, extra);
|
||||
if (result && result.cancel === true) {
|
||||
if (result?.cancel) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -97,11 +97,15 @@ export async function _handlePreSend(channelId: string, messageObj: MessageObjec
|
|||
export async function _handlePreEdit(channelId: string, messageId: string, messageObj: MessageObject) {
|
||||
for (const listener of editListeners) {
|
||||
try {
|
||||
await listener(channelId, messageId, messageObj);
|
||||
const result = await listener(channelId, messageId, messageObj);
|
||||
if (result?.cancel) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
MessageEventsLogger.error("MessageEditHandler: Listener encountered an unknown error\n", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,9 +39,7 @@ function validateUrl(url: string) {
|
|||
async function eraseAllData() {
|
||||
const res = await fetch(new URL("/v1/", getCloudUrl()), {
|
||||
method: "DELETE",
|
||||
headers: new Headers({
|
||||
Authorization: await getCloudAuth()
|
||||
})
|
||||
headers: { Authorization: await getCloudAuth() }
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
|
|
|
@ -25,10 +25,13 @@ export default definePlugin({
|
|||
authors: [Devs.Arjix, Devs.hunt, Devs.Ven],
|
||||
patches: [
|
||||
{
|
||||
find: '"MessageActionCreators"',
|
||||
find: ".Messages.EDIT_TEXTAREA_HELP",
|
||||
replacement: {
|
||||
match: /async editMessage\(.+?\)\{/,
|
||||
replace: "$&await Vencord.Api.MessageEvents._handlePreEdit(...arguments);"
|
||||
match: /(?<=,channel:\i\}\)\.then\().+?(?=return \i\.content!==this\.props\.message\.content&&\i\((.+?)\))/,
|
||||
replace: (match, args) => "" +
|
||||
`async ${match}` +
|
||||
`if(await Vencord.Api.MessageEvents._handlePreEdit(${args}))` +
|
||||
"return Promise.resolve({shoudClear:true,shouldRefocus:true});"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
// Add Decor avatar decoration hook to avatar decoration hook
|
||||
{
|
||||
match: /(?<=TryItOut:\i}\),)(?<=user:(\i).+?)/,
|
||||
match: /(?<=TryItOut:\i,guildId:\i}\),)(?<=user:(\i).+?)/,
|
||||
replace: "vcDecorAvatarDecoration=$self.useUserDecorAvatarDecoration($1),"
|
||||
},
|
||||
// Use added hook
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
*/
|
||||
|
||||
import { addPreEditListener, addPreSendListener, removePreEditListener, removePreSendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||
import { getCurrentGuild } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
||||
import { ChannelStore, EmojiStore, FluxDispatcher, lodash, Parser, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||
import { Alerts, ChannelStore, EmojiStore, FluxDispatcher, Forms, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||
import type { Message } from "discord-types/general";
|
||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||
import type { ReactElement, ReactNode } from "react";
|
||||
|
@ -51,8 +51,6 @@ const PreloadedUserSettingsActionCreators = proxyLazyWebpack(() => UserSettingsA
|
|||
const AppearanceSettingsActionCreators = proxyLazyWebpack(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
||||
const ClientThemeSettingsActionsCreators = proxyLazyWebpack(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
||||
|
||||
const USE_EXTERNAL_EMOJIS = 1n << 18n;
|
||||
const USE_EXTERNAL_STICKERS = 1n << 37n;
|
||||
|
||||
const enum EmojiIntentions {
|
||||
REACTION = 0,
|
||||
|
@ -162,8 +160,28 @@ const settings = definePluginSettings({
|
|||
description: "Whether to use hyperlinks when sending fake emojis and stickers",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
},
|
||||
hyperLinkText: {
|
||||
description: "What text the hyperlink should use. {{NAME}} will be replaced with the emoji name.",
|
||||
type: OptionType.STRING,
|
||||
default: "{{NAME}}"
|
||||
}
|
||||
});
|
||||
}).withPrivateSettings<{
|
||||
disableEmbedPermissionCheck: boolean;
|
||||
}>();
|
||||
|
||||
function hasPermission(channelId: string, permission: bigint) {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
|
||||
if (!channel || channel.isPrivate()) return true;
|
||||
|
||||
return PermissionStore.can(permission, channel);
|
||||
}
|
||||
|
||||
const hasExternalEmojiPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.USE_EXTERNAL_EMOJIS);
|
||||
const hasExternalStickerPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.USE_EXTERNAL_STICKERS);
|
||||
const hasEmbedPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.EMBED_LINKS);
|
||||
const hasAttachmentPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.ATTACH_FILES);
|
||||
|
||||
export default definePlugin({
|
||||
name: "FakeNitro",
|
||||
|
@ -351,8 +369,8 @@ export default definePlugin({
|
|||
predicate: () => settings.store.transformEmojis,
|
||||
replacement: {
|
||||
// Add the fake nitro emoji notice
|
||||
match: /(?<=isDiscoverable:\i,emojiComesFromCurrentGuild:\i,.+?}=(\i).+?;)(.*?return )(.{0,1000}\.Messages\.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION.+?)(?=},)/,
|
||||
replace: (_, props, rest, reactNode) => `let{fakeNitroNode}=${props};${rest}$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!fakeNitroNode?.fake)`
|
||||
match: /(?<=emojiDescription:)(\i)(?<=\1=\i\((\i)\).+?)/,
|
||||
replace: (_, reactNode, props) => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!${props}?.fakeNitroNode?.fake)`
|
||||
}
|
||||
},
|
||||
// Allow using custom app icons
|
||||
|
@ -456,7 +474,7 @@ export default definePlugin({
|
|||
if (typeof firstContent === "string") {
|
||||
content[0] = firstContent.trimStart();
|
||||
content[0] || content.shift();
|
||||
} else if (firstContent?.type === "span") {
|
||||
} else if (typeof firstContent?.props?.children === "string") {
|
||||
firstContent.props.children = firstContent.props.children.trimStart();
|
||||
firstContent.props.children || content.shift();
|
||||
}
|
||||
|
@ -466,7 +484,7 @@ export default definePlugin({
|
|||
if (typeof lastContent === "string") {
|
||||
content[lastIndex] = lastContent.trimEnd();
|
||||
content[lastIndex] || content.pop();
|
||||
} else if (lastContent?.type === "span") {
|
||||
} else if (typeof lastContent?.props?.children === "string") {
|
||||
lastContent.props.children = lastContent.props.children.trimEnd();
|
||||
lastContent.props.children || content.pop();
|
||||
}
|
||||
|
@ -696,22 +714,6 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
|
||||
hasPermissionToUseExternalEmojis(channelId: string): boolean {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
|
||||
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return true;
|
||||
|
||||
return PermissionStore.can(USE_EXTERNAL_EMOJIS, channel);
|
||||
},
|
||||
|
||||
hasPermissionToUseExternalStickers(channelId: string) {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
|
||||
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return true;
|
||||
|
||||
return PermissionStore.can(USE_EXTERNAL_STICKERS, channel);
|
||||
},
|
||||
|
||||
getStickerLink(stickerId: string) {
|
||||
return `https://media.discordapp.net/stickers/${stickerId}.png?size=${settings.store.stickerSize}`;
|
||||
},
|
||||
|
@ -722,7 +724,7 @@ export default definePlugin({
|
|||
const { frames, width, height } = await parseURL(stickerLink);
|
||||
|
||||
const gif = GIFEncoder();
|
||||
const resolution = Settings.plugins.FakeNitro.stickerSize;
|
||||
const resolution = settings.store.stickerSize;
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = resolution;
|
||||
|
@ -783,9 +785,38 @@ export default definePlugin({
|
|||
return (!origStr[offset] || /\s/.test(origStr[offset])) ? "" : " ";
|
||||
}
|
||||
|
||||
this.preSend = addPreSendListener((channelId, messageObj, extra) => {
|
||||
function cannotEmbedNotice() {
|
||||
return new Promise<boolean>(resolve => {
|
||||
Alerts.show({
|
||||
title: "Hold on!",
|
||||
body: <div>
|
||||
<Forms.FormText>
|
||||
You are trying to send/edit a message that contains a FakeNitro emoji or sticker
|
||||
, however you do not have permissions to embed links in the current channel.
|
||||
Are you sure you want to send this message? Your FakeNitro items will appear as a link only.
|
||||
</Forms.FormText>
|
||||
<Forms.FormText type={Forms.FormText.Types.DESCRIPTION}>
|
||||
You can disable this notice in the plugin settings.
|
||||
</Forms.FormText>
|
||||
</div>,
|
||||
confirmText: "Send Anyway",
|
||||
cancelText: "Cancel",
|
||||
secondaryConfirmText: "Do not show again",
|
||||
onConfirm: () => resolve(true),
|
||||
onCloseCallback: () => setImmediate(() => resolve(false)),
|
||||
onConfirmSecondary() {
|
||||
settings.store.disableEmbedPermissionCheck = true;
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.preSend = addPreSendListener(async (channelId, messageObj, extra) => {
|
||||
const { guildId } = this;
|
||||
|
||||
let hasBypass = false;
|
||||
|
||||
stickerBypass: {
|
||||
if (!s.enableStickerBypass)
|
||||
break stickerBypass;
|
||||
|
@ -798,7 +829,7 @@ export default definePlugin({
|
|||
if ("pack_id" in sticker)
|
||||
break stickerBypass;
|
||||
|
||||
const canUseStickers = this.canUseStickers && this.hasPermissionToUseExternalStickers(channelId);
|
||||
const canUseStickers = this.canUseStickers && hasExternalStickerPerms(channelId);
|
||||
if (sticker.available !== false && (canUseStickers || sticker.guild_id === guildId))
|
||||
break stickerBypass;
|
||||
|
||||
|
@ -812,9 +843,24 @@ export default definePlugin({
|
|||
}
|
||||
|
||||
if (sticker.format_type === StickerType.APNG) {
|
||||
this.sendAnimatedSticker(link, sticker.id, channelId);
|
||||
if (!hasAttachmentPerms(channelId)) {
|
||||
Alerts.show({
|
||||
title: "Hold on!",
|
||||
body: <div>
|
||||
<Forms.FormText>
|
||||
You cannot send this message because it contains an animated FakeNitro sticker,
|
||||
and you do not have permissions to attach files in the current channel. Please remove the sticker to proceed.
|
||||
</Forms.FormText>
|
||||
</div>
|
||||
});
|
||||
} else {
|
||||
this.sendAnimatedSticker(link, sticker.id, channelId);
|
||||
}
|
||||
|
||||
return { cancel: true };
|
||||
} else {
|
||||
hasBypass = true;
|
||||
|
||||
const url = new URL(link);
|
||||
url.searchParams.set("name", sticker.name);
|
||||
|
||||
|
@ -824,35 +870,47 @@ export default definePlugin({
|
|||
}
|
||||
|
||||
if (s.enableEmojiBypass) {
|
||||
const canUseEmotes = this.canUseEmotes && this.hasPermissionToUseExternalEmojis(channelId);
|
||||
const canUseEmotes = this.canUseEmotes && hasExternalEmojiPerms(channelId);
|
||||
|
||||
for (const emoji of messageObj.validNonShortcutEmojis) {
|
||||
if (!emoji.require_colons) continue;
|
||||
if (emoji.available !== false && canUseEmotes) continue;
|
||||
if (emoji.guildId === guildId && !emoji.animated) continue;
|
||||
|
||||
hasBypass = true;
|
||||
|
||||
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
||||
|
||||
const url = new URL(emoji.url);
|
||||
url.searchParams.set("size", s.emojiSize.toString());
|
||||
url.searchParams.set("name", emoji.name);
|
||||
|
||||
const linkText = s.hyperLinkText.replaceAll("{{NAME}}", emoji.name);
|
||||
|
||||
messageObj.content = messageObj.content.replace(emojiString, (match, offset, origStr) => {
|
||||
return `${getWordBoundary(origStr, offset - 1)}${s.useHyperLinks ? `[${emoji.name}](${url})` : url}${getWordBoundary(origStr, offset + match.length)}`;
|
||||
return `${getWordBoundary(origStr, offset - 1)}${s.useHyperLinks ? `[${linkText}](${url})` : url}${getWordBoundary(origStr, offset + match.length)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBypass && !s.disableEmbedPermissionCheck && !hasEmbedPerms(channelId)) {
|
||||
if (!await cannotEmbedNotice()) {
|
||||
return { cancel: true };
|
||||
}
|
||||
}
|
||||
|
||||
return { cancel: false };
|
||||
});
|
||||
|
||||
this.preEdit = addPreEditListener((channelId, __, messageObj) => {
|
||||
this.preEdit = addPreEditListener(async (channelId, __, messageObj) => {
|
||||
if (!s.enableEmojiBypass) return;
|
||||
|
||||
const canUseEmotes = this.canUseEmotes && this.hasPermissionToUseExternalEmojis(channelId);
|
||||
|
||||
const { guildId } = this;
|
||||
|
||||
let hasBypass = false;
|
||||
|
||||
const canUseEmotes = this.canUseEmotes && hasExternalEmojiPerms(channelId);
|
||||
|
||||
messageObj.content = messageObj.content.replace(/(?<!\\)<a?:(?:\w+):(\d+)>/ig, (emojiStr, emojiId, offset, origStr) => {
|
||||
const emoji = EmojiStore.getCustomEmojiById(emojiId);
|
||||
if (emoji == null) return emojiStr;
|
||||
|
@ -860,12 +918,24 @@ export default definePlugin({
|
|||
if (emoji.available !== false && canUseEmotes) return emojiStr;
|
||||
if (emoji.guildId === guildId && !emoji.animated) return emojiStr;
|
||||
|
||||
hasBypass = true;
|
||||
|
||||
const url = new URL(emoji.url);
|
||||
url.searchParams.set("size", s.emojiSize.toString());
|
||||
url.searchParams.set("name", emoji.name);
|
||||
|
||||
return `${getWordBoundary(origStr, offset - 1)}${s.useHyperLinks ? `[${emoji.name}](${url})` : url}${getWordBoundary(origStr, offset + emojiStr.length)}`;
|
||||
const linkText = s.hyperLinkText.replaceAll("{{NAME}}", emoji.name);
|
||||
|
||||
return `${getWordBoundary(origStr, offset - 1)}${s.useHyperLinks ? `[${linkText}](${url})` : url}${getWordBoundary(origStr, offset + emojiStr.length)}`;
|
||||
});
|
||||
|
||||
if (hasBypass && !s.disableEmbedPermissionCheck && !hasEmbedPerms(channelId)) {
|
||||
if (!await cannotEmbedNotice()) {
|
||||
return { cancel: true };
|
||||
}
|
||||
}
|
||||
|
||||
return { cancel: false };
|
||||
});
|
||||
},
|
||||
|
|
@ -9,6 +9,9 @@
|
|||
box-shadow: inset 0 0 10px 2px grey;
|
||||
filter: drop-shadow(0 0 2px grey);
|
||||
pointer-events: none;
|
||||
|
||||
/* negate the border offsetting the lens */
|
||||
margin: -2px;
|
||||
}
|
||||
|
||||
.vc-imgzoom-square {
|
||||
|
|
|
@ -170,6 +170,11 @@ const settings = definePluginSettings({
|
|||
}
|
||||
],
|
||||
},
|
||||
showLastFmLogo: {
|
||||
description: "show the Last.fm logo by the album cover",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
|
@ -276,8 +281,10 @@ export default definePlugin({
|
|||
{
|
||||
large_image: await getApplicationAsset(largeImage),
|
||||
large_text: trackData.album || undefined,
|
||||
small_image: await getApplicationAsset("lastfm-small"),
|
||||
small_text: "Last.fm",
|
||||
...(settings.store.showLastFmLogo && {
|
||||
small_image: await getApplicationAsset("lastfm-small"),
|
||||
small_text: "Last.fm"
|
||||
}),
|
||||
} : {
|
||||
large_image: await getApplicationAsset("lastfm-large"),
|
||||
large_text: trackData.album || undefined,
|
||||
|
|
66
src/plugins/memberCount/MemberCount.tsx
Normal file
66
src/plugins/memberCount/MemberCount.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import { SelectedChannelStore, Tooltip, useEffect, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { ChannelMemberStore, cl, GuildMemberCountStore, numberFormat } from ".";
|
||||
import { OnlineMemberCountStore } from "./OnlineMemberCountStore";
|
||||
|
||||
export function MemberCount({ isTooltip, tooltipGuildId }: { isTooltip?: true; tooltipGuildId?: string; }) {
|
||||
const currentChannel = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||
|
||||
const guildId = isTooltip ? tooltipGuildId! : currentChannel.guild_id;
|
||||
|
||||
const totalCount = useStateFromStores(
|
||||
[GuildMemberCountStore],
|
||||
() => GuildMemberCountStore.getMemberCount(guildId)
|
||||
);
|
||||
|
||||
let onlineCount = useStateFromStores(
|
||||
[OnlineMemberCountStore],
|
||||
() => OnlineMemberCountStore.getCount(guildId)
|
||||
);
|
||||
|
||||
const { groups } = useStateFromStores(
|
||||
[ChannelMemberStore],
|
||||
() => ChannelMemberStore.getProps(guildId, currentChannel.id)
|
||||
);
|
||||
|
||||
if (!isTooltip && (groups.length >= 1 || groups[0].id !== "unknown")) {
|
||||
onlineCount = groups.reduce((total, curr) => total + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
OnlineMemberCountStore.ensureCount(guildId);
|
||||
}, [guildId]);
|
||||
|
||||
if (totalCount == null)
|
||||
return null;
|
||||
|
||||
const formattedOnlineCount = onlineCount != null ? numberFormat(onlineCount) : "?";
|
||||
|
||||
return (
|
||||
<div className={cl("widget", { tooltip: isTooltip, "member-list": !isTooltip })}>
|
||||
<Tooltip text={`${formattedOnlineCount} online in this channel`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span className={cl("online-dot")} />
|
||||
<span className={cl("online")}>{formattedOnlineCount}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<Tooltip text={`${numberFormat(totalCount)} total server members`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span className={cl("total-dot")} />
|
||||
<span className={cl("total")}>{numberFormat(totalCount)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
52
src/plugins/memberCount/OnlineMemberCountStore.ts
Normal file
52
src/plugins/memberCount/OnlineMemberCountStore.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { sleep } from "@utils/misc";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { Flux, FluxDispatcher, GuildChannelStore, PrivateChannelsStore } from "@webpack/common";
|
||||
|
||||
export const OnlineMemberCountStore = proxyLazy(() => {
|
||||
const preloadQueue = new Queue();
|
||||
|
||||
const onlineMemberMap = new Map<string, number>();
|
||||
|
||||
class OnlineMemberCountStore extends Flux.Store {
|
||||
getCount(guildId: string) {
|
||||
return onlineMemberMap.get(guildId);
|
||||
}
|
||||
|
||||
async _ensureCount(guildId: string) {
|
||||
if (onlineMemberMap.has(guildId)) return;
|
||||
|
||||
await PrivateChannelsStore.preload(guildId, GuildChannelStore.getDefaultChannel(guildId).id);
|
||||
}
|
||||
|
||||
ensureCount(guildId: string) {
|
||||
if (onlineMemberMap.has(guildId)) return;
|
||||
|
||||
preloadQueue.push(() =>
|
||||
this._ensureCount(guildId)
|
||||
.then(
|
||||
() => sleep(200),
|
||||
() => sleep(200)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new OnlineMemberCountStore(FluxDispatcher, {
|
||||
GUILD_MEMBER_LIST_UPDATE({ guildId, groups }: { guildId: string, groups: { count: number; id: string; }[]; }) {
|
||||
onlineMemberMap.set(
|
||||
guildId,
|
||||
groups.reduce((total, curr) => total + (curr.id === "offline" ? 0 : curr.count), 0)
|
||||
);
|
||||
},
|
||||
ONLINE_GUILD_MEMBER_COUNT_UPDATE({ guildId, count }) {
|
||||
onlineMemberMap.set(guildId, count);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -16,101 +16,48 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
import { SelectedChannelStore, Tooltip, useStateFromStores } from "@webpack/common";
|
||||
import { FluxStore } from "@webpack/types";
|
||||
|
||||
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
import { MemberCount } from "./MemberCount";
|
||||
|
||||
export const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
export const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
||||
};
|
||||
|
||||
const sharedIntlNumberFormat = new Intl.NumberFormat();
|
||||
const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
|
||||
|
||||
function MemberCount() {
|
||||
const { id: channelId, guild_id: guildId } = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||
const { groups } = useStateFromStores(
|
||||
[ChannelMemberStore],
|
||||
() => ChannelMemberStore.getProps(guildId, channelId)
|
||||
);
|
||||
const total = useStateFromStores(
|
||||
[GuildMemberCountStore],
|
||||
() => GuildMemberCountStore.getMemberCount(guildId)
|
||||
);
|
||||
|
||||
if (total == null)
|
||||
return null;
|
||||
|
||||
const online =
|
||||
(groups.length === 1 && groups[0].id === "unknown")
|
||||
? 0
|
||||
: groups.reduce((count, curr) => count + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
|
||||
return (
|
||||
<Flex id="vc-membercount" style={{
|
||||
marginTop: "1em",
|
||||
paddingInline: "1em",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
gap: 0
|
||||
}}>
|
||||
<Tooltip text={`${numberFormat(online)} online in this channel`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: "var(--green-360)",
|
||||
width: "12px",
|
||||
height: "12px",
|
||||
borderRadius: "50%",
|
||||
display: "inline-block",
|
||||
marginRight: "0.5em"
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: "var(--green-360)" }}>{numberFormat(online)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<Tooltip text={`${numberFormat(total)} total server members`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
style={{
|
||||
width: "6px",
|
||||
height: "6px",
|
||||
borderRadius: "50%",
|
||||
border: "3px solid var(--primary-400)",
|
||||
display: "inline-block",
|
||||
marginRight: "0.5em",
|
||||
marginLeft: "1em"
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: "var(--primary-400)" }}>{numberFormat(total)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
export const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
|
||||
export const cl = classNameFactory("vc-membercount-");
|
||||
|
||||
export default definePlugin({
|
||||
name: "MemberCount",
|
||||
description: "Shows the amount of online & total members in the server member list",
|
||||
description: "Shows the amount of online & total members in the server member list and tooltip",
|
||||
authors: [Devs.Ven, Devs.Commandtechno],
|
||||
|
||||
patches: [{
|
||||
find: "{isSidebarVisible:",
|
||||
replacement: {
|
||||
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||
replace: ":[$1?.startsWith('members')?$self.render():null,$2"
|
||||
patches: [
|
||||
{
|
||||
find: "{isSidebarVisible:",
|
||||
replacement: {
|
||||
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||
replace: ":[$1?.startsWith('members')?$self.render():null,$2"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: ".invitesDisabledTooltip",
|
||||
replacement: {
|
||||
match: /(?<=\.VIEW_AS_ROLES_MENTIONS_WARNING.{0,100})]/,
|
||||
replace: ",$self.renderTooltip(arguments[0].guild)]"
|
||||
}
|
||||
}
|
||||
}],
|
||||
],
|
||||
|
||||
render: ErrorBoundary.wrap(MemberCount, { noop: true })
|
||||
render: ErrorBoundary.wrap(MemberCount, { noop: true }),
|
||||
renderTooltip: ErrorBoundary.wrap(guild => <MemberCount isTooltip tooltipGuildId={guild.id} />, { noop: true })
|
||||
});
|
||||
|
|
44
src/plugins/memberCount/style.css
Normal file
44
src/plugins/memberCount/style.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
.vc-membercount-widget {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
|
||||
--color-online: var(--green-360);
|
||||
--color-total: var(--primary-400);
|
||||
}
|
||||
|
||||
.vc-membercount-tooltip {
|
||||
margin-top: 0.25em;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.vc-membercount-member-list {
|
||||
justify-content: center;
|
||||
margin-top: 1em;
|
||||
padding-inline: 1em;
|
||||
}
|
||||
|
||||
.vc-membercount-online {
|
||||
color: var(--color-online);
|
||||
}
|
||||
|
||||
.vc-membercount-total {
|
||||
color: var(--color-total);
|
||||
}
|
||||
|
||||
.vc-membercount-online-dot {
|
||||
background-color: var(--color-online);
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.vc-membercount-total-dot {
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--color-total);
|
||||
margin: 0 0.5em 0 1em;
|
||||
}
|
|
@ -16,16 +16,18 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { definePluginSettings,migratePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
||||
const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings");
|
||||
const { toggleShowAllChannels } = findByPropsLazy("toggleShowAllChannels");
|
||||
const { isOptInEnabledForGuild } = findByPropsLazy("isOptInEnabledForGuild");
|
||||
|
||||
const settings = definePluginSettings({
|
||||
guild: {
|
||||
description: "Mute Guild",
|
||||
description: "Mute Guild automatically",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
},
|
||||
|
@ -38,13 +40,20 @@ const settings = definePluginSettings({
|
|||
description: "Suppress All Role @mentions",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
},
|
||||
showAllChannels: {
|
||||
description: "Show all channels automatically",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
migratePluginSettings("NewGuildSettings", "MuteNewGuild");
|
||||
export default definePlugin({
|
||||
name: "MuteNewGuild",
|
||||
description: "Mutes newly joined guilds",
|
||||
authors: [Devs.Glitch, Devs.Nuckyz, Devs.carince],
|
||||
name: "NewGuildSettings",
|
||||
description: "Automatically mute new servers and change various other settings upon joining",
|
||||
tags: ["MuteNewGuild", "mute", "server"],
|
||||
authors: [Devs.Glitch, Devs.Nuckyz, Devs.carince, Devs.Mopi],
|
||||
patches: [
|
||||
{
|
||||
find: ",acceptInvite(",
|
||||
|
@ -70,7 +79,9 @@ export default definePlugin({
|
|||
muted: settings.store.guild,
|
||||
suppress_everyone: settings.store.everyone,
|
||||
suppress_roles: settings.store.role
|
||||
}
|
||||
);
|
||||
});
|
||||
if (settings.store.showAllChannels && isOptInEnabledForGuild(guildId)) {
|
||||
toggleShowAllChannels(guildId);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -27,8 +27,8 @@ export default definePlugin({
|
|||
{
|
||||
find: "_ensureAudio(){",
|
||||
replacement: {
|
||||
match: /onloadeddata=\(\)=>\{.\.volume=/,
|
||||
replace: "$&$self.settings.store.notificationVolume/100*"
|
||||
match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/,
|
||||
replace: "$self.settings.store.notificationVolume/100*"
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -59,7 +59,7 @@ export function authorize(callback?: any) {
|
|||
const url = new URL(response.location);
|
||||
url.searchParams.append("clientMod", "vencord");
|
||||
const res = await fetch(url, {
|
||||
headers: new Headers({ Accept: "application/json" })
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
|
|
|
@ -32,6 +32,7 @@ const { Editor, Transforms } = findByPropsLazy("Editor", "Transforms");
|
|||
const { ChatInputTypes } = findByPropsLazy("ChatInputTypes");
|
||||
|
||||
const InputComponent = LazyComponent(() => find(m => m.default?.type?.render?.toString().includes("default.CHANNEL_TEXT_AREA")).default);
|
||||
const { createChannelRecordFromServer } = findByPropsLazy("createChannelRecordFromServer");
|
||||
|
||||
interface UserProps {
|
||||
discordId: string;
|
||||
|
@ -125,19 +126,7 @@ export function ReviewsInputComponent({ discordId, isAuthor, refetch, name }: {
|
|||
const inputType = ChatInputTypes.FORM;
|
||||
inputType.disableAutoFocus = true;
|
||||
|
||||
const channel = {
|
||||
flags_: 256,
|
||||
guild_id_: null,
|
||||
id: "0",
|
||||
getGuildId: () => null,
|
||||
isPrivate: () => true,
|
||||
isActiveThread: () => false,
|
||||
isArchivedLockedThread: () => false,
|
||||
isDM: () => true,
|
||||
roles: { "0": { permissions: 0n } },
|
||||
getRecipientId: () => "0",
|
||||
hasFlag: () => false,
|
||||
};
|
||||
const channel = createChannelRecordFromServer({ id: "0", type: 1 });
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -118,10 +118,10 @@ export async function addReview(review: any): Promise<Response | null> {
|
|||
export async function deleteReview(id: number): Promise<Response | null> {
|
||||
return await rdbRequest(`/users/${id}/reviews`, {
|
||||
method: "DELETE",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
reviewid: id
|
||||
})
|
||||
|
@ -135,10 +135,10 @@ export async function deleteReview(id: number): Promise<Response | null> {
|
|||
export async function reportReview(id: number) {
|
||||
const res = await rdbRequest("/reports", {
|
||||
method: "PUT",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
reviewid: id,
|
||||
})
|
||||
|
@ -150,10 +150,10 @@ export async function reportReview(id: number) {
|
|||
async function patchBlock(action: "block" | "unblock", userId: string) {
|
||||
const res = await rdbRequest("/blocks", {
|
||||
method: "PATCH",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
action: action,
|
||||
discordId: userId
|
||||
|
@ -180,9 +180,9 @@ export const unblockUser = (userId: string) => patchBlock("unblock", userId);
|
|||
export async function fetchBlocks(): Promise<ReviewDBUser[]> {
|
||||
const res = await rdbRequest("/blocks", {
|
||||
method: "GET",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error(`${res.status}: ${res.statusText}`);
|
||||
|
|
|
@ -371,6 +371,10 @@ export function Player() {
|
|||
if (!track || !device?.is_active || shouldHide)
|
||||
return null;
|
||||
|
||||
const exportTrackImageStyle = {
|
||||
"--vc-spotify-track-image": `url(${track?.album?.image?.url || ""})`,
|
||||
} as React.CSSProperties;
|
||||
|
||||
return (
|
||||
<ErrorBoundary fallback={() => (
|
||||
<div className="vc-spotify-fallback">
|
||||
|
@ -378,7 +382,7 @@ export function Player() {
|
|||
<p >Check the console for errors</p>
|
||||
</div>
|
||||
)}>
|
||||
<div id={cl("player")}>
|
||||
<div id={cl("player")} style={exportTrackImageStyle}>
|
||||
<Info track={track} />
|
||||
<SeekBar />
|
||||
<Controls />
|
||||
|
|
|
@ -31,7 +31,7 @@ function toggleHoverControls(value: boolean) {
|
|||
export default definePlugin({
|
||||
name: "SpotifyControls",
|
||||
description: "Adds a Spotify player above the account panel",
|
||||
authors: [Devs.Ven, Devs.afn, Devs.KraXen72],
|
||||
authors: [Devs.Ven, Devs.afn, Devs.KraXen72, Devs.Av32000],
|
||||
options: {
|
||||
hoverControls: {
|
||||
description: "Show controls on hover",
|
||||
|
|
|
@ -170,9 +170,16 @@
|
|||
/* these importants are necessary, it applies a width and height through inline styles */
|
||||
height: 10px !important;
|
||||
width: 10px !important;
|
||||
margin-top: 4px;
|
||||
background-color: var(--interactive-normal);
|
||||
border-color: var(--interactive-normal);
|
||||
color: var(--interactive-normal);
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
|
||||
#vc-spotify-progress-bar:hover > [class^="slider"] [class^="grabber"] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#vc-spotify-progress-text {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
superReactByDefault: {
|
||||
|
@ -49,7 +50,7 @@ export default definePlugin({
|
|||
find: ".trackEmojiSearchEmpty,200",
|
||||
replacement: {
|
||||
match: /(\.trackEmojiSearchEmpty,200(?=.+?isBurstReaction:(\i).+?(\i===\i\.EmojiIntention.REACTION)).+?\[\2,\i\]=\i\.useState\().+?\)/,
|
||||
replace: (_, rest, isBurstReactionVariable, isReactionIntention) => `${rest}$self.settings.store.superReactByDefault&&${isReactionIntention})`
|
||||
replace: (_, rest, isBurstReactionVariable, isReactionIntention) => `${rest}$self.shouldSuperReactByDefault&&${isReactionIntention})`
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -59,5 +60,9 @@ export default definePlugin({
|
|||
if (settings.store.unlimitedSuperReactionPlaying) return true;
|
||||
if (playingCount <= settings.store.superReactionPlayingLimit) return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
get shouldSuperReactByDefault() {
|
||||
return settings.store.superReactByDefault && UserStore.getCurrentUser().premiumType != null;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,13 +20,15 @@ import "./styles.css";
|
|||
|
||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { Microphone } from "@components/Icons";
|
||||
import { Link } from "@components/Link";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import definePlugin from "@utils/types";
|
||||
import { chooseFile } from "@utils/web";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { Button, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
|
||||
import { Button, Card, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
|
||||
import { ComponentType } from "react";
|
||||
|
||||
import { VoiceRecorderDesktop } from "./DesktopRecorder";
|
||||
|
@ -164,6 +166,11 @@ function Modal({ modalProps }: { modalProps: ModalProps; }) {
|
|||
fallbackValue: EMPTY_META,
|
||||
});
|
||||
|
||||
const isUnsupportedFormat = blob && (
|
||||
!blob.type.startsWith("audio/ogg")
|
||||
|| blob.type.includes("codecs") && !blob.type.includes("opus")
|
||||
);
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps}>
|
||||
<ModalHeader>
|
||||
|
@ -200,6 +207,16 @@ function Modal({ modalProps }: { modalProps: ModalProps; }) {
|
|||
recording={isRecording}
|
||||
/>
|
||||
|
||||
{isUnsupportedFormat && (
|
||||
<Card className={`vc-plugins-restart-card ${Margins.top16}`}>
|
||||
<Forms.FormText>Voice Messages have to be OggOpus to be playable on iOS. This file is <code>{blob.type}</code> so it will not be playable on iOS.</Forms.FormText>
|
||||
|
||||
<Forms.FormText className={Margins.top8}>
|
||||
To fix it, first convert it to OggOpus, for example using the <Link href="https://convertio.co/mp3-opus/">convertio web converter</Link>
|
||||
</Forms.FormText>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter>
|
||||
|
|
|
@ -69,14 +69,14 @@ function getReactionsWithQueue(msg: Message, e: ReactionEmoji, type: number) {
|
|||
function makeRenderMoreUsers(users: User[]) {
|
||||
return function renderMoreUsers(_label: string, _count: number) {
|
||||
return (
|
||||
<Tooltip text={users.slice(5).map(u => u.username).join(", ")} >
|
||||
<Tooltip text={users.slice(4).map(u => u.username).join(", ")} >
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div
|
||||
className={AvatarStyles.moreUsers}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
+{users.length - 5}
|
||||
+{users.length - 4}
|
||||
</div>
|
||||
)}
|
||||
</Tooltip >
|
||||
|
|
|
@ -106,7 +106,7 @@ export async function authorizeCloud() {
|
|||
|
||||
try {
|
||||
const res = await fetch(location, {
|
||||
headers: new Headers({ Accept: "application/json" })
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
const { secret } = await res.json();
|
||||
if (secret) {
|
||||
|
|
|
@ -399,6 +399,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
name: "maisy",
|
||||
id: 257109471589957632n,
|
||||
},
|
||||
Mopi: {
|
||||
name: "Mopi",
|
||||
id: 1022189106614243350n
|
||||
},
|
||||
Grzesiek11: {
|
||||
name: "Grzesiek11",
|
||||
id: 368475654662127616n,
|
||||
|
@ -410,6 +414,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
coolelectronics: {
|
||||
name: "coolelectronics",
|
||||
id: 696392247205298207n,
|
||||
},
|
||||
Av32000: {
|
||||
name: "Av32000",
|
||||
id: 593436735380127770n,
|
||||
}
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
|
|
|
@ -118,10 +118,10 @@ export async function putCloudSettings(manual?: boolean) {
|
|||
try {
|
||||
const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
|
||||
method: "PUT",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
Authorization: await getCloudAuth(),
|
||||
"Content-Type": "application/octet-stream"
|
||||
}),
|
||||
},
|
||||
body: deflateSync(new TextEncoder().encode(settings))
|
||||
});
|
||||
|
||||
|
@ -162,11 +162,11 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
try {
|
||||
const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
|
||||
method: "GET",
|
||||
headers: new Headers({
|
||||
headers: {
|
||||
Authorization: await getCloudAuth(),
|
||||
Accept: "application/octet-stream",
|
||||
"If-None-Match": Settings.cloud.settingsSyncVersion.toString()
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 404) {
|
||||
|
@ -251,9 +251,7 @@ export async function deleteCloudSettings() {
|
|||
try {
|
||||
const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
|
||||
method: "DELETE",
|
||||
headers: new Headers({
|
||||
Authorization: await getCloudAuth()
|
||||
}),
|
||||
headers: { Authorization: await getCloudAuth() },
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
|
|
1
src/webpack/common/types/utils.d.ts
vendored
1
src/webpack/common/types/utils.d.ts
vendored
|
@ -59,6 +59,7 @@ export interface Alerts {
|
|||
onCancel?(): void;
|
||||
onConfirm?(): void;
|
||||
onConfirmSecondary?(): void;
|
||||
onCloseCallback?(): void;
|
||||
}): void;
|
||||
/** This is a noop, it does nothing. */
|
||||
close(): void;
|
||||
|
|
|
@ -83,8 +83,8 @@ export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
|
|||
return true;
|
||||
}
|
||||
|
||||
let devToolsOpen = false;
|
||||
if (IS_DEV && IS_DISCORD_DESKTOP) {
|
||||
var devToolsOpen = false;
|
||||
// At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed
|
||||
setTimeout(() => {
|
||||
DiscordNative/* just to make sure */?.window.setDevtoolsCallbacks(() => devToolsOpen = true, () => devToolsOpen = false);
|
||||
|
|
Loading…
Reference in a new issue