aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnInternetTroll <lucafulger@gmail.com>2020-07-27 18:24:49 +0000
committerAnInternetTroll <lucafulger@gmail.com>2020-07-27 18:24:49 +0000
commit27c6a4a11ecfecfc5c989c96d9b236e89faf5984 (patch)
tree6051f1725c70651ddc326f2c395ee0af0cd3286f
parentfd4212d1a930aa72a84d8d380e22c3d89f206130 (diff)
parent85779b58d4b3b4b37ead36a68c8beacf0e2c554e (diff)
downloadsteve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar.gz
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar.bz2
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar.lz
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar.xz
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.tar.zst
steve-bot-27c6a4a11ecfecfc5c989c96d9b236e89faf5984.zip
Merge branch 'master' of github.com:AnInternetTroll/mcbeDiscordBot
-rwxr-xr-x.gitignore11
-rwxr-xr-xbot.py8
-rwxr-xr-xcogs/admin.py17
-rwxr-xr-xcogs/logs.py18
-rwxr-xr-xcogs/src.py134
-rwxr-xr-xcogs/utils.py10
-rwxr-xr-xmain.py64
-rw-r--r--readme.md17
8 files changed, 181 insertions, 98 deletions
diff --git a/.gitignore b/.gitignore
index e40241a..f0fb023 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,9 @@
-__pycache__
+.vscode/
+__pycache__/
+downloads/
+api_keys.json
config.json
+blacklist.json
+video_blacklist.json
discord.log
-api_keys.json
-.vscode/
leaderboard.png
-downloads/
-blacklist.json \ No newline at end of file
diff --git a/bot.py b/bot.py
index d405115..30d8b1f 100755
--- a/bot.py
+++ b/bot.py
@@ -33,7 +33,7 @@ def get_prefix(bot, message):
class BedrockBot(commands.Bot):
def __init__(self):
- super().__init__(command_prefix=get_prefix, case_insensitive=True)
+ 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()
@@ -60,6 +60,12 @@ class BedrockBot(commands.Bot):
except json.decoder.JSONDecodeError:
self.blacklist = []
+ with open('video_blacklist.json', 'r') as f:
+ try:
+ self.video_blacklist = json.load(f)
+ except json.decoder.JSONDecodeError:
+ self.video_blacklist = []
+
self.logger.warning(f'Online: {self.user} (ID: {self.user.id})')
async def on_message(self, message):
diff --git a/cogs/admin.py b/cogs/admin.py
index 3a6299f..8164790 100755
--- a/cogs/admin.py
+++ b/cogs/admin.py
@@ -237,6 +237,23 @@ class Admin(commands.Cog):
"""Print a config variable, use for testing"""
await ctx.send(self.bot.config[str(ctx.message.guild.id)][key])
+ @commands.command()
+ @commands.check(is_mod)
+ async def blacklistvideo(self, ctx, uri):
+ """Set runs from a specific url to be auto rejected"""
+ with open('video_blacklist.json', 'w') as f:
+ self.bot.video_blacklist.append(uri)
+ json.dump(self.bot.video_blacklist, f, indent=4)
+ await ctx.send(f'Blacklisted runs from `{uri}`')
+
+ @commands.command()
+ @commands.check(is_mod)
+ async def video_blacklist(self, ctx):
+ """Sends a list of blacklisted uris"""
+ message = '```The following URIs are blacklisted:\n'
+ for uri in self.bot.video_blacklist:
+ message += f'{uri}, '
+ await ctx.send(f'{message[:-2]}```')
def setup(bot):
bot.add_cog(Admin(bot))
diff --git a/cogs/logs.py b/cogs/logs.py
index c1b3a49..4f6aab1 100755
--- a/cogs/logs.py
+++ b/cogs/logs.py
@@ -19,15 +19,15 @@ class Logs(commands.Cog):
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',
+ title='**Deleted Message**',
color=color,
timestamp=message.created_at
)
embed.add_field(
- name='User', value=message.author.mention, inline=True)
+ 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)
+ 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()
@@ -43,17 +43,17 @@ class Logs(commands.Cog):
else:
color = before.author.color
embed = discord.Embed(
- title='Edited Message',
+ title='**Edited Message**',
color=color,
timestamp=after.edited_at
)
embed.add_field(
- name='User', value=before.author.mention, inline=True)
+ 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',
+ 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)
+ embed.add_field(name='**New Message**', value=after.content, inline=False)
await channel.send(embed=embed)
diff --git a/cogs/src.py b/cogs/src.py
index bf776e7..8afe1b5 100755
--- a/cogs/src.py
+++ b/cogs/src.py
@@ -9,84 +9,90 @@ import asyncio
import dateutil.parser
from pathlib import Path
+
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))
+ 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("Run rejected 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.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"
- }
- }
+ 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))
+ 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.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"})
+ 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.author.send(
+ f"```json\n{json.dumps(json.loads(r.text),indent=4)}```")
+
async def pendingRuns(self, ctx):
mcbe_runs = 0
mcbeil_runs = 0
mcbece_runs = 0
- head = {
- "Accept": "application/json",
- "User-Agent":"mcbeDiscordBot/1.0"
- }
+ head = {"Accept": "application/json", "User-Agent": "mcbeDiscordBot/1.0"}
gameID = 'yd4ovvg1' # ID of Minecraft bedrock
gameID2 = 'v1po7r76' # ID of Category extension
runsRequest = requests.get(
- f'https://www.speedrun.com/api/v1/runs?game={gameID}&status=new&max=200&embed=category,players,level&orderby=submitted', headers=head)
+ f'https://www.speedrun.com/api/v1/runs?game={gameID}&status=new&max=200&embed=category,players,level&orderby=submitted',
+ headers=head)
runs = json.loads(runsRequest.text)
runsRequest2 = requests.get(
- f'https://www.speedrun.com/api/v1/runs?game={gameID2}&status=new&max=200&embed=category,players,level&orderby=submitted', headers=head)
+ f'https://www.speedrun.com/api/v1/runs?game={gameID2}&status=new&max=200&embed=category,players,level&orderby=submitted',
+ headers=head)
runs2 = json.loads(runsRequest2.text)
# Use https://www.speedrun.com/api/v1/games?abbreviation=mcbe for ID
for game in range(2):
for i in range(200):
- leaderboard = '' # A little ugly but prevents name not defined error
+ leaderboard = '' # A little ugly but prevents name not defined error
level = False
try:
for key, value in runs['data'][i].items():
+ if key == 'id':
+ run_id = value
if key == 'weblink':
link = value
if key == 'level':
@@ -95,6 +101,11 @@ async def pendingRuns(self, ctx):
categoryName = value["data"]["name"]
if key == 'category' and not level:
categoryName = value["data"]["name"]
+ if key == 'videos':
+ if value['links'][0]['uri'] in self.bot.video_blacklist:
+ await rejectRun(
+ self, self.bot.config['api_key'], ctx, run_id,
+ 'Detected as spam by our automatic filter')
if key == 'players':
if value["data"][0]['rel'] == 'guest':
player = value["data"][0]['name']
@@ -113,30 +124,44 @@ async def pendingRuns(self, ctx):
leaderboard = 'Individual Level Run'
else:
mcbe_runs += 1
- leaderboard = "Full Game Run" # If this doesn't work I'm starting a genocide
+ leaderboard = "Full Game Run" # If this doesn't work I'm starting a genocide
elif game == 1:
leaderboard = "Category Extension Run"
mcbece_runs += 1
embed = discord.Embed(
- title=leaderboard, url=link, description=f"{categoryName} in `{str(rta).replace('000','')}` by **{player}**", color=16711680+i*60, timestamp=timestamp)
- await self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])).send(embed=embed)
+ title=leaderboard,
+ url=link,
+ description=
+ f"{categoryName} in `{str(rta).replace('000','')}` by **{player}**",
+ color=16711680 + i * 60,
+ timestamp=timestamp)
+ await self.bot.get_channel(
+ int(self.bot.config[str(
+ ctx.message.guild.id)]["pending_channel"])
+ ).send(embed=embed)
runs = runs2
gameID = gameID2
- embed_stats = discord.Embed(title='Pending Run Stats', description=f"Full Game Runs: {mcbe_runs}\nIndividual Level Runs: {mcbeil_runs}\nCategory Extension Runs: {mcbece_runs}", color=16711680 + i * 60)
- await self.bot.get_channel(int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])).send(embed=embed_stats)
+ embed_stats = discord.Embed(
+ title='Pending Run Stats',
+ description=
+ f"Full Game Runs: {mcbe_runs}\nIndividual Level Runs: {mcbeil_runs}\nCategory Extension Runs: {mcbece_runs}",
+ color=16711680 + i * 60)
+ await self.bot.get_channel(
+ int(self.bot.config[str(ctx.message.guild.id)]["pending_channel"])
+ ).send(embed=embed_stats)
async def verifyNew(self, apiKey=None, userID=None):
- if apiKey==None:
+ if apiKey == None:
head = {
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0"
}
else:
head = {
- "X-API-Key": apiKey,
- "Accept": "application/json",
- "User-Agent": "mcbeDiscordBot/1.0"
+ "X-API-Key": apiKey,
+ "Accept": "application/json",
+ "User-Agent": "mcbeDiscordBot/1.0"
}
server = self.bot.get_guild(574267523869179904)
# Troll is mentally challenged I guess ¯\_(ツ)_/¯
@@ -149,11 +174,13 @@ async def verifyNew(self, apiKey=None, userID=None):
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 = 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)
+ 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}```")
@@ -190,8 +217,8 @@ async def verifyNew(self, apiKey=None, userID=None):
else:
await server.get_member(user.id).remove_roles(RunneRole)
-class Src(commands.Cog):
+class Src(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.checker.start()
@@ -203,7 +230,10 @@ class Src(commands.Cog):
@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 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")
@@ -230,7 +260,9 @@ class Src(commands.Cog):
if apiKey == None:
data = json.loads(Path('./api_keys.json').read_text())
if not str(ctx.author.id) in data:
- await ctx.send(f"Please try again this command by getting an apiKey from https://www.speedrun.com/api/auth then do `{ctx.prefix}verify <apiKey>` in my DMs or anywhere in this server. \nBe careful who you share this key with. To learn more check out https://github.com/speedruncomorg/api/blob/master/authentication.md")
+ await ctx.send(
+ f"Please try again this command by getting an apiKey from https://www.speedrun.com/api/auth then do `{ctx.prefix}verify <apiKey>` in my DMs or anywhere in this server. \nBe careful who you share this key with. To learn more check out https://github.com/speedruncomorg/api/blob/master/authentication.md"
+ )
return
if ctx.guild != None:
await ctx.message.delete()
@@ -242,7 +274,7 @@ class Src(commands.Cog):
@tasks.loop(minutes=10.0)
async def checker(self):
data = json.loads(Path('./api_keys.json').read_text())
- for key,value in data.items():
+ for key, value in data.items():
await verifyNew(self, None, key)
diff --git a/cogs/utils.py b/cogs/utils.py
index bacf5e6..ab9bc42 100755
--- a/cogs/utils.py
+++ b/cogs/utils.py
@@ -118,7 +118,7 @@ class Utils(commands.Cog):
return
else:
await ctx.send(error)
- #await ctx.send(f"{ctx.message.author.display_name}, you have to wait {round(error.retry_after, 7)} seconds before using this again.")
+ #await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)}, you have to wait {round(error.retry_after, 7)} seconds before using this again.")
@commands.command()
async def findsleep(self, ctx):
@@ -147,15 +147,15 @@ class Utils(commands.Cog):
# Add extra comment based on number of sleepHrs
if sleepHrs == 0:
- await ctx.send(f"{ctx.message.author.display_name} -> your sleep is 0 hours long - nice try \:D")
+ await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)} -> your sleep is 0 hours long - nice try \:D")
elif sleepHrs <= 5:
if sleepHrs == 1:
s = ''
else:
s = 's'
- await ctx.send(f"{ctx.message.author.display_name} -> your sleep is {sleepHrs} hour{s} long - {lessSleepMsg[randint(0, len(lessSleepMsg) - 1)]}")
+ await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)} -> your sleep is {sleepHrs} hour{s} long - {lessSleepMsg[randint(0, len(lessSleepMsg) - 1)]}")
else:
- await ctx.send(f"{ctx.message.author.display_name} -> your sleep is {sleepHrs} hours long - {moreSleepMsg[randint(0, len(moreSleepMsg) - 1)]}")
+ await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)} -> your sleep is {sleepHrs} hours long - {moreSleepMsg[randint(0, len(moreSleepMsg) - 1)]}")
@commands.Cog.listener()
async def on_member_join(self, member):
@@ -234,7 +234,7 @@ class Utils(commands.Cog):
async def leaderboard_handler(self,ctx,error):
if isinstance(error, commands.CommandOnCooldown):
#return
- await ctx.send(f"{ctx.message.author.display_name}, you have to wait {round(error.retry_after, 2)} seconds before using this again.")
+ await ctx.send(f"{discord.utils.escape_mentions(ctx.message.author.display_name)}, you have to wait {round(error.retry_after, 2)} seconds before using this again.")
@commands.cooldown(1, 60, commands.BucketType.guild)
@commands.command()
diff --git a/main.py b/main.py
index 13bc0f0..3bf6112 100755
--- a/main.py
+++ b/main.py
@@ -1,37 +1,67 @@
import asyncio
import logging
+import json
from colorama import init as init_colorama
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('video_blacklist.json', 'r')
+ except FileNotFoundError:
+ with open('video_blacklist.json', 'w+') as f:
+ json.dump([], 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()
- run_bot()
+ run_bot()
diff --git a/readme.md b/readme.md
index f1c839b..245abe1 100644
--- a/readme.md
+++ b/readme.md
@@ -1,13 +1,6 @@
# Minecraft Bedrock Discord Bot
## How to
-Make a file called `config.json` and add
-```json
-{
- "token": "your_bot_token"
-}
-```
-
Launch the bot with `python3 main.py` and you're ready to go. Unless dependencies. Dependencies are google cloud and discord.
Install the dependencies with `python -m pip install -r requirements.txt`
@@ -16,13 +9,17 @@ A few "dangerous" commands such as `!purge` are restriced to `bot_masters`, to a
```json
{
"token": "your_bot_token",
- "bot_masters": <users_discord_id>
+ "<guild_id>": {
+ "bot_masters": <users_discord_id>
+ }
}
```
+`guild_id` is the ID of the discord server in the form of a string while user IDs are integers
+
You can also use lists, for example: `"bot_masters": [280428276810383370, 99457716614885376]`
-A user added as a botmaster will be able to edit the config via discord with the command `!setvar <var_name> <var_value>`
+A user added as a botmaster will be able to edit the config via discord with the command `!setvar <var_name> <var_value>`
`!setvar` also supports lists which can be added like so: `!setvar <var_name> [<index 0>, <index 1>]`
-This bot was built as a fork of [celesteBot](https://github.com/CelesteClassic/celestebot), so a lot of code is recycled.
+This bot was built as a fork of [celesteBot](https://github.com/CelesteClassic/celestebot), so a lot of code is recycled.
Feel free to make a pull request or use the code here.