2020-07-22 08:04:06 -07:00
r """
2020-07-21 20:21:00 -07:00
_____ __
/ ___ / __ __ _ _______ ____ / / __
/ / __ / _ \/ ' \ / __/ _ `/ _ / -_)
\___ / \___ / _ / _ / _ / _ / \_ , _ / \_ , _ / \__ /
2020-06-25 09:42:11 -07:00
2019-06-27 22:53:26 -07:00
A bot by turtlebasket
"""
import asyncio
import json
2019-09-03 22:14:23 -07:00
from urllib . request import urlopen , Request
2019-09-04 12:48:49 -07:00
import random
2019-06-25 14:33:06 -07:00
import discord
from discord . ext import commands
2020-06-25 09:48:44 -07:00
from discord . ext import tasks
2020-03-24 16:03:43 -07:00
from os import environ
2020-05-05 23:20:50 -07:00
import dbl
2019-08-31 20:28:21 -07:00
from bot_utils import *
2019-06-25 14:33:06 -07:00
2022-05-04 21:17:33 -07:00
from dotenv import load_dotenv
from os import path , getenv
basedir = path . abspath ( path . dirname ( __file__ ) )
load_dotenv ( )
2019-06-28 23:25:21 -07:00
with open ( ' config.json ' , ' r ' ) as json_file :
config = json . load ( json_file )
2022-05-04 21:17:33 -07:00
BOT_TOKEN = getenv ( ' BOT_TOKEN ' )
DBL_TOKEN = getenv ( ' DBL_TOKEN ' )
2020-05-05 23:20:50 -07:00
# Feeling cute, might refactor later
2019-06-28 23:25:21 -07:00
MUTE_VOTE_TIME = config [ " MUTE_VOTE_TIME " ]
MIN_MUTE_VOTERS = config [ " MIN_MUTE_VOTERS " ] # should be 3
MUTE_TIME = config [ " MUTE_TIME " ] # 10 mins
KICK_VOTE_TIME = config [ " KICK_VOTE_TIME " ]
MIN_KICK_VOTERS = config [ " MIN_KICK_VOTERS " ]
BAN_VOTE_TIME = config [ " BAN_VOTE_TIME " ]
MIN_BAN_VOTERS = config [ " MIN_BAN_VOTERS " ]
2019-08-31 20:28:21 -07:00
EMOTE_VOTE_TIME = config [ " EMOTE_VOTE_TIME " ]
MIN_EMOTE_VOTERS = config [ " MIN_EMOTE_VOTERS " ]
2019-11-25 10:00:47 -08:00
STATUS_LOOP = config [ " STATUS_LOOP " ]
2019-06-25 14:33:06 -07:00
bot = commands . Bot ( command_prefix = ' >> ' )
2019-08-31 20:28:21 -07:00
bot . remove_command ( ' help ' )
2019-06-25 14:33:06 -07:00
2019-06-28 23:25:21 -07:00
# To store users who are currently being voted on
muted_users = [ ]
muting_users = [ ]
kicking_users = [ ]
banning_users = [ ]
2019-11-25 10:00:47 -08:00
async def status_loop ( ) :
while True :
2020-05-05 23:14:17 -07:00
await bot . change_presence ( activity = discord . Game ( name = " Serving {0} glorious servers " . format ( len ( bot . guilds ) ) ) )
2019-11-25 10:00:47 -08:00
await asyncio . sleep ( STATUS_LOOP )
2019-11-29 12:24:49 -08:00
2020-05-05 23:14:17 -07:00
await bot . change_presence ( activity = discord . Game ( name = " >>help " ) )
2019-11-29 21:33:51 -08:00
await asyncio . sleep ( STATUS_LOOP )
2020-05-05 23:14:17 -07:00
await bot . change_presence ( activity = discord . Game ( name = " Proletarian Uprising 2: Electric Boogaloo " ) )
2020-01-26 22:45:17 -08:00
await asyncio . sleep ( STATUS_LOOP )
2020-05-05 23:20:50 -07:00
2020-06-25 09:42:11 -07:00
# top.gg API interaction handling (boilerplate)
2020-05-05 23:20:50 -07:00
class TopGG ( commands . Cog ) :
""" Handles interactions with the top.gg API """
def __init__ ( self , bot ) :
self . bot = bot
2022-05-04 21:17:33 -07:00
self . token = DBL_TOKEN
2020-05-05 23:20:50 -07:00
self . dblpy = dbl . DBLClient ( self . bot , self . token , autopost = True ) # refresh guild count every 30 mins
2020-06-25 09:42:11 -07:00
@tasks.loop ( minutes = 30.0 )
async def update_stats ( self ) :
""" Automatically update server count """
try :
await self . dblpy . post_guild_count ( )
except Exception as e :
print ( ' Failed to post server count \n {} : {} ' . format ( type ( e ) . __name__ , e ) )
# await asyncio.sleep(1800)
2020-05-05 23:20:50 -07:00
2019-06-25 14:33:06 -07:00
@bot.event
async def on_ready ( ) :
2019-11-25 10:00:47 -08:00
# await bot.change_presence(activity=discord.Game(name='{} servers | >>help'.format(len(bot.guilds))))
2020-06-25 09:42:11 -07:00
bot . add_cog ( TopGG ( bot ) )
2019-06-25 14:33:06 -07:00
print ( " Bot started. " )
print ( " -------------------------- " )
2020-07-22 08:04:06 -07:00
await asyncio . sleep ( 300 )
bot . loop . create_task ( status_loop ( ) )
2020-05-06 10:53:02 -07:00
@bot.command ( aliases = [ ' manual ' , ' commands ' , ' info ' ] )
2019-08-31 20:28:21 -07:00
async def help ( ctx ) :
2020-05-06 10:53:02 -07:00
embed = discord . Embed ( title = " Comrade: Usage & Other Info " )
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>addEmote` <emoji name> [ATTACHED IMAGE] " ,
2020-01-26 22:45:17 -08:00
value =
2020-05-09 12:50:51 -07:00
""" Vote to add a new emoji, attached as JPEG, PNG or GIF image.
2020-01-26 22:45:17 -08:00
Vote time : { 0 } minutes
Minimum Voters : { 1 }
""" .format(int(EMOTE_VOTE_TIME/60), MIN_EMOTE_VOTERS)
2019-08-31 20:28:21 -07:00
)
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>mute` <user> " ,
2020-01-26 22:45:17 -08:00
value =
""" Vote to mute user for {0} minutes.
Vote time : { 1 } minutes
Minimum Voters : { 2 }
""" .format(int(MUTE_TIME/60), int(MUTE_VOTE_TIME/60), MIN_MUTE_VOTERS)
2019-06-28 23:25:21 -07:00
)
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>kick` <user> " ,
2020-01-26 22:45:17 -08:00
value =
""" Vote to kick user.
Vote Time : { 0 } minutes
Minimum Voters : { 1 }
""" .format(int(KICK_VOTE_TIME/60), MIN_KICK_VOTERS)
2019-06-28 23:25:21 -07:00
)
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>ban` <user> " ,
2020-01-26 22:45:17 -08:00
value =
""" Vote to ban user.
2020-05-05 23:14:17 -07:00
Vote Time : { 0 } minutes
2020-01-26 22:45:17 -08:00
Minimum Voters : { 1 }
""" .format(int(BAN_VOTE_TIME/60), MIN_BAN_VOTERS)
2019-06-28 23:25:21 -07:00
)
2019-08-31 20:28:21 -07:00
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>shibe` " ,
2020-01-26 22:45:17 -08:00
value = " Random shibe :dog: :eyes: "
2019-08-31 20:28:21 -07:00
)
2019-09-03 22:14:23 -07:00
2020-09-08 17:39:38 -07:00
embed . add_field ( inline = False ,
name = " `>>cat` " ,
value = " Random cat :cat: :cat2: "
)
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>birb` " ,
2020-01-26 22:45:17 -08:00
value = " Random birb :bird: :hatching_chick: "
2019-09-03 22:14:23 -07:00
)
2019-06-28 23:25:21 -07:00
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
name = " `>>ping` " ,
2019-09-08 22:16:16 -07:00
value = " Get bot latency. "
)
2020-03-25 12:33:20 -07:00
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
2020-05-06 10:53:02 -07:00
name = " Enjoying Comrade? " ,
value = " [Upvote Comrade on Discord Bot List!](https://top.gg/bot/592852914553487370/vote) "
)
2020-05-09 12:50:51 -07:00
embed . add_field ( inline = False ,
2020-05-06 10:53:02 -07:00
name = " Need help? " ,
value = " [Report an issue](https://github.com/turtlebasket/comrade-bot/issues) "
2020-03-25 12:33:20 -07:00
)
2019-06-28 23:25:21 -07:00
await ctx . send ( embed = embed )
2019-06-25 14:33:06 -07:00
2020-05-08 14:17:56 -07:00
@bot.command ( aliases = [ ' addemote ' , ' addemoji ' , ' addEmoji ' ] )
2019-08-31 20:28:21 -07:00
async def addEmote ( ctx , emote_name : str ) :
2019-06-25 14:33:06 -07:00
"""
2019-08-31 20:28:21 -07:00
command : addEmote
2019-06-27 22:53:26 -07:00
2019-08-31 20:28:21 -07:00
Hold a vote to add an emoji .
2019-06-25 14:33:06 -07:00
"""
2019-11-25 10:00:47 -08:00
2019-08-31 20:28:21 -07:00
filename = str ( ctx . message . attachments [ 0 ] . filename )
valid_exts = [ " .jpg " , " .jpeg " , " .png " , " .gif " ]
valid = False
for ext in valid_exts :
# print(filename.endswith(ext))
if filename . endswith ( ext ) :
valid = True
break
if not valid :
await ctx . send ( " Invalid filetype! " )
return
vote_passed = await take_vote ( ctx , " Add emoji ` {} `? " . format ( emote_name ) , EMOTE_VOTE_TIME , MIN_EMOTE_VOTERS )
2019-06-25 14:33:06 -07:00
2019-08-31 20:28:21 -07:00
if vote_passed :
2019-11-07 18:52:53 -08:00
try :
file_bytes = await ctx . message . attachments [ 0 ] . read ( )
await ctx . guild . create_custom_emoji ( name = emote_name , image = file_bytes )
await ctx . send ( " `Emote {0} added!` : {0} : " . format ( emote_name ) )
except :
await ctx . send ( " :warning: `There was an error adding emote {} .` " . format ( emote_name ) )
2019-06-25 14:33:06 -07:00
2019-09-03 22:14:23 -07:00
@bot.command ( )
async def shibe ( ctx ) :
# with urllib.request.urlopen("http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true") as json_return:
with urlopen ( Request ( url = " http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true " , headers = { ' User-Agent ' : ' Mozilla/5.0 ' } ) ) as json_return :
shibe_contents = json_return . read ( )
2019-09-04 12:48:49 -07:00
msg = " {0} , here is your random shibe: " . format ( ctx . message . author . name )
url = json . loads ( shibe_contents ) [ 0 ]
await ctx . send ( embed = imgfun ( msg , url ) )
2019-09-08 22:13:04 -07:00
@bot.command ( aliases = [ ' bird ' ] )
async def birb ( ctx ) :
with urlopen ( Request ( url = " http://random.birb.pw/tweet.json " , headers = { ' User-Agent ' : ' Mozilla/5.0 ' } ) ) as json_return :
# get image filename
birb_contents = json_return . read ( )
msg = " {0} , here is your random birb: " . format ( ctx . message . author . name )
# insert image filename into URL
url = " http://random.birb.pw/img/ {} " . format ( json . loads ( birb_contents ) [ " file " ] )
await ctx . send ( embed = imgfun ( msg , url ) )
2020-09-08 16:52:29 -07:00
@bot.command ( aliases = [ ' kitty ' , ' kitti ' ] )
async def cat ( ctx ) :
with urlopen ( Request ( url = " http://aws.random.cat/meow " , headers = { ' User-Agent ' : ' Mozilla/5.0 ' } ) ) as json_return :
# get image filename
cat_contents = json_return . read ( )
msg = " {0} , here is your random cat: " . format ( ctx . message . author . name )
# insert image filename into URL
url = json . loads ( cat_contents ) [ " file " ]
await ctx . send ( embed = imgfun ( msg , url ) )
2019-08-31 20:28:21 -07:00
@bot.command ( aliases = [ ' latency ' ] )
async def ping ( ctx ) :
2019-09-03 21:22:05 -07:00
await ctx . send ( " `Bot latency: {} s` " . format ( round ( bot . latency , 2 ) ) )
2019-06-27 22:53:26 -07:00
@bot.command ( )
async def mute ( ctx , target_user : discord . User ) :
2021-01-16 17:27:42 -08:00
# await require_lower_permissions(ctx, target_user, bot)
2020-07-21 20:21:00 -07:00
2019-06-28 23:25:21 -07:00
if target_user in muting_users :
await ctx . send ( " There is already a mute vote on ` {} `! " . format ( target_user ) )
return
elif target_user in muted_users :
await ctx . send ( " ` {} ` is already muted! " . format ( target_user ) )
return
muting_users . append ( target_user )
2021-01-16 17:27:42 -08:00
vote_passed = await take_vote ( ctx , " Mute ` {} `? \n ⚠ NOTE: Can ' t mute users with an equal or higher role. " . format ( target_user ) , MUTE_VOTE_TIME , MIN_MUTE_VOTERS )
2019-06-28 23:25:21 -07:00
muting_users . remove ( target_user )
2019-08-31 20:28:21 -07:00
if vote_passed :
2020-07-21 20:46:56 -07:00
try :
# Add to muted_users
muted_users . append ( target_user )
# add temp. role for mute, edit role position to take precedence over other roles
muted_role = await ctx . guild . create_role ( name = " Muted " )
await muted_role . edit ( position = ctx . guild . get_member ( target_user . id ) . top_role . position + 1 )
# change channel permissions for new role
for channel in ctx . guild . channels :
if type ( channel ) is discord . TextChannel and target_user in channel . members :
await channel . set_permissions ( muted_role , read_messages = True , send_messages = False , add_reactions = False )
elif type ( channel ) is discord . VoiceChannel :
await channel . set_permissions ( muted_role , connect = False )
# Give role to member
await ctx . guild . get_member ( target_user . id ) . add_roles ( muted_role )
await ctx . send ( " ** {0} , the majority has ruled that you should be muted.** See ya in {1} minutes! " . format ( target_user , int ( MUTE_TIME / 60 ) ) )
await asyncio . sleep ( MUTE_TIME )
await muted_role . delete ( )
# Remove from muted_users
muted_users . remove ( target_user )
except discord . ext . commands . errors . CommandInvokeError :
await error_admin_targeted ( ctx )
2020-07-22 08:04:06 -07:00
muted_users . remove ( target_user )
2019-06-28 23:25:21 -07:00
2019-06-27 22:53:26 -07:00
@bot.command ( )
2019-06-28 23:25:21 -07:00
async def kick ( ctx , target_user : discord . User ) :
2021-01-16 17:27:42 -08:00
# await require_lower_permissions(ctx, target_user, bot)
2020-07-21 20:21:00 -07:00
2019-06-28 23:25:21 -07:00
if target_user in kicking_users :
await ctx . send ( " There is already a kick vote on ` {} `! " . format ( target_user ) )
return
# add to kicking_users
kicking_users . append ( target_user )
2021-01-16 17:27:42 -08:00
vote_passed = await take_vote ( ctx , " Kick ` {} `? \n ⚠ NOTE: Can ' t kick users with an equal or higher role. " . format ( target_user ) , KICK_VOTE_TIME , MIN_KICK_VOTERS )
2019-06-28 23:25:21 -07:00
2019-08-31 20:28:21 -07:00
if vote_passed :
2020-07-21 20:46:56 -07:00
try :
await ctx . guild . kick ( target_user )
2020-07-22 08:04:06 -07:00
await ctx . send ( " 👢 Kicked ` {} `. " . format ( target_user ) )
2020-07-21 20:46:56 -07:00
except discord . ext . commands . errors . CommandInvokeError :
await error_admin_targeted ( ctx )
2019-06-28 23:25:21 -07:00
kicking_users . remove ( target_user )
2019-06-27 22:53:26 -07:00
2019-08-31 20:28:21 -07:00
@bot.command ( aliases = [ ' exile ' ] )
async def ban ( ctx , target_user : discord . User ) :
2019-06-28 23:25:21 -07:00
2021-01-16 17:27:42 -08:00
# await require_lower_permissions(ctx, target_user, bot)
2020-07-21 20:21:00 -07:00
2019-06-28 23:25:21 -07:00
if target_user in banning_users :
await ctx . send ( " There is already a ban vote on ` {} `! " . format ( target_user ) )
return
# add to banning_users
banning_users . append ( target_user )
2021-01-16 17:27:42 -08:00
vote_passed = await take_vote ( ctx , " Ban ` {} `? \n ⚠ NOTE: Can ' t ban users with an equal or higher role. " . format ( target_user ) , BAN_VOTE_TIME , MIN_BAN_VOTERS )
2019-06-27 22:53:26 -07:00
2019-08-31 20:28:21 -07:00
if vote_passed :
2020-07-21 20:46:56 -07:00
try :
await ctx . guild . ban ( target_user )
2020-07-22 08:04:06 -07:00
await ctx . send ( " 🦀🦀 ` {} ` IS GONE 🦀🦀 " . format ( target_user . name ) )
2020-07-21 20:46:56 -07:00
except discord . ext . commands . errors . CommandInvokeError :
await error_admin_targeted ( ctx )
2019-06-28 23:25:21 -07:00
banning_users . remove ( target_user )
2020-07-21 20:21:00 -07:00
@bot.command ( )
async def test ( ctx , target_user : discord . User ) :
await require_lower_permissions ( ctx , target_user , bot )
await ctx . send ( " success " )
2022-05-04 21:17:33 -07:00
bot . run ( BOT_TOKEN )