291 lines
11 KiB
Python
291 lines
11 KiB
Python
from discord.ext import commands
|
|
import discord
|
|
import itertools
|
|
import random
|
|
import re
|
|
import math
|
|
|
|
import utils
|
|
|
|
|
|
class Images(commands.Cog):
|
|
"""Commands that post images, or look up images"""
|
|
|
|
async def horse_noodle_api(self, ctx, animal):
|
|
data = await utils.request(f"http://hrsendl.com/api/{animal}")
|
|
|
|
try:
|
|
url = data["data"]["file_url_size_large"]
|
|
credit = data["data"]["file_source_url"]
|
|
except (KeyError, TypeError):
|
|
return await ctx.send(
|
|
f"I couldn't connect! Sorry no {animal}s right now ;w;"
|
|
)
|
|
else:
|
|
e = discord.Embed(title="Source", url=credit)
|
|
e.set_image(url=url)
|
|
await ctx.send(embed=e)
|
|
|
|
@commands.command(aliases=["rc"])
|
|
@utils.can_run(send_messages=True)
|
|
async def cat(self, ctx):
|
|
"""Use this to print a random cat image.
|
|
|
|
EXAMPLE: !cat
|
|
RESULT: A beautiful picture of a cat o3o"""
|
|
url = "http://thecatapi.com/api/images/get"
|
|
opts = {"format": "src"}
|
|
result = await utils.request(url, attr="url", payload=opts)
|
|
|
|
e = discord.Embed(title="Source", url=str(result))
|
|
e.set_image(url=str(result))
|
|
await ctx.send(embed=e)
|
|
|
|
@commands.command(aliases=["dog", "rd"])
|
|
@utils.can_run(send_messages=True)
|
|
async def doggo(self, ctx):
|
|
"""Use this to print a random doggo image.
|
|
|
|
EXAMPLE: !doggo
|
|
RESULT: A beautiful picture of a dog o3o"""
|
|
result = await utils.request("https://dog.ceo/api/breeds/image/random")
|
|
try:
|
|
url = result.get("message")
|
|
e = discord.Embed(title="Source", url=str(url))
|
|
e.set_image(url=str(url))
|
|
await ctx.send(embed=e)
|
|
except AttributeError:
|
|
await ctx.send("I couldn't connect! Sorry no dogs right now ;w;")
|
|
|
|
@commands.command(aliases=["snake"])
|
|
@utils.can_run(send_messages=True)
|
|
async def snek(self, ctx):
|
|
"""Use this to print a random snek image.
|
|
|
|
EXAMPLE: !snek
|
|
RESULT: A beautiful picture of a snek o3o"""
|
|
await self.horse_noodle_api(ctx, "snake")
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def horse(self, ctx):
|
|
"""Use this to print a random horse image.
|
|
|
|
EXAMPLE: !horse
|
|
RESULT: A beautiful picture of a horse o3o"""
|
|
await self.horse_noodle_api(ctx, "horse")
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def duck(self, ctx):
|
|
"""Use this to print a random duck image.
|
|
|
|
EXAMPLE: !duck
|
|
RESULT: A beautiful picture of a duck o3o"""
|
|
await self.horse_noodle_api(ctx, "duck")
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def snail(self, ctx):
|
|
"""Use this to print a random snail image.
|
|
|
|
EXAMPLE: !snail
|
|
RESULT: A beautiful picture of a snail o3o"""
|
|
await self.horse_noodle_api(ctx, "snail")
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def pleco(self, ctx):
|
|
"""Use this to print a random pleco image.
|
|
|
|
EXAMPLE: !pleco
|
|
RESULT: A beautiful picture of a pleco o3o"""
|
|
await self.horse_noodle_api(ctx, "pleco")
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def moth(self, ctx):
|
|
"""Use this to print a random moth image.
|
|
|
|
EXAMPLE: !moth
|
|
RESULT: A beautiful picture of a moth o3o"""
|
|
await self.horse_noodle_api(ctx, "moth")
|
|
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
@utils.can_run(send_messages=True)
|
|
async def avatar(self, ctx, member: discord.Member = None):
|
|
"""Provides an image for the provided person's avatar (yours if no other member is provided)
|
|
|
|
EXAMPLE: !avatar @person
|
|
RESULT: A full image of that person's avatar"""
|
|
|
|
if member is None:
|
|
member = ctx.message.author
|
|
|
|
url = str(member.avatar_url)
|
|
if ".gif" not in url:
|
|
url = str(member.avatar_url_as(format="png"))
|
|
filename = "avatar.png"
|
|
else:
|
|
filename = "avatar.gif"
|
|
if ctx.message.guild.me.permissions_in(ctx.message.channel).attach_files:
|
|
filedata = await utils.download_image(url)
|
|
if filedata is None:
|
|
await ctx.send(url)
|
|
else:
|
|
try:
|
|
f = discord.File(filedata, filename=filename)
|
|
await ctx.send(file=f)
|
|
except discord.HTTPException:
|
|
await ctx.send("Sorry but that avatar is too large for me to send!")
|
|
else:
|
|
await ctx.send(url)
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def derpi(self, ctx, *search: str):
|
|
"""Provides a random image from the first page of derpibooru.org for the following term
|
|
|
|
EXAMPLE: !derpi Rainbow Dash
|
|
RESULT: A picture of Rainbow Dash!"""
|
|
|
|
if len(search) > 0:
|
|
url = "https://derpibooru.org/api/v1/json/search/images"
|
|
|
|
# Ensure a filter was not provided, as we either want to use our own, or none (for safe pics)
|
|
query = " ".join(
|
|
value for value in search if not re.search("&?filter_id=[0-9]+", value)
|
|
)
|
|
params = {"q": query}
|
|
|
|
nsfw = utils.channel_is_nsfw(ctx.message.channel)
|
|
# If this is a nsfw channel, we just need to tack on 'explicit' to the terms
|
|
# Also use the custom filter that I have setup, that blocks some certain tags
|
|
# If the channel is not nsfw, we don't need to do anything, as the default filter blocks explicit
|
|
if nsfw:
|
|
params["q"] += ", (explicit OR suggestive)"
|
|
params["filter_id"] = 95938
|
|
else:
|
|
params["q"] += ", safe"
|
|
# Lets filter out some of the "crap" that's on derpibooru by requiring an image with a score higher than 15
|
|
params["q"] += ", score.gt:15"
|
|
|
|
try:
|
|
# Get the response from derpibooru and parse the 'search' result from it
|
|
data = await utils.request(url, payload=params)
|
|
|
|
if data is None:
|
|
await ctx.send("Sorry but I failed to connect to Derpibooru!")
|
|
return
|
|
results = data["images"]
|
|
except KeyError:
|
|
await ctx.send(
|
|
"No results with that search term, {0}!".format(
|
|
ctx.message.author.mention
|
|
)
|
|
)
|
|
return
|
|
|
|
# The first request we've made ensures there are results
|
|
# Now we can get the total count from that, and make another request based on the number of pages as well
|
|
if len(results) > 0:
|
|
# Get the total number of pages
|
|
pages = math.ceil(data["total"] / len(results))
|
|
# Set a new paramater to set which page to use, randomly based on the number of pages
|
|
params["page"] = random.SystemRandom().randint(1, pages)
|
|
data = await utils.request(url, payload=params)
|
|
if data is None:
|
|
await ctx.send("Sorry but I failed to connect to Derpibooru!")
|
|
return
|
|
# Now get the results again
|
|
results = data["images"]
|
|
|
|
# Get the image link from the now random page'd and random result from that page
|
|
index = random.SystemRandom().randint(0, len(results) - 1)
|
|
# image_link = 'https://derpibooru.org/{}'.format(results[index]['id'])
|
|
image_link = results[index]["view_url"]
|
|
else:
|
|
await ctx.send(
|
|
"No results with that search term, {0}!".format(
|
|
ctx.message.author.mention
|
|
)
|
|
)
|
|
return
|
|
else:
|
|
# If no search term was provided, search for a random image
|
|
# .url will be the URL we end up at, not the one requested.
|
|
# https://derpibooru.org/images/random redirects to a random image, so this is exactly what we want
|
|
image_link = await utils.request(
|
|
"https://derpibooru.org/images/random", attr="url"
|
|
)
|
|
await ctx.send(image_link)
|
|
|
|
@commands.command()
|
|
@utils.can_run(send_messages=True)
|
|
async def e621(self, ctx, *, tags: str):
|
|
"""Searches for a random image from e621.net
|
|
Format for the search terms need to be 'search term 1, search term 2, etc.'
|
|
If the channel the command is ran in, is registered as a nsfw channel, this image will be explicit
|
|
|
|
EXAMPLE: !e621 dragon
|
|
RESULT: A picture of a dragon (hopefully, screw your tagging system e621)"""
|
|
|
|
# This changes the formatting for queries, so we don't
|
|
# Have to use e621's stupid formatting when using the command
|
|
|
|
tags = tags.replace(" ", "_")
|
|
tags = tags.replace(",_", " ")
|
|
|
|
url = "https://e621.net/posts.json"
|
|
params = {
|
|
"login": utils.config.e621_user,
|
|
"api_key": utils.config.e621_key,
|
|
"limit": 5,
|
|
"tags": tags,
|
|
}
|
|
headers = {"User-Agent": utils.config.user_agent}
|
|
nsfw = utils.channel_is_nsfw(ctx.message.channel)
|
|
|
|
# e621 by default does not filter explicit content, so tack on
|
|
# safe/explicit based on if this channel is nsfw or not
|
|
params["tags"] += " rating:explicit" if nsfw else " rating:safe"
|
|
# Tack on a random order
|
|
params["tags"] += " order:random"
|
|
|
|
data = await utils.request(url, payload=params, headers=headers)
|
|
|
|
if data is None:
|
|
await ctx.send(
|
|
"Sorry, I had trouble connecting at the moment; please try again later"
|
|
)
|
|
return
|
|
|
|
# Try to find an image from the list. If there were no results, we're going to attempt to find
|
|
# A number between (0,-1) and receive an error.
|
|
# The response should be in a list format, so we'll end up getting a key error if the response was in json
|
|
# i.e. it responded with a 404/504/etc.
|
|
try:
|
|
for image in data["posts"]:
|
|
# Will support in the future
|
|
blacklist = []
|
|
tags = itertools.chain.from_iterable(image["tags"].values())
|
|
# Check if any of the tags are in the blacklist
|
|
if any(tag in tags for tag in blacklist):
|
|
continue
|
|
# If this image is fine, then send this and break
|
|
await ctx.send(image["file"]["url"])
|
|
return
|
|
except (ValueError, KeyError):
|
|
await ctx.send(
|
|
"No results with that tag {}".format(ctx.message.author.mention)
|
|
)
|
|
return
|
|
|
|
# If we're here then there was nothing in the posts, or nothing found that's not blacklisted
|
|
await ctx.send("No results with that tag {}".format(ctx.message.author.mention))
|
|
|
|
|
|
def setup(bot):
|
|
bot.add_cog(Images(bot))
|