Skip to content

Commit

Permalink
Wakeup channel (#115)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
ebm5025 and Ed Morgan authored Jun 22, 2024
1 parent 8891b2a commit 0617557
Show file tree
Hide file tree
Showing 12 changed files with 10,193 additions and 199 deletions.
Binary file added media/daddychill.mp3
Binary file not shown.
9,640 changes: 9,640 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@discordjs/builders": "^0.12.0",
"@discordjs/rest": "^0.3.0",
"@discordjs/voice": "^0.17.0",
"@google-cloud/local-auth": "^2.1.0",
"@prisma/client": "^5.1.0",
"@types/moment-timezone": "^0.5.30",
Expand All @@ -31,20 +32,24 @@
"axios-retry": "^3.4.0",
"discord-api-types": "^0.31.1",
"discord.js": "^14",
"ffmpeg-static": "^5.2.0",
"google-spreadsheet": "^3.3.0",
"googleapis": "^105.0.0",
"jest": "^27.5.1",
"libsodium-wrappers": "^0.7.13",
"lodash": "^4.17.21",
"lru-cache": "^7.17.0",
"moment": "^2.29.2",
"moment-timezone": "^0.5.34",
"pg": "^8.7.3",
"prisma": "^5.2.0",
"redis": "^4.6.5",
"reflect-metadata": "^0.1.13",
"reflect-metadata": "^0.2.2",
"rimraf": "^3.0.2",
"tsyringe": "^4.8.0",
"typeorm": "^0.3.6",
"xlsx": "^0.18.5"
"xlsx": "^0.18.5",
"ytdl-core": "^4.11.5"
},
"devDependencies": {
"@types/google-spreadsheet": "^3.3.1",
Expand All @@ -66,4 +71,4 @@
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
}
}
}
4 changes: 3 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export const {
GOOGLE_KEY_FILE,
bankGoogleDriveFolderId,
modRoleId,
batphoneChannelId
batphoneChannelId,
wakeupChannelId,
} = process.env as {
/**
* [Optional] PostgreSQL DB connection URL. Defaults to gitpod development DB.
Expand Down Expand Up @@ -165,6 +166,7 @@ export const {
guardOfficeChannelId: string;
raidBotsChannelId: string;
batphoneChannelId: string;
wakeupChannelId: string;

// Google Ids
bankGoogleDriveFolderId: string;
Expand Down
164 changes: 100 additions & 64 deletions src/features/bp/bp-command.ts
Original file line number Diff line number Diff line change
@@ -1,145 +1,177 @@
import { ApplicationCommandOptionChoiceData, AutocompleteInteraction, CacheType, CommandInteraction } from "discord.js";
import {
ApplicationCommandOptionChoiceData,
AutocompleteInteraction,
CacheType,
CommandInteraction,
} from "discord.js";
import { Command } from "../../shared/command/command";
import { Subcommand } from "../../shared/command/subcommand";
import { getTextChannel } from "../..";
import { batphoneChannelId, raiderRoleId } from "../../config";
import { batphoneChannelId, raiderRoleId, wakeupChannelId } from "../../config";
import { authorizeByMemberRoles } from "../../shared/command/util";
import { officerRoleId, modRoleId, knightRoleId } from "../../config";
import { kStringMaxLength } from "buffer";
import { error } from "console";
import { redisClient } from "../../redis/client";
import { redis } from "googleapis/build/src/apis/redis";
import { isObject } from "lodash";
import { container } from "tsyringe";
import { WakeupService } from "../wakeup/wakeup.service";

class sendBp extends Subcommand {
public async execute(interaction: CommandInteraction<CacheType>) {

// authorize
authorizeByMemberRoles([
officerRoleId, modRoleId, knightRoleId
], interaction);
authorizeByMemberRoles(
[officerRoleId, modRoleId, knightRoleId],
interaction
);

const message = this.getOption("message", interaction)?.value;
const bpChannel = await getTextChannel(batphoneChannelId);
if (typeof(message)==="string") {

if (typeof message === "string") {
await bpChannel.send({
content: `[${interaction.user}] <@&${raiderRoleId}> ${message}`
})
interaction.editReply("Batphone posted: " + message)
content: `[${interaction.user}] <@&${raiderRoleId}> ${message}`,
});
interaction.editReply("Batphone posted: " + message);

// Wakeup
if (wakeupChannelId) {
const wakeupService = container.resolve(WakeupService);
wakeupService.runWakeup(
`Batphone. ${interaction.user} sent ${message}`
);
}
} else {
interaction.editReply("Failed to post batphone.");
}

}
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
public async getOptionAutocomplete(
option: string,
interaction: AutocompleteInteraction<CacheType>
): Promise<
ApplicationCommandOptionChoiceData<string | number>[] | undefined
> {
const res = await getBpOptions();
if (isObject(res)) {
const opts = Object.entries(res).map(
([key, value]) => ({ name: value, value: value })
);
if (isObject(res)) {
const opts = Object.entries(res).map(([key, value]) => ({
name: value,
value: value,
}));
return opts;
}
return [];
}

public get command() {
return super.command
.addStringOption((o) =>
o.setName("message")
.setDescription("BP Message")
.setRequired(true)
.setAutocomplete(true)
)
return super.command.addStringOption((o) =>
o
.setName("message")
.setDescription("BP Message")
.setRequired(true)
.setAutocomplete(true)
);
}
}

class setBp extends Subcommand {
public async execute(interaction: CommandInteraction<CacheType>) {

// authorize
authorizeByMemberRoles([
officerRoleId, modRoleId, knightRoleId
], interaction);
authorizeByMemberRoles(
[officerRoleId, modRoleId, knightRoleId],
interaction
);

const message = this.getOption("message", interaction)?.value;
try {
if (typeof(message)==="string") {
if (typeof message === "string") {
let key = this.getOption("key", interaction)?.value;
if(!key){
if (!key) {
key = message.split(" ")[0].toLowerCase();
}
await redisClient.hSet("bp", String(key), message);
interaction.editReply("Saved preset message: " + message)
interaction.editReply("Saved preset message: " + message);
} else {
throw error;
}
} catch(err) {
} catch (err) {
console.error(err);
interaction.editReply("Failed save batphone message.");
}

}
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
public async getOptionAutocomplete(
option: string,
interaction: AutocompleteInteraction<CacheType>
): Promise<
ApplicationCommandOptionChoiceData<string | number>[] | undefined
> {
return [];
}

public get command() {
return super.command
.addStringOption((o) =>
o.setName("message")
o
.setName("message")
.setDescription("BP Message")
.setRequired(true)
.setAutocomplete(false)
).addStringOption((o) =>
o.setName("key")
)
.addStringOption((o) =>
o
.setName("key")
.setDescription("Key (optional")
.setRequired(false)
.setAutocomplete(false)
)
);
}
}

class unsetBp extends Subcommand {
public async execute(interaction: CommandInteraction<CacheType>) {

// authorize
authorizeByMemberRoles([
officerRoleId, modRoleId, knightRoleId
], interaction);
authorizeByMemberRoles(
[officerRoleId, modRoleId, knightRoleId],
interaction
);

const key = this.getOption("message", interaction)?.value;
try {
if (typeof(key)==="string") {
if (typeof key === "string") {
await redisClient.hDel("bp", String(key));
interaction.editReply("Removed preset message: " + key)
interaction.editReply("Removed preset message: " + key);
} else {
throw error;
}
} catch(err) {
} catch (err) {
console.error(err);
interaction.editReply("Failed save batphone message.");
}
}
public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction<CacheType>): Promise<ApplicationCommandOptionChoiceData<string | number>[] | undefined> {
public async getOptionAutocomplete(
option: string,
interaction: AutocompleteInteraction<CacheType>
): Promise<
ApplicationCommandOptionChoiceData<string | number>[] | undefined
> {
const res = await getBpOptions();
if (isObject(res)) {
const opts = Object.entries(res).map(
([key, value]) => ({ name: value, value: key })
);
if (isObject(res)) {
const opts = Object.entries(res).map(([key, value]) => ({
name: value,
value: key,
}));
return opts;
}
return [];
}

public get command() {
return super.command
.addStringOption((o) =>
o.setName("message")
.setDescription("BP Message")
.setRequired(true)
.setAutocomplete(true)
)
return super.command.addStringOption((o) =>
o
.setName("message")
.setDescription("BP Message")
.setRequired(true)
.setAutocomplete(true)
);
}
}

Expand All @@ -151,10 +183,14 @@ const getBpOptions = async () => {
console.error(err);
return [];
}
}

export const batphoneCommand = new Command('bp', 'set and send batphone messages', [
new sendBp("send", "send batphone"),
new setBp("set", "save a BP preset"),
new unsetBp("unset", "remove BP preset")
])
};

export const batphoneCommand = new Command(
"bp",
"set and send batphone messages",
[
new sendBp("send", "send batphone"),
new setBp("set", "save a BP preset"),
new unsetBp("unset", "remove BP preset"),
]
);
62 changes: 62 additions & 0 deletions src/features/wakeup/setsong-subcommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
ApplicationCommandOptionChoiceData,
AutocompleteInteraction,
CacheType,
CommandInteraction,
} from "discord.js";
import { Subcommand } from "../../shared/command/subcommand";
import { IPublicAccountService } from "../../services/bot/public-accounts.i";
import { PublicAccountsFactory } from "../../services/bot/bot-factory";
import { authorizeByMemberRoles } from "../../shared/command/util";
import { officerRoleId, knightRoleId } from "../../config";
import { redisClient } from "../../redis/client";

export enum SetSongOption {
URL = "url",
}
export class SetSongSubcommand extends Subcommand {

constructor(name: string, description: string) {
super(name, description);
}

public async execute(interaction: CommandInteraction<CacheType>) {
const URL = this.getRequiredOptionValue(
SetSongOption.URL,
interaction
) as string;

try {
authorizeByMemberRoles([officerRoleId, knightRoleId], interaction);
redisClient.hSet("wakeup", "song", URL);
await interaction.editReply("Edited song to " + URL);
} catch (error) {
await interaction.editReply(`Failed to edit song: ${error}`);
}
}

public get command() {
const command = super.command.addStringOption((o) =>
o
.setName(SetSongOption.URL)
.setDescription("URL of the media to play for wake up")
.setAutocomplete(false)
.setRequired(true)
);
return command;
}

public getOptionAutocomplete(
option: string,
interaction: AutocompleteInteraction<CacheType>
): Promise<
ApplicationCommandOptionChoiceData<string | number>[] | undefined
> {
throw new Error("Method not implemented.");
}
}

export const setSongSubCommand = new SetSongSubcommand(
"setsong",
"Sets the wakeup song (be nice)"
);
8 changes: 8 additions & 0 deletions src/features/wakeup/wakeup-command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Command } from "../../shared/command/command";
import { setSongSubCommand } from "./setsong-subcommand";

export const wakeupCommand = new Command(
"wakeup",
"Retrieve information about bots.",
[setSongSubCommand]
);
4 changes: 4 additions & 0 deletions src/features/wakeup/wakeup.service.i.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export interface IWakeupService {
runWakeup(batphoneMessageId: string): void;
}
Loading

0 comments on commit 0617557

Please sign in to comment.