2023-02-08 20:51:59 -05:00
import Discord , { Client , WebhookClient , GatewayIntentBits , Partials } from 'discord.js' ;
2022-11-13 08:46:50 -05:00
import fs from 'node:fs' ;
2023-02-24 19:55:11 -05:00
import { exec } from 'node:child_process' ;
2022-11-13 19:18:15 -05:00
import timeNames from './timeNames' ;
2023-02-24 19:55:11 -05:00
import mongoose from 'mongoose' ;
import { formatTimeOpt , Tokens , Config , repeatedMessages } from './typings/interfaces' ;
import bannedWords from './models/bannedWords' ;
import userLevels from './models/userLevels' ;
2023-02-26 23:31:16 -05:00
import suggestion from './models/suggestion' ;
2023-02-24 19:55:11 -05:00
import punishments from './models/punishments' ;
import bonkCount from './models/bonkCount' ;
2023-02-26 18:45:56 -05:00
import MPServer from './models/MPServer' ;
2022-12-18 23:22:28 -05:00
import axios from 'axios' ;
import moment from 'moment' ;
2022-12-29 05:10:13 -05:00
import tokens from './tokens.json' ;
2023-01-06 19:41:20 -05:00
let importconfig :Config
try {
2023-03-05 05:04:10 -05:00
importconfig = require ( './DB-Beta.config.json' )
console . log ( 'Using development config :: Daggerbot Beta' )
//importconfig = require('./Toast-Testbot.config.json')
//console.log('Using development config :: Toast-Testbot')
2023-01-06 19:41:20 -05:00
} catch ( e ) {
2023-03-05 05:04:10 -05:00
importconfig = require ( './config.json' )
console . log ( 'Using production config' )
2023-01-06 19:41:20 -05:00
}
2023-01-27 21:33:55 -05:00
export default class TClient extends Client {
2023-03-05 05:04:10 -05:00
invites : Map < any , any > ;
commands : Discord.Collection < string , any > ;
registry : Array < Discord.ApplicationCommandDataResolvable > ;
config : Config ;
tokens : Tokens ;
YTCache : any ;
embed : typeof Discord . EmbedBuilder ;
collection : any ;
messageCollector : any ;
attachmentBuilder : any ;
moment : typeof moment ;
xjs : any ;
axios : typeof axios ;
ms : any ;
userLevels : userLevels ;
punishments : punishments ;
bonkCount : bonkCount ;
bannedWords : bannedWords ;
MPServer : MPServer ;
suggestion : suggestion ;
repeatedMessages : repeatedMessages ;
statsGraph : number ;
2022-11-11 19:58:11 -05:00
2023-03-05 05:04:10 -05:00
constructor ( ) {
super ( {
intents : [
GatewayIntentBits . Guilds , GatewayIntentBits . GuildMembers ,
2023-03-12 18:04:32 -04:00
GatewayIntentBits . GuildModeration , GatewayIntentBits . GuildInvites ,
2023-03-05 05:04:10 -05:00
GatewayIntentBits . GuildPresences , GatewayIntentBits . MessageContent , GatewayIntentBits . GuildMessages
] ,
partials : [
Partials . Channel ,
Partials . Reaction ,
Partials . Message
] ,
allowedMentions : { users : [ ] , roles : [ ] }
} )
this . invites = new Map ( ) ;
this . commands = new Discord . Collection ( ) ;
this . registry = [ ] ;
this . config = importconfig as Config ;
this . tokens = tokens as Tokens ;
this . YTCache = {
'UCQ8k8yTDLITldfWYKDs3xFg' : undefined , // Daggerwin
'UCguI73--UraJpso4NizXNzA' : undefined // Machinery Restorer
2022-11-11 19:58:11 -05:00
}
2023-03-05 05:04:10 -05:00
this . embed = Discord . EmbedBuilder ;
this . collection = Discord . Collection ;
this . messageCollector = Discord . MessageCollector ;
this . attachmentBuilder = Discord . AttachmentBuilder ;
this . moment = moment ;
this . xjs = require ( 'xml-js' ) ;
this . axios = axios ;
this . ms = require ( 'ms' ) ;
this . userLevels = new userLevels ( this ) ;
this . bonkCount = new bonkCount ( this ) ;
this . punishments = new punishments ( this ) ;
this . bannedWords = new bannedWords ( this ) ;
this . MPServer = new MPServer ( this ) ;
this . suggestion = new suggestion ( this ) ;
this . repeatedMessages = { } ;
2023-03-18 04:21:07 -04:00
this . setMaxListeners ( 20 ) ;
2023-03-05 05:04:10 -05:00
this . statsGraph = - 60 ;
}
async init ( ) {
console . time ( 'Startup' ) ;
mongoose . set ( 'strictQuery' , true ) ;
await mongoose . connect ( this . tokens . mongodb_uri , {
replicaSet : 'toastyy' ,
autoIndex : true ,
keepAlive : true ,
serverSelectionTimeoutMS : 15000 ,
waitQueueTimeoutMS : 50000 ,
socketTimeoutMS : 30000 ,
family : 4
} ) . then ( ( ) = > console . log ( this . logTime ( ) , 'Successfully connected to MongoDB' ) ) . catch ( ( err ) = > { console . error ( this . logTime ( ) , ` Failed to connect to MongoDB \ n ${ err . reason } ` ) ; exec ( 'pm2 stop Daggerbot' ) } )
await this . login ( this . tokens . main ) ;
const commandFiles = fs . readdirSync ( 'src/commands' ) . filter ( file = > file . endsWith ( '.ts' ) ) ;
for ( const file of commandFiles ) {
const command = require ( ` ./commands/ ${ file } ` ) ;
this . commands . set ( command . default . data . name , command )
this . registry . push ( command . default . data . toJSON ( ) )
2022-11-11 19:58:11 -05:00
}
2023-03-05 05:04:10 -05:00
fs . readdirSync ( 'src/events' ) . forEach ( ( file ) = > {
const eventFile = require ( ` ./events/ ${ file } ` ) ;
this . on ( file . replace ( '.ts' , '' ) , async ( . . . args ) = > eventFile . default . run ( this , . . . args ) ) ;
} ) ;
}
formatTime ( integer : number , accuracy = 1 , options? : formatTimeOpt ) {
let achievedAccuracy = 0 ;
let text :any = '' ;
for ( const timeName of timeNames ) {
if ( achievedAccuracy < accuracy ) {
const fullTimelengths = Math . floor ( integer / timeName . length ) ;
if ( fullTimelengths == 0 ) continue ;
achievedAccuracy ++ ;
text += fullTimelengths + ( options ? . longNames ? ( ' ' + timeName . name + ( fullTimelengths === 1 ? '' : 's' ) ) : timeName . name . slice ( 0 , timeName . name === 'month' ? 2 : 1 ) ) + ( options ? . commas ? ', ' : ' ' ) ;
integer -= fullTimelengths * timeName . length ;
} else break ;
2022-11-11 19:58:11 -05:00
}
2023-03-05 05:04:10 -05:00
if ( text . length == 0 ) text = integer + ( options ? . longNames ? ' milliseconds' : 'ms' ) + ( options ? . commas ? ', ' : '' ) ;
if ( options ? . commas ) {
text = text . slice ( 0 , - 2 ) ;
if ( options ? . longNames ) {
text = text . split ( '' ) ;
text [ text . lastIndexOf ( ',' ) ] = ' and' ;
text = text . join ( '' ) ;
}
} return text . trim ( ) ;
}
isStaff = ( guildMember :Discord.GuildMember ) = > this . config . mainServer . staffRoles . map ( ( x : string ) = > this . config . mainServer . roles [ x ] ) . some ( ( x : string ) = > guildMember . roles . cache . has ( x ) ) ;
youNeedRole = ( interaction :Discord.CommandInteraction , role :string ) = > interaction . reply ( ` This command is restricted to <@& ${ this . config . mainServer . roles [ role ] } > ` ) ;
2022-12-01 17:53:57 -05:00
2023-03-05 05:04:10 -05:00
logTime = ( ) = > ` [ ${ this . moment ( ) . format ( 'DD/MM/YY HH:mm:ss' ) } ] ` ;
2022-12-01 17:53:57 -05:00
2023-03-05 05:04:10 -05:00
alignText ( text : string , length : number , alignment : string , emptyChar = ' ' ) {
if ( alignment == 'right' ) text = emptyChar . repeat ( length - text . length ) + text ;
else if ( alignment == 'middle' ) {
const emptyCharsPerSide = ( length - text . length ) / 2 ;
text = emptyChar . repeat ( Math . floor ( emptyCharsPerSide ) ) + text + emptyChar . repeat ( Math . floor ( emptyCharsPerSide ) ) ;
} else text = text + emptyChar . repeat ( length - text . length ) ;
return text ;
}
async punish ( client : TClient , interaction : Discord.ChatInputCommandInteraction < 'cached' > , type : string ) {
if ( ! client . isStaff ( interaction . member as Discord . GuildMember ) ) return client . youNeedRole ( interaction , "dcmod" ) ;
2022-12-03 18:35:14 -05:00
2023-03-05 05:04:10 -05:00
const time = interaction . options . getString ( 'time' ) ? ? undefined ;
const reason = interaction . options . getString ( 'reason' ) ? ? 'Reason unspecified' ;
const GuildMember = interaction . options . getMember ( 'member' ) ? ? undefined ;
const User = interaction . options . getUser ( 'member' , true ) ;
if ( interaction . user . id == User . id ) return interaction . reply ( ` You cannot ${ type } yourself. ` ) ;
if ( ! GuildMember && type != 'ban' ) return interaction . reply ( ` You cannot ${ type } someone who is not in the server. ` ) ;
if ( User . bot ) return interaction . reply ( ` You cannot ${ type } a bot! ` ) ;
await interaction . deferReply ( ) ;
await client . punishments . addPunishment ( type , { time , interaction } , interaction . user . id , reason , User , GuildMember ) ;
}
async YTLoop ( YTChannelID : string , YTChannelName : string , DCChannelID : string ) {
let Data :any ;
let error ;
try {
await this . axios . get ( ` https://www.youtube.com/feeds/videos.xml?channel_id= ${ YTChannelID } ` , { timeout : 5000 } ) . then ( ( xml :any ) = > Data = this . xjs . xml2js ( xml . data , { compact : true , spaces : 2 } ) )
} catch ( err ) {
error = true ;
console . log ( this . logTime ( ) , ` ${ YTChannelName } YT fail ` )
2022-11-13 08:46:50 -05:00
}
2022-11-17 12:58:19 -05:00
2023-03-05 05:04:10 -05:00
if ( ! Data ) return ;
if ( this . YTCache [ YTChannelID ] == undefined ) {
this . YTCache [ YTChannelID ] = Data . feed . entry [ 0 ] [ 'yt:videoId' ] . _text ;
return ;
2022-11-13 08:46:50 -05:00
}
2023-03-05 05:04:10 -05:00
if ( Data . feed . entry [ 1 ] [ 'yt:videoId' ] . _text == this . YTCache [ YTChannelID ] ) {
this . YTCache [ YTChannelID ] = Data . feed . entry [ 0 ] [ 'yt:videoId' ] . _text ;
( this . channels . resolve ( DCChannelID ) as Discord . TextChannel ) . send ( ` ** ${ YTChannelName } ** just uploaded a video! \ n ${ Data . feed . entry [ 0 ] . link . _attributes . href } ` )
}
}
2022-11-14 03:45:40 -05:00
}
2023-02-08 20:51:59 -05:00
2023-03-05 05:04:10 -05:00
export class WClient extends WebhookClient {
tokens : Tokens ;
constructor ( ) {
super ( {
url : tokens.webhook_url
} )
}
}
2023-02-08 20:51:59 -05:00
// hi tae, ik you went to look for secret hello msgs in here too.