From 758cb4ca1cc71b5dcac3acdd17d5e44edf8ca977 Mon Sep 17 00:00:00 2001 From: qwewqa <198e559dbd446d973355f415bdfa34@gmail.com> Date: Fri, 15 Jan 2021 13:11:46 -0500 Subject: [PATCH] add asset export script and change online asset structure --- .gitignore | 3 +- export_assets.py | 54 +++++++++++++++++++ miyu_bot/commands/cogs/music.py | 12 +++-- .../commands/common/master_asset_manager.py | 48 +++++++++++------ 4 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 export_assets.py diff --git a/.gitignore b/.gitignore index 0dff943..6f26507 100644 --- a/.gitignore +++ b/.gitignore @@ -248,4 +248,5 @@ dmypy.json # End of https://www.toptal.com/developers/gitignore/api/pycharm,python config.json -assets/ \ No newline at end of file +assets/ +export/ \ No newline at end of file diff --git a/export_assets.py b/export_assets.py new file mode 100644 index 0000000..3244642 --- /dev/null +++ b/export_assets.py @@ -0,0 +1,54 @@ +import hashlib +import shutil +from pathlib import Path + +from d4dj_utils.manager.asset_manager import AssetManager +from d4dj_utils.master.master_asset import MasterAsset + +from miyu_bot.commands.common.master_asset_manager import MasterFilterManager, hash_master + + +def main(): + target_dir = Path('./export') + target_dir.mkdir(parents=True, exist_ok=True) + + asset_manager = AssetManager('assets') + + music_dir = target_dir / 'music' + chart_dir = music_dir / 'charts' + card_dir = target_dir / 'cards' + card_icon_dir = card_dir / 'icons' + card_art_dir = card_dir / 'art' + + music_dir.mkdir(exist_ok=True) + chart_dir.mkdir(exist_ok=True) + card_dir.mkdir(exist_ok=True) + card_icon_dir.mkdir(exist_ok=True) + card_art_dir.mkdir(exist_ok=True) + + for music in asset_manager.music_master.values(): + for chart in music.charts.values(): + try: + chart_hash = hash_master(chart) + chart_path = chart.image_path + target_path = chart_dir / f'{chart_path.stem}_{chart_hash}{chart_path.suffix}' + shutil.copy(chart_path, target_path) + except FileNotFoundError: + pass + + for card in asset_manager.card_master.values(): + card_hash = hash_master(card) + try: + for lb in range(2): + art_path = card.art_path(lb) + art_target = card_art_dir / f'{art_path.stem}_{card_hash}{art_path.suffix}' + icon_path = card.icon_path(lb) + icon_target = card_icon_dir / f'{icon_path.stem}_{card_hash}{icon_path.suffix}' + shutil.copy(art_path, art_target) + shutil.copy(icon_path, icon_target) + except FileNotFoundError: + pass + + +if __name__ == '__main__': + main() diff --git a/miyu_bot/commands/cogs/music.py b/miyu_bot/commands/cogs/music.py index 2711355..7553ba4 100644 --- a/miyu_bot/commands/cogs/music.py +++ b/miyu_bot/commands/cogs/music.py @@ -17,6 +17,7 @@ from miyu_bot.commands.common.argument_parsing import parse_arguments, ArgumentE from miyu_bot.commands.common.emoji import difficulty_emoji_ids from miyu_bot.commands.common.formatting import format_info from miyu_bot.commands.common.fuzzy_matching import romanize +from miyu_bot.commands.common.master_asset_manager import hash_master from miyu_bot.commands.common.reaction_message import run_tabbed_message, run_paged_message @@ -166,7 +167,8 @@ class Music(commands.Cog): def difficulty_converter(d): return int(d[:-1]) + 0.5 if d[-1] == '+' else int(d) - difficulty = arguments.repeatable(['difficulty', 'diff', 'level'], is_list=True, converter=difficulty_converter) + difficulty = arguments.repeatable(['difficulty', 'diff', 'level'], is_list=True, + converter=difficulty_converter) arguments.require_all_arguments_used() except ArgumentError as e: await ctx.send(str(e)) @@ -201,17 +203,19 @@ class Music(commands.Cog): try: thumb = discord.File(song.jacket_path, filename='jacket.png') except FileNotFoundError: - # dig delight is just a fallback - thumb = discord.File(masters.music.get('110001', None).jacket_path, filename='jacket.png') + # fallback + thumb = discord.File(asset_manager.path / 'ondemand/stamp/stamp_10006.png', filename='jacket.png') files = [thumb] for difficulty in [ChartDifficulty.Easy, ChartDifficulty.Normal, ChartDifficulty.Hard, ChartDifficulty.Expert]: chart = song.charts[difficulty] + chart_hash = hash_master(chart) + chart_path = chart.image_path embed = discord.Embed(title=f'{song.name} [{chart.difficulty.name}]') embed.set_thumbnail(url=f'attachment://jacket.png') embed.set_image( - url=f'https://qwewqa.github.io/d4dj-dumps/{chart.image_path.relative_to(asset_manager.path).as_posix()}' + url=f'https://qwewqa.github.io/d4dj-dumps/music/charts/{chart_path.stem}_{chart_hash}{chart_path.suffix}' ) chart_data = chart.load_chart_data() diff --git a/miyu_bot/commands/common/master_asset_manager.py b/miyu_bot/commands/common/master_asset_manager.py index 604d8c5..5b1781c 100644 --- a/miyu_bot/commands/common/master_asset_manager.py +++ b/miyu_bot/commands/common/master_asset_manager.py @@ -1,8 +1,9 @@ +import hashlib from functools import lru_cache from typing import Callable, Any, Optional from d4dj_utils.manager.asset_manager import AssetManager -from d4dj_utils.master.master_asset import MasterDict +from d4dj_utils.master.master_asset import MasterDict, MasterAsset from discord.ext import commands from miyu_bot.commands.common.fuzzy_matching import FuzzyFilteredMap @@ -34,54 +35,67 @@ class MasterFilterManager: dt.timezone.utc) + dt.timedelta(hours=12), ) + @property + @lru_cache(None) + def cards(self): + return MasterFilter( + self.manager.card_master, + naming_function=lambda c: c.name, + filter_function=lambda c: c.is_released, + ) + class MasterFilter: def __init__(self, masters: MasterDict, naming_function: Callable[[Any], str], filter_function=lambda _: True, fallback_naming_function: Optional[Callable[[Any], str]] = None): self.masters = masters - self.fuzzy_map = FuzzyFilteredMap(filter_function) - self.unfiltered_fuzzy_map = FuzzyFilteredMap() + self.default_filter = FuzzyFilteredMap(filter_function) + self.unrestricted_filter = FuzzyFilteredMap() for master in masters.values(): name = naming_function(master) - if self.fuzzy_map.has_exact(name) and fallback_naming_function: + if self.default_filter.has_exact(name) and fallback_naming_function: name = fallback_naming_function(master) - if self.fuzzy_map.has_exact(name): + if self.default_filter.has_exact(name): continue - self.fuzzy_map[name] = master - self.unfiltered_fuzzy_map[name] = master + self.default_filter[name] = master + self.unrestricted_filter[name] = master def get(self, name_or_id: str, ctx: Optional[commands.Context]): if ctx and ctx.channel.id in no_filter_channels: try: return self.masters[int(name_or_id)] except (KeyError, ValueError): - return self.unfiltered_fuzzy_map[name_or_id] + return self.unrestricted_filter[name_or_id] else: try: master = self.masters[int(name_or_id)] - if master not in self.fuzzy_map.values(): - master = self.fuzzy_map[name_or_id] + if master not in self.default_filter.values(): + master = self.default_filter[name_or_id] return master except (KeyError, ValueError): - return self.fuzzy_map[name_or_id] + return self.default_filter[name_or_id] def get_sorted(self, name: str, ctx: commands.Context): if name: if ctx.channel.id in no_filter_channels: - return self.unfiltered_fuzzy_map.get_sorted(name) + return self.unrestricted_filter.get_sorted(name) else: - return self.fuzzy_map.get_sorted(name) + return self.default_filter.get_sorted(name) else: if ctx.channel.id in no_filter_channels: - return list(self.unfiltered_fuzzy_map.values()) + return list(self.unrestricted_filter.values()) else: - return list(self.fuzzy_map.values()) + return list(self.default_filter.values()) def values(self, ctx: commands.Context): if ctx.channel.id in no_filter_channels: - return self.unfiltered_fuzzy_map.values() + return self.unrestricted_filter.values() else: - return self.fuzzy_map.values() + return self.default_filter.values() + + +def hash_master(master: MasterAsset): + return hashlib.md5(master.extended_description().encode('utf-8')).hexdigest() no_filter_channels = {790033228600705048, 790033272376918027, 795640603114864640}