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 {
importconfig = require ( './DB-Beta.config.json' )
console . log ( 'Using development config : Daggerbot Beta' )
2023-01-11 03:33:38 -05:00
//importconfig = require('./Toast-Testbot.config.json')
//console.log('Using development config : Toast-Testbot')
2023-01-06 19:41:20 -05:00
} catch ( e ) {
importconfig = require ( './config.json' )
console . log ( 'Using production config' )
}
2023-01-27 21:33:55 -05:00
export default class TClient extends Client {
2022-11-14 03:45:40 -05:00
invites : Map < any , any > ;
commands : Discord.Collection < string , any > ;
registry : Array < Discord.ApplicationCommandDataResolvable > ;
2022-12-29 05:10:13 -05:00
config : Config ;
tokens : Tokens ;
2022-11-11 19:58:11 -05:00
YTCache : any ;
2022-11-14 03:45:40 -05:00
embed : typeof Discord . EmbedBuilder ;
2022-11-11 19:58:11 -05:00
collection : any ;
messageCollector : any ;
attachmentBuilder : any ;
2022-12-18 23:22:28 -05:00
moment : typeof moment ;
2022-11-13 08:46:50 -05:00
xjs : any ;
2022-12-18 23:22:28 -05:00
axios : typeof axios ;
2022-11-15 09:06:18 -05:00
ms : any ;
2022-11-14 03:45:40 -05:00
userLevels : userLevels ;
punishments : punishments ;
bonkCount : bonkCount ;
bannedWords : bannedWords ;
2023-02-26 18:45:56 -05:00
MPServer : MPServer ;
2023-02-26 23:31:16 -05:00
suggestion : suggestion ;
2023-02-16 03:48:24 -05:00
repeatedMessages : repeatedMessages ;
2023-01-22 06:21:32 -05:00
statsGraph : number ;
2022-11-11 19:58:11 -05:00
constructor ( ) {
super ( {
intents : [
GatewayIntentBits . Guilds , GatewayIntentBits . GuildMembers ,
GatewayIntentBits . GuildBans , GatewayIntentBits . GuildInvites ,
2022-11-26 17:18:40 -05:00
GatewayIntentBits . GuildPresences , GatewayIntentBits . MessageContent , GatewayIntentBits . GuildMessages
2022-11-11 19:58:11 -05:00
] ,
partials : [
Partials . Channel ,
Partials . Reaction ,
Partials . Message
] ,
2022-11-17 12:58:19 -05:00
allowedMentions : { users : [ ] , roles : [ ] }
2022-11-11 19:58:11 -05:00
} )
this . invites = new Map ( ) ;
this . commands = new Discord . Collection ( ) ;
2022-11-14 03:45:40 -05:00
this . registry = [ ] ;
2023-01-06 19:41:20 -05:00
this . config = importconfig as Config ;
2022-12-29 05:10:13 -05:00
this . tokens = tokens as Tokens ;
2022-11-11 19:58:11 -05:00
this . YTCache = {
'UCQ8k8yTDLITldfWYKDs3xFg' : undefined , // Daggerwin
2022-11-18 23:29:01 -05:00
'UCguI73--UraJpso4NizXNzA' : undefined // Machinery Restorer
2022-11-11 19:58:11 -05:00
}
this . embed = Discord . EmbedBuilder ;
this . collection = Discord . Collection ;
this . messageCollector = Discord . MessageCollector ;
this . attachmentBuilder = Discord . AttachmentBuilder ;
2022-12-18 23:22:28 -05:00
this . moment = moment ;
2022-11-16 13:53:42 -05:00
this . xjs = require ( 'xml-js' ) ;
2022-12-18 23:22:28 -05:00
this . axios = axios ;
2022-11-16 13:53:42 -05:00
this . ms = require ( 'ms' ) ;
2022-11-15 09:06:18 -05:00
this . userLevels = new userLevels ( this ) ;
this . bonkCount = new bonkCount ( this ) ;
this . punishments = new punishments ( this ) ;
this . bannedWords = new bannedWords ( this ) ;
2023-02-26 18:45:56 -05:00
this . MPServer = new MPServer ( this ) ;
2023-02-26 23:31:16 -05:00
this . suggestion = new suggestion ( this ) ;
2022-11-11 19:58:11 -05:00
this . repeatedMessages = { } ;
2023-01-22 06:21:32 -05:00
this . setMaxListeners ( 80 ) ;
this . statsGraph = - 60 ;
2022-11-11 19:58:11 -05:00
}
async init ( ) {
2023-02-24 19:55:11 -05:00
mongoose . set ( 'strictQuery' , true ) ;
await mongoose . connect ( this . tokens . mongodb_uri , {
autoIndex : true ,
2023-03-03 06:10:36 -05:00
serverSelectionTimeoutMS : 12000 ,
2023-02-24 19:55:11 -05:00
socketTimeoutMS : 30000 ,
family : 4 ,
keepAlive : true ,
waitQueueTimeoutMS : 50000
} ) . then ( ( ) = > console . log ( this . logTime ( ) , 'Successfully connected to MongoDB' ) ) . catch ( ( ) = > { console . log ( this . logTime ( ) , 'Failed to connect to MongoDB' ) ; exec ( 'pm2 stop Daggerbot' ) } )
await this . login ( this . tokens . main ) ;
2022-11-16 13:53:42 -05:00
const commandFiles = fs . readdirSync ( 'src/commands' ) . filter ( file = > file . endsWith ( '.ts' ) ) ;
2022-11-14 03:45:40 -05:00
for ( const file of commandFiles ) {
2022-11-16 13:53:42 -05:00
const command = require ( ` ./commands/ ${ file } ` ) ;
this . commands . set ( command . default . data . name , command )
this . registry . push ( command . default . data . toJSON ( ) )
2022-11-14 03:45:40 -05:00
}
2023-02-09 23:01:55 -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 ) ) ;
} ) ;
2022-11-11 19:58:11 -05:00
}
2022-11-13 08:46:50 -05:00
formatTime ( integer : number , accuracy = 1 , options? : formatTimeOpt ) {
2022-11-11 19:58:11 -05:00
let achievedAccuracy = 0 ;
2022-11-15 09:06:18 -05:00
let text :any = '' ;
2022-11-11 19:58:11 -05:00
for ( const timeName of timeNames ) {
if ( achievedAccuracy < accuracy ) {
const fullTimelengths = Math . floor ( integer / timeName . length ) ;
if ( fullTimelengths == 0 ) continue ;
achievedAccuracy ++ ;
2022-11-17 12:58:19 -05:00
text += fullTimelengths + ( options ? . longNames ? ( ' ' + timeName . name + ( fullTimelengths === 1 ? '' : 's' ) ) : timeName . name . slice ( 0 , timeName . name === 'month' ? 2 : 1 ) ) + ( options ? . commas ? ', ' : ' ' ) ;
2022-11-11 19:58:11 -05:00
integer -= fullTimelengths * timeName . length ;
} else {
break ;
}
}
2022-11-13 08:46:50 -05:00
if ( text . length == 0 ) text = integer + ( options ? . longNames ? ' milliseconds' : 'ms' ) + ( options ? . commas ? ', ' : '' ) ;
if ( options ? . commas ) {
2022-11-11 19:58:11 -05:00
text = text . slice ( 0 , - 2 ) ;
2022-11-13 08:46:50 -05:00
if ( options ? . longNames ) {
2022-11-11 19:58:11 -05:00
text = text . split ( '' ) ;
text [ text . lastIndexOf ( ',' ) ] = ' and' ;
text = text . join ( '' ) ;
}
} return text . trim ( ) ;
}
2022-11-13 08:46:50 -05:00
isStaff ( guildMember : Discord.GuildMember ) {
return this . config . mainServer . staffRoles . map ( ( x : string ) = > this . config . mainServer . roles [ x ] ) . some ( ( x : string ) = > guildMember . roles . cache . has ( x ) )
}
2022-11-15 09:06:18 -05:00
youNeedRole ( interaction : Discord.CommandInteraction , role :string ) {
return interaction . reply ( ` This command is restricted to <@& ${ this . config . mainServer . roles [ role ] } > ` )
}
2023-02-24 19:55:11 -05:00
logTime ( ) {
return ` [ ${ this . moment ( ) . format ( 'DD/MM/YY HH:mm:ss' ) } ] `
}
2022-11-13 08:46:50 -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 ;
}
2022-11-15 09:06:18 -05:00
async punish ( client : TClient , interaction : Discord.ChatInputCommandInteraction < 'cached' > , type : string ) {
2022-12-01 17:53:57 -05:00
if ( ! client . isStaff ( interaction . member as Discord . GuildMember ) ) return client . youNeedRole ( interaction , "dcmod" ) ;
2022-11-17 12:58:19 -05:00
const time = interaction . options . getString ( 'time' ) as string ;
2022-12-02 21:02:53 -05:00
const reason = interaction . options . getString ( 'reason' ) ? ? 'Reason unspecified' ;
2022-12-01 17:53:57 -05:00
const GuildMember = interaction . options . getMember ( 'member' ) as Discord . GuildMember ;
const User = interaction . options . getUser ( 'member' ) as Discord . User ;
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. ` ) ;
2023-02-09 16:50:17 -05:00
if ( GuildMember . user . bot ) return interaction . reply ( ` You cannot ${ type } a bot! ` ) ;
2022-12-03 18:35:14 -05:00
await interaction . deferReply ( ) ;
2022-12-01 17:53:57 -05:00
await client . punishments . addPunishment ( type , { time , interaction } , interaction . user . id , reason , User , GuildMember ) ;
2022-11-13 08:46:50 -05:00
}
async YTLoop ( YTChannelID : string , YTChannelName : string , DCChannelID : string ) {
2022-11-17 12:58:19 -05:00
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 ;
2023-02-24 19:55:11 -05:00
console . log ( this . logTime ( ) , ` ${ YTChannelName } YT fail ` )
2022-11-17 12:58:19 -05:00
}
2022-11-13 08:46:50 -05:00
if ( ! Data ) return ;
if ( this . YTCache [ YTChannelID ] == undefined ) {
this . YTCache [ YTChannelID ] = Data . feed . entry [ 0 ] [ 'yt:videoId' ] . _text ;
return ;
}
if ( Data . feed . entry [ 1 ] [ 'yt:videoId' ] . _text == this . YTCache [ YTChannelID ] ) {
2022-11-18 22:23:33 -05:00
this . YTCache [ YTChannelID ] = Data . feed . entry [ 0 ] [ 'yt:videoId' ] . _text ;
2022-11-13 08:46:50 -05:00
( 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-02-26 23:31:16 -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.