Plugin
WhosWatching
Lets you view what users are watching your stream by hovering over the screenshare icon
1
/*2
* FiveCord — a Discord client mod3
* Copyright (c) 2025 FiveCord4
* SPDX-License-Identifier: GPL-3.0-or-later5
*/6
7
import { classNameFactory } from "@api/Styles";8
import { Flex } from "@components/Flex";9
import { Devs } from "@utils/constants";10
import definePlugin from "@utils/types";11
import { findByPropsLazy, findStoreLazy } from "@webpack";12
import { Forms, i18n, React, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";13
14
interface WatchingProps {15
userIds: string[];16
guildId?: string;17
}18
19
const cl = classNameFactory("whosWatching-");20
21
function getUsername(user: any): string {22
return RelationshipStore.getNickname(user.id) || user.globalName || user.username;23
}24
25
function Watching({ userIds, guildId }: WatchingProps): React.ReactNode {26
// Missing Users happen when UserStore.getUser(id) returns null -- The client should automatically cache spectators, so this might not be possible but it's better to be sure just in case27
let missingUsers = 0;28
const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false));29
return (30
<div className={cl("content")}>31
{userIds.length ?32
(<>33
<Forms.FormTitle>{i18n.Messages.SPECTATORS.format({ numViewers: userIds.length })}</Forms.FormTitle>34
<Flex flexDirection="column" style={{ gap: 6 }} >35
{users.map(user => (36
<Flex key={user.id} flexDirection="row" style={{ gap: 6, alignContent: "center" }} className={cl("user")} >37
<img src={user.getAvatarURL(guildId)} style={{ borderRadius: 8, width: 16, height: 16 }} />38
{getUsername(user)}39
</Flex>40
))}41
{missingUsers > 0 && <span className={cl("more_users")}>{`+${i18n.Messages.NUM_USERS.format({ num: missingUsers })}`}</span>}42
</Flex>43
</>)44
: (<span className={cl("no_viewers")}>No spectators</span>)}45
</div>46
);47
}48
49
const ApplicationStreamingStore = findStoreLazy("ApplicationStreamingStore");50
const { encodeStreamKey }: {51
encodeStreamKey: (any) => string;52
} = findByPropsLazy("encodeStreamKey");53
54
export default definePlugin({55
name: "WhosWatching",56
description: "Lets you view what users are watching your stream by hovering over the screenshare icon",57
authors: [Devs.FiveCord],58
patches: [59
{60
find: ".Masks.STATUS_SCREENSHARE,width:32",61
replacement: {62
match: /default:function\(\)\{return ([a-zA-Z0-9_]{0,5})\}/,63
replace: "default:function(){return $self.component({OriginalComponent:$1})}"64
}65
}66
],67
component: function ({ OriginalComponent }) {68
return (props: any) => {69
const stream = useStateFromStores([ApplicationStreamingStore], () => ApplicationStreamingStore.getCurrentUserActiveStream());70
const viewers = ApplicationStreamingStore.getViewerIds(encodeStreamKey(stream));71
return <Tooltip text={<Watching userIds={viewers} guildId={stream.guildId} />}>72
{({ onMouseEnter, onMouseLeave }) => (73
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>74
<OriginalComponent {...props} />75
</div>76
)}77
</Tooltip>;78
};79
}80
});81