async def get_talents_image(abilities, hero_id): if isinstance(abilities, int): abilities = [ abilities ] if abilities is None: abilities = [] talent_slots = [] for ability_id in abilities: if ability_id not in ability_infos: continue ability = ability_infos[ability_id]["entity"] if not ability.is_talent: continue for talent in ability.talent_links: if talent.hero_id is None or talent.hero_id == hero_id: talent_slots.append(talent.slot) talent_slots = sorted(talent_slots, reverse=True) uri = f"talents_icon:{'_'.join(map(str, talent_slots))}" filename = httpgetter.cache.get_filename(uri) if filename and not settings.debug: return Image.open(filename) filename = await httpgetter.cache.new(uri, "png") image = Image.open(settings.resource("images/talents/talent_background.png")) for slot in talent_slots: slot_image = Image.open(settings.resource(f"images/talents/talent_{slot}.png")) image = paste_image(image, slot_image) image.save(filename, format="PNG") return image
def init_local_clipinfo(self): infofile = settings.resource("clips/clipinfo.json") if os.path.isfile(infofile): clipinfos = read_json(infofile) else: clipinfos = {} clipsdir = settings.resource("clips/") for root, dirs, files in os.walk(clipsdir): for file in files: match = re.search(f"clips[/\\\\]((?:.*[/\\\\])?([^/\\\\]+)\.(?:{audio_extensions}))", os.path.join(root, file)) if match: path = match.group(1) name = match.group(2) if name not in clipinfos: found = False for clipname in clipinfos: if clipinfos[clipname]["path"] == path: found = True break if not found: info = { "path": path } in_dir = re.search(f"(.+)[/\\\\](?:.+)\.(?:{audio_extensions})", path) if in_dir: info["tags"] = in_dir.group(1) clipinfos[name] = info write_json(infofile, clipinfos) return clipinfos
def __init__(self, bot): MangoCog.__init__(self, bot) self.reactions = read_json(settings.resource("json/reactions.json")) self.questions = read_json(settings.resource("json/questions.json")) self.subscripts = read_json(settings.resource("json/subscripts.json")) self.superscripts = read_json( settings.resource("json/superscripts.json"))
async def updateemoji(self, ctx): """Updates the emoji information for the bot""" emoji_json = read_json(settings.resource("json/emoji.json")) with ctx.channel.typing(): for emoji in ctx.guild.emojis: imgpath = settings.resource(f"images/emojis/{emoji.name}.png") with open(imgpath, 'wb+') as f: f.write((await httpgetter.get(emoji.url, return_type="bytes")).read()) emoji_json[emoji.name] = emoji.id write_json(settings.resource("json/emoji.json"), emoji_json) await ctx.send("done!")
def __init__(self, bot): MangoCog.__init__(self, bot) self.donation_link = "https://www.paypal.me/dillerm" self.reactions = read_json(settings.resource("json/reactions.json")) self.questions = read_json(settings.resource("json/questions.json")) self.subscripts = read_json(settings.resource("json/subscripts.json")) self.superscripts = read_json( settings.resource("json/superscripts.json")) self.showerthoughts_data = read_json( settings.resource("json/showerthoughts.json")) self.words = load_words()
def __init__(self, bot): MangoCog.__init__(self, bot) self.session = session self.criteria_aliases = read_json(settings.resource("json/criteria_aliases.json")) self.hero_stat_categories = read_json(settings.resource("json/hero_stats.json")) self.hero_aliases = {} self.item_aliases = {} self.leveled_hero_stats = [] # by level (0 is null, and 1-30 are filled in) self.hero_regex = "" self.build_helpers() self.vpkurl = "http://dotabase.dillerm.io/dota-vpk" drawdota.init_dota_info(self.get_hero_infos(), self.get_item_infos(), self.get_ability_infos(), self.vpkurl)
def __init__(self, bot): MangoCog.__init__(self, bot) self.session = session self.criteria_aliases = read_json( settings.resource("json/criteria_aliases.json")) self.item_colors = read_json( settings.resource("json/dota_item_colors.json")) self.hero_aliases = {} self.item_aliases = {} self.build_aliases() self.vpkurl = "http://dotabase.dillerm.io/dota-vpk" drawdota.init_dota_info(self.get_hero_infos(), self.get_item_infos())
async def addclip(self, ctx, url, clipname, start, end, start_fade=0.25, end_fade=0.25): """Adds a clip from youtube""" outfile = settings.resource(f"clips/{clipname}.mp3") start = get_time(start) end = get_time(end) duration = end - start matches = [ re.match(r"https?://(?:www\.)?youtube\.com/watch\?v=([^/]*)", url), re.match(r"https?://(?:www\.)?youtu\.be/([^/]*)", url), re.match(r"([^/]*)", url) ] youtube_id = None for match in matches: if match: youtube_id = match.group(1) break if youtube_id is None: raise UserError("This doesnt look like a youtube url or an id") video_file = settings.resource(f"cache/youtube/{youtube_id}.mp3") if not os.path.exists(video_file): await self.youtube_download(youtube_id, video_file) fadefilter = f"afade=t=in:ss=0:d={start_fade},afade=t=out:st={duration - end_fade}:d={end_fade}" # Converting / Cropping run_command([ "ffmpeg", "-ss", str(start), "-t", str(duration), "-y", "-i", video_file, "-af", fadefilter, outfile ]) audio = self.bot.get_cog("Audio") audio.local_clipinfo[clipname] = OrderedDict([ ('path', f"{clipname}.mp3"), ('source', f"https://www.youtube.com/watch?v={youtube_id}"), ('start', start), ('end', end) ]) audio.save_local_clipinfo() # Playing await self.play_clip(f"local:{clipname}", ctx)
async def updateemoji(self, ctx, name=None): """Updates the emoji information for the bot passing in a name will target that emoji specifically""" emoji_json = read_json(settings.resource("json/emoji.json")) with ctx.channel.typing(): for emoji in ctx.guild.emojis: if name is None or name == emoji.name: imgpath = settings.resource(f"images/emojis/{emoji.name}.png") with open(imgpath, 'wb+') as f: f.write((await httpgetter.get(str(emoji.url), return_type="bytes")).read()) emoji_json[emoji.name] = emoji.id write_json(settings.resource("json/emoji.json"), emoji_json) await ctx.send("done!")
async def dota_rank_icon(rank_tier, leaderboard_rank): if rank_tier is None: rank_tier = 0 uri = f"dota_rank:{rank_tier}_{leaderboard_rank}" print(uri) filename = httpgetter.cache.get_filename(uri) if filename and not settings.debug: return filename filename = await httpgetter.cache.new(uri, "png") badge_num = rank_tier // 10 stars_num = min(rank_tier % 10, 7) modifier = "" if leaderboard_rank and badge_num == 7: badge_num = 8 # this is to make consistant with what opendota shows if badge_num == 8 and leaderboard_rank: stars_num = 0 if leaderboard_rank <= 10: modifier = "c" elif leaderboard_rank <= 100: modifier = "b" image = Image.open( settings.resource(f"images/ranks/rank_{badge_num}{modifier}.png")) if stars_num > 0: stars_image = Image.open( settings.resource(f"images/ranks/stars_{stars_num}.png")) image = paste_image(image, stars_image, 0, 0) if leaderboard_rank: draw = ImageDraw.Draw(image) box_width = 256 box_height = 50 cell = TextCell(leaderboard_rank, color="#feffe5", font_size=50, horizontal_align="center") cell.render(draw, image, 0, 232 - box_height, box_width, box_height) image.save(filename, "png") return filename
async def do_tts(self, text, ctx): gtts_fixes = read_json(settings.resource("json/gtts_fixes.json")) text = text.replace("\n", " ") for key in gtts_fixes: text = re.sub("\\b({})\\b".format(key), gtts_fixes[key], text, re.IGNORECASE) await self.play_clip("tts:" + text, ctx)
def get_clipdirs(): result = [] for root, dirs, files in os.walk(settings.resource("clips/")): for d in dirs: result.append(d) result.sort() return result
async def dog(self, ctx): """Gets a picture of one of my dogs These are pictures of my (the developer of mangobyte) dogs. Thier names are Fizzgig and Comet. One is floof. Other is big doggo. Floof older. Both good boys. """ cat_dir = settings.resource("images/dog") imagepath = os.path.join(cat_dir, random.choice(os.listdir(cat_dir))) await ctx.send(file=discord.File(imagepath))
async def courage(self, ctx, *, hero=None): """Generates a challenge build Creates a challenge build with a random (or given) hero and a random set of items **Examples:** `{cmdpfx}courage` `{cmdpfx}courage shadow fiend`""" all_boots = [ "travel_boots", "phase_boots", "power_treads", "arcane_boots", "tranquil_boots", "guardian_greaves" ] all_items = read_json(settings.resource("json/courage_items.json")) random.shuffle(all_items) items = all_items[0:5] items.append(random.choice(all_boots)) random.shuffle(items) item_ids = [] for item in items: item_ids.append( session.query(Item).filter( Item.name == f"item_{item}").first().id) if hero: hero_id = self.lookup_hero_id(hero) if not hero_id: raise UserError(f"Couldn't a hero called '{hero}'") else: hero_id = session.query(Hero).order_by(func.random()).first().id image = discord.File(await drawdota.draw_courage(hero_id, item_ids), "courage.png") await ctx.send(file=image)
async def do_tts(self, text, ctx): gtts_fixes = read_json(settings.resource("json/gtts_fixes.json")) text = text.replace("\n", " ") for key in gtts_fixes: pattern = f"\\b({key})\\b" if not key.startswith("regex:") else re.sub("^regex:", "", key) text = re.sub(pattern, gtts_fixes[key], text, re.IGNORECASE) await self.play_clip("tts:" + text, ctx)
def init_local_clipinfo(self): infofile = settings.resource("clips/clipinfo.json") if not os.path.isfile(infofile): with open(infofile, 'w+') as f: f.write("{}") return {} return read_json(infofile)
async def cat(self, ctx): """Gets a picture of my cat These are pictures of my (the developer of mangobyte) cat. Shes a bit over a year old now. Her name is Minnie. Short for Minerva. Also known as "Kitten", "Sneakerdoodle", or "Noodle." Shes a good kitten. """ cat_dir = settings.resource("images/cat") imagepath = os.path.join(cat_dir, random.choice(os.listdir(cat_dir))) await ctx.send(file=discord.File(imagepath))
async def draw_matches_table(matches, game_strings): region_data = read_json(settings.resource("json/region_data.json")) border_size = 10 grey_color = "#BBBBBB" table = Table(background=background_color) # Header headers = [ TextCell("Hero", padding=0), TextCell(""), TextCell("Result"), TextCell("K", horizontal_align="center"), TextCell("D", horizontal_align="center"), TextCell("A", horizontal_align="center"), TextCell("Duration"), TextCell("Type"), TextCell("Date") ] table.add_row(headers) for cell in table.rows[0]: cell.background = trim_color table.add_row([ColorCell(color=trim_color, height=6) for i in range(len(headers))]) first = True for match in matches: won_match = bool(match["radiant_win"]) == bool(match["player_slot"] < 128) game_mode = game_strings[f"game_mode_{match['game_mode']}"] lobby_type = game_strings[f"lobby_type_{match['lobby_type']}"] if first: first = False else: table.add_row([ColorCell(color=background_color, height=12) for i in range(len(headers))]) table.add_row([ ImageCell(img=await get_hero_image(match["hero_id"]), height=48), DoubleCell( TextCell(get_hero_name(match["hero_id"]), font_size=24), TextCell(match.get("match_id"), font_size=12, horizontal_align="left", color=grey_color) ), TextCell("Win" if won_match else "Loss", color=("green" if won_match else "red"), horizontal_align="center"), TextCell(match.get("kills")), TextCell(match.get("deaths")), TextCell(match.get("assists")), TextCell(format_duration_simple(match.get("duration")), horizontal_align="center"), DoubleCell( TextCell(game_mode, font_size=18, padding_right=15, color=grey_color), TextCell(lobby_type, font_size=18, padding_right=15, color=grey_color) ), get_datetime_cell(match, region_data) ]) image = table.render() border_image = Image.new('RGBA', (image.size[0] + (border_size * 2), image.size[1] + border_size), color=trim_color) image = paste_image(border_image, image, border_size, 0) fp = BytesIO() image.save(fp, format="PNG") fp.seek(0) return fp
def get_playlist(clipdir): clips = [] for root, dirs, files in os.walk(settings.resource("clips/" + clipdir)): for file in files: if file.endswith(".mp3") or file.endswith(".wav"): clips.append(file[:-4]) clips.sort() return clips
async def clips(self, ctx, tag : str=None): """Lists the local audio clips available for the play command Calling this command with no arguments gets you a list of all of the clips To get the clips that have a specific tag, do `{cmdpfx}clips <tag>` To get a list of all of the possible clip tags, try `{cmdpfx}clips tags` You can also do `{cmdpfx}clips new` to get the 10 newest clips""" message = "" clips = [] sort = True if tag is None: message += "\n**Clips:**\n" for clipname in self.local_clipinfo: clips.append(clipname) elif tag in [ "recent", "latest", "new" ]: clips = {} for clipname in self.local_clipinfo: clips[clipname] = os.path.getctime(settings.resource(f"clips/{self.local_clipinfo[clipname]['path']}")) clips = list(map(lambda x: x[0], sorted(clips.items(), key=lambda x: x[1], reverse=True))) clips = clips[:10] sort = False elif tag in [ "tags", "sections" ]: message += "\n**Tags:**\n" for clipname in self.local_clipinfo: tags = self.local_clipinfo[clipname].get("tags") if tags: tags = tags.split("|") for t in tags: if t not in clips: clips.append(t) else: for clipname in self.local_clipinfo: info = self.local_clipinfo[clipname] tags = info.get("tags") if tags: tags = tags.split("|") if tag in tags: clips.append(clipname) continue if len(tag) > 3 and tag.lower() in info.get("author", "").lower(): clips.append(clipname) if not clips: raise UserError("No clips not found for that tag") if len(clips) > 0: if sort: clips.sort() clip_format = "`{}` " if len(clips) <= 10: clip_format = "`{}`\n" for clip in clips: message += clip_format.format(clip) await ctx.send(message)
def load_words(): words = {} for root, dirs, files in os.walk(settings.resource("words/")): for file in files: with open(os.path.join(root, file), 'r') as f: text = f.read() key, ext = os.path.splitext(file) words[key] = text.split("\n") return words
def __init__(self, steam_id): super().__init__(f"") self.embed = discord.Embed( description= f"It looks like you either haven't played dota on this account, or the matches you've played are hidden. If you've played matches on this account, you should try enabling the **Expose Public Match Data** option in dota (see image below). Once you've done that, go to [your opendota profile](http://www.opendota.com/players/{steam_id}) and click the button under your name that says **REFRESH**" ) self.file = discord.File( settings.resource("images/expose_match_data.png"), "tip.png") self.embed.set_image(url=f"attachment://{self.file.filename}")
def __init__(self, text, bot, ctx): tempfile = settings.resource("temp/{}.wav".format( int(random.random() * 1000000000))) data = botdata.guildinfo(ctx) if data: tts_save(tempfile, text, data.ttslang) else: tts_save(tempfile, text) Clip.__init__(self, text, tempfile, text)
async def restget(self, ctx, url): """Gets a json response from a rest api and returns it""" await ctx.channel.trigger_typing() data = await httpgetter.get(url) filename = settings.resource("temp/response.json") write_json(filename, data) await ctx.send(file=discord.File(filename)) os.remove(filename)
def __init__(self, bot): MangoCog.__init__(self, bot) self.embed_color = discord.Color.teal() dotabase = self.bot.get_cog("Dotabase") if not dotabase: raise ImportError("The Dotabase cog must be added before the DotaStats cog") self.dota_game_strings = read_json(settings.resource("json/dota_game_strings.json")) self.hero_info = dotabase.get_hero_infos() self.lookup_hero = dotabase.lookup_hero self.chat_wheel_info = dotabase.get_chat_wheel_infos()
def __init__(self, loop): self.loop = loop self.cache_dir = settings.resource("cache/") self.index_file = self.cache_dir + "cache_index.json" self.cache = {} self.lock = asyncio.Lock(loop=self.loop) if os.path.isfile(self.index_file): self.cache = read_json(self.index_file) for key in default_cache: if key not in self.cache: self.cache[key] = default_cache[key] self.save_cache()
async def editclipinfo(self, ctx, clipname, attribute, *, value): """Allows editing of a clip's info warning: volume actually edits the clip, and is a multiplier (0.5 cuts in half, 2 doubles) Example: `{cmdpfx}editclipinfo wow text Waow!`""" audio = self.bot.get_cog("Audio") if clipname not in audio.local_clipinfo: raise UserError("That clip doesn't exist") attribs = ["text", "author", "source", "start", "end"] if value is None or value == "": raise UserError("Gotta gimme a value") if attribute == "volume": filename = settings.resource( "clips/" + audio.local_clipinfo[clipname]["path"]) temp_file = settings.resource(f"temp/temp_{clipname}" + os.path.splitext(filename)[1]) run_command([ "ffmpeg", "-i", filename, "-af", f"volume={value}", temp_file ]) shutil.copyfile(temp_file, filename) os.remove(temp_file) await self.play_clip(f"local:{clipname}", ctx) await ctx.message.add_reaction("✅") return if attribute not in attribs: attribs_string = "\n".join(attribs) raise UserError( f"Invalid attribute name, try one of these:```\n{attribs_string}\n```" ) audio.local_clipinfo[clipname][attribute] = value audio.save_local_clipinfo() await ctx.message.add_reaction("✅")
def draw_poly_label(draw, point, center, text): font = ImageFont.truetype(settings.resource("images/arial_unicode_bold.ttf"), 16) font_size = font.getsize(text) point = list(point) if point[0] < center[0]: point[0] -= font_size[0] if point[1] < center[1]: point[1] -= font_size[1] if point[0] == center[0]: point[0] -= font_size[0] / 2 if point[1] == center[1]: point[1] -= font_size[1] / 2 draw.text(tuple(point), text, font=font, fill="#ffffff")
def get_cache_game_mode_patterns(): global game_mode_patterns if not game_mode_patterns: patterns = OrderedDict() dota_strings = read_json(settings.resource("json/dota_game_strings.json")) for key in dota_strings: prefix = "game_mode_" if prefix not in key: continue mode_id = int(key.replace(prefix, "")) name = dota_strings[key] pattern = name.lower() patterns[pattern] = mode_id game_mode_patterns = patterns return game_mode_patterns
async def draw_hero_talents(hero): talents = hero.talents.split("|") talent_rows = [[talents[7], talents[6]], [talents[5], talents[4]], [talents[3], talents[2]], [talents[1], talents[0]]] image = Image.open(settings.resource("images/talents.png")) draw = ImageDraw.Draw(image) header_x = 19 header_y = 17 header_width = 655 header_height = 51 cell = TextCell(hero.localized_name, color="#dddddd", font_size=28, horizontal_align="center") cell.render(draw, image, header_x, header_y, header_width, header_height) box_width = 306 box_height = 73 box_margin_y = 14 start_y = 70 start_x_left = 14 start_x_right = 370 start_x = [start_x_left, start_x_right] for i in range(0, 4): for j in range(0, 2): x = start_x[j] y = start_y + (i * (box_height + box_margin_y)) text = talent_rows[i][j] cell = TextCell(text, color="#cca770", font_size=20, wrap=True, padding=[0, 15, 0, 15], horizontal_align="center") cell.render(draw, image, x, y, box_width, box_height) fp = BytesIO() image.save(fp, format="PNG") fp.seek(0) return fp