Skip to content

Commit ae1fa34

Browse files
committed
First version of VC notifications
1 parent e4320a6 commit ae1fa34

File tree

13 files changed

+202
-22
lines changed

13 files changed

+202
-22
lines changed

package-lock.json

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"@typescript-eslint/parser": "^5.10.0",
1717
"cron-validator": "^1.3.1",
1818
"croner": "^4.1.95",
19-
"detritus-client": "^0.16.4-beta.6",
19+
"detritus-client": "^0.17.0-beta.1",
2020
"jimp": "^0.16.1",
2121
"mysql2": "^2.3.3",
2222
"reflect-metadata": "^0.1.13",

src/Modules/Bot.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { ClusterClient, InteractionCommandClient, ShardClient, Utils } from "detritus-client";
1+
import { ClusterClient, InteractionCommandClient } from "detritus-client";
2+
import { MessageComponentButtonStyles, MessageComponentTypes } from "detritus-client/lib/constants";
23

3-
import { Config, Signale, Webhooks } from "./";
4+
import { Config, Signale, Webhooks, VCNotifyManager } from "./";
45

56
export const InteractionBot = new InteractionCommandClient(Config.token, {
67
gateway: {
7-
intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_WEBHOOKS"],
8+
intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_WEBHOOKS", "GUILD_VOICE_STATES"],
89
},
910
});
1011

1112
// Events
13+
// Message Component Interactions are handled in InteractionHandling.ts
14+
1215
InteractionBot.client.on("guildMemberRemove", async (gmr) => {
1316
const client = (InteractionBot.client as ClusterClient).shards.first()!;
1417

@@ -31,6 +34,37 @@ InteractionBot.client.on("guildUpdate", (guildUpdate) => {
3134
}
3235
});
3336

37+
InteractionBot.client.on("voiceStateUpdate", (vsu) => {
38+
if (vsu.leftChannel || VCNotifyManager.watchers.length === 0) return;
39+
40+
let message = "";
41+
let j = 0;
42+
43+
for (var i = VCNotifyManager.watchers.length; i--; ) {
44+
const [key, value] = VCNotifyManager.watchers[i];
45+
46+
if (vsu.voiceState.userId === key) {
47+
j++;
48+
message += `<@${value}>`;
49+
VCNotifyManager.watchers.splice(i, 1);
50+
}
51+
}
52+
53+
if (j <= 2) {
54+
message += " - ";
55+
} else {
56+
message += "\n\n";
57+
}
58+
59+
message += `<@${vsu.voiceState.userId}> has joined <#${vsu.voiceState.channelId}>. (You will not be notified again.)`;
60+
61+
const client = (InteractionBot.client as ClusterClient).shards.first()!;
62+
Webhooks.execute(Webhooks.ids.voiceStateNotification, {
63+
avatarUrl: client.user!.avatarUrl,
64+
content: message,
65+
});
66+
});
67+
3468
// Helper Functions
3569

3670
/**

src/Modules/Commands/Basecommand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ enum EoRStatus {
1515
}
1616

1717
/**
18-
* Interaction.InteractionContext.editOrRespond(), but the response is forced to be ephemeral and edits strings into the normal form.
18+
* Interaction.InteractionContext.editOrRespond(), but the response is forced to be ephemeral and edits strings into the project-defined normal form. Strings will not be edited when status is 0 or when options is an object.
1919
* @param ctx
2020
* @param options
2121
* @param status What icon to add to the content
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Interaction } from "detritus-client";
2+
import { MessageComponentTypes, MessageComponentButtonStyles } from "detritus-client/lib/constants";
3+
4+
import { BaseContextMenuUserCommand, ContextMenuUserArgs } from "..";
5+
import { VCNotifyManager } from "../..";
6+
import { VCNotifyToggleButtonComponent } from "../../Components";
7+
8+
class VCNotifyContextCommand extends BaseContextMenuUserCommand {
9+
constructor() {
10+
super({
11+
name: "Toggle VC Notification",
12+
});
13+
}
14+
15+
async run(ctx: Interaction.InteractionContext, args: ContextMenuUserArgs) {
16+
const toggleString = VCNotifyManager.toggleMessage(args.user.id, ctx.userId);
17+
18+
this.ephEoR(
19+
ctx,
20+
{
21+
content: toggleString,
22+
components: [
23+
{
24+
type: MessageComponentTypes.ACTION_ROW,
25+
components: [
26+
/*{
27+
type: MessageComponentTypes.BUTTON,
28+
customId: `vcnotify:${args.user.id}`,
29+
emoji: { name: "🔔" },
30+
label: `Toggle VC Notification`,
31+
style: MessageComponentButtonStyles.PRIMARY,
32+
},*/
33+
34+
new VCNotifyToggleButtonComponent(args.user.id),
35+
],
36+
},
37+
],
38+
},
39+
0
40+
);
41+
}
42+
}
43+
44+
export default VCNotifyContextCommand;

src/Modules/Commands/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ import PingCommand from "./slash/Ping";
66
import PurgeCommand from "./slash/Purge";
77
import RoleGroupCommand from "./slash/RoleGroup";
88

9-
export default [new HelpCommand(), new HueGroupCommand(), new PingCommand(), new PurgeCommand(), new RoleGroupCommand()];
9+
import VCNotifyContextCommand from "./contextUser/VCNotify";
10+
11+
export default [new HelpCommand(), new HueGroupCommand(), new PingCommand(), new PurgeCommand(), new RoleGroupCommand(), new VCNotifyContextCommand()];
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { MessageComponentButtonStyles, MessageFlags } from "detritus-client/lib/constants";
2+
import { InteractionEditOrRespond } from "detritus-client/lib/structures";
3+
import { ComponentActionData, ComponentActionRow, ComponentButton, ComponentContext } from "detritus-client/lib/utils";
4+
5+
import { VCNotifyManager } from "..";
6+
7+
new ComponentActionRow({});
8+
9+
export class VCNotifyToggleButtonComponent extends ComponentButton {
10+
componentId: string;
11+
watchedId: string;
12+
13+
constructor(watchedId: string, data?: ComponentActionData) {
14+
super(data);
15+
16+
this.componentId = "vcnotify:";
17+
this.watchedId = watchedId;
18+
19+
this.customId = this.componentId + this.watchedId;
20+
this.emoji = { name: "🔔" };
21+
this.label = "Toggle VC Notification";
22+
this.style = MessageComponentButtonStyles.PRIMARY;
23+
}
24+
25+
run(ctx: ComponentContext) {
26+
const toggleString = VCNotifyManager.toggleMessage(this.watchedId, ctx.userId);
27+
28+
const message: InteractionEditOrRespond = {
29+
content: toggleString,
30+
flags: MessageFlags.EPHEMERAL,
31+
};
32+
33+
return ctx.editOrRespond(message);
34+
}
35+
}

src/Modules/Components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./VCNotifyToggleButton";

src/Modules/VCNotifyManager.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @key userId of the user to watch out for
3+
* @value userId of the user that should be notified
4+
*/
5+
class VCNotifyManagerClass {
6+
watchers: string[][];
7+
8+
constructor() {
9+
this.watchers = [];
10+
}
11+
12+
/**
13+
* Toggles whether or not the user of notifiedId should recieve a notification when watchedId join a VC
14+
*
15+
* @param watchedId userId of the person to watch out for
16+
* @param notifiedId userId of the user that should be notified
17+
* @return True if user gets notified, False if not
18+
*/
19+
toggle(watchedId: string, notifiedId: string): boolean {
20+
let vswIndex: number | undefined;
21+
22+
for (var i = this.watchers.length; i--; ) {
23+
const [key, value] = this.watchers[i];
24+
25+
if (key === watchedId && value === notifiedId) {
26+
vswIndex = i;
27+
}
28+
}
29+
30+
// If a user is already watching for this person, disable the notification
31+
if (typeof vswIndex !== "undefined") {
32+
this.watchers.splice(vswIndex, 1);
33+
34+
return false;
35+
} else {
36+
this.watchers.push([watchedId, notifiedId]);
37+
38+
return true;
39+
}
40+
}
41+
42+
/**
43+
* Calls VCNotifyManagerClass.toggle() and returns a string depending on the outcome
44+
*
45+
* @param watchedId userId of the person to watch out for
46+
* @param notifiedId userId of the user that should be notified
47+
* @return string
48+
*/
49+
toggleMessage(watchedId: string, notifiedId: string) {
50+
const toggle = VCNotifyManager.toggle(watchedId, notifiedId);
51+
52+
if (toggle) {
53+
return `🔔 **You will recieve a ping when <@${watchedId}> joins a voice channel.**`;
54+
} else {
55+
return `🔕 **You will no longer be notified when <@${watchedId}> joins a voice channel.**`;
56+
}
57+
}
58+
}
59+
60+
export const VCNotifyManager = new VCNotifyManagerClass();

src/Modules/Webhooks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface WebhookIds {
77
customRoles: string;
88
commandUse: string;
99
guildMemberRemove: string;
10+
voiceStateNotification: string;
1011
[key: string]: string;
1112
}
1213

@@ -19,6 +20,7 @@ class WebhooksClass {
1920
commandUse: Config.webhooks.commandUse,
2021
customRoles: Config.webhooks.customRoles,
2122
guildMemberRemove: Config.webhooks.guildMemberRemove,
23+
voiceStateNotification: Config.webhooks.voiceStateNotification,
2224
};
2325
}
2426

0 commit comments

Comments
 (0)