Merge branch 'Vendicated:main' into Encryptcord

This commit is contained in:
Inbestigator 2024-03-02 02:55:43 -08:00 committed by GitHub
commit f2c9f59f7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 206 additions and 100 deletions

View file

@ -62,7 +62,7 @@ function GM_fetch(url, opt) {
resp.arrayBuffer = () => blobTo("arrayBuffer", blob); resp.arrayBuffer = () => blobTo("arrayBuffer", blob);
resp.text = () => blobTo("text", blob); resp.text = () => blobTo("text", blob);
resp.json = async () => JSON.parse(await 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; resp.ok = resp.status >= 200 && resp.status < 300;
resolve(resp); resolve(resp);
}; };

View file

@ -428,10 +428,11 @@ function runTime(token: string) {
if (searchType === "findComponent") method = "find"; if (searchType === "findComponent") method = "find";
if (searchType === "findExportedComponent") method = "findByProps"; if (searchType === "findExportedComponent") method = "findByProps";
if (searchType === "waitFor" || searchType === "waitForComponent" || searchType === "waitForStore") { if (searchType === "waitFor" || searchType === "waitForComponent") {
if (typeof args[0] === "string") method = "findByProps"; if (typeof args[0] === "string") method = "findByProps";
else method = "find"; else method = "find";
} }
if (searchType === "waitForStore") method = "findStore";
try { try {
let result: any; let result: any;

View file

@ -39,9 +39,7 @@ function validateUrl(url: string) {
async function eraseAllData() { async function eraseAllData() {
const res = await fetch(new URL("/v1/", getCloudUrl()), { const res = await fetch(new URL("/v1/", getCloudUrl()), {
method: "DELETE", method: "DELETE",
headers: new Headers({ headers: { Authorization: await getCloudAuth() }
Authorization: await getCloudAuth()
})
}); });
if (!res.ok) { if (!res.ok) {

View file

@ -369,8 +369,8 @@ export default definePlugin({
predicate: () => settings.store.transformEmojis, predicate: () => settings.store.transformEmojis,
replacement: { replacement: {
// Add the fake nitro emoji notice // Add the fake nitro emoji notice
match: /(?<=isDiscoverable:\i,emojiComesFromCurrentGuild:\i,.+?}=(\i).+?;)(.*?return )(.{0,1000}\.Messages\.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION.+?)(?=},)/, match: /(?<=emojiDescription:)(\i)(?<=\1=\i\((\i)\).+?)/,
replace: (_, props, rest, reactNode) => `let{fakeNitroNode}=${props};${rest}$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!fakeNitroNode?.fake)` replace: (_, reactNode, props) => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!${props}?.fakeNitroNode?.fake)`
} }
}, },
// Allow using custom app icons // Allow using custom app icons
@ -474,7 +474,7 @@ export default definePlugin({
if (typeof firstContent === "string") { if (typeof firstContent === "string") {
content[0] = firstContent.trimStart(); content[0] = firstContent.trimStart();
content[0] || content.shift(); 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 = firstContent.props.children.trimStart();
firstContent.props.children || content.shift(); firstContent.props.children || content.shift();
} }
@ -484,7 +484,7 @@ export default definePlugin({
if (typeof lastContent === "string") { if (typeof lastContent === "string") {
content[lastIndex] = lastContent.trimEnd(); content[lastIndex] = lastContent.trimEnd();
content[lastIndex] || content.pop(); 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 = lastContent.props.children.trimEnd();
lastContent.props.children || content.pop(); lastContent.props.children || content.pop();
} }

View 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>
);
}

View 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);
}
});
});

View file

@ -16,101 +16,48 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * 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 ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { findStoreLazy } from "@webpack"; import { findStoreLazy } from "@webpack";
import { SelectedChannelStore, Tooltip, useStateFromStores } from "@webpack/common";
import { FluxStore } from "@webpack/types"; import { FluxStore } from "@webpack/types";
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; }; import { MemberCount } from "./MemberCount";
const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
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; }[]; }; getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
}; };
const sharedIntlNumberFormat = new Intl.NumberFormat(); const sharedIntlNumberFormat = new Intl.NumberFormat();
const numberFormat = (value: number) => sharedIntlNumberFormat.format(value); export const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
export const cl = classNameFactory("vc-membercount-");
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 default definePlugin({ export default definePlugin({
name: "MemberCount", 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], authors: [Devs.Ven, Devs.Commandtechno],
patches: [{ patches: [
find: "{isSidebarVisible:", {
replacement: { find: "{isSidebarVisible:",
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/, replacement: {
replace: ":[$1?.startsWith('members')?$self.render():null,$2" 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 })
}); });

View 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;
}

View file

@ -27,8 +27,8 @@ export default definePlugin({
{ {
find: "_ensureAudio(){", find: "_ensureAudio(){",
replacement: { replacement: {
match: /onloadeddata=\(\)=>\{.\.volume=/, match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/,
replace: "$&$self.settings.store.notificationVolume/100*" replace: "$self.settings.store.notificationVolume/100*"
}, },
}, },
], ],

View file

@ -106,7 +106,7 @@ export async function authorizeCloud() {
try { try {
const res = await fetch(location, { const res = await fetch(location, {
headers: new Headers({ Accept: "application/json" }) headers: { Accept: "application/json" }
}); });
const { secret } = await res.json(); const { secret } = await res.json();
if (secret) { if (secret) {

View file

@ -118,10 +118,10 @@ export async function putCloudSettings(manual?: boolean) {
try { try {
const res = await fetch(new URL("/v1/settings", getCloudUrl()), { const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
method: "PUT", method: "PUT",
headers: new Headers({ headers: {
Authorization: await getCloudAuth(), Authorization: await getCloudAuth(),
"Content-Type": "application/octet-stream" "Content-Type": "application/octet-stream"
}), },
body: deflateSync(new TextEncoder().encode(settings)) body: deflateSync(new TextEncoder().encode(settings))
}); });
@ -162,11 +162,11 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
try { try {
const res = await fetch(new URL("/v1/settings", getCloudUrl()), { const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
method: "GET", method: "GET",
headers: new Headers({ headers: {
Authorization: await getCloudAuth(), Authorization: await getCloudAuth(),
Accept: "application/octet-stream", Accept: "application/octet-stream",
"If-None-Match": Settings.cloud.settingsSyncVersion.toString() "If-None-Match": Settings.cloud.settingsSyncVersion.toString()
}), },
}); });
if (res.status === 404) { if (res.status === 404) {
@ -251,9 +251,7 @@ export async function deleteCloudSettings() {
try { try {
const res = await fetch(new URL("/v1/settings", getCloudUrl()), { const res = await fetch(new URL("/v1/settings", getCloudUrl()), {
method: "DELETE", method: "DELETE",
headers: new Headers({ headers: { Authorization: await getCloudAuth() },
Authorization: await getCloudAuth()
}),
}); });
if (!res.ok) { if (!res.ok) {

View file

@ -83,8 +83,8 @@ export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
return true; return true;
} }
let devToolsOpen = false;
if (IS_DEV && IS_DISCORD_DESKTOP) { if (IS_DEV && IS_DISCORD_DESKTOP) {
var devToolsOpen = false;
// At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed // At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed
setTimeout(() => { setTimeout(() => {
DiscordNative/* just to make sure */?.window.setDevtoolsCallbacks(() => devToolsOpen = true, () => devToolsOpen = false); DiscordNative/* just to make sure */?.window.setDevtoolsCallbacks(() => devToolsOpen = true, () => devToolsOpen = false);