@@ -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,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(): |
@@ -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) |
@@ -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") |
@@ -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: |
@@ -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=""): | |||
""" |
@@ -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)) |
@@ -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"]: |
@@ -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) | |||
@@ -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() |
@@ -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) | |||
@@ -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 |