Browse Source

Moved guildsettings into the main Roxbot folder and moved almost all requests from the request lib to aiohttp using http.py as the way to do requests from now on with functions to make code more readable.

tags/v1.7.0
Roxie Gibson 6 years ago
parent
commit
da4dc7815e
13 changed files with 139 additions and 122 deletions
  1. +1
    -2
      Roxbot/__init__.py
  2. +1
    -1
      Roxbot/checks.py
  3. +9
    -9
      Roxbot/cogs/customcommands.py
  4. +3
    -4
      Roxbot/cogs/fun.py
  5. +6
    -12
      Roxbot/cogs/gss.py
  6. +6
    -17
      Roxbot/cogs/nsfw.py
  7. +23
    -35
      Roxbot/cogs/reddit.py
  8. +4
    -5
      Roxbot/cogs/trivia.py
  9. +19
    -28
      Roxbot/cogs/util.py
  10. +0
    -0
      Roxbot/guild_settings.py
  11. +59
    -0
      Roxbot/http.py
  12. +7
    -7
      Roxbot/logging.py
  13. +1
    -2
      Roxbot/settings/settings.py

+ 1
- 2
Roxbot/__init__.py View File

@@ -1,7 +1,6 @@
from Roxbot import checks
from Roxbot import checks, http, guild_settings
from Roxbot.load_config import *
from Roxbot.logging import log
from Roxbot.settings import guild_settings


def blacklisted(user):

+ 1
- 1
Roxbot/checks.py View File

@@ -1,6 +1,6 @@
from discord.ext import commands
from Roxbot.load_config import owner
from Roxbot.settings import guild_settings as gs
from Roxbot import guild_settings as gs


def is_owner_or_admin():

+ 9
- 9
Roxbot/cogs/customcommands.py View File

@@ -1,7 +1,7 @@
import discord
from discord.ext.commands import group

import Roxbot as roxbot
import Roxbot


class CustomCommands():
@@ -11,11 +11,11 @@ class CustomCommands():
async def on_message(self, message):
if isinstance(message.channel, discord.DMChannel):
return
settings = roxbot.guild_settings.get(message.guild)
settings = Roxbot.guild_settings.get(message.guild)
msg = message.content.lower()
channel = message.channel

if roxbot.blacklisted(message.author) or type(message.channel) != discord.TextChannel:
if Roxbot.blacklisted(message.author) or type(message.channel) != discord.TextChannel:
return
if message.author == self.bot.user:
return
@@ -29,7 +29,7 @@ class CustomCommands():
return await channel.send(settings.custom_commands["0"][command])

@group(pass_context=True, aliases=["cc"])
@roxbot.checks.is_owner_or_admin()
@Roxbot.checks.is_owner_or_admin()
async def custom(self, ctx):
""""A group of commands to manage custom commands for your server."""
if ctx.invoked_subcommand is None:
@@ -38,7 +38,7 @@ class CustomCommands():
@custom.command(pass_context=True)
async def add(self, ctx, command, output, prefix_required="0"):
"""Adds a custom command to the list of custom commands."""
settings = roxbot.guild_settings.get(ctx.guild)
settings = Roxbot.guild_settings.get(ctx.guild)
command = command.lower()
output = output
zero = settings.custom_commands["0"]
@@ -64,7 +64,7 @@ class CustomCommands():
@custom.command(pass_context=True)
async def edit(self, ctx, command, edit):
""""Edits an existing custom command."""
settings = roxbot.guild_settings.get(ctx.guild)
settings = Roxbot.guild_settings.get(ctx.guild)
zero = settings.custom_commands["0"]
one = settings.custom_commands["1"]

@@ -85,7 +85,7 @@ class CustomCommands():
@custom.command(pass_context=True)
async def remove(self, ctx, command):
""""Removes a custom command."""
settings = roxbot.guild_settings.get(ctx.guild)
settings = Roxbot.guild_settings.get(ctx.guild)
command = command.lower()
if command in settings.custom_commands["1"]:
settings.custom_commands["1"].pop(command)
@@ -103,7 +103,7 @@ class CustomCommands():
""""Lists all custom commands for this server."""
if debug != "0" and debug != "1":
debug = "0"
settings = roxbot.guild_settings.get(ctx.guild)
settings = Roxbot.guild_settings.get(ctx.guild)
cc = settings.custom_commands
listzero = ""
listone = ""
@@ -123,7 +123,7 @@ class CustomCommands():

# TODO: Sort out a way to shorten this if it goes over 2000 characters.
em = discord.Embed(title="Here is the list of Custom Commands", color=roxbot.embedcolour)
em = discord.Embed(title="Here is the list of Custom Commands", color=Roxbot.embedcolour)
em.add_field(name="Commands that require Prefix:", value=listone, inline=False)
em.add_field(name="Commands that don't:", value=listzero, inline=False)
return await ctx.send(embed=em)

+ 3
- 4
Roxbot/cogs/fun.py View File

@@ -1,7 +1,6 @@
import random
import re
import random
import discord
import requests
from discord.ext.commands import bot

import Roxbot
@@ -252,8 +251,8 @@ class Fun:
async def frogtips(self, ctx):
"""RETURNS FROG TIPS FOR HOW TO OPERATE YOUR FROG"""
endpoint = "https://frog.tips/api/1/tips/"
croak = requests.get(endpoint)
tip = random.choice(croak.json()["tips"])
croak = await Roxbot.http.api_request(endpoint)
tip = random.choice(croak["tips"])
embed = discord.Embed(title="Frog Tip #{}".format(tip["number"]), description=tip["tip"], colour=discord.Colour(0x4C943D))
embed.set_author(name="HOW TO OPERATE YOUR FROG")
embed.set_footer(text="https://frog.tips")

+ 6
- 12
Roxbot/cogs/gss.py View File

@@ -1,13 +1,10 @@
import json
import datetime
import requests

import discord
from discord.ext import commands
from discord.ext.commands import bot

import Roxbot
from Roxbot import guild_settings


def is_gss():
@@ -21,14 +18,11 @@ def is_not_nsfw_disabled():
return commands.check(lambda ctx: predicate(ctx))


def tatsumaki_api_call(member, guild):
async def tatsumaki_api_call(member, guild):
base = "https://api.tatsumaki.xyz/"
url = base + "guilds/" + str(guild.id) + "/members/" + str(member.id) + "/stats"
r = requests.get(url, headers={"Authorization": Roxbot.tat_token})
try:
return r.json()
except json.JSONDecodeError:
return {}
return await Roxbot.http.api_request(url, headers={"Authorization": Roxbot.tat_token})


class GaySoundsShitposts():
def __init__(self, bot_client):
@@ -42,12 +36,12 @@ class GaySoundsShitposts():
# Just in case some cunt looks at the source code and thinks they can give themselves Admin.
if role.id not in self.acceptable_roles:
return False
settings = guild_settings.get(ctx.guild)
settings = Roxbot.guild_settings.get(ctx.guild)
member = ctx.author
required_score = settings.gss["required_score"]
days = int(settings.gss["required_days"])
data = tatsumaki_api_call(member, ctx.guild)
if not data:
data = await tatsumaki_api_call(member, ctx.guild)
if data is None:
return await ctx.send("Tatsumaki API call returned nothing. Maybe the API is down?")

if role in member.roles:

+ 6
- 17
Roxbot/cogs/nsfw.py View File

@@ -1,9 +1,7 @@
import json
import random
import aiohttp
from discord.ext.commands import bot

from Roxbot import checks
import Roxbot as roxbot
from Roxbot import guild_settings as gs


@@ -14,15 +12,6 @@ def tag_blacklist(guild):
return blacklist


async def http_request(url):
async with aiohttp.ClientSession() as session:
async with session.get(url, headers={'User-agent': 'RoxBot Discord Bot'}) as resp:
try:
return json.loads(await resp.read())
except json.JSONDecodeError:
return None


class NFSW():
def __init__(self, bot_client):
self.bot = bot_client
@@ -30,14 +19,14 @@ class NFSW():
for guild in self.bot.guilds:
self.cache[guild.id] = []

@checks.is_nfsw_enabled()
@roxbot.checks.is_nfsw_enabled()
@bot.command(hidden=True)
async def gelbooru_clone(self, ctx, base_url, post_url, tags):
limit = 150
tags = tags + tag_blacklist(ctx.guild)
url = base_url + tags + '&limit=' + str(limit)

posts = await http_request(url)
posts = await roxbot.http.api_request(url)

if posts is None:
return await ctx.send("Nothing was found. *psst, check the tags you gave me.*")
@@ -59,7 +48,7 @@ class NFSW():
url = post_url + "{0[directory]}/{0[image]}".format(post)
return await ctx.send(url)

@checks.is_nfsw_enabled()
@roxbot.checks.is_nfsw_enabled()
@bot.command()
async def e621(self, ctx, *, tags=""):
"""
@@ -68,7 +57,7 @@ class NFSW():
base_url = "https://e621.net/post/index.json?tags="
return await ctx.invoke(self.gelbooru_clone, base_url=base_url, post_url="", tags=tags)

@checks.is_nfsw_enabled()
@roxbot.checks.is_nfsw_enabled()
@bot.command()
async def rule34(self, ctx, *, tags=""):
"""
@@ -78,7 +67,7 @@ class NFSW():
post_url = "https://img.rule34.xxx/images/"
return await ctx.invoke(self.gelbooru_clone, base_url=base_url, post_url=post_url, tags=tags)

@checks.is_nfsw_enabled()
@roxbot.checks.is_nfsw_enabled()
@bot.command()
async def gelbooru(self, ctx, *, tags=""):
"""

+ 23
- 35
Roxbot/cogs/reddit.py View File

@@ -1,8 +1,5 @@
import random
import requests

from html import unescape
from lxml import html
from bs4 import BeautifulSoup
from discord.ext.commands import bot

@@ -10,8 +7,8 @@ import Roxbot as roxbot
from Roxbot import guild_settings


def _imgur_removed(url):
page = requests.get(url)
async def _imgur_removed(url):
page = await roxbot.http.get_page(url)
soup = BeautifulSoup(page.content, 'html.parser')
if "removed.png" in soup.img["src"]:
return True
@@ -19,14 +16,14 @@ def _imgur_removed(url):
return False


def imgur_get(url):
async def imgur_get(url):
if url.split(".")[-1] in ("png", "jpg", "jpeg", "gif", "gifv"):
return url
else:
if _imgur_removed(url):
if await _imgur_removed(url):
return False
page = requests.get(url)
soup = BeautifulSoup(page.content, 'html.parser')
page = await roxbot.http.get_page(url)
soup = BeautifulSoup(page, 'html.parser')
links = []
for img in soup.find_all("img"):
if "imgur" in img["src"]:
@@ -44,42 +41,29 @@ def imgur_get(url):
links[0] = "https:" + links[0]
return links[0]

# TODO: Reimplement eroshare, eroshae, and erome support.

def ero_get(url):
if "eroshare" in url:
url = "https://eroshae.com/" + url.split("/")[3]
page = requests.get(url)
tree = html.fromstring(page.content)
links = tree.xpath('//source[@src]/@src')
if links:
return False
links = tree.xpath('//*[@src]/@src')
if len(links) > 2:
return False
for link in links:
if "i." in link and "thumb" not in link:
return "https:" + link


def subreddit_request(subreddit):
async def subreddit_request(subreddit):
options = [".json?count=1000", "/top/.json?sort=top&t=all&count=1000"]
choice = random.choice(options)
subreddit += choice
r = requests.get("https://reddit.com/r/"+subreddit, headers={'User-agent': 'RoxBot Discord Bot'})
url = "https://reddit.com/r/"+subreddit
r = await roxbot.http.api_request(url)
try:
reddit = r.json()["data"]
except KeyError:
posts = r["data"]
return posts
except KeyError or TypeError:
return {}
return reddit


def parse_url(url):
async def parse_url(url):
if url.split(".")[-1] in ("png", "jpg", "jpeg", "gif", "gifv", "webm", "mp4", "webp"):
return url
if "imgur" in url:
return imgur_get(url)
return await imgur_get(url)
elif "eroshare" in url or "eroshae" in url or "erome" in url:
return ero_get(url)
return False
#return ero_get(url)
elif "gfycat" in url or "redd.it" in url or "i.reddituploads" in url or "media.tumblr" in url or "streamable" in url:
return url
else:
@@ -101,7 +85,7 @@ class Reddit():
{command_prefix}subreddit pics
"""
subreddit = subreddit.lower()
links = subreddit_request(subreddit)
links = await subreddit_request(subreddit)
title = ""
choice = {}

@@ -114,7 +98,7 @@ class Reddit():
# Choosing a while loop here because, for some reason, the for loop would never exit till the end. Leading to slow times.
while not url or not x > 20:
choice = random.choice(links["children"])["data"]
url = parse_url(choice["url"])
url = await parse_url(choice["url"])
if url:
x_old = int(x)
# If the url or id are in the cache, continue the loop. If not, proceed with the post.
@@ -194,6 +178,10 @@ class Reddit():
subreddit = "gaysoundsshitposts"
return await ctx.invoke(self.subreddit, subreddit=subreddit)

@bot.command(hidden=True, name="subreddit_dryrun")
async def _subreddit_test(self, ctx, url):
return await ctx.send(await parse_url(url))


def setup(bot_client):
bot_client.add_cog(Reddit(bot_client))

+ 4
- 5
Roxbot/cogs/trivia.py View File

@@ -2,13 +2,13 @@

import discord
import asyncio
import requests
import datetime
from html import unescape
from random import shuffle
from collections import OrderedDict
from discord.ext import commands

from Roxbot import http
from Roxbot import checks


@@ -34,9 +34,8 @@ class Trivia:

# Game Functions

def get_questions(self, amount=10):
r = requests.get("https://opentdb.com/api.php?amount={}".format(amount))
return r.json()
async def get_questions(self, amount=10):
return await http.api_request("https://opentdb.com/api.php?amount={}".format(amount))

def parse_question(self, question, counter):
embed = discord.Embed(
@@ -274,7 +273,7 @@ class Trivia:
await asyncio.sleep(20)

# Get questions
questions = self.get_questions(length[amount])
questions = await self.get_questions(length[amount])

# Checks if there is any players to play the game still
if not self.games[channel.id]["players"]:

+ 19
- 28
Roxbot/cogs/util.py View File

@@ -1,12 +1,13 @@
import os
import json
import random
import aiohttp
import discord
import requests
from discord.ext import commands
from discord.ext.commands import bot

import Roxbot


class Util():
"""
A cog that offers utility commands.
@@ -15,7 +16,7 @@ class Util():
self.bot = bot_client

@bot.command()
async def avatar(self, ctx, *,user: discord.User = None):
async def avatar(self, ctx, *, user: discord.User = None):
"""
Returns a mentioned users avatar
Example:
@@ -31,10 +32,7 @@ class Util():
else:
avaimg = '{0.name}.png'.format(user)

async with aiohttp.ClientSession() as session:
async with session.get(url) as img:
with open(avaimg, 'wb') as f:
f.write(await img.read())
await Roxbot.http.download_file(url, avaimg)
await ctx.send(file=discord.File(avaimg))
os.remove(avaimg)

@@ -138,41 +136,37 @@ class Util():
embed.add_field(name="Managed", value=str(role.managed), inline=False)
return await ctx.send(embed=embed)

@bot.command()
@bot.command(enabled=True)
async def upload(self, ctx):
"""
Uploads selected file to the host, thanks to the fact that
every pomf.se based site has pretty much the same architecture.
"""
# Fucking broke because uploading is impossible whyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
sites = [
"https://comfy.moe/",
"https://safe.moe/api/",
"http://up.che.moe/",
"https://mixtape.moe/",
"https://pomf.cat/",
"https://sugoi.vidyagam.es/",
"https://doko.moe/",
"https://pomfe.co/",
"https://pomf.space/",
#"https://pomfe.co/",
#"https://pomf.space/",
"https://vidga.me/",
"https://pomf.pyonpyon.moe/"
] # List of pomf clone sites and upload limits
] # List of pomf clone sites and upload limits
if ctx.message.attachments:
# Site choice, shouldn't need an upload size check since max upload for discord atm is 50MB
site = random.choice(sites)
urls = []

print(site)
for attachment in ctx.message.attachments:
name = attachment['url'].split("/")[-1]
name = attachment.url.split("/")[-1]
# Download File
with aiohttp.ClientSession() as session:
async with session.get(attachment['url']) as img:
with open(name, 'wb') as f:
f.write(await img.read())
await Roxbot.http.download_file(attachment.url, name)
# Upload file
with open(name, 'rb') as f:
answer = requests.post(url=site+"upload.php",files={'files[]': f.read()})
response = json.loads(answer.text)
file_name_1 = response["files"][0]["url"].replace("\\", "")
answer = requests.post(url=site + "upload.php", files={'files[]': (name, f.read())})
response = answer.json()
file_name_1 = response["files"][0]["url"].replace("\\", "")
urls.append(file_name_1)
os.remove(name)
msg = "".join(urls)
@@ -182,7 +176,7 @@ class Util():

@upload.error
async def upload_err(self, ctx, error):
return await ctx.send("File couldn't be uploaded. {}".format(error))
return await ctx.send("File couldn't be uploaded.")

@bot.command(aliases=["emoji"])
async def emote(self, ctx, emote):
@@ -200,10 +194,7 @@ class Util():
emoji_id = emote[2]
url = "https://cdn.discordapp.com/emojis/{}".format(emoji_id)

async with aiohttp.ClientSession() as session:
async with session.get(url) as img:
with open(imgname, 'wb') as f:
f.write(await img.read())
await Roxbot.http.download_file(url, imgname)
await ctx.send(file=discord.File(imgname))
os.remove(imgname)


Roxbot/settings/guild_settings.py → Roxbot/guild_settings.py View File


+ 59
- 0
Roxbot/http.py View File

@@ -0,0 +1,59 @@
import json
import aiohttp


async def api_request(url, *, headers=None):
"""
Returns a JSON dict object for most api calls in RoxBot.
:param url: URL Should be a api endpoint that will return
:param headers: There is no need to pass the user agent, this is done for you.
:return: dict of JSON or None if a JSON was not returned from the call.
"""
if headers is None:
headers = {'User-agent': 'RoxBot Discord Bot'}
else:
headers = {'User-agent': 'RoxBot Discord Bot', **headers}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as resp:
try:
return json.loads(await resp.read())
except json.JSONDecodeError:
return None


async def download_file(url, filename=None):
"""
Downloads the file at the given url and then saves it under the filename given to disk.
:param filename:
:param url:
"""
if filename is None:
filename = url.split("/")[-1]
async with aiohttp.ClientSession() as session:
async with session.get(url, headers={'User-agent': 'RoxBot Discord Bot'}) as data:
with open(filename, 'wb') as f:
f.write(await data.read())


async def upload_file(url, file):
"""

:param url: url to POST to.
:param file: Byes-like object to upload.
:return:
"""
async with aiohttp.ClientSession() as session:
with open(file, "rb") as f:
files = {file: f.read()}
return await session.post(url, data=files)


async def get_page(url):
"""
Returns the page at the given url
:param url: the url of the page you want to get
:return: the html page
"""
async with aiohttp.ClientSession() as session:
async with session.get(url, headers={'User-agent': 'RoxBot Discord Bot'}) as page:
return await page.text()

+ 7
- 7
Roxbot/logging.py View File

@@ -1,11 +1,11 @@
import discord
import Roxbot
from Roxbot import guild_settings, embedcolour


async def log(guild, channel, command_name, **kwargs):
logging = Roxbot.guild_settings.get(guild).logging
logging = guild_settings.get(guild).logging
if logging["enabled"]:
embed = discord.Embed(title="{} command logging".format(command_name), colour=Roxbot.embedcolour)
embed = discord.Embed(title="{} command logging".format(command_name), colour=embedcolour)
for key, value in kwargs.items():
embed.add_field(name=key, value=value)
return await channel.send(embed=embed)
@@ -16,10 +16,10 @@ class Logging:
self.bot = bot_client

async def on_member_join(self, member):
logging = Roxbot.guild_settings.get(member.guild).logging
logging = guild_settings.get(member.guild).logging
if logging["enabled"]:
channel = self.bot.get_channel(logging["channel"])
embed = discord.Embed(title="{} joined the server".format(member), colour=Roxbot.embedcolour)
embed = discord.Embed(title="{} joined the server".format(member), colour=embedcolour)
embed.add_field(name="ID", value=member.id)
embed.add_field(name="Mention", value=member.mention)
embed.add_field(name="Date Account Created", value="{:%a %Y/%m/%d %H:%M:%S} UTC".format(member.created_at))
@@ -29,10 +29,10 @@ class Logging:

async def on_member_remove(self, member):
# TODO: Add some way of detecting whether a user left/was kicked or was banned.
logging = Roxbot.guild_settings.get(member.guild).logging
logging = guild_settings.get(member.guild).logging
if logging["enabled"]:
channel = self.bot.get_channel(logging["channel"])
embed = discord.Embed(description="{} left the server".format(member), colour=Roxbot.embedcolour)
embed = discord.Embed(description="{} left the server".format(member), colour=embedcolour)
return await channel.send(embed=embed)



+ 1
- 2
Roxbot/settings/settings.py View File

@@ -4,8 +4,7 @@ import aiohttp
import asyncio
import datetime

from Roxbot import checks, load_config
from Roxbot.settings import guild_settings
from Roxbot import checks, load_config, guild_settings

import discord
from discord.ext.commands import bot, group, is_owner, bot_has_permissions

Loading…
Cancel
Save