diff options
author | 0ceanlight <59946346+0ceanlight@users.noreply.github.com> | 2020-07-24 01:36:24 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-24 01:36:24 +0000 |
commit | 95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e (patch) | |
tree | e6167e7c47e24f1b2f8b3346d2acdc20edef6126 /cogs | |
parent | c8ed74e1b9ffc3070c76fe7f84350df390fc4a50 (diff) | |
parent | 41526349740b6ed8e4d5564ed67934016126d7be (diff) | |
download | steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar.gz steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar.bz2 steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar.lz steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar.xz steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.tar.zst steve-bot-95a61e8d70eb8069d3c7adb2ecf7d59d252cef3e.zip |
Merge pull request #2 from AnInternetTroll/master
updating fork
Diffstat (limited to '')
-rwxr-xr-x | cogs/admin.py | 143 | ||||
-rwxr-xr-x | cogs/general.py | 648 | ||||
-rwxr-xr-x | cogs/help.py | 395 | ||||
-rwxr-xr-x | cogs/logs.py | 16 | ||||
-rwxr-xr-x | cogs/player.py | 455 | ||||
-rwxr-xr-x | cogs/src.py | 22 | ||||
-rwxr-xr-x | cogs/trans.py | 5 | ||||
-rwxr-xr-x | cogs/utils.py | 253 |
8 files changed, 1227 insertions, 710 deletions
diff --git a/cogs/admin.py b/cogs/admin.py index 3cb7ff8..3a6299f 100755 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -1,7 +1,6 @@ from discord.ext import commands import discord import asyncio -import subprocess import json import git import os @@ -12,30 +11,35 @@ class Admin(commands.Cog): async def is_mod(ctx): return ctx.author.guild_permissions.manage_channels - + + async def is_botmaster(ctx): + return ctx.author.id in ctx.bot.config[str(ctx.message.guild.id)]["bot_masters"] + @commands.command(aliases=['deleteEverything'], hidden=True) - @commands.check(is_mod) - async def purge(self, ctx, password): - if password == "MaxCantBeTrusted": - async for msg in ctx.channel.history(): - await msg.delete() + @commands.check(is_botmaster) + async def purge(self, ctx): + await ctx.message.channel.purge(limit=500) @commands.command(aliases=['quit'], hidden=True) - @commands.check(is_mod) - async def forceexit(self, ctx, password): - if password == "abort": - ctx.message.delete() - exit() + @commands.check(is_botmaster) + async def forceexit(self, ctx): + await ctx.send('Self Destructing') + await ctx.bot.close() @commands.command() @commands.check(is_mod) async def pull(self, ctx): + """Update the bot from github""" g = git.cmd.Git(os.getcwd()) - await ctx.send(f"Probably pulled.\n```bash\n{g.pull()}```") + try: + await ctx.send(f"Probably pulled.\n```bash\n{g.pull()}```") + except git.exc.GitCommandError as e: + await ctx.send(f"An error has occured when pulling```bash\n{e}```") @commands.command(aliases=['addcommand', 'newcommand']) @commands.check(is_mod) async def setcommand(self, ctx, command, *, message): + """Add a new simple command""" self.bot.custom_commands[ctx.prefix + command] = message with open('custom_commands.json', 'w') as f: json.dump(self.bot.custom_commands, f, indent=4) @@ -45,20 +49,20 @@ class Admin(commands.Cog): @commands.command(aliases=['deletecommand']) @commands.check(is_mod) async def removecommand(self, ctx, command): + """Remove a simple command""" del self.bot.custom_commands[ctx.prefix + command] with open('custom_commands.json', 'w') as f: json.dump(self.bot.custom_commands, f, indent=4) await ctx.send(f"Removed command {command}") - - - @commands.check(is_mod) + @commands.command(name='reload', hidden=True, usage='<extension>') + @commands.check(is_mod) async def _reload(self, ctx, ext): """Reloads an extension""" try: self.bot.reload_extension(f'cogs.{ext}') - await ctx.send(f'The extension {ext} was realoaded!') # Oceanlight told me too + await ctx.send(f'The extension {ext} was reloaded!') except commands.ExtensionNotFound: await ctx.send(f'The extension {ext} doesn\'t exist.') except commands.ExtensionNotLoaded: @@ -68,9 +72,9 @@ class Admin(commands.Cog): except commands.ExtensionFailed: await ctx.send(f'Some unknown error happened while trying to reload extension {ext} (check logs)') self.bot.logger.exception(f'Failed to reload extension {ext}:') - - @commands.check(is_mod) + @commands.command(name='load', hidden=True, usage='<extension>') + @commands.check(is_mod) async def _load(self, ctx, ext): """Loads an extension""" try: @@ -86,8 +90,8 @@ class Admin(commands.Cog): await ctx.send(f'Some unknown error happened while trying to reload extension {ext} (check logs)') self.bot.logger.exception(f'Failed to reload extension {ext}:') - @commands.check(is_mod) @commands.command(name='unload', hidden=True, usage='<extension>') + @commands.check(is_mod) async def _unload(self, ctx, ext): """Loads an extension""" try: @@ -101,27 +105,14 @@ class Admin(commands.Cog): await ctx.send(f'Some unknown error happened while trying to reload extension {ext} (check logs)') self.bot.logger.exception(f'Failed to unload extension {ext}:') - """ - @commands.command() - @commands.check(is_mod) - async def connect(self, ctx): - await ctx.author.voice.channel.connect() - await ctx.send(f"Joined channel {ctx.author.voice.channel.name}") - - @commands.command() - @commands.check(is_mod) - async def disconnect(self, ctx): - await ctx.voice_client.disconnect() - await ctx.send(f"Left channel {ctx.author.voice.channel.name}") - """ - @commands.command() @commands.check(is_mod) async def clear(self, ctx, number): + """Mass delete messages""" await ctx.message.channel.purge(limit=int(number)+1, check=None, before=None, after=None, around=None, oldest_first=False, bulk=True) - @commands.check(is_mod) @commands.command() + @commands.check(is_mod) async def mute(self, ctx, members: commands.Greedy[discord.Member]=False, mute_minutes: int = 0, *, reason: str = "absolutely no reason"): @@ -130,11 +121,11 @@ class Admin(commands.Cog): if not members: await ctx.send("You need to name someone to mute") return - elif type(members)=="str": - members = self.bot.get_user(int(user)) + elif type(members)==str: + members = [self.bot.get_user(int(members))] #muted_role = discord.utils.find(ctx.guild.roles, name="Muted") - muted_role = ctx.guild.get_role(707707894694412371) + muted_role = ctx.guild.get_role(int(self.bot.config[str(ctx.message.guild.id)]["mute_role"])) for member in members: if self.bot.user == member: # what good is a muted bot? embed = discord.Embed(title = "You can't mute me, I'm an almighty bot") @@ -148,31 +139,59 @@ class Admin(commands.Cog): for member in members: await member.remove_roles(muted_role, reason = "time's up ") - @commands.check(is_mod) @commands.command() + @commands.check(is_mod) async def unmute(self, ctx, members: commands.Greedy[discord.Member]): + """Remove the muted role""" if not members: await ctx.send("You need to name someone to unmute") return - elif type(members)=="str": + elif type(members)==str: members = self.bot.get_user(int(user)) - muted_role = ctx.guild.get_role(707707894694412371) + muted_role = ctx.guild.get_role(int(self.bot.config[str(ctx.message.guild.id)]["mute_role"])) for i in members: await i.remove_roles(muted_role) await ctx.send("{0.mention} has been unmuted by {1.mention}".format(i, ctx.author)) @commands.command() - @commands.check(is_mod) - async def logs(self, ctx, *, password): - if password == "beep boop": - await ctx.message.delete() - file = discord.File("discord.log") - await ctx.send(file=file) + @commands.check(is_botmaster) + async def ban(self, ctx, members: commands.Greedy[discord.Member]=False, + ban_minutes: int = 0, + *, reason: str = "absolutely no reason"): + """Mass ban members with an optional mute_minutes parameter to time it""" + + if not members: + await ctx.send("You need to name someone to ban") + return + elif type(members)==str: + members = [self.bot.get_user(int(members))] + for member in members: + if self.bot.user == member: # what good is a muted bot? + embed = discord.Embed(title = "You can't ban me, I'm an almighty bot") + await ctx.send(embed = embed) + continue + await member.send(f"You have been banned from {ctx.guild.name} for {mute_minutes} minutes because: ```{reason}```") + await ctx.guild.ban(member, reason=reason, delete_message_days=0) + await ctx.send("{0.mention} has been banned by {1.mention} for *{2}*".format(member, ctx.author, reason)) - @commands.command(aliases=['ban'], hidden=True) + if mute_minutes > 0: + await asyncio.sleep(ban_minutes * 60) + for member in members: + await ctx.guild.unban(member, reason="Time is up") + + @commands.command() + @commands.check(is_botmaster) + async def logs(self, ctx): + """Send the discord.log file""" + await ctx.message.delete() + file = discord.File("discord.log") + await ctx.send(file=file) + + @commands.command(hidden=True) @commands.check(is_mod) async def blacklist(self, ctx, members: commands.Greedy[discord.Member]=None): + """Ban someone from using the bot""" if not members: await ctx.send("You need to name someone to blacklist") return @@ -190,6 +209,34 @@ class Admin(commands.Cog): json.dump(self.bot.blacklist, f, indent=4) await ctx.send(f"{i} has been blacklisted.") + @commands.command() + @commands.check(is_mod) + async def activity(self, ctx, *, activity=None): + """Change the bot's activity""" + if activity: + game = discord.Game(activity) + else: + activity = "Mining away" + game = discord.Game(activity) + await self.bot.change_presence(activity=game) + await ctx.send(f"Activity changed to {activity}") + + @commands.command() + @commands.check(is_botmaster) + async def setvar(self, ctx, key, *, value): + """Set a config variable, ***use with caution**""" + with open('config.json', 'w') as f: + if value[0] == '[' and value[len(value)-1] == ']': + value = list(map(int, value[1:-1].split(','))) + self.bot.config[str(ctx.message.guild.id)][key] = value + json.dump(self.bot.config, f, indent=4) + + @commands.command() + @commands.check(is_mod) + async def printvar(self, ctx, key): + """Print a config variable, use for testing""" + await ctx.send(self.bot.config[str(ctx.message.guild.id)][key]) + def setup(bot): bot.add_cog(Admin(bot)) diff --git a/cogs/general.py b/cogs/general.py index ff60bb7..cf05eb4 100755 --- a/cogs/general.py +++ b/cogs/general.py @@ -1,6 +1,16 @@ from discord.ext import commands
import discord
import datetime
+import requests
+import json
+import dateutil.parser
+from random import randint
+import os, sys, inspect
+current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parent_dir = os.path.dirname(current_dir)
+sys.path.insert(0, parent_dir)
+import bot
+
def dump(obj):
output = ""
@@ -10,39 +20,419 @@ def dump(obj): return output
+class MyHelpCommand(commands.MinimalHelpCommand):
+ messages = [
+ "As seen on TV!",
+ "Awesome!",
+ "100% pure!",
+ "May contain nuts!",
+ "Better than Prey!",
+ "More polygons!",
+ "Sexy!",
+ "Limited edition!",
+ "Flashing letters!",
+ "Made by Notch!",
+ "It's here!",
+ "Best in class!",
+ "It's finished!",
+ "Kind of dragon free!",
+ "Excitement!",
+ "More than 500 sold!",
+ "One of a kind!",
+ "Heaps of hits on YouTube!",
+ "Indev!",
+ "Spiders everywhere!",
+ "Check it out!",
+ "Holy cow",
+ " man!",
+ "It's a game!",
+ "Made in Sweden!",
+ "Uses LWJGL!",
+ "Reticulating splines!",
+ "Minecraft!",
+ "Yaaay!",
+ "Singleplayer!",
+ "Keyboard compatible!",
+ "Undocumented!",
+ "Ingots!",
+ "Exploding creepers!",
+ "That's no moon!",
+ "l33t!",
+ "Create!",
+ "Survive!",
+ "Dungeon!",
+ "Exclusive!",
+ "The bee's knees!",
+ "Down with O.P.P.!",
+ "Closed source!",
+ "Classy!",
+ "Wow!",
+ "Not on steam!",
+ "Oh man!",
+ "Awesome community!",
+ "Pixels!",
+ "Teetsuuuuoooo!",
+ "Kaaneeeedaaaa!",
+ "Now with difficulty!",
+ "Enhanced!",
+ "90% bug free!",
+ "Pretty!",
+ "12 herbs and spices!",
+ "Fat free!",
+ "Absolutely no memes!",
+ "Free dental!",
+ "Ask your doctor!",
+ "Minors welcome!",
+ "Cloud computing!",
+ "Legal in Finland!",
+ "Hard to label!",
+ "Technically good!",
+ "Bringing home the bacon!",
+ "Indie!",
+ "GOTY!",
+ "Ceci n'est pas une title screen!",
+ "Euclidian!",
+ "Now in 3D!",
+ "Inspirational!",
+ "Herregud!",
+ "Complex cellular automata!",
+ "Yes",
+ " sir!",
+ "Played by cowboys!",
+ "OpenGL 1.2!",
+ "Thousands of colors!",
+ "Try it!",
+ "Age of Wonders is better!",
+ "Try the mushroom stew!",
+ "Sensational!",
+ "Hot tamale",
+ " hot hot tamale!",
+ "Play him off",
+ " keyboard cat!",
+ "Guaranteed!",
+ "Macroscopic!",
+ "Bring it on!",
+ "Random splash!",
+ "Call your mother!",
+ "Monster infighting!",
+ "Loved by millions!",
+ "Ultimate edition!",
+ "Freaky!",
+ "You've got a brand new key!",
+ "Water proof!",
+ "Uninflammable!",
+ "Whoa",
+ " dude!",
+ "All inclusive!",
+ "Tell your friends!",
+ "NP is not in P!",
+ "Notch <3 ez!",
+ "Music by C418!",
+ "Livestreamed!",
+ "Haunted!",
+ "Polynomial!",
+ "Terrestrial!",
+ "All is full of love!",
+ "Full of stars!",
+ "Scientific!",
+ "Cooler than Spock!",
+ "Collaborate and listen!",
+ "Never dig down!",
+ "Take frequent breaks!",
+ "Not linear!",
+ "Han shot first!",
+ "Nice to meet you!",
+ "Buckets of lava!",
+ "Ride the pig!",
+ "Larger than Earth!",
+ "sqrt(-1) love you!",
+ "Phobos anomaly!",
+ "Punching wood!",
+ "Falling off cliffs!",
+ "0% sugar!",
+ "150% hyperbole!",
+ "Synecdoche!",
+ "Let's danec!",
+ "Seecret Friday update!",
+ "Reference implementation!",
+ "Lewd with two dudes with food!",
+ "Kiss the sky!",
+ "20 GOTO 10!",
+ "Verlet intregration!",
+ "Peter Griffin!",
+ "Do not distribute!",
+ "Cogito ergo sum!",
+ "4815162342 lines of code!",
+ "A skeleton popped out!",
+ "The Work of Notch!",
+ "The sum of its parts!",
+ "BTAF used to be good!",
+ "I miss ADOM!",
+ "umop-apisdn!",
+ "OICU812!",
+ "Bring me Ray Cokes!",
+ "Finger-licking!",
+ "Thematic!",
+ "Pneumatic!",
+ "Sublime!",
+ "Octagonal!",
+ "Une baguette!",
+ "Gargamel plays it!",
+ "Rita is the new top dog!",
+ "SWM forever!",
+ "Representing Edsbyn!",
+ "Matt Damon!",
+ "Supercalifragilisticexpialidocious!",
+ "Consummate V's!",
+ "Cow Tools!",
+ "Double buffered!",
+ "Fan fiction!",
+ "Flaxkikare!",
+ "Jason! Jason! Jason!",
+ "Hotter than the sun!",
+ "Internet enabled!",
+ "Autonomous!",
+ "Engage!",
+ "Fantasy!",
+ "DRR! DRR! DRR!",
+ "Kick it root down!",
+ "Regional resources!",
+ "Woo",
+ " facepunch!",
+ "Woo",
+ " somethingawful!",
+ "Woo",
+ " /v/!",
+ "Woo",
+ " tigsource!",
+ "Woo",
+ " minecraftforum!",
+ "Woo",
+ " worldofminecraft!",
+ "Woo",
+ " reddit!",
+ "Woo",
+ " 2pp!",
+ "Google anlyticsed!",
+ "Now supports åäö!",
+ "Give us Gordon!",
+ "Tip your waiter!",
+ "Very fun!",
+ "12345 is a bad password!",
+ "Vote for net neutrality!",
+ "Lives in a pineapple under the sea!",
+ "MAP11 has two names!",
+ "Omnipotent!",
+ "Gasp!",
+ "...!",
+ "Bees",
+ " bees",
+ " bees",
+ " bees!",
+ "Jag känner en bot!",
+ "This text is hard to read if you play the game at the default resolution",
+ " but at 1080p it's fine!",
+ "Haha",
+ " LOL!",
+ "Hampsterdance!",
+ "Switches and ores!",
+ "Menger sponge!",
+ "idspispopd!",
+ "Eple (original edit)!",
+ "So fresh",
+ " so clean!",
+ "Slow acting portals!",
+ "Try the Nether!",
+ "Don't look directly at the bugs!",
+ "Oh",
+ " ok",
+ " Pigmen!",
+ "Finally with ladders!",
+ "Scary!",
+ "Play Minecraft",
+ " Watch Topgear",
+ " Get Pig!",
+ "Twittered about!",
+ "Jump up",
+ " jump up",
+ " and get down!",
+ "Joel is neat!",
+ "A riddle",
+ " wrapped in a mystery!",
+ "Huge tracts of land!",
+ "Welcome to your Doom!",
+ "Stay a while",
+ " stay forever!",
+ "Stay a while and listen!",
+ "Treatment for your rash!",
+ "\"Autological\" is!",
+ "Information wants to be free!",
+ "\"Almost never\" is an interesting concept!",
+ "Lots of truthiness!",
+ "The creeper is a spy!",
+ "Turing complete!",
+ "It's groundbreaking!",
+ "Let our battle's begin!",
+ "The sky is the limit!",
+ "Jeb has amazing hair!",
+ "Ryan also has amazing hair!",
+ "Casual gaming!",
+ "Undefeated!",
+ "Kinda like Lemmings!",
+ "Follow the train",
+ " CJ!",
+ "Leveraging synergy!",
+ "This message will never appear on the splash screen",
+ " isn't that weird?",
+ "DungeonQuest is unfair!",
+ "110813!",
+ "90210!",
+ "Check out the far lands!",
+ "Tyrion would love it!",
+ "Also try VVVVVV!",
+ "Also try Super Meat Boy!",
+ "Also try Terraria!",
+ "Also try Mount And Blade!",
+ "Also try Project Zomboid!",
+ "Also try World of Goo!",
+ "Also try Limbo!",
+ "Also try Pixeljunk Shooter!",
+ "Also try Braid!",
+ "That's super!",
+ "Bread is pain!",
+ "Read more books!",
+ "Khaaaaaaaaan!",
+ "Less addictive than TV Tropes!",
+ "More addictive than lemonade!",
+ "Bigger than a bread box!",
+ "Millions of peaches!",
+ "Fnord!",
+ "This is my true form!",
+ "Totally forgot about Dre!",
+ "Don't bother with the clones!",
+ "Pumpkinhead!",
+ "Hobo humping slobo babe!",
+ "Made by Jeb!",
+ "Has an ending!",
+ "Finally complete!",
+ "Feature packed!",
+ "Boots with the fur!",
+ "Stop",
+ " hammertime!",
+ "Testificates!",
+ "Conventional!",
+ "Homeomorphic to a 3-sphere!",
+ "Doesn't avoid double negatives!",
+ "Place ALL the blocks!",
+ "Does barrel rolls!",
+ "Meeting expectations!",
+ "PC gaming since 1873!",
+ "Ghoughpteighbteau tchoghs!",
+ "Déjà vu!",
+ "Déjà vu!",
+ "Got your nose!",
+ "Haley loves Elan!",
+ "Afraid of the big",
+ " black bat!",
+ "Doesn't use the U-word!",
+ "Child's play!",
+ "See you next Friday or so!",
+ "From the streets of Södermalm!",
+ "150 bpm for 400000 minutes!",
+ "Technologic!",
+ "Funk soul brother!",
+ "Pumpa kungen!",
+ "日本ハロー!",
+ "한국 안녕하세요!",
+ "Helo Cymru!",
+ "Cześć Polsko!",
+ "你好中国!",
+ "Привет Россия!",
+ "Γεια σου Ελλάδα!",
+ "My life for Aiur!",
+ "Lennart lennart = new Lennart();",
+ "I see your vocabulary has improved!",
+ "Who put it there?",
+ "You can't explain that!",
+ "if not ok then return end",
+ "§1C§2o§3l§4o§5r§6m§7a§8t§9i§ac",
+ "§kFUNKY LOL",
+ "SOPA means LOSER in Swedish!",
+ "Big Pointy Teeth!",
+ "Bekarton guards the gate!",
+ "Mmmph",
+ " mmph!",
+ "Don't feed avocados to parrots!",
+ "Swords for everyone!",
+ "Plz reply to my tweet!",
+ ".party()!",
+ "Take her pillow!",
+ "Put that cookie down!",
+ "Pretty scary!",
+ "I have a suggestion.",
+ "Now with extra hugs!",
+ "Now java 6!",
+ "Woah.",
+ "HURNERJSGER?",
+ "What's up",
+ " Doc?",
+ "Now contains 32 random daily cats!",
+ ""]
+ def get_command_signature(self, command):
+ return f'``{self.clean_prefix}{command.qualified_name} {command.signature}``'
+ def get_ending_note(self):
+ return self.messages[randint(0, len(self.messages)-1)]
+
class General(commands.Cog):
def __init__(self, bot):
self.bot = bot
+ self._original_help_command = bot.help_command
+ bot.help_command = MyHelpCommand()
+ bot.help_command.cog = self
+
+ def cog_unload(self):
+ self.bot.help_command = self._original_help_command
+
+ @commands.command()
+ async def prefix(self, ctx):
+ """Gets the bot prefixes"""
+ prefixes = bot.get_prefix(self.bot, ctx.message)
+ prefixes.pop(1)
+ prefixes.pop(1)
+ prefixes.pop(1)
+ output = ""
+ for i in prefixes:
+ output += i+", "
+
+ await ctx.send(f"My prefixes are {output}")
@commands.command()
async def userinfo(self, ctx, user: discord.Member=None):
+ """Get information about a user"""
#await ctx.send(f"```py\n{dump(user)}```")
if not user:
user = ctx.message.author
- elif type(user)=="str":
- user = self.bot.get_user(int(user))
- # Very very shit
- """
- await ctx.send(str(user.avatar_url))
- request.urlretrieve(str(user.avatar_url), "temp.webp")
- #filename = wget.download(user.avatar_url, out="temp.webp")
- image = Image.open("temp.webp").convert("RGB")
- image.save("temp.png", "PNG")
-
- f = discord.File("temp.png", filename="temp.png")
- #await messagable.send(file=f, embed=e)
- """
output = ""
for i in user.roles:
- output += i.mention
+ output += i.mention + " "
+ if user.color.value == 0:
+ color = 16777210
+ else:
+ color = user.color
- embed=discord.Embed(title=user.name, description=user.mention, color=user.color, timestamp=ctx.message.created_at)
+ if user.is_avatar_animated():
+ profilePic = user.avatar_url_as(format="gif")
+ else:
+ profilePic = user.avatar_url_as(format="png")
+
+ embed=discord.Embed(title=user.name, description=user.mention, color=color, timestamp=ctx.message.created_at)
+ if user.premium_since:
+ embed.add_field(name="Boosting since", value=user.premium_since.date())
#embed.set_thumbnail(url="attachment://temp.webp")
- embed.set_thumbnail(url=user.avatar_url)
- embed.set_image(url="attachment://temp.png")
+ embed.set_thumbnail(url=profilePic)
embed.add_field(name="Nickname", value=user.display_name, inline=False)
embed.add_field(name="Joined on", value=user.joined_at.date(), inline=True)
embed.add_field(name="Status", value=user.status, inline=True)
@@ -54,13 +444,14 @@ class General(commands.Cog): #os.remove("temp.png")
@commands.command()
- async def coop(self, ctx, user: discord.Member=None):
+ async def coop(self, ctx, *, user: discord.Member=None):
+ """Get the coop gang role"""
if not user:
user = ctx.message.author
- elif type(user)=="str":
+ else:
user = self.bot.get_user(int(user))
- coop_role = ctx.guild.get_role(694261282861219952)
+ coop_role = ctx.guild.get_role(int(self.bot.config[str(ctx.message.guild.id)]["coop_roleID"]))
if coop_role in user.roles:
await user.remove_roles(coop_role)
@@ -69,5 +460,222 @@ class General(commands.Cog): await user.add_roles(coop_role)
await ctx.send("You are now in the coop gang")
+ @commands.command()
+ async def serverinfo(self, ctx, guild=None):
+ """Get information about the server you are in"""
+ if not guild:
+ guild = ctx.message.guild
+ else:
+ print(type(guild))
+ guild = self.bot.get_guild(int(guild))
+
+ if guild.owner.color.value == 0:
+ color = 16777210
+ else:
+ color = guild.owner.color
+
+ emojiList = " "
+ for i in guild.emojis:
+ emojiList += str(i) + " "
+
+ if guild.is_icon_animated():
+ serverIcon = guild.icon_url_as(format="gif")
+ else:
+ serverIcon = guild.icon_url_as(format="png")
+
+ inactiveMembers = await guild.estimate_pruned_members(days=7)
+
+ embed=discord.Embed(title=guild.name, description=guild.description, color=color, timestamp=ctx.message.created_at)
+ if guild.premium_subscription_count == 0:
+ pass
+ else:
+ if guild.premium_subscription_count == 1:
+ embed.add_field(name="Boosted by:", value=f"{guild.premium_subscription_count} member", inline=True)
+ else:
+ embed.add_field(name="Boosted by:", value=f"{guild.premium_subscription_count} members", inline=True)
+ if guild.premium_subscribers:
+ boosters = ""
+ for i in guild.premium_subscribers:
+ boosters += i.mention+" "
+ embed.add_field(name="Boosted by:", value=boosters, inline=True)
+ embed.set_thumbnail(url=serverIcon)
+ embed.set_image(url=guild.splash_url_as(format="png"))
+ embed.add_field(name="Created on", value=guild.created_at.date(), inline=True)
+ embed.add_field(name="Members", value=guild.member_count, inline=True)
+ embed.add_field(name="Emojis", value=emojiList, inline=True)
+ embed.add_field(name="Owner", value=guild.owner.mention, inline=True)
+ embed.add_field(name="Members who haven't spoken in 7 days:", value=inactiveMembers, inline=True)
+ embed.set_footer(text=f"ID: {guild.id}")
+ await ctx.send(embed=embed)
+
+ @commands.command()
+ async def xboxuser(self, ctx, *, gamertag=None):
+ """Get information about an xbox live user"""
+ if not gamertag:
+ await ctx.send("You need to specify a gamer, gamer")
+ return
+
+ async with self.bot.session.get(f'https://xbl-api.prouser123.me/profile/gamertag/{gamertag}') as r:
+ gamer = json.loads(await r.text())
+
+ try:
+ await ctx.send(f"{gamer['error']}: {gamer['message']}")
+ return
+ except KeyError:
+ pass
+
+ for i in gamer["profileUsers"][0]["settings"]:
+ if i["id"] == "GameDisplayName":
+ gameName = i["value"]
+ continue
+ if i["id"] == "AppDisplayPicRaw":
+ picUrl = i["value"]
+ continue
+ if i["id"] == "Gamerscore":
+ Gamerscore = i["value"]+"<:gamerscore:727131234534424586>"
+ continue
+ if i["id"] == "AccountTier":
+ accountTier = i["value"]
+ continue
+ if i["id"] == "XboxOneRep":
+ reputation = i["value"]
+ continue
+ if i["id"] == "PreferredColor":
+ color = int(json.loads(requests.get(i["value"]).text)["primaryColor"], 16)
+ continue
+ if i["id"] == "Location":
+ location = i["value"]
+ continue
+ if i["id"] == "Bio":
+ #if len(i["value"]) == 0:
+ # Bio = "Unknown"
+ #else:
+ Bio = i["value"]
+ continue
+ if i["id"] == "Watermarks":
+ Watermarks = i["value"]
+ continue
+ if i["id"] == "RealName":
+ RealName = i["value"]
+ continue
+
+
+ embed=discord.Embed(title=gameName, description=Bio, color=color, timestamp=ctx.message.created_at)
+ embed.set_thumbnail(url=picUrl)
+ embed.add_field(name="Gamerscore", value=Gamerscore, inline=True)
+ if len(location) != 0:
+ embed.add_field(name="Location", value=location, inline=True)
+ if len(Watermarks) != 0:
+ embed.add_field(name="Watermarks", value=Watermarks, inline=True)
+ embed.add_field(name="Account Tier", value=accountTier, inline=True)
+ embed.add_field(name="Reputation", value=reputation, inline=True)
+ await ctx.send(embed=embed)
+
+ @commands.command(hidden=True)
+ async def xboxpresence(self, ctx, *, gamertag=None):
+ if not gamertag:
+ await ctx.send("You need to specify a gamer, gamer")
+ return
+
+ async with self.bot.session.get(f"https://xbl-api.prouser123.me/presence/gamertag/{gamertag}") as r:
+ gamer = json.loads(await r.text())
+
+ try:
+ await ctx.send(f"{gamer['error']}: {gamer['message']}")
+ return
+ except KeyError:
+ pass
+
+ state = gamer["state"]
+
+ try:
+ game = json.loads(requests.get(f"https://xbl-api.prouser123.me/titleinfo/{gamer['lastSeen']['titleId']}").text)
+ gameName = game["titles"][0]["name"]
+ gamePic = game["titles"][0]["images"][4]["url"]
+ timestamp = dateutil.parser.isoparse(gamer["lastSeen"]["timestamp"])
+ lastSeen = True
+ except Exception as e:
+ print(e)
+ lastSeen = False
+
+ if lastSeen:
+ embed=discord.Embed(title=gamer["gamertag"], description=state, timestamp=timestamp)
+ embed.set_thumbnail(url=gamePic)
+ embed.add_field(name="Game", value=gameName, inline=True)
+ await ctx.send(embed=embed)
+ else:
+ embed=discord.Embed(title=gamer["gamertag"], description=state, timestamp=ctx.message.created_at)
+ await ctx.send(embed=embed)
+
+ @commands.command()
+ async def compile(self, ctx, language=None, *, code=None):
+ """Compile code from a variety of programming languages, powered by <https://wandbox.org/>"""
+ """
+ listRequest = requests.get("https://wandbox.org/api/list.json")
+ compilerList = json.loads(listRequest.text)
+
+ for i in compilerList:
+ if i["language"] == language:
+ compiler = i["name"]
+ print(compiler)
+ """
+ compilers = {
+ "bash": "bash",
+ "c":"gcc-head-c",
+ "c#":"dotnetcore-head",
+ "coffeescript": "coffeescript-head",
+ "cpp": "gcc-head",
+ "elixir": "elixir-head",
+ "go": "go-head",
+ "java": "openjdk-head",
+ "javascript":"nodejs-head",
+ "lua": "lua-5.3.4",
+ "perl": "perl-head",
+ "php": "php-head",
+ "python":"cpython-3.8.0",
+ "ruby": "ruby-head",
+ "rust": "rust-head",
+ "sql": "sqlite-head",
+ "swift": "swift-5.0.1",
+ "typescript":"typescript-3.5.1",
+ "vim-script": "vim-head"
+ }
+ if not language:
+ await ctx.send(f"```json\n{json.dumps(compilers, indent=4)}```")
+ if not code:
+ await ctx.send("No code found")
+ return
+ try:
+ compiler = compilers[language.lower()]
+ except KeyError:
+ await ctx.send("Language not found")
+ return
+ body = {
+ "compiler": compiler,
+ "code": code,
+ "save": True
+ }
+ head = {
+ "Content-Type":"application/json"
+ }
+ async with ctx.typing():
+ async with self.bot.session.post("https://wandbox.org/api/compile.json", headers=head, data=json.dumps(body)) as r:
+ #r = requests.post("https://wandbox.org/api/compile.json", headers=head, data=json.dumps(body))
+ try:
+ response = json.loads(await r.text())
+ #await ctx.send(f"```json\n{json.dumps(response, indent=4)}```")
+ print(f"```json\n{json.dumps(response, indent=4)}```")
+ except json.decoder.JSONDecodeError:
+ await ctx.send(f"```json\n{r.text}```")
+
+ try:
+ embed=discord.Embed(title="Compiled code")
+ embed.add_field(name="Output", value=f'```{response["program_message"]}```', inline=False)
+ embed.add_field(name="Exit code", value=response["status"], inline=True)
+ embed.add_field(name="Link", value=f"[Permalink]({response['url']})", inline=True)
+ await ctx.send(embed=embed)
+ except KeyError:
+ await ctx.send(f"```json\n{json.dumps(response, indent=4)}```")
+
def setup(bot):
bot.add_cog(General(bot))
diff --git a/cogs/help.py b/cogs/help.py deleted file mode 100755 index 91c9c45..0000000 --- a/cogs/help.py +++ /dev/null @@ -1,395 +0,0 @@ -from discord.ext import commands
-from random import randint
-import os, sys, inspect
-current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
-parent_dir = os.path.dirname(current_dir)
-sys.path.insert(0, parent_dir)
-import bot
-
-class MyHelpCommand(commands.MinimalHelpCommand):
- messages = [
- "As seen on TV!",
- "Awesome!",
- "100% pure!",
- "May contain nuts!",
- "Better than Prey!",
- "More polygons!",
- "Sexy!",
- "Limited edition!",
- "Flashing letters!",
- "Made by Notch!",
- "It's here!",
- "Best in class!",
- "It's finished!",
- "Kind of dragon free!",
- "Excitement!",
- "More than 500 sold!",
- "One of a kind!",
- "Heaps of hits on YouTube!",
- "Indev!",
- "Spiders everywhere!",
- "Check it out!",
- "Holy cow",
- " man!",
- "It's a game!",
- "Made in Sweden!",
- "Uses LWJGL!",
- "Reticulating splines!",
- "Minecraft!",
- "Yaaay!",
- "Singleplayer!",
- "Keyboard compatible!",
- "Undocumented!",
- "Ingots!",
- "Exploding creepers!",
- "That's no moon!",
- "l33t!",
- "Create!",
- "Survive!",
- "Dungeon!",
- "Exclusive!",
- "The bee's knees!",
- "Down with O.P.P.!",
- "Closed source!",
- "Classy!",
- "Wow!",
- "Not on steam!",
- "Oh man!",
- "Awesome community!",
- "Pixels!",
- "Teetsuuuuoooo!",
- "Kaaneeeedaaaa!",
- "Now with difficulty!",
- "Enhanced!",
- "90% bug free!",
- "Pretty!",
- "12 herbs and spices!",
- "Fat free!",
- "Absolutely no memes!",
- "Free dental!",
- "Ask your doctor!",
- "Minors welcome!",
- "Cloud computing!",
- "Legal in Finland!",
- "Hard to label!",
- "Technically good!",
- "Bringing home the bacon!",
- "Indie!",
- "GOTY!",
- "Ceci n'est pas une title screen!",
- "Euclidian!",
- "Now in 3D!",
- "Inspirational!",
- "Herregud!",
- "Complex cellular automata!",
- "Yes",
- " sir!",
- "Played by cowboys!",
- "OpenGL 1.2!",
- "Thousands of colors!",
- "Try it!",
- "Age of Wonders is better!",
- "Try the mushroom stew!",
- "Sensational!",
- "Hot tamale",
- " hot hot tamale!",
- "Play him off",
- " keyboard cat!",
- "Guaranteed!",
- "Macroscopic!",
- "Bring it on!",
- "Random splash!",
- "Call your mother!",
- "Monster infighting!",
- "Loved by millions!",
- "Ultimate edition!",
- "Freaky!",
- "You've got a brand new key!",
- "Water proof!",
- "Uninflammable!",
- "Whoa",
- " dude!",
- "All inclusive!",
- "Tell your friends!",
- "NP is not in P!",
- "Notch <3 ez!",
- "Music by C418!",
- "Livestreamed!",
- "Haunted!",
- "Polynomial!",
- "Terrestrial!",
- "All is full of love!",
- "Full of stars!",
- "Scientific!",
- "Cooler than Spock!",
- "Collaborate and listen!",
- "Never dig down!",
- "Take frequent breaks!",
- "Not linear!",
- "Han shot first!",
- "Nice to meet you!",
- "Buckets of lava!",
- "Ride the pig!",
- "Larger than Earth!",
- "sqrt(-1) love you!",
- "Phobos anomaly!",
- "Punching wood!",
- "Falling off cliffs!",
- "0% sugar!",
- "150% hyperbole!",
- "Synecdoche!",
- "Let's danec!",
- "Seecret Friday update!",
- "Reference implementation!",
- "Lewd with two dudes with food!",
- "Kiss the sky!",
- "20 GOTO 10!",
- "Verlet intregration!",
- "Peter Griffin!",
- "Do not distribute!",
- "Cogito ergo sum!",
- "4815162342 lines of code!",
- "A skeleton popped out!",
- "The Work of Notch!",
- "The sum of its parts!",
- "BTAF used to be good!",
- "I miss ADOM!",
- "umop-apisdn!",
- "OICU812!",
- "Bring me Ray Cokes!",
- "Finger-licking!",
- "Thematic!",
- "Pneumatic!",
- "Sublime!",
- "Octagonal!",
- "Une baguette!",
- "Gargamel plays it!",
- "Rita is the new top dog!",
- "SWM forever!",
- "Representing Edsbyn!",
- "Matt Damon!",
- "Supercalifragilisticexpialidocious!",
- "Consummate V's!",
- "Cow Tools!",
- "Double buffered!",
- "Fan fiction!",
- "Flaxkikare!",
- "Jason! Jason! Jason!",
- "Hotter than the sun!",
- "Internet enabled!",
- "Autonomous!",
- "Engage!",
- "Fantasy!",
- "DRR! DRR! DRR!",
- "Kick it root down!",
- "Regional resources!",
- "Woo",
- " facepunch!",
- "Woo",
- " somethingawful!",
- "Woo",
- " /v/!",
- "Woo",
- " tigsource!",
- "Woo",
- " minecraftforum!",
- "Woo",
- " worldofminecraft!",
- "Woo",
- " reddit!",
- "Woo",
- " 2pp!",
- "Google anlyticsed!",
- "Now supports åäö!",
- "Give us Gordon!",
- "Tip your waiter!",
- "Very fun!",
- "12345 is a bad password!",
- "Vote for net neutrality!",
- "Lives in a pineapple under the sea!",
- "MAP11 has two names!",
- "Omnipotent!",
- "Gasp!",
- "...!",
- "Bees",
- " bees",
- " bees",
- " bees!",
- "Jag känner en bot!",
- "This text is hard to read if you play the game at the default resolution",
- " but at 1080p it's fine!",
- "Haha",
- " LOL!",
- "Hampsterdance!",
- "Switches and ores!",
- "Menger sponge!",
- "idspispopd!",
- "Eple (original edit)!",
- "So fresh",
- " so clean!",
- "Slow acting portals!",
- "Try the Nether!",
- "Don't look directly at the bugs!",
- "Oh",
- " ok",
- " Pigmen!",
- "Finally with ladders!",
- "Scary!",
- "Play Minecraft",
- " Watch Topgear",
- " Get Pig!",
- "Twittered about!",
- "Jump up",
- " jump up",
- " and get down!",
- "Joel is neat!",
- "A riddle",
- " wrapped in a mystery!",
- "Huge tracts of land!",
- "Welcome to your Doom!",
- "Stay a while",
- " stay forever!",
- "Stay a while and listen!",
- "Treatment for your rash!",
- "\"Autological\" is!",
- "Information wants to be free!",
- "\"Almost never\" is an interesting concept!",
- "Lots of truthiness!",
- "The creeper is a spy!",
- "Turing complete!",
- "It's groundbreaking!",
- "Let our battle's begin!",
- "The sky is the limit!",
- "Jeb has amazing hair!",
- "Ryan also has amazing hair!",
- "Casual gaming!",
- "Undefeated!",
- "Kinda like Lemmings!",
- "Follow the train",
- " CJ!",
- "Leveraging synergy!",
- "This message will never appear on the splash screen",
- " isn't that weird?",
- "DungeonQuest is unfair!",
- "110813!",
- "90210!",
- "Check out the far lands!",
- "Tyrion would love it!",
- "Also try VVVVVV!",
- "Also try Super Meat Boy!",
- "Also try Terraria!",
- "Also try Mount And Blade!",
- "Also try Project Zomboid!",
- "Also try World of Goo!",
- "Also try Limbo!",
- "Also try Pixeljunk Shooter!",
- "Also try Braid!",
- "That's super!",
- "Bread is pain!",
- "Read more books!",
- "Khaaaaaaaaan!",
- "Less addictive than TV Tropes!",
- "More addictive than lemonade!",
- "Bigger than a bread box!",
- "Millions of peaches!",
- "Fnord!",
- "This is my true form!",
- "Totally forgot about Dre!",
- "Don't bother with the clones!",
- "Pumpkinhead!",
- "Hobo humping slobo babe!",
- "Made by Jeb!",
- "Has an ending!",
- "Finally complete!",
- "Feature packed!",
- "Boots with the fur!",
- "Stop",
- " hammertime!",
- "Testificates!",
- "Conventional!",
- "Homeomorphic to a 3-sphere!",
- "Doesn't avoid double negatives!",
- "Place ALL the blocks!",
- "Does barrel rolls!",
- "Meeting expectations!",
- "PC gaming since 1873!",
- "Ghoughpteighbteau tchoghs!",
- "Déjà vu!",
- "Déjà vu!",
- "Got your nose!",
- "Haley loves Elan!",
- "Afraid of the big",
- " black bat!",
- "Doesn't use the U-word!",
- "Child's play!",
- "See you next Friday or so!",
- "From the streets of Södermalm!",
- "150 bpm for 400000 minutes!",
- "Technologic!",
- "Funk soul brother!",
- "Pumpa kungen!",
- "日本ハロー!",
- "한국 안녕하세요!",
- "Helo Cymru!",
- "Cześć Polsko!",
- "你好中国!",
- "Привет Россия!",
- "Γεια σου Ελλάδα!",
- "My life for Aiur!",
- "Lennart lennart = new Lennart();",
- "I see your vocabulary has improved!",
- "Who put it there?",
- "You can't explain that!",
- "if not ok then return end",
- "§1C§2o§3l§4o§5r§6m§7a§8t§9i§ac",
- "§kFUNKY LOL",
- "SOPA means LOSER in Swedish!",
- "Big Pointy Teeth!",
- "Bekarton guards the gate!",
- "Mmmph",
- " mmph!",
- "Don't feed avocados to parrots!",
- "Swords for everyone!",
- "Plz reply to my tweet!",
- ".party()!",
- "Take her pillow!",
- "Put that cookie down!",
- "Pretty scary!",
- "I have a suggestion.",
- "Now with extra hugs!",
- "Now java 6!",
- "Woah.",
- "HURNERJSGER?",
- "What's up",
- " Doc?",
- "Now contains 32 random daily cats!",
- ""]
- def get_command_signature(self, command):
- return f'``{self.clean_prefix}{command.qualified_name} {command.signature}``'
- def get_ending_note(self):
- return self.messages[randint(0, len(self.messages)-1)]
-
-class Help(commands.Cog):
- def __init__(self, bot):
- self.bot = bot
- self._original_help_command = bot.help_command
- bot.help_command = MyHelpCommand()
- bot.help_command.cog = self
-
- def cog_unload(self):
- self.bot.help_command = self._original_help_command
-
- @commands.command()
- async def prefix(self, ctx):
- prefixes = bot.get_prefix(self.bot, ctx.message)
- prefixes.pop(1)
- prefixes.pop(1)
- prefixes.pop(1)
- output = ""
- for i in prefixes:
- output += i+", "
-
- await ctx.send(f"My prefixes are {output}")
-
-def setup(bot):
- bot.add_cog(Help(bot))
diff --git a/cogs/logs.py b/cogs/logs.py index ea3870a..c1b3a49 100755 --- a/cogs/logs.py +++ b/cogs/logs.py @@ -8,12 +8,19 @@ class Logs(commands.Cog): @commands.Cog.listener() async def on_message_delete(self, message): + if (message.id in self.bot.messageBlacklist): + self.bot.messageBlacklist.remove(message.id) + return if message.guild.id != 574267523869179904: return - channel = self.bot.get_channel(718187032869994686) + if message.author.color.value == 0: + color = 16777210 + else: + color = message.author.color + channel = self.bot.get_channel(int(self.bot.config[str(message.guild.id)]["logs_channel"])) embed = discord.Embed( title='Deleted Message', - color=message.author.color, + color=color, timestamp=message.created_at ) embed.add_field( @@ -25,9 +32,12 @@ class Logs(commands.Cog): @commands.Cog.listener() async def on_message_edit(self, before, after): + if before.content == after.content: + return + if after.guild.id != 574267523869179904: return - channel = self.bot.get_channel(718187032869994686) + channel = self.bot.get_channel(int(self.bot.config[str(before.guild.id)]["logs_channel"])) if before.author.color.value == 0: color = 16777210 else: diff --git a/cogs/player.py b/cogs/player.py index 5c046a7..7013e6d 100755 --- a/cogs/player.py +++ b/cogs/player.py @@ -1,18 +1,38 @@ -import asyncio
+"""
+Please understand Music bots are complex, and that even this basic example can be daunting to a beginner.
+
+For this reason it's highly advised you familiarize yourself with discord.py, python and asyncio, BEFORE
+you attempt to write a music bot.
+
+This example makes use of: Python 3.6
+
+For a more basic voice example please read:
+ https://github.com/Rapptz/discord.py/blob/rewrite/examples/basic_voice.py
+
+This is a very basic playlist example, which allows per guild playback of unique queues.
+The commands implement very basic logic for basic usage. But allow for expansion. It would be advisable to implement
+your own permissions and usage logic for commands.
+
+e.g You might like to implement a vote before skipping the song or only allow admins to stop the player.
+
+Music bots require lots of work, and tuning. Goodluck.
+If you find any bugs feel free to ping me on discord. @Eviee#0666
+"""
import discord
-import youtube_dl
from discord.ext import commands
-from discord.ext import tasks
-from pathlib import Path
-
-# Straight up copied from
-# https://github.com/Rapptz/discord.py/blob/master/examples/basic_voice.py
-# Suppress noise about console usage from errors
-youtube_dl.utils.bug_reports_message = lambda: ''
+import asyncio
+import itertools
+import sys
+import traceback
+from async_timeout import timeout
+from functools import partial
+from youtube_dl import YoutubeDL
+from pathlib import Path
+from discord.ext import tasks
-ytdl_format_options = {
+ytdlopts = {
'format': 'bestaudio/best',
'outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s',
'restrictfilenames': True,
@@ -23,117 +43,396 @@ ytdl_format_options = { 'quiet': True,
'no_warnings': True,
'default_search': 'auto',
- 'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes
+ 'source_address': '0.0.0.0' # ipv6 addresses cause issues sometimes
}
-ffmpeg_options = {
- 'options': '-vn'
+ffmpegopts = {
+ 'before_options': '-nostdin',
+ 'options': '-vn -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'
}
-ytdl = youtube_dl.YoutubeDL(ytdl_format_options)
+ytdl = YoutubeDL(ytdlopts)
+
+
+class VoiceConnectionError(commands.CommandError):
+ """Custom Exception class for connection errors."""
+
+
+class InvalidVoiceChannel(VoiceConnectionError):
+ """Exception for cases of invalid Voice Channels."""
class YTDLSource(discord.PCMVolumeTransformer):
- def __init__(self, source, *, data, volume=0.5):
- super().__init__(source, volume)
- self.data = data
+ def __init__(self, source, *, data, requester):
+ super().__init__(source)
+ self.requester = requester
self.title = data.get('title')
- self.url = data.get('url')
+ self.web_url = data.get('webpage_url')
+
+ # YTDL info dicts (data) have other useful information you might want
+ # https://github.com/rg3/youtube-dl/blob/master/README.md
+
+ def __getitem__(self, item: str):
+ """Allows us to access attributes similar to a dict.
+
+ This is only useful when you are NOT downloading.
+ """
+ return self.__getattribute__(item)
@classmethod
- async def from_url(cls, url, *, loop=None, stream=False):
+ async def create_source(cls, ctx, search: str, *, loop, download=True):
loop = loop or asyncio.get_event_loop()
- data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream))
+
+ to_run = partial(ytdl.extract_info, url=search, download=download)
+ data = await loop.run_in_executor(None, to_run)
if 'entries' in data:
# take first item from a playlist
data = data['entries'][0]
- filename = data['url'] if stream else ytdl.prepare_filename(data)
- return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)
+ await ctx.send(f'```ini\n[Added {data["title"]} to the Queue.]\n```', delete_after=15)
+
+ if download:
+ source = ytdl.prepare_filename(data)
+ else:
+ return {'webpage_url': data['webpage_url'], 'requester': ctx.author, 'title': data['title']}
+
+ return cls(discord.FFmpegPCMAudio(source, **ffmpegopts), data=data, requester=ctx.author)
+
+ @classmethod
+ async def regather_stream(cls, data, *, loop):
+ """Used for preparing a stream, instead of downloading.
+
+ Since Youtube Streaming links expire."""
+ loop = loop or asyncio.get_event_loop()
+ requester = data['requester']
+
+ to_run = partial(ytdl.extract_info, url=data['webpage_url'], download=False)
+ data = await loop.run_in_executor(None, to_run)
+
+ return cls(discord.FFmpegPCMAudio(data['url'], **ffmpegopts), data=data, requester=requester)
+
+
+class MusicPlayer:
+ """A class which is assigned to each guild using the bot for Music.
+
+ This class implements a queue and loop, which allows for different guilds to listen to different playlists
+ simultaneously.
+
+ When the bot disconnects from the Voice it's instance will be destroyed.
+ """
+
+ __slots__ = ('bot', '_guild', '_channel', '_cog', 'queue', 'next', 'current', 'np', 'volume')
+
+ def __init__(self, ctx):
+ self.bot = ctx.bot
+ self._guild = ctx.guild
+ self._channel = ctx.channel
+ self._cog = ctx.cog
+
+ self.queue = asyncio.Queue()
+ self.next = asyncio.Event()
+
+ self.np = None # Now playing message
+ self.volume = .5
+ self.current = None
+
+ ctx.bot.loop.create_task(self.player_loop())
+
+ async def player_loop(self):
+ """Our main player loop."""
+ await self.bot.wait_until_ready()
+
+ while not self.bot.is_closed():
+ self.next.clear()
+
+ try:
+ # Wait for the next song. If we timeout cancel the player and disconnect...
+ async with timeout(300): # 5 minutes...
+ source = await self.queue.get()
+ except asyncio.TimeoutError:
+ if self in self._cog.players.values():
+ return self.destroy(self._guild)
+ return
+
+ if not isinstance(source, YTDLSource):
+ # Source was probably a stream (not downloaded)
+ # So we should regather to prevent stream expiration
+ try:
+ source = await YTDLSource.regather_stream(source, loop=self.bot.loop)
+ except Exception as e:
+ await self._channel.send(f'There was an error processing your song.\n'
+ f'```css\n[{e}]\n```')
+ continue
+
+ source.volume = self.volume
+ self.current = source
+
+ self._guild.voice_client.play(source, after=lambda _: self.bot.loop.call_soon_threadsafe(self.next.set))
+ self.np = await self._channel.send(f'**Now Playing:** `{source.title}` requested by '
+ f'`{source.requester}`')
+ await self.next.wait()
+
+ # Make sure the FFmpeg process is cleaned up.
+ source.cleanup()
+ self.current = None
+
+ try:
+ # We are no longer playing this song...
+ await self.np.delete()
+ except discord.HTTPException:
+ pass
+
+ def destroy(self, guild):
+ """Disconnect and cleanup the player."""
+ return self.bot.loop.create_task(self._cog.cleanup(guild))
class Player(commands.Cog):
+ """Music related commands."""
+
+ __slots__ = ('bot', 'players')
+
def __init__(self, bot):
self.bot = bot
self.cleanup.start()
+ self.players = {}
- async def is_in_vc(ctx):
+ async def cleanup(self, guild):
try:
- return ctx.author.voice.channel
+ await guild.voice_client.disconnect()
except AttributeError:
- return False
+ pass
+
+ try:
+ for entry in self.players[guild.id].queue._queue:
+ if isinstance(entry, YTDLSource):
+ entry.cleanup()
+ self.players[guild.id].queue._queue.clear()
+ except KeyError:
+ pass
+
+ try:
+ del self.players[guild.id]
+ except KeyError:
+ pass
+
+ async def __local_check(self, ctx):
+ """A local check which applies to all commands in this cog."""
+ if not ctx.guild:
+ raise commands.NoPrivateMessage
+ return True
+
+ async def __error(self, ctx, error):
+ """A local error handler for all errors arising from commands in this cog."""
+ if isinstance(error, commands.NoPrivateMessage):
+ try:
+ return await ctx.send('This command can not be used in Private Messages.')
+ except discord.HTTPException:
+ pass
+ elif isinstance(error, InvalidVoiceChannel):
+ await ctx.send('Error connecting to Voice Channel. '
+ 'Please make sure you are in a valid channel or provide me with one')
+
+ print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
+ traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
+
+ def get_player(self, ctx):
+ """Retrieve the guild player, or generate one."""
+ try:
+ player = self.players[ctx.guild.id]
+ except KeyError:
+ player = MusicPlayer(ctx)
+ self.players[ctx.guild.id] = player
+
+ return player
+
+ @commands.command(name='connectvc', aliases=['join'])
+ async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
+ """Connect to voice.
+
+ Parameters
+ ------------
+ channel: discord.VoiceChannel [Optional]
+ The channel to connect to. If a channel is not specified, an attempt to join the voice channel you are in
+ will be made.
+
+ This command also handles moving the bot to different channels.
+ """
+ if not channel:
+ try:
+ channel = ctx.author.voice.channel
+ except AttributeError:
+ raise InvalidVoiceChannel('No channel to join. Please either specify a valid channel or join one.')
+
+ vc = ctx.voice_client
+
+ if vc:
+ if vc.channel.id == channel.id:
+ return
+ try:
+ await vc.move_to(channel)
+ except asyncio.TimeoutError:
+ raise VoiceConnectionError(f'Moving to channel: <{channel}> timed out.')
+ else:
+ try:
+ await channel.connect()
+ except asyncio.TimeoutError:
+ raise VoiceConnectionError(f'Connecting to channel: <{channel}> timed out.')
+
+ await ctx.send(f'Connected to: **{channel}**', delete_after=20)
+
+ @commands.command(name='play', aliases=['sing'])
+ async def play_(self, ctx, *, search: str):
+ """Request a song and add it to the queue.
+
+ This command attempts to join a valid voice channel if the bot is not already in one.
+ Uses YTDL to automatically search and retrieve a song.
+
+ Parameters
+ ------------
+ search: str [Required]
+ The song to search and retrieve using YTDL. This could be a simple search, an ID or URL.
+ """
+ await ctx.trigger_typing()
+
+ vc = ctx.voice_client
+
+ if not vc:
+ await ctx.invoke(self.connect_)
- @commands.check(is_in_vc)
- @commands.command()
- async def join(self, ctx, *, channel: discord.VoiceChannel):
- """Joins a voice channel"""
+ player = self.get_player(ctx)
- if ctx.voice_client is not None:
- return await ctx.voice_client.move_to(channel)
+ # If download is False, source will be a dict which will be used later to regather the stream.
+ # If download is True, source will be a discord.FFmpegPCMAudio with a VolumeTransformer.
+ source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop, download=False)
- await channel.connect()
- @commands.command()
- async def play(self, ctx, *, query):
- """Plays a file from the local filesystem"""
+ await player.queue.put(source)
- source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(query))
- ctx.voice_client.play(source, after=lambda e: print('Player error: %s' % e) if e else None)
+ @commands.command(name='pause')
+ async def pause_(self, ctx):
+ """Pause the currently playing song."""
+ vc = ctx.voice_client
- await ctx.send('Now playing: {}'.format(query))
- @commands.command()
- async def yt(self, ctx, *, url):
- """Plays from a url (almost anything youtube_dl supports)"""
+ if not vc or not vc.is_playing():
+ return await ctx.send('I am not currently playing anything!', delete_after=20)
+ elif vc.is_paused():
+ return
+
+ vc.pause()
+ await ctx.send(f'**`{ctx.author}`**: Paused the song!')
+
+ @commands.command(name='resume')
+ async def resume_(self, ctx):
+ """Resume the currently paused song."""
+ vc = ctx.voice_client
+
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently playing anything!', delete_after=20)
+ elif not vc.is_paused():
+ return
+
+ vc.resume()
+ await ctx.send(f'**`{ctx.author}`**: Resumed the song!')
+
+ @commands.command(name='skip')
+ async def skip_(self, ctx):
+ """Skip the song."""
+ vc = ctx.voice_client
+
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently playing anything!', delete_after=20)
+
+ if vc.is_paused():
+ pass
+ elif not vc.is_playing():
+ return
+
+ vc.stop()
+ await ctx.send(f'**`{ctx.author}`**: Skipped the song!')
+
+ @commands.command(name='queue', aliases=['q', 'playlist'])
+ async def queue_info(self, ctx):
+ """Retrieve a basic queue of upcoming songs."""
+ vc = ctx.voice_client
+
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently connected to voice!', delete_after=20)
+
+ player = self.get_player(ctx)
+ if player.queue.empty():
+ return await ctx.send('There are currently no more queued songs.')
+
+ # Grab up to 5 entries from the queue...
+ upcoming = list(itertools.islice(player.queue._queue, 0, 5))
+
+ fmt = '\n'.join(f'**`{_["title"]}`**' for _ in upcoming)
+ embed = discord.Embed(title=f'Upcoming - Next {len(upcoming)}', description=fmt)
+
+ await ctx.send(embed=embed)
+
+ @commands.command(name='now_playing', aliases=['np', 'current', 'currentsong', 'playing'])
+ async def now_playing_(self, ctx):
+ """Display information about the currently playing song."""
+ vc = ctx.voice_client
+
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently connected to voice!', delete_after=20)
+
+ player = self.get_player(ctx)
+ if not player.current:
+ return await ctx.send('I am not currently playing anything!')
+
+ try:
+ # Remove our previous now_playing message.
+ await player.np.delete()
+ except discord.HTTPException:
+ pass
- async with ctx.typing():
- player = await YTDLSource.from_url(url, loop=self.bot.loop)
- ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)
+ player.np = await ctx.send(f'**Now Playing:** `{vc.source.title}` '
+ f'requested by `{vc.source.requester}`')
- await ctx.send('Now playing: {}'.format(player.title))
+ @commands.command(name='volume', aliases=['vol'])
+ async def change_volume(self, ctx, *, vol: float):
+ """Change the player volume.
- @commands.command()
- async def stream(self, ctx, *, url):
- """Streams from a url (same as yt, but doesn't predownload)"""
+ Parameters
+ ------------
+ volume: float or int [Required]
+ The volume to set the player to in percentage. This must be between 1 and 100.
+ """
+ vc = ctx.voice_client
- async with ctx.typing():
- player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True)
- ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently connected to voice!', delete_after=20)
- await ctx.send('Now playing: {}'.format(player.title))
+ if not 0 < vol < 101:
+ return await ctx.send('Please enter a value between 1 and 100.')
- @commands.check(is_in_vc)
- @commands.command()
- async def volume(self, ctx, volume: int):
- """Changes the player's volume"""
+ player = self.get_player(ctx)
- if ctx.voice_client is None:
- return await ctx.send("Not connected to a voice channel.")
+ if vc.source:
+ vc.source.volume = vol / 100
- ctx.voice_client.source.volume = volume / 100
- await ctx.send("Changed volume to {}%".format(volume))
+ player.volume = vol / 100
+ await ctx.send(f'**`{ctx.author}`**: Set the volume to **{vol}%**')
- @commands.check(is_in_vc)
- @commands.command()
- async def stop(self, ctx):
- """Stops and disconnects the bot from voice"""
+ @commands.command(name='stop')
+ async def stop_(self, ctx):
+ """Stop the currently playing song and destroy the player.
- await ctx.voice_client.disconnect()
+ !Warning!
+ This will destroy the player assigned to your guild, also deleting any queued songs and settings.
+ """
+ vc = ctx.voice_client
- @play.before_invoke
- @yt.before_invoke
- @stream.before_invoke
- async def ensure_voice(self, ctx):
- if ctx.voice_client is None:
- if ctx.author.voice:
- await ctx.author.voice.channel.connect()
- else:
- await ctx.send("You are not connected to a voice channel.")
- raise commands.CommandError("Author not connected to a voice channel.")
- elif ctx.voice_client.is_playing():
- ctx.voice_client.stop()
+ if not vc or not vc.is_connected():
+ return await ctx.send('I am not currently playing anything!', delete_after=20)
+ await self.cleanup(ctx.guild)
+
@tasks.loop(hours=10.0)
async def cleanup(self):
for p in Path("./downloads/").glob("*"):
@@ -141,4 +440,4 @@ class Player(commands.Cog): def setup(bot):
- bot.add_cog(Player(bot))
\ No newline at end of file + bot.add_cog(Player(bot))
diff --git a/cogs/src.py b/cogs/src.py index 96bf53c..bf776e7 100755 --- a/cogs/src.py +++ b/cogs/src.py @@ -63,11 +63,6 @@ async def deleteRun(self, apiKey, ctx, run): await ctx.send("Something went wrong") await ctx.message.author.send(f"```json\n{json.dumps(json.loads(r.text),indent=4)}```") -async def clear(self): - async for msg in self.bot.get_channel(699713639866957905).history(): - await msg.delete() - - async def pendingRuns(self, ctx): mcbe_runs = 0 mcbeil_runs = 0 @@ -124,11 +119,11 @@ async def pendingRuns(self, ctx): mcbece_runs += 1 embed = discord.Embed( title=leaderboard, url=link, description=f"{categoryName} in `{str(rta).replace('000','')}` by **{player}**", color=16711680+i*60, timestamp=timestamp) - await self.bot.get_channel(699713639866957905).send(embed=embed) + await self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])).send(embed=embed) runs = runs2 gameID = gameID2 embed_stats = discord.Embed(title='Pending Run Stats', description=f"Full Game Runs: {mcbe_runs}\nIndividual Level Runs: {mcbeil_runs}\nCategory Extension Runs: {mcbece_runs}", color=16711680 + i * 60) - await self.bot.get_channel(699713639866957905).send(embed=embed_stats) + await self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])).send(embed=embed_stats) async def verifyNew(self, apiKey=None, userID=None): @@ -176,7 +171,7 @@ async def verifyNew(self, apiKey=None, userID=None): wrCounter = False runnerCounter = False - + for i in pbs["data"]: if i["place"] == 1: if i["run"]["game"] == "yd4ovvg1" or i["run"]["game"] == "v1po7r76": @@ -208,7 +203,7 @@ class Src(commands.Cog): @commands.guild_only() async def pending(self, ctx): async with ctx.typing(): - await clear(self) + await self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])).purge(limit=500) await pendingRuns(self, ctx) @commands.command(description="Reject runs quickly") @@ -231,9 +226,12 @@ class Src(commands.Cog): @commands.command() async def verify(self, ctx, apiKey=None, userID=None): - #if apiKey == None: - # await ctx.send(f"Please try again this command by getting an apiKey from https://www.speedrun.com/api/auth then do `{ctx.prefix}verify <apiKey>` in my DMs or anywhere in this server. \nBe careful who you share this key with. To learn more check out https://github.com/speedruncomorg/api/blob/master/authentication.md") - # return + self.bot.messageBlacklist.append(ctx.message.id) + if apiKey == None: + data = json.loads(Path('./api_keys.json').read_text()) + if not str(ctx.author.id) in data: + await ctx.send(f"Please try again this command by getting an apiKey from https://www.speedrun.com/api/auth then do `{ctx.prefix}verify <apiKey>` in my DMs or anywhere in this server. \nBe careful who you share this key with. To learn more check out https://github.com/speedruncomorg/api/blob/master/authentication.md") + return if ctx.guild != None: await ctx.message.delete() async with ctx.typing(): diff --git a/cogs/trans.py b/cogs/trans.py index 2c6ed71..9ca1004 100755 --- a/cogs/trans.py +++ b/cogs/trans.py @@ -20,6 +20,7 @@ async def translateMsg(text, target="en"): result['translatedText'] = result['translatedText'].replace("'", "'") result['translatedText'] = result['translatedText'].replace(""", '"') result['translatedText'] = result['translatedText'].replace("<@! ", "<@!") + result['translatedText'] = result['translatedText'].replace("<@ ", "<@") result['translatedText'] = result['translatedText'].replace("<# ", "<#") return result; @@ -28,8 +29,9 @@ class Trans(commands.Cog): def __init__(self, bot): self.bot = bot - @commands.command(help="Translate text in english (using google translate)", brief="Translate to english") + @commands.command(help="Translate text in english (using google translate)", brief="Translate to english", aliases=["翻译", "脑热", "动漫"]) async def translate(self, ctx, *, message): + """Translate to english""" response = await translateMsg(message) embed=discord.Embed(title="Translation",description=f"{ctx.message.author.mention} says:", timestamp=ctx.message.created_at, color=0x4d9aff) embed.add_field(name=f"[{response['detectedSourceLanguage']}] Source:" , value=response['input'], inline=False) @@ -38,6 +40,7 @@ class Trans(commands.Cog): @commands.command() async def trans(self, ctx, lan, *, message): + """Translate to a specific language""" response = await translateMsg(message, lan) embed=discord.Embed(title="Translation",description=f"{ctx.message.author.mention} says:", timestamp=ctx.message.created_at, color=0x4d9aff) embed.add_field(name=f"[{response['detectedSourceLanguage']}] Source:" , value=response['input'], inline=False) diff --git a/cogs/utils.py b/cogs/utils.py index 27fd708..bacf5e6 100755 --- a/cogs/utils.py +++ b/cogs/utils.py @@ -1,9 +1,7 @@ from discord.ext import commands from discord.ext import tasks import discord -import requests import json -import asyncio import datetime # forgot to import this and ended up looking mentally unstable # troll literally pointed out atleast 4 things I did wrong in 3 lines of code @@ -16,6 +14,7 @@ from selenium.webdriver.chrome.options import Options #import image as Image from PIL import Image from PIL import ImageFilter +import functools def set_viewport_size(driver, width, height): window_size = driver.execute_script(""" @@ -25,16 +24,55 @@ def set_viewport_size(driver, width, height): driver.set_window_size(*window_size) async def reportStuff(self, ctx, message): - channel = self.bot.get_channel(715549209998262322) + channel = self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["report_channel"])) embed = discord.Embed( title=f"Report from {ctx.message.author}", - description=f"{message}", + description=f"{message}", color=ctx.message.author.color, timestamp=ctx.message.created_at) await channel.send(embed=embed) await ctx.author.send("Report has been submitted") +def save_leaderboard(): + DRIVER = '/usr/lib/chromium-browser/chromedriver' + chrome_options = Options() + chrome_options.add_argument("--disable-dev-shm-usage") + chrome_options.add_argument("--headless") + chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument("--disable-gpu") + #chrome_options.binary_location = "" + driver = webdriver.Chrome(DRIVER, chrome_options=chrome_options) + set_viewport_size(driver, 1000, 1000) + driver.get('https://aninternettroll.github.io/mcbeVerifierLeaderboard/') + screenshot = driver.find_element_by_id('table').screenshot('leaderboard.png') + driver.quit() + #transparency time + img = Image.open('leaderboard.png') + img = img.convert("RGB") + pallette = Image.open("palette.png") + pallette = pallette.convert("P") + img = img.quantize(colors=256, method=3, kmeans=0, palette=pallette) + img = img.convert("RGBA") + datas = img.getdata() + + newData = [] + for item in datas: + if item[0] == 255 and item[1] == 255 and item[2] == 255: + newData.append((255, 255, 255, 0)) + else: + newData.append(item) + + img.putdata(newData) + """ + img = img.filter(ImageFilter.SHARPEN) + img = img.filter(ImageFilter.SHARPEN) + img = img.filter(ImageFilter.SHARPEN) + """ + #height, width = img.size + #img = img.resize((height*10,width*10), resample=Image.BOX) + img.save("leaderboard.png", "PNG") + class Utils(commands.Cog): def __init__(self, bot): @@ -48,10 +86,12 @@ class Utils(commands.Cog): @commands.cooldown(1, 25, commands.BucketType.guild) @commands.command() async def findseed(self, ctx): - if ctx.message.channel.id != 684787316489060422: + """Test yout luck""" + if ctx.message.channel.id != int(self.bot.config[str(ctx.message.guild.id)]["bot_channel"]): await ctx.message.delete() + ctx.command.reset_cooldown(ctx) return - + # Don't ask rigged_findseed = { 280428276810383370: 12, # Thomas's User ID @@ -67,13 +107,13 @@ class Utils(commands.Cog): randomness = randint(1, 10) if randomness <= 1: totalEyes += 1 - - await ctx.send(f"{ctx.message.author.display_name} -> your seed is a {totalEyes} eye") + await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)} -> your seed is a {totalEyes} eye") @findseed.error async def findseed_handler(self,ctx,error): if isinstance(error, commands.CommandOnCooldown): - if ctx.message.channel.id != 684787316489060422: + if ctx.message.channel.id != int(self.bot.config[str(ctx.message.guild.id)]["bot_channel"]): + ctx.command.reset_cooldown(ctx) await ctx.message.delete() return else: @@ -82,7 +122,8 @@ class Utils(commands.Cog): @commands.command() async def findsleep(self, ctx): - if ctx.message.channel.id != 684787316489060422: + """Test your sleep""" + if ctx.message.channel.id != int(self.bot.config[str(ctx.message.guild.id)]["bot_channel"]): await ctx.message.delete() return @@ -98,78 +139,61 @@ class Utils(commands.Cog): "waaakeee uuuppp!", "are they dead or asleep? I can't tell.", "wake up, muffin head", - "psst... coffeeee \:D" + "psst... coffeeee \\:D" ] - - # Set up initial message - msg = f"{ctx.message.author.display_name} -> " # Optional TODO: Create non-normal distribution sleepHrs = randint(0, 24) - # Add sleepHrs with bonus grammar check :D - if sleepHrs == 1: - msg += f"your sleep is {sleepHrs} hour long " - else: - msg += f"your sleep is {sleepHrs} hours long " - # Add extra comment based on number of sleepHrs if sleepHrs == 0: - msg += "- nice try \:D" + await ctx.send(f"{ctx.message.author.display_name} -> your sleep is 0 hours long - nice try \:D") elif sleepHrs <= 5: - msg += f"- {lessSleepMsg[randint(0, len(lessSleepMsg) - 1)]}" - elif sleepHrs >= 10: - msg += f"- {moreSleepMsg[randint(0, len(moreSleepMsg) - 1)]}" - - await ctx.send(msg) + if sleepHrs == 1: + s = '' + else: + s = 's' + await ctx.send(f"{ctx.message.author.display_name} -> your sleep is {sleepHrs} hour{s} long - {lessSleepMsg[randint(0, len(lessSleepMsg) - 1)]}") + else: + await ctx.send(f"{ctx.message.author.display_name} -> your sleep is {sleepHrs} hours long - {moreSleepMsg[randint(0, len(moreSleepMsg) - 1)]}") + + @commands.Cog.listener() + async def on_member_join(self, member): + def check(msg): + return msg.author == member and msg.type != discord.MessageType.new_member + msg = await self.bot.wait_for("message", check=check, timeout=300) + await msg.channel.send("<:PeepoPog:732172337956257872>") + @commands.Cog.listener() async def on_message(self, message): - if message.channel.id != 589110766578434078: + if not message.guild: + return + if message.channel.id != int(self.bot.config[str(message.guild.id)]["fair_channel"]): return if message.author.bot: return badWords = ["fair", "f a i r", "ⓕⓐⓘⓡ", "ⓕ ⓐ ⓘ ⓡ"] count = 0 - + coolKids = [ ['Cameron', self.bot.get_user(468262902969663488), datetime.date(2020, 10, 8)], ['Indy', self.bot.get_user(274923326890311691), datetime.date(2020, 9, 10)], ['Kai', self.bot.get_user(199070670221475842), datetime.date(2020, 11, 20)], ['Luca', self.bot.get_user(99457716614885376), datetime.date(2020, 11, 5)], ['Max', self.bot.get_user(543958509243596800), datetime.date(2020, 11, 10)], + ['Mistaken', self.bot.get_user(264121998173536256), datetime.date(2020, 7, 6)], ['Murray', self.bot.get_user(400344183333847060), datetime.date(2020, 11, 10)], + ['RKREE', self.bot.get_user(395872198323077121), datetime.date(2020, 11, 5)], # idk if she goes by her irl name but I'm sticking with it for the sake of uniformity # also idk how to pronounce prakxo - ['Samantha', self.bot.get_user(226312219787264000), datetime.date(2020, 6, 25)], + ['Samantha', self.bot.get_user(226312219787264000), datetime.date(2020, 6, 24)], ['Scott', self.bot.get_user(223937483774230528), datetime.date(2020, 6, 23)], + ['Sky', self.bot.get_user(329538915805691905), datetime.date(2020, 6, 24)], ['Thomas', self.bot.get_user(280428276810383370), datetime.date(2020, 9, 29)] ] - - - # Luca plz dont remove the bottom code (just incase the new code doesnt work, - # and also for me to laugh at how bad my code is) - - # brb while I write ugly and inefficient code in my - # conquest to make Steve the Bot bloated and unworkable - - #if datetime.date.today() == datetime.date(2020, 6, 23): - # await scott.send('Happy Birthday Scott. You\'re a boomer now! :mango:') - #elif datetime.date.today() == datetime.date(2020, 6, 25): - # await samantha.send('Happy Birthday Prakxo. You\'re a boomer now! :mango:') - #elif datetime.date.today() == datetime.date(2020, 5, 28): - # await thomas.send('Testy Test :mango:') - #elif datetime.date.today() == datetime.date(2020, 9, 29): - # await thomas.send('Now you know how the others felt :mango:') - #elif datetime.date.today() == datetime.date(2020, 10, 8): - # await cameron.send('Happy Birthday Cameron. You\'re a boomer now! :mango:') - #elif datetime.date.today() == datetime.date(2020, 11, 10): - # await murray.send('Happy Birthday Murray. You\'re a boomer now! :mango:') - #elif datetime.date.today() == datetime.date(2020, 9, 10): - # await indy.send('Happy Birthday Indy. You\'re a boomer now! :mango:) - - # Ignore the above message. I got sick and tired of looking at trash code - + + for coolKid in coolKids: if datetime.date.today() == coolKid[2]: try: @@ -178,7 +202,7 @@ class Utils(commands.Cog): self.tries = 1 except: self.tries +=1 - + for word in badWords: if word in message.content.lower(): count += 1; @@ -188,6 +212,7 @@ class Utils(commands.Cog): @commands.cooldown(1, 60, commands.BucketType.member) @commands.command() async def report(self, ctx, *, message=None): + """Send a message to the super mods about anything""" if ctx.message.guild != None: await ctx.message.delete() if message == None: @@ -198,45 +223,10 @@ class Utils(commands.Cog): @commands.cooldown(1, 20, commands.BucketType.member) @commands.command() async def leaderboard(self, ctx): + """Leaderboard of the people that matter""" async with ctx.typing(): - DRIVER = '/usr/lib/chromium-browser/chromedriver' - chrome_options = Options() - chrome_options.add_argument("--disable-dev-shm-usage") - chrome_options.add_argument("--headless") - chrome_options.add_argument("--no-sandbox") - chrome_options.add_argument("--disable-gpu") - #chrome_options.binary_location = "" - driver = webdriver.Chrome(DRIVER, chrome_options=chrome_options) - set_viewport_size(driver, 1000, 1000) - driver.get('https://aninternettroll.github.io/mcbeVerifierLeaderboard/') - screenshot = driver.find_element_by_id('table').screenshot('leaderboard.png') - driver.quit() - #transparency time - img = Image.open('leaderboard.png') - img = img.convert("RGB") - pallette = Image.open("palette.png") - pallette = pallette.convert("P") - img = img.quantize(colors=256, method=3, kmeans=0, palette=pallette) - img = img.convert("RGBA") - datas = img.getdata() - - newData = [] - for item in datas: - if item[0] == 255 and item[1] == 255 and item[2] == 255: - newData.append((255, 255, 255, 0)) - else: - newData.append(item) - - img.putdata(newData) - """ - img = img.filter(ImageFilter.SHARPEN) - img = img.filter(ImageFilter.SHARPEN) - img = img.filter(ImageFilter.SHARPEN) - """ - #height, width = img.size - #img = img.resize((height*10,width*10), resample=Image.BOX) - img.save("leaderboard.png", "PNG") - + lbFunc = functools.partial(save_leaderboard) + await self.bot.loop.run_in_executor(None, lbFunc) await ctx.send(file=discord.File("leaderboard.png")) @@ -245,72 +235,29 @@ class Utils(commands.Cog): if isinstance(error, commands.CommandOnCooldown): #return await ctx.send(f"{ctx.message.author.display_name}, you have to wait {round(error.retry_after, 2)} seconds before using this again.") - - # Why? Because I can. lel - - # celeste guyToday at 6:13 PM - # @Mango Man that's not how it works - - # Mango ManToday at 6:13 PM - # it looks fine in lightmode - # wait whats not how what works - - # celeste guyToday at 6:13 PM - # the command - - # Mango ManToday at 6:13 PM - # o - # how does it work - - # celeste guyToday at 6:14 PM - # Like for a start, nothing is defined - # use ctx D: - - # Mango ManToday at 6:14 PM - # Do I need to though? - - # celeste guyToday at 6:14 PM - # ctx.guild.members() or something - # Yes, server is not a thing - # 2nd, mention is not used like that - # You still have to send a message - # And mention in the message - - # Mango ManToday at 6:14 PM - # o - - # celeste guyToday at 6:15 PM - # 3rd, don't forget to import choice from random - - # Mango ManToday at 6:15 PM - # this is why you dont steal code from github - # I actually feel embarrased over forgetting to import random - - # celeste guyToday at 6:15 PM - # 4th, add ctx in the arguments list, or you'll get an error like "function takes 1 argument but 2 were given" - # And you will use it to send the message and get the server - # Also forgetting the import is the least embarrassing thing - # Since I did remove it - # And replaced with import randint from random - + + @commands.cooldown(1, 60, commands.BucketType.guild) @commands.command() async def someone(self, ctx): - blacklist = [536071288859656193] - if ctx.channel.id != 589110766578434078: - if ctx.author.id == 395872198323077121: - await ctx.send("grape is a bitch") - elif ctx.author.id == 521153476714299402: - await ctx.send("ZMG is smooth brain") - elif ctx.author.id == 199070670221475842: - await ctx.send(f"fuck you {ctx.message.author.mention}") - elif ctx.author.id in blacklist: - await ctx.send("not even bothering with a message for you. You're just an edgy sheep") - else: - await ctx.send(choice(ctx.guild.members).mention) + """Discord's mistake""" + if ctx.channel.id != int(self.bot.config[str(ctx.message.guild.id)]["fair_channel"]): + await ctx.send(choice(ctx.guild.members).mention) @commands.command() async def roll(self, ctx, pool): + """Toll the dice""" await ctx.send(f"You rolled a {randint(0, int(pool))}") + @commands.command(aliases=['commands', 'allcommands']) + async def listcommands(self, ctx): + """List all custom commands""" + with open('custom_commands.json', 'r') as f: + commands = json.load(f) + output = '```List of custom commands:\n' + for key in commands: + output += f'{key}, ' + output += '```' + await ctx.send(output) + def setup(bot): bot.add_cog(Utils(bot)) |