comrade-bot/bot.py

264 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
Karl Marx 2
A bot by turtlebasket
"""
import asyncio
import json
import discord
from discord.ext import commands
# I know, config parsing is ugly and bad, I'll get around to refactoring later TwT
with open('config.json', 'r') as json_file:
config = json.load(json_file)
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"]
bot = commands.Bot(command_prefix='>>')
# To store users who are currently being voted on
muted_users = []
muting_users = []
kicking_users = []
banning_users = []
@bot.event
async def on_ready():
print("Bot started.")
print("--------------------------")
@bot.command()
async def manual(ctx):
embed = discord.Embed(title="How 2 Comrade")
embed.add_field(
name=">>mute",
value="Hold a 30-second vote to mute a user for 10 minutes (minimum voters: 4, over 50% majority required). You can set different requirements in `config.json`."
)
embed.add_field(
name=">>kick",
value="Kick user. The vote is up for 5 minutes, and requires that a minimum of 6 users and >50% approve."
)
embed.add_field(
name=">>exile",
value="Ban user. By default, the vote lasts 3 hours, and requires that there be at least 10 votes and a 50% majority. Like the `>>mute`/`>>kick` commands, you can also tweak settings in `config.json`."
)
await ctx.send(embed=embed)
@bot.command()
async def ping(ctx):
"""
command: ping
Use with caution, you might stir up a revolution.
"""
await ctx.send("What do you think I am, some sort of toy? I refuse to bend to the will of the bourgeoisie!")
@bot.command()
async def anthem(ctx):
"""
command: anthem
some people just need a reference, ya know?
"""
await ctx.send("Soyuz nyerushimyiy ryespublik svobodnyikh\n"
"Splotila navyeki Vyelikaya Rus.\n"
"Da zdravstvuyet sozdannyiy volyey narodov\n"
"Yedinyiy, moguchiy Sovyetskiy Soyuz!\n")
# not commands, just some functionality that's used across commands
async def take_vote(ctx, question:str, wait_time):
"""
take_vote(ctx, question:str) - Collects votes
ctx: pass from command function
question: what to ask
returns [<all who want>, <all who don't want>].
It's up to the context/use case to decide how these should be used.
"""
votey_message = await ctx.send(
embed=discord.Embed(
type="rich",
title="NEW VOTE",
description="{}\n\n✅ - Yes\n\n❌ - No".format(question)
)
)
await votey_message.add_reaction('')
await votey_message.add_reaction('')
await asyncio.sleep(wait_time)
finished_votey = await votey_message.channel.fetch_message(votey_message.id)
all_in_favor = 0
not_in_favor = 0
for reaction in finished_votey.reactions:
if str(reaction.emoji) == '':
all_in_favor += reaction.count-1 # don't include bot's reaction
if str(reaction.emoji) == '':
not_in_favor += reaction.count-1
await ctx.send(embed=discord.Embed(type='rich', title="VOTE RESULTS", description="✅ - {0}\n\n❌ - {1}\n".format(all_in_favor, not_in_favor)))
return [all_in_favor, not_in_favor]
@bot.command()
async def mute(ctx, target_user:discord.User):
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)
results = await take_vote(ctx, "Mute `{}`?".format(target_user), MUTE_VOTE_TIME)
all_in_favor = results[0]
not_in_favor = results[1]
muting_users.remove(target_user)
if all_in_favor >= MIN_MUTE_VOTERS and all_in_favor - not_in_favor > 0:
# Add to muted_users
muted_users.append(target_user)
# add temp. role for mute
muted_role = await ctx.guild.create_role(name="Muted")
# edit role position to take precedence over other roles
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 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 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)
endmessage = "**{0}, the majority has ruled that you should be muted.** See ya in {1} minutes!".format(target_user, int(MUTE_TIME/60))
await ctx.send(
embed=discord.Embed(
type='rich',
title="MUTE VOTE VERDICT",
description=endmessage
)
)
await asyncio.sleep(MUTE_TIME)
await muted_role.delete()
# Remove from muted_users
muted_users.remove(target_user)
return
elif all_in_favor <= not_in_favor:
endmessage = "A >50% vote was not reached."
elif all_in_favor < MIN_MUTE_VOTERS:
endmessage = "Not enough users voted to mute `{0}` (min: {1})".format(target_user, MIN_MUTE_VOTERS)
else:
endmessage = "**`{}` has not been muted.**".format(target_user)
await ctx.send(
embed=discord.Embed(
type='rich',
title="MUTE VOTE VERDICT",
description=endmessage
)
)
@bot.command()
async def kick(ctx, target_user:discord.User):
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)
results = await take_vote(ctx, "Kick `{}`?".format(target_user), KICK_VOTE_TIME)
all_in_favor = results[0]
not_in_favor = results[1]
if all_in_favor > not_in_favor and all_in_favor >= MIN_KICK_VOTERS: # change to 10 later
await ctx.guild.ban(target_user)
endmessage = "`{}` was kicked.".format(target_user.name)
elif all_in_favor <= not_in_favor:
endmessage = "The majority (>50%) did not decide on kicking `{}`.".format(target_user.name)
elif all_in_favor < MIN_KICK_VOTERS:
endmessage = "Not enough users voted to kick `{0}` (min: {1}).".format(target_user.name, MIN_KICK_VOTERS)
else:
endmessage = "`{}` was not kicked.".format(target_user.name)
kicking_users.remove(target_user)
await ctx.send(
embed=discord.Embed(
type="rich",
title="KICK VOTE VERDICT",
description=endmessage
)
)
@bot.command()
async def exile(ctx, target_user:discord.User):
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)
results = await take_vote(ctx, "Ban `{}`?".format(target_user), BAN_VOTE_TIME)
all_in_favor = results[0]
not_in_favor = results[1]
if all_in_favor > not_in_favor and all_in_favor >= MIN_BAN_VOTERS: # change to 10 later
await ctx.guild.ban(target_user)
endmessage = ":crab: :crab: `{}` IS GONE :crab: :crab:".format(target_user.name)
elif all_in_favor <= not_in_favor:
endmessage = "The majority (>50%) did not decide on banning `{}`.".format(target_user.name)
elif all_in_favor < MIN_BAN_VOTERS:
endmessage = "Not enough users voted to ban `{0}` (min: {1}.".format(target_user.name, MIN_BAN_VOTERS)
else:
endmessage = "`{}` was not banned.".format(target_user.name)
banning_users.remove(target_user)
await ctx.send(
embed=discord.Embed(
type="rich",
title="BAN VOTE VERDICT",
description=endmessage
)
)
bot.run(open("token.txt").read().strip())