Version 3.0 sortie, fusion avec JujulBot

This commit is contained in:
Angels-dev
2024-08-07 01:09:05 +02:00
parent 696b284b6c
commit 586f68b0df
51 changed files with 2472 additions and 1144 deletions

View File

@@ -1,35 +1,45 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, EmbedBuilder, inlineCode } from 'discord.js'
import * as AMP from '../../utils/amp'
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, ApplicationCommandOptionChoiceData, EmbedBuilder, inlineCode, PermissionFlagsBits } from 'discord.js'
import dbGuild from '../../schemas/guild'
import * as AMP from '../../utils/amp'
interface ListInstancesResult {
status: string
data: [
Host: {
AvailableInstances: any[]
FriendlyName: string
}
]
}
interface InstanceFields {
name: string
value: string
inline: boolean
}
interface failData {
Title: string
Message: string
interface InstanceResult {
status: string
data: [
Host
]
}
interface errorData {
error_code: string
interface Host {
AvailableInstances: Instance[]
FriendlyName: string
}
interface Instance {
InstanceID: string
FriendlyName: string
Running: boolean
Module: string
Port: number
}
interface FailMsgData {
Title: string
Message: string
}
interface ErrorMsgData {
error_code: string
}
function failMsg(data: any) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` }
function errorMsg(data: any) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` }
function failMsg(data: FailMsgData) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` }
function errorMsg(data: ErrorMsgData) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` }
export default {
data: new SlashCommandBuilder().setName('amp').setDescription('Accède à mon panel de jeu AMP !')
data: new SlashCommandBuilder()
.setName('amp')
.setDescription('Accède à mon panel de jeu AMP !')
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.addSubcommand(subcommand => subcommand.setName('login').setDescription("Connectez-vous avant d'effectuer une autre commande !")
.addStringOption(option => option.setName('username').setDescription("Nom d'Utilisateur").setRequired(true))
.addStringOption(option => option.setName('password').setDescription('Mot de Passe').setRequired(true))
@@ -71,12 +81,12 @@ export default {
}
else if (session.status === 'error') return interaction.respond([])
let choices: any = []
let choices: ApplicationCommandOptionChoiceData[] = []
let result = await AMP.ADSModule.GetInstances(host, sessionID)
if (result.status === 'success') {
let hosts = result.data.result as any[]
let hosts = result.data.result as Host[]
hosts.forEach(host => {
let instances = host.AvailableInstances as any[]
let instances = host.AvailableInstances as Instance[]
instances.forEach(instance => {
if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID })
})
@@ -105,10 +115,10 @@ export default {
await interaction.deferReply({ ephemeral: true })
let details = {
username: interaction.options.getString('username'),
password: interaction.options.getString('password'),
token: interaction.options.getString('otp') || '',
rememberMe: interaction.options.getBoolean('remember')
username: interaction.options.getString('username') || '',
password: interaction.options.getString('password') || '',
rememberMe: interaction.options.getBoolean('remember') || '',
token: interaction.options.getString('otp') || ''
}
let result = await AMP.Core.Login(host, details)
@@ -146,13 +156,13 @@ export default {
if (interaction.options.getSubcommandGroup() == 'instances') {
if (interaction.options.getSubcommand() == 'list') {
let result = await AMP.ADSModule.GetInstances(host, sessionID) as ListInstancesResult
let result = await AMP.ADSModule.GetInstances(host, sessionID) as InstanceResult
if (result.status === 'success') {
await interaction.followUp({ content: `${result.data.length} hôte(s) trouvé(s) !` })
result.data.forEach(async host => {
let fields = [] as InstanceFields[]
host.AvailableInstances.forEach(instance => {
host.AvailableInstances.forEach((instance: Instance) => {
fields.push({
name: instance.FriendlyName,
value: `**Running:** ${instance.Running}\n**Port:** ${instance.Port}\n**Module:** ${instance.Module}`,
@@ -168,8 +178,8 @@ export default {
return await interaction.channel?.send({ embeds: [embed] })
})
}
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data as unknown as FailMsgData))
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data as unknown as ErrorMsgData))
}
else if (interaction.options.getSubcommand() == 'manage') {
let instanceID = interaction.options.getString('instance', true)

View File

@@ -0,0 +1,37 @@
import { SlashCommandBuilder, EmbedBuilder, ChatInputCommandInteraction, TextChannel, PermissionFlagsBits } from 'discord.js'
module.exports = {
data: new SlashCommandBuilder()
.setName('boost')
.setDescription('Tester le boost du serveur !')
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
async execute(interaction: ChatInputCommandInteraction) {
if (interaction.guild?.id !== '796327643783626782') return interaction.reply({ content: 'Non !' })// Jujul Community
let member = interaction.member
if (!member) return console.log(`\u001b[1;31m Aucun membre trouvé !`)
let guild = interaction.guild
if (!guild) return console.log(`\u001b[1;31m Aucun serveur trouvé !`)
let channel = guild.channels.cache.get('924353449930412153') as TextChannel
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "924353449930412153" !`)
let boostRole = guild.roles.premiumSubscriberRole
if (!boostRole) return console.log(`\u001b[1;31m Aucun rôle de boost trouvé !`)
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
let embed = new EmbedBuilder()
.setColor(guild.members.me.displayHexColor)
.setTitle(`Nouveau boost de ${member.user.username} !`)
.setDescription(`
Merci à toi pour ce boost.\n
Grâce à toi, on a atteint ${guild.premiumSubscriptionCount} boosts !
`)
.setThumbnail(member.user.avatar)
.setTimestamp(new Date())
await channel.send({ embeds: [embed] })
await interaction.reply({ content: 'Va voir dans <#924353449930412153> !' })
}
}

View File

@@ -1,58 +0,0 @@
import { SlashCommandBuilder, EmbedBuilder, ChatInputCommandInteraction, MessageReaction, User }from 'discord.js'
import * as crack from '../../utils/crack'
export default {
data: new SlashCommandBuilder().setName('crack').setDescription('Télécharge un crack sur le site online-fix.me !')
.addStringOption(option => option.setName('jeu').setDescription('Quel jeu tu veux DL ?').setRequired(true)),
async execute(interaction: ChatInputCommandInteraction) {
await interaction.deferReply()
let query = interaction.options.getString('jeu')
if (!query) return
let games = await crack.search(query) as crack.Game[]
if (!Array.isArray(games)) {
//if (games.toString() == "TypeError: Cannot read properties of undefined (reading 'split')") return interaction.followUp({ content: `J'ai rien trouvé pour "${query}" !` })
//else return interaction.followUp({ content: "Une erreur s'est produite ! ```" + games + "```" })
return interaction.followUp({ content: `J'ai rien trouvé pour "${query}" !` })
}
let game = {} as crack.Game
if (games.length > 1) {
games = games.slice(0, 9)
let list = ''
for (let i = 0; i < games.length; i++) list += `\n${i + 1}. ${games[i].name} (${games[i].link})`
let message = await interaction.followUp({ content: `J'ai trouvé plusieurs jeux pour "${query}" ! ${list}` })
let emojis = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣']
for (let i = 0; i < games.length; i++) await message.react(emojis[i])
// Wait for a reaction to be added by the interaction author.
const filter: any = (reaction: MessageReaction, user: User) => { if (reaction.emoji.name) return emojis.includes(reaction.emoji.name) && user.id === interaction.user.id }
await message.awaitReactions({ filter, max: 1, time: 5000, errors: ['time'] }).then(collected => {
console.log(collected)
if (!collected.first) return
let reaction = collected.first()
let index = emojis.indexOf(reaction?.emoji.name ?? '')
game = games[index]
}).catch(() => { return interaction.followUp({ content: 'T\'as mis trop de temps à choisir !' }) })
}
else game = games[0]
let url = await crack.repo(game)
if (!url) return
let file = await crack.torrent(url)
if (!file) return
let filePath = await crack.download(url, file)
if (!filePath) return
let link = await crack.magnet(filePath)
let embed = new EmbedBuilder()
.setColor('#ffc370')
.setTitle(game.name)
.setURL(game.link)
.setDescription(`Voici ce que j'ai trouvé pour "${query}".\nTu peux aussi cliquer sur [ce lien](https://angels-dev.fr/magnet/${link}) pour pouvoir télécharger le jeu direct !`)
await interaction.followUp({ embeds: [embed], files: [filePath] })
}
}

View File

@@ -1,4 +1,4 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, APIEmbedField } from 'discord.js'
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, APIEmbedField, PermissionFlagsBits } from 'discord.js'
import dbGuildInit from '../../utils/dbGuildInit'
import dbGuild from '../../schemas/guild'
@@ -23,6 +23,7 @@ export default {
data: new SlashCommandBuilder()
.setName('database')
.setDescription('Communicate with the database')
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.addSubcommand(subcommand => subcommand.setName('info').setDescription('Returns information about the current guild'))
.addSubcommand(subcommand => subcommand.setName('init').setDescription('Force initialize an entry for the current guild in the database'))
.addSubcommand(subcommand => subcommand.setName('edit').setDescription('Modify parameters for the current guild')
@@ -44,7 +45,9 @@ export default {
.setDescription(`Guild **${guildProfile.guildName}** (ID: ${guildProfile.guildId})`)
.setThumbnail(guildProfile.guildIcon as string)
.setTimestamp()
.addFields(fields as APIEmbedField[])
//.addFields(fields as APIEmbedField[])
// Limit the number of fields to 25
.addFields(fields.slice(0, 25) as APIEmbedField[])
return await interaction.reply({ embeds: [embed] })
} else if (interaction.options.getSubcommand() === 'init') {

View File

@@ -1,146 +0,0 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, Message, inlineCode } from 'discord.js'
import https from 'https'
import crypto from 'crypto'
//import path from 'path'
//import fs from 'fs'
import * as Freebox from '../../utils/freebox'
import dbGuild from '../../schemas/guild'
function returnMsg(result: any) {
if (result.status === 'fail') return `La commande a échouée !\n${inlineCode(`${result.Title}: ${result.Message}`)}`
if (result.status === 'error') return `Y'a eu une erreur !\n${inlineCode(`${result.error_code}`)}`
}
export default {
data: new SlashCommandBuilder().setName('freebox').setDescription("Accéder à l'API FreeboxOS !")
.addSubcommand(subcommand => subcommand.setName('import').setDescription("Envoyer un fichier d'autorité de certification."))
.addSubcommand(subcommand => subcommand.setName('version').setDescription("Afficher la version de l'API."))
.addSubcommand(subcommand => subcommand.setName('init').setDescription("Créer une app sur la Freebox pour s'authentifier."))
.addSubcommandGroup(subcommandGroup => subcommandGroup.setName('get').setDescription('Récupérer des données.')
.addSubcommand(subcommand => subcommand.setName('connection').setDescription('Récupérer les informations de connexion.'))
),
async execute(interaction: ChatInputCommandInteraction) {
let guildProfile = await dbGuild.findOne({ guildId: interaction?.guild?.id })
if (!guildProfile) return interaction.reply({ content: `Database data for **${interaction.guild?.name}** does not exist, please initialize with \`/database init\` !` })
let dbData = guildProfile.get('guildFbx')
if (!dbData?.enabled) return interaction.reply({ content: `Freebox module is disabled for **${interaction.guild?.name}**, please activate with \`/database edit guildFbx.enabled True\` !` })
let host = dbData.host as string
if (!host) return interaction.reply({ content: `Freebox host is not set for **${interaction.guild?.name}**, please set with \`/database edit guildFbx.host <host>\` !` })
let version = dbData.version as number
if (!version) return interaction.reply({ content: `Freebox API version is not set for **${interaction.guild?.name}**, please set with \`/database edit guildFbx.version <version>\` !` })
let httpsOptions = {}
//let caCrt = fs.readFileSync(path.resolve(__dirname, '../../static/freebox-ecc-root-ca.crt'))
// MIME Type : application/x-x509-ca-cert
//if (caCrt) httpsOptions = { ca: caCrt }
let httpsAgent = new https.Agent(httpsOptions)
if (interaction.options.getSubcommand() === 'import') {
let filter = (m: Message) => m.author.id === interaction.user.id
await interaction.reply({ content: 'Please send another message with the CA file attached, you have one minute.', fetchReply: true }).then(async () => {
console.log('waiting for message')
await interaction.channel?.awaitMessages({ filter, time: 60_000, errors: ['time'] }).then(async collected => {
console.log(collected)
let message = collected.first()
if (!message?.attachments.size) return interaction.followUp('No file was sent in your message!')
let attachment = message.attachments.first()
console.log(attachment)
// Save the file to the database // TODO
interaction.followUp(`File saved, you can now interact with your Freebox!`)
}).catch(() => interaction.followUp('No message was sent before the time limit!'))
})
}
else if (interaction.options.getSubcommand() === 'version') {
let result = await Freebox.Core.Version(host, httpsAgent)
if (result.status === 'success') {
let embed = new EmbedBuilder()
embed.setTitle('FreeboxOS API Version')
embed.setDescription(`Version: ${result.data.api_version}`)
return await interaction.reply({ embeds: [embed] })
}
else if (result.status === 'fail') return await interaction.reply({ content: `Failed to retrieve the API version: ${result.data}`, ephemeral: true })
else if (result.status === 'error') return await interaction.reply({ content: `An error occurred while retrieving the API version: ${result.data}`, ephemeral: true })
}
else if (interaction.options.getSubcommand() === 'init') {
await interaction.deferReply({ ephemeral: true })
let app = {
app_id: 'fr.angels.bot_tamiseur',
app_name: 'Bot Tamiseur',
app_version: '2.3.0',
device_name: 'Bot Discord NodeJS'
}
let result = await Freebox.Core.Init(host, version, httpsAgent, app, '')
if (result.status === 'success') {
let appToken = result.data.app_token
let trackId = result.data.track_id
let initCheck = setInterval(async () => {
let result = await Freebox.Core.Init(host, version, httpsAgent, app, trackId)
if (result.status !== 'success') return await interaction.followUp(returnMsg(result) as string)
let status = result.data.status
if (status === 'granted') {
clearInterval(initCheck)
let password_salt = result.data.password_salt
if (!dbData) return
dbData['appToken'] = appToken
dbData['password_salt'] = password_salt
if (!guildProfile) return
guildProfile.set('guildFbx', dbData)
guildProfile.markModified('guildFbx')
await guildProfile.save().catch(console.error)
return await interaction.followUp('Done !')
}
else if (status === 'denied') {
clearInterval(initCheck)
return await interaction.followUp('The user denied the app access to the Freebox.')
}
else if (status === 'pending') return
}, 2000)
} else return await interaction.followUp({ content: returnMsg(result) as string, ephemeral: true })
}
else if (interaction.options.getSubcommandGroup() === 'get') {
let appToken = dbData.appToken as string
if (!appToken) return await interaction.reply({ content: `Freebox appToken is not set for **${interaction.guild?.name}**, please init the app with \`/freebox init\` !` })
console.log(appToken)
let challengeData = await Freebox.Login.Challenge(host, version, httpsAgent)
if (!challengeData) return await interaction.reply({ content: `Failed to retrieve the challenge for **${interaction.guild?.name}** !` })
let challenge = challengeData.data.challenge
console.log(challenge)
let password = crypto.createHmac('sha1', appToken).update(challenge).digest('hex')
console.log(password)
let session = await Freebox.Login.Session(host, version, httpsAgent, 'fr.angels.bot_tamiseur', password)
if (!session) return await interaction.reply({ content: `Failed to retrieve the session for **${interaction.guild?.name}** !` })
let sessionToken = dbData['sessionToken'] = session.data.session_token
guildProfile.set('guildFbx', dbData)
guildProfile.markModified('guildFbx')
await guildProfile.save().catch(console.error)
if (interaction.options.getSubcommand() === 'connection') {
let connection = await Freebox.Get.Connection(host, version, httpsAgent, sessionToken)
if (!connection) return await interaction.reply({ content: `Failed to retrieve the connection details for **${interaction.guild?.name}** !` })
return await interaction.reply({ content: `Connection details for **${interaction.guild?.name}**:\n${inlineCode(JSON.stringify(connection))}` })
}
}
}
}

View File

@@ -1,34 +0,0 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, GuildMember } from 'discord.js'
import { getVoiceConnection, joinVoiceChannel } from '@discordjs/voice'
export default {
data: new SlashCommandBuilder()
.setName('papa')
.setDescription('Si papa m\'appelle, je le rejoins !'),
async execute(interaction: ChatInputCommandInteraction) {
if (interaction.user.id !== '223831938346123275') return interaction.reply({ content: 'T\'es pas mon père, dégage !' })
let guild = interaction.guild
if (!guild) return interaction.reply({ content: 'Je ne peux pas rejoindre ton vocal en message privé, papa !' })
let member = interaction.member as GuildMember
let botChannel = guild.members.me?.voice.channel
let papaChannel = member.voice.channel
if (!papaChannel && botChannel) {
const voiceConnection = getVoiceConnection(guild.id);
if (voiceConnection) voiceConnection.destroy()
return interaction.reply({ content: 'Je quitte le vocal, papa !' })
}
else if (papaChannel && (!botChannel || botChannel.id !== papaChannel.id)) {
joinVoiceChannel({
channelId: papaChannel.id,
guildId: papaChannel.guild.id,
adapterCreator: papaChannel.guild.voiceAdapterCreator,
})
return interaction.reply({ content: 'Je rejoins ton vocal, papa !' })
}
else return interaction.reply({ content: 'Je suis déjà dans ton vocal, papa !' })
}
}

View File

@@ -1,79 +0,0 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, GuildMember } from 'discord.js'
import { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, EndBehaviorType } from '@discordjs/voice'
export default {
data: new SlashCommandBuilder()
.setName('parle')
.setDescription('Fais moi parler par dessus quelqu\'un de chiant dans le vocal')
.addUserOption(option => option.setName('user').setDescription('La personne en question').setRequired(true)),
async execute(interaction: ChatInputCommandInteraction) {
if (interaction.user.id !== '223831938346123275') return await interaction.reply({ content: 'Tu n\'as pas le droit d\'utiliser cette commande !', ephemeral: true })
let user = interaction.options.getUser('user')
if (!user) return
let guild = interaction.guild
if (!guild) return
let member = guild.members.cache.get(user.id) as GuildMember
if (!member) return
let caller = interaction.member as GuildMember
if (!caller) return
if (!caller.voice.channel) return await interaction.reply({ content: 'You must be in a voice channel to use this command.', ephemeral: true })
if (!member.voice.channel) return await interaction.reply({ content: 'The member must be in a voice channel to use this command.', ephemeral: true })
if (caller.voice.channelId !== member.voice.channelId) return await interaction.reply({ content: 'You must be in the same voice channel than the member to use this command.', ephemeral: true })
await interaction.reply({ content: 'Je vais parler par dessus cette personne !', ephemeral: true })
/*
// Searches for audio files uploaded in the channel
let messages = await interaction.channel.messages.fetch({ limit: 10, cache: false })
messages = messages.filter(m => m.attachments.size > 0)
let files = []
await messages.forEach(m => m.attachments.forEach(a => {
if (a.contentType === 'audio/mpeg') files.push(a)
}))
if (files.size === 0) return await interaction.editReply({ content: 'Aucun fichier audio trouvé dans ce channel.', ephemeral: true })
// Limit the number of files to the last 10
//files = files.sort((a, b) => b.createdTimestamp - a.createdTimestamp).first(10)
// Ask the user to choose a file
let file = await interaction.channel.send({ content: 'Choisissez un fichier audio :', files: files })
let filter = m => m.author.id === interaction.user.id && !isNaN(m.content) && parseInt(m.content) > 0 && parseInt(m.content) <= files.size
let response = await interaction.channel.awaitMessages({ filter, max: 1, time: 30000, errors: ['time'] })
file = files.get(files.keyArray()[response.first().content - 1])
*/
let playing = false
let player = createAudioPlayer()
player.on(AudioPlayerStatus.Idle, () => { playing = false })
let connection = joinVoiceChannel({
channelId: caller.voice.channelId as string,
guildId: interaction.guildId as string,
adapterCreator: guild.voiceAdapterCreator,
selfDeaf: false
})
connection.subscribe(player)
let stream = connection.receiver.subscribe(user.id, { end: { behavior: EndBehaviorType.Manual } })
stream.on('data', (chunk) => {
if (!user) return
if (connection.receiver.speaking.users.has(user.id) && !playing) {
playing = true
let resource = createAudioResource('../../static/parle.mp3', { inlineVolume: true })
//let resource = createAudioResource(file.attachments.first().url, { inlineVolume: true })
if (resource.volume) resource.volume.setVolume(0.2)
player.play(resource)
}
})
interaction.client.on('voiceStateUpdate', (oldState, newState) => {
if (oldState.id === member.id && newState.channelId !== caller.voice.channelId) {
stream.destroy()
connection.disconnect()
}
})
}
}

View File

@@ -1,29 +0,0 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
export default {
data: new SlashCommandBuilder()
.setName('spam')
.setDescription('Spam')
.addUserOption(option => option.setName('user').setDescription('Spam').setRequired(true))
.addStringOption(option => option.setName('string').setDescription('Spam').setRequired(true))
.addIntegerOption(option => option.setName('integer').setDescription('Spam').setRequired(true)),
async execute(interaction: ChatInputCommandInteraction) {
let user = interaction.options.getUser('user')
let string = interaction.options.getString('string')
let integer = interaction.options.getInteger('integer')
await interaction.reply({ content: 'Spam', ephemeral: true })
let i = 0
function myLoop() {
setTimeout(function () {
if (!user) return
if (!string) return
if (!integer) return
user.send(string).catch(error => console.error(error))
i++
if (i < integer) myLoop()
}, 1000)
}
myLoop()
}
}

View File

@@ -1,19 +0,0 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, Guild } from 'discord.js'
export default {
data: new SlashCommandBuilder()
.setName('update')
.setDescription('Update the member count channel.'),
async execute(interaction: ChatInputCommandInteraction) {
let guild = interaction.guild as Guild
guild.members.fetch().then(() => {
var i = 0
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = guild.channels.cache.get('1091140609139560508')
if (!channel) return
channel.setName(`${i} Gens Posés`)
interaction.reply(`${i} Gens Posés !`)
}).catch(console.error)
}
}