Files
dotflies/.config/BetterDiscord/plugins/BetterGuildTooltip.plugin.js
T
2026-05-17 11:29:41 +02:00

313 lines
8.7 KiB
JavaScript

/**
* @name BetterGuildTooltip
* @author arg0NNY
* @authorId 633223783204782090
* @invite M8DBtcZjXD
* @version 1.2.4
* @description Displays an online and total member count in the guild tooltip.
* @website https://github.com/arg0NNY/DiscordPlugins/tree/master/BetterGuildTooltip
* @source https://raw.githubusercontent.com/arg0NNY/DiscordPlugins/master/BetterGuildTooltip/BetterGuildTooltip.plugin.js
* @updateUrl https://raw.githubusercontent.com/arg0NNY/DiscordPlugins/master/BetterGuildTooltip/BetterGuildTooltip.plugin.js
* @runAt idle
*/
/* ### CONFIG START ### */
const config = {
info: {
name: 'BetterGuildTooltip',
version: '1.2.4',
description: 'Displays an online and total member count in the guild tooltip.'
},
changelog: [
{
type: 'fixed',
title: 'Fixes',
items: [
'Updated to work in the latest release of Discord.'
]
}
]
}
/* ### CONFIG END ### */
const {
Webpack,
UI,
Patcher,
React,
Utils,
Data
} = new BdApi(config.info.name)
const { Filters } = Webpack
const Dispatcher = Webpack.getModule(Filters.byKeys('dispatch', 'subscribe'), { searchExports: true })
const GuildMemberCountStore = Webpack.getStore('GuildMemberCountStore')
const GuildChannelStore = Webpack.getStore('GuildChannelStore')
const Flux = Webpack.getByKeys('Store', 'connectStores')
const ActionTypes = {
CONNECTION_OPEN: 'CONNECTION_OPEN',
GUILD_CREATE: 'GUILD_CREATE',
GUILD_DELETE: 'GUILD_DELETE',
GUILD_MEMBER_LIST_UPDATE: 'GUILD_MEMBER_LIST_UPDATE',
ONLINE_GUILD_MEMBER_COUNT_UPDATE: 'ONLINE_GUILD_MEMBER_COUNT_UPDATE'
}
const useStateFromStores = Webpack.getModule(Filters.byStrings('useStateFromStores'), { searchExports: true })
const Selectors = {
Guild: Webpack.getByKeys('statusOffline', 'guildDetail')
}
const GuildStore = Webpack.getStore('GuildStore')
const GuildActions = Webpack.getByKeys('preload', 'closePrivateChannel')
const GuildTooltip = [...Webpack.getWithKey(Filters.byStrings('guild', '__unsupportedReactNodeAsText'), { target: Webpack.getBySource('GuildTooltip', { raw: true })?.declarations })]
const memberCounts = new Map()
const onlineMemberCounts = new Map()
function handleConnectionOpen ({ guilds }) {
for (const guild of guilds) {
memberCounts.set(guild.id, guild.member_count)
}
}
function handleGuildCreate ({ guild }) {
memberCounts.set(guild.id, guild.member_count)
}
function handleGuildDelete ({ guild }) {
memberCounts.delete(guild.id)
onlineMemberCounts.delete(guild.id)
}
function handleGuildMemberListUpdate ({ guildId, memberCount, groups }) {
if (memberCount !== 0) {
memberCounts.set(guildId, memberCount)
}
onlineMemberCounts.set(
guildId,
groups.reduce((total, group) => {
return group.id !== 'offline' ? total + group.count : total
}, 0)
)
}
function handleOnlineGuildMemberCountUpdate ({ guildId, count }) {
onlineMemberCounts.set(guildId, count)
}
const MemberCountsStore = new class extends Flux.Store {
initialize () {
const nativeMemberCounts = GuildMemberCountStore.getMemberCounts()
for (const guildId in nativeMemberCounts) {
memberCounts.set(guildId, nativeMemberCounts[guildId])
}
};
getMemberCounts (guildId) {
return {
members: memberCounts.get(guildId),
membersOnline: onlineMemberCounts.get(guildId)
}
};
}(Dispatcher, {
[ActionTypes.CONNECTION_OPEN]: handleConnectionOpen,
[ActionTypes.GUILD_CREATE]: handleGuildCreate,
[ActionTypes.GUILD_DELETE]: handleGuildDelete,
[ActionTypes.GUILD_MEMBER_LIST_UPDATE]: handleGuildMemberListUpdate,
[ActionTypes.ONLINE_GUILD_MEMBER_COUNT_UPDATE]: handleOnlineGuildMemberCountUpdate
})
function formatNumber (number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ')
}
function GuildTooltipCounters (props) {
MemberCountsStore.initialize()
const { presenceCount, memberCount } = useStateFromStores([GuildStore], () =>
GuildStore.getGuild(props.guild.id) ?? {}
)
const { members, membersOnline } = useStateFromStores([MemberCountsStore], () =>
MemberCountsStore.getMemberCounts(props.guild.id)
)
const onlineDisplayed = props.settings.displayOnline && (membersOnline || presenceCount)
const totalDisplayed = props.settings.displayTotal && (memberCount || members)
return onlineDisplayed || totalDisplayed ? React.createElement(
'div',
{
className: Selectors.Guild.guildDetail,
style: props.isPopout ? {
fontWeight: '600'
} : {
marginTop: '5px',
marginBottom: '5px'
}
},
React.createElement(
'div',
{
className: Selectors.Guild.statusCounts,
style: {
columnGap: 0,
'-webkit-column-gap': 0
}
},
[
...(onlineDisplayed ? [React.createElement(
'i',
{
className: Selectors.Guild.statusOnline
}
),
React.createElement(
'span',
{
className: Selectors.Guild.count
},
formatNumber(membersOnline ?? presenceCount)
)] : []),
...(totalDisplayed ? [React.createElement(
'i',
{
className: Selectors.Guild.statusOffline
}
),
React.createElement(
'span',
{
className: Selectors.Guild.count
},
formatNumber(memberCount ?? members)
)] : [])
]
)
) : React.createElement('div')
}
const PRELOAD_DELAY = 200
module.exports = class BetterGuildTooltip {
start () {
this.patchGuildTooltip()
this.preloadInProccess = false
this.preloadNext = null
}
preloadGuild (guild) {
if (!guild || this.preloadInProccess) return this.preloadNext = guild
this._preloadGuild(guild)
this.preloadInProccess = true
setTimeout(() => {
this.preloadInProccess = false
this.preloadGuild(this.preloadNext)
this.preloadNext = null
}, PRELOAD_DELAY)
}
_preloadGuild (guild) {
GuildActions.preload(
guild.id,
GuildChannelStore.getDefaultChannel(guild.id).id
)
}
patchGuildTooltip () {
const callback = (index, props = {}) => (self, [{ guild }], value) => {
if (!this.settings.displayOnline && !this.settings.displayTotal) return
if (this.settings.displayOnline && !onlineMemberCounts.has(guild.id)) this.preloadGuild(guild)
value.props.children.splice(index, 0, React.createElement(GuildTooltipCounters, {
guild,
settings: this.settings,
...props
}))
}
Patcher.after(...GuildTooltip, (self, _, value) => {
const nodeRef = React.useRef()
if (!this.settings.displayOnline && !this.settings.displayTotal) return
const node = Utils.findInTree(
value,
m => Filters.byStrings('isViewingRoles')(m?.type),
{ walkable: ['props', 'children', '__unsupportedReactNodeAsText'] }
)
if (!node || nodeRef.current === node) return
Patcher.after(node, 'type', callback(1))
nodeRef.current = node
})
}
stop () {
Patcher.unpatchAll()
}
constructor () {
this.defaultSettings = {
displayOnline: true,
displayTotal: true
}
this.settings = this.loadSettings(this.defaultSettings)
this.showChangelogIfNeeded()
}
loadSettings (defaults = {}) {
return Utils.extend({}, defaults, Data.load('settings'))
}
saveSettings (settings = this.settings) {
return Data.save('settings', settings)
}
showChangelogIfNeeded () {
const currentVersionInfo = Utils.extend(
{ version: config.info.version, hasShownChangelog: false },
Data.load('currentVersionInfo')
)
if (currentVersionInfo.version === config.info.version && currentVersionInfo.hasShownChangelog) return
this.showChangelog()
Data.save('currentVersionInfo', { version: config.info.version, hasShownChangelog: true })
}
showChangelog () {
return UI.showChangelogModal({
title: config.info.name,
subtitle: 'Version ' + config.info.version,
changes: config.changelog
})
}
getSettingsPanel () {
return UI.buildSettingsPanel({
onChange: () => this.saveSettings(),
settings: [
{
type: 'switch',
id: 'displayOnline',
name: 'Display online count',
note: 'Displays an online member count in the guild tooltip.',
value: this.settings.displayOnline,
onChange: e => this.settings.displayOnline = e
},
{
type: 'switch',
id: 'displayTotal',
name: 'Display total count',
note: 'Displays a total member count in the guild tooltip.',
value: this.settings.displayTotal,
onChange: e => this.settings.displayTotal = e
}
]
})
}
}