from discord.ext import commands import discord import random import re import math import glob from bs4 import BeautifulSoup as bs from . import utils class Images: def __init__(self, bot): self.bot = bot @commands.command(aliases=['rc']) @utils.custom_perms(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""" result = await utils.request('http://random.cat/meow') if result is None: await ctx.send("I couldn't connect! Sorry no cats right now ;w;") return filename = result.get('file', None) if filename is None: await ctx.send("I couldn't connect! Sorry no cats right now ;w;") return image = await utils.download_image(filename) filename = re.search('.*/i/(.*)', filename).group(1) f = discord.File(image, filename=filename) await ctx.send(file=f) @commands.command(aliases=['dog', 'rd']) @utils.custom_perms(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('http://random.dog', attr='text') try: soup = bs(result, 'html.parser') filename = soup.img.get('src') except (TypeError, AttributeError): await ctx.send("I couldn't connect! Sorry no dogs right now ;w;") return image = await utils.download_image("http://random.dog/{}".format(filename)) f = discord.File(image, filename=filename) await ctx.send(file=f) @commands.command() @utils.custom_perms(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""" # Find a random image based on how many we currently have f = random.SystemRandom().choice(glob.glob('images/snek*')) with open(f, 'rb') as f: await ctx.send(file=discord.File(f)) @commands.command() @commands.guild_only() @utils.custom_perms(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 = member.avatar_url if '.gif' not in url: url = 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.custom_perms(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!""" await ctx.message.channel.trigger_typing() if len(search) > 0: url = 'https://derpibooru.org/search.json' # 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 = await utils.channel_is_nsfw(ctx.message.channel, self.bot.db) # 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['search'] 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['search'] # 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 = 'https:{}'.format(results[index]['image']) 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.custom_perms(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)""" await ctx.message.channel.trigger_typing() # 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/post/index.json' params = {'limit': 320, 'tags': tags} nsfw = await utils.channel_is_nsfw(ctx.message.channel, self.bot.db) # 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" data = await utils.request(url, payload=params) 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: rand_image = data[random.SystemRandom().randint(0, len(data) - 1)]['file_url'] await ctx.send(rand_image) except (ValueError, KeyError): await ctx.send("No results with that tag {}".format(ctx.message.author.mention)) return def setup(bot): bot.add_cog(Images(bot))