async def process_request(ctx:Union[commands.Context, discord.CommandInteraction], room:str): url = f"https://www.fit.vut.cz/fit/map/.cs?show={room.upper()}&big=1" r = requests.get(url) if r.status_code != 200: return await ctx.send(embed=general_util.generate_error_message(Strings.fitroom_bad_response), delete_after=Config.base_error_duration) try: soup = BeautifulSoup(r.content, 'html.parser') main_body_ = soup.find("main", {"id": "main"}) floor_list_ = main_body_.find("ul", {"class": "pagination__list"}) active_floor_ = floor_list_.find("a", {"aria-current": "page"}) image_ = main_body_.find("svg") cursor_ = image_.find("polygon", {"class": "arrow"}) except Exception: logger.error(f"Failed to parse fit room\n{traceback.format_exc()}") return await ctx.send(embed=general_util.generate_error_message(Strings.fitroom_page_parsing_failed), delete_after=Config.base_error_duration) if image_ is None or cursor_ is None: return await ctx.send(embed=general_util.generate_error_message(Strings.fitroom_room_not_on_plan), delete_after=Config.base_error_duration) image_bytes = BytesIO() image_bytestring = str(image_).replace("/img/su/logo-kachnicka-mapa.png", "https://www.fit.vut.cz/img/su/logo-kachnicka-mapa.png").encode("utf-8") svg2png(bytestring=image_bytestring, write_to=image_bytes, parent_width=720, parent_height=1000, background_color="white", dpi=300) image_bytes.seek(0) embed = discord.Embed(title=f"Room {room}", color=discord.Color.dark_blue()) embed.set_image(url="attachment://plan.png") embed.description = f"[Link to website]({url})" embed.set_footer(text=str(active_floor_.text)) file = discord.File(fp=image_bytes, filename="plan.png") await ctx.send(embed=embed, file=file)
async def reload(self, ctx: KurisuContext, *cogs): """Reload cogs""" succeed = 0 failed = 0 error_str = "" embed = disnake.Embed(description=":ok_hand:", color=self.bot.info_color) for ext in cogs: try: self.bot.reload_extension(ext) succeed += 1 except commands.ExtensionError as e: failed += 1 error_str += ( f"**Error for {ext}**:\n\n{''.join(traceback.format_exception(None, e, e.__traceback__))}\n" ) if failed > 0: embed.set_footer( text=f"Failed to reload {failed} cogs. Sending error file...") await ctx.send(embed=embed) if error_str: await ctx.send(file=disnake.File( io.BytesIO(error_str.encode("utf-8")), "error.nim"))
async def run_discord(self, func, inter, *args, **kwargs): data = func(*args, **kwargs) if "view" in data: await inter.send( embed=data["embed"][0], view=data["view"](data["embed"], data["choices"]), ) else: title = data.get("title", "") embed = disnake.Embed(title=title, colour=imps.COLOR, description=data.get("description", "")) embed.set_author( name=imps.AUTHOR_NAME, icon_url=imps.AUTHOR_ICON_URL, ) if "imagefile" in data: filename = data["imagefile"] imagefile = imps.IMG_DIR.joinpath(filename) image = disnake.File(imagefile, filename=filename) embed.set_image(url=f"attachment://{filename}") await inter.send(embed=embed, file=image) image.close() os.remove(imagefile) else: await inter.send(embed=embed)
async def run_discord(self, func, inter, *args, **kwargs): data = func(*args, **kwargs) if "view" in data: await inter.send( embed=data["embed"][0], view=data["view"](data["embed"], data["choices"]), ) else: title = data.get("title", "") embed = disnake.Embed( title=title, colour=cfg.COLOR, description=data.get("description", "") ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) if "imagefile" in data: image = disnake.File(data["imagefile"]) embed.set_image(url=f"attachment://{data['imagefile']}") os.remove(data["imagefile"]) await inter.send(embed=embed, file=image) else: await inter.send(embed=embed)
async def post_info(self, ctx, name): with open(f"{name}.txt", "r") as file: pages = Pages.paginate("".join(file.readlines()), 500, 2000) await ctx.channel.purge(limit=len(pages) + 2) await ctx.send(file=disnake.File(f"{name}.png")) for page in pages: await ctx.send(page)
def log_to(guild_id, targets, message, embed, file, tag_on=None): for target in targets: # make sure we have a queue and a running task if target not in LOG_QUEUE: LOG_QUEUE[target] = Queue() BOT.loop.create_task(log_task(guild_id, target)) # duplicate the file bytes so it doesn't freak out when we try to send it twice f = None if file is not None: buffer = file[0] name = file[1] buffer.seek(0) b2 = io.BytesIO() for line in buffer.readlines(): b2.write(line) b2.seek(0) f = disnake.File(b2, name) # actually adding to the queue if tag_on is None: LOG_QUEUE[target].put(todo(message, embed, f)) else: LOG_QUEUE[target].put(todo(message, None, None)) LOG_QUEUE[target].put(todo(tag_on, embed, f))
async def on_message(self, message: disnake.Message): """Api point for grillbot""" if message.author.id not in config.grillbot_ids: return lines = message.content.split('\n') if not (lines[0] == '```json' and lines[-1] == '```'): return lines = lines[1:-1] content = '\n'.join(lines) request = json.loads(content) if "method" not in request or request["method"] not in config.grillbot_api_supported_methods: await message.reply("Unsupported method") return params = request["parameters"] cog = self.bot.get_cog(request["method"]) # check if cog is loaded if cog: status, content = cog.api(message, params) if status != 0: await message.reply(content) return res_json = json.dumps(content) with BytesIO(bytes(res_json, 'utf-8')) as file_binary: await message.reply(file=disnake.File(fp=file_binary, filename="res.json")) else: await message.reply("Extension not loaded")
async def on_message(self, message: disnake.message): global uhoh_counter global storno_time if message.author.bot: if (message.author.id in config.grillbot_ids and message.content.startswith("<:") and message.content.endswith(">")): await message.channel.send(message.content) return elif config.uhoh_string in message.content.lower(): await message.channel.send("uh oh") uhoh_counter += 1 elif message.content == "PR": await message.channel.send(messages.pr_meme) elif (storno_time + datetime.timedelta(hours=config.storno_delay) < message.created_at and "storno" in message.content.lower() and message.channel.id == config.covid_channel_id): storno_time = message.created_at image = choice(storno_images) await message.channel.send( utils.fill_message("covid_storno", user=message.author.id), file=disnake.File(f"images/{image}", filename=image), )
async def collage(self, inter: ApplicationCommandInteraction, username: str, dimensions: str, period: str): await inter.response.defer( ) # we do a little ACK so we have time to fetch stats if username == "": username = inter.author.name self.log.request_slash(inter, "collage", username, extras={ "dimensions": dimensions, "period": period }) re_type, response = await self.service.top_collage(username, period, dims=dimensions) self.log.response("collage", username, re_type, response) if re_type == BotResponseCode.ERROR or re_type == BotResponseCode.TEXT: await inter.edit_original_message(content=response) elif re_type == BotResponseCode.IMAGE: await inter.edit_original_message( file=disnake.File(fp=response, filename="image.png"))
async def attachments_to_files( self, attachments: List[disnake.Attachment]) -> List[disnake.File]: files = [] for attachment in attachments: buffer = BytesIO(await attachment.read()) files.append(disnake.File(buffer, filename=attachment.filename)) return files
async def savechat(self, ctx: KurisuContext, limit: int = 15): """Save messages from the current text channel""" basestr = "" async for msg in ctx.channel.history(limit=limit): basestr += f"{msg.author}: {msg.content}\n" await ctx.send(file=disnake.File((io.BytesIO(basestr.encode( "utf-8"))), f"{ctx.message.created_at.strftime('%c')}.txt"))
async def eval(self, ctx, *, body: str): '''Evaluates some code.''' from pprint import pprint from tabulate import tabulate env = { 'disnake.': disnake, 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message, 'pprint': pprint, 'tabulate': tabulate, 'db': self.db } env.update(globals()) body = self.cleanup_code(body) stdout = io.StringIO() to_compile = f'async def func():\n{textwrap.indent(body, " ")}' try: exec(to_compile, env) except Exception as e: return await ctx.send(f'```py\n{e.__class__.__name__}: {e}\n```') func = env['func'] try: with redirect_stdout(stdout): ret = await func() except Exception as e: value = stdout.getvalue() await ctx.send(f'```py\n{value}{traceback.format_exc()}\n```') else: value = stdout.getvalue() try: await ctx.message.add_reaction('\u2705') except: pass if ret is None: if value: if len(value) > 1990: fp = io.BytesIO(value.encode('utf-8')) await ctx.send('Log too large...', file=disnake.File(fp, 'results.txt')) else: await ctx.send(f'```py\n{value}\n```')
async def jsk_curl(self, ctx: commands.Context, url: str): """ Download and display a text file from the internet. This command is similar to jsk cat, but accepts a URL. """ # remove embed maskers if present url = url.lstrip("<").rstrip(">") async with ReplResponseReactor(ctx.message): async with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.read() hints = (response.content_type, url) code = response.status if not data: return await ctx.send( f"HTTP response was empty (status code {code}).") if use_file_check(ctx, len(data)): # File "full content" preview limit # Shallow language detection language = None for hint in hints: language = get_language(hint) if language: break await ctx.send( file=disnake.File(filename=f"response.{language or 'txt'}", fp=io.BytesIO(data))) else: try: paginator = WrappedFilePaginator(io.BytesIO(data), language_hints=hints, max_size=1985) except UnicodeDecodeError: return await ctx.send( f"Couldn't determine the encoding of the response. (status code {code})" ) except ValueError as exc: return await ctx.send( f"Couldn't read response (status code {code}), {exc}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def pet(self, ctx: Union[commands.Context, discord.CommandInteraction], *, user: Optional[discord.Member] = None): if user is None: user = ctx.author if not user.avatar: await ctx.send(embed=general_util.generate_error_message( Strings.action_unsupported_avatar), delete_after=Config.base_error_duration) return url = user.avatar.with_format('jpg').url response = requests.get(url) avatarFull = Image.open(BytesIO(response.content)) frames = [] deformWidth = [-1, -2, 1, 2, 1] deformHeight = [4, 3, 1, 1, -4] width = 80 height = 80 for i in range(5): frame = Image.new('RGBA', (112, 112), (255, 255, 255, 1)) hand = Image.open(f"static_data/images/pet/{i}.png") width = width - deformWidth[i] height = height - deformHeight[i] avatar = avatarFull.resize((width, height)) avatarMask = Image.new('1', avatar.size, 0) draw = ImageDraw.Draw(avatarMask) draw.ellipse((0, 0) + avatar.size, fill=255) avatar.putalpha(avatarMask) frame.paste(avatar, (112 - width, 112 - height), avatar) frame.paste(hand, (0, 0), hand) frames.append(frame) with BytesIO() as image_binary: frames[0].save(image_binary, format='GIF', save_all=True, append_images=frames[1:], duration=40, loop=0, transparency=0, disposal=2, optimize=False) image_binary.seek(0) await ctx.send( file=discord.File(fp=image_binary, filename="pet.gif"))
async def bonk(self, ctx: commands.Context, member: disnake.User) -> None: """Sends gif of mentioned member being "bonked" by Yoda.""" pfp = await member.display_avatar.read() created_at = ctx.message.created_at.strftime("%Y-%m-%d_%H-%M") out_filename = f"bonk_{member.id}_{created_at}.gif" func = functools.partial(self._generate_gif, pfp) async with ctx.typing(): with futures.ThreadPoolExecutor() as pool: out_gif = await asyncio.get_running_loop().run_in_executor( pool, func) out_gif.seek(0) await ctx.send(file=disnake.File(out_gif, out_filename))
async def updateTracker(self, t): day = self.getCurrentGWDayID() if day is None or day <= 1 or day >= 10: # check if match day return you_id = self.bot.data.config['granblue']['gbfgcrew'].get('you', None) # our id if you_id is None: return if self.bot.data.save['matchtracker'] is None: return # not initialized if self.bot.data.save['matchtracker']['day'] != day: # new day, reset with self.bot.data.lock: self.bot.data.save['matchtracker'] = { 'day':day, 'init':False, 'id':self.bot.data.save['matchtracker']['id'], 'plot':[] } self.bot.data.pending = True infos = await self.bot.do(self.searchScoreForTracker, day, [you_id, self.bot.data.save['matchtracker']['id']]) newtracker = self.bot.data.save['matchtracker'].copy() if newtracker['init']: d = t - newtracker['last'] speed = [(infos[0][1] - newtracker['scores'][0]) / (d.seconds//60), (infos[1][1] - newtracker['scores'][1]) / (d.seconds//60)] if speed[0] > newtracker['top_speed'][0]: newtracker['top_speed'][0] = speed[0] if speed[1] > newtracker['top_speed'][1]: newtracker['top_speed'][1] = speed[1] newtracker['speed'] = speed else: newtracker['init'] = True newtracker['speed'] = None newtracker['top_speed'] = [0, 0] newtracker['names'] = [infos[0][0], infos[1][0]] newtracker['scores'] = [infos[0][1], infos[1][1]] newtracker['last'] = t newtracker['gwid'] = self.bot.data.save['gw']['id'] if newtracker['speed'] is not None: # save chart data newtracker['plot'].append([t, newtracker['speed'][0] / 1000000, newtracker['speed'][1] / 1000000]) if len(newtracker['plot']) > 1: # generate chart try: imgdata = self.drawChart(newtracker['plot']) with BytesIO(imgdata) as f: df = disnake.File(f, filename="chart.png") message = await self.bot.send('image', file=df) df.close() newtracker['chart'] = message.attachments[0].url except Exception as e: await self.bot.sendError('updatetracker', e) with self.bot.data.lock: self.bot.data.save['matchtracker'] = newtracker self.bot.data.pending = True
async def on_message(self, message): if message.author == self.bot.user: return if type(message.channel) is disnake.DMChannel: channel = await self.bot.fetch_channel(self.channel_id) files = [] for attachment in message.attachments: fp = io.BytesIO() await attachment.save(fp) files.append(disnake.File(fp, filename=attachment.filename)) await channel.send( f"Support Nachricht von <@!{message.author.id}>:") await channel.send(message.content, files=files)
def check_saves(self): """Checks if the user saved the game.""" if os.path.exists(self.save_path): files = [x for x in os.listdir(self.save_path) if not SCRIPT_OR_RECORD.match(x) and x != "__UPLOADED__.qzl"] latest = [0, None] for file in files: mod_time = os.stat("{}/{}".format(self.save_path, file)).st_mtime_ns if mod_time > latest[0]: latest = [mod_time, file] if latest[1] and latest[1] != self.last_save: self.last_save = latest[1] return discord.File("{}/{}".format(self.save_path, latest[1]), latest[1]) return None
async def on_message(self, message: disnake.Message): """Sending commands help to grillbot""" if message.author.id not in config.grillbot_ids: return lines = message.content.split('\n') if not (lines[0] == '```json' and lines[-1] == '```'): return lines = lines[1:-1] content = '\n'.join(lines) request = json.loads(content) if "method" not in request or request["method"] != "help": await message.reply("Unsupported method") return param = request["parameters"] # mock ctx mock_message = copy.copy(message) mock_view = commands.view.StringView("") mock_message.author = self.bot.get_user(param["user_id"]) ctx = commands.Context( bot=self.bot, view=mock_view, prefix=config.default_prefix, message=mock_message, ) if "command" in param and param["command"] != None: command = self.bot.get_command(param["command"]) if not command: await message.reply("Command not found") return help = {} for check in command.checks: try: if not check(ctx): break except Exception: break else: help = self.command_help(ctx, command) else: # return help for all commands help = self.generate_pages(ctx) help_json = json.dumps(help) with BytesIO(bytes(help_json, 'utf-8')) as file_binary: await message.reply( file=disnake.File(fp=file_binary, filename="help.json"))
async def pet(self, ctx, user: disnake.Member = None): if user is None: user = ctx.author if not user.avatar: await ctx.send(Messages.unsupported_image) return url = user.display_avatar.with_format('jpg') response = requests.get(url) avatarFull = Image.open(BytesIO(response.content)) frames = [] deformWidth = [-1, -2, 1, 2, 1] deformHeight = [4, 3, 1, 1, -4] width = 80 height = 80 for i in range(5): frame = Image.new('RGBA', (112, 112), (255, 255, 255, 1)) hand = Image.open(f"images/pet/{i}.png") width = width - deformWidth[i] height = height - deformHeight[i] avatar = avatarFull.resize((width, height)) avatarMask = Image.new('1', avatar.size, 0) draw = ImageDraw.Draw(avatarMask) draw.ellipse((0, 0) + avatar.size, fill=255) avatar.putalpha(avatarMask) frame.paste(avatar, (112 - width, 112 - height), avatar) frame.paste(hand, (0, 0), hand) frames.append(frame) with BytesIO() as image_binary: frames[0].save(image_binary, format='GIF', save_all=True, append_images=frames[1:], duration=40, loop=0, transparency=0, disposal=2, optimize=False) image_binary.seek(0) await ctx.send( file=disnake.File(fp=image_binary, filename="pet.gif"))
async def jsk_source(self, ctx: commands.Context, *, command_name: str): """ Displays the source code for a command. """ command = self.bot.get_command(command_name) or self.get_slash_command( command_name) if not command: return await ctx.send(f"Couldn't find command `{command_name}`.") try: source_lines, _ = inspect.getsourcelines(command.callback) except (TypeError, OSError): return await ctx.send( f"Was unable to retrieve the source for `{command}` for some reason." ) filename = "source.py" try: filename = pathlib.Path(inspect.getfile(command.callback)).name except (TypeError, OSError): pass # getsourcelines for some reason returns WITH line endings source_text = ''.join(source_lines) if use_file_check( ctx, len(source_text)): # File "full content" preview limit await ctx.send(file=disnake.File( filename=filename, fp=io.BytesIO(source_text.encode('utf-8')))) else: paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985) paginator.add_line( source_text.replace('```', '``\N{zero width space}`')) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def room(self, ctx: commands.Context, *, room: str): url = f"https://www.fit.vut.cz/fit/map/.cs?show={room.upper()}&big=1" r = requests.get(url) if r.status_code != 200: return await ctx.send(Messages.fit_room_unreach) async with ctx.typing(): try: soup = BeautifulSoup(r.content, 'html.parser') main_body = soup.find("main", {"id": "main"}) floor_list = main_body.find("ul", {"class": "pagination__list"}) active_floor = floor_list.find("a", {"aria-current": "page"}) image = main_body.find("svg") cursor = image.find("polygon", {"class": "arrow"}) except: return await ctx.send(Messages.fit_room_parsing_failed) if image is None or cursor is None: return await ctx.send( utils.fill_message("fit_room_room_not_on_plan", room=room)) image_bytes = BytesIO() image_bytestring = str(image).replace( kachnicka_path, kachnicka_url).encode("utf-8") svg2png(bytestring=image_bytestring, write_to=image_bytes, parent_width=720, parent_height=1000, background_color="white", dpi=300) image_bytes.seek(0) embed = disnake.Embed(title=f"Místnost: {room}", color=disnake.Color.dark_blue()) embed.set_image(url="attachment://plan.png") embed.description = f"[Odkaz na plánek]({url})" utils.add_author_footer(embed, ctx.author, additional_text=[str(active_floor.text)]) file = disnake.File(fp=image_bytes, filename="plan.png") await ctx.send(embed=embed, file=file)
async def game_loop(self): """Enters into the channel's game process loop.""" if not self.process: await self.init_process() self.first_time = True self.playing = True async def looper(buffer): await self.parse_output(buffer) if os.path.exists(self.save_path): files = os.listdir(self.save_path) latest = 0 for file in os.listdir(self.save_path): mod_time = os.stat("{}/{}".format(self.save_path, file)).st_mtime_ns if mod_time < latest or SCRIPT_OR_RECORD.match(file) or file == "__UPLOADED__.qzl": os.unlink("{}/{}".format(self.save_path, file)) elif mod_time > latest and not SCRIPT_OR_RECORD.match(file): latest = mod_time await handle_process_output(self.process, looper, self.parse_output) self.playing = False end_msg = "```diff\n-The game has ended.\n" end_kwargs = {} if self.last_save: file_dir = "{}/{}".format(self.save_path, self.last_save) if os.path.isfile(file_dir): end_kwargs = {"file": discord.File(file_dir, self.last_save)} end_msg += "+Here is your most recent save from the game.\n" end_msg += "```" await self.channel.send(end_msg, **end_kwargs) self.cleanup()
async def add_appointment(self, channel, author_id, date, time, reminder, title, recurring: int = None): """ Add appointment to a channel """ try: date_time = datetime.datetime.strptime(f"{date} {time}", self.fmt) except ValueError: await channel.send("Fehler! Ungültiges Datums und/oder Zeit Format!") return if not utils.is_valid_time(reminder): await channel.send("Fehler! Benachrichtigung in ungültigem Format!") return else: reminder = utils.to_minutes(reminder) embed = disnake.Embed(title="Neuer Termin hinzugefügt!", description=f"Wenn du eine Benachrichtigung zum Beginn des Termins" f"{f', sowie {reminder} Minuten vorher, ' if reminder > 0 else f''} " f"erhalten möchtest, reagiere mit :thumbsup: auf diese Nachricht.", color=19607) embed.add_field(name="Titel", value=title, inline=False) embed.add_field(name="Startzeitpunkt", value=f"{date_time.strftime(self.fmt)}", inline=False) if reminder > 0: embed.add_field(name="Benachrichtigung", value=f"{reminder} Minuten vor dem Start", inline=False) if recurring: embed.add_field(name="Wiederholung", value=f"Alle {recurring} Tage", inline=False) message = await channel.send(embed=embed, file=disnake.File(get_ics_file(title, date_time, reminder, recurring), filename=f"{title}.ics")) await message.add_reaction("👍") await message.add_reaction("🗑️") if str(channel.id) not in self.appointments: self.appointments[str(channel.id)] = {} channel_appointments = self.appointments.get(str(channel.id)) channel_appointments[str(message.id)] = {"date_time": date_time.strftime(self.fmt), "reminder": reminder, "title": title, "author_id": author_id, "recurring": recurring} self.save_appointments()
async def dump(self, ctx, message: disnake.Message, return_json: Optional[bool] = False): """Get the source json data for an embed, returns a discohook url by default""" embeds = [] for embed in message.embeds: embeds.append(embed.to_dict()) j = json.dumps({"message": {"embeds": embeds}}) b64 = urlsafe_b64encode(j.encode('utf-8')).decode('utf-8') url = f'{DISCOHOOK_BASE}/?message={b64}' if len(url) > 2000 or return_json: fp = BytesIO(bytes(j, encoding='utf-8')) await ctx.send(file=disnake.File(fp, filename='embed.json')) return await ctx.send(f'<{url}>')
async def sql(self, ctx, *, query: str): '''Execute a SQL query.''' try: result = await self.db.fetch(query) except Exception as exc: raise commands.CommandError(str(exc)) if not len(result): await ctx.send('No rows returned.') return table = tabulate(result, {header: header for header in result[0].keys()}) if len(table) > 1994: fp = io.BytesIO(table.encode('utf-8')) await ctx.send('Too many results...', file=disnake.File(fp, 'results.txt')) else: await ctx.send('```' + table + '```')
async def autosave(self, discordDump = False): # called when pending is true by statustask() if self.autosaving: return self.autosaving = True result = False for i in range(0, 3): # try a few times with self.lock: if self.saveData(): self.pending = False result = True break await asyncio.sleep(0.001) if not result: await self.bot.send('debug', embed=self.bot.util.embed(title="Failed Save", timestamp=self.bot.util.timestamp())) discordDump = True if discordDump: try: with open('save.json', 'r') as infile: df = disnake.File(infile) await self.bot.send('debug', 'save.json', file=df) df.close() except: pass self.autosaving = False
async def bonk(self, ctx: Union[commands.Context, discord.CommandInteraction], *, user: Optional[discord.Member] = None): if user is None: bonked = ctx.author else: bonked = user if not bonked.avatar: await ctx.send(embed=general_util.generate_error_message( Strings.action_unsupported_avatar), delete_after=Config.base_error_duration) return url = bonked.avatar.with_format('jpg').url response = requests.get(url) avatar = Image.open(BytesIO(response.content)) frames = self.get_bonk_frames(avatar) with BytesIO() as image_binary: frames[0].save( image_binary, format="GIF", save_all=True, append_images=frames[1:], duration=30, loop=0, transparency=0, disposal=2, optimize=False, ) image_binary.seek(0) await ctx.send( file=discord.File(fp=image_binary, filename="bonk.gif"))
async def bonk(self, ctx, member: disnake.Member = None): """Bonk someone member: disnake user. If none, the bot will bonk you. """ if member is None: bonked = ctx.author else: bonked = member if not bonked.avatar: await ctx.send(messages.unsupported_image) return async with ctx.typing(): url = bonked.display_avatar.with_format("jpg") response = requests.get(url) avatar = Image.open(BytesIO(response.content)) frames = self.get_bonk_frames(avatar) with BytesIO() as image_binary: frames[0].save( image_binary, format="GIF", save_all=True, append_images=frames[1:], duration=30, loop=0, transparency=0, disposal=2, optimize=False, ) image_binary.seek(0) await ctx.reply( file=disnake.File(fp=image_binary, filename="bonk.gif"), mention_author=False, )
async def latex(self, ctx, *, equation): channel = ctx.channel async with ctx.typing(): eq = urllib.parse.quote(equation) imgURL = f"http://www.sciweavers.org/tex2img.php?eq={eq}&fc=White&im=png&fs=25&edit=0" async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout( total=10)) as session: try: async with session.get(imgURL) as resp: if resp.status != 200: return await ctx.send("Could not get image.") data = await resp.read() if not data.startswith(PNG_HEADER): return await ctx.send("Could not get image.") datastream = io.BytesIO(data) await channel.send( file=disnake.File(datastream, "latex.png")) except (asyncio.exceptions.TimeoutError, aiohttp.client_exceptions.ClientConnectorError): await channel.send("Website unreachable")