Skip to content

Commit 0617557

Browse files
ebm5025Ed Morgan
andauthored
Wakeup channel (#115)
* Wakeup WIP * Wakeup WIP - still need TTS working * Wakeup fixes, mp3/yt support * Switching bp text back to real value --------- Co-authored-by: Ed Morgan <[email protected]>
1 parent 8891b2a commit 0617557

File tree

12 files changed

+10193
-199
lines changed

12 files changed

+10193
-199
lines changed

media/daddychill.mp3

1.83 MB
Binary file not shown.

package-lock.json

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

package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"dependencies": {
2323
"@discordjs/builders": "^0.12.0",
2424
"@discordjs/rest": "^0.3.0",
25+
"@discordjs/voice": "^0.17.0",
2526
"@google-cloud/local-auth": "^2.1.0",
2627
"@prisma/client": "^5.1.0",
2728
"@types/moment-timezone": "^0.5.30",
@@ -31,20 +32,24 @@
3132
"axios-retry": "^3.4.0",
3233
"discord-api-types": "^0.31.1",
3334
"discord.js": "^14",
35+
"ffmpeg-static": "^5.2.0",
3436
"google-spreadsheet": "^3.3.0",
3537
"googleapis": "^105.0.0",
3638
"jest": "^27.5.1",
39+
"libsodium-wrappers": "^0.7.13",
3740
"lodash": "^4.17.21",
3841
"lru-cache": "^7.17.0",
3942
"moment": "^2.29.2",
4043
"moment-timezone": "^0.5.34",
4144
"pg": "^8.7.3",
4245
"prisma": "^5.2.0",
4346
"redis": "^4.6.5",
44-
"reflect-metadata": "^0.1.13",
47+
"reflect-metadata": "^0.2.2",
4548
"rimraf": "^3.0.2",
49+
"tsyringe": "^4.8.0",
4650
"typeorm": "^0.3.6",
47-
"xlsx": "^0.18.5"
51+
"xlsx": "^0.18.5",
52+
"ytdl-core": "^4.11.5"
4853
},
4954
"devDependencies": {
5055
"@types/google-spreadsheet": "^3.3.1",
@@ -66,4 +71,4 @@
6671
"ts-node": "^10.7.0",
6772
"typescript": "^4.6.3"
6873
}
69-
}
74+
}

src/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export const {
5757
GOOGLE_KEY_FILE,
5858
bankGoogleDriveFolderId,
5959
modRoleId,
60-
batphoneChannelId
60+
batphoneChannelId,
61+
wakeupChannelId,
6162
} = process.env as {
6263
/**
6364
* [Optional] PostgreSQL DB connection URL. Defaults to gitpod development DB.
@@ -165,6 +166,7 @@ export const {
165166
guardOfficeChannelId: string;
166167
raidBotsChannelId: string;
167168
batphoneChannelId: string;
169+
wakeupChannelId: string;
168170

169171
// Google Ids
170172
bankGoogleDriveFolderId: string;

src/features/bp/bp-command.ts

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,177 @@
1-
import { ApplicationCommandOptionChoiceData, AutocompleteInteraction, CacheType, CommandInteraction } from "discord.js";
1+
import {
2+
ApplicationCommandOptionChoiceData,
3+
AutocompleteInteraction,
4+
CacheType,
5+
CommandInteraction,
6+
} from "discord.js";
27
import { Command } from "../../shared/command/command";
38
import { Subcommand } from "../../shared/command/subcommand";
49
import { getTextChannel } from "../..";
5-
import { batphoneChannelId, raiderRoleId } from "../../config";
10+
import { batphoneChannelId, raiderRoleId, wakeupChannelId } from "../../config";
611
import { authorizeByMemberRoles } from "../../shared/command/util";
712
import { officerRoleId, modRoleId, knightRoleId } from "../../config";
813
import { kStringMaxLength } from "buffer";
914
import { error } from "console";
1015
import { redisClient } from "../../redis/client";
1116
import { redis } from "googleapis/build/src/apis/redis";
1217
import { isObject } from "lodash";
18+
import { container } from "tsyringe";
19+
import { WakeupService } from "../wakeup/wakeup.service";
1320

1421
class sendBp extends Subcommand {
1522
public async execute(interaction: CommandInteraction<CacheType>) {
16-
1723
// authorize
18-
authorizeByMemberRoles([
19-
officerRoleId, modRoleId, knightRoleId
20-
], interaction);
24+
authorizeByMemberRoles(
25+
[officerRoleId, modRoleId, knightRoleId],
26+
interaction
27+
);
2128

2229
const message = this.getOption("message", interaction)?.value;
2330
const bpChannel = await getTextChannel(batphoneChannelId);
24-
if (typeof(message)==="string") {
25-
31+
if (typeof message === "string") {
2632
await bpChannel.send({
27-
content: `[${interaction.user}] <@&${raiderRoleId}> ${message}`
28-
})
29-
interaction.editReply("Batphone posted: " + message)
33+
content: `[${interaction.user}] <@&${raiderRoleId}> ${message}`,
34+
});
35+
interaction.editReply("Batphone posted: " + message);
36+
37+
// Wakeup
38+
if (wakeupChannelId) {
39+
const wakeupService = container.resolve(WakeupService);
40+
wakeupService.runWakeup(
41+
`Batphone. ${interaction.user} sent ${message}`
42+
);
43+
}
3044
} else {
3145
interaction.editReply("Failed to post batphone.");
3246
}
33-
3447
}
35-
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
48+
public async getOptionAutocomplete(
49+
option: string,
50+
interaction: AutocompleteInteraction<CacheType>
51+
): Promise<
52+
ApplicationCommandOptionChoiceData<string | number>[] | undefined
53+
> {
3654
const res = await getBpOptions();
37-
if (isObject(res)) {
38-
const opts = Object.entries(res).map(
39-
([key, value]) => ({ name: value, value: value })
40-
);
55+
if (isObject(res)) {
56+
const opts = Object.entries(res).map(([key, value]) => ({
57+
name: value,
58+
value: value,
59+
}));
4160
return opts;
4261
}
4362
return [];
4463
}
4564

4665
public get command() {
47-
return super.command
48-
.addStringOption((o) =>
49-
o.setName("message")
50-
.setDescription("BP Message")
51-
.setRequired(true)
52-
.setAutocomplete(true)
53-
)
66+
return super.command.addStringOption((o) =>
67+
o
68+
.setName("message")
69+
.setDescription("BP Message")
70+
.setRequired(true)
71+
.setAutocomplete(true)
72+
);
5473
}
5574
}
5675

5776
class setBp extends Subcommand {
5877
public async execute(interaction: CommandInteraction<CacheType>) {
59-
6078
// authorize
61-
authorizeByMemberRoles([
62-
officerRoleId, modRoleId, knightRoleId
63-
], interaction);
79+
authorizeByMemberRoles(
80+
[officerRoleId, modRoleId, knightRoleId],
81+
interaction
82+
);
6483

6584
const message = this.getOption("message", interaction)?.value;
6685
try {
67-
if (typeof(message)==="string") {
86+
if (typeof message === "string") {
6887
let key = this.getOption("key", interaction)?.value;
69-
if(!key){
88+
if (!key) {
7089
key = message.split(" ")[0].toLowerCase();
7190
}
7291
await redisClient.hSet("bp", String(key), message);
73-
interaction.editReply("Saved preset message: " + message)
92+
interaction.editReply("Saved preset message: " + message);
7493
} else {
7594
throw error;
7695
}
77-
} catch(err) {
96+
} catch (err) {
7897
console.error(err);
7998
interaction.editReply("Failed save batphone message.");
8099
}
81-
82100
}
83-
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
101+
public async getOptionAutocomplete(
102+
option: string,
103+
interaction: AutocompleteInteraction<CacheType>
104+
): Promise<
105+
ApplicationCommandOptionChoiceData<string | number>[] | undefined
106+
> {
84107
return [];
85108
}
86109

87110
public get command() {
88111
return super.command
89112
.addStringOption((o) =>
90-
o.setName("message")
113+
o
114+
.setName("message")
91115
.setDescription("BP Message")
92116
.setRequired(true)
93117
.setAutocomplete(false)
94-
).addStringOption((o) =>
95-
o.setName("key")
118+
)
119+
.addStringOption((o) =>
120+
o
121+
.setName("key")
96122
.setDescription("Key (optional")
97123
.setRequired(false)
98124
.setAutocomplete(false)
99-
)
125+
);
100126
}
101127
}
102128

103129
class unsetBp extends Subcommand {
104130
public async execute(interaction: CommandInteraction<CacheType>) {
105-
106131
// authorize
107-
authorizeByMemberRoles([
108-
officerRoleId, modRoleId, knightRoleId
109-
], interaction);
132+
authorizeByMemberRoles(
133+
[officerRoleId, modRoleId, knightRoleId],
134+
interaction
135+
);
110136

111137
const key = this.getOption("message", interaction)?.value;
112138
try {
113-
if (typeof(key)==="string") {
139+
if (typeof key === "string") {
114140
await redisClient.hDel("bp", String(key));
115-
interaction.editReply("Removed preset message: " + key)
141+
interaction.editReply("Removed preset message: " + key);
116142
} else {
117143
throw error;
118144
}
119-
} catch(err) {
145+
} catch (err) {
120146
console.error(err);
121147
interaction.editReply("Failed save batphone message.");
122148
}
123149
}
124-
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
150+
public async getOptionAutocomplete(
151+
option: string,
152+
interaction: AutocompleteInteraction<CacheType>
153+
): Promise<
154+
ApplicationCommandOptionChoiceData<string | number>[] | undefined
155+
> {
125156
const res = await getBpOptions();
126-
if (isObject(res)) {
127-
const opts = Object.entries(res).map(
128-
([key, value]) => ({ name: value, value: key })
129-
);
157+
if (isObject(res)) {
158+
const opts = Object.entries(res).map(([key, value]) => ({
159+
name: value,
160+
value: key,
161+
}));
130162
return opts;
131163
}
132164
return [];
133165
}
134166

135167
public get command() {
136-
return super.command
137-
.addStringOption((o) =>
138-
o.setName("message")
139-
.setDescription("BP Message")
140-
.setRequired(true)
141-
.setAutocomplete(true)
142-
)
168+
return super.command.addStringOption((o) =>
169+
o
170+
.setName("message")
171+
.setDescription("BP Message")
172+
.setRequired(true)
173+
.setAutocomplete(true)
174+
);
143175
}
144176
}
145177

@@ -151,10 +183,14 @@ const getBpOptions = async () => {
151183
console.error(err);
152184
return [];
153185
}
154-
}
155-
156-
export const batphoneCommand = new Command('bp', 'set and send batphone messages', [
157-
new sendBp("send", "send batphone"),
158-
new setBp("set", "save a BP preset"),
159-
new unsetBp("unset", "remove BP preset")
160-
])
186+
};
187+
188+
export const batphoneCommand = new Command(
189+
"bp",
190+
"set and send batphone messages",
191+
[
192+
new sendBp("send", "send batphone"),
193+
new setBp("set", "save a BP preset"),
194+
new unsetBp("unset", "remove BP preset"),
195+
]
196+
);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
ApplicationCommandOptionChoiceData,
3+
AutocompleteInteraction,
4+
CacheType,
5+
CommandInteraction,
6+
} from "discord.js";
7+
import { Subcommand } from "../../shared/command/subcommand";
8+
import { IPublicAccountService } from "../../services/bot/public-accounts.i";
9+
import { PublicAccountsFactory } from "../../services/bot/bot-factory";
10+
import { authorizeByMemberRoles } from "../../shared/command/util";
11+
import { officerRoleId, knightRoleId } from "../../config";
12+
import { redisClient } from "../../redis/client";
13+
14+
export enum SetSongOption {
15+
URL = "url",
16+
}
17+
export class SetSongSubcommand extends Subcommand {
18+
19+
constructor(name: string, description: string) {
20+
super(name, description);
21+
}
22+
23+
public async execute(interaction: CommandInteraction<CacheType>) {
24+
const URL = this.getRequiredOptionValue(
25+
SetSongOption.URL,
26+
interaction
27+
) as string;
28+
29+
try {
30+
authorizeByMemberRoles([officerRoleId, knightRoleId], interaction);
31+
redisClient.hSet("wakeup", "song", URL);
32+
await interaction.editReply("Edited song to " + URL);
33+
} catch (error) {
34+
await interaction.editReply(`Failed to edit song: ${error}`);
35+
}
36+
}
37+
38+
public get command() {
39+
const command = super.command.addStringOption((o) =>
40+
o
41+
.setName(SetSongOption.URL)
42+
.setDescription("URL of the media to play for wake up")
43+
.setAutocomplete(false)
44+
.setRequired(true)
45+
);
46+
return command;
47+
}
48+
49+
public getOptionAutocomplete(
50+
option: string,
51+
interaction: AutocompleteInteraction<CacheType>
52+
): Promise<
53+
ApplicationCommandOptionChoiceData<string | number>[] | undefined
54+
> {
55+
throw new Error("Method not implemented.");
56+
}
57+
}
58+
59+
export const setSongSubCommand = new SetSongSubcommand(
60+
"setsong",
61+
"Sets the wakeup song (be nice)"
62+
);

src/features/wakeup/wakeup-command.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Command } from "../../shared/command/command";
2+
import { setSongSubCommand } from "./setsong-subcommand";
3+
4+
export const wakeupCommand = new Command(
5+
"wakeup",
6+
"Retrieve information about bots.",
7+
[setSongSubCommand]
8+
);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
export interface IWakeupService {
3+
runWakeup(batphoneMessageId: string): void;
4+
}

0 commit comments

Comments
 (0)