mirror of
https://github.com/Equicord/Equicord.git
synced 2025-01-18 05:13:29 -05:00
Merge Dev
This commit is contained in:
commit
a62029833f
10 changed files with 204 additions and 127 deletions
|
@ -110,6 +110,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
- PolishWording (Grammar) by Samwich
|
||||
- PlatformSpoofer by Drag
|
||||
- PurgeMessages by bhop & nyx
|
||||
- QuestCompleter by HappyEnderman, SerStars, maintained by thororen
|
||||
- QuestionMarkReplacement by nyx
|
||||
- Quoter by Samwich
|
||||
- RemixMe by kvba
|
||||
|
@ -163,7 +164,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
|
||||
### Discord Desktop Only
|
||||
- MediaDownloader by Colorman
|
||||
- QuestCompleter by HappyEnderman, SerStars, maintained by thororen
|
||||
- StatusWhilePlaying by thororen
|
||||
|
||||
### Equicord Devbuilds Only
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton } from "@api/ChatButtons";
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import {
|
||||
ApplicationCommandInputType,
|
||||
ApplicationCommandOptionType,
|
||||
|
@ -12,7 +12,6 @@ import {
|
|||
} from "@api/Commands";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { addPreSendListener, removePreSendListener, SendListener } from "@api/MessageEvents";
|
||||
import { removeButton } from "@api/MessagePopover";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { sleep } from "@utils/misc";
|
||||
import definePlugin from "@utils/types";
|
||||
|
@ -273,7 +272,7 @@ export default definePlugin({
|
|||
await DataStore.set("encryptcordGroupMembers", {});
|
||||
},
|
||||
async stop() {
|
||||
removeButton("Encryptcord");
|
||||
removeChatBarButton("Encryptcord");
|
||||
if (await DataStore.get("encryptcordGroup") === true) {
|
||||
await leave("", { channel: { id: await DataStore.get("encryptcordChannelId") } });
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton } from "@api/ChatButtons";
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel, sendMessage } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
|
@ -27,7 +27,6 @@ export default definePlugin({
|
|||
description: "Adds a chatbar button to meow in chat",
|
||||
authors:
|
||||
[Devs.Samwich],
|
||||
start() {
|
||||
addChatBarButton("vc-meow", ChatBarIcon);
|
||||
}
|
||||
start: () => addChatBarButton("Meow", ChatBarIcon),
|
||||
stop: () => removeChatBarButton("Meow")
|
||||
});
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
.quest-warning {
|
||||
font-size: 16px !important;
|
||||
background-color: rgb(240 71 71 / 10%) !important;
|
||||
color: rgb(240 71 71) !important;
|
||||
border: 1px solid rgb(240 71 71 / 60%) !important;
|
||||
border-radius: 5px !important;
|
||||
font-weight: 500;
|
||||
padding: 6px 10px;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-style: bold;
|
||||
}
|
|
@ -16,8 +16,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
|
@ -25,7 +23,7 @@ import { getTheme, Theme } from "@utils/discord";
|
|||
import { classes } from "@utils/misc";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByProps, findExportedComponentLazy } from "@webpack";
|
||||
import { Button, FluxDispatcher, Forms, RestAPI, Tooltip, UserStore } from "@webpack/common";
|
||||
import { Button, FluxDispatcher, RestAPI, Tooltip, UserStore } from "@webpack/common";
|
||||
const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider");
|
||||
const isApp = navigator.userAgent.includes("Electron/");
|
||||
|
||||
|
@ -64,13 +62,12 @@ function ToolBarHeader() {
|
|||
async function openCompleteQuestUI() {
|
||||
const ApplicationStreamingStore = findByProps("getStreamerActiveStreamMetadata");
|
||||
const RunningGameStore = findByProps("getRunningGames");
|
||||
const ExperimentStore = findByProps("getGuildExperiments");
|
||||
const QuestsStore = findByProps("getQuest");
|
||||
const quest = [...QuestsStore.quests.values()].find(x => x.id !== "1248385850622869556" && x.userStatus?.enrolledAt && !x.userStatus?.completedAt && new Date(x.config.expiresAt).getTime() > Date.now());
|
||||
|
||||
if (!quest) {
|
||||
showNotification({
|
||||
title: "Quests Completer",
|
||||
title: "Quest Completer",
|
||||
body: "No Quests To Complete",
|
||||
});
|
||||
} else {
|
||||
|
@ -79,27 +76,52 @@ async function openCompleteQuestUI() {
|
|||
? "light"
|
||||
: "dark";
|
||||
|
||||
let applicationId, applicationName, secondsNeeded, secondsDone, canPlay, icon, questId;
|
||||
if (quest.config.configVersion === 1) {
|
||||
questId = quest.id;
|
||||
applicationId = quest.config.applicationId;
|
||||
applicationName = quest.config.applicationName;
|
||||
secondsNeeded = quest.config.streamDurationRequirementMinutes * 60;
|
||||
secondsDone = quest.userStatus?.streamProgressSeconds ?? 0;
|
||||
icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`;
|
||||
canPlay = quest.config.variants.includes(2);
|
||||
} else if (quest.config.configVersion === 2) {
|
||||
questId = quest.id;
|
||||
applicationId = quest.config.application.id;
|
||||
applicationName = quest.config.application.name;
|
||||
icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`;
|
||||
canPlay = ExperimentStore.getUserExperimentBucket("2024-04_quest_playtime_task") > 0 && quest.config.taskConfig.tasks.PLAY_ON_DESKTOP;
|
||||
const taskName = canPlay ? "PLAY_ON_DESKTOP" : "STREAM_ON_DESKTOP";
|
||||
secondsNeeded = quest.config.taskConfig.tasks[taskName]?.target;
|
||||
secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
|
||||
}
|
||||
if (canPlay) {
|
||||
await RestAPI.get({ url: `/applications/public?application_ids=${applicationId}` }).then(res => {
|
||||
const applicationId = quest.config.application.id;
|
||||
const applicationName = quest.config.application.name;
|
||||
const taskName = ["WATCH_VIDEO", "PLAY_ON_DESKTOP", "STREAM_ON_DESKTOP"].find(x => quest.config.taskConfig.tasks[x] != null);
|
||||
// @ts-ignore
|
||||
const secondsNeeded = quest.config.taskConfig.tasks[taskName].target;
|
||||
// @ts-ignore
|
||||
const secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
|
||||
const icon = `https://cdn.discordapp.com/assets/quests/${quest.id}/${theme}/${quest.config.assets.gameTile}`;
|
||||
if (taskName === "WATCH_VIDEO") {
|
||||
const tolerance = 2, speed = 10;
|
||||
const diff = Math.floor((Date.now() - new Date(quest.userStatus.enrolledAt).getTime()) / 1000);
|
||||
const startingPoint = Math.min(Math.max(Math.ceil(secondsDone), diff), secondsNeeded);
|
||||
const fn = async () => {
|
||||
for (let i = startingPoint; i <= secondsNeeded; i += speed) {
|
||||
try {
|
||||
await RestAPI.post({ url: `/quests/${quest.id}/video-progress`, body: { timestamp: Math.min(secondsNeeded, i + Math.random()) } });
|
||||
} catch (ex) {
|
||||
console.log("Failed to send increment of", i, ex);
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, tolerance * 1000));
|
||||
}
|
||||
if ((secondsNeeded - secondsDone) % speed !== 0) {
|
||||
await RestAPI.post({ url: `/quests/${quest.id}/video-progress`, body: { timestamp: secondsNeeded } });
|
||||
showNotification({
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: "Quest Completed.",
|
||||
icon: icon,
|
||||
});
|
||||
}
|
||||
};
|
||||
fn();
|
||||
showNotification({
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: `Wait for ${Math.ceil((secondsNeeded - startingPoint) / speed * tolerance)} more seconds.`,
|
||||
icon: icon,
|
||||
});
|
||||
console.log(`Spoofing video for ${applicationName}.`);
|
||||
} else if (taskName === "PLAY_ON_DESKTOP") {
|
||||
if (!isApp) {
|
||||
showNotification({
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: `${applicationName}'s quest requires the desktop app.`,
|
||||
icon: icon,
|
||||
});
|
||||
}
|
||||
RestAPI.get({ url: `/applications/public?application_ids=${applicationId}` }).then(res => {
|
||||
const appData = res.body[0];
|
||||
const exeName = appData.executables.find(x => x.os === "win32").name.replace(">", "");
|
||||
|
||||
|
@ -123,14 +145,14 @@ async function openCompleteQuestUI() {
|
|||
const fn = data => {
|
||||
const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value);
|
||||
showNotification({
|
||||
title: `${applicationName} - Quests Completer`,
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: `Current progress: ${progress}/${secondsNeeded} seconds.`,
|
||||
icon: icon,
|
||||
});
|
||||
|
||||
if (progress >= secondsNeeded) {
|
||||
showNotification({
|
||||
title: `${applicationName} - Quests Completer`,
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: "Quest Completed.",
|
||||
icon: icon,
|
||||
});
|
||||
|
@ -144,16 +166,29 @@ async function openCompleteQuestUI() {
|
|||
}
|
||||
};
|
||||
FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);
|
||||
console.log(`Spoofed your game to ${applicationName}.`);
|
||||
});
|
||||
} else {
|
||||
const stream = ApplicationStreamingStore.getAnyStreamForUser(UserStore.getCurrentUser()?.id);
|
||||
if (!stream) {
|
||||
} else if (taskName === "STREAM_ON_DESKTOP") {
|
||||
if (!isApp) {
|
||||
showNotification({
|
||||
title: "You're not streaming - Quests Completer",
|
||||
body: `${applicationName} requires you to be streaming.`,
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: `${applicationName}'s quest requires the desktop app.`,
|
||||
icon: icon,
|
||||
});
|
||||
}
|
||||
const stream = ApplicationStreamingStore.getAnyStreamForUser(UserStore.getCurrentUser()?.id);
|
||||
if (!stream) {
|
||||
showNotification({
|
||||
title: "You're not streaming - Quest Completer",
|
||||
body: `${applicationName} requires you to be streaming.\nPlease stream any window in vc.`,
|
||||
icon: icon,
|
||||
});
|
||||
}
|
||||
showNotification({
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: "Remember that you need at least 1 other person to be in the vc!",
|
||||
icon: icon,
|
||||
});
|
||||
const realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata;
|
||||
ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({
|
||||
id: applicationId,
|
||||
|
@ -164,14 +199,14 @@ async function openCompleteQuestUI() {
|
|||
const fn = data => {
|
||||
const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value);
|
||||
showNotification({
|
||||
title: `${applicationName} - Quests Completer`,
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: `Current progress: ${progress}/${secondsNeeded} seconds.`,
|
||||
icon: icon,
|
||||
});
|
||||
|
||||
if (progress >= secondsNeeded) {
|
||||
showNotification({
|
||||
title: `${applicationName} - Quests Completer`,
|
||||
title: `${applicationName} - Quest Completer`,
|
||||
body: "Quest Completed.",
|
||||
icon: icon,
|
||||
});
|
||||
|
@ -181,6 +216,7 @@ async function openCompleteQuestUI() {
|
|||
}
|
||||
};
|
||||
FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);
|
||||
console.log(`Spoofed your stream to ${applicationName}.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -190,11 +226,6 @@ export default definePlugin({
|
|||
name: "QuestCompleter",
|
||||
description: "A plugin to complete quests without having the game installed.",
|
||||
authors: [Devs.HappyEnderman, EquicordDevs.SerStars, EquicordDevs.thororen],
|
||||
settingsAboutComponent: () => <>
|
||||
<Forms.FormText className="remixme-warning">
|
||||
We can't guarantee this plugin won't get you warned or banned.
|
||||
</Forms.FormText>
|
||||
</>,
|
||||
patches: [
|
||||
{
|
||||
find: "\"invite-button\"",
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton } from "@api/ChatButtons";
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel, sendMessage } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
|
@ -26,7 +26,6 @@ export default definePlugin({
|
|||
name: "Woof",
|
||||
description: "Adds a chatbar button to woof in chat",
|
||||
authors: [Devs.Samwich],
|
||||
start() {
|
||||
addChatBarButton("vc-woof", ChatBarIcon);
|
||||
}
|
||||
start: () => addChatBarButton("Woof", ChatBarIcon),
|
||||
stop: () => removeChatBarButton("Woof")
|
||||
});
|
||||
|
|
|
@ -23,11 +23,14 @@ export default definePlugin({
|
|||
name: "MessagePopoverAPI",
|
||||
description: "API to add buttons to message popovers.",
|
||||
authors: [Devs.KingFish, Devs.Ven, Devs.Nuckyz],
|
||||
patches: [{
|
||||
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
||||
replacement: {
|
||||
match: /\.jsx\)\((\i\.\i),\{label:\i\.\i\.string\(\i\.\i#{intl::MESSAGE_ACTION_REPLY}.{0,200}?"reply-self".{0,50}?\}\):null(?=,.+?message:(\i))/,
|
||||
replace: "$&,Vencord.Api.MessagePopover._buildPopoverElements($1,$2)"
|
||||
patches: [
|
||||
{
|
||||
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
||||
replacement: {
|
||||
match: /(?<=:null),(.{0,40}togglePopout:.+?}\))\]}\):null,(?<=\((\i\.\i),{label:.+?:null,(\i&&!\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/,
|
||||
replace: (_, ReactButton, ButtonComponent, showReactButton, message) => "" +
|
||||
`]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,`
|
||||
}
|
||||
}
|
||||
}],
|
||||
]
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/Settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
@ -27,6 +27,21 @@ import { Message } from "discord-types/general";
|
|||
|
||||
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
||||
|
||||
const settings = definePluginSettings({
|
||||
ignoreBlockedMessages: {
|
||||
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: true,
|
||||
},
|
||||
hideRepliesToBlockedMessages: {
|
||||
description: "Hides replies to blocked messages.",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: false,
|
||||
},
|
||||
});
|
||||
|
||||
interface MessageDeleteProps {
|
||||
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
||||
collapsedReason: () => any;
|
||||
|
@ -35,7 +50,9 @@ interface MessageDeleteProps {
|
|||
export default definePlugin({
|
||||
name: "NoBlockedMessages",
|
||||
description: "Hides all blocked messages from chat completely.",
|
||||
authors: [Devs.rushii, Devs.Samu],
|
||||
authors: [Devs.rushii, Devs.Samu, Devs.Elvyra],
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "#{intl::BLOCKED_MESSAGES_HIDE}",
|
||||
|
@ -51,49 +68,40 @@ export default definePlugin({
|
|||
'"ReadStateStore"'
|
||||
].map(find => ({
|
||||
find,
|
||||
predicate: () => Settings.plugins.NoBlockedMessages.ignoreBlockedMessages === true,
|
||||
predicate: () => settings.store.ignoreBlockedMessages === true,
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,
|
||||
replace: (_, props) => `if($self.isBlocked(${props}.message))return;`
|
||||
replace: (_, props) => `if($self.isBlocked(${props}.message)||$self.isReplyToBlocked(${props}.message))return;`
|
||||
}
|
||||
]
|
||||
})),
|
||||
{
|
||||
find: ".messageListItem",
|
||||
replacement: {
|
||||
match: /(?<=\i=)(?=\(0,(\i)\.jsx)/,
|
||||
replace: "!$self.isReplyToBlocked(arguments[0].message)&&"
|
||||
}
|
||||
}
|
||||
],
|
||||
options: {
|
||||
ignoreBlockedMessages: {
|
||||
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: true,
|
||||
find: "referencedUsernameProfile,referencedAvatarProfile",
|
||||
replacement: [
|
||||
{
|
||||
match: /CUSTOM_GIFT.*?=(?=\(0,\i.jsx\)\(\i.FocusRing)/,
|
||||
replace: "$&!$self.isReplyToBlocked(arguments[0].message)&&",
|
||||
}
|
||||
],
|
||||
},
|
||||
hideRepliesToBlockedMessages: {
|
||||
description: "Hide replies to messages made by users you've blocked",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: false,
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
isReplyToBlocked(message: Message) {
|
||||
if (!Settings.plugins.NoBlockedMessages.hideRepliesToBlockedMessages)
|
||||
return false;
|
||||
if (!settings.store.hideRepliesToBlockedMessages) return false;
|
||||
try {
|
||||
const { messageReference } = message;
|
||||
if (!messageReference) return false;
|
||||
|
||||
const { messageReference } = message;
|
||||
if (!messageReference) return false;
|
||||
const replyMessage = MessageStore.getMessage(messageReference.channel_id, messageReference.message_id);
|
||||
return this.isBlocked(replyMessage);
|
||||
const replyMessage = MessageStore.getMessage(messageReference.channel_id, messageReference.message_id);
|
||||
|
||||
return replyMessage ? this.isBlocked(replyMessage) : false;
|
||||
} catch (e) {
|
||||
new Logger("NoBlockedMessages").error("Failed to check if referenced message is blocked:", e);
|
||||
}
|
||||
},
|
||||
|
||||
isBlocked(message: Message | undefined) {
|
||||
if (!message) return false;
|
||||
isBlocked(message: Message) {
|
||||
try {
|
||||
return RelationshipStore.isBlocked(message.author.id);
|
||||
} catch (e) {
|
||||
|
@ -105,7 +113,7 @@ export default definePlugin({
|
|||
try {
|
||||
return props.collapsedReason() === i18n.t[runtimeHashMessageKey("BLOCKED_MESSAGE_COUNT")]();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
new Logger("NoBlockedMessages").error("Failed to hide blocked message:", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import "./style.css";
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
import { canonicalizeMatch } from "@utils/patches";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
@ -33,24 +33,38 @@ const ChannelListClasses = findByPropsLazy("modeMuted", "modeSelected", "unread"
|
|||
|
||||
const enum ShowMode {
|
||||
LockIcon,
|
||||
HiddenIconWithMutedStyle
|
||||
LockIconRight,
|
||||
EyeIconRight,
|
||||
}
|
||||
|
||||
const enum ChannelStyle {
|
||||
Classic,
|
||||
Muted,
|
||||
Unread,
|
||||
MutedUnread,
|
||||
}
|
||||
|
||||
const CONNECT = 1n << 20n;
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
hideUnreads: {
|
||||
description: "Hide Unreads",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
channelStyle: {
|
||||
description: "The style used to display hidden channels.",
|
||||
type: OptionType.SELECT,
|
||||
options: [
|
||||
{ label: "Classic", value: ChannelStyle.Classic, default: true },
|
||||
{ label: "Muted", value: ChannelStyle.Muted },
|
||||
{ label: "Show Unreads", value: ChannelStyle.Unread },
|
||||
{ label: "Muted and Show Unreads", value: ChannelStyle.MutedUnread }
|
||||
],
|
||||
restartNeeded: true
|
||||
},
|
||||
showMode: {
|
||||
description: "The mode used to display hidden channels.",
|
||||
type: OptionType.SELECT,
|
||||
options: [
|
||||
{ label: "Plain style with Lock Icon instead", value: ShowMode.LockIcon, default: true },
|
||||
{ label: "Muted style with hidden eye icon on the right", value: ShowMode.HiddenIconWithMutedStyle },
|
||||
{ label: "Lock Icon replacing channel icon", value: ShowMode.LockIcon, default: true },
|
||||
{ label: "Eye icon on the right", value: ShowMode.EyeIconRight },
|
||||
{ label: "Lock icon on the right", value: ShowMode.LockIconRight }
|
||||
],
|
||||
restartNeeded: true
|
||||
},
|
||||
|
@ -68,7 +82,7 @@ function isUncategorized(objChannel: { channel: Channel; comparator: number; })
|
|||
export default definePlugin({
|
||||
name: "ShowHiddenChannels",
|
||||
description: "Show channels that you do not have access to view.",
|
||||
authors: [Devs.BigDuck, Devs.AverageReactEnjoyer, Devs.D3SOX, Devs.Ven, Devs.Nuckyz, Devs.Nickyux, Devs.dzshn],
|
||||
authors: [Devs.BigDuck, Devs.AverageReactEnjoyer, Devs.D3SOX, Devs.Ven, Devs.Nuckyz, Devs.Nickyux, Devs.dzshn, EquicordDevs.Oggetto],
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
|
@ -159,37 +173,50 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
find: "UNREAD_IMPORTANT:",
|
||||
predicate: () => settings.store.showMode === ShowMode.HiddenIconWithMutedStyle,
|
||||
predicate: () => settings.store.showMode !== ShowMode.LockIcon,
|
||||
replacement: [
|
||||
// Add the hidden eye icon if the channel is hidden
|
||||
{
|
||||
predicate: () => settings.store.showMode === ShowMode.EyeIconRight,
|
||||
match: /\.name\),.{0,120}\.children.+?:null(?<=,channel:(\i).+?)/,
|
||||
replace: (m, channel) => `${m},$self.isHiddenChannel(${channel})?$self.EyeRightIcon():null`
|
||||
},
|
||||
// Add the hidden lock icon if the channel is hidden
|
||||
{
|
||||
predicate: () => settings.store.showMode === ShowMode.LockIconRight,
|
||||
match: /\.name\),.{0,120}\.children.+?:null(?<=,channel:(\i).+?)/,
|
||||
replace: (m, channel) => `${m},$self.isHiddenChannel(${channel})?$self.LockRightIcon():null`
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
find: "UNREAD_IMPORTANT:",
|
||||
predicate: () => settings.store.channelStyle === ChannelStyle.Muted || settings.store.channelStyle === ChannelStyle.MutedUnread,
|
||||
replacement: [
|
||||
// Make the channel appear as muted if it's hidden
|
||||
{
|
||||
match: /{channel:(\i),name:\i,muted:(\i).+?;/,
|
||||
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
|
||||
},
|
||||
// Add the hidden eye icon if the channel is hidden
|
||||
{
|
||||
match: /\.name\),.{0,120}\.children.+?:null(?<=,channel:(\i).+?)/,
|
||||
replace: (m, channel) => `${m},$self.isHiddenChannel(${channel})?$self.HiddenChannelIcon():null`
|
||||
},
|
||||
// Make voice channels also appear as muted if they are muted
|
||||
{
|
||||
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)if\((\i)\)return (\i\.MUTED);/,
|
||||
replace: (_, otherClasses, isMuted, mutedClassExpression) => `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return "";`
|
||||
},
|
||||
{
|
||||
// Make muted channels also appear as unread if hide unreads is false and the channel is hidden
|
||||
predicate: () => settings.store.channelStyle === ChannelStyle.MutedUnread || settings.store.channelStyle === ChannelStyle.Unread,
|
||||
match: /\.LOCKED;if\((?<={channel:(\i).+?)/,
|
||||
replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: "UNREAD_IMPORTANT:",
|
||||
predicate: () => settings.store.channelStyle !== ChannelStyle.Unread && settings.store.channelStyle !== ChannelStyle.MutedUnread,
|
||||
replacement: [
|
||||
{
|
||||
// Make muted channels also appear as unread if hide unreads is false, using the HiddenIconWithMutedStyle and the channel is hidden
|
||||
predicate: () => settings.store.hideUnreads === false && settings.store.showMode === ShowMode.HiddenIconWithMutedStyle,
|
||||
match: /\.LOCKED;if\((?<={channel:(\i).+?)/,
|
||||
replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&`
|
||||
},
|
||||
{
|
||||
// Hide unreads
|
||||
predicate: () => settings.store.hideUnreads === true,
|
||||
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/,
|
||||
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
|
||||
}
|
||||
|
@ -543,7 +570,7 @@ export default definePlugin({
|
|||
</svg>
|
||||
), { noop: true }),
|
||||
|
||||
HiddenChannelIcon: ErrorBoundary.wrap(() => (
|
||||
EyeRightIcon: ErrorBoundary.wrap(() => (
|
||||
<Tooltip text="Hidden Channel">
|
||||
{({ onMouseLeave, onMouseEnter }) => (
|
||||
<svg
|
||||
|
@ -560,5 +587,24 @@ export default definePlugin({
|
|||
</svg>
|
||||
)}
|
||||
</Tooltip>
|
||||
), { noop: true }),
|
||||
|
||||
LockRightIcon: ErrorBoundary.wrap(() => (
|
||||
<Tooltip text="Hidden Channel">
|
||||
{({ onMouseLeave, onMouseEnter }) => (
|
||||
<svg
|
||||
onMouseLeave={onMouseLeave}
|
||||
onMouseEnter={onMouseEnter}
|
||||
className={ChannelListClasses.icon + " " + "shc-hidden-channel-icon"}
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden={true}
|
||||
role="img"
|
||||
>
|
||||
<path className="shc-evenodd-fill-current-color" d="M17 11V7C17 4.243 14.756 2 12 2C9.242 2 7 4.243 7 7V11C5.897 11 5 11.896 5 13V20C5 21.103 5.897 22 7 22H17C18.103 22 19 21.103 19 20V13C19 11.896 18.103 11 17 11ZM12 18C11.172 18 10.5 17.328 10.5 16.5C10.5 15.672 11.172 15 12 15C12.828 15 13.5 15.672 13.5 16.5C13.5 17.328 12.828 18 12 18ZM15 11H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V11Z" />
|
||||
</svg>
|
||||
)}
|
||||
</Tooltip>
|
||||
), { noop: true })
|
||||
});
|
||||
|
|
|
@ -943,7 +943,11 @@ export const EquicordDevs = Object.freeze({
|
|||
Z1xus: {
|
||||
name: "Z1xus",
|
||||
id: 377450600797044746n,
|
||||
}
|
||||
},
|
||||
Oggetto: {
|
||||
name: "Oggetto",
|
||||
id: 619203349954166804n,
|
||||
},
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
// iife so #__PURE__ works correctly
|
||||
|
|
Loading…
Reference in a new issue