2017-05-04 05:22:27 +02:00
from config import config
2018-07-16 05:50:31 +02:00
from titanembeds . redisqueue import RedisQueue
2017-05-20 09:50:29 +02:00
from titanembeds . commands import Commands
2017-08-20 21:56:54 +02:00
from titanembeds . socketio import SocketIOInterface
2018-01-06 10:59:04 +01:00
from titanembeds . poststats import DiscordBotsOrg , BotsDiscordPw
2017-09-16 19:16:34 +02:00
from collections import deque
2018-12-30 21:55:24 +01:00
# from raven import Client as RavenClient
# import raven
2017-05-04 05:22:27 +02:00
import discord
2017-05-04 07:16:49 +02:00
import aiohttp
import asyncio
2017-05-14 23:05:51 +02:00
import sys
2017-05-15 00:09:38 +02:00
import logging
2017-09-06 06:58:46 +02:00
import json
2018-12-30 21:55:24 +01:00
# try:
# raven_client = RavenClient(config["sentry-dsn"])
# except raven.exceptions.InvalidDsn:
# pass
2017-05-04 05:22:27 +02:00
2018-03-22 23:55:09 +01:00
class Titan ( discord . AutoShardedClient ) :
2020-02-18 03:00:19 +01:00
def __init__ ( self , shard_ids = None , shard_count = None ) :
2019-03-05 20:49:08 +01:00
super ( ) . __init__ (
2020-02-18 03:00:19 +01:00
shard_ids = shard_ids ,
shard_count = shard_count ,
2019-03-05 20:49:08 +01:00
max_messages = 10000 ,
activity = discord . Game ( name = " Embed your Discord server! Visit https://TitanEmbeds.com/ " )
)
2020-02-18 03:00:19 +01:00
self . setup_logger ( shard_ids )
2017-05-04 07:16:49 +02:00
self . aiosession = aiohttp . ClientSession ( loop = self . loop )
self . http . user_agent + = ' TitanEmbeds-Bot '
2018-07-16 05:50:31 +02:00
self . redisqueue = RedisQueue ( self , config [ " redis-uri " ] )
2018-08-10 06:13:56 +02:00
self . command = Commands ( self , config )
2017-08-20 21:56:54 +02:00
self . socketio = SocketIOInterface ( self , config [ " redis-uri " ] )
2017-09-16 19:16:34 +02:00
2018-03-22 23:55:09 +01:00
self . delete_list = deque ( maxlen = 100 ) # List of msg ids to prevent duplicate delete
2018-01-05 10:21:25 +01:00
self . discordBotsOrg = None
2018-01-06 10:59:04 +01:00
self . botsDiscordPw = None
2017-05-04 05:22:27 +02:00
2020-02-18 03:00:19 +01:00
def setup_logger ( self , shard_ids = None ) :
shard_ids = ' - ' . join ( str ( x ) for x in shard_ids ) if shard_ids is not None else ' '
logging . basicConfig (
filename = ' titanbot {} .log ' . format ( shard_ids ) ,
level = logging . INFO ,
format = ' %(asctime)s %(message)s ' ,
datefmt = ' % m/ %d / % Y % I: % M: % S % p '
)
logging . getLogger ( ' TitanBot ' )
2017-05-04 07:16:49 +02:00
def _cleanup ( self ) :
try :
self . loop . run_until_complete ( self . logout ( ) )
except : # Can be ignored
pass
pending = asyncio . Task . all_tasks ( )
gathered = asyncio . gather ( * pending )
try :
gathered . cancel ( )
self . loop . run_until_complete ( gathered )
gathered . exception ( )
except : # Can be ignored
2020-02-17 23:40:53 +01:00
pass
2018-07-10 21:06:54 +02:00
async def start ( self ) :
2020-02-17 23:11:24 +01:00
await self . redisqueue . connect ( )
2018-07-10 21:06:54 +02:00
await super ( ) . start ( config [ " bot-token " ] )
2017-05-04 07:16:49 +02:00
2020-02-17 23:47:32 +01:00
async def on_shard_ready ( self , shard_id ) :
2020-02-18 03:00:19 +01:00
logging . info ( ' Titan [DiscordBot] ' )
logging . info ( ' Logged in as the following user: ' )
logging . info ( self . user . name )
logging . info ( self . user . id )
logging . info ( ' ------ ' )
logging . info ( " Shard count: " + str ( self . shard_count ) )
logging . info ( " Shard id: " + str ( shard_id ) )
logging . info ( " ------ " )
self . loop . create_task ( self . redisqueue . subscribe ( ) )
2018-03-24 15:54:50 +01:00
2018-01-05 11:00:24 +01:00
self . discordBotsOrg = DiscordBotsOrg ( self . user . id , config . get ( " discord-bots-org-token " , None ) )
2018-01-06 10:59:04 +01:00
self . botsDiscordPw = BotsDiscordPw ( self . user . id , config . get ( " bots-discord-pw-token " , None ) )
2020-02-21 11:41:39 +01:00
self . loop . create_task ( self . auto_post_stats ( ) )
2017-05-27 19:50:52 +02:00
2017-05-06 10:03:52 +02:00
async def on_message ( self , message ) :
2017-08-20 21:56:54 +02:00
await self . socketio . on_message ( message )
2018-07-16 05:50:31 +02:00
await self . redisqueue . push_message ( message )
2017-05-27 19:50:52 +02:00
2017-05-20 09:50:29 +02:00
msg_arr = message . content . split ( ) # split the message
2018-03-22 23:55:09 +01:00
if len ( message . content . split ( ) ) > 1 and message . guild : #making sure there is actually stuff in the message and have arguments and check if it is sent in server (not PM)
2017-11-14 21:58:19 +01:00
if msg_arr [ 0 ] == " <@ {} > " . format ( self . user . id ) or msg_arr [ 0 ] == " <@! {} > " . format ( self . user . id ) : #make sure it is mention
2017-05-20 09:50:29 +02:00
msg_cmd = msg_arr [ 1 ] . lower ( ) # get command
2018-05-22 00:35:08 +02:00
if msg_cmd == " __init__ " :
return
2017-05-20 09:50:29 +02:00
cmd = getattr ( self . command , msg_cmd , None ) #check if cmd exist, if not its none
if cmd : # if cmd is not none...
2018-03-24 09:19:46 +01:00
async with message . channel . typing ( ) : #this looks nice
await getattr ( self . command , msg_cmd ) ( message ) #actually run cmd, passing in msg obj
2017-05-06 10:03:52 +02:00
async def on_message_edit ( self , message_before , message_after ) :
2018-07-16 05:50:31 +02:00
await self . redisqueue . update_message ( message_after )
2017-08-22 08:57:30 +02:00
await self . socketio . on_message_update ( message_after )
2017-05-07 00:27:07 +02:00
async def on_message_delete ( self , message ) :
2017-09-16 19:16:34 +02:00
self . delete_list . append ( message . id )
2018-07-16 05:50:31 +02:00
await self . redisqueue . delete_message ( message )
2017-08-22 08:57:30 +02:00
await self . socketio . on_message_delete ( message )
2018-07-27 10:57:54 +02:00
async def on_reaction_add ( self , reaction , user ) :
await self . redisqueue . update_message ( reaction . message )
await self . socketio . on_reaction_add ( reaction . message )
async def on_reaction_remove ( self , reaction , user ) :
await self . redisqueue . update_message ( reaction . message )
await self . socketio . on_reaction_remove ( reaction . message )
async def on_reaction_clear ( self , message , reactions ) :
await self . redisqueue . update_message ( message )
await self . socketio . on_reaction_clear ( message )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_join ( self , guild ) :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( guild )
2018-01-06 10:59:04 +01:00
await self . postStats ( )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_remove ( self , guild ) :
2018-07-21 01:10:24 +02:00
await self . redisqueue . delete_guild ( guild )
2018-01-06 10:59:04 +01:00
await self . postStats ( )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_update ( self , guildbefore , guildafter ) :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( guildafter )
2017-08-25 08:37:14 +02:00
await self . socketio . on_guild_update ( guildafter )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_role_create ( self , role ) :
2017-05-07 00:27:07 +02:00
if role . name == self . user . name and role . managed :
await asyncio . sleep ( 2 )
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( role . guild )
2017-08-25 08:37:14 +02:00
await self . socketio . on_guild_role_create ( role )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_role_delete ( self , role ) :
if role . guild . me not in role . guild . members :
2017-05-07 00:27:07 +02:00
return
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( role . guild )
2017-08-25 08:37:14 +02:00
await self . socketio . on_guild_role_delete ( role )
2017-05-07 00:27:07 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_role_update ( self , rolebefore , roleafter ) :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( roleafter . guild )
2017-09-05 09:37:04 +02:00
await self . socketio . on_guild_role_update ( roleafter )
2017-05-07 00:27:07 +02:00
async def on_channel_delete ( self , channel ) :
2018-03-22 23:55:09 +01:00
if channel . guild :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( channel . guild )
2018-01-25 12:20:56 +01:00
await self . socketio . on_channel_delete ( channel )
2017-05-07 00:27:07 +02:00
async def on_channel_create ( self , channel ) :
2018-03-22 23:55:09 +01:00
if channel . guild :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( channel . guild )
2018-01-25 12:20:56 +01:00
await self . socketio . on_channel_create ( channel )
2017-05-07 00:27:07 +02:00
2018-03-23 00:07:52 +01:00
async def on_guild_channel_update ( self , channelbefore , channelafter ) :
2018-07-21 01:10:24 +02:00
await self . redisqueue . update_guild ( channelafter . guild )
2017-08-25 08:37:14 +02:00
await self . socketio . on_channel_update ( channelafter )
2017-05-07 00:27:07 +02:00
async def on_member_join ( self , member ) :
2018-07-18 01:47:30 +02:00
await self . redisqueue . add_member ( member )
2017-08-22 08:57:30 +02:00
await self . socketio . on_guild_member_add ( member )
2017-05-07 00:27:07 +02:00
async def on_member_remove ( self , member ) :
2018-07-18 01:47:30 +02:00
await self . redisqueue . remove_member ( member )
2017-08-22 08:57:30 +02:00
await self . socketio . on_guild_member_remove ( member )
2017-05-07 00:27:07 +02:00
async def on_member_update ( self , memberbefore , memberafter ) :
2018-07-18 01:47:30 +02:00
await self . redisqueue . update_member ( memberafter )
2018-03-25 21:56:32 +02:00
await self . socketio . on_guild_member_update ( memberafter )
2017-05-07 00:27:07 +02:00
2018-03-24 09:02:03 +01:00
async def on_member_ban ( self , guild , user ) :
if self . user . id == user . id :
2017-05-07 00:27:07 +02:00
return
2018-07-18 01:47:30 +02:00
await self . redisqueue . ban_member ( guild , user )
2017-05-30 00:07:32 +02:00
2018-03-22 23:55:09 +01:00
async def on_guild_emojis_update ( self , guild , before , after ) :
2018-12-30 21:22:58 +01:00
await self . redisqueue . update_guild ( guild )
2017-05-30 00:07:32 +02:00
if len ( after ) == 0 :
2017-08-22 09:53:41 +02:00
await self . socketio . on_guild_emojis_update ( before )
2018-12-30 22:00:41 +01:00
else :
2017-08-22 09:53:41 +02:00
await self . socketio . on_guild_emojis_update ( after )
2017-07-01 08:52:21 +02:00
2019-01-08 18:49:17 +01:00
# async def on_webhooks_update(self, channel):
# await self.redisqueue.update_guild(channel.guild)
2018-03-24 15:46:32 +01:00
2018-07-09 03:58:23 +02:00
async def on_raw_message_edit ( self , payload ) :
message_id = payload . message_id
data = payload . data
2018-03-24 15:46:32 +01:00
if not self . in_messages_cache ( int ( message_id ) ) :
channel = self . get_channel ( int ( data [ " channel_id " ] ) )
2018-12-30 21:22:58 +01:00
me = channel . guild . get_member ( self . user . id )
if channel . permissions_for ( me ) . read_messages :
2019-10-08 07:37:49 +02:00
message = await channel . fetch_message ( int ( message_id ) )
2018-12-30 21:22:58 +01:00
await self . on_message_edit ( None , message )
2018-03-24 15:46:32 +01:00
2018-07-09 03:58:23 +02:00
async def on_raw_message_delete ( self , payload ) :
message_id = payload . message_id
channel_id = payload . channel_id
2018-03-24 15:46:32 +01:00
if not self . in_messages_cache ( int ( message_id ) ) :
2017-09-16 19:16:34 +02:00
await asyncio . sleep ( 1 )
2018-03-24 15:46:32 +01:00
await self . process_raw_message_delete ( int ( message_id ) , int ( channel_id ) )
2018-07-09 03:58:23 +02:00
async def raw_bulk_message_delete ( self , payload ) :
message_ids = payload . message_ids
2018-07-21 01:10:24 +02:00
channel_id = payload . channel_id
2018-03-24 15:46:32 +01:00
await asyncio . sleep ( 1 )
for msgid in message_ids :
msgid = int ( msgid )
if not self . in_messages_cache ( msgid ) :
await self . process_raw_message_delete ( msgid , int ( channel_id ) )
2017-09-06 06:58:46 +02:00
async def process_raw_message_delete ( self , msg_id , channel_id ) :
2017-09-16 19:16:34 +02:00
if msg_id in self . delete_list :
self . delete_list . remove ( msg_id )
return
2018-03-22 23:55:09 +01:00
channel = self . get_channel ( int ( channel_id ) )
2019-10-08 07:50:52 +02:00
data = {
' content ' : " What fun is there in making sense? " ,
' type ' : 0 ,
' edited_timestamp ' : None ,
' id ' : msg_id ,
' channel_id ' : channel_id ,
' timestamp ' : ' 2017-01-15T02:59:58+00:00 ' ,
' attachments ' : [ ] ,
' embeds ' : [ ] ,
' pinned ' : False ,
' mention_everyone ' : False ,
' tts ' : False ,
' nonce ' : None ,
}
2018-03-22 23:55:09 +01:00
msg = discord . Message ( channel = channel , state = self . _connection , data = data ) # Procreate a fake message object
2017-09-06 06:58:46 +02:00
await self . on_message_delete ( msg )
2018-07-27 10:57:54 +02:00
async def on_raw_reaction_add ( self , payload ) :
message_id = payload . message_id
if not self . in_messages_cache ( message_id ) :
channel = self . get_channel ( payload . channel_id )
2018-12-30 21:22:58 +01:00
me = channel . guild . get_member ( self . user . id )
if channel . permissions_for ( me ) . read_messages :
2019-10-08 07:37:49 +02:00
message = await channel . fetch_message ( message_id )
2019-01-05 21:54:50 +01:00
if len ( message . reactions ) :
await self . on_reaction_add ( message . reactions [ 0 ] , None )
2018-07-27 10:57:54 +02:00
async def on_raw_reaction_remove ( self , payload ) :
message_id = payload . message_id
if not self . in_messages_cache ( message_id ) :
partial = payload . emoji
emoji = self . _connection . _upgrade_partial_emoji ( partial )
channel = self . get_channel ( payload . channel_id )
2018-12-30 21:22:58 +01:00
me = channel . guild . get_member ( self . user . id )
if channel . permissions_for ( me ) . read_messages :
2019-10-08 07:37:49 +02:00
message = await channel . fetch_message ( message_id )
2018-12-30 21:22:58 +01:00
message . _add_reaction ( { " me " : payload . user_id == self . user . id } , emoji , payload . user_id )
reaction = message . _remove_reaction ( { } , emoji , payload . user_id )
await self . on_reaction_remove ( reaction , None )
2018-07-27 10:57:54 +02:00
async def on_raw_reaction_clear ( self , payload ) :
message_id = payload . message_id
if not self . in_messages_cache ( message_id ) :
channel = self . get_channel ( payload . channel_id )
2018-12-30 21:22:58 +01:00
me = channel . guild . get_member ( self . user . id )
if channel . permissions_for ( me ) . read_messages :
2019-10-08 07:37:49 +02:00
message = await channel . fetch_message ( message_id )
2018-12-30 21:22:58 +01:00
await self . on_reaction_clear ( message , [ ] )
2018-07-27 10:57:54 +02:00
2019-01-08 18:49:17 +01:00
async def on_socket_response ( self , msg ) :
if " op " in msg and " t " in msg and msg [ " op " ] == 0 :
if msg [ " t " ] == " WEBHOOKS_UPDATE " :
guild_id = int ( msg [ " d " ] [ " guild_id " ] )
guild = self . get_guild ( guild_id )
if guild :
await self . redisqueue . update_guild ( guild )
2017-09-06 06:58:46 +02:00
def in_messages_cache ( self , msg_id ) :
2018-03-22 23:55:09 +01:00
for msg in self . _connection . _messages :
2017-09-06 06:58:46 +02:00
if msg . id == msg_id :
return True
2017-09-07 06:00:09 +02:00
return False
2020-02-21 11:41:39 +01:00
async def auto_post_stats ( self ) :
while not self . is_closed ( ) :
await self . postStats ( )
await asyncio . sleep ( 1800 )
2018-01-06 10:59:04 +01:00
async def postStats ( self ) :
2018-03-22 23:55:09 +01:00
count = len ( self . guilds )
shard_count = self . shard_count
shard_id = self . shard_id
await self . discordBotsOrg . post ( count , shard_count , shard_id )
await self . botsDiscordPw . post ( count , shard_count , shard_id )