Compare commits
118 Commits
57fcb9f625
...
develop_ch
| Author | SHA1 | Date | |
|---|---|---|---|
| 81f91df8ac | |||
| 6c6c2655f2 | |||
| 6012351b3e | |||
| 934fa4d37f | |||
| 44982fd439 | |||
| 46fdebd503 | |||
| c294489a60 | |||
| 2cf2ec7d88 | |||
| 2f03a0de4c | |||
| 3b33bb6ee4 | |||
| f7e0c4b15a | |||
| 9fc901a2ef | |||
| b7283c17b6 | |||
| 40f6ea7cd7 | |||
| cb94d94943 | |||
| 00b834c40b | |||
| a294b8c668 | |||
| 263405141b | |||
| 089bb99119 | |||
| 2f51c18a69 | |||
| 7afbb169e2 | |||
| bdb9d4b807 | |||
| ed67193761 | |||
| 18c9be444d | |||
| 40956e5c9e | |||
| 4de56c1af8 | |||
| 7b9a7fb339 | |||
| 3039bf65bd | |||
| 850e7288d1 | |||
| 3bbba3217a | |||
| 7b0fde230d | |||
| 511f4bf69e | |||
| 78f1232f5b | |||
| 41683fe098 | |||
| 61b617db04 | |||
| 740213712a | |||
| 8cdd7d3974 | |||
| e7681bf7cd | |||
| 7bee11e4f4 | |||
| 2954d1b304 | |||
| 4868f6930e | |||
| 42f04a552a | |||
| 00de13acd2 | |||
| 9a5942facc | |||
| bdc0ed0fad | |||
| 55490c4b04 | |||
| 66cec55bb6 | |||
| 16b41fad2b | |||
| ab3ef81df9 | |||
| 0f68356254 | |||
| 855a91e340 | |||
| 8ef2ede2c0 | |||
| 32954a2536 | |||
| a689783b36 | |||
| 9b0f381673 | |||
| 1eb4da8729 | |||
| 85fc4805dc | |||
| f7bcbe348b | |||
| 2307119ad7 | |||
| d3daa299c0 | |||
| abf8f10668 | |||
| acaedb434c | |||
| e64811a179 | |||
| 113f6cbbd5 | |||
| 7c4b5c52f1 | |||
| b5ded6acaf | |||
| 08a9d0addd | |||
| aa1789da97 | |||
| 9e0c78d939 | |||
| d82c569363 | |||
| 6effe2983e | |||
| a729545e01 | |||
| 7e79b2c3b4 | |||
| 87be8ca8db | |||
| 5507fea98e | |||
| 92df0cf4a7 | |||
| 944f8d4e72 | |||
| 27e9fdb743 | |||
| b9a699c4c2 | |||
| 734aa58e67 | |||
| dc323ffeb1 | |||
| 9fd8f3c289 | |||
| c82fceeef1 | |||
| 01a72ca544 | |||
| 8befc32453 | |||
| 4a3e470945 | |||
| 7c6389d421 | |||
| ac672e73d0 | |||
| 43546d93fe | |||
| 6ea91cd1c9 | |||
| 0ad30722ae | |||
| dfeb3d5148 | |||
| 6cbf6dc718 | |||
| e24cc98fec | |||
| a0e979e0bc | |||
| 69a711a4a4 | |||
| 89e73e866b | |||
| 77b526ca21 | |||
| 881b7f6359 | |||
| ece032ff5a | |||
| dabb635b6b | |||
| 2de2202187 | |||
| 3928b1f564 | |||
| 8865015499 | |||
| 811478f486 | |||
| 808ca6c442 | |||
| cb3466c6c6 | |||
| 0d15e7931c | |||
| e68272236f | |||
| febbd1fa8e | |||
| 0033bea4ab | |||
| d120cf9945 | |||
| 24b97bc5b0 | |||
| 7ebdb84c98 | |||
| 30a2114ff4 | |||
| dce3b6ecc4 | |||
| b2b8bccaa6 | |||
| 97af77745f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
.env
|
.env
|
||||||
config.json
|
config.json
|
||||||
|
node_modules
|
||||||
|
keyfile.json
|
||||||
|
media
|
||||||
17
README.md
17
README.md
@@ -3,3 +3,20 @@
|
|||||||
BreadBot helps, BreadBot does the things. Whatever things I'm willing to add to BreadBot.
|
BreadBot helps, BreadBot does the things. Whatever things I'm willing to add to BreadBot.
|
||||||
|
|
||||||
BreadBot is the breadiest bread.
|
BreadBot is the breadiest bread.
|
||||||
|
|
||||||
|
In all seriousness, BreadBot is my first real attempt at a Discord bot. I'm writing it such that it can really only be used in one server at the moment, although that will hopefully change in the future. The intention is really for it only to be used for the Team 2648 Discord server.
|
||||||
|
|
||||||
|
I have a subset of features that I want it to have before I call it "production ready" and a set of features that I want if I'm feeling adventurous and want to put in a lot of work.
|
||||||
|
|
||||||
|
"Production Ready" Features
|
||||||
|
- [ ] Google Calendar Integration for Event Management
|
||||||
|
- [ ] Create/Manage/Remove Events and Calendars
|
||||||
|
- [ ] Add Autocomplete for common elements like Calendar Names, Event Names, Timezones, etc.
|
||||||
|
- [ ] Calendar Announcements for Upcoming Events
|
||||||
|
- [ ] Poll Creation and Results Announcements
|
||||||
|
- [ ] Conversation Archiving (Partially working, need to work out edited messages, deleted messages, and attachments)
|
||||||
|
|
||||||
|
"Adventurous (Lots of Work)" Features
|
||||||
|
- [ ] BreadBot Voice Chat Hall Monitor
|
||||||
|
- [ ] Breadle (BreadBot Idle Bread Baking Game)
|
||||||
|
- [ ] BreadBot Calendar Send To Email
|
||||||
|
|||||||
201
bin/breadmixer.py
Normal file
201
bin/breadmixer.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import argparse
|
||||||
|
import mysql.connector
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import subprocess
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from txtai.pipeline import Transcription
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
argument_parser = argparse.ArgumentParser(description="BreadMixer is used to combine media from Discord Voice Calls")
|
||||||
|
argument_parser.add_argument("callid", help="The call id that needs to be mixed")
|
||||||
|
argument_parser.add_argument("config", help="The BreadBot config file location")
|
||||||
|
argument_parser.add_argument("-f", "--filespercycle", help="The number of files to combine per run of ffmpeg", default=50)
|
||||||
|
argument_parser.add_argument("-v", "--verbose", help="Make the script tell you more about what it's doing", action="store_true")
|
||||||
|
|
||||||
|
args = argument_parser.parse_args()
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Checking config file")
|
||||||
|
|
||||||
|
if not os.path.exists(args.config):
|
||||||
|
print('The file path {path} does not exist'.format(path=args.config))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(args.config) as config:
|
||||||
|
json_config = json.loads(config.read())
|
||||||
|
|
||||||
|
config_must_contain = [
|
||||||
|
"mysql_username",
|
||||||
|
"mysql_password",
|
||||||
|
"mysql_db_name",
|
||||||
|
"mysql_host",
|
||||||
|
"media_voice_folder"
|
||||||
|
]
|
||||||
|
|
||||||
|
if not all([element in json_config for element in config_must_contain]):
|
||||||
|
print('One or more of the following config items are missing')
|
||||||
|
for element in config_must_contain:
|
||||||
|
print('\t{item}'.format(item=element))
|
||||||
|
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Connecting to mysql db {dbname}".format(dbname=json_config["mysql_db_name"]))
|
||||||
|
|
||||||
|
mydb = mysql.connector.connect(
|
||||||
|
host=json_config["mysql_host"],
|
||||||
|
user=json_config["mysql_username"],
|
||||||
|
password=json_config["mysql_password"],
|
||||||
|
database=json_config["mysql_db_name"]
|
||||||
|
)
|
||||||
|
mydb.autocommit = True
|
||||||
|
|
||||||
|
cursor = mydb.cursor()
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Checking to see if call ID {callid} exists".format(callid=args.callid))
|
||||||
|
|
||||||
|
cursor.execute("SELECT call_start_time FROM call_states WHERE call_id = %s", [args.callid])
|
||||||
|
|
||||||
|
call_start_time = cursor.fetchall()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
if len(call_start_time) == 0:
|
||||||
|
print('{call_id} does not exist in the database'.format(call_id=args.callid))
|
||||||
|
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Collecting files from {folder}".format(folder=os.path.join(json_config["media_voice_folder"], args.callid)))
|
||||||
|
|
||||||
|
file_dict = {}
|
||||||
|
|
||||||
|
for file in os.listdir(os.path.join(json_config["media_voice_folder"], args.callid)):
|
||||||
|
file_name_no_ext = file.split('.')[0]
|
||||||
|
timestamp = int(file_name_no_ext.split('-')[0])
|
||||||
|
user_snowflake = file_name_no_ext.split('-')[1]
|
||||||
|
|
||||||
|
file_stamp_as_datetime = datetime.datetime.fromtimestamp(timestamp / 1000)
|
||||||
|
time_diff = file_stamp_as_datetime - call_start_time[0][0]
|
||||||
|
|
||||||
|
file_dict[os.path.join(json_config["media_voice_folder"], args.callid, file)] = dict(
|
||||||
|
user=user_snowflake,
|
||||||
|
real_date=file_stamp_as_datetime,
|
||||||
|
milliseconds_from_starttime=int((time_diff.seconds * 1000) + (time_diff.microseconds / 1000))
|
||||||
|
)
|
||||||
|
|
||||||
|
file_dict_items = [(k, v) for k, v in file_dict.items()]
|
||||||
|
file_dict_items.sort(key=lambda a: a[1]["milliseconds_from_starttime"])
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Collected files: ")
|
||||||
|
[print(element) for element in file_dict_items]
|
||||||
|
|
||||||
|
list_of_final_merges = []
|
||||||
|
|
||||||
|
for i in range(0, len(file_dict_items), args.filespercycle):
|
||||||
|
input_list = []
|
||||||
|
filter_list = []
|
||||||
|
|
||||||
|
next_endpoint = i + 50 if i + 50 <= len(file_dict_items) else len(file_dict_items)
|
||||||
|
|
||||||
|
for j in range(i, next_endpoint, 1):
|
||||||
|
input_list.append(file_dict_items[j][0])
|
||||||
|
filter_list.append("[{inputid}]adelay={delay}|{delay}[a{inputid}]".format(
|
||||||
|
inputid = j - i,
|
||||||
|
delay = file_dict_items[j][1]["milliseconds_from_starttime"]
|
||||||
|
))
|
||||||
|
|
||||||
|
command_list = ["ffmpeg"]
|
||||||
|
|
||||||
|
for input in input_list:
|
||||||
|
command_list.append("-i")
|
||||||
|
command_list.append(input)
|
||||||
|
|
||||||
|
command_list.append("-filter_complex")
|
||||||
|
|
||||||
|
filter_string = "\""
|
||||||
|
filter_string = filter_string + ';'.join(filter_list)
|
||||||
|
filter_string = filter_string + ";"
|
||||||
|
|
||||||
|
for j in range(i, next_endpoint, 1):
|
||||||
|
filter_string = filter_string + "[a{inputid}]".format(inputid=j - i)
|
||||||
|
|
||||||
|
filter_string = filter_string + "amix=inputs={input_count}:normalize=0[a]\"".format(input_count = next_endpoint - i)
|
||||||
|
|
||||||
|
command_list.append(filter_string)
|
||||||
|
command_list.append("-map")
|
||||||
|
command_list.append("\"[a]\"")
|
||||||
|
|
||||||
|
output_file_name = os.path.join(
|
||||||
|
json_config["media_voice_folder"],
|
||||||
|
args.callid,
|
||||||
|
"intermediate-" + "".join(random.choices(string.ascii_uppercase + string.digits, k=10)) + ".mp3"
|
||||||
|
)
|
||||||
|
|
||||||
|
list_of_final_merges.append(output_file_name)
|
||||||
|
|
||||||
|
command_list.append(output_file_name)
|
||||||
|
|
||||||
|
ffmpeg_process = subprocess.Popen(' '.join(command_list), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||||
|
print(ffmpeg_process.args)
|
||||||
|
|
||||||
|
stdout, stderr = ffmpeg_process.communicate()
|
||||||
|
|
||||||
|
if (ffmpeg_process.returncode != 0):
|
||||||
|
print("The ffmpeg process failed")
|
||||||
|
print(stdout)
|
||||||
|
print(stderr)
|
||||||
|
sys.exit(5)
|
||||||
|
|
||||||
|
final_command_list = ["ffmpeg"]
|
||||||
|
|
||||||
|
for file in list_of_final_merges:
|
||||||
|
final_command_list.append("-i")
|
||||||
|
final_command_list.append(file)
|
||||||
|
|
||||||
|
final_command_list.append("-filter_complex")
|
||||||
|
|
||||||
|
filter_string = "\""
|
||||||
|
|
||||||
|
for i in range(len(list_of_final_merges)):
|
||||||
|
filter_string = filter_string + "[{inputid}]".format(inputid=i)
|
||||||
|
|
||||||
|
filter_string = filter_string + "amix=inputs={input_count}:normalize=0[a];[a]volume=3[boosted]\"".format(input_count=len(list_of_final_merges))
|
||||||
|
|
||||||
|
final_command_list.append(filter_string)
|
||||||
|
final_command_list.append("-map")
|
||||||
|
final_command_list.append("\"[boosted]\"")
|
||||||
|
final_command_list.append(os.path.join(json_config["media_voice_folder"], args.callid, "output.mp3"))
|
||||||
|
|
||||||
|
final_command_process = subprocess.Popen(' '.join(final_command_list), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||||
|
stdout, stderr = final_command_process.communicate()
|
||||||
|
|
||||||
|
if (final_command_process.returncode != 0):
|
||||||
|
print("The final ffmpeg process failed")
|
||||||
|
print(stdout)
|
||||||
|
print(stderr)
|
||||||
|
sys.exit(6)
|
||||||
|
|
||||||
|
for file in os.listdir(os.path.join(json_config["media_voice_folder"], args.callid)):
|
||||||
|
if file.startswith("intermediate"):
|
||||||
|
os.remove(os.path.join(json_config["media_voice_folder"], args.callid, file))
|
||||||
|
|
||||||
|
transcribe = Transcription("openai/whisper-base")
|
||||||
|
|
||||||
|
for (k, v) in file_dict.items():
|
||||||
|
text = transcribe(k)
|
||||||
|
|
||||||
|
cursor = mydb.cursor()
|
||||||
|
cursor.execute("INSERT INTO call_transcriptions (call_id, user_snowflake, speaking_start_time, text) VALUES (%s, %s, %s, %s)", [
|
||||||
|
args.callid,
|
||||||
|
v["user"],
|
||||||
|
v["real_date"],
|
||||||
|
text
|
||||||
|
])
|
||||||
|
cursor.close()
|
||||||
279
breadbot.js
279
breadbot.js
@@ -1,26 +1,70 @@
|
|||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { Client, Events, GatewayIntentBits, Collection } = require('discord.js');
|
const { Client, Events, GatewayIntentBits, Collection } = require('discord.js');
|
||||||
const { token } = require('./config.json');
|
const { joinVoiceChannel, getVoiceConnection, entersState, VoiceConnectionStatus, EndBehaviorType } = require('@discordjs/voice')
|
||||||
|
const { token, media_voice_folder, breadbot_logging_config } = require('./config.json');
|
||||||
|
const winston = require('winston')
|
||||||
|
const winston_mysql = require('winston-mysql')
|
||||||
|
const sqlutil = require('./utilities/sqlutil');
|
||||||
|
const { Console } = require('node:console');
|
||||||
|
const prism = require('prism-media')
|
||||||
|
|
||||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
const logger = winston.createLogger({
|
||||||
|
level: "silly",
|
||||||
|
transports: [
|
||||||
|
new winston.transports.Console({
|
||||||
|
format: winston.format.simple(),
|
||||||
|
level: breadbot_logging_config["console_log_level"]
|
||||||
|
}),
|
||||||
|
new winston_mysql({
|
||||||
|
level: breadbot_logging_config["sql_log_level"],
|
||||||
|
host: breadbot_logging_config["mysql_host"],
|
||||||
|
user: breadbot_logging_config["mysql_username"],
|
||||||
|
password: breadbot_logging_config["mysql_password"],
|
||||||
|
database: breadbot_logging_config["mysql_db_name"],
|
||||||
|
table: breadbot_logging_config["mysql_table_name"]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
sqlutil.buildPool()
|
||||||
|
|
||||||
|
const getAllFiles = function(directoryPath, arrayOfFiles) {
|
||||||
|
const files = fs.readdirSync(directoryPath);
|
||||||
|
|
||||||
|
arrayOfFiles = arrayOfFiles || [];
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
if (fs.statSync(directoryPath + path.sep + file).isDirectory()) {
|
||||||
|
arrayOfFiles = getAllFiles(directoryPath + path.sep + file, arrayOfFiles);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arrayOfFiles.push(path.join(__dirname, directoryPath, path.sep, file));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return arrayOfFiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMembers, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildVoiceStates] });
|
||||||
|
|
||||||
client.commands = new Collection();
|
client.commands = new Collection();
|
||||||
|
|
||||||
const commandsPath = path.join(__dirname, 'commands');
|
var activeCalls = []
|
||||||
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
|
||||||
|
|
||||||
for (const file of commandFiles) {
|
getAllFiles('.' + path.sep + 'commands', [])
|
||||||
const filePath = path.join(commandsPath, file);
|
.filter(file => file.endsWith('.js'))
|
||||||
const command = require(filePath);
|
.forEach(file => {
|
||||||
|
const command = require(file);
|
||||||
|
|
||||||
if ('data' in command && 'execute' in command) {
|
if ('enabled' in command && command.enabled && 'data' in command && 'execute' in command) {
|
||||||
client.commands.set(command.data.name, command);
|
client.commands.set(command.data.name, command);
|
||||||
}
|
logger.info(`Loaded command at ${file}`)
|
||||||
else {
|
}
|
||||||
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
|
else {
|
||||||
}
|
logger.warn(`The command at ${file} is missing a required "data" or "execute" property or is not enabled`)
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
client.on(Events.InteractionCreate, async interaction => {
|
client.on(Events.InteractionCreate, async interaction => {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
@@ -28,7 +72,7 @@ client.on(Events.InteractionCreate, async interaction => {
|
|||||||
const command = interaction.client.commands.get(interaction.commandName);
|
const command = interaction.client.commands.get(interaction.commandName);
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
console.error(`No command matching ${interaction.commandName} was found.`);
|
logger.error(`No command matching ${interaction.commandName} was found`)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,13 +80,214 @@ client.on(Events.InteractionCreate, async interaction => {
|
|||||||
await command.execute(interaction);
|
await command.execute(interaction);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(error);
|
logger.error(error)
|
||||||
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
|
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
client.on(Events.GuildCreate, async guild => {
|
||||||
|
if (guild.available) {
|
||||||
|
logger.info(`Got into a server, ${guild.name}, ${guild.id}, ${guild.description}`)
|
||||||
|
|
||||||
|
sqlutil.registerServerIfMissing(guild.id, guild.name, guild.description).then(server_added => {
|
||||||
|
if(server_added) {
|
||||||
|
logger.info(`Server Added ${guild.name}`)
|
||||||
|
} else {
|
||||||
|
logger.error(`Server failed to add ${guild.name}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on(Events.VoiceStateUpdate, async (oldState, newState) => {
|
||||||
|
logger.info("Voice State Update Fired")
|
||||||
|
|
||||||
|
if (oldState.channel == null && newState.channel != null) {
|
||||||
|
if (newState.member.id == client.user.id) {
|
||||||
|
return //If the user is breadbot, ignore and exit
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`Channel Join Detected ${newState.guild.id} - ${newState.channelId} - ${newState.member.id}`)
|
||||||
|
|
||||||
|
//TODO Nothing should happen after this if the channel fails to register
|
||||||
|
await sqlutil.registerChannelIfMissing(newState.channel.id, newState.guild.id, newState.channel.name)
|
||||||
|
|
||||||
|
var existingCallID = await sqlutil.inCall(newState.guild.id, newState.channelId)
|
||||||
|
|
||||||
|
logger.info(`Existing call ID ${existingCallID}`)
|
||||||
|
|
||||||
|
if (existingCallID == -1) {
|
||||||
|
logger.info("Joining a call")
|
||||||
|
|
||||||
|
var newCallID = await sqlutil.registerNewCall(newState.guild.id, newState.channelId, new Date())
|
||||||
|
existingCallID = newCallID // To ensure all the stuff that happens after call creation works
|
||||||
|
|
||||||
|
logger.info(`Next call ID ${newCallID}`)
|
||||||
|
|
||||||
|
fs.mkdirSync(media_voice_folder + path.sep + newCallID, {recursive: true})
|
||||||
|
|
||||||
|
const connection = joinVoiceChannel({
|
||||||
|
channelId: newState.channelId,
|
||||||
|
guildId: newState.guild.id,
|
||||||
|
selfDeaf: false,
|
||||||
|
selfMute: true,
|
||||||
|
adapterCreator: newState.guild.voiceAdapterCreator
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
await entersState(connection, VoiceConnectionStatus.Ready, 20e3)
|
||||||
|
const receiver = connection.receiver
|
||||||
|
|
||||||
|
if (receiver.speaking.listenerCount("start") == 0) {
|
||||||
|
receiver.speaking.on("start", (user_id) => {
|
||||||
|
if(!receiver.subscriptions.has(user_id)) {
|
||||||
|
receiver.subscribe(user_id, {
|
||||||
|
end: {
|
||||||
|
behavior: EndBehaviorType.AfterSilence,
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.pipe(new prism.opus.OggLogicalBitstream({
|
||||||
|
opusHead: new prism.opus.OpusHead({
|
||||||
|
channelCount: 2,
|
||||||
|
sampleRate: 48000
|
||||||
|
}),
|
||||||
|
pageSizeControl: {
|
||||||
|
maxPackets: 10
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.pipe(fs.createWriteStream(media_voice_folder + path.sep + newCallID + path.sep + `${Date.now()}-${user_id}.ogg`))
|
||||||
|
} else {
|
||||||
|
logger.warn(`Attempted to create new user subscriber for ${user_id} even though one already exists, receiver arm if statement protected against this`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
receiver.speaking.on("end", (user_id) => {
|
||||||
|
logger.info(`User ${user_id} stopped speaking`)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.warn("Attempted to create a new start and end listener for users who are speaking for some reason, receiver armor if statement protected against this")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var userRegistered = await sqlutil.registerUserIfMissing(newState.member.id, newState.member.username, newState.member.displayName)
|
||||||
|
|
||||||
|
if (userRegistered) {
|
||||||
|
var markedUserInCall = await sqlutil.registerUserInCall(existingCallID, newState.member.id)
|
||||||
|
|
||||||
|
if (!markedUserInCall) {
|
||||||
|
logger.error(`Something went wrong when marking user in voice call: ${newState.member.id} - ${newState.channelId}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error(`Something went wrong when registering user for call: ${newState.member.id} - ${newState.member.username}`)
|
||||||
|
}
|
||||||
|
} else if (oldState.channel != null && newState.channel == null) {
|
||||||
|
if (oldState.member.id == client.user.id) {
|
||||||
|
return //If the user is breadbot, ignore and exit
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`Channel Exit Detected ${oldState.guild.id} - ${oldState.channelId} - ${oldState.member.id}`)
|
||||||
|
|
||||||
|
var existingCallID = await sqlutil.inCall(oldState.guild.id, oldState.channelId)
|
||||||
|
|
||||||
|
logger.info(`Existing call ID ${existingCallID}`)
|
||||||
|
|
||||||
|
if (existingCallID != -1) {
|
||||||
|
await sqlutil.deregisterUserInCall(existingCallID, oldState.member.id)
|
||||||
|
|
||||||
|
var usersInCall = await sqlutil.getNumberUsersInCall(existingCallID)
|
||||||
|
|
||||||
|
if (usersInCall == 0) {
|
||||||
|
const connection = getVoiceConnection(oldState.guild.id)
|
||||||
|
connection.disconnect()
|
||||||
|
|
||||||
|
var didUpdateEndTime = await sqlutil.updateCallEndTime(existingCallID, new Date())
|
||||||
|
|
||||||
|
if (!didUpdateEndTime) {
|
||||||
|
logger.error(`Failed to mark call ID ${existingCallID} as ended with an end date`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Couldn't find a call ID based on the guild and channel info, was Breadbot in the call?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on(Events.MessageCreate, async message => {
|
||||||
|
console.info("Message Create Fired")
|
||||||
|
|
||||||
|
var channel_ok = await sqlutil.registerChannelIfMissing(message.channelId, message.channel.guild.id, message.channel.name)
|
||||||
|
var user_ok = await sqlutil.registerUserIfMissing(message.author.id, message.author.username, message.author.displayName)
|
||||||
|
|
||||||
|
logger.info(`Channel Ok? ${channel_ok} User OK? ${user_ok}`)
|
||||||
|
|
||||||
|
if (channel_ok && user_ok) {
|
||||||
|
await sqlutil.registerMessage(message.id, message.channelId, message.author.id, message.content, message.createdAt).then(async message_add => {
|
||||||
|
if(message_add) {
|
||||||
|
logger.info("Message Added")
|
||||||
|
|
||||||
|
if (message.attachments.size != 0) {
|
||||||
|
const all_attachments = message.attachments.map(attachment => sqlutil.registerAttachmentIfMissing(
|
||||||
|
attachment.id,
|
||||||
|
message.id,
|
||||||
|
attachment.name,
|
||||||
|
attachment.description,
|
||||||
|
message.createdAt,
|
||||||
|
attachment.contentType,
|
||||||
|
attachment.url
|
||||||
|
))
|
||||||
|
|
||||||
|
await Promise.all(all_attachments).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Failed to log message")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on(Events.MessageUpdate, async (oldMessage, newMessage) => {
|
||||||
|
logger.info("Message Update Fired")
|
||||||
|
logger.info(`Old Message Snowflake: ${oldMessage.id} New Message Snowflake: ${newMessage.id}`)
|
||||||
|
|
||||||
|
var editTime = newMessage.editedAt
|
||||||
|
|
||||||
|
if (editTime == null) {
|
||||||
|
editTime = newMessage.createdAt
|
||||||
|
}
|
||||||
|
|
||||||
|
await sqlutil.updateMessageContentIfPresent(newMessage.id, newMessage.content, editTime).then(async (updated) => {
|
||||||
|
if (updated) {
|
||||||
|
if (newMessage.attachments.size != 0) {
|
||||||
|
const all_attachments = newMessage.attachments.map(attachment => sqlutil.registerAttachmentIfMissing(
|
||||||
|
attachment.id,
|
||||||
|
newMessage.id,
|
||||||
|
attachment.name,
|
||||||
|
attachment.description,
|
||||||
|
editTime,
|
||||||
|
attachment.contentType,
|
||||||
|
attachment.url
|
||||||
|
))
|
||||||
|
|
||||||
|
await Promise.all(all_attachments).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on(Events.MessageDelete, async deletedMessage => {
|
||||||
|
await sqlutil.markMessageDeletedIfPresent(deletedMessage.id)
|
||||||
|
})
|
||||||
|
|
||||||
client.once(Events.ClientReady, c => {
|
client.once(Events.ClientReady, c => {
|
||||||
console.log(`Ready! Logged in as ${c.user.tag}`);
|
logger.info(`Ready! Logged in as ${c.user.tag} - ${c.user.id}`)
|
||||||
});
|
});
|
||||||
|
|
||||||
client.login(token);
|
client.login(token);
|
||||||
33
calendarpulltest.js
Normal file
33
calendarpulltest.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
const { google } = require('googleapis');
|
||||||
|
const { googlePrivateKey, googleClientEmail, googleProjectNumber } = require('./config.json');
|
||||||
|
|
||||||
|
const SCOPES = ['https://www.googleapis.com/auth/calendar'];
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const jwtClient = new google.auth.JWT(
|
||||||
|
googleClientEmail,
|
||||||
|
null,
|
||||||
|
googlePrivateKey,
|
||||||
|
SCOPES,
|
||||||
|
);
|
||||||
|
|
||||||
|
const calendar = new google.calendar({
|
||||||
|
version: 'v3',
|
||||||
|
project: googleProjectNumber,
|
||||||
|
auth: jwtClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
calendar.calendarList.list({}, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
console.log('[ERROR]');
|
||||||
|
console.log(err.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(res.data.items.map(x => x.summary + '---' + x.timeZone));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
37
commands/googlecalendar/addcalendar.js
Normal file
37
commands/googlecalendar/addcalendar.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
|
||||||
|
const { addCalendar } = require('../../utilities/googlecalendar.js');
|
||||||
|
// const { getTimeZones } = require('@vvo/tzdb');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('addcalendar')
|
||||||
|
.setDescription('Creates a new Google Calendar')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option
|
||||||
|
.setName('name')
|
||||||
|
.setDescription('The new name for the calendar')
|
||||||
|
.setRequired(true))
|
||||||
|
.addStringOption(option =>
|
||||||
|
option
|
||||||
|
.setName('timezone')
|
||||||
|
.setDescription('The Time Zone of this new calendar, must be in IANA format')
|
||||||
|
.setRequired(true)),
|
||||||
|
// .addChoices(getTimeZones().map(tz => {
|
||||||
|
// return { name: tz.name, value: tz.name };
|
||||||
|
// }))),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
|
const name = interaction.options.getString('name');
|
||||||
|
const timezone = interaction.options.getString('timezone');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
addCalendar(name, timezone, async (success, message, extra) => {
|
||||||
|
const embedResponse = new EmbedBuilder()
|
||||||
|
.setColor(success ? 0x00FF00 : 0xFF0000)
|
||||||
|
.setTitle(message);
|
||||||
|
|
||||||
|
await interaction.editReply({ embeds: [ embedResponse ] });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
0
commands/googlecalendar/addevent.js
Normal file
0
commands/googlecalendar/addevent.js
Normal file
27
commands/googlecalendar/deletecalendar.js
Normal file
27
commands/googlecalendar/deletecalendar.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
|
||||||
|
const { deleteCalendar } = require('../../utilities/googlecalendar.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('deletecalendar')
|
||||||
|
.setDescription('Permanently deletes a calendar and it\'s associated events')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option
|
||||||
|
.setName('name')
|
||||||
|
.setDescription('The name of the calendar you want to delete')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
|
const name = interaction.options.getString('name');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
deleteCalendar(name, async (success, message, extra) => {
|
||||||
|
const embedResponse = new EmbedBuilder()
|
||||||
|
.setColor(success ? 0x0FF00 : 0xFF0000)
|
||||||
|
.setTitle(message);
|
||||||
|
|
||||||
|
await interaction.editReply({ embeds: [ embedResponse ] });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
0
commands/googlecalendar/deleteevent.js
Normal file
0
commands/googlecalendar/deleteevent.js
Normal file
20
commands/googlecalendar/listcalendar.js
Normal file
20
commands/googlecalendar/listcalendar.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
|
||||||
|
const { getListOfCalendars } = require('../../utilities/googlecalendar');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('listcalendars')
|
||||||
|
.setDescription('Lists the currently available calendars'),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
|
getListOfCalendars({}, async (success, message, extra) => {
|
||||||
|
const embedResponse = new EmbedBuilder()
|
||||||
|
.setColor(success ? 0x00FF00 : 0xFF0000)
|
||||||
|
.setTitle(message)
|
||||||
|
.setDescription(extra.map(x => x.summary + ' --- ' + x.timeZone).join('\n\n'));
|
||||||
|
|
||||||
|
await interaction.editReply({ embeds: [ embedResponse ] });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
0
commands/googlecalendar/listevents.js
Normal file
0
commands/googlecalendar/listevents.js
Normal file
0
commands/googlecalendar/modifyevent.js
Normal file
0
commands/googlecalendar/modifyevent.js
Normal file
@@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
const { SlashCommandBuilder } = require('discord.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
enabled: true,
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('ping')
|
.setName('ping')
|
||||||
.setDescription('Replies with Pong!'),
|
.setDescription('Replies with Pong!'),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
const { SlashCommandBuilder } = require('discord.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
enabled: true,
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('server')
|
.setName('server')
|
||||||
.setDescription('Provides information about the server.'),
|
.setDescription('Provides information about the server.'),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
const { SlashCommandBuilder } = require('discord.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
enabled: true,
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('user')
|
.setName('user')
|
||||||
.setDescription('Provides information about the user.'),
|
.setDescription('Provides information about the user.'),
|
||||||
|
|||||||
178
database_generator.sql
Normal file
178
database_generator.sql
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
-- --------------------------------------------------------
|
||||||
|
-- Host: 192.168.1.196
|
||||||
|
-- Server version: 8.0.33 - MySQL Community Server - GPL
|
||||||
|
-- Server OS: Linux
|
||||||
|
-- HeidiSQL Version: 12.5.0.6677
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET NAMES utf8 */;
|
||||||
|
/*!50503 SET NAMES utf8mb4 */;
|
||||||
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Dumping database structure for breadbot_test
|
||||||
|
CREATE DATABASE IF NOT EXISTS `breadbot_test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
|
||||||
|
USE `breadbot_test`;
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.call_states
|
||||||
|
CREATE TABLE IF NOT EXISTS `call_states` (
|
||||||
|
`call_id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`server_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`channel_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`call_start_time` datetime NOT NULL,
|
||||||
|
`call_end_time` datetime DEFAULT NULL,
|
||||||
|
`call_consolidated` bit(1) NOT NULL DEFAULT (0),
|
||||||
|
`call_transcribed` bit(1) NOT NULL DEFAULT (0),
|
||||||
|
`call_data_cleaned_up` bit(1) NOT NULL DEFAULT (0),
|
||||||
|
PRIMARY KEY (`call_id`),
|
||||||
|
KEY `fk_snowflake_recording_to_server` (`server_snowflake`),
|
||||||
|
KEY `fk_snowflake_recording_to_channel` (`channel_snowflake`),
|
||||||
|
CONSTRAINT `fk_snowflake_recording_to_channel` FOREIGN KEY (`channel_snowflake`) REFERENCES `channels` (`channel_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `fk_snowflake_recording_to_server` FOREIGN KEY (`server_snowflake`) REFERENCES `servers` (`server_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.call_transcriptions
|
||||||
|
CREATE TABLE IF NOT EXISTS `call_transcriptions` (
|
||||||
|
`transcription_id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`call_id` int NOT NULL,
|
||||||
|
`user_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`speaking_start_time` datetime NOT NULL,
|
||||||
|
`text` longtext NOT NULL,
|
||||||
|
PRIMARY KEY (`transcription_id`),
|
||||||
|
KEY `fk_call_id_states_to_transcriptions` (`call_id`),
|
||||||
|
KEY `fk_snowflake_call_states_to_users` (`user_snowflake`),
|
||||||
|
CONSTRAINT `fk_call_id_states_to_transcriptions` FOREIGN KEY (`call_id`) REFERENCES `call_states` (`call_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `fk_snowflake_call_states_to_users` FOREIGN KEY (`user_snowflake`) REFERENCES `users` (`user_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.call_users
|
||||||
|
CREATE TABLE IF NOT EXISTS `call_users` (
|
||||||
|
`call_users_id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`call_id` int NOT NULL,
|
||||||
|
`user_snowflake` bigint unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`call_users_id`) USING BTREE,
|
||||||
|
KEY `fk_call_id_call_user_to_state` (`call_id`),
|
||||||
|
KEY `fk_snowflake_call_user_to_users` (`user_snowflake`),
|
||||||
|
CONSTRAINT `fk_call_id_call_user_to_state` FOREIGN KEY (`call_id`) REFERENCES `call_states` (`call_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `fk_snowflake_call_user_to_users` FOREIGN KEY (`user_snowflake`) REFERENCES `users` (`user_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.channels
|
||||||
|
CREATE TABLE IF NOT EXISTS `channels` (
|
||||||
|
`channel_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`server_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`channel_name` text,
|
||||||
|
PRIMARY KEY (`channel_snowflake`),
|
||||||
|
KEY `fk_snowflake_channel_to_server` (`server_snowflake`),
|
||||||
|
CONSTRAINT `fk_snowflake_channel_to_server` FOREIGN KEY (`server_snowflake`) REFERENCES `servers` (`server_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.messages
|
||||||
|
CREATE TABLE IF NOT EXISTS `messages` (
|
||||||
|
`message_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`channel_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`user_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`message_content` text NOT NULL,
|
||||||
|
`message_timestamp` datetime NOT NULL,
|
||||||
|
`message_deleted` bit(1) NOT NULL DEFAULT (0),
|
||||||
|
PRIMARY KEY (`message_snowflake`),
|
||||||
|
KEY `fk_snowflake_message_to_channel` (`channel_snowflake`),
|
||||||
|
KEY `fk_snowflake_message_to_user` (`user_snowflake`),
|
||||||
|
CONSTRAINT `fk_snowflake_message_to_channel` FOREIGN KEY (`channel_snowflake`) REFERENCES `channels` (`channel_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `fk_snowflake_message_to_user` FOREIGN KEY (`user_snowflake`) REFERENCES `users` (`user_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.message_attachments
|
||||||
|
CREATE TABLE IF NOT EXISTS `message_attachments` (
|
||||||
|
`attachment_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`message_snowflake` bigint unsigned NOT NULL DEFAULT (0),
|
||||||
|
`attachment_name` text NOT NULL,
|
||||||
|
`attachment_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
|
||||||
|
`attachment_timestamp` datetime NOT NULL,
|
||||||
|
`attachment_mime_type` tinytext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
|
||||||
|
`attachment_url` text NOT NULL,
|
||||||
|
`attachment_downloaded` bit(1) NOT NULL DEFAULT (0),
|
||||||
|
PRIMARY KEY (`attachment_snowflake`) USING BTREE,
|
||||||
|
KEY `fk_snowflake_messages_to_attachments` (`message_snowflake`),
|
||||||
|
CONSTRAINT `fk_snowflake_messages_to_attachments` FOREIGN KEY (`message_snowflake`) REFERENCES `messages` (`message_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.message_content_changes
|
||||||
|
CREATE TABLE IF NOT EXISTS `message_content_changes` (
|
||||||
|
`message_change_id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`message_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`message_change_old_timestamp` datetime NOT NULL,
|
||||||
|
`message_change_old_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`message_change_id`),
|
||||||
|
KEY `fk_snowflake_message_to_message_changes` (`message_snowflake`),
|
||||||
|
CONSTRAINT `fk_snowflake_message_to_message_changes` FOREIGN KEY (`message_snowflake`) REFERENCES `messages` (`message_snowflake`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.servers
|
||||||
|
CREATE TABLE IF NOT EXISTS `servers` (
|
||||||
|
`server_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`server_name` text NOT NULL,
|
||||||
|
`server_description` mediumtext,
|
||||||
|
PRIMARY KEY (`server_snowflake`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.users
|
||||||
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
|
`user_snowflake` bigint unsigned NOT NULL,
|
||||||
|
`user_name` text NOT NULL,
|
||||||
|
`user_displayname` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
|
||||||
|
PRIMARY KEY (`user_snowflake`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.winston_breadbot
|
||||||
|
CREATE TABLE IF NOT EXISTS `winston_breadbot` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`level` varchar(16) NOT NULL,
|
||||||
|
`message` varchar(2048) NOT NULL,
|
||||||
|
`meta` varchar(2048) NOT NULL,
|
||||||
|
`timestamp` datetime NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
-- Dumping structure for table breadbot_test.winston_sqlutil
|
||||||
|
CREATE TABLE IF NOT EXISTS `winston_sqlutil` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`level` varchar(16) NOT NULL,
|
||||||
|
`message` varchar(2048) NOT NULL,
|
||||||
|
`meta` varchar(2048) NOT NULL,
|
||||||
|
`timestamp` datetime NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
|
||||||
|
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
|
||||||
35
datetesting.js
Normal file
35
datetesting.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const readline = require('readline');
|
||||||
|
|
||||||
|
const r1 = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
terminal: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let date1 = null;
|
||||||
|
let date2 = null;
|
||||||
|
let result = null;
|
||||||
|
|
||||||
|
r1.on('line', line => {
|
||||||
|
if (line.startsWith('date1')) {
|
||||||
|
date1 = new Date(line.split(':')[1]);
|
||||||
|
}
|
||||||
|
else if (line.startsWith('date2')) {
|
||||||
|
date2 = new Date(line.split(':')[1]);
|
||||||
|
}
|
||||||
|
else if (line.startsWith('result')) {
|
||||||
|
if (date1 !== null && date2 !== null) {
|
||||||
|
result = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate(),
|
||||||
|
date2.getHours(), date2.getMinutes(), date2.getSeconds());
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('Bad command');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
r1.once('close', () => {
|
||||||
|
console.log('Closing');
|
||||||
|
});
|
||||||
@@ -1,15 +1,43 @@
|
|||||||
const { REST, Routes } = require('discord.js');
|
const { REST, Routes } = require('discord.js');
|
||||||
const { clientId, guildId, token } = require('./config.json');
|
const { clientId, guildId, token } = require('./config.json');
|
||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const getAllFiles = function(directoryPath, arrayOfFiles) {
|
||||||
|
const files = fs.readdirSync(directoryPath);
|
||||||
|
|
||||||
|
arrayOfFiles = arrayOfFiles || [];
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
if (fs.statSync(directoryPath + path.sep + file).isDirectory()) {
|
||||||
|
arrayOfFiles = getAllFiles(directoryPath + path.sep + file, arrayOfFiles);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arrayOfFiles.push(path.join(__dirname, directoryPath, path.sep, file));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return arrayOfFiles;
|
||||||
|
};
|
||||||
|
|
||||||
const commands = [];
|
const commands = [];
|
||||||
|
const allFiles = [];
|
||||||
|
getAllFiles('.' + path.sep + 'commands', allFiles);
|
||||||
|
allFiles.forEach(file => {
|
||||||
|
console.log(file);
|
||||||
|
});
|
||||||
// Grab all the command files from the commands directory you created earlier
|
// Grab all the command files from the commands directory you created earlier
|
||||||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
|
const commandFiles = allFiles.filter(file => file.endsWith('.js'));
|
||||||
|
|
||||||
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
|
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
|
||||||
for (const file of commandFiles) {
|
for (const file of commandFiles) {
|
||||||
const command = require(`./commands/${file}`);
|
const command = require(`${file}`);
|
||||||
commands.push(command.data.toJSON());
|
if ('enabled' in command && command.enabled && 'data' in command && 'execute' in command) {
|
||||||
|
commands.push(command.data.toJSON());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(`Skipping ${file} as it is missing one or more required exported fields`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct and prepare an instance of the REST module
|
// Construct and prepare an instance of the REST module
|
||||||
|
|||||||
3007
package-lock.json
generated
3007
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -9,8 +9,18 @@
|
|||||||
"author": "Bradley Bickford",
|
"author": "Bradley Bickford",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@discordjs/opus": "^0.9.0",
|
||||||
|
"@discordjs/voice": "^0.16.0",
|
||||||
|
"@vvo/tzdb": "^6.77.0",
|
||||||
"discord.js": "^14.6.0",
|
"discord.js": "^14.6.0",
|
||||||
"googleapis": "^109.0.1"
|
"googleapis": "^109.0.1",
|
||||||
|
"libsodium-wrappers": "^0.7.13",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"mysql2": "^3.6.3",
|
||||||
|
"node-crc": "1.3.2",
|
||||||
|
"prism-media": "^2.0.0-alpha.0",
|
||||||
|
"winston": "^3.11.0",
|
||||||
|
"winston-mysql": "^1.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.27.0"
|
"eslint": "^8.27.0"
|
||||||
|
|||||||
18
promise_chain_test.js
Normal file
18
promise_chain_test.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const mysql = require('mysql2')
|
||||||
|
const { mysql_username, mysql_password } = require('./config.json')
|
||||||
|
|
||||||
|
var connection_pool = mysql.createPool({
|
||||||
|
host: "10.26.48.207",
|
||||||
|
user: mysql_username,
|
||||||
|
password: mysql_password,
|
||||||
|
database: 'breadbot_test',
|
||||||
|
connectionLimit: 10
|
||||||
|
}).promise()
|
||||||
|
|
||||||
|
connection_pool.query("SELECT * FROM servers").then(async ([rows, fields]) => {
|
||||||
|
console.log(rows)
|
||||||
|
return await connection_pool.query("SELECT * FROM channels").then(([rows, fields]) => {
|
||||||
|
console.log(rows)
|
||||||
|
return "SOME TEXT"
|
||||||
|
})
|
||||||
|
}).catch(() => {return "SOME FAIL TEXT"}).then(console.log)
|
||||||
122
utilities/googlecalendar.js
Normal file
122
utilities/googlecalendar.js
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
const { google } = require('googleapis');
|
||||||
|
const { googlePrivateKey, googleClientEmail, googleProjectNumber } = require('../config.json');
|
||||||
|
const { stdout } = require('node:process');
|
||||||
|
const SCOPES = ['https://www.googleapis.com/auth/calendar'];
|
||||||
|
|
||||||
|
async function getCalendarReference() {
|
||||||
|
const jwtClient = new google.auth.JWT(
|
||||||
|
googleClientEmail,
|
||||||
|
'../keyfile.json',
|
||||||
|
googlePrivateKey,
|
||||||
|
SCOPES,
|
||||||
|
);
|
||||||
|
|
||||||
|
return new google.calendar({
|
||||||
|
version: 'v3',
|
||||||
|
project: googleProjectNumber,
|
||||||
|
auth: jwtClient,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doesCalendarExist(calendarName) {
|
||||||
|
const calendarReference = await getCalendarReference();
|
||||||
|
const listResults = await calendarReference.calendarList.list({});
|
||||||
|
|
||||||
|
for (const item of listResults.data.items) {
|
||||||
|
if (item.summary === calendarName) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getListOfCalendars(options, callback) {
|
||||||
|
const calendarReference = await getCalendarReference();
|
||||||
|
calendarReference.calendarList.list(options, async (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
callback(false, 'Failed to retrieve the list of calendars\nAsk Bradley to check Breadbot console');
|
||||||
|
stdout.write('[ERROR]:');
|
||||||
|
console.log(err.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(true, 'Calendar List', res.data.items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addCalendar(calendarName, timezone, callback) {
|
||||||
|
const calendarReference = await getCalendarReference();
|
||||||
|
calendarReference.calendars.insert({
|
||||||
|
resource: {
|
||||||
|
summary: calendarName,
|
||||||
|
timeZone: timezone,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
async (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
callback(false, 'Failed to create new calendar ' + calendarName + '\nAsk Bradley to check Breadbat console', err);
|
||||||
|
stdout.write('[ERROR]: ');
|
||||||
|
console.log(err.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(true, 'Successfully created new calendar ' + calendarName, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteCalendar(calendarName, callback) {
|
||||||
|
const exists = await doesCalendarExist(calendarName);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
const calendarReference = await getCalendarReference();
|
||||||
|
calendarReference.calendars.delete({
|
||||||
|
calendarId: exists.id,
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
async (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
callback(false, 'Failed to delete ' + calendarName + '\nAsk Bradley to check Breadbot console', err);
|
||||||
|
stdout.write('[ERROR]: ');
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(true, 'Successfully deleted ' + calendarName, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(false, 'The calendar name specified doesn\'t exist', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addEvent(calendarName, eventName, location, description, startDate, startTime, endDate, endTime) {
|
||||||
|
const exists = await doesCalendarExist(calendarName);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
const calendarReference = await getCalendarReference();
|
||||||
|
calendarReference.events.insert({
|
||||||
|
calendarId: exists.id,
|
||||||
|
resource: {
|
||||||
|
summary: eventName,
|
||||||
|
location: location,
|
||||||
|
description: description,
|
||||||
|
start: {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(false, 'The calendar name specified doesn\'t exist', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getCalendarReference,
|
||||||
|
getListOfCalendars,
|
||||||
|
doesCalendarExist,
|
||||||
|
deleteCalendar,
|
||||||
|
addCalendar,
|
||||||
|
};
|
||||||
241
utilities/sqlutil.js
Normal file
241
utilities/sqlutil.js
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
const mysql = require('mysql2')
|
||||||
|
const winston = require('winston')
|
||||||
|
const winston_mysql = require('winston-mysql')
|
||||||
|
const {
|
||||||
|
mysql_username,
|
||||||
|
mysql_password,
|
||||||
|
mysql_host,
|
||||||
|
mysql_db_name,
|
||||||
|
sqlutil_logging_config
|
||||||
|
} = require('../config.json')
|
||||||
|
|
||||||
|
var connection_pool = null
|
||||||
|
var logger = null
|
||||||
|
|
||||||
|
async function buildPool() {
|
||||||
|
if (connection_pool == null) {
|
||||||
|
connection_pool = mysql.createPool({
|
||||||
|
host: mysql_host,
|
||||||
|
user: mysql_username,
|
||||||
|
password: mysql_password,
|
||||||
|
database: mysql_db_name,
|
||||||
|
connectionLimit: 10,
|
||||||
|
multipleStatements: true
|
||||||
|
}).promise()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger == null) {
|
||||||
|
logger = winston.createLogger({
|
||||||
|
level: "silly",
|
||||||
|
transports: [
|
||||||
|
new winston.transports.Console({
|
||||||
|
format: winston.format.simple(),
|
||||||
|
level: sqlutil_logging_config["console_log_level"]
|
||||||
|
}),
|
||||||
|
new winston_mysql({
|
||||||
|
level: sqlutil_logging_config["sql_log_level"],
|
||||||
|
host: sqlutil_logging_config["mysql_host"],
|
||||||
|
user: sqlutil_logging_config["mysql_username"],
|
||||||
|
password: sqlutil_logging_config["mysql_password"],
|
||||||
|
database: sqlutil_logging_config["mysql_db_name"],
|
||||||
|
table: sqlutil_logging_config["mysql_table_name"]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerServerIfMissing(server_snowflake, server_name, server_description) {
|
||||||
|
return connection_pool.query("SELECT * FROM servers WHERE server_snowflake = ?;", [server_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length != 0) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return await connection_pool.query("INSERT INTO servers VALUES (?, ?, ?)", [server_snowflake, server_name, server_description]).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerChannelIfMissing(channel_snowflake, server_snowflake, channel_name) {
|
||||||
|
return connection_pool.query("SELECT * FROM channels WHERE channel_snowflake = ?;", [channel_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length != 0) {+
|
||||||
|
logger.info("Channel already registered")
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
logger.info("Channel Not registered, registering")
|
||||||
|
return await connection_pool.query("INSERT INTO channels VALUES (?, ?, ?)", [channel_snowflake, server_snowflake, channel_name]).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateMessageContentIfPresent(message_snowflake, message_content, message_timestamp) {
|
||||||
|
return connection_pool.query("SELECT message_snowflake FROM messages WHERE message_snowflake = ?", [message_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length == 0) {
|
||||||
|
logger.info("Message specified doesn't exist, probably created before breadbot was here")
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return await connection_pool.query(
|
||||||
|
"INSERT INTO message_content_changes (message_snowflake, message_change_old_timestamp, message_change_old_content) " +
|
||||||
|
"SELECT message_snowflake, message_timestamp, message_content FROM messages WHERE message_snowflake = ?;" +
|
||||||
|
"UPDATE messages SET message_timestamp = ?, message_content = ? WHERE message_snowflake = ?;",
|
||||||
|
[message_snowflake, message_timestamp, message_content, message_snowflake]
|
||||||
|
).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function markMessageDeletedIfPresent(message_snowflake) {
|
||||||
|
return connection_pool.query("SELECT message_snowflake FROM messages WHERE message_snowflake = ?", [message_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length == 0) {
|
||||||
|
logger.info("Message specified doesn't exists, probably created before breadbot was here")
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return await connection_pool.query(
|
||||||
|
"UPDATE messages SET message_deleted = 1 WHERE message_snowflake = ?", [message_snowflake]
|
||||||
|
).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerAttachmentIfMissing(attachment_snowflake, message_snowflake, attachment_name, attachment_description, attachment_timestamp, attachment_mime_type, attachment_url) {
|
||||||
|
return connection_pool.query("SELECT attachment_snowflake FROM message_attachments WHERE attachment_snowflake = ?", [attachment_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length != 0) {
|
||||||
|
logger.info("Attachment alreaedy exists")
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return await connection_pool.query(
|
||||||
|
"INSERT INTO message_attachments (attachment_snowflake, message_snowflake, attachment_name, attachment_description, attachment_timestamp, attachment_mime_type, attachment_url) " +
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
[attachment_snowflake, message_snowflake, attachment_name, attachment_description, attachment_timestamp, attachment_mime_type, attachment_url]
|
||||||
|
).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerUserIfMissing(user_snowflake, user_name, user_displayname) {
|
||||||
|
return connection_pool.query("SELECT * FROM users WHERE user_snowflake = ?;", [user_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length != 0) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return await connection_pool.query("INSERT INTO users VALUES (?, ?, ?)", [user_snowflake, user_name, user_displayname]).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerMessage(message_snowflake, channel_snowflake, user_snowflake, message_content, message_timestamp) {
|
||||||
|
return connection_pool.query("INSERT INTO messages VALUES (?, ?, ?, ?, ?, 0)", [message_snowflake, channel_snowflake, user_snowflake, message_content, message_timestamp]).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function inCall(server_snowflake, channel_snowflake) {
|
||||||
|
return connection_pool.query("SELECT call_id FROM call_states WHERE server_snowflake = ? AND channel_snowflake = ? AND call_end_time IS NULL", [server_snowflake, channel_snowflake]).then(async ([rows, fields]) => {
|
||||||
|
if (rows.length == 0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return rows[0].call_id
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return -1;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerNewCall(server_snowflake, channel_snowflake, call_start_time) {
|
||||||
|
return connection_pool.query("INSERT INTO call_states (server_snowflake, channel_snowflake, call_start_time, call_end_time, call_consolidated, call_transcribed, call_data_cleaned_up) VALUES (?, ?, ?, NULL, 0, 0, 0)", [server_snowflake, channel_snowflake, call_start_time]).then(async ([rows, fields]) => {
|
||||||
|
if (typeof rows.insertId === 'undefined') {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return rows.insertId
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return -1;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerUserInCall(call_id, user_snowflake) {
|
||||||
|
return connection_pool.query("INSERT INTO call_users (call_id, user_snowflake) VALUES (?, ?)", [call_id, user_snowflake]).then(([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deregisterUserInCall(call_id, user_snowflake) {
|
||||||
|
return connection_pool.query("DELETE FROM call_users WHERE call_id = ? AND user_snowflake = ?", [call_id, user_snowflake]).then(([rows, field]) => {
|
||||||
|
return true
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getNumberUsersInCall(call_id) {
|
||||||
|
return connection_pool.query("SELECT COUNT(call_users_id) AS users_in_call FROM call_users WHERE call_id = ?", [call_id]).then(([rows, fields]) => {
|
||||||
|
return rows[0].users_in_call
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return -1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateCallEndTime(call_id, call_end_time) {
|
||||||
|
return await connection_pool.query("UPDATE call_states SET call_end_time = ? WHERE call_id = ?", [call_end_time, call_id]).then(async ([rows, fields]) => {
|
||||||
|
return true
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.error(error)
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buildPool,
|
||||||
|
registerMessage,
|
||||||
|
registerServerIfMissing,
|
||||||
|
registerChannelIfMissing,
|
||||||
|
registerUserIfMissing,
|
||||||
|
registerNewCall,
|
||||||
|
updateCallEndTime,
|
||||||
|
inCall,
|
||||||
|
updateMessageContentIfPresent,
|
||||||
|
markMessageDeletedIfPresent,
|
||||||
|
registerAttachmentIfMissing,
|
||||||
|
registerUserInCall,
|
||||||
|
deregisterUserInCall,
|
||||||
|
getNumberUsersInCall
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user