Compare commits

..

5 Commits

Author SHA1 Message Date
neru 8e8d5dc479 feat: set default voice if found 2026-01-14 21:51:20 -03:00
neru dfb58318af feat: check if mod can be used before listing it 2026-01-14 21:51:13 -03:00
neru 4abc2ff594 fix: make canBeUsed non async 2026-01-14 21:50:54 -03:00
neru 5877644ed9 feat: add default voices 2026-01-14 21:29:07 -03:00
neru 71da6e841d feat: add better checks before joining 2026-01-14 21:26:48 -03:00
7 changed files with 49 additions and 14 deletions
+8 -4
View File
@@ -30,6 +30,7 @@ const cmd: Command = {
const modeName = interaction.options.getString('mode', true); const modeName = interaction.options.getString('mode', true);
const selectedMode = TTSManager.get const selectedMode = TTSManager.get
.getModules() .getModules()
.filter(async (mod) => await mod.canBeUsed())
.find((mode) => mode.name === modeName); .find((mode) => mode.name === modeName);
if (!selectedMode) { if (!selectedMode) {
@@ -38,6 +39,8 @@ const cmd: Command = {
} }
await userData.set('tts_mode', modeName); await userData.set('tts_mode', modeName);
if (selectedMode.defaultVoice)
await userData.set('tts_voice', selectedMode.defaultVoice);
await userData.save(); await userData.save();
interaction.editReply(`TTS mode has been set to: ${modeName}.`); interaction.editReply(`TTS mode has been set to: ${modeName}.`);
@@ -50,12 +53,13 @@ const cmd: Command = {
const modes = TTSManager.get.getModules(); const modes = TTSManager.get.getModules();
const filtered: string[] = modes const filtered: string[] = modes
.filter((mode) => { .filter((mod) => mod.canBeUsed())
return mode.name .filter((mod) => {
? mode.name.toLowerCase().startsWith(focused.value.toLowerCase()) return mod.name
? mod.name.toLowerCase().startsWith(focused.value.toLowerCase())
: undefined; : undefined;
}) })
.map((mode) => mode.name) .map((mod) => mod.name)
.slice(0, 25); .slice(0, 25);
await interaction.respond( await interaction.respond(
+25 -1
View File
@@ -1,6 +1,7 @@
import { import {
ChatInputCommandInteraction, ChatInputCommandInteraction,
GuildMember, GuildMember,
PermissionsBitField,
SlashCommandBuilder SlashCommandBuilder
} from 'discord.js'; } from 'discord.js';
import { Command } from '../../commands'; import { Command } from '../../commands';
@@ -25,7 +26,7 @@ const cmd: Command = {
return; return;
} }
if (!member.voice.channelId) { if (!member.voice.channel || !member.voice.channelId) {
interaction.reply('You are not currently on a voice channel'); interaction.reply('You are not currently on a voice channel');
return; return;
} }
@@ -40,6 +41,29 @@ const cmd: Command = {
return; return;
} }
const voiceChannel = member.voice.channel;
if (voiceChannel.userLimit != 0 && voiceChannel.members.size >= voiceChannel.userLimit) {
interaction.reply('Channel is full');
return;
}
const perms = voiceChannel.permissionsFor(me)
if (!perms.has(PermissionsBitField.Flags.ViewChannel)) {
interaction.reply("I don't have permissions to see that channel")
return;
}
if (!perms.has(PermissionsBitField.Flags.Connect)) {
interaction.reply("I don't have the permissions to join that channel");
return;
}
if (!perms.has(PermissionsBitField.Flags.Speak)) {
interaction.reply("I don't have permissions to speak on that channel")
return;
}
const voiceOptions: JoinVoiceChannelOptions & CreateVoiceConnectionOptions = const voiceOptions: JoinVoiceChannelOptions & CreateVoiceConnectionOptions =
{ {
channelId: member.voice.channelId, channelId: member.voice.channelId,
+2 -1
View File
@@ -6,6 +6,7 @@ class AzureTTS implements TTSModule {
private voices: Array<string> | undefined = undefined; private voices: Array<string> | undefined = undefined;
public name: string = 'Azure'; public name: string = 'Azure';
public defaultVoice: string = 'en-US-AvaNeural';
async getVoices(): Promise<Array<string> | undefined> { async getVoices(): Promise<Array<string> | undefined> {
if (!this.voices) { if (!this.voices) {
@@ -33,7 +34,7 @@ class AzureTTS implements TTSModule {
return { data: Buffer.concat(buffers) }; return { data: Buffer.concat(buffers) };
} }
async canBeUsed(): Promise<boolean> { canBeUsed(): boolean {
return true; return true;
} }
} }
+3 -1
View File
@@ -9,6 +9,8 @@ const USER_AGENT =
const ttsGoogle: TTSModule = { const ttsGoogle: TTSModule = {
name: 'Google', name: 'Google',
defaultVoice: 'en',
async getVoices(): Promise<string[]> { return GOOGLE_TTS_VOICES.voices }, async getVoices(): Promise<string[]> { return GOOGLE_TTS_VOICES.voices },
async generate(voice: string, text: string): Promise<TTSResponse> { async generate(voice: string, text: string): Promise<TTSResponse> {
@@ -43,7 +45,7 @@ const ttsGoogle: TTSModule = {
}); });
}, },
async canBeUsed(): Promise<boolean> { canBeUsed(): boolean {
return true; return true;
} }
}; };
+3
View File
@@ -5,6 +5,9 @@ const ttsNone: TTSModule = {
getVoices: async (): Promise<Array<string>> => [], getVoices: async (): Promise<Array<string>> => [],
generate: async (): Promise<TTSResponse> => { generate: async (): Promise<TTSResponse> => {
return { data: Buffer.from([]) }; return { data: Buffer.from([]) };
},
canBeUsed: (): boolean => {
return true;
} }
}; };
+1 -1
View File
@@ -82,7 +82,7 @@ class PollyTTS implements TTSModule {
return {}; return {};
} }
async canBeUsed(): Promise<boolean> { canBeUsed(): boolean {
if (!config.aws_access_id || !config.aws_access_key) if (!config.aws_access_id || !config.aws_access_key)
return false; return false;
return true; return true;
+2 -1
View File
@@ -11,9 +11,10 @@ export interface TTSResponse {
export interface TTSModule { export interface TTSModule {
name: string; name: string;
defaultVoice?: string;
getVoices: () => Promise<Array<string> | undefined>; getVoices: () => Promise<Array<string> | undefined>;
generate: (voice: string, text: string) => Promise<TTSResponse>; generate: (voice: string, text: string) => Promise<TTSResponse>;
canBeUsed: () => Promise<boolean>; canBeUsed: () => boolean;
} }
export class TTSManager { export class TTSManager {