async def gridify(self, ctx, *args): faction = None color = 0x808080 iter_args = iter(args) name = next(iter_args, None) while name in ["-f", "-c"]: if name == "-f": fac = next(iter_args, None) if fac is None: await ctx.send(ctx.s("error.missing_arg_faction")) return f = sql.guild_get_by_faction_name_or_alias(fac) if not faction: await ctx.send(ctx.s("error.faction_not_found")) return if name == "-c": try: color = abs(int(next(iter_args, None), 16) % 0xFFFFFF) name = next(iter_args, None) except ValueError: await ctx.send(ctx.s("error.invalid_color")) return def parse_zoom(z): try: if type(z) is int: return z if type(z) is str: if z.startswith("#"): z = z[1:] return int(z) if z is None: return 8 except ValueError: return 8 t = sql.template_get_by_name( faction.id, name) if faction else sql.template_get_by_name( ctx.guild.id, name) if t: log.info("(T:{} | GID:{})".format(t.name, t.gid)) data = await http.get_template(t.url, t.name) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(parse_zoom(next(iter_args, 1)), max_zoom)) template = await render.gridify(data, color, zoom) else: att = await utils.verify_attachment(ctx) data = io.BytesIO() await att.save(data) max_zoom = int(math.sqrt(4000000 // (att.width * att.height))) zoom = max(1, min(parse_zoom(name), max_zoom)) template = await render.gridify(data, color, zoom) with io.BytesIO() as bio: template.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "gridded.png") await ctx.send(file=f)
async def gridify(self, ctx, *args): log.info(f"g!gridify run in {ctx.guild.name} with args: {args}") # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-f", "--faction", default=None, action=FactionAction) parser.add_argument("-c", "--color", default=0x808080, action=ColorAction) parser.add_argument("-z", "--zoom", type=int, default=1) # Pre-Parsing if len(args) == 0: name = None a = args elif args[0][0] != "-": name = args[0] a = args[1:] else: name = None a = args try: a = vars(parser.parse_args(a)) except TypeError: return faction = a["faction"] color = a["color"] zoom = a["zoom"] gid = ctx.guild.id if not faction else faction.id t = sql.template_get_by_name(gid, name) if name: if t: log.info("(T:{} | GID:{})".format(t.name, t.gid)) data = await http.get_template(t.url, t.name) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(zoom, max_zoom)) template = await render.gridify(data, color, zoom) else: raise TemplateNotFoundError(gid, name) else: att = await verify_attachment(ctx) data = io.BytesIO() await att.save(data) max_zoom = int(math.sqrt(4000000 // (att.width * att.height))) zoom = max(1, min(zoom, max_zoom)) template = await render.gridify(data, color, zoom) with io.BytesIO() as bio: template.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "gridded.png") await ctx.send(file=f)
async def _quantize(ctx, args, canvas, palette): gid = ctx.guild.id iter_args = iter(args) name = next(iter_args, None) if name == "-f": faction = sql.guild_get_by_faction_name_or_alias(next(iter_args, None)) if not faction: raise errors.FactionNotFound gid = faction.id name = next(iter_args, None) t = sql.template_get_by_name(gid, name) data = None if t: log.debug("(T:{} | GID:{})".format(t.name, t.gid)) if t.canvas == canvas: raise errors.IdempotentActionError data = await http.get_template(t.url) else: att = await utils.verify_attachment(ctx) if att: data = io.BytesIO() await att.save(data) if data: template, bad_pixels = await render.quantize(data, palette) with io.BytesIO() as bio: template.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "template.png") return await ctx.send(ctx.s("canvas.quantize").format(bad_pixels), file=f)
async def template_snapshot_add(self, ctx, base_template, snapshot_template): if not utils.is_template_admin(ctx) and not utils.is_admin(ctx): await ctx.send(ctx.s("template.err.not_owner")) return base = sql.template_get_by_name(ctx.guild.id, base_template) target = sql.template_get_by_name(ctx.guild.id, snapshot_template) if base == None: await ctx.send("The base template does not exist.") return if target == None: await ctx.send("The snapshot template does not exist.") return sql.snapshot_add(ctx.guild.id, base_template, snapshot_template) await ctx.send("Snapshot added!")
async def check_for_duplicate_by_name(ctx, template): dup = sql.template_get_by_name(ctx.guild.id, template.name) if dup: if template.owner_id != ctx.author.id and not utils.is_admin(ctx): await ctx.send(ctx.s("template.err.name_exists")) return False print(dup.x) q = ctx.s("template.name_exists_ask_replace") \ .format(dup.name, canvases.pretty_print[dup.canvas], dup.x, dup.y) return await utils.yes_no(ctx, q)
async def template_remove(self, ctx, name): t = sql.template_get_by_name(ctx.guild.id, name) if not t: raise TemplateNotFoundError log.info("(T:{})".format(t.name, t.gid)) if t.owner_id != ctx.author.id and not utils.is_template_admin( ctx) and not utils.is_admin(ctx): await ctx.send(ctx.s("template.err.not_owner")) return sql.template_delete(t.gid, t.name) await ctx.send(ctx.s("template.remove").format(name))
async def check_for_duplicate_by_name(ctx, template): """Checks for duplicates by name, will bypass and signal to overwrite if told to. Arguments: ctx - commands.Context. template - A template object. Returns: A boolean or nothing. """ dup = sql.template_get_by_name(ctx.guild.id, template.name) if dup: if template.owner_id != ctx.author.id and not utils.is_admin(ctx): await ctx.send(ctx.s("template.err.name_exists")) return False q = ctx.s("template.name_exists_ask_replace") \ .format(dup.name, canvases.pretty_print[dup.canvas], dup.x, dup.y) yesnomenu = await utils.yes_no(ctx, q) if yesnomenu == True: return True else: await ctx.send(ctx.s("template.menuclose")) return False
async def template_info(self, ctx, *args): gid = ctx.guild.id iter_args = iter(args) name = next(iter_args, 1) image_only = False if name == "-r": image_only = True name = next(iter_args, 1) if name == "-f": fac = next(iter_args, None) if fac is None: await ctx.send(ctx.s("error.missing_arg_faction")) return faction = sql.guild_get_by_faction_name_or_alias(fac) if not faction: raise FactionNotFoundError gid = faction.id name = next(iter_args, 1) else: faction = sql.guild_get_by_id(gid) t = sql.template_get_by_name(gid, name) if not t: raise TemplateNotFoundError if image_only: zoom = next(iter_args, 1) try: if type(zoom) is not int: if zoom.startswith("#"): zoom = zoom[1:] zoom = int(zoom) except ValueError: zoom = 1 max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(zoom, max_zoom)) img = render.zoom(await http.get_template(t.url, t.name), zoom) with io.BytesIO() as bio: img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, t.name + ".png") await ctx.send(file=f) return canvas_name = canvases.pretty_print[t.canvas] coords = "({}, {})".format(t.x, t.y) dimensions = "{} x {}".format(t.width, t.height) size = t.size visibility = ctx.s("bot.private") if bool( t.private) else ctx.s("bot.public") owner = self.bot.get_user(t.owner_id) if owner is None: added_by = ctx.s("error.account_deleted") else: added_by = owner.name + "#" + owner.discriminator date_added = datetime.date.fromtimestamp( t.date_created).strftime("%d %b, %Y") date_modified = datetime.date.fromtimestamp( t.date_updated).strftime("%d %b, %Y") color = faction.faction_color description = "[__{}__]({})".format( ctx.s("template.link_to_canvas"), canvases.url_templates[t.canvas].format(*t.center())) if size == 0: t.size = await render.calculate_size(await http.get_template( t.url, t.name)) sql.template_update(t) e = discord.Embed(title=t.name, color=color, description=description) \ .set_image(url=t.url) \ .add_field(name=ctx.s("bot.canvas"), value=canvas_name, inline=True) \ .add_field(name=ctx.s("bot.coordinates"), value=coords, inline=True) \ .add_field(name=ctx.s("bot.dimensions"), value=dimensions, inline=True) \ .add_field(name=ctx.s("bot.size"), value=size, inline=True) \ .add_field(name=ctx.s("bot.visibility"), value=visibility, inline=True) \ .add_field(name=ctx.s("bot.added_by"), value=added_by, inline=True) \ .add_field(name=ctx.s("bot.date_added"), value=date_added, inline=True) \ .add_field(name=ctx.s("bot.date_modified"), value=date_modified, inline=True) if faction.id != ctx.guild.id and faction.faction_name: e = e.set_author(name=faction.faction_name, icon_url=faction.faction_emblem or discord.Embed.Empty) await ctx.send(embed=e)
async def diff(self, ctx, *args): if len(args) < 1: return list_pixels = False iter_args = iter(args) a = next(iter_args, None) if a == "-e": list_pixels = True a = next(iter_args, None) if a == "-f": fac = next(iter_args, None) if fac is None: await ctx.send(ctx.s("error.missing_arg_faction")) return f = sql.guild_get_by_faction_name_or_alias(fac) if not f: await ctx.send(ctx.s("error.faction_not_found")) return name = next(iter_args, None) zoom = next(iter_args, 1) t = sql.template_get_by_name(f.id, name) else: name = a zoom = next(iter_args, 1) t = sql.template_get_by_name(ctx.guild.id, name) try: if type(zoom) is not int: if zoom.startswith("#"): zoom = zoom[1:] zoom = int(zoom) except ValueError: zoom = 1 if t: async with ctx.typing(): log.info("(T:{} | GID:{})".format(t.name, t.gid)) data = await http.get_template(t.url, t.name) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(zoom, max_zoom)) fetchers = { 'pixelcanvas': render.fetch_pixelcanvas, 'pixelzone': render.fetch_pixelzone, 'pxlsspace': render.fetch_pxlsspace } diff_img, tot, err, bad, err_list \ = await render.diff(t.x, t.y, data, zoom, fetchers[t.canvas], colors.by_name[t.canvas]) done = tot - err perc = done / tot if perc < 0.00005 and done > 0: perc = ">0.00%" elif perc >= 0.99995 and err > 0: perc = "<100.00%" else: perc = "{:.2f}%".format(perc * 100) out = ctx.s("canvas.diff") if bad == 0 else ctx.s( "canvas.diff_bad_color") out = out.format(done, tot, err, perc, bad=bad) with io.BytesIO() as bio: diff_img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "diff.png") await ctx.send(content=out, file=f) if list_pixels and len(err_list) > 0: out = ["```xl"] for p in err_list: x, y, current, target = p current = ctx.s("color.{}.{}".format( t.canvas, current)) target = ctx.s("color.{}.{}".format(t.canvas, target)) out.append("({}, {}) is {}, should be {}".format( x + t.x, y + t.y, current, target)) if err > 15: out.append("...") out.append("```") await ctx.send('\n'.join(out)) return await ctx.invoke_default("diff")
async def preview(self, ctx, *args): if len(args) < 1: return preview_template_region = False iter_args = iter(args) a = next(iter_args, None) if a == "-t": preview_template_region = True a = next(iter_args, None) if a == "-f": fac = next(iter_args, None) if fac is None: await ctx.send(ctx.s("error.missing_arg_faction")) return f = sql.guild_get_by_faction_name_or_alias(fac) if not f: await ctx.send(ctx.s("error.faction_not_found")) return name = next(iter_args, None) zoom = next(iter_args, 1) t = sql.template_get_by_name(f.id, name) else: name = a zoom = next(iter_args, 1) t = sql.template_get_by_name(ctx.guild.id, name) try: if type(zoom) is not int: if zoom.startswith("#"): zoom = zoom[1:] zoom = int(zoom) except ValueError: zoom = 1 if t: async with ctx.typing(): log.info("(T:{} | GID:{})".format(t.name, t.gid)) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(-8, min(zoom, max_zoom)) fetchers = { 'pixelcanvas': render.fetch_pixelcanvas, 'pixelzone': render.fetch_pixelzone, 'pxlsspace': render.fetch_pxlsspace } if preview_template_region: preview_img = await render.preview(*t.center(), zoom, fetchers[t.canvas]) else: preview_img = await render.preview_template( t, zoom, fetchers[t.canvas]) with io.BytesIO() as bio: preview_img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "preview.png") await ctx.send(file=f) return await ctx.invoke_default("preview")
async def template_info(self, ctx, *args): # Order Parsing try: name = args[0] except TypeError: await ctx.send("Error: no arguments were provided.") return if re.match("-\D+", name) != None: name = args[-1] args = args[:-1] else: args = args[1:] # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-r", "--raw", action="store_true") parser.add_argument("-f", "--faction", default=None, action=FactionAction) parser.add_argument("-z", "--zoom", default=1) try: args = vars(parser.parse_args(args)) except TypeError: return image_only = args["raw"] f = args["faction"] try: gid, faction = f.id, f except AttributeError: gid, faction = ctx.guild.id, sql.guild_get_by_id(ctx.guild.id) zoom = args["zoom"] t = sql.template_get_by_name(gid, name) if not t: raise TemplateNotFoundError(gid, name) if image_only: try: if type(zoom) is not int: if zoom.startswith("#"): zoom = zoom[1:] zoom = int(zoom) except ValueError: zoom = 1 max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(zoom, max_zoom)) img = render.zoom(await http.get_template(t.url, t.name), zoom) with io.BytesIO() as bio: img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, t.name + ".png") await ctx.send(file=f) return canvas_name = canvases.pretty_print[t.canvas] coords = "{}, {}".format(t.x, t.y) dimensions = "{} x {}".format(t.width, t.height) size = t.size visibility = ctx.s("bot.private") if bool( t.private) else ctx.s("bot.public") owner = self.bot.get_user(t.owner_id) if owner is None: added_by = ctx.s("error.account_deleted") else: added_by = owner.name + "#" + owner.discriminator date_added = datetime.date.fromtimestamp( t.date_created).strftime("%d %b, %Y") date_modified = datetime.date.fromtimestamp( t.date_updated).strftime("%d %b, %Y") color = faction.faction_color description = "[__{}__]({})".format( ctx.s("template.link_to_canvas"), canvases.url_templates[t.canvas].format(*t.center())) if size == 0: t.size = await render.calculate_size(await http.get_template( t.url, t.name)) sql.template_update(t) e = discord.Embed(title=t.name, color=color, description=description) \ .set_image(url=t.url) \ .add_field(name=ctx.s("bot.canvas"), value=canvas_name, inline=True) \ .add_field(name=ctx.s("bot.coordinates"), value=coords, inline=True) \ .add_field(name=ctx.s("bot.dimensions"), value=dimensions, inline=True) \ .add_field(name=ctx.s("bot.size"), value=size, inline=True) \ .add_field(name=ctx.s("bot.visibility"), value=visibility, inline=True) \ .add_field(name=ctx.s("bot.added_by"), value=added_by, inline=True) \ .add_field(name=ctx.s("bot.date_added"), value=date_added, inline=True) \ .add_field(name=ctx.s("bot.date_modified"), value=date_modified, inline=True) if faction.id != ctx.guild.id and faction.faction_name: e = e.set_author(name=faction.faction_name, icon_url=faction.faction_emblem or discord.Embed.Empty) await ctx.send(embed=e)
async def template_update_pixelcanvas(self, ctx, *args): log.info(f"g!t update run in {ctx.guild.name} with args: {args}") try: name = args[0] except TypeError: await ctx.send( "Template not updated as no arguments were provided.") return if re.match("-\D+", name) != None: name = args[-1] args = args[:-1] else: args = args[1:] orig_template = sql.template_get_by_name(ctx.guild.id, name) if not orig_template: raise TemplateNotFoundError(ctx.guild.id, name) # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-n", "--newName", nargs="?", default=None) parser.add_argument("-x", nargs="?", default=None) parser.add_argument("-y", nargs="?", default=None) # if -i not present, False # if no value after -i, True # if value after -i, capture parser.add_argument("-i", "--image", nargs="?", const=True, default=None) try: args = vars(parser.parse_args(args)) except TypeError: return new_name = args["newName"] x = args["x"] y = args["y"] image = args["image"] out = [] """Image is done first since I'm using the build_template method to update stuff, and I don't want anything to have changed in orig_template before I use it""" if image: # Update image url = None if not isinstance(image, bool): url = image url = await Template.select_url_update(ctx, url, out) if url is None: return # Sending the end is handled in select_url_update if it fails try: t = await Template.build_template(ctx, orig_template.name, orig_template.x, orig_template.y, url, "pixelcanvas") except TemplateHttpError: out.append( f"Updating file failed: Could not access URL for template." ) await Template.send_end(ctx, out) return except NoJpegsError: out.append( f"Updating file failed: Seriously? A JPEG? Gross! Please create a PNG template instead." ) await Template.send_end(ctx, out) return except NotPngError: out.append( f"Updating file failed: That command requires a PNG image." ) await Template.send_end(ctx, out) return except (PilImageError, UrlError): out.append(f"Updating file failed.") await Template.send_end(ctx, out) return if t is None: out.append(f"Updating file failed.") await Template.send_end(ctx, out) return # Could check for md5 duplicates here, maybe implement that later sql.template_kwarg_update(ctx.guild.id, orig_template.name, url=t.url, md5=t.md5, w=t.width, h=t.height, size=t.size, date_modified=int(time.time())) out.append(f"File updated.") if x: # Update x coord try: x = int(re.sub('[^0-9-]', '', x)) except ValueError: out.append( "Updating x failed, value provided was not a number.") await Template.send_end(ctx, out) return sql.template_kwarg_update(ctx.guild.id, orig_template.name, x=x, date_modified=int(time.time())) out.append(f"X coordinate changed from {orig_template.x} to {x}.") if y: # Update y coord try: y = int(re.sub('[^0-9-]', '', y)) except ValueError: out.append( "Updating y failed, value provided was not a number.") await Template.send_end(ctx, out) return sql.template_kwarg_update(ctx.guild.id, orig_template.name, y=y, date_modified=int(time.time())) out.append(f"Y coordinate changed from {orig_template.y} to {y}.") if new_name: # Check if new name is already in use dup_check = sql.template_get_by_name(ctx.guild.id, new_name) if dup_check != None: out.append( f"Updating name failed, the name {new_name} is already in use." ) await Template.send_end(ctx, out) return # Check if new name is too long if len(new_name) > config.MAX_TEMPLATE_NAME_LENGTH: out.append("Updating name failed: " + ctx.s("template.err.name_too_long").format( config.MAX_TEMPLATE_NAME_LENGTH)) await Template.send_end(ctx, out) return # Check if new name begins with a '-' if new_name[0] == "-": out.append( "Updating name failed: Names cannot begin with hyphens.") await Template.send_end(ctx, out) return # Make sure the name isn't a number try: c = int(new_name) out.append("Updating name failed: Names cannot be numbers.") await Template.send_end(ctx, out) return except ValueError: pass # None with new nick, update template sql.template_kwarg_update(ctx.guild.id, orig_template.name, new_name=new_name, date_modified=int(time.time())) out.append(f"Nickname changed from {name} to {new_name}.") await Template.send_end(ctx, out)
async def _quantize(ctx, args, canvas, palette): """Sends a message containing a quantised version of the image given. Arguments: ctx - A commands.Context object. args - A list of arguments from the user, all strings. canvas - The canvas to use, string. palette - The palette to quantise to, a list of rgb tuples. Returns: The discord.Message object returned when ctx.send() is called to send the quantised image. """ # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-f", "--faction", default=None, action=FactionAction) parser.add_argument("-z", "--zoom", type=int, default=1) # Pre-Parsing if len(args) == 0: name = None elif args[0][0] != "-": name = args[0] args = args[1:] else: name = None try: args = vars(parser.parse_args(args)) except TypeError: return faction = args["faction"] zoom = args["zoom"] gid = ctx.guild.id if not faction else faction.id t = sql.template_get_by_name(gid, name) data = None if name: if t: log.info("(T:{} | GID:{})".format(t.name, t.gid)) if t.canvas == canvas: raise IdempotentActionError data = await http.get_template(t.url, t.name) else: raise TemplateNotFoundError(gid, name) else: att = await verify_attachment(ctx) if att: data = io.BytesIO() await att.save(data) if data: template, bad_pixels = await render.quantize(data, palette) with io.BytesIO() as bio: template.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "template.png") return await ctx.send(ctx.s("canvas.quantize").format(bad_pixels), file=f)
async def diff(self, ctx, *args): log.info(f"g!diff run in {ctx.guild.name} with args: {args}") # Order Parsing try: name = args[0] except TypeError: await ctx.send("Error: no arguments were provided.") return if re.match("-\D+", name) != None: name = args[-1] args = args[:-1] else: args = args[1:] if re.match("-{0,1}\d+", name) != None: # Skip to coords + image parsing await ctx.invoke_default("diff") return # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-e", "--errors", action='store_true') parser.add_argument("-s", "--snapshot", action='store_true') parser.add_argument("-f", "--faction", default=None, action=FactionAction) parser.add_argument("-z", "--zoom", type=int, default=1) parser.add_argument("-t", "--excludeTarget", action='store_true') colorFilters = parser.add_mutually_exclusive_group() colorFilters.add_argument("-ec", "--excludeColors", nargs="+", type=int, default=None) colorFilters.add_argument("-oc", "--onlyColors", nargs="+", type=int, default=None) try: a = vars(parser.parse_args(args)) except TypeError: return list_pixels = a["errors"] create_snapshot = a["snapshot"] faction = a["faction"] zoom = a["zoom"] exclude_target = a["excludeTarget"] exclude_colors = a["excludeColors"] only_colors = a["onlyColors"] gid = ctx.guild.id if not faction else faction.id t = sql.template_get_by_name(gid, name) if t: async with ctx.typing(): log.info("(T:{} | GID:{})".format(t.name, t.gid)) data = await http.get_template(t.url, t.name) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(1, min(zoom, max_zoom)) fetchers = { 'pixelcanvas': render.fetch_pixelcanvas, 'pixelzone': render.fetch_pixelzone, 'pxlsspace': render.fetch_pxlsspace } diff_img, tot, err, bad, err_list \ = await render.diff(t.x, t.y, data, zoom, fetchers[t.canvas], colors.by_name[t.canvas], create_snapshot) done = tot - err perc = done / tot if perc < 0.00005 and done > 0: perc = ">0.00%" elif perc >= 0.99995 and err > 0: perc = "<100.00%" else: perc = "{:.2f}%".format(perc * 100) out = ctx.s("canvas.diff") if bad == 0 else ctx.s( "canvas.diff_bad_color") out = out.format(done, tot, err, perc, bad=bad) with io.BytesIO() as bio: diff_img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "diff.png") await ctx.send(content=out, file=f) if list_pixels and len(err_list) > 0: error_list = [] for x, y, current, target in err_list: # Color Filtering c = current if not exclude_target else target if exclude_colors: if c in exclude_colors: continue elif only_colors: if not c in only_colors: continue # The current x,y are in terms of the template area, add to template start coords so they're in terms of canvas x += t.x y += t.y error_list.append(Pixel(current, target, x, y)) checker = Checker(self.bot, ctx, t.canvas, error_list) checker.connect_websocket() else: # No template found raise TemplateNotFoundError(gid, name)
async def preview(self, ctx, *args): log.info(f"g!preview run in {ctx.guild.name} with args: {args}") # Order Parsing try: name = args[0] except TypeError: await ctx.send("Error: no arguments were provided.") return if re.match("-\D+", name) != None: name = args[-1] args = args[:-1] else: args = args[1:] if re.match("-{0,1}\d+", name) != None: # Skip to coords + image parsing await ctx.invoke_default("preview") return # Argument Parsing parser = GlimmerArgumentParser(ctx) parser.add_argument("-t", "--templateRegion", action='store_true') parser.add_argument("-f", "--faction", default=None, action=FactionAction) parser.add_argument("-z", "--zoom", type=int, default=1) try: a = vars(parser.parse_args(args)) except TypeError: return preview_template_region = a["templateRegion"] faction = a["faction"] zoom = a["zoom"] gid = ctx.guild.id if not faction else faction.id t = sql.template_get_by_name(gid, name) if t: async with ctx.typing(): log.info("(T:{} | GID:{})".format(t.name, t.gid)) max_zoom = int(math.sqrt(4000000 // (t.width * t.height))) zoom = max(-8, min(zoom, max_zoom)) fetchers = { 'pixelcanvas': render.fetch_pixelcanvas, 'pixelzone': render.fetch_pixelzone, 'pxlsspace': render.fetch_pxlsspace } if preview_template_region: preview_img = await render.preview(*t.center(), zoom, fetchers[t.canvas]) else: preview_img = await render.preview_template( t, zoom, fetchers[t.canvas]) with io.BytesIO() as bio: preview_img.save(bio, format="PNG") bio.seek(0) f = discord.File(bio, "preview.png") await ctx.send(file=f) return # No template found raise TemplateNotFoundError(gid, name)