fix: voice bug

This commit is contained in:
2023-04-23 13:36:43 +02:00
parent bb164f509e
commit 46c396834d
24 changed files with 3168 additions and 1468 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,3 @@
/node_modules
/dist
/node_modules
/dist
.env

View File

@@ -1,5 +1,5 @@
{
"useTabs": true,
"singleQuote": true,
"tabWidth": 4
{
"useTabs": true,
"singleQuote": true,
"tabWidth": 4
}

View File

@@ -1,3 +1,3 @@
{
"dotenv.enableAutocloaking": true
{
"dotenv.enableAutocloaking": true
}

View File

@@ -1,17 +1,17 @@
FROM node:latest
WORKDIR /app
COPY package.json ./
RUN npm install
RUN apt update && apt install ffmpeg -y
COPY . .
RUN npm run generateprisma
RUN npm run build
FROM node:latest
WORKDIR /app
COPY package.json ./
RUN npm install
RUN apt update && apt install ffmpeg -y
COPY . .
RUN npm run generateprisma
RUN npm run build
CMD node dist/index.js

1348
LICENSE

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,2 @@
# ava
A discord bot that plays KNGI and Gensokyo Radio.
# ava
A discord bot that plays KNGI and Gensokyo Radio.

View File

@@ -1,145 +1,145 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { ActionRowBuilder, ComponentType, EmbedBuilder, StringSelectMenuBuilder } from 'discord.js';
import axios from 'axios';
import progressbar from 'string-progressbar'
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Check what\'s playing on both radios',
options: [],
execute: async (ctx, options) => {
const nowplayingkngi = await axios.get('https://network.kngi.org/api/nowplaying').then(res => res.data[0])
const nowplayingensokyo = await axios.get('https://gensokyoradio.net/api/station/playing/').then(res => res.data)
const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
.setComponents(
new StringSelectMenuBuilder()
.setCustomId('nowplaying-selectmenu')
.setMinValues(1)
.setMaxValues(1)
.addOptions(
{
label: 'KNGI',
value: 'kngi',
},
{
label: 'Gensokyo Radio',
value: 'gensokyo'
},
)
.setPlaceholder('Select the radio')
);
const kngiembed = new EmbedBuilder()
.setAuthor({
iconURL: 'https://kngi.org/public_html/wp-content/uploads/NGI2015AlbumArt-200.png',
name: 'KNGI'
})
.setColor('Random')
.setTitle('Now playing on KNGI Radio')
.setThumbnail(nowplayingkngi.now_playing.song.art)
.setFields(
{
name: 'Name',
value: nowplayingkngi.now_playing.song.text,
inline: true
},
{
name: 'Artist',
value: nowplayingkngi.now_playing.song.artist,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Playing next: Name',
value: nowplayingkngi.playing_next.song.text,
inline: true
},
{
name: 'Playing next: Artist',
value: nowplayingkngi.playing_next.song.artist,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Progressbar',
value: (progressbar.splitBar(nowplayingkngi.now_playing.duration, nowplayingkngi.now_playing.elapsed, 20))[0],
inline: true
},
)
.setFooter({text: `Total listeners: ${nowplayingkngi.station.mounts[0].listeners.total}`})
const gensokyoembed = new EmbedBuilder()
.setAuthor({
iconURL: 'https://raw.githubusercontent.com/SrIzan10/ava/main/util/logos/gensokyoradio.png',
name: 'Gensokyo Radio'
})
.setColor('Random')
.setTitle('Now playing on Gensokyo Radio')
.setThumbnail(`https://gensokyoradio.net/images/albums/500/${nowplayingensokyo.MISC.ALBUMART}`)
.setFields(
{
name: 'Name',
value: nowplayingensokyo.SONGINFO.TITLE,
inline: true
},
{
name: 'Artist',
value: nowplayingensokyo.SONGINFO.ARTIST,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Rating',
value: nowplayingensokyo.SONGDATA.RATING,
inline: true
},
{
name: 'Times rated',
value: String(nowplayingensokyo.SONGDATA.TIMESRATED),
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Progressbar',
value: (progressbar.splitBar(nowplayingensokyo.SONGTIMES.DURATION, nowplayingensokyo.SONGTIMES.PLAYED, 20))[0]
}
)
.setFooter({text: `Total listeners: ${nowplayingensokyo.SERVERINFO.LISTENERS}`})
const msg = await ctx.reply({embeds: [kngiembed], components: [selectMenu]})
const collector = msg.createMessageComponentCollector({time: 30_000, componentType: ComponentType.StringSelect})
collector.on('collect', async (i) => {
if (i.customId === 'nowplaying-selectmenu') {
const selected = i.values[0]
if (selected === 'kngi') {
// KNGI
await ctx.interaction.editReply({embeds: [kngiembed], components: [selectMenu]})
await i.deferUpdate()
} else if (selected === 'gensokyo') {
// Gensokyo
await ctx.interaction.editReply({embeds: [gensokyoembed], components: [selectMenu]})
await i.deferUpdate()
}
}
})
},
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { ActionRowBuilder, ComponentType, EmbedBuilder, StringSelectMenuBuilder } from 'discord.js';
import axios from 'axios';
import progressbar from 'string-progressbar'
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Check what\'s playing on both radios',
options: [],
execute: async (ctx, options) => {
const nowplayingkngi = await axios.get('https://network.kngi.org/api/nowplaying').then(res => res.data[0])
const nowplayingensokyo = await axios.get('https://gensokyoradio.net/api/station/playing/').then(res => res.data)
const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
.setComponents(
new StringSelectMenuBuilder()
.setCustomId('nowplaying-selectmenu')
.setMinValues(1)
.setMaxValues(1)
.addOptions(
{
label: 'KNGI',
value: 'kngi',
},
{
label: 'Gensokyo Radio',
value: 'gensokyo'
},
)
.setPlaceholder('Select the radio')
);
const kngiembed = new EmbedBuilder()
.setAuthor({
iconURL: 'https://kngi.org/public_html/wp-content/uploads/NGI2015AlbumArt-200.png',
name: 'KNGI'
})
.setColor('Random')
.setTitle('Now playing on KNGI Radio')
.setThumbnail(nowplayingkngi.now_playing.song.art)
.setFields(
{
name: 'Name',
value: nowplayingkngi.now_playing.song.text,
inline: true
},
{
name: 'Artist',
value: nowplayingkngi.now_playing.song.artist,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Playing next: Name',
value: nowplayingkngi.playing_next.song.text,
inline: true
},
{
name: 'Playing next: Artist',
value: nowplayingkngi.playing_next.song.artist,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Progressbar',
value: (progressbar.splitBar(nowplayingkngi.now_playing.duration, nowplayingkngi.now_playing.elapsed, 20))[0],
inline: true
},
)
.setFooter({text: `Total listeners: ${nowplayingkngi.station.mounts[0].listeners.total}`})
const gensokyoembed = new EmbedBuilder()
.setAuthor({
iconURL: 'https://raw.githubusercontent.com/SrIzan10/ava/main/util/logos/gensokyoradio.png',
name: 'Gensokyo Radio'
})
.setColor('Random')
.setTitle('Now playing on Gensokyo Radio')
.setThumbnail(`https://gensokyoradio.net/images/albums/500/${nowplayingensokyo.MISC.ALBUMART}`)
.setFields(
{
name: 'Name',
value: nowplayingensokyo.SONGINFO.TITLE,
inline: true
},
{
name: 'Artist',
value: nowplayingensokyo.SONGINFO.ARTIST,
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Rating',
value: nowplayingensokyo.SONGDATA.RATING,
inline: true
},
{
name: 'Times rated',
value: String(nowplayingensokyo.SONGDATA.TIMESRATED),
inline: true
},
{
name: '\u200B',
value: '\u200B',
inline: true
},
{
name: 'Progressbar',
value: (progressbar.splitBar(nowplayingensokyo.SONGTIMES.DURATION, nowplayingensokyo.SONGTIMES.PLAYED, 20))[0]
}
)
.setFooter({text: `Total listeners: ${nowplayingensokyo.SERVERINFO.LISTENERS}`})
const msg = await ctx.reply({embeds: [kngiembed], components: [selectMenu]})
const collector = msg.createMessageComponentCollector({time: 30_000, componentType: ComponentType.StringSelect})
collector.on('collect', async (i) => {
if (i.customId === 'nowplaying-selectmenu') {
const selected = i.values[0]
if (selected === 'kngi') {
// KNGI
await ctx.interaction.editReply({embeds: [kngiembed], components: [selectMenu]})
await i.deferUpdate()
} else if (selected === 'gensokyo') {
// Gensokyo
await ctx.interaction.editReply({embeds: [gensokyoembed], components: [selectMenu]})
await i.deferUpdate()
}
}
})
},
});

View File

@@ -1,124 +1,124 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import {
createAudioPlayer,
createAudioResource,
joinVoiceChannel,
} from '@discordjs/voice';
import {
ApplicationCommandOptionType,
EmbedBuilder,
GuildMember,
} from 'discord.js';
import got from 'got';
import { radioResolver } from '../util/radioResolver.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Play the radio you want',
options: [
{
name: 'radio',
description: 'The radio you want to play.',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (ctx) => {
const focusedValue = ctx.options.getFocused();
const choices = ['KNGI', 'Gensokyo Radio'];
const filtered = choices.filter((choice) =>
choice.startsWith(focusedValue)
);
await ctx.respond(
filtered.map((choice) => ({
name: choice,
value: choice,
}))
);
},
},
},
],
execute: async (ctx, options) => {
const radioname = options[1].getString('radio', true);
const fetchUser = (await (
await ctx.client.guilds.fetch(ctx.guild!.id)
).members.fetch(ctx.user.id)) as GuildMember;
if (!fetchUser.voice.channel?.id)
return await ctx.reply({
content: 'You are not in a VC!',
ephemeral: true,
});
if (!fetchUser.voice.channel!.joinable)
return await ctx.reply({
content: "I can't join that VC!",
ephemeral: true,
});
const embed = new EmbedBuilder()
.setAuthor({
name: ctx.user.username,
iconURL: ctx.user.displayAvatarURL(),
})
.setColor('Green')
.setTitle(
`Started playing ${radioname} in ${fetchUser.voice.channel?.name}`
)
.setDescription(
`Go ahead and join <#${fetchUser.voice.channelId}> to listen ${radioname}!`
);
const embedNotFound = new EmbedBuilder()
.setAuthor({
name: ctx.user.username,
iconURL: ctx.user.displayAvatarURL(),
})
.setColor('Red')
.setTitle(`Radio not found.`)
.setDescription(
`Make sure you select the radio from the autocomplete!`
);
switch (radioname) {
case 'KNGI':
{
const stream = got.stream(radioResolver(radioname));
const connection = joinVoiceChannel({
adapterCreator:
ctx.interaction.guild!.voiceAdapterCreator,
guildId: ctx.guild!.id,
channelId: fetchUser.voice.channelId!,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
await ctx.reply({ embeds: [embed] });
}
break;
case 'Gensokyo Radio':
{
const stream = got.stream(radioResolver(radioname));
const connection = joinVoiceChannel({
adapterCreator:
ctx.interaction.guild!.voiceAdapterCreator,
guildId: ctx.guild!.id,
channelId: fetchUser.voice.channelId!,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
await ctx.reply({ embeds: [embed] });
}
break;
default:
{
await ctx.reply({ embeds: [embedNotFound] });
}
break;
}
},
});
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import {
createAudioPlayer,
createAudioResource,
joinVoiceChannel,
} from '@discordjs/voice';
import {
ApplicationCommandOptionType,
EmbedBuilder,
GuildMember,
} from 'discord.js';
import got from 'got';
import { radioResolver } from '../util/radioResolver.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Play the radio you want',
options: [
{
name: 'radio',
description: 'The radio you want to play.',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (ctx) => {
const focusedValue = ctx.options.getFocused();
const choices = ['KNGI', 'Gensokyo Radio'];
const filtered = choices.filter((choice) =>
choice.startsWith(focusedValue)
);
await ctx.respond(
filtered.map((choice) => ({
name: choice,
value: choice,
}))
);
},
},
},
],
execute: async (ctx, options) => {
const radioname = options[1].getString('radio', true);
const fetchUser = (await (
await ctx.client.guilds.fetch(ctx.guild!.id)
).members.fetch(ctx.user.id)) as GuildMember;
if (!fetchUser.voice.channel?.id)
return await ctx.reply({
content: 'You are not in a VC!',
ephemeral: true,
});
if (!fetchUser.voice.channel!.joinable)
return await ctx.reply({
content: "I can't join that VC!",
ephemeral: true,
});
const embed = new EmbedBuilder()
.setAuthor({
name: ctx.user.username,
iconURL: ctx.user.displayAvatarURL(),
})
.setColor('Green')
.setTitle(
`Started playing ${radioname} in ${fetchUser.voice.channel?.name}`
)
.setDescription(
`Go ahead and join <#${fetchUser.voice.channelId}> to listen ${radioname}!`
);
const embedNotFound = new EmbedBuilder()
.setAuthor({
name: ctx.user.username,
iconURL: ctx.user.displayAvatarURL(),
})
.setColor('Red')
.setTitle(`Radio not found.`)
.setDescription(
`Make sure you select the radio from the autocomplete!`
);
switch (radioname) {
case 'KNGI':
{
const stream = got.stream(radioResolver(radioname));
const connection = joinVoiceChannel({
adapterCreator:
ctx.interaction.guild!.voiceAdapterCreator,
guildId: ctx.guild!.id,
channelId: fetchUser.voice.channelId!,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
await ctx.reply({ embeds: [embed] });
}
break;
case 'Gensokyo Radio':
{
const stream = got.stream(radioResolver(radioname));
const connection = joinVoiceChannel({
adapterCreator:
ctx.interaction.guild!.voiceAdapterCreator,
guildId: ctx.guild!.id,
channelId: fetchUser.voice.channelId!,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
await ctx.reply({ embeds: [embed] });
}
break;
default:
{
await ctx.reply({ embeds: [embedNotFound] });
}
break;
}
},
});

View File

@@ -1,82 +1,82 @@
import { commandModule, CommandType } from '@sern/handler';
import { ApplicationCommandOptionType, GuildMember } from 'discord.js';
import { prisma } from '../index.js';
import { publish } from '../plugins/publish.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish({defaultMemberPermissions: 'ManageGuild'})],
description: 'Stick to a VC',
options: [
{
name: 'radio',
description: 'The radio you want to play.',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (ctx) => {
const focusedValue = ctx.options.getFocused();
const choices = ['KNGI', 'Gensokyo Radio'];
const filtered = choices.filter((choice) =>
choice.startsWith(focusedValue)
);
await ctx.respond(
filtered.map((choice) => ({ name: choice, value: choice }))
);
},
},
},
],
execute: async (ctx, options) => {
const radioname = options[1].getString('radio', true);
const fetchUser = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.user.id) as GuildMember
async function createDoc(radio: string) {
return await prisma.stick.create({
data: {
channelid: fetchUser.voice.channel?.id!,
guildid: ctx.guild!.id,
radio: radio
}
})
}
if (!fetchUser.voice.channel?.id)
return await ctx.reply({
content: 'You are not in a VC!',
ephemeral: true
})
if (!fetchUser.voice.channel!.joinable)
return await ctx.reply({
content: 'I can\'t join that VC!',
ephemeral: true
})
const countDocs = await prisma.stick.count({
where: {
guildid: ctx.guild!.id
}
})
if (countDocs !== 0)
return await ctx.reply({
content: 'There\'s more than one entry in the database!\nIf you want to remove that stick, first run the `/unstick` command!',
ephemeral: true
})
switch (radioname) {
case 'KNGI': {
await createDoc(radioname)
await ctx.reply({content: `${radioname} is going to be sticked from now on!`})
} break;
case 'Gensokyo Radio': {
await createDoc(radioname)
await ctx.reply({content: `${radioname} is going to be sticked from now on!`})
} break;
default: {
await ctx.reply({content: `Couldn't find that radio!`, ephemeral: true})
} break;
}
},
import { commandModule, CommandType } from '@sern/handler';
import { ApplicationCommandOptionType, GuildMember } from 'discord.js';
import { prisma } from '../index.js';
import { publish } from '../plugins/publish.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish({defaultMemberPermissions: 'ManageGuild'})],
description: 'Stick to a VC',
options: [
{
name: 'radio',
description: 'The radio you want to play.',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (ctx) => {
const focusedValue = ctx.options.getFocused();
const choices = ['KNGI', 'Gensokyo Radio'];
const filtered = choices.filter((choice) =>
choice.startsWith(focusedValue)
);
await ctx.respond(
filtered.map((choice) => ({ name: choice, value: choice }))
);
},
},
},
],
execute: async (ctx, options) => {
const radioname = options[1].getString('radio', true);
const fetchUser = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.user.id) as GuildMember
async function createDoc(radio: string) {
return await prisma.stick.create({
data: {
channelid: fetchUser.voice.channel?.id!,
guildid: ctx.guild!.id,
radio: radio
}
})
}
if (!fetchUser.voice.channel?.id)
return await ctx.reply({
content: 'You are not in a VC!',
ephemeral: true
})
if (!fetchUser.voice.channel!.joinable)
return await ctx.reply({
content: 'I can\'t join that VC!',
ephemeral: true
})
const countDocs = await prisma.stick.count({
where: {
guildid: ctx.guild!.id
}
})
if (countDocs !== 0)
return await ctx.reply({
content: 'There\'s more than one entry in the database!\nIf you want to remove that stick, first run the `/unstick` command!',
ephemeral: true
})
switch (radioname) {
case 'KNGI': {
await createDoc(radioname)
await ctx.reply({content: `${radioname} is going to be sticked from now on!`})
} break;
case 'Gensokyo Radio': {
await createDoc(radioname)
await ctx.reply({content: `${radioname} is going to be sticked from now on!`})
} break;
default: {
await ctx.reply({content: `Couldn't find that radio!`, ephemeral: true})
} break;
}
},
});

View File

@@ -1,29 +1,29 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { getVoiceConnection } from '@discordjs/voice'
import type { GuildMember } from 'discord.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Stop the radio of that guild',
options: [],
execute: async (ctx, options) => {
const fetchUser = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.user.id) as GuildMember
const fetchBot = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.client.user!.id) as GuildMember
if (fetchUser.voice.channel?.id !== fetchBot.voice.channel?.id)
return await ctx.reply({
content: 'You are not in the same VC as me or I\'m not on a VC in this discord server.',
ephemeral: true
})
const connection = getVoiceConnection(ctx.guild!.id)
connection!.destroy()
await ctx.reply({
content: 'Radio stopped successfully!',
ephemeral: true
})
},
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { getVoiceConnection } from '@discordjs/voice'
import type { GuildMember } from 'discord.js';
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Stop the radio of that guild',
options: [],
execute: async (ctx, options) => {
const fetchUser = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.user.id) as GuildMember
const fetchBot = await (await ctx.client.guilds.fetch(ctx.guild!.id)).members.fetch(ctx.client.user!.id) as GuildMember
if (fetchUser.voice.channel?.id !== fetchBot.voice.channel?.id)
return await ctx.reply({
content: 'You are not in the same VC as me or I\'m not on a VC in this discord server.',
ephemeral: true
})
const connection = getVoiceConnection(ctx.guild!.id)
connection!.destroy()
await ctx.reply({
content: 'Radio stopped successfully!',
ephemeral: true
})
},
});

View File

@@ -1,36 +1,36 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { prisma } from '../index.js';
import { getVoiceConnection } from '@discordjs/voice'
export default commandModule({
type: CommandType.Slash,
plugins: [publish({defaultMemberPermissions: 'ManageGuild'})],
description: 'Unstick the sticking',
options: [],
execute: async (ctx, options) => {
const countDocs = await prisma.stick.count({
where: {
guildid: ctx.guild!.id
}
})
if (countDocs === 0)
return await ctx.reply({
content: 'You can\'t unstick if the bot isn\'t sticked!',
ephemeral: true
})
await prisma.stick.deleteMany({
where: {
guildid: ctx.guild!.id
}
})
const connection = getVoiceConnection(ctx.guild!.id)
connection!.destroy()
await ctx.reply({
content: 'Unsticked and left the VC successfully!',
ephemeral: true
})
},
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '../plugins/publish.js';
import { prisma } from '../index.js';
import { getVoiceConnection } from '@discordjs/voice'
export default commandModule({
type: CommandType.Slash,
plugins: [publish({defaultMemberPermissions: 'ManageGuild'})],
description: 'Unstick the sticking',
options: [],
execute: async (ctx, options) => {
const countDocs = await prisma.stick.count({
where: {
guildid: ctx.guild!.id
}
})
if (countDocs === 0)
return await ctx.reply({
content: 'You can\'t unstick if the bot isn\'t sticked!',
ephemeral: true
})
await prisma.stick.deleteMany({
where: {
guildid: ctx.guild!.id
}
})
const connection = getVoiceConnection(ctx.guild!.id)
connection!.destroy()
await ctx.reply({
content: 'Unsticked and left the VC successfully!',
ephemeral: true
})
},
});

View File

@@ -1,10 +1,10 @@
#!/bin/bash
git pull
docker build . -t srizan10/ava
docker stop ava
docker rm ava
#!/bin/bash
git pull
docker build . -t srizan10/ava
docker stop ava
docker rm ava
docker run -d -t --name ava --restart unless-stopped srizan10/ava

View File

@@ -1,9 +1,9 @@
import { EventType, eventModule } from "@sern/handler";
export default eventModule({
type: EventType.Sern,
name: "error",
execute(err) {
console.log(err);
},
import { EventType, eventModule } from "@sern/handler";
export default eventModule({
type: EventType.Sern,
name: "error",
execute(err) {
console.log(err);
},
});

View File

@@ -1,24 +1,24 @@
import { EventType, eventModule } from '@sern/handler';
import axios from 'axios';
import { ActivityType, Client } from 'discord.js';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute: async (client: Client) => {
setInterval(async () => {
// For KNGI
const nowplayingapi = await axios.get('https://network.kngi.org/api/nowplaying').then(res => res.data[0])
client.user?.setActivity({type: ActivityType.Listening, name: `KNGI | ${nowplayingapi.now_playing.song.text}`})
}, 30_000)
setInterval(async () => {
// For Gensokyo Radio
const nowplayingapi = await axios.get('https://gensokyoradio.net/api/station/playing/').then(res => res.data)
client.user?.setActivity({type: ActivityType.Listening, name: `Gensokyo | ${nowplayingapi.SONGINFO.TITLE}`})
}, 20_000)
setInterval(async () => {
// For Gensokyo Radio
client.user?.setActivity({type: ActivityType.Watching, name: `${client.guilds.cache.filter((g)=> g.members.me!.voice.channelId).size} voice connections`})
}, 10_000)
},
});
import { EventType, eventModule } from '@sern/handler';
import axios from 'axios';
import { ActivityType, Client } from 'discord.js';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute: async (client: Client) => {
setInterval(async () => {
// For KNGI
const nowplayingapi = await axios.get('https://network.kngi.org/api/nowplaying').then(res => res.data[0])
client.user?.setActivity({type: ActivityType.Listening, name: `KNGI | ${nowplayingapi.now_playing.song.text}`})
}, 30_000)
setInterval(async () => {
// For Gensokyo Radio
const nowplayingapi = await axios.get('https://gensokyoradio.net/api/station/playing/').then(res => res.data)
client.user?.setActivity({type: ActivityType.Listening, name: `Gensokyo | ${nowplayingapi.SONGINFO.TITLE}`})
}, 20_000)
setInterval(async () => {
// For Gensokyo Radio
client.user?.setActivity({type: ActivityType.Watching, name: `${client.guilds.cache.filter((g)=> g.members.me!.voice.channelId).size} voice connections`})
}, 10_000)
},
});

View File

@@ -1,9 +1,9 @@
import { EventType, eventModule } from '@sern/handler';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute() {
console.log('Bot ready!');
},
});
import { EventType, eventModule } from '@sern/handler';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute() {
console.log('Bot ready!');
},
});

View File

@@ -1,36 +1,36 @@
import { joinVoiceChannel, createAudioResource, createAudioPlayer } from '@discordjs/voice';
import { EventType, eventModule } from '@sern/handler';
import type { Client, VoiceChannel } from 'discord.js';
import got from 'got';
import { prisma } from '../index.js';
import { radioResolver } from '../util/radioResolver.js';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute: async (client: Client) => {
const documents = await prisma.stick.findMany();
documents.forEach(async (document) => {
const fetchguild = await client.guilds.fetch(document.guildid);
try {
await fetchguild.channels.fetch(document.channelid) as VoiceChannel
} catch {
await prisma.stick.delete({
where: {
id: document.id
}
})
}
const stream = got.stream(radioResolver(document.radio as "KNGI" | "Gensokyo Radio"));
const connection = joinVoiceChannel({
adapterCreator: fetchguild.voiceAdapterCreator,
guildId: fetchguild.id,
channelId: document.channelid,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
});
},
});
import { joinVoiceChannel, createAudioResource, createAudioPlayer } from '@discordjs/voice';
import { EventType, eventModule } from '@sern/handler';
import type { Client, VoiceChannel } from 'discord.js';
import got from 'got';
import { prisma } from '../index.js';
import { radioResolver } from '../util/radioResolver.js';
export default eventModule({
type: EventType.Discord,
name: 'ready',
execute: async (client: Client) => {
const documents = await prisma.stick.findMany();
documents.forEach(async (document) => {
const fetchguild = await client.guilds.fetch(document.guildid);
try {
await fetchguild.channels.fetch(document.channelid) as VoiceChannel
} catch {
await prisma.stick.delete({
where: {
id: document.id
}
})
}
const stream = got.stream(radioResolver(document.radio as "KNGI" | "Gensokyo Radio"));
const connection = joinVoiceChannel({
adapterCreator: fetchguild.voiceAdapterCreator,
guildId: fetchguild.id,
channelId: document.channelid,
});
const resource = createAudioResource(stream);
const player = createAudioPlayer();
connection.subscribe(player);
player.play(resource);
});
},
});

View File

@@ -1,34 +1,34 @@
import { Client, GatewayIntentBits } from 'discord.js';
import { PrismaClient } from '@prisma/client';
import 'dotenv/config';
import { type Dependencies, type Singleton, DefaultLogging, Sern, single } from '@sern/handler';
export const prisma = new PrismaClient()
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
],
});
interface MyDependencies extends Dependencies {
'@sern/client' : Singleton<Client>;
'@sern/logger' : Singleton<DefaultLogging>
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: root => root
.add({ '@sern/client': single(client) })
.add({ '@sern/logger': single(new DefaultLogging()) })
});
Sern.init({
commands: 'dist/commands',
events: 'dist/events',
containerConfig: {
get: useContainer
}
});
client.login(process.env.TOKEN);
import { Client, GatewayIntentBits } from 'discord.js';
import { PrismaClient } from '@prisma/client';
import 'dotenv/config';
import { type Dependencies, type Singleton, DefaultLogging, Sern, single } from '@sern/handler';
export const prisma = new PrismaClient()
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
],
});
interface MyDependencies extends Dependencies {
'@sern/client' : Singleton<Client>;
'@sern/logger' : Singleton<DefaultLogging>
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: root => root
.add({ '@sern/client': single(client) })
.add({ '@sern/logger': single(new DefaultLogging()) })
});
Sern.init({
commands: 'dist/commands',
events: 'dist/events',
containerConfig: {
get: useContainer
}
});
client.login(process.env.TOKEN);

1719
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,42 @@
{
"name": "ava",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc --build",
"start": "tsc && node ./dist/index.js",
"dev": "tsc-watch --onSuccess \"node dist/index.js\"",
"generateprisma": "prisma generate"
},
"keywords": [
"typescript",
"sern",
"discord.js"
],
"type": "module",
"imports": {
"#plugins": "./dist/plugins/index.js"
},
"license": "UNLICENSED",
"dependencies": {
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.15.0",
"@prisma/client": "^4.7.1",
"@sern/handler": "^2.0.0",
"axios": "^1.2.1",
"discord.js": "^14.7.1",
"dotenv": "^16.0.3",
"got": "^12.5.3",
"libsodium-wrappers": "^0.7.10",
"string-progressbar": "^1.0.4"
},
"devDependencies": {
"@types/node": "^17.0.25",
"prettier": "^2.8.1",
"prisma": "^4.7.1",
"tsc-watch": "^6.0.0",
"typescript": "^4.9.4"
}
}
{
"name": "ava",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc --build",
"start": "tsc && node ./dist/index.js",
"dev": "tsc-watch --onSuccess \"node dist/index.js\"",
"generateprisma": "prisma generate"
},
"keywords": [
"typescript",
"sern",
"discord.js"
],
"type": "module",
"imports": {
"#plugins": "./dist/plugins/index.js"
},
"license": "UNLICENSED",
"dependencies": {
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.16.0",
"@prisma/client": "^4.7.1",
"@sern/handler": "^2.6.2",
"axios": "^1.2.1",
"discord.js": "^14.9.0",
"dotenv": "^16.0.3",
"got": "^12.5.3",
"libsodium-wrappers": "^0.7.10",
"string-progressbar": "^1.0.4"
},
"devDependencies": {
"@types/node": "^17.0.25",
"prettier": "^2.8.1",
"prisma": "^4.7.1",
"tsc-watch": "^6.0.0",
"typescript": "^4.9.4"
}
}

View File

@@ -1,18 +1,18 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("MONGODB")
}
model stick {
id String @id @map("_id") @default(uuid())
guildid String
channelid String
radio String
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("MONGODB")
}
model stick {
id String @id @map("_id") @default(uuid())
guildid String
channelid String
radio String
}

View File

@@ -1,7 +1,7 @@
{
"language": "typescript",
"paths": {
"base": "src",
"commands": "commands"
}
{
"language": "typescript",
"paths": {
"base": "src",
"commands": "commands"
}
}

View File

@@ -1,20 +1,20 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"target": "ESNext",
"module": "ESNext",
"outDir": "dist",
"rootDir": ".",
"strict": true,
"esModuleInterop": true,
"noImplicitAny": false,
"strictNullChecks": true,
"importsNotUsedAsValues": "error",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"paths": {
"#plugins": ["./dist/plugins/index.js"]
}
}
{
"compilerOptions": {
"resolveJsonModule": true,
"target": "ESNext",
"module": "ESNext",
"outDir": "dist",
"rootDir": ".",
"strict": true,
"esModuleInterop": true,
"noImplicitAny": false,
"strictNullChecks": true,
"importsNotUsedAsValues": "error",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"paths": {
"#plugins": ["./dist/plugins/index.js"]
}
}
}

View File

@@ -1,17 +1,17 @@
/**
* It converts a radio name to a URL
* @example
* ```ts
* radioResolver('KNGI')
* ```
* @returns {string} Radio URL
*/
export function radioResolver(radioName: 'KNGI' | 'Gensokyo Radio'): string {
switch (radioName) {
case 'KNGI':
return 'https://network.kngi.org/radio/8000/stream';
case 'Gensokyo Radio':
return 'https://stream.gensokyoradio.net/1';
}
}
/**
* It converts a radio name to a URL
* @example
* ```ts
* radioResolver('KNGI')
* ```
* @returns {string} Radio URL
*/
export function radioResolver(radioName: 'KNGI' | 'Gensokyo Radio'): string {
switch (radioName) {
case 'KNGI':
return 'https://network.kngi.org/radio/8000/stream';
case 'Gensokyo Radio':
return 'https://stream.gensokyoradio.net/1';
}
}

251
yarn.lock
View File

@@ -2,22 +2,30 @@
# yarn lockfile v1
"@discordjs/builders@^1.4.0":
version "1.4.0"
resolved "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz"
integrity sha512-nEeTCheTTDw5kO93faM1j8ZJPonAX86qpq/QVoznnSa8WWcCgJpjlu6GylfINTDW6o7zZY0my2SYdxx2mfNwGA==
"@discordjs/builders@^1.6.0":
version "1.6.1"
resolved "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.1.tgz"
integrity sha512-CCcLwn/8ANhlAbhlE18fcaN0hfXTen53/JiwZs1t9oE/Cqa9maA8ZRarkCIsXF4J7J/MYnd0J6IsxeKsq+f6mw==
dependencies:
"@discordjs/util" "^0.1.0"
"@sapphire/shapeshift" "^3.7.1"
discord-api-types "^0.37.20"
"@discordjs/formatters" "^0.3.0"
"@discordjs/util" "^0.2.0"
"@sapphire/shapeshift" "^3.8.1"
discord-api-types "^0.37.37"
fast-deep-equal "^3.1.3"
ts-mixer "^6.0.2"
tslib "^2.4.1"
ts-mixer "^6.0.3"
tslib "^2.5.0"
"@discordjs/collection@^1.3.0":
version "1.3.0"
resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-1.3.0.tgz"
integrity sha512-ylt2NyZ77bJbRij4h9u/wVy7qYw/aDqQLWnadjvDqW/WoWCxrsX6M3CIw9GVP5xcGCDxsrKj5e0r5evuFYwrKg==
"@discordjs/collection@^1.5.0":
version "1.5.0"
resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.0.tgz"
integrity sha512-suyVndkEAAWrGxyw/CPGdtXoRRU6AUNkibtnbJevQzpelkJh3Q1gQqWDpqf5i39CnAn5+LrN0YS+cULeEjq2Yw==
"@discordjs/formatters@^0.3.0":
version "0.3.0"
resolved "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.0.tgz"
integrity sha512-Fc4MomalbP8HMKEMor3qUiboAKDtR7PSBoPjwm7WYghVRwgJlj5WYvUsriLsxeKk8+Qq2oy+HJlGTUkGvX0YnA==
dependencies:
discord-api-types "^0.37.37"
"@discordjs/node-pre-gyp@^0.4.5":
version "0.4.5"
@@ -34,7 +42,7 @@
semver "^7.3.5"
tar "^6.1.11"
"@discordjs/opus@^0.9.0":
"@discordjs/opus@^0.9.0", "@discordjs/opus@>=0.8.0 <1.0.0":
version "0.9.0"
resolved "https://registry.npmjs.org/@discordjs/opus/-/opus-0.9.0.tgz"
integrity sha512-NEE76A96FtQ5YuoAVlOlB3ryMPrkXbUCTQICHGKb8ShtjXyubGicjRMouHtP1RpuDdm16cDa+oI3aAMo1zQRUQ==
@@ -42,35 +50,35 @@
"@discordjs/node-pre-gyp" "^0.4.5"
node-addon-api "^5.0.0"
"@discordjs/rest@^1.4.0":
version "1.5.0"
resolved "https://registry.npmjs.org/@discordjs/rest/-/rest-1.5.0.tgz"
integrity sha512-lXgNFqHnbmzp5u81W0+frdXN6Etf4EUi8FAPcWpSykKd8hmlWh1xy6BmE0bsJypU1pxohaA8lQCgp70NUI3uzA==
"@discordjs/rest@^1.7.0":
version "1.7.0"
resolved "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.0.tgz"
integrity sha512-r2HzmznRIo8IDGYBWqQfkEaGN1LrFfWQd3dSyC4tOpMU8nuVvFUEw6V/lwnG44jyOq+vgyDny2fxeUDMt9I4aQ==
dependencies:
"@discordjs/collection" "^1.3.0"
"@discordjs/util" "^0.1.0"
"@discordjs/collection" "^1.5.0"
"@discordjs/util" "^0.2.0"
"@sapphire/async-queue" "^1.5.0"
"@sapphire/snowflake" "^3.2.2"
discord-api-types "^0.37.23"
file-type "^18.0.0"
tslib "^2.4.1"
undici "^5.13.0"
"@sapphire/snowflake" "^3.4.0"
discord-api-types "^0.37.37"
file-type "^18.2.1"
tslib "^2.5.0"
undici "^5.21.0"
"@discordjs/util@^0.1.0":
version "0.1.0"
resolved "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz"
integrity sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==
"@discordjs/util@^0.2.0":
version "0.2.0"
resolved "https://registry.npmjs.org/@discordjs/util/-/util-0.2.0.tgz"
integrity sha512-/8qNbebFzLWKOOg+UV+RB8itp4SmU5jw0tBUD3ifElW6rYNOj1Ku5JaSW7lLl/WgjjxF01l/1uQPCzkwr110vg==
"@discordjs/voice@^0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@discordjs/voice/-/voice-0.15.0.tgz#774febb2a1623b23e234744fefb60544858db77d"
integrity sha512-YEvrRchDhjB0QbI9QYOF/qgDwvGb9sNGUyks5d3Srl+VRoMoKkMzWY+wcEfVbAgdMIAdLi5vyrTKP/gLND26jA==
"@discordjs/voice@^0.16.0":
version "0.16.0"
resolved "https://registry.npmjs.org/@discordjs/voice/-/voice-0.16.0.tgz"
integrity sha512-ToGCvHD1cBscuW3p+C7zOF5+L7MJmU4GjdOARfNk9mkHyFFZq4grK+Sxr3QXKbp27DtfDBc9uqD4GUOYgxngfA==
dependencies:
"@types/ws" "^8.5.4"
discord-api-types "^0.37.35"
discord-api-types "^0.37.37"
prism-media "^1.3.5"
tslib "^2.5.0"
ws "^8.12.1"
ws "^8.13.0"
"@prisma/client@^4.7.1":
version "4.7.1"
@@ -94,28 +102,27 @@
resolved "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz"
integrity sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==
"@sapphire/shapeshift@^3.7.1":
version "3.8.1"
resolved "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.1.tgz"
integrity sha512-xG1oXXBhCjPKbxrRTlox9ddaZTvVpOhYLmKmApD/vIWOV1xEYXnpoFs68zHIZBGbqztq6FrUPNPerIrO1Hqeaw==
"@sapphire/shapeshift@^3.8.1":
version "3.8.2"
resolved "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.2.tgz"
integrity sha512-NXpnJAsxN3/h9TqQPntOeVWZrpIuucqXI3IWF6tj2fWCoRLCuVK5wx7Dtg7pRrtkYfsMUbDqgKoX26vrC5iYfA==
dependencies:
fast-deep-equal "^3.1.3"
lodash "^4.17.21"
"@sapphire/snowflake@^3.2.2":
version "3.3.0"
resolved "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.3.0.tgz"
integrity sha512-Hec5N6zEkZuZFLybVKyLFLlcSgYmR6C1/+9NkIhxPwOf6tgX52ndJCSz8ADejmbrNE0VuNCNkpzhRZzenEC9vA==
"@sapphire/snowflake@^3.4.0":
version "3.4.2"
resolved "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.2.tgz"
integrity sha512-KJwlv5gkGjs1uFV7/xx81n3tqgBwBJvH94n1xDyH3q+JSmtsMeSleJffarEBfG2yAFeJiFA4BnGOK6FFPHc19g==
"@sern/handler@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@sern/handler/-/handler-2.0.0.tgz#06229074b810349588973b6a4714e624d081d09d"
integrity sha512-i9BbUxwOYX1rn1FUfVFT+c8ltAloEfIMUznOt2T4h1xbWyXm/aKocmcgt5DkBHRU8yGoCfDiFF3E3I1mHln3UQ==
"@sern/handler@^2.6.2":
version "2.6.2"
resolved "https://registry.npmjs.org/@sern/handler/-/handler-2.6.2.tgz"
integrity sha512-M0wiLL4eN1ddktrl+5dCFX1jipGJm5wU+2SBOioIqm3qr4vweRHx81o9B0HvcrqXnre1B1PIOG6EX6CQatLgbA==
dependencies:
iti "^0.5.0"
rxjs "^7.5.6"
ts-pattern "^4.0.2"
ts-results-es "^3.5.0"
iti "^0.6.0"
rxjs "^7.8.0"
ts-results-es "^3.6.0"
"@sindresorhus/is@^5.2.0":
version "5.3.0"
@@ -144,16 +151,9 @@
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz"
integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==
"@types/ws@^8.5.3":
version "8.5.3"
resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz"
integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==
dependencies:
"@types/node" "*"
"@types/ws@^8.5.4":
version "8.5.4"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5"
resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz"
integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==
dependencies:
"@types/node" "*"
@@ -310,33 +310,29 @@ detect-libc@^2.0.0:
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz"
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
discord-api-types@^0.37.20, discord-api-types@^0.37.23:
version "0.37.23"
resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.23.tgz"
integrity sha512-IixodMf9PjOSrsPorbti5aGv6sJVSPJybAlFMYsYDQXFS7zJyhSmA/ofpPTR9ZYqL1KEDY+xU74oZgBQa52eSQ==
discord-api-types@^0.37.37:
version "0.37.39"
resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.39.tgz"
integrity sha512-hkhQsQyzsTJITp311WXvHZh9j4RAMfIk2hPmsWeOTN50QTpg6zqmJNfel9D/8lYNvsU01wzw9281Yke8NhYyHg==
discord-api-types@^0.37.35:
version "0.37.36"
resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.36.tgz#650a8f66dce2c5e54a8c2275db74a0bb7936430d"
integrity sha512-Nlxmp10UpVr/utgZ9uODQvG2Or+5w7LFrvFMswyeKC9l/+UaqGT6H0OVgEFhu9GEO4U6K7NNO5W8Carv7irnCA==
discord.js@^14.7.1:
version "14.7.1"
resolved "https://registry.npmjs.org/discord.js/-/discord.js-14.7.1.tgz"
integrity sha512-1FECvqJJjjeYcjSm0IGMnPxLqja/pmG1B0W2l3lUY2Gi4KXiyTeQmU1IxWcbXHn2k+ytP587mMWqva2IA87EbA==
discord.js@^14.9.0:
version "14.9.0"
resolved "https://registry.npmjs.org/discord.js/-/discord.js-14.9.0.tgz"
integrity sha512-ygGms5xP4hG+QrrY9k7d/OYCzMltSMtdl/2Snzq/nLCiZo+Sna91Ulv9l0+B5Jd/Czcq37B7wJAnmja7GOa+bg==
dependencies:
"@discordjs/builders" "^1.4.0"
"@discordjs/collection" "^1.3.0"
"@discordjs/rest" "^1.4.0"
"@discordjs/util" "^0.1.0"
"@sapphire/snowflake" "^3.2.2"
"@types/ws" "^8.5.3"
discord-api-types "^0.37.20"
"@discordjs/builders" "^1.6.0"
"@discordjs/collection" "^1.5.0"
"@discordjs/formatters" "^0.3.0"
"@discordjs/rest" "^1.7.0"
"@discordjs/util" "^0.2.0"
"@sapphire/snowflake" "^3.4.0"
"@types/ws" "^8.5.4"
discord-api-types "^0.37.37"
fast-deep-equal "^3.1.3"
lodash.snakecase "^4.1.1"
tslib "^2.4.1"
undici "^5.13.0"
ws "^8.11.0"
tslib "^2.5.0"
undici "^5.21.0"
ws "^8.13.0"
dotenv@^16.0.3:
version "16.0.3"
@@ -371,10 +367,10 @@ fast-deep-equal@^3.1.3:
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
file-type@^18.0.0:
version "18.0.0"
resolved "https://registry.npmjs.org/file-type/-/file-type-18.0.0.tgz"
integrity sha512-jjMwFpnW8PKofLE/4ohlhqwDk5k0NC6iy0UHAJFKoY1fQeGMN0GDdLgHQrvCbSpMwbqzoCZhRI5dETCZna5qVA==
file-type@^18.2.1:
version "18.2.1"
resolved "https://registry.npmjs.org/file-type/-/file-type-18.2.1.tgz"
integrity sha512-Yw5MtnMv7vgD2/6Bjmmuegc8bQEVA9GmAyaR18bMYWKqsWDG9wgYZ1j4I6gNMF5Y5JBDcUcjRQqNQx7Y8uotcg==
dependencies:
readable-web-to-node-stream "^3.0.2"
strtok3 "^7.0.0"
@@ -504,7 +500,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.3:
inherits@^2.0.3, inherits@2:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -519,10 +515,10 @@ isexe@^2.0.0:
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
iti@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/iti/-/iti-0.5.0.tgz#fb7bcd32f60d71d9232e8b936608025f2ce106f7"
integrity sha512-ZiwdEIhXAxyb6/+j2didONRa3q73y9h8oHMRXAIkXv7k851cm8H7fyZZyszr514TdzgoVQl7Z6hvsdTogjgc0w==
iti@^0.6.0:
version "0.6.0"
resolved "https://registry.npmjs.org/iti/-/iti-0.6.0.tgz"
integrity sha512-JqujcnAIF3pmzitjbT3acc0LkordU6oHBDvWeT6a25wvEVBddFX3DFx/p6YBwGX1TTFsyLgVZtwhGOknthC96A==
dependencies:
utility-types "^3.10.0"
@@ -730,10 +726,10 @@ prettier@^2.8.1:
prism-media@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.3.5.tgz#ea1533229f304a1b774b158de40e98c765db0aa6"
resolved "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz"
integrity sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==
prisma@^4.7.1:
prisma@*, prisma@^4.7.1:
version "4.7.1"
resolved "https://registry.npmjs.org/prisma/-/prisma-4.7.1.tgz"
integrity sha512-CCQP+m+1qZOGIZlvnL6T3ZwaU0LAleIHYFPN9tFSzjs/KL6vH9rlYbGOkTuG9Q1s6Ki5D0LJlYlW18Z9EBUpGg==
@@ -792,7 +788,7 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
rxjs@^7.5.6:
rxjs@^7.8.0:
version "7.8.0"
resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz"
integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==
@@ -857,6 +853,13 @@ streamsearch@^1.1.0:
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
string-argv@^0.3.1:
version "0.3.1"
resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz"
@@ -876,13 +879,6 @@ string-progressbar@^1.0.4:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@@ -910,7 +906,7 @@ tar@^6.1.11:
mkdirp "^1.0.3"
yallist "^4.0.0"
through@2, through@~2.3, through@~2.3.1:
through@~2.3, through@~2.3.1, through@2:
version "2.3.8"
resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
@@ -928,20 +924,15 @@ tr46@~0.0.3:
resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
ts-mixer@^6.0.2:
version "6.0.2"
resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz"
integrity sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==
ts-mixer@^6.0.3:
version "6.0.3"
resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz"
integrity sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==
ts-pattern@^4.0.2:
version "4.0.6"
resolved "https://registry.npmjs.org/ts-pattern/-/ts-pattern-4.0.6.tgz"
integrity sha512-sFHQYD4KoysBi7e7a2mzDPvRBeqA4w+vEyRE+P5MU9VLq8eEYxgKCgD9RNEAT+itGRWUTYN+hry94GDPLb1/Yw==
ts-results-es@^3.5.0:
version "3.5.0"
resolved "https://registry.npmjs.org/ts-results-es/-/ts-results-es-3.5.0.tgz"
integrity sha512-W7Vtg9u7QsutEfDbLEJNDlDrYGK7spxab6Je+K9+tjI/ixCM1ouniQmHJX0mZUok5WsWiCGxQy6lIrI//nBzTg==
ts-results-es@^3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/ts-results-es/-/ts-results-es-3.6.0.tgz"
integrity sha512-swha7PpeUNX93LzwhNtlk97FZZdTkCsI4j2ShletEmQ4cEi9SWy95x8XRTpfOP8gr16ikEBSi4U8xD43BYHDFg==
tsc-watch@^6.0.0:
version "6.0.0"
@@ -953,25 +944,20 @@ tsc-watch@^6.0.0:
ps-tree "^1.2.0"
string-argv "^0.3.1"
tslib@^2.1.0, tslib@^2.4.1:
version "2.4.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz"
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
tslib@^2.5.0:
tslib@^2.1.0, tslib@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
typescript@^4.9.4:
typescript@*, typescript@^4.9.4:
version "4.9.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
undici@^5.13.0:
version "5.14.0"
resolved "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz"
integrity sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==
undici@^5.21.0:
version "5.22.0"
resolved "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz"
integrity sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==
dependencies:
busboy "^1.6.0"
@@ -982,7 +968,7 @@ util-deprecate@^1.0.1:
utility-types@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz"
integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
webidl-conversions@^3.0.0:
@@ -1017,14 +1003,9 @@ wrappy@1:
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@^8.11.0:
version "8.11.0"
resolved "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz"
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
ws@^8.12.1:
ws@^8.13.0:
version "8.13.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
resolved "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz"
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
yallist@^4.0.0: