Fix ShowHiddenChannels

This commit is contained in:
Nuckyz 2023-10-25 17:20:51 -03:00
parent 0c6445b66b
commit 123853e848
No known key found for this signature in database
GPG Key ID: 440BF8296E1C4AD9
2 changed files with 104 additions and 98 deletions

@ -20,14 +20,13 @@ import { Settings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { LazyComponent } from "@utils/react"; import { LazyComponent } from "@utils/react";
import { formatDuration } from "@utils/text"; import { formatDuration } from "@utils/text";
import { find, findByPropsLazy } from "@webpack"; import { find, findByCode, findByPropsLazy } from "@webpack";
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, moment, Parser, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common"; import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, moment, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
import type { Channel } from "discord-types/general"; import type { Channel } from "discord-types/general";
import type { ComponentType } from "react";
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions"; import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions";
import { sortPermissionOverwrites } from "../../permissionsViewer/utils"; import { sortPermissionOverwrites } from "../../permissionsViewer/utils";
import { settings, VIEW_CHANNEL } from ".."; import { settings } from "..";
const enum SortOrderTypes { const enum SortOrderTypes {
LATEST_ACTIVITY = 0, LATEST_ACTIVITY = 0,
@ -79,19 +78,15 @@ const enum ChannelFlags {
REQUIRE_TAG = 1 << 4 REQUIRE_TAG = 1 << 4
} }
let ChannelBeginHeader: ComponentType<any>;
export function setChannelBeginHeaderComponent(component: ComponentType<any>) {
ChannelBeginHeader = component;
}
const ChatScrollClasses = findByPropsLazy("auto", "content", "scrollerBase"); const ChatScrollClasses = findByPropsLazy("auto", "content", "scrollerBase");
const ChatClasses = findByPropsLazy("chat", "content", "noChat", "chatContent"); const ChatClasses = findByPropsLazy("chat", "content", "noChat", "chatContent");
const ChannelBeginHeader = LazyComponent(() => findByCode(".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE"));
const TagComponent = LazyComponent(() => find(m => { const TagComponent = LazyComponent(() => find(m => {
if (typeof m !== "function") return false; if (typeof m !== "function") return false;
const code = Function.prototype.toString.call(m); const code = Function.prototype.toString.call(m);
// Get the component which doesn't include increasedActivity logic // Get the component which doesn't include increasedActivity
return code.includes(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG") && !code.includes("increasedActivityPill"); return code.includes(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG") && !code.includes("increasedActivityPill");
})); }));
@ -185,7 +180,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
<img className="shc-lock-screen-logo" src={HiddenChannelLogo} /> <img className="shc-lock-screen-logo" src={HiddenChannelLogo} />
<div className="shc-lock-screen-heading-container"> <div className="shc-lock-screen-heading-container">
<Text variant="heading-xxl/bold">This is a {!PermissionStore.can(VIEW_CHANNEL, channel) ? "hidden" : "locked"} {ChannelTypesToChannelNames[type]} channel.</Text> <Text variant="heading-xxl/bold">This is a {!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) ? "hidden" : "locked"} {ChannelTypesToChannelNames[type]} channel.</Text>
{channel.isNSFW() && {channel.isNSFW() &&
<Tooltip text="NSFW"> <Tooltip text="NSFW">
{({ onMouseLeave, onMouseEnter }) => ( {({ onMouseLeave, onMouseEnter }) => (

@ -24,16 +24,13 @@ import { Devs } from "@utils/constants";
import { canonicalizeMatch } from "@utils/patches"; import { canonicalizeMatch } from "@utils/patches";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack"; import { findByPropsLazy } from "@webpack";
import { ChannelStore, PermissionStore, Tooltip } from "@webpack/common"; import { ChannelStore, PermissionsBits, PermissionStore, Tooltip } from "@webpack/common";
import type { Channel, Role } from "discord-types/general"; import type { Channel, Role } from "discord-types/general";
import HiddenChannelLockScreen, { setChannelBeginHeaderComponent } from "./components/HiddenChannelLockScreen"; import HiddenChannelLockScreen from "./components/HiddenChannelLockScreen";
const ChannelListClasses = findByPropsLazy("channelEmoji", "unread", "icon"); const ChannelListClasses = findByPropsLazy("channelEmoji", "unread", "icon");
export const VIEW_CHANNEL = 1n << 10n;
const CONNECT = 1n << 20n;
const enum ShowMode { const enum ShowMode {
LockIcon, LockIcon,
HiddenIconWithMutedStyle HiddenIconWithMutedStyle
@ -72,16 +69,10 @@ export default definePlugin({
{ {
// RenderLevel defines if a channel is hidden, collapsed in category, visible, etc // RenderLevel defines if a channel is hidden, collapsed in category, visible, etc
find: ".CannotShow=", find: ".CannotShow=",
// These replacements only change the necessary CannotShow's
replacement: [ replacement: [
{ {
match: /(?<=isChannelGatedAndVisible\(this\.record\.guild_id,this\.record\.id\).+?renderLevel:)(\i)\..+?(?=,)/, match: /if\(!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL.+?{if\(this\.id===\i\).+?threadIds:\i}}/,
replace: (_, RenderLevels) => `this.category.isCollapsed?${RenderLevels}.WouldShowIfUncollapsed:${RenderLevels}.Show` replace: ""
},
// Move isChannelGatedAndVisible renderLevel logic to the bottom to not show hidden channels in case they are muted
{
match: /(?<=(if\(!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL.+?{)if\(this\.id===\i\).+?};)(if\(!\i\.\i\.isChannelGatedAndVisible\(.+?})(.+?)(?=return{renderLevel:\i\.Show.{0,40}?return \i)/,
replace: (_, permissionCheck, isChannelGatedAndVisibleCondition, rest) => `${rest}${permissionCheck}${isChannelGatedAndVisibleCondition}}`
}, },
{ {
match: /(?<=renderLevel:(\i\(this,\i\)\?\i\.Show:\i\.WouldShowIfUncollapsed).+?renderLevel:).+?(?=,)/, match: /(?<=renderLevel:(\i\(this,\i\)\?\i\.Show:\i\.WouldShowIfUncollapsed).+?renderLevel:).+?(?=,)/,
@ -92,8 +83,8 @@ export default definePlugin({
replace: (_, RenderLevels) => `${RenderLevels}.Show` replace: (_, RenderLevels) => `${RenderLevels}.Show`
}, },
{ {
match: /(?<=getRenderLevel=function.+?return ).+?\?(.+?):\i\.CannotShow(?=})/, match: /(?<=getRenderLevel\(\i\){.+?return)!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL,this\.record\)\|\|/,
replace: (_, renderLevelExpressionWithoutPermCheck) => renderLevelExpressionWithoutPermCheck replace: " "
} }
] ]
}, },
@ -102,13 +93,13 @@ export default definePlugin({
replacement: [ replacement: [
{ {
// Do not show confirmation to join a voice channel when already connected to another if clicking on a hidden voice channel // Do not show confirmation to join a voice channel when already connected to another if clicking on a hidden voice channel
match: /(?<=getCurrentClientVoiceChannelId\((\i)\.guild_id\);if\()/, match: /(?<=getCurrentClientVoiceChannelId\((\i)\.guild_id\);return)/,
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&` replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
}, },
{ {
// Prevent Discord from trying to connect to hidden channels // Prevent Discord from trying to connect to hidden voice channels
match: /(?=\|\|\i\.default\.selectVoiceChannel\((\i)\.id\))/, match: /(?=&&\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
replace: (_, channel) => `||$self.isHiddenChannel(${channel})` replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
}, },
{ {
// Make Discord show inside the channel if clicking on a hidden or locked channel // Make Discord show inside the channel if clicking on a hidden or locked channel
@ -117,26 +108,42 @@ export default definePlugin({
} }
] ]
}, },
// Prevent Discord from trying to connect to hidden stage channels
{ {
find: "VoiceChannel.renderPopout: There must always be something to render", find: ".MAX_STAGE_VOICE_USER_LIMIT})",
replacement: {
match: /!(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})`
}
},
{
find: "ChannelItemEditButton:function(){",
replacement: [ replacement: [
// Render null instead of the buttons if the channel is hidden // Render null instead of the buttons if the channel is hidden
...[ ...[
"renderEditButton", "renderEditButton",
"renderInviteButton", "renderInviteButton",
"renderOpenChatButton"
].map(func => ({ ].map(func => ({
match: new RegExp(`(?<=${func}=function\\(\\){)`, "g"), // Global because Discord has multiple declarations of the same functions match: new RegExp(`(?<=${func}\\(\\){)`, "g"), // Global because Discord has multiple declarations of the same functions
replace: "if($self.isHiddenChannel(this.props.channel))return null;" replace: "if($self.isHiddenChannel(this.props.channel))return null;"
})) }))
] ]
}, },
{
find: "VoiceChannel.renderPopout: There must always be something to render",
all: true,
// Render null instead of the buttons if the channel is hidden
replacement: {
match: /(?<=renderOpenChatButton=\(\)=>{)/,
replace: "if($self.isHiddenChannel(this.props.channel))return null;"
}
},
{ {
find: ".Messages.CHANNEL_TOOLTIP_DIRECTORY", find: ".Messages.CHANNEL_TOOLTIP_DIRECTORY",
predicate: () => settings.store.showMode === ShowMode.LockIcon, predicate: () => settings.store.showMode === ShowMode.LockIcon,
replacement: { replacement: {
// Lock Icon // Lock Icon
match: /(?=switch\((\i)\.type\).{0,30}\.GUILD_ANNOUNCEMENT.{0,30}\(0,\i\.\i\))/, match: /(?=switch\((\i)\.type\).{0,30}\.GUILD_ANNOUNCEMENT.{0,70}\(0,\i\.\i\))/,
replace: (_, channel) => `if($self.isHiddenChannel(${channel}))return $self.LockIcon;` replace: (_, channel) => `if($self.isHiddenChannel(${channel}))return $self.LockIcon;`
} }
}, },
@ -146,18 +153,18 @@ export default definePlugin({
replacement: [ replacement: [
// Make the channel appear as muted if it's hidden // Make the channel appear as muted if it's hidden
{ {
match: /(?<=\i\.name,\i=)(?=(\i)\.muted)/, match: /(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
replace: (_, props) => `$self.isHiddenChannel(${props}.channel)?true:` replace: (_, channel, muted) => `${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
}, },
// Add the hidden eye icon if the channel is hidden // Add the hidden eye icon if the channel is hidden
{ {
match: /\(\).children.+?:null(?<=(\i)=\i\.channel,.+?)/, match: /\i\.children.+?:null(?<=,channel:(\i).+?)/,
replace: (m, channel) => `${m},$self.isHiddenChannel(${channel})?$self.HiddenChannelIcon():null` replace: (m, channel) => `${m},$self.isHiddenChannel(${channel})?$self.HiddenChannelIcon():null`
}, },
// Make voice channels also appear as muted if they are muted // Make voice channels also appear as muted if they are muted
{ {
match: /(?<=\.wrapper:\i\(\)\.notInteractive,)(.+?)((\i)\?\i\.MUTED)/, match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)if\((\i)\)return (\i\.MUTED);/,
replace: (_, otherClasses, mutedClassExpression, isMuted) => `${mutedClassExpression}:"",${otherClasses}${isMuted}?""` replace: (_, otherClasses, isMuted, mutedClassExpression) => `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return "";`
} }
] ]
}, },
@ -167,14 +174,14 @@ export default definePlugin({
{ {
// Make muted channels also appear as unread if hide unreads is false, using the HiddenIconWithMutedStyle and the channel is hidden // 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, predicate: () => settings.store.hideUnreads === false && settings.store.showMode === ShowMode.HiddenIconWithMutedStyle,
match: /\.LOCKED:\i(?<=(\i)=\i\.channel,.+?)/, match: /\.LOCKED;if\((?<={channel:(\i).+?)/,
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})` replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&`
}, },
{ {
// Hide unreads // Hide unreads
predicate: () => settings.store.hideUnreads === true, predicate: () => settings.store.hideUnreads === true,
match: /(?<=\i\.connected,\i=)(?=(\i)\.unread)/, match: /(?<={channel:(\i),name:\i,.+?unread:(\i).+?;)/,
replace: (_, props) => `$self.isHiddenChannel(${props}.channel)?false:` replace: (_, channel, unread) => `${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
} }
] ]
}, },
@ -182,8 +189,8 @@ export default definePlugin({
// Hide New unreads box for hidden channels // Hide New unreads box for hidden channels
find: '.displayName="ChannelListUnreadsStore"', find: '.displayName="ChannelListUnreadsStore"',
replacement: { replacement: {
match: /(?<=return null!=(\i))(?=.{0,130}?hasRelevantUnread\(\i\))/g, // Global because Discord has multiple methods like that in the same module match: /(?<=if\(null==(\i))(?=.{0,160}?hasRelevantUnread\(\i\))/g, // Global because Discord has multiple methods like that in the same module
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})` replace: (_, channel) => `||$self.isHiddenChannel(${channel})`
} }
}, },
// Only render the channel header and buttons that work when transitioning to a hidden channel // Only render the channel header and buttons that work when transitioning to a hidden channel
@ -191,27 +198,27 @@ export default definePlugin({
find: "Missing channel in Channel.renderHeaderToolbar", find: "Missing channel in Channel.renderHeaderToolbar",
replacement: [ replacement: [
{ {
match: /(?<=renderHeaderToolbar=function.+?case \i\.\i\.GUILD_TEXT:)(?=.+?;(.+?{channel:(\i)},"notifications"\)\);))/, match: /(?<=renderHeaderToolbar=\(\)=>{.+?case \i\.\i\.GUILD_TEXT:)(?=.+?(\i\.push.{0,50}channel:(\i)},"notifications"\)\)))(?<=isLurking:(\i).+?)/,
replace: (_, pushNotificationButtonExpression, channel) => `if($self.isHiddenChannel(${channel})){${pushNotificationButtonExpression}break;}` replace: (_, pushNotificationButtonExpression, channel, isLurking) => `if(!${isLurking}&&$self.isHiddenChannel(${channel})){${pushNotificationButtonExpression};break;}`
}, },
{ {
match: /(?<=renderHeaderToolbar=function.+?case \i\.\i\.GUILD_FORUM:.+?if\(!\i\){)(?=.+?;(.+?{channel:(\i)},"notifications"\)\)))/, match: /(?<=renderHeaderToolbar=\(\)=>{.+?case \i\.\i\.GUILD_MEDIA:)(?=.+?(\i\.push.{0,40}channel:(\i)},"notifications"\)\)))(?<=isLurking:(\i).+?)/,
replace: (_, pushNotificationButtonExpression, channel) => `if($self.isHiddenChannel(${channel})){${pushNotificationButtonExpression};break;}` replace: (_, pushNotificationButtonExpression, channel, isLurking) => `if(!${isLurking}&&$self.isHiddenChannel(${channel})){${pushNotificationButtonExpression};break;}`
}, },
{ {
match: /renderMobileToolbar=function.+?case \i\.\i\.GUILD_FORUM:(?<=(\i)\.renderMobileToolbar.+?)/, match: /renderMobileToolbar=\(\)=>{.+?case \i\.\i\.GUILD_DIRECTORY:(?<=let{channel:(\i).+?)/,
replace: (m, that) => `${m}if($self.isHiddenChannel(${that}.props.channel))break;` replace: (m, channel) => `${m}if($self.isHiddenChannel(${channel}))break;`
}, },
{ {
match: /(?<=renderHeaderBar=function.+?hideSearch:(\i)\.isDirectory\(\))/, match: /(?<=renderHeaderBar=\(\)=>{.+?hideSearch:(\i)\.isDirectory\(\))/,
replace: (_, channel) => `||$self.isHiddenChannel(${channel})` replace: (_, channel) => `||$self.isHiddenChannel(${channel})`
}, },
{ {
match: /(?<=renderSidebar=function\(\){)/, match: /(?<=renderSidebar\(\){)/,
replace: "if($self.isHiddenChannel(this.props.channel))return null;" replace: "if($self.isHiddenChannel(this.props.channel))return null;"
}, },
{ {
match: /(?<=renderChat=function\(\){)/, match: /(?<=renderChat\(\){)/,
replace: "if($self.isHiddenChannel(this.props.channel))return $self.HiddenChannelLockScreen(this.props.channel);" replace: "if($self.isHiddenChannel(this.props.channel))return $self.HiddenChannelLockScreen(this.props.channel);"
} }
] ]
@ -220,7 +227,7 @@ export default definePlugin({
{ {
find: '"MessageManager"', find: '"MessageManager"',
replacement: { replacement: {
match: /"Skipping fetch because channelId is a static route"\);else{(?=.+?getChannel\((\i)\))/, match: /"Skipping fetch because channelId is a static route"\);return}(?=.+?getChannel\((\i)\))/,
replace: (m, channelId) => `${m}if($self.isHiddenChannel({channelId:${channelId}}))return;` replace: (m, channelId) => `${m}if($self.isHiddenChannel({channelId:${channelId}}))return;`
} }
}, },
@ -228,48 +235,44 @@ export default definePlugin({
{ {
find: '"alt+shift+down"', find: '"alt+shift+down"',
replacement: { replacement: {
match: /(?<=getChannel\(\i\);return null!=(\i))(?=.{0,130}?hasRelevantUnread\(\i\))/, match: /(?<=getChannel\(\i\);return null!=(\i))(?=.{0,150}?hasRelevantUnread\(\i\))/,
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})` replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
} }
}, },
// Patch keybind handlers so you can't accidentally jump to hidden channels
{ {
find: '"alt+down"', find: ".APPLICATION_STORE&&null!=",
replacement: { replacement: {
match: /(?<=getState\(\)\.channelId.{0,30}?\(0,\i\.\i\)\(\i\))(?=\.map\()/, match: /(?<=getState\(\)\.channelId.{0,30}?\(0,\i\.\i\)\(\i\))(?=\.map\()/,
replace: ".filter(ch=>!$self.isHiddenChannel(ch))" replace: ".filter(e=>!$self.isHiddenChannel(e))"
} }
}, },
{ {
find: ".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE", find: ".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE",
replacement: [ replacement: [
{
// Export the channel beginning header
match: /computePermissionsForRoles.+?}\)}(?<=function (\i)\(.+?)(?=var)/,
replace: (m, component) => `${m}$self.setChannelBeginHeaderComponent(${component});`
},
{ {
// Change the role permission check to CONNECT if the channel is locked // Change the role permission check to CONNECT if the channel is locked
match: /ADMINISTRATOR\)\|\|(?<=context:(\i)}.+?)(?=(.+?)VIEW_CHANNEL)/, match: /ADMINISTRATOR\)\|\|(?<=context:(\i)}.+?)(?=(.+?)VIEW_CHANNEL)/,
replace: (m, channel, permCheck) => `${m}!Vencord.Webpack.Common.PermissionStore.can(${CONNECT}n,${channel})?${permCheck}CONNECT):` replace: (m, channel, permCheck) => `${m}!Vencord.Webpack.Common.PermissionStore.can(${PermissionsBits.CONNECT}n,${channel})?${permCheck}CONNECT):`
}, },
{ {
// Change the permissionOverwrite check to CONNECT if the channel is locked // Change the permissionOverwrite check to CONNECT if the channel is locked
match: /permissionOverwrites\[.+?\i=(?<=context:(\i)}.+?)(?=(.+?)VIEW_CHANNEL)/, match: /permissionOverwrites\[.+?\i=(?<=context:(\i)}.+?)(?=(.+?)VIEW_CHANNEL)/,
replace: (m, channel, permCheck) => `${m}!Vencord.Webpack.Common.PermissionStore.can(${CONNECT}n,${channel})?${permCheck}CONNECT):` replace: (m, channel, permCheck) => `${m}!Vencord.Webpack.Common.PermissionStore.can(${PermissionsBits.CONNECT}n,${channel})?${permCheck}CONNECT):`
}, },
{ {
// Include the @everyone role in the allowed roles list for Hidden Channels // Include the @everyone role in the allowed roles list for Hidden Channels
match: /sortBy.{0,100}?return (?<=var (\i)=\i\.channel.+?)(?=\i\.id)/, match: /sortBy.{0,30}?\.filter\(\i=>(?<=channel:(\i).+?)/,
replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?true:` replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?true:`
}, },
{ {
// If the @everyone role has the required permissions, make the array only contain it // If the @everyone role has the required permissions, make the array only contain it
match: /computePermissionsForRoles.+?.value\(\)(?<=var (\i)=\i\.channel.+?)/, match: /computePermissionsForRoles.+?.value\(\)(?<=channel:(\i).+?)/,
replace: (m, channel) => `${m}.reduce(...$self.makeAllowedRolesReduce(${channel}.guild_id))` replace: (m, channel) => `${m}.reduce(...$self.makeAllowedRolesReduce(${channel}.guild_id))`
}, },
{ {
// Patch the header to only return allowed users and roles if it's a hidden channel or locked channel (Like when it's used on the HiddenChannelLockScreen) // Patch the header to only return allowed users and roles if it's a hidden channel or locked channel (Like when it's used on the HiddenChannelLockScreen)
match: /MANAGE_ROLES.{0,60}?return(?=\(.+?(\(0,\i\.jsxs\)\("div",{className:\i\(\)\.members.+?guildId:(\i)\.guild_id.+?roleColor.+?]}\)))/, match: /MANAGE_ROLES.{0,90}?return(?=\(.+?(\(0,\i\.jsxs\)\("div",{className:\i\.members.+?guildId:(\i)\.guild_id.+?roleColor.+?\]}\)))/,
replace: (m, component, channel) => { replace: (m, component, channel) => {
// Export the channel for the users allowed component patch // Export the channel for the users allowed component patch
component = component.replace(canonicalizeMatch(/(?<=users:\i)/), `,channel:${channel}`); component = component.replace(canonicalizeMatch(/(?<=users:\i)/), `,channel:${channel}`);
@ -282,12 +285,12 @@ export default definePlugin({
] ]
}, },
{ {
find: "().avatars),children", find: ".avatars),children",
replacement: [ replacement: [
{ {
// Create a variable for the channel prop // Create a variable for the channel prop
match: /=(\i)\.maxUsers,/, match: /maxUsers:\i,users:\i.+?=(\i).+?;/,
replace: (m, props) => `${m}channel=${props}.channel,` replace: (m, props) => `${m}var channel=${props}.channel;`
}, },
{ {
// Make Discord always render the plus button if the component is used inside the HiddenChannelLockScreen // Make Discord always render the plus button if the component is used inside the HiddenChannelLockScreen
@ -307,63 +310,73 @@ export default definePlugin({
] ]
}, },
{ {
find: ".Messages.SHOW_CHAT", find: ".Messages.CHANNEL_CALL_CURRENT_SPEAKER.format",
replacement: [ replacement: [
{ {
// Remove the divider and the open chat button for the HiddenChannelLockScreen // Remove the divider and the open chat button for the HiddenChannelLockScreen
match: /"more-options-popout"\)\);if\((?<=function \i\((\i)\).+?)/, match: /"more-options-popout"\)\),(?<=let{channel:(\i).+?inCall:(\i).+?)/,
replace: (m, props) => `${m}!${props}.inCall&&$self.isHiddenChannel(${props}.channel,true)){}else if(` replace: (m, channel, inCall) => `${m}${inCall}||!$self.isHiddenChannel(${channel},true)&&`
}, },
{ {
// Remove invite users button for the HiddenChannelLockScreen // Remove invite users button for the HiddenChannelLockScreen
match: /"popup".{0,100}?if\((?<=(\i)\.channel.+?)/, match: /"popup".{0,100}?if\((?<=let{channel:(\i).+?inCall:(\i).+?)/,
replace: (m, props) => `${m}(${props}.inCall||!$self.isHiddenChannel(${props}.channel,true))&&` replace: (m, channel, inCall) => `${m}(${inCall}||!$self.isHiddenChannel(${channel},true))&&`
}, },
]
},
{
find: ".Messages.EMBEDDED_ACTIVITIES_DEVELOPER_ACTIVITY_SHELF_FETCH_ERROR",
replacement: [
{ {
// Render our HiddenChannelLockScreen component instead of the main voice channel component // Render our HiddenChannelLockScreen component instead of the main voice channel component
match: /this\.renderVoiceChannelEffects.+?children:(?<=renderContent=function.+?)/, match: /renderContent\(\i\){.+?this\.renderVoiceChannelEffects.+?children:/,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?$self.HiddenChannelLockScreen(this.props.channel):" replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?$self.HiddenChannelLockScreen(this.props.channel):"
}, },
{ {
// Disable gradients for the HiddenChannelLockScreen of voice channels // Disable gradients for the HiddenChannelLockScreen of voice channels
match: /this\.renderVoiceChannelEffects.+?disableGradients:(?<=renderContent=function.+?)/, match: /renderContent\(\i\){.+?disableGradients:/,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)||" replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)||"
}, },
{ {
// Disable useless components for the HiddenChannelLockScreen of voice channels // Disable useless components for the HiddenChannelLockScreen of voice channels
match: /(?:{|,)render(?!Header|ExternalHeader).{0,30}?:(?<=renderContent=function.+?)(?!void)/g, match: /(?:{|,)render(?!Header|ExternalHeader).{0,30}?:/g,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?null:" replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?()=>null:"
}, },
{ {
// Disable bad CSS class which mess up hidden voice channels styling // Disable bad CSS class which mess up hidden voice channels styling
match: /callContainer,(?<=\(\)\.callContainer,)/, match: /callContainer,(?<=\i\.callContainer,)/,
replace: '$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?"":' replace: '$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?"":'
} }
] ]
}, },
{ {
find: "useNotificationSettingsItem: channel cannot be undefined", find: '"HasBeenInStageChannel"',
replacement: [ replacement: [
{ {
// Render our HiddenChannelLockScreen component instead of the main stage channel component // Render our HiddenChannelLockScreen component instead of the main stage channel component
match: /"124px".+?children:(?<=var (\i)=\i\.channel.+?)(?=.{0,20}?}\)}function)/, match: /"124px".+?children:(?<=let \i,{channel:(\i).+?)(?=.{0,20}?}\)}function)/,
replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?$self.HiddenChannelLockScreen(${channel}):` replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?$self.HiddenChannelLockScreen(${channel}):`
}, },
{ {
// Disable useless components for the HiddenChannelLockScreen of stage channels // Disable useless components for the HiddenChannelLockScreen of stage channels
match: /render(?:BottomLeft|BottomCenter|BottomRight|ChatToasts):(?<=var (\i)=\i\.channel.+?)/g, match: /render(?:BottomLeft|BottomCenter|BottomRight|ChatToasts):\(\)=>(?<=let \i,{channel:(\i).+?)/g,
replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?null:` replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?null:`
}, },
{ {
// Disable gradients for the HiddenChannelLockScreen of stage channels // Disable gradients for the HiddenChannelLockScreen of stage channels
match: /"124px".+?disableGradients:(?<=(\i)\.getGuildId\(\).+?)/, match: /"124px".+?disableGradients:(?<=let \i,{channel:(\i).+?)/,
replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})||` replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})||`
}, },
{ {
// Disable strange styles applied to the header for the HiddenChannelLockScreen of stage channels // Disable strange styles applied to the header for the HiddenChannelLockScreen of stage channels
match: /"124px".+?style:(?<=(\i)\.getGuildId\(\).+?)/, match: /"124px".+?style:(?<=let \i,{channel:(\i).+?)/,
replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?void 0:` replace: (m, channel) => `${m}$self.isHiddenChannel(${channel})?void 0:`
}, }
]
},
{
find: ".Messages.STAGE_FULL_MODERATOR_TITLE",
replacement: [
{ {
// Remove the divider and amount of users in stage channel components for the HiddenChannelLockScreen // Remove the divider and amount of users in stage channel components for the HiddenChannelLockScreen
match: /\(0,\i\.jsx\)\(\i\.\i\.Divider.+?}\)]}\)(?=.+?:(\i)\.guild_id)/, match: /\(0,\i\.jsx\)\(\i\.\i\.Divider.+?}\)]}\)(?=.+?:(\i)\.guild_id)/,
@ -374,7 +387,7 @@ export default definePlugin({
match: /"recents".+?&&(?=\(.+?channelId:(\i)\.id,showRequestToSpeakSidebar)/, match: /"recents".+?&&(?=\(.+?channelId:(\i)\.id,showRequestToSpeakSidebar)/,
replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&` replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&`
} }
], ]
}, },
{ {
find: "\"^/guild-stages/(\\\\d+)(?:/)?(\\\\d+)?\"", find: "\"^/guild-stages/(\\\\d+)(?:/)?(\\\\d+)?\"",
@ -388,8 +401,8 @@ export default definePlugin({
find: ".shouldCloseDefaultModals", find: ".shouldCloseDefaultModals",
replacement: { replacement: {
// Show inside voice channel instead of trying to join them when clicking on a channel mention // Show inside voice channel instead of trying to join them when clicking on a channel mention
match: /(?<=getChannel\((\i)\)\)(?=.{0,100}?selectVoiceChannel))/, match: /(?<=getChannel\(\i\);if\(null!=(\i))(?=.{0,100}?selectVoiceChannel)/,
replace: (_, channelId) => `&&!$self.isHiddenChannel({channelId:${channelId}})` replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
} }
}, },
{ {
@ -397,13 +410,13 @@ export default definePlugin({
replacement: [ replacement: [
{ {
// Make GuildChannelStore contain hidden channels // Make GuildChannelStore contain hidden channels
match: /isChannelGated\(.+?\)(?=\|\|)/, match: /isChannelGated\(.+?\)(?=&&)/,
replace: m => `${m}||true` replace: m => `${m}&&false`
}, },
{ {
// Filter hidden channels from GuildChannelStore.getChannels unless told otherwise // Filter hidden channels from GuildChannelStore.getChannels unless told otherwise
match: /(?<=getChannels=function\(\i)\).+?(?=return (\i)})/, match: /(?<=getChannels\(\i)(\){.+?)return (.+?)}/,
replace: (rest, channels) => `,shouldIncludeHidden=false${rest}${channels}=$self.resolveGuildChannels(${channels},shouldIncludeHidden);` replace: (_, rest, channels) => `,shouldIncludeHidden=false${rest}return $self.resolveGuildChannels(${channels},shouldIncludeHidden);}`
} }
] ]
}, },
@ -418,22 +431,20 @@ export default definePlugin({
{ {
find: '.displayName="NowPlayingViewStore"', find: '.displayName="NowPlayingViewStore"',
replacement: { replacement: {
// Make active now voice states on hiddenl channels // Make active now voice states on hidden channels
match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/, match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/,
replace: "$1" replace: "$1"
} }
} }
], ],
setChannelBeginHeaderComponent,
isHiddenChannel(channel: Channel & { channelId?: string; }, checkConnect = false) { isHiddenChannel(channel: Channel & { channelId?: string; }, checkConnect = false) {
if (!channel) return false; if (!channel) return false;
if (channel.channelId) channel = ChannelStore.getChannel(channel.channelId); if (channel.channelId) channel = ChannelStore.getChannel(channel.channelId);
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false; if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false;
return !PermissionStore.can(VIEW_CHANNEL, channel) || checkConnect && !PermissionStore.can(CONNECT, channel); return !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || checkConnect && !PermissionStore.can(PermissionsBits.CONNECT, channel);
}, },
resolveGuildChannels(channels: Record<string | number, Array<{ channel: Channel; comparator: number; }> | string | number>, shouldIncludeHidden: boolean) { resolveGuildChannels(channels: Record<string | number, Array<{ channel: Channel; comparator: number; }> | string | number>, shouldIncludeHidden: boolean) {