package main
import (
"flag"
"fmt"
"math/rand"
"os"
"os/signal"
"syscall"
"time"
"github.com/bwmarrin/discordgo"
"github.com/rudi9719/loggy"
)
var (
startupTime time . Time
setupToken = fmt . Sprintf ( "%+v" , rand . Intn ( 9999 ) + 1000 )
rebootToken = fmt . Sprintf ( "%+v" , rand . Intn ( 9999 ) + 1000 )
bump = true
config Config
log = loggy . NewLogger ( config . LogOpts )
lastActiveChan string
lastActiveTime time . Time
token string
configFile string
dg * discordgo . Session
lastPM = make ( map [ string ] time . Time )
introMsg = make ( map [ string ] string )
quotes = [ ] string { "The hardest choices require the strongest wills." , "You're strong, but I could snap my fingers and you'd all cease to exist." , "Fun isn't something one considers when balancing the universe. But this... does put a smile on my face." , "Perfectly balanced, as all things should be." , "I am inevitable." }
version = "3.2"
gitCommit string
commands [ ] Command
)
func init ( ) {
flag . StringVar ( & token , "t" , "" , "Bot Token" )
flag . StringVar ( & configFile , "c" , "" , "Config file" )
flag . Parse ( )
}
func main ( ) {
go runWeb ( )
defer log . PanicSafe ( )
if configFile == "" {
configFile = "config.json"
} else {
loadConfig ( )
}
log = loggy . NewLogger ( config . LogOpts )
startupTime = time . Now ( )
lastActiveTime = time . Now ( )
lastActiveChan = config . AdminChannel
if token == "" {
log . LogPanic ( "No token provided. Please run: disgord-thanos -t <bot token>" )
}
log . LogCritical ( "SetupToken: %+v\nRebootToken: %+v" , setupToken , rebootToken )
var err error
dg , err = discordgo . New ( "Bot " + token )
if err != nil {
log . LogErrorType ( err )
log . LogPanic ( "Unable to create bot using token." )
}
dg . AddHandler ( ready )
dg . AddHandler ( guildMemberRemove )
dg . AddHandler ( guildMemberAdd )
dg . AddHandler ( guildMemberBanned )
go setupCommands ( )
dg . AddHandler ( messageCreate )
dg . AddHandler ( readReaction )
dg . AddHandler ( guildMemberUpdate )
dg . Identify . Intents = discordgo . MakeIntent ( discordgo . IntentsAll )
err = dg . Open ( )
if err != nil {
log . LogErrorType ( err )
log . LogPanic ( "Unable to open websocket." )
}
log . LogInfo ( "Thanos is now running. Press CTRL-C to exit." )
go purgeTimer ( dg )
go rebootBump ( )
sc := make ( chan os . Signal , 1 )
signal . Notify ( sc , syscall . SIGINT , syscall . SIGTERM , os . Interrupt )
<- sc
saveConfig ( )
dg . Close ( )
}
func exit ( s * discordgo . Session ) {
s . Close ( )
saveConfig ( )
os . Exit ( 0 )
}
func runPurge ( s * discordgo . Session ) {
defer log . PanicSafe ( )
if time . Since ( config . BumpTime ) > 2 * time . Hour {
bump = true
}
for uid , join := range config . Probations {
if time . Since ( join ) > 2 * time . Hour {
delete ( config . Probations , uid )
s . ChannelMessageDelete ( config . IntroChann , introMsg [ uid ] )
}
}
for k , v := range config . Unverified {
isUnverified := false
m , err := s . GuildMember ( config . GuildID , k )
if err != nil {
delete ( config . Unverified , k )
continue
}
for _ , role := range m . Roles {
if role == config . MonitorRole {
isUnverified = true
}
}
if isUnverified {
if val , ok := lastPM [ k ] ; ok && time . Since ( val ) < 5 * time . Minute {
continue
}
lastPM [ k ] = time . Now ( )
pmChann , _ := s . UserChannelCreate ( k )
s . ChannelMessageSend ( pmChann . ID ,
fmt . Sprintf ( "This is a reminder that you have not verified with me and will be removed at <t:%+v:t>. You may reply to this message for verification instructions." , v . Add ( 1 * time . Hour ) . Unix ( ) ) )
if time . Since ( v ) > ( time . Hour * 1 ) {
s . ChannelMessageSend ( config . AdminChannel , fmt . Sprintf ( "%+v was removed." , m . Mention ( ) ) )
s . GuildMemberDeleteWithReason ( config . GuildID , k , fmt . Sprintf ( "Unverified user %+v." , v ) )
}
} else {
delete ( config . Unverified , k )
}
}
messages , _ := s . ChannelMessages ( config . MonitorChann , 100 , "" , "" , "" )
for _ , message := range messages {
found := false
for user := range config . Unverified {
if message . Author . ID == user {
found = true
}
for _ , mention := range message . Mentions {
if mention . ID == user {
found = true
}
}
}
if ! found {
s . ChannelMessageDelete ( config . MonitorChann , message . ID )
}
}
go cleanSocials ( s )
saveConfig ( )
}
func cleanSocials ( s * discordgo . Session ) {
if len ( config . SocialChanns ) == 0 {
config . SocialChanns = append ( config . SocialChanns , "730437117913858129" )
config . SocialChanns = append ( config . SocialChanns , "730439200771670076" )
config . SocialChanns = append ( config . SocialChanns , "730439324675473470" )
}
for _ , channel := range config . SocialChanns {
go func ( channel string , s * discordgo . Session ) {
messages , _ := s . ChannelMessages ( channel , 100 , "" , "" , "" )
for _ , message := range messages {
_ , err := s . GuildMember ( config . GuildID , message . Author . ID )
if err != nil {
s . ChannelMessageDelete ( channel , message . ID )
}
}
} ( channel , s )
}
}
func verifyMember ( s * discordgo . Session , u discordgo . User ) {
defer log . PanicSafe ( )
s . GuildMemberRoleAdd ( config . GuildID , u . ID , config . VerifiedRole )
s . GuildMemberRoleRemove ( config . GuildID , u . ID , config . MonitorRole )
st , _ := s . UserChannelCreate ( u . ID )
s . ChannelMessageSend ( st . ID , "Your verification has been accepted, welcome!" )
m , _ := s . ChannelMessageSend ( config . IntroChann , fmt . Sprintf ( "Welcome %+v please introduce yourself! :) feel free to check out <#710557387937022034> to tag your roles. Also please mute any channels you are not interested in!" , u . Mention ( ) ) )
introMsg [ u . ID ] = m . ID
}
func rejectVerification ( s * discordgo . Session , u discordgo . User ) {
defer log . PanicSafe ( )
st , _ := s . UserChannelCreate ( u . ID )
if st != nil {
s . ChannelMessageSend ( st . ID , fmt . Sprintf ( "Your verification has been rejected. This means it did not clearly show your face, with your pinkie finger held to the corner of your mouth, or the photo looked edited/filtered. No filters will be accepted.\n\nPlease try again before <t:%+v:t>" , time . Now ( ) . Add ( 1 * time . Hour ) . Unix ( ) ) )
}
config . Unverified [ u . ID ] = time . Now ( )
}
func requestAge ( s * discordgo . Session , u discordgo . User ) {
defer log . PanicSafe ( )
st , _ := s . UserChannelCreate ( u . ID )
s . ChannelMessageSend ( st . ID , "What is your ASL? (Age/Sex/Language) Please note, this is NOT requesting your gender, but your biological sex. Gender is a social construct, sex is biology and in the context of pornographic images more important." )
}