mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-09 14:43:03 -04:00
Merge remote-tracking branch 'upstream/dev'
This commit is contained in:
commit
830d4fb738
15 changed files with 496 additions and 33 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.8.1",
|
"version": "1.8.2",
|
||||||
"description": "The other cutest Discord client mod",
|
"description": "The other cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Equicord/Equicord#readme",
|
"homepage": "https://github.com/Equicord/Equicord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -16,20 +16,24 @@
|
||||||
* 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 { DataStore } from "@api/index";
|
import { Link } from "@components/Link";
|
||||||
|
import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
|
||||||
import { Devs, EquicordDevs, SUPPORT_CHANNEL_ID, SUPPORT_CHANNEL_IDS, VC_SUPPORT_CHANNEL_ID } from "@utils/constants";
|
import { Devs, EquicordDevs, SUPPORT_CHANNEL_ID, SUPPORT_CHANNEL_IDS, VC_SUPPORT_CHANNEL_ID } from "@utils/constants";
|
||||||
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { relaunch } from "@utils/native";
|
||||||
import { makeCodeblock } from "@utils/text";
|
import { makeCodeblock } from "@utils/text";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { isOutdated } from "@utils/updater";
|
import { isOutdated, update } from "@utils/updater";
|
||||||
import { Alerts, Forms, UserStore } from "@webpack/common";
|
import { Alerts, Card, ChannelStore, Forms, GuildMemberStore, NavigationRouter, Parser, RelationshipStore, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import gitHash from "~git-hash";
|
import gitHash from "~git-hash";
|
||||||
import plugins from "~plugins";
|
import plugins from "~plugins";
|
||||||
|
|
||||||
import settings from "./settings";
|
import settings from "./settings";
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
|
||||||
const REMEMBER_DISMISS_KEY = "Vencord-SupportHelper-Dismiss";
|
const VENCORD_GUILD_ID = "1015060230222131221";
|
||||||
|
|
||||||
const AllowedChannelIds = [
|
const AllowedChannelIds = [
|
||||||
SUPPORT_CHANNEL_ID,
|
SUPPORT_CHANNEL_ID,
|
||||||
|
@ -37,6 +41,12 @@ const AllowedChannelIds = [
|
||||||
"1173342942858055721", // Equicord > #support
|
"1173342942858055721", // Equicord > #support
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TrustedRolesIds = [
|
||||||
|
"1026534353167208489", // contributor
|
||||||
|
"1026504932959977532", // regular
|
||||||
|
"1042507929485586532", // donor
|
||||||
|
];
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "SupportHelper",
|
name: "SupportHelper",
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -44,6 +54,14 @@ export default definePlugin({
|
||||||
authors: [Devs.Ven, EquicordDevs.thororen],
|
authors: [Devs.Ven, EquicordDevs.thororen],
|
||||||
dependencies: ["CommandsAPI"],
|
dependencies: ["CommandsAPI"],
|
||||||
|
|
||||||
|
patches: [{
|
||||||
|
find: ".BEGINNING_DM.format",
|
||||||
|
replacement: {
|
||||||
|
match: /BEGINNING_DM\.format\(\{.+?\}\),(?=.{0,100}userId:(\i\.getRecipientId\(\)))/,
|
||||||
|
replace: "$& $self.ContributorDmWarningCard({ userId: $1 }),"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
commands: [{
|
commands: [{
|
||||||
name: "equicord-debug",
|
name: "equicord-debug",
|
||||||
description: "Send Equicord Debug info",
|
description: "Send Equicord Debug info",
|
||||||
|
@ -64,15 +82,13 @@ export default definePlugin({
|
||||||
const isApiPlugin = (plugin: string) => plugin.endsWith("API") || plugins[plugin].required;
|
const isApiPlugin = (plugin: string) => plugin.endsWith("API") || plugins[plugin].required;
|
||||||
|
|
||||||
const enabledPlugins = Object.keys(plugins).filter(p => Vencord.Plugins.isPluginEnabled(p) && !isApiPlugin(p));
|
const enabledPlugins = Object.keys(plugins).filter(p => Vencord.Plugins.isPluginEnabled(p) && !isApiPlugin(p));
|
||||||
const enabledApiPlugins = Object.keys(plugins).filter(p => Vencord.Plugins.isPluginEnabled(p) && isApiPlugin(p));
|
|
||||||
|
|
||||||
const info = {
|
const info = {
|
||||||
Vencord: `v${VERSION} • ${gitHash}${settings.additionalInfo} - ${Intl.DateTimeFormat("en-GB", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
|
Vencord:
|
||||||
"Discord Branch": RELEASE_CHANNEL,
|
`v${VERSION} • [${gitHash}](<https://github.com/Vendicated/Vencord/commit/${gitHash}>)` +
|
||||||
Client: client,
|
`${settings.additionalInfo} - ${Intl.DateTimeFormat("en-GB", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
|
||||||
Platform: window.navigator.platform,
|
Client: `${RELEASE_CHANNEL} ~ ${client}`,
|
||||||
Outdated: isOutdated,
|
Platform: window.navigator.platform
|
||||||
OpenAsar: "openasar" in window,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (IS_DISCORD_DESKTOP) {
|
if (IS_DISCORD_DESKTOP) {
|
||||||
|
@ -80,11 +96,10 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
|
|
||||||
const debugInfo = `
|
const debugInfo = `
|
||||||
**Equicord Debug Info**
|
>>> ${Object.entries(info).map(([k, v]) => `**${k}**: ${v}`).join("\n")}
|
||||||
>>> ${Object.entries(info).map(([k, v]) => `${k}: ${v}`).join("\n")}
|
|
||||||
|
|
||||||
Enabled Plugins (${enabledPlugins.length + enabledApiPlugins.length}):
|
Enabled Plugins (${enabledPlugins.length}):
|
||||||
${makeCodeblock(enabledPlugins.join(", ") + "\n\n" + enabledApiPlugins.join(", "))}
|
${makeCodeblock(enabledPlugins.join(", "))}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -114,25 +129,75 @@ ${makeCodeblock(enabledPlugins.join(", ") + "\n\n" + enabledApiPlugins.join(", "
|
||||||
onConfirm: () => history.back()
|
onConfirm: () => history.back()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isPluginDev(UserStore.getCurrentUser().id)) return;
|
const selfId = UserStore.getCurrentUser()?.id;
|
||||||
if (isEquicordPluginDev(UserStore.getCurrentUser().id)) return;
|
if (!selfId || isPluginDev(selfId) || isEquicordPluginDev(selfId)) return;
|
||||||
|
|
||||||
if (isOutdated && gitHash !== await DataStore.get(REMEMBER_DISMISS_KEY)) {
|
if (isOutdated) {
|
||||||
const rememberDismiss = () => DataStore.set(REMEMBER_DISMISS_KEY, gitHash);
|
return Alerts.show({
|
||||||
|
|
||||||
Alerts.show({
|
|
||||||
title: "Hold on!",
|
title: "Hold on!",
|
||||||
body: <div>
|
body: <div>
|
||||||
<Forms.FormText>You are using an outdated version of Vencord! Chances are, your issue is already fixed.</Forms.FormText>
|
<Forms.FormText>You are using an outdated version of Vencord! Chances are, your issue is already fixed.</Forms.FormText>
|
||||||
<Forms.FormText>
|
<Forms.FormText className={Margins.top8}>
|
||||||
Please first update using the Updater Page in Settings, or use the VencordInstaller (Update Vencord Button)
|
Please first update before asking for support!
|
||||||
to do so, in case you can't access the Updater page.
|
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</div>,
|
</div>,
|
||||||
onCancel: rememberDismiss,
|
onCancel: () => openUpdaterModal!(),
|
||||||
onConfirm: rememberDismiss
|
cancelText: "View Updates",
|
||||||
|
confirmText: "Update & Restart Now",
|
||||||
|
async onConfirm() {
|
||||||
|
await update();
|
||||||
|
relaunch();
|
||||||
|
},
|
||||||
|
secondaryConfirmText: "I know what I'm doing or I can't update"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
// @ts-ignore outdated type
|
||||||
|
const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles;
|
||||||
|
if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return;
|
||||||
|
|
||||||
|
if (IS_UPDATER_DISABLED) {
|
||||||
|
return Alerts.show({
|
||||||
|
title: "Hold on!",
|
||||||
|
body: <div>
|
||||||
|
<Forms.FormText>You are using an externally updated Vencord version, which we do not provide support for!</Forms.FormText>
|
||||||
|
<Forms.FormText className={Margins.top8}>
|
||||||
|
Please either switch to an <Link href="https://vencord.dev/download">officially supported version of Vencord</Link>, or
|
||||||
|
contact your package maintainer for support instead.
|
||||||
|
</Forms.FormText>
|
||||||
|
</div>,
|
||||||
|
onCloseCallback: () => setTimeout(() => NavigationRouter.back(), 50)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const repo = await VencordNative.updater.getRepo();
|
||||||
|
if (repo.ok && !repo.value.includes("Vendicated/Vencord")) {
|
||||||
|
return Alerts.show({
|
||||||
|
title: "Hold on!",
|
||||||
|
body: <div>
|
||||||
|
<Forms.FormText>You are using a fork of Vencord, which we do not provide support for!</Forms.FormText>
|
||||||
|
<Forms.FormText className={Margins.top8}>
|
||||||
|
Please either switch to an <Link href="https://vencord.dev/download">officially supported version of Vencord</Link>, or
|
||||||
|
contact your package maintainer for support instead.
|
||||||
|
</Forms.FormText>
|
||||||
|
</div>,
|
||||||
|
onCloseCallback: () => setTimeout(() => NavigationRouter.back(), 50)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ContributorDmWarningCard: ErrorBoundary.wrap(({ userId }) => {
|
||||||
|
if (!isPluginDev(userId)) return null;
|
||||||
|
if (RelationshipStore.isFriend(userId)) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={`vc-plugins-restart-card ${Margins.top8}`}>
|
||||||
|
Please do not private message Vencord plugin developers for support!
|
||||||
|
<br />
|
||||||
|
Instead, use the Vencord support channel: {Parser.parse("https://discord.com/channels/1015060230222131221/1026515880080842772")}
|
||||||
|
{!ChannelStore.getChannel(SUPPORT_CHANNEL_ID) && " (Click the link to join)"}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}, { noop: true })
|
||||||
});
|
});
|
||||||
|
|
|
@ -127,7 +127,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children
|
// If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children
|
||||||
{
|
{
|
||||||
match: /unreadMentionsIndicatorBottom,barClassName.+?}\)\]/,
|
match: /unreadMentionsIndicatorBottom,.+?}\)\]/,
|
||||||
replace: "$&.filter($self.makeGuildsBarTreeFilter(!!arguments[0].isBetterFolders))"
|
replace: "$&.filter($self.makeGuildsBarTreeFilter(!!arguments[0].isBetterFolders))"
|
||||||
},
|
},
|
||||||
// Export the isBetterFolders variable to the folders component
|
// Export the isBetterFolders variable to the folders component
|
||||||
|
|
|
@ -77,7 +77,8 @@ const enum NameFormat {
|
||||||
ArtistFirst = "artist-first",
|
ArtistFirst = "artist-first",
|
||||||
SongFirst = "song-first",
|
SongFirst = "song-first",
|
||||||
ArtistOnly = "artist",
|
ArtistOnly = "artist",
|
||||||
SongOnly = "song"
|
SongOnly = "song",
|
||||||
|
AlbumName = "album"
|
||||||
}
|
}
|
||||||
|
|
||||||
const applicationId = "1108588077900898414";
|
const applicationId = "1108588077900898414";
|
||||||
|
@ -147,6 +148,10 @@ const settings = definePluginSettings({
|
||||||
{
|
{
|
||||||
label: "Use song name only",
|
label: "Use song name only",
|
||||||
value: NameFormat.SongOnly
|
value: NameFormat.SongOnly
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Use album name (falls back to custom status text if song has no album)",
|
||||||
|
value: NameFormat.AlbumName
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -313,6 +318,8 @@ export default definePlugin({
|
||||||
return trackData.artist;
|
return trackData.artist;
|
||||||
case NameFormat.SongOnly:
|
case NameFormat.SongOnly:
|
||||||
return trackData.name;
|
return trackData.name;
|
||||||
|
case NameFormat.AlbumName:
|
||||||
|
return trackData.album || settings.store.statusName;
|
||||||
default:
|
default:
|
||||||
return settings.store.statusName;
|
return settings.store.statusName;
|
||||||
}
|
}
|
||||||
|
|
31
src/plugins/messageLatency/README.md
Normal file
31
src/plugins/messageLatency/README.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# MessageLatency
|
||||||
|
|
||||||
|
Displays an indicator for messages that took ≥n seconds to send.
|
||||||
|
|
||||||
|
> **NOTE**
|
||||||
|
>
|
||||||
|
> - This plugin only applies to messages received after opening the channel
|
||||||
|
> - False positives can exist if the user's system clock has drifted.
|
||||||
|
> - Grouped messages only display latency of the first message
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
### Chat View
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Clock -ve Drift
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Clock +ve Drift
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Connection Delay
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Icons
|
||||||
|
|
||||||
|

|
147
src/plugins/messageLatency/index.tsx
Normal file
147
src/plugins/messageLatency/index.tsx
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import { isNonNullish } from "@utils/guards";
|
||||||
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import { findExportedComponentLazy } from "@webpack";
|
||||||
|
import { SnowflakeUtils, Tooltip } from "@webpack/common";
|
||||||
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
type FillValue = ("status-danger" | "status-warning" | "text-muted");
|
||||||
|
type Fill = [FillValue, FillValue, FillValue];
|
||||||
|
type DiffKey = keyof Diff;
|
||||||
|
|
||||||
|
interface Diff {
|
||||||
|
days: number,
|
||||||
|
hours: number,
|
||||||
|
minutes: number,
|
||||||
|
seconds: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HiddenVisually = findExportedComponentLazy("HiddenVisually");
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "MessageLatency",
|
||||||
|
description: "Displays an indicator for messages that took ≥n seconds to send",
|
||||||
|
authors: [Devs.arHSM],
|
||||||
|
settings: definePluginSettings({
|
||||||
|
latency: {
|
||||||
|
type: OptionType.NUMBER,
|
||||||
|
description: "Threshold in seconds for latency indicator",
|
||||||
|
default: 2
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "showCommunicationDisabledStyles",
|
||||||
|
replacement: {
|
||||||
|
match: /(message:(\i),avatar:\i,username:\(0,\i.jsxs\)\(\i.Fragment,\{children:\[)(\i&&)/,
|
||||||
|
replace: "$1$self.Tooltip()({ message: $2 }),$3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
stringDelta(delta: number) {
|
||||||
|
const diff: Diff = {
|
||||||
|
days: Math.round(delta / (60 * 60 * 24)),
|
||||||
|
hours: Math.round((delta / (60 * 60)) % 24),
|
||||||
|
minutes: Math.round((delta / (60)) % 60),
|
||||||
|
seconds: Math.round(delta % 60),
|
||||||
|
};
|
||||||
|
|
||||||
|
const str = (k: DiffKey) => diff[k] > 0 ? `${diff[k]} ${k}` : null;
|
||||||
|
const keys = Object.keys(diff) as DiffKey[];
|
||||||
|
|
||||||
|
return keys.map(str).filter(isNonNullish).join(" ") || "0 seconds";
|
||||||
|
},
|
||||||
|
latencyTooltipData(message: Message) {
|
||||||
|
const { id, nonce } = message;
|
||||||
|
|
||||||
|
// Message wasn't received through gateway
|
||||||
|
if (!isNonNullish(nonce)) return null;
|
||||||
|
|
||||||
|
const delta = Math.round((SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce)) / 1000);
|
||||||
|
|
||||||
|
// Thanks dziurwa (I hate you)
|
||||||
|
// This is when the user's clock is ahead
|
||||||
|
// Can't do anything if the clock is behind
|
||||||
|
const abs = Math.abs(delta);
|
||||||
|
const ahead = abs !== delta;
|
||||||
|
|
||||||
|
const stringDelta = this.stringDelta(abs);
|
||||||
|
|
||||||
|
// Also thanks dziurwa
|
||||||
|
// 2 minutes
|
||||||
|
const TROLL_LIMIT = 2 * 60;
|
||||||
|
const { latency } = this.settings.store;
|
||||||
|
|
||||||
|
const fill: Fill = delta >= TROLL_LIMIT || ahead ? ["text-muted", "text-muted", "text-muted"] : delta >= (latency * 2) ? ["status-danger", "text-muted", "text-muted"] : ["status-warning", "status-warning", "text-muted"];
|
||||||
|
|
||||||
|
return abs >= latency ? { delta: stringDelta, ahead: abs !== delta, fill } : null;
|
||||||
|
},
|
||||||
|
Tooltip() {
|
||||||
|
return ErrorBoundary.wrap(({ message }: { message: Message; }) => {
|
||||||
|
|
||||||
|
const d = this.latencyTooltipData(message);
|
||||||
|
|
||||||
|
if (!isNonNullish(d)) return null;
|
||||||
|
|
||||||
|
return <Tooltip
|
||||||
|
text={d.ahead ? `This user's clock is ${d.delta} ahead` : `This message was sent with a delay of ${d.delta}.`}
|
||||||
|
position="top"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
props => <>
|
||||||
|
{<this.Icon delta={d.delta} fill={d.fill} props={props} />}
|
||||||
|
{/* Time Out indicator uses this, I think this is for a11y */}
|
||||||
|
<HiddenVisually>Delayed Message</HiddenVisually>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</Tooltip>;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Icon({ delta, fill, props }: {
|
||||||
|
delta: string;
|
||||||
|
fill: Fill,
|
||||||
|
props: {
|
||||||
|
onClick(): void;
|
||||||
|
onMouseEnter(): void;
|
||||||
|
onMouseLeave(): void;
|
||||||
|
onContextMenu(): void;
|
||||||
|
onFocus(): void;
|
||||||
|
onBlur(): void;
|
||||||
|
"aria-label"?: string;
|
||||||
|
};
|
||||||
|
}) {
|
||||||
|
return <svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="12"
|
||||||
|
height="12"
|
||||||
|
role="img"
|
||||||
|
fill="none"
|
||||||
|
style={{ marginRight: "8px", verticalAlign: -1 }}
|
||||||
|
aria-label={delta}
|
||||||
|
aria-hidden="false"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill={`var(--${fill[0]})`}
|
||||||
|
d="M4.8001 12C4.8001 11.5576 4.51344 11.2 4.16023 11.2H2.23997C1.88676 11.2 1.6001 11.5576 1.6001 12V13.6C1.6001 14.0424 1.88676 14.4 2.23997 14.4H4.15959C4.5128 14.4 4.79946 14.0424 4.79946 13.6L4.8001 12Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill={`var(--${fill[1]})`}
|
||||||
|
d="M9.6001 7.12724C9.6001 6.72504 9.31337 6.39998 8.9601 6.39998H7.0401C6.68684 6.39998 6.40011 6.72504 6.40011 7.12724V13.6727C6.40011 14.0749 6.68684 14.4 7.0401 14.4H8.9601C9.31337 14.4 9.6001 14.0749 9.6001 13.6727V7.12724Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill={`var(--${fill[2]})`}
|
||||||
|
d="M14.4001 2.31109C14.4001 1.91784 14.1134 1.59998 13.7601 1.59998H11.8401C11.4868 1.59998 11.2001 1.91784 11.2001 2.31109V13.6888C11.2001 14.0821 11.4868 14.4 11.8401 14.4H13.7601C14.1134 14.4 14.4001 14.0821 14.4001 13.6888V2.31109Z"
|
||||||
|
/>
|
||||||
|
</svg>;
|
||||||
|
}
|
||||||
|
});
|
|
@ -255,7 +255,7 @@ export default definePlugin({
|
||||||
replace: "$1" +
|
replace: "$1" +
|
||||||
".update($3,m =>" +
|
".update($3,m =>" +
|
||||||
" (($2.message.flags & 64) === 64 || $self.shouldIgnore($2.message, true)) ? m :" +
|
" (($2.message.flags & 64) === 64 || $self.shouldIgnore($2.message, true)) ? m :" +
|
||||||
" $2.message.content !== m.content ?" +
|
" $2.message.content !== m.editHistory?.[0]?.content && $2.message.content !== m.content ?" +
|
||||||
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :" +
|
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :" +
|
||||||
" m" +
|
" m" +
|
||||||
")" +
|
")" +
|
||||||
|
|
5
src/plugins/replyTimestamp/README.md
Normal file
5
src/plugins/replyTimestamp/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# ReplyTimestamp
|
||||||
|
|
||||||
|
Shows timestamps on the previews of replied-to messages. Pretty simple.
|
||||||
|
|
||||||
|

|
77
src/plugins/replyTimestamp/index.tsx
Normal file
77
src/plugins/replyTimestamp/index.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./style.css";
|
||||||
|
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
import { findByPropsLazy } from "@webpack";
|
||||||
|
import { Timestamp } from "@webpack/common";
|
||||||
|
import type { Message } from "discord-types/general";
|
||||||
|
import type { HTMLAttributes } from "react";
|
||||||
|
|
||||||
|
const { getMessageTimestampId } = findByPropsLazy("getMessageTimestampId");
|
||||||
|
const { calendarFormat, dateFormat, isSameDay } = findByPropsLazy("calendarFormat", "dateFormat", "isSameDay", "accessibilityLabelCalendarFormat");
|
||||||
|
const MessageClasses = findByPropsLazy("separator", "latin24CompactTimeStamp");
|
||||||
|
|
||||||
|
function Sep(props: HTMLAttributes<HTMLElement>) {
|
||||||
|
return <i className={MessageClasses.separator} aria-hidden={true} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum ReferencedMessageState {
|
||||||
|
LOADED = 0,
|
||||||
|
NOT_LOADED = 1,
|
||||||
|
DELETED = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferencedMessage = { state: ReferencedMessageState.LOADED; message: Message; } | { state: ReferencedMessageState.NOT_LOADED | ReferencedMessageState.DELETED; };
|
||||||
|
|
||||||
|
function ReplyTimestamp({
|
||||||
|
referencedMessage,
|
||||||
|
baseMessage,
|
||||||
|
}: {
|
||||||
|
referencedMessage: ReferencedMessage,
|
||||||
|
baseMessage: Message;
|
||||||
|
}) {
|
||||||
|
if (referencedMessage.state !== ReferencedMessageState.LOADED) return null;
|
||||||
|
const refTimestamp = referencedMessage.message.timestamp as any;
|
||||||
|
const baseTimestamp = baseMessage.timestamp as any;
|
||||||
|
return (
|
||||||
|
<Timestamp
|
||||||
|
id={getMessageTimestampId(referencedMessage.message)}
|
||||||
|
className="vc-reply-timestamp"
|
||||||
|
compact={isSameDay(refTimestamp, baseTimestamp)}
|
||||||
|
timestamp={refTimestamp}
|
||||||
|
isInline={false}
|
||||||
|
>
|
||||||
|
<Sep>[</Sep>
|
||||||
|
{isSameDay(refTimestamp, baseTimestamp)
|
||||||
|
? dateFormat(refTimestamp, "LT")
|
||||||
|
: calendarFormat(refTimestamp)
|
||||||
|
}
|
||||||
|
<Sep>]</Sep>
|
||||||
|
</Timestamp>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "ReplyTimestamp",
|
||||||
|
description: "Shows a timestamp on replied-message previews",
|
||||||
|
authors: [Devs.Kyuuhachi],
|
||||||
|
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "renderSingleLineMessage:function()",
|
||||||
|
replacement: {
|
||||||
|
match: /(?<="aria-label":\i,children:\[)(?=\i,\i,\i\])/,
|
||||||
|
replace: "$self.ReplyTimestamp(arguments[0]),"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
ReplyTimestamp: ErrorBoundary.wrap(ReplyTimestamp, { noop: true }),
|
||||||
|
});
|
3
src/plugins/replyTimestamp/style.css
Normal file
3
src/plugins/replyTimestamp/style.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.vc-reply-timestamp {
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
|
@ -31,12 +31,22 @@ const settings = definePluginSettings({
|
||||||
description: "Show the invites paused tooltip in the server list.",
|
description: "Show the invites paused tooltip in the server list.",
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
showModView: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Show the member mod view context menu item in all servers.",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
disableDiscoveryFilters: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Disable filters in Server Discovery search that hide servers that don't meet discovery criteria.",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
migratePluginSettings("ShowHiddenThings", "ShowTimeouts");
|
migratePluginSettings("ShowHiddenThings", "ShowTimeouts");
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ShowHiddenThings",
|
name: "ShowHiddenThings",
|
||||||
tags: ["ShowTimeouts", "ShowInvitesPaused"],
|
tags: ["ShowTimeouts", "ShowInvitesPaused", "ShowModView", "DisableDiscoveryFilters"],
|
||||||
description: "Displays various moderator-only elements regardless of permissions.",
|
description: "Displays various moderator-only elements regardless of permissions.",
|
||||||
authors: [Devs.Dolfies],
|
authors: [Devs.Dolfies],
|
||||||
patches: [
|
patches: [
|
||||||
|
@ -55,6 +65,22 @@ export default definePlugin({
|
||||||
match: /\i\.\i\.can\(\i\.Permissions.MANAGE_GUILD,\i\)/,
|
match: /\i\.\i\.can\(\i\.Permissions.MANAGE_GUILD,\i\)/,
|
||||||
replace: "true",
|
replace: "true",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "canAccessGuildMemberModViewWithExperiment:",
|
||||||
|
predicate: () => settings.store.showModView,
|
||||||
|
replacement: {
|
||||||
|
match: /return \i\.hasAny\(\i\.computePermissions\(\{user:\i,context:\i,checkElevated:!1\}\),\i\.MemberSafetyPagePermissions\)/,
|
||||||
|
replace: "return true",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "auto_removed:",
|
||||||
|
predicate: () => settings.store.disableDiscoveryFilters,
|
||||||
|
replacement: {
|
||||||
|
match: /filters:\i\.join\(" AND "\),facets:\[/,
|
||||||
|
replace: "facets:["
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
settings,
|
settings,
|
||||||
|
|
52
src/plugins/voiceDownload/index.tsx
Normal file
52
src/plugins/voiceDownload/index.tsx
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 "./style.css";
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "VoiceDownload",
|
||||||
|
description: "Adds a download to voice messages. (Opens a new browser tab)",
|
||||||
|
authors: [Devs.puv],
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "rippleContainer,children",
|
||||||
|
replacement: {
|
||||||
|
match: /\(0,\i\.jsx\).{0,150},children:.{0,50}\("source",{src:(\i)}\)}\)/,
|
||||||
|
replace: "[$&, $self.renderDownload($1)]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
renderDownload(src: string) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
className="vc-voice-download"
|
||||||
|
href={src}
|
||||||
|
download="voice-message.ogg"
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
|
aria-label="Download voice message"
|
||||||
|
>
|
||||||
|
<this.Icon />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
Icon: () => (
|
||||||
|
<svg
|
||||||
|
height="24"
|
||||||
|
width="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 2a1 1 0 0 1 1 1v10.59l3.3-3.3a1 1 0 1 1 1.4 1.42l-5 5a1 1 0 0 1-1.4 0l-5-5a1 1 0 1 1 1.4-1.42l3.3 3.3V3a1 1 0 0 1 1-1ZM3 20a1 1 0 1 0 0 2h18a1 1 0 1 0 0-2H3Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
});
|
12
src/plugins/voiceDownload/style.css
Normal file
12
src/plugins/voiceDownload/style.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.vc-voice-download {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: var(--interactive-normal);
|
||||||
|
margin-left: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-voice-download:hover {
|
||||||
|
color: var(--interactive-active);
|
||||||
|
}
|
30
src/plugins/webScreenShareFixes.web/index.ts
Normal file
30
src/plugins/webScreenShareFixes.web/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "WebScreenShareFixes",
|
||||||
|
authors: [Devs.Kaitlyn],
|
||||||
|
description: "Removes 2500kbps bitrate cap on chromium and vesktop clients.",
|
||||||
|
enabledByDefault: true,
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "x-google-max-bitrate",
|
||||||
|
replacement: [
|
||||||
|
{
|
||||||
|
match: /"x-google-max-bitrate=".concat\(\i\)/,
|
||||||
|
replace: '"x-google-max-bitrate=".concat("80_000")'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /;level-asymmetry-allowed=1/,
|
||||||
|
replace: ";b=AS:800000;level-asymmetry-allowed=1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
|
@ -268,6 +268,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
name: "Dziurwa",
|
name: "Dziurwa",
|
||||||
id: 1001086404203389018n
|
id: 1001086404203389018n
|
||||||
},
|
},
|
||||||
|
arHSM: {
|
||||||
|
name: "arHSM",
|
||||||
|
id: 841509053422632990n
|
||||||
|
},
|
||||||
F53: {
|
F53: {
|
||||||
name: "F53",
|
name: "F53",
|
||||||
id: 280411966126948353n
|
id: 280411966126948353n
|
||||||
|
@ -428,6 +432,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
name: "newwares",
|
name: "newwares",
|
||||||
id: 421405303951851520n
|
id: 421405303951851520n
|
||||||
},
|
},
|
||||||
|
puv: {
|
||||||
|
name: "puv",
|
||||||
|
id: 469441552251355137n
|
||||||
|
},
|
||||||
Kodarru: {
|
Kodarru: {
|
||||||
name: "Kodarru",
|
name: "Kodarru",
|
||||||
id: 785227396218748949n
|
id: 785227396218748949n
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue