aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMango0x45 <thomasvoss@live.com>2020-09-12 13:13:29 +0000
committerMango0x45 <thomasvoss@live.com>2020-09-12 13:13:29 +0000
commit0baa36497519711953603db640bf099db19af826 (patch)
treea5e196ee48d6552894c683db2272de16f8d77c41
parentfed0c6b1767f3eddbabed9cc28dd0f5615889811 (diff)
downloadsteve-bot-0baa36497519711953603db640bf099db19af826.tar
steve-bot-0baa36497519711953603db640bf099db19af826.tar.gz
steve-bot-0baa36497519711953603db640bf099db19af826.tar.bz2
steve-bot-0baa36497519711953603db640bf099db19af826.tar.lz
steve-bot-0baa36497519711953603db640bf099db19af826.tar.xz
steve-bot-0baa36497519711953603db640bf099db19af826.tar.zst
steve-bot-0baa36497519711953603db640bf099db19af826.zip
Black is neat
-rwxr-xr-xbot.py153
-rwxr-xr-xcogs/admin.py8
-rwxr-xr-xcogs/general.py1359
-rwxr-xr-xcogs/logs.py97
-rwxr-xr-xcogs/player.py719
-rwxr-xr-xcogs/src.py711
-rwxr-xr-xcogs/trans.py104
-rwxr-xr-xcogs/twitter.py81
-rwxr-xr-xcogs/utils.py2
-rwxr-xr-xcogs/webserver.py87
-rwxr-xr-xmain.py78
11 files changed, 1783 insertions, 1616 deletions
diff --git a/bot.py b/bot.py
index 114b109..320a805 100755
--- a/bot.py
+++ b/bot.py
@@ -7,88 +7,91 @@ import discord
from discord.ext import commands
extensions = [
- "cogs.utils",
- "cogs.admin",
- "cogs.src",
- "cogs.trans",
- "cogs.player",
- "cogs.general",
- #"cogs.webserver",
- #"cogs.twitter",
- "cogs.logs"
+ "cogs.utils",
+ "cogs.admin",
+ "cogs.src",
+ "cogs.trans",
+ "cogs.player",
+ "cogs.general",
+ # "cogs.webserver",
+ # "cogs.twitter",
+ "cogs.logs",
]
def get_prefix(bot, message):
- """A callable Prefix for our bot. This could be edited to allow per server prefixes."""
+ """A callable Prefix for our bot. This could be edited to allow per server prefixes."""
- prefixes = ['steve ', 'STEVE ', '/', '!', '@', 'Steve ']
+ prefixes = ["steve ", "STEVE ", "/", "!", "@", "Steve "]
- # Check to see if we are outside of a guild. e.g DM's etc.
- # if not message.guild:
- # Only allow ? to be used in DMs
- # return '?'
+ # Check to see if we are outside of a guild. e.g DM's etc.
+ # if not message.guild:
+ # Only allow ? to be used in DMs
+ # return '?'
- # If we are in a guild, we allow for the user to mention us or use any of the prefixes in our list.
- return commands.when_mentioned_or(*prefixes)(bot, message)
+ # If we are in a guild, we allow for the user to mention us or use any of the prefixes in our list.
+ return commands.when_mentioned_or(*prefixes)(bot, message)
class BedrockBot(commands.Bot):
- def __init__(self):
- super().__init__(command_prefix=get_prefix,
- case_insensitive=True,
- allowed_mentions=discord.AllowedMentions(
- everyone=False, users=True, roles=False))
- self.logger = logging.getLogger('discord')
- self.messageBlacklist = []
- self.session = aiohttp.ClientSession()
-
- with open('custom_commands.json', 'r') as f:
- self.custom_commands = json.load(f)
-
- with open('config.json', 'r') as f:
- self.config = json.load(f)
- config = self.config
-
- async def on_ready(self):
- self.uptime = datetime.datetime.utcnow()
-
- game = discord.Game("Mining away")
- await self.change_presence(activity=game)
-
- with open('blacklist.json', 'r') as f:
- try:
- self.blacklist = json.load(f)
- except json.decoder.JSONDecodeError:
- self.blacklist = []
-
- with open('runs_blacklist.json', 'r') as f:
- try:
- self.runs_blacklist = json.load(f)
- except json.decoder.JSONDecodeError:
- self.runs_blacklist = {"videos": [], "players": []}
-
- for extension in extensions:
- self.load_extension(extension)
-
- self.logger.warning(f'Online: {self.user} (ID: {self.user.id})')
-
- async def on_message(self, message):
-
- if message.author.bot or message.author.id in self.blacklist:
- return
- await self.process_commands(message)
-
- try:
- command = message.content.split()[0]
- except IndexError:
- pass
- try:
- if command in self.custom_commands:
- await message.channel.send(self.custom_commands[command])
- return
- except:
- return
-
- def run(self):
- super().run(self.config["token"], reconnect=True)
+ def __init__(self):
+ super().__init__(
+ command_prefix=get_prefix,
+ case_insensitive=True,
+ allowed_mentions=discord.AllowedMentions(
+ everyone=False, users=True, roles=False
+ ),
+ )
+ self.logger = logging.getLogger("discord")
+ self.messageBlacklist = []
+ self.session = aiohttp.ClientSession()
+
+ with open("custom_commands.json", "r") as f:
+ self.custom_commands = json.load(f)
+
+ with open("config.json", "r") as f:
+ self.config = json.load(f)
+ config = self.config
+
+ async def on_ready(self):
+ self.uptime = datetime.datetime.utcnow()
+
+ game = discord.Game("Mining away")
+ await self.change_presence(activity=game)
+
+ with open("blacklist.json", "r") as f:
+ try:
+ self.blacklist = json.load(f)
+ except json.decoder.JSONDecodeError:
+ self.blacklist = []
+
+ with open("runs_blacklist.json", "r") as f:
+ try:
+ self.runs_blacklist = json.load(f)
+ except json.decoder.JSONDecodeError:
+ self.runs_blacklist = {"videos": [], "players": []}
+
+ for extension in extensions:
+ self.load_extension(extension)
+
+ self.logger.warning(f"Online: {self.user} (ID: {self.user.id})")
+
+ async def on_message(self, message):
+
+ if message.author.bot or message.author.id in self.blacklist:
+ return
+ await self.process_commands(message)
+
+ try:
+ command = message.content.split()[0]
+ except IndexError:
+ pass
+ try:
+ if command in self.custom_commands:
+ await message.channel.send(self.custom_commands[command])
+ return
+ except:
+ return
+
+ def run(self):
+ super().run(self.config["token"], reconnect=True)
diff --git a/cogs/admin.py b/cogs/admin.py
index 176c295..a966334 100755
--- a/cogs/admin.py
+++ b/cogs/admin.py
@@ -130,7 +130,7 @@ class Admin(commands.Cog):
after=None,
around=None,
oldest_first=False,
- bulk=True
+ bulk=True,
)
@commands.command()
@@ -141,7 +141,7 @@ class Admin(commands.Cog):
members: commands.Greedy[discord.Member] = False,
mute_minutes: int = 0,
*,
- reason: str = "absolutely no reason"
+ reason: str = "absolutely no reason",
):
"""Mass mute members with an optional mute_minutes parameter to time it"""
@@ -297,7 +297,9 @@ class Admin(commands.Cog):
async def delvar(self, ctx, key):
"""Deletes a config variable, be careful"""
with open("config.json", "w") as f:
- await ctx.send(f"Removed {self.bot.config[str(ctx.message.guild.id)].pop(key)}")
+ await ctx.send(
+ f"Removed {self.bot.config[str(ctx.message.guild.id)].pop(key)}"
+ )
json.dump(self.bot.config, f, indent=4)
@commands.command()
diff --git a/cogs/general.py b/cogs/general.py
index d4813db..0ad808a 100755
--- a/cogs/general.py
+++ b/cogs/general.py
@@ -12,607 +12,657 @@ from discord.ext import commands
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)
+sys.path.insert(0, parent_dir)
import bot
def dump(obj):
- output = ""
- for attr in dir(obj):
- output += "\nobj.%s = %r" % (attr, getattr(obj, attr))
- print("obj.%s = %r" % (attr, getattr(obj, attr)))
- return output
+ output = ""
+ for attr in dir(obj):
+ output += "\nobj.%s = %r" % (attr, getattr(obj, attr))
+ print("obj.%s = %r" % (attr, getattr(obj, attr)))
+ 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)]
+ 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 = ", ".join(prefixes)
-
- 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
-
- output = ""
- for i in user.roles:
- output += i.mention + " "
-
- if user.color.value == 0:
- color = 16777210
- else:
- color = user.color
-
- 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=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)
- embed.add_field(name="Created account on", value=user.created_at.date(), inline=True)
- embed.add_field(name="Roles", value=output, inline=True)
- embed.set_footer(text=f"ID: {user.id}")
- await ctx.send(embed=embed)
- #os.remove("temp.webp")
- #os.remove("temp.png")
-
- @commands.command()
- async def coop(self, ctx, *, user: discord.Member=None):
- """Get the coop gang role"""
- if not user:
- user = ctx.message.author
- else:
- user = self.bot.get_user(int(user))
-
- 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)
- await ctx.send('You have left coop gang')
- else:
- 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/>"""
- """
+ 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 = ", ".join(prefixes)
+
+ 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
+
+ output = ""
+ for i in user.roles:
+ output += i.mention + " "
+
+ if user.color.value == 0:
+ color = 16777210
+ else:
+ color = user.color
+
+ 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=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)
+ embed.add_field(
+ name="Created account on", value=user.created_at.date(), inline=True
+ )
+ embed.add_field(name="Roles", value=output, inline=True)
+ embed.set_footer(text=f"ID: {user.id}")
+ await ctx.send(embed=embed)
+ # os.remove("temp.webp")
+ # os.remove("temp.png")
+
+ @commands.command()
+ async def coop(self, ctx, *, user: discord.Member = None):
+ """Get the coop gang role"""
+ if not user:
+ user = ctx.message.author
+ else:
+ user = self.bot.get_user(int(user))
+
+ 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)
+ await ctx.send("You have left coop gang")
+ else:
+ 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)
@@ -621,63 +671,72 @@ class General(commands.Cog):
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)}```")
+ 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))
+ bot.add_cog(General(bot))
diff --git a/cogs/logs.py b/cogs/logs.py
index 21516be..9912d63 100755
--- a/cogs/logs.py
+++ b/cogs/logs.py
@@ -3,59 +3,54 @@ from discord.ext import commands
class Logs(commands.Cog):
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- @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
- 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=color,
- timestamp=message.created_at
- )
- embed.add_field(
- name='**User**', value=message.author.mention, inline=True)
- embed.add_field(
- name='**Channel**', value=message.channel.mention, inline=True)
- embed.add_field(name='**Message**', value=message.content, inline=False)
- await channel.send(embed=embed)
+ @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
+ 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=color, timestamp=message.created_at
+ )
+ embed.add_field(name="**User**", value=message.author.mention, inline=True)
+ embed.add_field(name="**Channel**", value=message.channel.mention, inline=True)
+ embed.add_field(name="**Message**", value=message.content, inline=False)
+ await channel.send(embed=embed)
- @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(int(self.bot.config[str(before.guild.id)]["logs_channel"]))
- if before.author.color.value == 0:
- color = 16777210
- else:
- color = before.author.color
- embed = discord.Embed(
- title='**Edited Message**',
- color=color,
- timestamp=after.edited_at
- )
- embed.add_field(
- name='**User**', value=before.author.mention, inline=True)
- embed.add_field(
- name='**Channel**', value=before.channel.mention, inline=True)
- embed.add_field(name='**Original Message**',
- value=before.content, inline=False)
- embed.add_field(name='**New Message**', value=after.content, inline=False)
- await channel.send(embed=embed)
+ @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(
+ int(self.bot.config[str(before.guild.id)]["logs_channel"])
+ )
+ if before.author.color.value == 0:
+ color = 16777210
+ else:
+ color = before.author.color
+ embed = discord.Embed(
+ title="**Edited Message**", color=color, timestamp=after.edited_at
+ )
+ embed.add_field(name="**User**", value=before.author.mention, inline=True)
+ embed.add_field(name="**Channel**", value=before.channel.mention, inline=True)
+ embed.add_field(name="**Original Message**", value=before.content, inline=False)
+ embed.add_field(name="**New Message**", value=after.content, inline=False)
+ await channel.send(embed=embed)
def setup(bot):
- bot.add_cog(Logs(bot))
+ bot.add_cog(Logs(bot))
diff --git a/cogs/player.py b/cogs/player.py
index 605d5ef..f21992d 100755
--- a/cogs/player.py
+++ b/cogs/player.py
@@ -31,90 +31,103 @@ from discord.ext import commands, tasks
from youtube_dl import YoutubeDL
ytdlopts = {
- 'format': 'bestaudio/best',
- 'outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s',
- 'restrictfilenames': True,
- 'noplaylist': True,
- 'nocheckcertificate': True,
- 'ignoreerrors': False,
- 'logtostderr': False,
- 'quiet': True,
- 'no_warnings': True,
- 'default_search': 'auto',
- 'source_address': '0.0.0.0' # ipv6 addresses cause issues sometimes
+ "format": "bestaudio/best",
+ "outtmpl": "downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s",
+ "restrictfilenames": True,
+ "noplaylist": True,
+ "nocheckcertificate": True,
+ "ignoreerrors": False,
+ "logtostderr": False,
+ "quiet": True,
+ "no_warnings": True,
+ "default_search": "auto",
+ "source_address": "0.0.0.0", # ipv6 addresses cause issues sometimes
}
ffmpegopts = {
- 'before_options': '-nostdin',
- 'options': '-vn -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'
+ "before_options": "-nostdin",
+ "options": "-vn -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
}
ytdl = YoutubeDL(ytdlopts)
class VoiceConnectionError(commands.CommandError):
- """Custom Exception class for connection errors."""
+ """Custom Exception class for connection errors."""
class InvalidVoiceChannel(VoiceConnectionError):
- """Exception for cases of invalid Voice Channels."""
+ """Exception for cases of invalid Voice Channels."""
class YTDLSource(discord.PCMVolumeTransformer):
+ def __init__(self, source, *, data, requester):
+ super().__init__(source)
+ self.requester = requester
- def __init__(self, source, *, data, requester):
- super().__init__(source)
- self.requester = requester
+ self.title = data.get("title")
+ self.web_url = data.get("webpage_url")
- self.title = data.get('title')
- 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
- # 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.
+ 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 create_source(cls, ctx, search: str, *, loop, download=True):
- loop = loop or asyncio.get_event_loop()
-
- 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]
-
- 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.
+ return self.__getattribute__(item)
+
+ @classmethod
+ async def create_source(cls, ctx, search: str, *, loop, download=True):
+ loop = loop or asyncio.get_event_loop()
+
+ 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]
+
+ 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']
+ loop = loop or asyncio.get_event_loop()
+ requester = data["requester"]
- to_run = partial(ytdl.extract_info, url=data['webpage_url'])
- data = await loop.run_in_executor(None, to_run)
+ to_run = partial(ytdl.extract_info, url=data["webpage_url"])
+ data = await loop.run_in_executor(None, to_run)
- return cls(discord.FFmpegPCMAudio(data['url'], **ffmpegopts), data=data, requester=requester)
+ 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.
+ """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.
@@ -122,134 +135,159 @@ class MusicPlayer:
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))
+ __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 = 0.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.removedownloads.start()
- self.players = {}
-
- async def cleanup(self, guild):
- try:
- await guild.voice_client.disconnect()
- except AttributeError:
- 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='connect', aliases=['join'])
- async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
- """Connect to voice.
+ """Music related commands."""
+
+ __slots__ = ("bot", "players")
+
+ def __init__(self, bot):
+ self.bot = bot
+ # self.removedownloads.start()
+ self.players = {}
+
+ async def cleanup(self, guild):
+ try:
+ await guild.voice_client.disconnect()
+ except AttributeError:
+ 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="connect", aliases=["join"])
+ async def connect_(self, ctx, *, channel: discord.VoiceChannel = None):
+ """Connect to voice.
Parameters
------------
@@ -259,32 +297,36 @@ class Player(commands.Cog):
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.
+ 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.
@@ -294,149 +336,166 @@ class Player(commands.Cog):
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_)
-
- player = self.get_player(ctx)
+ await ctx.trigger_typing()
- # 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)
+ vc = ctx.voice_client
+
+ if not vc:
+ await ctx.invoke(self.connect_)
- await player.queue.put(source)
-
- @commands.command(name='pause')
- async def pause_(self, ctx):
- """Pause the currently playing song."""
- vc = ctx.voice_client
-
- 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
-
- player.np = await ctx.send(f'**Now Playing:** `{vc.source.title}` '
- f'requested by `{vc.source.requester}`')
-
- @commands.command(name='volume', aliases=['vol'])
- async def change_volume(self, ctx, *, vol: float):
- """Change the player volume.
+ player = self.get_player(ctx)
+
+ # 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)
+
+ await player.queue.put(source)
+
+ @commands.command(name="pause")
+ async def pause_(self, ctx):
+ """Pause the currently playing song."""
+ vc = ctx.voice_client
+
+ 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
+
+ player.np = await ctx.send(
+ f"**Now Playing:** `{vc.source.title}` "
+ f"requested by `{vc.source.requester}`"
+ )
+
+ @commands.command(name="volume", aliases=["vol"])
+ async def change_volume(self, ctx, *, vol: float):
+ """Change the player volume.
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
+ 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)
+ if not vc or not vc.is_connected():
+ return await ctx.send(
+ "I am not currently connected to voice!", delete_after=20
+ )
- if not 0 < vol < 101:
- return await ctx.send('Please enter a value between 1 and 100.')
+ if not 0 < vol < 101:
+ return await ctx.send("Please enter a value between 1 and 100.")
- player = self.get_player(ctx)
+ player = self.get_player(ctx)
- if vc.source:
- vc.source.volume = vol / 100
+ if vc.source:
+ vc.source.volume = vol / 100
- player.volume = vol / 100
- await ctx.send(f'**`{ctx.author}`**: Set the volume to **{vol}%**')
+ player.volume = vol / 100
+ await ctx.send(f"**`{ctx.author}`**: Set the volume to **{vol}%**")
- @commands.command(name='stop')
- async def stop_(self, ctx):
- """Stop the currently playing song and destroy the player.
+ @commands.command(name="stop")
+ async def stop_(self, ctx):
+ """Stop the currently playing song and destroy the player.
!Warning!
This will destroy the player assigned to your guild, also deleting any queued songs and settings.
"""
- vc = ctx.voice_client
+ 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 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 removedownloads(self):
- for p in Path("./downloads/").glob("*"):
- p.unlink()
+ await self.cleanup(ctx.guild)
+ @tasks.loop(hours=10.0)
+ async def removedownloads(self):
+ for p in Path("./downloads/").glob("*"):
+ p.unlink()
-def setup(bot):
- bot.add_cog(Player(bot))
+def setup(bot):
+ bot.add_cog(Player(bot))
diff --git a/cogs/src.py b/cogs/src.py
index c179a51..4c1f82e 100755
--- a/cogs/src.py
+++ b/cogs/src.py
@@ -11,371 +11,388 @@ from discord.utils import get
class SubmittedRun:
- def __init__(self, game, _id, category, video, players, duration, _type):
- self.game = game
- self._id = _id
- self.category = category
- self.video = video
- self.players = players
- self.duration = duration
- self._type = _type
- self.link = f'https://www.speedrun.com/{game}/run/{_id}'
+ def __init__(self, game, _id, category, video, players, duration, _type):
+ self.game = game
+ self._id = _id
+ self.category = category
+ self.video = video
+ self.players = players
+ self.duration = duration
+ self._type = _type
+ self.link = f"https://www.speedrun.com/{game}/run/{_id}"
async def rejectRun(self, apiKey, ctx, run, reason):
- await ctx.message.delete()
- run = run.split('/')[-1]
- reject = {"status": {"status": "rejected", "reason": reason}}
- r = requests.put(f"https://www.speedrun.com/api/v1/runs/{run}/status",
- headers={
- "X-API-Key": apiKey,
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- },
- data=json.dumps(reject))
- if r.status_code == 200 or r.status_code == 204:
- await ctx.send(f'Run rejected succesfully for `{reason}`')
- else:
- await ctx.send("Something went wrong")
- await ctx.message.author.send(
- f"```json\n{json.dumps(json.loads(r.text),indent=4)}```")
+ await ctx.message.delete()
+ run = run.split("/")[-1]
+ reject = {"status": {"status": "rejected", "reason": reason}}
+ r = requests.put(
+ f"https://www.speedrun.com/api/v1/runs/{run}/status",
+ headers={
+ "X-API-Key": apiKey,
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0",
+ },
+ data=json.dumps(reject),
+ )
+ if r.status_code == 200 or r.status_code == 204:
+ await ctx.send(f"Run rejected succesfully for `{reason}`")
+ else:
+ await ctx.send("Something went wrong")
+ await ctx.message.author.send(
+ f"```json\n{json.dumps(json.loads(r.text),indent=4)}```"
+ )
async def approveRun(self, apiKey, ctx, run, reason=None):
- await ctx.message.delete()
- run = run.split('/')[-1]
- if reason == None:
- approve = {"status": {"status": "verified"}}
- else:
- approve = {"status": {"status": "verified", "reason": reason}}
- r = requests.put(f"https://www.speedrun.com/api/v1/runs/{run}/status",
- headers={
- "X-API-Key": apiKey,
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- },
- data=json.dumps(approve))
- if r.status_code == 200 or r.status_code == 204:
- await ctx.send("Run approved succesfully")
- else:
- await ctx.send("Something went wrong")
- await ctx.message.author.send(
- f"```json\n{json.dumps(json.loads(r.text),indent=4)}```")
+ await ctx.message.delete()
+ run = run.split("/")[-1]
+ if reason == None:
+ approve = {"status": {"status": "verified"}}
+ else:
+ approve = {"status": {"status": "verified", "reason": reason}}
+ r = requests.put(
+ f"https://www.speedrun.com/api/v1/runs/{run}/status",
+ headers={
+ "X-API-Key": apiKey,
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0",
+ },
+ data=json.dumps(approve),
+ )
+ if r.status_code == 200 or r.status_code == 204:
+ await ctx.send("Run approved succesfully")
+ else:
+ await ctx.send("Something went wrong")
+ await ctx.message.author.send(
+ f"```json\n{json.dumps(json.loads(r.text),indent=4)}```"
+ )
async def deleteRun(self, apiKey, ctx, run):
- await ctx.message.delete()
- run = run.split('/')[-1]
- r = requests.delete(f"https://www.speedrun.com/api/v1/runs/{run}",
- headers={
- "X-API-Key": apiKey,
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- })
- if r.status_code == 200 or r.status_code == 204:
- await ctx.send("Run deleted succesfully")
- else:
- await ctx.send("Something went wrong")
- await ctx.message.author.send(
- f"```json\n{json.dumps(json.loads(r.text),indent=4)}```")
+ await ctx.message.delete()
+ run = run.split("/")[-1]
+ r = requests.delete(
+ f"https://www.speedrun.com/api/v1/runs/{run}",
+ headers={
+ "X-API-Key": apiKey,
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0",
+ },
+ )
+ if r.status_code == 200 or r.status_code == 204:
+ await ctx.send("Run deleted succesfully")
+ else:
+ await ctx.send("Something went wrong")
+ await ctx.message.author.send(
+ f"```json\n{json.dumps(json.loads(r.text),indent=4)}```"
+ )
async def pendingRuns(self, ctx):
- def banned_player_coop(run):
- for player in run.players:
- if player in self.bot.runs_blacklist["players"]:
- return True
- return False
-
- def duplicate_run(run):
- for pending_run in pending_runs:
- if run._id != pending_run._id and run.category == pending_run.category and run.video == pending_run.video and run.duration == pending_run.duration:
- return True
- return False
-
- def get_player_name(player):
- if player["rel"] == 'user':
- return player["names"]["international"]
- else:
- return player["name"]
-
- mcbe_runs = 0
- mcbeil_runs = 0
- mcbece_runs = 0
- pending_runs = []
- runs_to_reject = []
- game_ids = ['yd4ovvg1', 'v1po7r76'] # [mcbe, mcbece]
- head = {"Accept": "application/json", "User-Agent": "mcbeDiscordBot/1.0"}
-
- for game in game_ids:
- runs_request = requests.get(
- f'https://www.speedrun.com/api/v1/runs?game={game}&status=new&max=200&embed=category,players,level&orderby=submitted',
- headers=head)
- runs = json.loads(runs_request.text)
-
- for run in runs["data"]:
- _id = run["id"]
- duration = timedelta(seconds=run["times"]["realtime_t"])
-
- if run["videos"] != None:
- try:
- video = run["videos"]["links"][0]["uri"]
- except KeyError:
- video = run["videos"]["text"]
- else:
- video = None
-
- # Get the category name for each run, while specifiying if its a full game, il, or cat ext run
- if run["level"]["data"] != []:
- category = run["level"]["data"]["name"]
- if game == 'yd4ovvg1':
- _type = 'Individual Level'
- else:
- category = run["category"]["data"]["name"]
- if game == 'yd4ovvg1':
- _type = 'Full Game Run'
-
- if game == 'v1po7r76':
- _type = 'Category Extension'
-
- # Set players to a string if solo, or a list if coop
- if len(run["players"]["data"]) == 1:
- players = get_player_name(run["players"]["data"][0])
- else:
- players = list(
- map(lambda player: get_player_name(player),
- run["players"]["data"]))
-
- pending_run = SubmittedRun(game, _id, category, video, players,
- duration, _type)
- pending_runs.append(pending_run)
-
- for run in pending_runs:
- # Reject run if video is blacklisted
- if run.video.split('/')[-1].split(
- '=')[-1] in self.bot.runs_blacklist["videos"]:
- runs_to_reject.append(
- [run, 'Detected as spam by our automatic filter.'])
-
- # Reject run if player is banned (solo runs)
- elif type(
- run.players
- ) == str and run.players in self.bot.runs_blacklist["players"]:
- runs_to_reject.append([
- run,
- f'Detected as a banned player ({run.players}) run by our automatic filter.'
- ])
-
- # Reject run if player is banned (coop runs)
- elif banned_player_coop(run) == True:
- runs_to_reject.append([
- run,
- f'Detected a banned player in the list of runners ({run.players}) by our automatic filter.'
- ])
-
- # Reject run if duplicate submission
- elif duplicate_run(run) == True:
- runs_to_reject.append([
- run,
- 'Detected as a duplicate submission by our automatic filter.'
- ])
- pending_runs.remove(run)
-
- else:
- if run._type == 'Full Game Run':
- mcbe_runs += 1
- elif run._type == 'Individual Level':
- mcbeil_runs += 1
- else:
- mcbece_runs += 1
-
- # In the case of coop, change the player names from a list to a string for prettier output
- if type(run.players) == list:
- run.players = ', '.join(map(str, run.players))
-
- embed = discord.Embed(
- title=run._type,
- url=run.link,
- description=
- f"{run.category} in `{str(run.duration).replace('000','')}` by **{run.players}**",
- color=0x9400D3)
- await self.bot.get_channel(
- int(self.bot.config[str(
- ctx.message.guild.id)]["pending_channel"])
- ).send(embed=embed)
-
- 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}\nTotal Runs: {mcbe_runs+mcbeil_runs+mcbece_runs}",
- color=0x000000)
- await self.bot.get_channel(
- int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])
- ).send(embed=embed_stats)
-
- for run in runs_to_reject:
- try:
- reject = {"status": {"status": "rejected", "reason": run[1]}}
- r = requests.put(
- f"https://www.speedrun.com/api/v1/runs/{run[0]._id}/status",
- headers={
- "X-API-Key": self.bot.config["api_key"],
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- },
- data=json.dumps(reject))
- if r.status_code == 200 or r.status_code == 204:
- await ctx.send(
- f'Run rejected succesfully for `{run[1]}`\nLink: {run[0].link}'
- )
- else:
- await ctx.send("Something went wrong")
- await ctx.message.author.send(
- f"```json\n{json.dumps(json.loads(r.text),indent=4)}```")
- except:
- continue
+ def banned_player_coop(run):
+ for player in run.players:
+ if player in self.bot.runs_blacklist["players"]:
+ return True
+ return False
+
+ def duplicate_run(run):
+ for pending_run in pending_runs:
+ if (
+ run._id != pending_run._id
+ and run.category == pending_run.category
+ and run.video == pending_run.video
+ and run.duration == pending_run.duration
+ ):
+ return True
+ return False
+
+ def get_player_name(player):
+ if player["rel"] == "user":
+ return player["names"]["international"]
+ else:
+ return player["name"]
+
+ mcbe_runs = 0
+ mcbeil_runs = 0
+ mcbece_runs = 0
+ pending_runs = []
+ runs_to_reject = []
+ game_ids = ["yd4ovvg1", "v1po7r76"] # [mcbe, mcbece]
+ head = {"Accept": "application/json", "User-Agent": "mcbeDiscordBot/1.0"}
+
+ for game in game_ids:
+ runs_request = requests.get(
+ f"https://www.speedrun.com/api/v1/runs?game={game}&status=new&max=200&embed=category,players,level&orderby=submitted",
+ headers=head,
+ )
+ runs = json.loads(runs_request.text)
+
+ for run in runs["data"]:
+ _id = run["id"]
+ duration = timedelta(seconds=run["times"]["realtime_t"])
+
+ if run["videos"] != None:
+ try:
+ video = run["videos"]["links"][0]["uri"]
+ except KeyError:
+ video = run["videos"]["text"]
+ else:
+ video = None
+
+ # Get the category name for each run, while specifiying if its a full game, il, or cat ext run
+ if run["level"]["data"] != []:
+ category = run["level"]["data"]["name"]
+ if game == "yd4ovvg1":
+ _type = "Individual Level"
+ else:
+ category = run["category"]["data"]["name"]
+ if game == "yd4ovvg1":
+ _type = "Full Game Run"
+
+ if game == "v1po7r76":
+ _type = "Category Extension"
+
+ # Set players to a string if solo, or a list if coop
+ if len(run["players"]["data"]) == 1:
+ players = get_player_name(run["players"]["data"][0])
+ else:
+ players = list(
+ map(lambda player: get_player_name(player), run["players"]["data"])
+ )
+
+ pending_run = SubmittedRun(
+ game, _id, category, video, players, duration, _type
+ )
+ pending_runs.append(pending_run)
+
+ for run in pending_runs:
+ # Reject run if video is blacklisted
+ if run.video.split("/")[-1].split("=")[-1] in self.bot.runs_blacklist["videos"]:
+ runs_to_reject.append([run, "Detected as spam by our automatic filter."])
+
+ # Reject run if player is banned (solo runs)
+ elif (
+ type(run.players) == str
+ and run.players in self.bot.runs_blacklist["players"]
+ ):
+ runs_to_reject.append(
+ [
+ run,
+ f"Detected as a banned player ({run.players}) run by our automatic filter.",
+ ]
+ )
+
+ # Reject run if player is banned (coop runs)
+ elif banned_player_coop(run) == True:
+ runs_to_reject.append(
+ [
+ run,
+ f"Detected a banned player in the list of runners ({run.players}) by our automatic filter.",
+ ]
+ )
+
+ # Reject run if duplicate submission
+ elif duplicate_run(run) == True:
+ runs_to_reject.append(
+ [run, "Detected as a duplicate submission by our automatic filter."]
+ )
+ pending_runs.remove(run)
+
+ else:
+ if run._type == "Full Game Run":
+ mcbe_runs += 1
+ elif run._type == "Individual Level":
+ mcbeil_runs += 1
+ else:
+ mcbece_runs += 1
+
+ # In the case of coop, change the player names from a list to a string for prettier output
+ if type(run.players) == list:
+ run.players = ", ".join(map(str, run.players))
+
+ embed = discord.Embed(
+ title=run._type,
+ url=run.link,
+ description=f"{run.category} in `{str(run.duration).replace('000','')}` by **{run.players}**",
+ color=0x9400D3,
+ )
+ await self.bot.get_channel(
+ int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])
+ ).send(embed=embed)
+
+ 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}\nTotal Runs: {mcbe_runs+mcbeil_runs+mcbece_runs}",
+ color=0x000000,
+ )
+ await self.bot.get_channel(
+ int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])
+ ).send(embed=embed_stats)
+
+ for run in runs_to_reject:
+ try:
+ reject = {"status": {"status": "rejected", "reason": run[1]}}
+ r = requests.put(
+ f"https://www.speedrun.com/api/v1/runs/{run[0]._id}/status",
+ headers={
+ "X-API-Key": self.bot.config["api_key"],
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0",
+ },
+ data=json.dumps(reject),
+ )
+ if r.status_code == 200 or r.status_code == 204:
+ await ctx.send(
+ f"Run rejected succesfully for `{run[1]}`\nLink: {run[0].link}"
+ )
+ else:
+ await ctx.send("Something went wrong")
+ await ctx.message.author.send(
+ f"```json\n{json.dumps(json.loads(r.text),indent=4)}```"
+ )
+ except:
+ continue
async def verifyNew(self, apiKey=None, userID=None):
- if apiKey == None:
- head = {
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- }
- else:
- head = {
- "X-API-Key": apiKey,
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
- }
- server = self.bot.get_guild(574267523869179904)
- # Troll is mentally challenged I guess ¯\_(ツ)_/¯
- RunneRole = server.get_role(574268937454223361)
- WrRole = server.get_role(583622436378116107)
- #if userID == None:
- # return
- #else:
- user = self.bot.get_user(int(userID))
- data = json.loads(Path('./api_keys.json').read_text())
-
- if str(user.id) in data:
- pbs = requests.get(
- f"https://www.speedrun.com/api/v1/users/{data[str(user.id)]}/personal-bests",
- headers=head)
- pbs = json.loads(pbs.text)
- else:
- r = requests.get('https://www.speedrun.com/api/v1/profile',
- headers=head)
- # print(r.text)
- if r.status_code >= 400:
- await user.send(f"```json\n{r.text}```")
- return
- try:
- profile = json.loads(r.text)
- except json.decoder.JSONDecodeError:
- return
- srcUserID = profile["data"]["id"]
- with open('api_keys.json', 'w') as file:
- data[user.id] = srcUserID
- json.dump(data, file, indent=4)
- pbs = requests.get(profile["data"]["links"][3]["uri"], headers=head)
- pbs = json.loads(pbs.text)
-
- wrCounter = False
- runnerCounter = False
-
- for i in pbs["data"]:
- if i["place"] == 1:
- if i["run"]["game"] == "yd4ovvg1" or i["run"]["game"] == "v1po7r76":
- if not i["run"]["level"]:
- wrCounter = True
- if i["run"]["game"] == "yd4ovvg1" or i["run"]["game"] == "v1po7r76":
- # I have no shame
- runnerCounter = True
-
- if wrCounter:
- await server.get_member(user.id).add_roles(WrRole)
- else:
- await server.get_member(user.id).remove_roles(WrRole)
- if runnerCounter:
- await server.get_member(user.id).add_roles(RunneRole)
- else:
- await server.get_member(user.id).remove_roles(RunneRole)
+ if apiKey == None:
+ head = {"Accept": "application/json", "User-Agent": "mcbeDiscordBot/1.0"}
+ else:
+ head = {
+ "X-API-Key": apiKey,
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0",
+ }
+ server = self.bot.get_guild(574267523869179904)
+ # Troll is mentally challenged I guess ¯\_(ツ)_/¯
+ RunneRole = server.get_role(574268937454223361)
+ WrRole = server.get_role(583622436378116107)
+ # if userID == None:
+ # return
+ # else:
+ user = self.bot.get_user(int(userID))
+ data = json.loads(Path("./api_keys.json").read_text())
+
+ if str(user.id) in data:
+ pbs = requests.get(
+ f"https://www.speedrun.com/api/v1/users/{data[str(user.id)]}/personal-bests",
+ headers=head,
+ )
+ pbs = json.loads(pbs.text)
+ else:
+ r = requests.get("https://www.speedrun.com/api/v1/profile", headers=head)
+ # print(r.text)
+ if r.status_code >= 400:
+ await user.send(f"```json\n{r.text}```")
+ return
+ try:
+ profile = json.loads(r.text)
+ except json.decoder.JSONDecodeError:
+ return
+ srcUserID = profile["data"]["id"]
+ with open("api_keys.json", "w") as file:
+ data[user.id] = srcUserID
+ json.dump(data, file, indent=4)
+ pbs = requests.get(profile["data"]["links"][3]["uri"], headers=head)
+ pbs = json.loads(pbs.text)
+
+ wrCounter = False
+ runnerCounter = False
+
+ for i in pbs["data"]:
+ if i["place"] == 1:
+ if i["run"]["game"] == "yd4ovvg1" or i["run"]["game"] == "v1po7r76":
+ if not i["run"]["level"]:
+ wrCounter = True
+ if i["run"]["game"] == "yd4ovvg1" or i["run"]["game"] == "v1po7r76":
+ # I have no shame
+ runnerCounter = True
+
+ if wrCounter:
+ await server.get_member(user.id).add_roles(WrRole)
+ else:
+ await server.get_member(user.id).remove_roles(WrRole)
+ if runnerCounter:
+ await server.get_member(user.id).add_roles(RunneRole)
+ else:
+ await server.get_member(user.id).remove_roles(RunneRole)
class Src(commands.Cog):
- def __init__(self, bot):
- self.bot = bot
- self.checker.start()
-
- async def is_mod(ctx):
- return ctx.author.guild_permissions.manage_channels
-
- @commands.command(description="Posts all pending runs to #pending-runs")
- @commands.guild_only()
- async def pending(self, ctx):
- async with ctx.typing():
- 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")
- @commands.check(is_mod)
- @commands.guild_only()
- async def reject(
- self,
- ctx,
- apiKey,
- run,
- *,
- reason="Rejected using Steve. No additional reason provided"):
- if apiKey == None:
- apiKey = self.bot.config['api_key']
- await rejectRun(self, apiKey, ctx, run, reason)
-
- @commands.command(description="Approve runs quickly")
- @commands.check(is_mod)
- @commands.guild_only()
- async def approve(
- self,
- ctx,
- apiKey,
- run,
- *,
- reason="Approved using Steve. No additional reason provided"):
- if apiKey == None:
- apiKey = self.bot.config['api_key']
- await approveRun(self, apiKey, ctx, run, reason)
-
- @commands.command(description="Delete runs quickly")
- async def delete(self, ctx, apiKey, run):
- await deleteRun(self, apiKey, ctx, run)
-
- @commands.command()
- async def verify(self, ctx, apiKey=None, userID=None):
- 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 this command again by getting an api key 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():
- if userID == None:
- userID = ctx.message.author.id
- await verifyNew(self, apiKey, userID)
-
- @tasks.loop(minutes=10.0)
- async def checker(self):
- data = json.loads(Path('./api_keys.json').read_text())
- for key, value in data.items():
- await verifyNew(self, None, key)
+ def __init__(self, bot):
+ self.bot = bot
+ self.checker.start()
+
+ async def is_mod(ctx):
+ return ctx.author.guild_permissions.manage_channels
+
+ @commands.command(description="Posts all pending runs to #pending-runs")
+ @commands.guild_only()
+ async def pending(self, ctx):
+ async with ctx.typing():
+ 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")
+ @commands.check(is_mod)
+ @commands.guild_only()
+ async def reject(
+ self,
+ ctx,
+ apiKey,
+ run,
+ *,
+ reason="Rejected using Steve. No additional reason provided",
+ ):
+ if apiKey == None:
+ apiKey = self.bot.config["api_key"]
+ await rejectRun(self, apiKey, ctx, run, reason)
+
+ @commands.command(description="Approve runs quickly")
+ @commands.check(is_mod)
+ @commands.guild_only()
+ async def approve(
+ self,
+ ctx,
+ apiKey,
+ run,
+ *,
+ reason="Approved using Steve. No additional reason provided",
+ ):
+ if apiKey == None:
+ apiKey = self.bot.config["api_key"]
+ await approveRun(self, apiKey, ctx, run, reason)
+
+ @commands.command(description="Delete runs quickly")
+ async def delete(self, ctx, apiKey, run):
+ await deleteRun(self, apiKey, ctx, run)
+
+ @commands.command()
+ async def verify(self, ctx, apiKey=None, userID=None):
+ 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 this command again by getting an api key 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():
+ if userID == None:
+ userID = ctx.message.author.id
+ await verifyNew(self, apiKey, userID)
+
+ @tasks.loop(minutes=10.0)
+ async def checker(self):
+ data = json.loads(Path("./api_keys.json").read_text())
+ for key, value in data.items():
+ await verifyNew(self, None, key)
def setup(bot):
- bot.add_cog(Src(bot))
+ bot.add_cog(Src(bot))
diff --git a/cogs/trans.py b/cogs/trans.py
index 965f68e..d2aead2 100755
--- a/cogs/trans.py
+++ b/cogs/trans.py
@@ -5,48 +5,74 @@ from google.cloud import translate_v2 as translate
translate_client = translate.Client()
+
async def translateMsg(text, target="en"):
- # Text can also be a sequence of strings, in which case this method
- # will return a sequence of results for each text.
- if isinstance(text, six.binary_type):
- text = text.decode('utf-8')
- result = translate_client.translate(
- text, target_language=target)
- print(u'Text: {}'.format(result['input']))
- print(u'Translation: {}'.format(result['translatedText']))
- print(u'Detected source language: {}'.format(
- result['detectedSourceLanguage']))
- result['translatedText'] = result['translatedText'].replace("&lt;", "<")
- result['translatedText'] = result['translatedText'].replace("&gt;", ">")
- result['translatedText'] = result['translatedText'].replace("&#39;", "'")
- result['translatedText'] = result['translatedText'].replace("&quot;", '"')
- result['translatedText'] = result['translatedText'].replace("<@! ", "<@!")
- result['translatedText'] = result['translatedText'].replace("<@ ", "<@")
- result['translatedText'] = result['translatedText'].replace("<# ", "<#")
- return result;
+ # Text can also be a sequence of strings, in which case this method
+ # will return a sequence of results for each text.
+ if isinstance(text, six.binary_type):
+ text = text.decode("utf-8")
+ result = translate_client.translate(text, target_language=target)
+ print("Text: {}".format(result["input"]))
+ print("Translation: {}".format(result["translatedText"]))
+ print("Detected source language: {}".format(result["detectedSourceLanguage"]))
+ result["translatedText"] = result["translatedText"].replace("&lt;", "<")
+ result["translatedText"] = result["translatedText"].replace("&gt;", ">")
+ result["translatedText"] = result["translatedText"].replace("&#39;", "'")
+ result["translatedText"] = result["translatedText"].replace("&quot;", '"')
+ result["translatedText"] = result["translatedText"].replace("<@! ", "<@!")
+ result["translatedText"] = result["translatedText"].replace("<@ ", "<@")
+ result["translatedText"] = result["translatedText"].replace("<# ", "<#")
+ return result
+
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",
+ 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,
+ )
+ embed.add_field(
+ name="Translation", value=response["translatedText"], inline=True
+ )
+ await ctx.send(embed=embed)
+
+ @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,
+ )
+ embed.add_field(
+ name="Translation", value=response["translatedText"], inline=True
+ )
+ await ctx.send(embed=embed)
- def __init__(self, bot):
- self.bot = bot
-
- @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)
- embed.add_field(name="Translation", value=response['translatedText'], inline=True)
- await ctx.send(embed=embed)
-
- @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)
- embed.add_field(name="Translation", value=response['translatedText'], inline=True)
- await ctx.send(embed=embed)
def setup(bot):
- bot.add_cog(Trans(bot))
+ bot.add_cog(Trans(bot))
diff --git a/cogs/twitter.py b/cogs/twitter.py
index 0688380..d633b8e 100755
--- a/cogs/twitter.py
+++ b/cogs/twitter.py
@@ -7,46 +7,55 @@ from discord.ext import commands, tasks
class StreamListener(tweepy.StreamListener):
- def __init__(self):
- with open('./config.json') as f:
- self.config = json.load(f)
-
- def on_error(self, status_code):
- if status_code == 420:
- print("Rate limit reached. ")
- #returning False in on_error disconnects the stream
- return False
-
- def on_data(self, data):
- data = json.loads(data)
- try:
- tweetUser = data['tweet']['user']['screen_name']
- tweetID = data['tweet']['id_str']
- except:
- tweetUser = data['user']['screen_name']
- tweetID = data['id_str']
- tweetLink = f'https://twitter.com/{tweetUser}/status/{tweetID}'
- body = {
- "content": tweetLink
- }
- global config
- r = requests.post(self.config['574267523869179904']['tweetWebhook'], headers={"Content-Type": "application/json"}, data=json.dumps(body))#config['574267523869179904']['tweetWebhook'], data=json.dumps(body))
- print(r.status_code)
- print(r.text)
- #print(json.dumps(data, indent='\t'))
+ def __init__(self):
+ with open("./config.json") as f:
+ self.config = json.load(f)
+
+ def on_error(self, status_code):
+ if status_code == 420:
+ print("Rate limit reached. ")
+ # returning False in on_error disconnects the stream
+ return False
+
+ def on_data(self, data):
+ data = json.loads(data)
+ try:
+ tweetUser = data["tweet"]["user"]["screen_name"]
+ tweetID = data["tweet"]["id_str"]
+ except:
+ tweetUser = data["user"]["screen_name"]
+ tweetID = data["id_str"]
+ tweetLink = f"https://twitter.com/{tweetUser}/status/{tweetID}"
+ body = {"content": tweetLink}
+ global config
+ r = requests.post(
+ self.config["574267523869179904"]["tweetWebhook"],
+ headers={"Content-Type": "application/json"},
+ data=json.dumps(body),
+ ) # config['574267523869179904']['tweetWebhook'], data=json.dumps(body))
+ print(r.status_code)
+ print(r.text)
+ # print(json.dumps(data, indent='\t'))
class Twitter(commands.Cog):
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- auth = tweepy.OAuthHandler(self.bot.config['twitter']['consumer_key'], self.bot.config['twitter']['consumer_secret'])
- auth.set_access_token(self.bot.config['twitter']['access_token'], self.bot.config['twitter']['access_token_secret'])
+ auth = tweepy.OAuthHandler(
+ self.bot.config["twitter"]["consumer_key"],
+ self.bot.config["twitter"]["consumer_secret"],
+ )
+ auth.set_access_token(
+ self.bot.config["twitter"]["access_token"],
+ self.bot.config["twitter"]["access_token_secret"],
+ )
+
+ api = tweepy.API(auth)
+ myStreamListener = StreamListener()
+ stream = tweepy.Stream(auth=api.auth, listener=myStreamListener)
+ stream.filter(follow=["1287799985040437254"], is_async=True)
- api = tweepy.API(auth)
- myStreamListener = StreamListener()
- stream = tweepy.Stream(auth = api.auth, listener=myStreamListener)
- stream.filter(follow=['1287799985040437254'], is_async=True)
def setup(bot):
- bot.add_cog(Twitter(bot)) \ No newline at end of file
+ bot.add_cog(Twitter(bot))
diff --git a/cogs/utils.py b/cogs/utils.py
index 5f879a2..d0324fb 100755
--- a/cogs/utils.py
+++ b/cogs/utils.py
@@ -3,14 +3,12 @@ import datetime
import functools
import json
from datetime import timedelta
-
# 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
from random import choice, randint
import discord
from discord.ext import commands, tasks
-
# from PIL.Image import core as Image
# import image as Image
from PIL import Image, ImageFilter
diff --git a/cogs/webserver.py b/cogs/webserver.py
index d9c92cf..757c8c5 100755
--- a/cogs/webserver.py
+++ b/cogs/webserver.py
@@ -11,48 +11,49 @@ routes = web.RouteTableDef()
class Webserver(commands.Cog):
- def __init__(self, bot):
- self.bot = bot
- self.web_server.start()
-
- @routes.get('/')
- async def welcome(request):
- return web.Response(text="Hello, world")
-
- @routes.get('/keys')
- async def get_keys(request):
- with open('./api_keys.json') as f:
- keys = json.load(f)
- return web.json_response(keys)
-
- @routes.post('/keys')
- async def post_keys(request):
- data = await request.post()
- try:
- discord_id = data['discord_id']
- src_id = data['src_id']
- except KeyError:
- return 400
- with open('./api_keys.json', 'r') as f:
- keys = json.load(f)
- keys[discord_id] = src_id
- with open('./api_keys.json', 'w') as f:
- json.dump(keys, f, indent=4)
- return web.json_response(keys)
-
- self.webserver_port = os.environ.get('PORT', 5000)
- app.add_routes(routes)
-
- @tasks.loop()
- async def web_server(self):
- runner = web.AppRunner(app)
- await runner.setup()
- site = web.TCPSite(runner, host='0.0.0.0', port=self.webserver_port)
- await site.start()
-
- @web_server.before_loop
- async def web_server_before_loop(self):
- await self.bot.wait_until_ready()
+ def __init__(self, bot):
+ self.bot = bot
+ self.web_server.start()
+
+ @routes.get("/")
+ async def welcome(request):
+ return web.Response(text="Hello, world")
+
+ @routes.get("/keys")
+ async def get_keys(request):
+ with open("./api_keys.json") as f:
+ keys = json.load(f)
+ return web.json_response(keys)
+
+ @routes.post("/keys")
+ async def post_keys(request):
+ data = await request.post()
+ try:
+ discord_id = data["discord_id"]
+ src_id = data["src_id"]
+ except KeyError:
+ return 400
+ with open("./api_keys.json", "r") as f:
+ keys = json.load(f)
+ keys[discord_id] = src_id
+ with open("./api_keys.json", "w") as f:
+ json.dump(keys, f, indent=4)
+ return web.json_response(keys)
+
+ self.webserver_port = os.environ.get("PORT", 5000)
+ app.add_routes(routes)
+
+ @tasks.loop()
+ async def web_server(self):
+ runner = web.AppRunner(app)
+ await runner.setup()
+ site = web.TCPSite(runner, host="0.0.0.0", port=self.webserver_port)
+ await site.start()
+
+ @web_server.before_loop
+ async def web_server_before_loop(self):
+ await self.bot.wait_until_ready()
+
def setup(bot):
- bot.add_cog(Webserver(bot)) \ No newline at end of file
+ bot.add_cog(Webserver(bot))
diff --git a/main.py b/main.py
index 76f5638..3b008ff 100755
--- a/main.py
+++ b/main.py
@@ -8,60 +8,58 @@ from bot import BedrockBot
def check_jsons():
- try:
- f = open('config.json', 'r')
- except FileNotFoundError:
- token = input('BOT SETUP - Enter bot token: ')
- with open('config.json', 'w+') as f:
- json.dump({"token": token}, f, indent=4)
-
- try:
- f = open('blacklist.json', 'r')
- except FileNotFoundError:
- with open('blacklist.json', 'w+') as f:
- json.dump([], f, indent=4)
-
- try:
- f = open('runs_blacklist.json', 'r')
- except FileNotFoundError:
- with open('runs_blacklist.json', 'w+') as f:
- json.dump({"videos": [], "players": []}, f, indent=4)
+ try:
+ f = open("config.json", "r")
+ except FileNotFoundError:
+ token = input("BOT SETUP - Enter bot token: ")
+ with open("config.json", "w+") as f:
+ json.dump({"token": token}, f, indent=4)
+
+ try:
+ f = open("blacklist.json", "r")
+ except FileNotFoundError:
+ with open("blacklist.json", "w+") as f:
+ json.dump([], f, indent=4)
+
+ try:
+ f = open("runs_blacklist.json", "r")
+ except FileNotFoundError:
+ with open("runs_blacklist.json", "w+") as f:
+ json.dump({"videos": [], "players": []}, f, indent=4)
def setup_logging():
- FORMAT = '%(asctime)s - [%(levelname)s]: %(message)s'
- DATE_FORMAT = '%d/%m/%Y (%H:%M:%S)'
+ FORMAT = "%(asctime)s - [%(levelname)s]: %(message)s"
+ DATE_FORMAT = "%d/%m/%Y (%H:%M:%S)"
- logger = logging.getLogger('discord')
- logger.setLevel(logging.INFO)
+ logger = logging.getLogger("discord")
+ logger.setLevel(logging.INFO)
- file_handler = logging.FileHandler(filename='discord.log',
- mode='a',
- encoding='utf-8')
- file_handler.setFormatter(
- logging.Formatter(fmt=FORMAT, datefmt=DATE_FORMAT))
- file_handler.setLevel(logging.INFO)
- logger.addHandler(file_handler)
+ file_handler = logging.FileHandler(
+ filename="discord.log", mode="a", encoding="utf-8"
+ )
+ file_handler.setFormatter(logging.Formatter(fmt=FORMAT, datefmt=DATE_FORMAT))
+ file_handler.setLevel(logging.INFO)
+ logger.addHandler(file_handler)
- console_handler = logging.StreamHandler()
- console_handler.setFormatter(
- logging.Formatter(fmt=FORMAT, datefmt=DATE_FORMAT))
- console_handler.setLevel(logging.WARNING)
- logger.addHandler(console_handler)
+ console_handler = logging.StreamHandler()
+ console_handler.setFormatter(logging.Formatter(fmt=FORMAT, datefmt=DATE_FORMAT))
+ console_handler.setLevel(logging.WARNING)
+ logger.addHandler(console_handler)
def run_bot():
- bot = BedrockBot()
- bot.run()
+ bot = BedrockBot()
+ bot.run()
if __name__ == "__main__":
- init_colorama(autoreset=True)
+ init_colorama(autoreset=True)
- setup_logging()
+ setup_logging()
- check_jsons()
+ check_jsons()
- run_bot()
+ run_bot()