From b7396a7171b6a3b723e0b330521ac50926a7981c Mon Sep 17 00:00:00 2001 From: xtaodada Date: Wed, 3 May 2023 00:16:14 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Support=20starrail=20material=20lig?= =?UTF-8?q?ht=5Fcone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/services/game/cache.py | 18 +++- core/services/game/services.py | 37 ++++++-- metadata/shortname.py | 7 ++ .../apihelper/client/components/calendar.py | 48 +++------- modules/wiki/raider.py | 56 ++++++----- plugins/app/inline.py | 71 ++++++++++---- plugins/starrail/daily_note.py | 2 +- plugins/starrail/light_cone.py | 88 ++++++++++++++++++ plugins/starrail/material.py | 88 ++++++++++++++++++ plugins/starrail/strategy.py | 25 +++-- resources/bot/help/background/starrail.png | Bin 19586 -> 0 bytes resources/bot/help/help.html | 40 ++++---- 12 files changed, 356 insertions(+), 124 deletions(-) create mode 100644 plugins/starrail/light_cone.py create mode 100644 plugins/starrail/material.py delete mode 100644 resources/bot/help/background/starrail.png diff --git a/core/services/game/cache.py b/core/services/game/cache.py index c0bffb3..db66155 100644 --- a/core/services/game/cache.py +++ b/core/services/game/cache.py @@ -3,7 +3,7 @@ from typing import List from core.base_service import BaseService from core.dependence.redisdb import RedisDB -__all__ = ["GameCache", "GameCacheForStrategy"] +__all__ = ["GameCache", "GameCacheForStrategy", "GameCacheForMaterial", "GameCacheForLightCone"] class GameCache: @@ -24,10 +24,6 @@ class GameCache: await self.client.expire(qname, self.ttl) return await self.client.llen(qname) - -class GameCacheForStrategy(BaseService.Component, GameCache): - qname = "game:strategy" - async def get_file(self, character_name: str): qname = f"{self.qname}:{character_name}" return await self.client.get(qname) @@ -36,3 +32,15 @@ class GameCacheForStrategy(BaseService.Component, GameCache): qname = f"{self.qname}:{character_name}" await self.client.set(qname, file) await self.client.expire(qname, self.ttl) + + +class GameCacheForStrategy(BaseService.Component, GameCache): + qname = "game:strategy" + + +class GameCacheForMaterial(BaseService.Component, GameCache): + qname = "game:material" + + +class GameCacheForLightCone(BaseService.Component, GameCache): + qname = "game:lightcone" diff --git a/core/services/game/services.py b/core/services/game/services.py index 3e0f778..0aa7e90 100644 --- a/core/services/game/services.py +++ b/core/services/game/services.py @@ -1,17 +1,40 @@ from core.base_service import BaseService -from core.services.game.cache import GameCacheForStrategy +from core.services.game.cache import GameCacheForStrategy, GameCacheForMaterial, GameCacheForLightCone -__all__ = "GameStrategyService" +__all__ = "GameCacheService" -class GameStrategyService(BaseService): - def __init__(self, cache: GameCacheForStrategy): - self._cache = cache +class GameCacheService(BaseService): + def __init__( + self, + strategy_cache: GameCacheForStrategy, + material_cache: GameCacheForMaterial, + light_cone_cache: GameCacheForLightCone, + ): + self.strategy_cache = strategy_cache + self.material_cache = material_cache + self.light_cone_cache = light_cone_cache async def get_strategy_cache(self, character_name: str) -> str: - cache = await self._cache.get_file(character_name) + cache = await self.strategy_cache.get_file(character_name) if cache is not None: return cache async def set_strategy_cache(self, character_name: str, file: str) -> None: - await self._cache.set_file(character_name, file) + await self.strategy_cache.set_file(character_name, file) + + async def get_material_cache(self, character_name: str) -> str: + cache = await self.material_cache.get_file(character_name) + if cache is not None: + return cache + + async def set_material_cache(self, character_name: str, file: str) -> None: + await self.material_cache.set_file(character_name, file) + + async def get_light_cone_cache(self, light_cone_name: str) -> str: + cache = await self.light_cone_cache.get_file(light_cone_name) + if cache is not None: + return cache + + async def set_light_cone_cache(self, light_cone_name: str, file: str) -> None: + await self.light_cone_cache.set_file(light_cone_name, file) diff --git a/metadata/shortname.py b/metadata/shortname.py index 76bd163..26dc61f 100644 --- a/metadata/shortname.py +++ b/metadata/shortname.py @@ -147,3 +147,10 @@ def roleToTag(role_name: str) -> List[str]: """通过角色名获取TAG""" role_name = str.casefold(role_name) return next((value for value in roles.values() if value[0] == role_name), [role_name]) + + +@functools.lru_cache() +def lightConeToTag(name: str) -> List[str]: + """通过光锥名获取TAG""" + name = str.casefold(name) + return next((value for value in light_cones.values() if value[0] == name), [name]) diff --git a/modules/apihelper/client/components/calendar.py b/modules/apihelper/client/components/calendar.py index a098375..00d527a 100644 --- a/modules/apihelper/client/components/calendar.py +++ b/modules/apihelper/client/components/calendar.py @@ -16,55 +16,33 @@ if TYPE_CHECKING: class Calendar: - """原神活动日历""" + """活动日历""" - ANNOUNCEMENT_LIST = "https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnList" - ANNOUNCEMENT_CONTENT = "https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnContent" + ANNOUNCEMENT_LIST = "https://hkrpg-api.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnList" + ANNOUNCEMENT_CONTENT = "https://hkrpg-api-static.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnContent" ANNOUNCEMENT_PARAMS = { - "game": "hk4e", - "game_biz": "hk4e_cn", + "game": "hkrpg", + "game_biz": "hkrpg_cn", "lang": "zh-cn", - "bundle_id": "hk4e_cn", + "bundle_id": "hkrpg_cn", "platform": "pc", - "region": "cn_gf01", + "region": "prod_gf_cn", "level": "55", "uid": "100000000", } - MIAO_API = "http://miaoapi.cn/api/calendar" IGNORE_IDS = [ - 495, # 有奖问卷调查开启! - 1263, # 米游社《原神》专属工具一览 - 423, # 《原神》玩家社区一览 - 422, # 《原神》防沉迷系统说明 - 762, # 《原神》公平运营声明 - 762, # 《原神》公平运营声明 + 194, # 有奖问卷调查开启! + 183, # 官方社群一览 + 171, # 米游社《崩坏:星穹铁道》专属工具一览 + 187, # 《崩坏:星穹铁道》防沉迷系统公告 + 185, # 《崩坏:星穹铁道》公平运营声明 ] - IGNORE_RE = re.compile(r"(内容专题页|版本更新说明|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示)") + IGNORE_RE = re.compile(r"(内容专题页|版本更新说明|调研|防沉迷|米游社|专项意见|游戏优化及已知问题说明|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示)") FULL_TIME_RE = re.compile(r"(魔神任务)") def __init__(self): self.client = AsyncClient() - @staticmethod - async def async_gen_birthday_list() -> Dict[str, List[str]]: - """生成生日列表并且合并云端生日列表""" - birthday_list = Calendar.gen_birthday_list() - remote_data = await Remote.get_remote_birthday() - if remote_data: - birthday_list.update(remote_data) - return birthday_list - - @staticmethod - def gen_birthday_list() -> Dict[str, List[str]]: - """生成生日列表""" - birthday_list = {} - for value in AVATAR_DATA.values(): - key = "_".join([str(i) for i in value["birthday"]]) - data = birthday_list.get(key, []) - data.append(value["name"]) - birthday_list[key] = data - return birthday_list - @staticmethod def get_now_hour() -> datetime: """获取当前时间""" diff --git a/modules/wiki/raider.py b/modules/wiki/raider.py index 1cf4b9c..8a7ad50 100644 --- a/modules/wiki/raider.py +++ b/modules/wiki/raider.py @@ -1,46 +1,54 @@ import asyncio -from typing import List +from typing import List, Dict from modules.wiki.base import WikiModel class Raider(WikiModel): - raider_url = WikiModel.BASE_URL + "raiders/" + raider_url = "https://raw.githubusercontent.com/PaiGramTeam/star-rail-atlas/master" raider_path = WikiModel.BASE_PATH / "raiders" - raider_info_path = WikiModel.BASE_PATH / "raiders" / "info.json" - raider_path.mkdir(parents=True, exist_ok=True) + raider_role_path = WikiModel.BASE_PATH / "raiders" / "role" + raider_light_cone_path = WikiModel.BASE_PATH / "raiders" / "light_cone" + raider_role_material_path = WikiModel.BASE_PATH / "raiders" / "role_material" + raider_info_path = WikiModel.BASE_PATH / "raiders" / "path.json" + raider_role_path.mkdir(parents=True, exist_ok=True) + raider_light_cone_path.mkdir(parents=True, exist_ok=True) + raider_role_material_path.mkdir(parents=True, exist_ok=True) + name_map = {"role": "role", "lightcone": "light_cone", "material for role": "role_material"} def __init__(self): super().__init__() - self.all_raiders: List[str] = [] + self.all_role_raiders: List[str] = [] + self.all_light_cone_raiders: List[str] = [] + self.all_role_material_raiders: List[str] = [] def clear_class_data(self) -> None: - self.all_raiders.clear() + self.all_role_raiders.clear() + self.all_light_cone_raiders.clear() + self.all_role_material_raiders.clear() - async def refresh_task(self, name: str): - photo = await self.remote_get(f"{self.raider_url}{name}.png") - await self.save_file(photo.content, self.raider_path / f"{name}.png") + async def refresh_task(self, name: str, path: str = "", start: str = ""): + photo = await self.remote_get(f"{self.raider_url}{path}") + await self.save_file(photo.content, self.raider_path / start / f"{name}.png") async def refresh(self): - datas = await self.remote_get(self.raider_url + "info.json") + datas = await self.remote_get(self.raider_url + "/path.json") data = datas.json() - tasks = [] - for name in data: - tasks.append(self.refresh_task(name)) - await asyncio.gather(*tasks) - await self.dump(data, self.raider_info_path) + new_data = {} + for key, start in self.name_map.items(): + new_data[start] = list(data[key].keys()) + tasks = [] + for name, path in data[key].items(): + tasks.append(self.refresh_task(name, path, start)) + await asyncio.gather(*tasks) + await self.dump(new_data, self.raider_info_path) await self.read() async def read(self): if not self.raider_info_path.exists(): await self.refresh() return - datas = await WikiModel.read(self.raider_info_path) + datas: Dict[str, List] = await WikiModel.read(self.raider_info_path) self.clear_class_data() - for data in datas: - self.all_raiders.append(data) - - def get_name_list(self) -> List[str]: - return self.all_raiders.copy() - - def get_item_id(self, name: str) -> int: - return self.all_raiders.index(name) + self.all_role_raiders.extend(datas["role"]) + self.all_light_cone_raiders.extend(datas["light_cone"]) + self.all_role_material_raiders.extend(datas["role_material"]) diff --git a/plugins/app/inline.py b/plugins/app/inline.py index 6512f5e..22bf679 100644 --- a/plugins/app/inline.py +++ b/plugins/app/inline.py @@ -15,6 +15,7 @@ from telegram.error import BadRequest from telegram.ext import CallbackContext, InlineQueryHandler from core.plugin import Plugin, handler +from core.dependence.assets import AssetsService from core.services.search.services import SearchServices from core.services.wiki.services import WikiService from utils.log import logger @@ -25,25 +26,40 @@ class Inline(Plugin): def __init__( self, - wiki_service: WikiService, + asset_service: AssetsService, search_service: SearchServices, + wiki_service: WikiService, ): + self.asset_service = asset_service self.wiki_service = wiki_service self.weapons_list: List[Dict[str, str]] = [] self.characters_list: List[Dict[str, str]] = [] + self.characters_material_list: List[Dict[str, str]] = [] + self.light_cone_list: List[Dict[str, str]] = [] self.refresh_task: List[Awaitable] = [] self.search_service = search_service async def initialize(self): + async def task_light_cone(): + logger.info("Inline 模块正在获取光锥列表") + light_cone_datas: Dict[str, str] = {} + for light_cone in self.asset_service.light_cone.data: + light_cone_datas[light_cone.name] = light_cone.icon_ + # 光锥列表 + for light_cone in self.wiki_service.raider.all_light_cone_raiders: + if light_cone in light_cone_datas: + self.light_cone_list.append({"name": light_cone, "icon": light_cone_datas[light_cone]}) + else: + logger.warning(f"未找到光锥 {light_cone} 的图标,inline 不显示此光锥") + logger.success("Inline 模块获取光锥列表完成") + async def task_characters(): logger.info("Inline 模块正在获取角色列表") datas: Dict[str, str] = {} - for character in self.wiki_service.character.all_avatars: - if not character.icon: - logger.warning(f"角色 {character.name} 无图标") - continue - datas[character.name] = character.icon - for character in self.wiki_service.raider.get_name_list(): + for character in self.asset_service.avatar.data: + datas[character.name] = character.square or character.normal + # 角色攻略 + for character in self.wiki_service.raider.all_role_raiders: if character in datas: self.characters_list.append({"name": character, "icon": datas[character]}) else: @@ -51,11 +67,21 @@ class Inline(Plugin): if character.startswith(key): self.characters_list.append({"name": character, "icon": value}) break + # 角色培养素材 + for character in self.wiki_service.raider.all_role_material_raiders: + if character in datas: + self.characters_material_list.append({"name": character, "icon": datas[character]}) + else: + for key, value in datas.items(): + if character.startswith(key): + self.characters_material_list.append({"name": character, "icon": value}) + break logger.success("Inline 模块获取角色列表成功") self.refresh_task.append(asyncio.create_task(task_characters())) + self.refresh_task.append(asyncio.create_task(task_light_cone())) - @handler(InlineQueryHandler, block=False) + @handler.inline_query(block=False) async def inline_query(self, update: Update, _: CallbackContext) -> None: user = update.effective_user ilq = cast(InlineQuery, update.inline_query) @@ -65,27 +91,34 @@ class Inline(Plugin): results_list = [] args = query.split(" ") if args[0] == "": - results_list.append( - InlineQueryResultArticle( - id=str(uuid4()), - title="角色攻略查询", - description="输入角色名即可查询角色攻略", - input_message_content=InputTextMessageContent("角色攻略查询"), + temp_data = [("光锥图鉴查询", "输入光锥名称即可查询光锥图鉴"), ("角色攻略查询", "输入角色名即可查询角色攻略图鉴")] + for i in temp_data: + results_list.append( + InlineQueryResultArticle( + id=str(uuid4()), + title=i[0], + description=i[1], + input_message_content=InputTextMessageContent(i[0]), + ) ) - ) else: - if args[0] == "查看角色攻略列表并查询": - for character in self.characters_list: + if args[0] in ["查看角色攻略列表并查询", "查看角色培养素材列表并查询", "查看光锥列表并查询"]: + temp_data = { + "查看角色攻略列表并查询": (self.characters_list, "角色攻略查询"), + "查看角色培养素材列表并查询": (self.characters_material_list, "角色培养素材查询"), + "查看光锥列表并查询": (self.light_cone_list, "光锥查询"), + }[args[0]] + for character in temp_data[0]: name = character["name"] icon = character["icon"] results_list.append( InlineQueryResultArticle( id=str(uuid4()), title=name, - description=f"查看角色攻略列表并查询 {name}", + description=f"{args[0]} {name}", thumb_url=icon, input_message_content=InputTextMessageContent( - f"角色攻略查询{name}", parse_mode=ParseMode.MARKDOWN_V2 + f"{temp_data[1]}{name}", parse_mode=ParseMode.MARKDOWN_V2 ), ) ) diff --git a/plugins/starrail/daily_note.py b/plugins/starrail/daily_note.py index 80e155e..cd5aca6 100644 --- a/plugins/starrail/daily_note.py +++ b/plugins/starrail/daily_note.py @@ -58,7 +58,7 @@ class DailyNotePlugin(Plugin): "expeditions": bool(daily_info.expeditions), "remained_time": remained_time, "current_expeditions": len(daily_info.expeditions), - "max_expeditions": daily_info.accepted_epedition_num, + "max_expeditions": daily_info.total_expedition_num, } render_result = await self.template_service.render( "starrail/daily_note/daily_note.html", diff --git a/plugins/starrail/light_cone.py b/plugins/starrail/light_cone.py new file mode 100644 index 0000000..11bf389 --- /dev/null +++ b/plugins/starrail/light_cone.py @@ -0,0 +1,88 @@ +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update +from telegram.constants import ChatAction, ParseMode +from telegram.ext import CallbackContext, filters + +from core.plugin import Plugin, handler +from core.services.game.services import GameCacheService +from core.services.search.models import StrategyEntry +from core.services.search.services import SearchServices +from core.services.wiki.services import WikiService +from metadata.shortname import lightConeToTag, lightConeToName +from utils.log import logger + + +class LightConePlugin(Plugin): + """光锥图鉴查询""" + + KEYBOARD = [[InlineKeyboardButton(text="查看光锥列表并查询", switch_inline_query_current_chat="查看光锥列表并查询")]] + + def __init__( + self, + cache_service: GameCacheService = None, + wiki_service: WikiService = None, + search_service: SearchServices = None, + ): + self.cache_service = cache_service + self.wiki_service = wiki_service + self.search_service = search_service + + @handler.command(command="light_cone", block=False) + @handler.message(filters=filters.Regex("^光锥查询(.*)"), block=False) + async def command_start(self, update: Update, context: CallbackContext) -> None: + message = update.effective_message + user = update.effective_user + args = self.get_args(context) + if len(args) >= 1: + light_cone_name = args[0] + else: + reply_message = await message.reply_text( + "请回复你要查询的光锥名称", + reply_markup=InlineKeyboardMarkup(self.KEYBOARD) + ) + if filters.ChatType.GROUPS.filter(reply_message): + self.add_delete_message_job(message) + self.add_delete_message_job(reply_message) + return + light_cone_name = lightConeToName(light_cone_name) + file_path = self.wiki_service.raider.raider_light_cone_path / f"{light_cone_name}.png" + if not file_path.exists(): + reply_message = await message.reply_text( + f"没有找到 {light_cone_name} 的光锥图鉴", reply_markup=InlineKeyboardMarkup(self.KEYBOARD) + ) + if filters.ChatType.GROUPS.filter(reply_message): + self.add_delete_message_job(message) + self.add_delete_message_job(reply_message) + return + logger.info("用户 %s[%s] 查询光锥图鉴命令请求 || 参数 %s", user.full_name, user.id, light_cone_name) + await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) + caption = "From 米游社@听语惊花" + if file_id := await self.cache_service.get_light_cone_cache(light_cone_name): + await message.reply_photo( + photo=file_id, + caption=caption, + filename=f"{light_cone_name}.png", + allow_sending_without_reply=True, + parse_mode=ParseMode.HTML, + ) + else: + reply_photo = await message.reply_photo( + photo=open(file_path, "rb"), + caption=caption, + filename=f"{light_cone_name}.png", + allow_sending_without_reply=True, + parse_mode=ParseMode.HTML, + ) + if reply_photo.photo: + tags = lightConeToTag(light_cone_name) + photo_file_id = reply_photo.photo[0].file_id + await self.cache_service.set_light_cone_cache(light_cone_name, photo_file_id) + entry = StrategyEntry( + key=f"plugin:strategy:{light_cone_name}", + title=light_cone_name, + description=f"{light_cone_name} 光锥图鉴", + tags=tags, + caption=caption, + parse_mode="HTML", + photo_file_id=photo_file_id, + ) + await self.search_service.add_entry(entry) diff --git a/plugins/starrail/material.py b/plugins/starrail/material.py new file mode 100644 index 0000000..5cdac50 --- /dev/null +++ b/plugins/starrail/material.py @@ -0,0 +1,88 @@ +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update +from telegram.constants import ChatAction, ParseMode +from telegram.ext import CallbackContext, filters + +from core.plugin import Plugin, handler +from core.services.game.services import GameCacheService +from core.services.search.models import StrategyEntry +from core.services.search.services import SearchServices +from core.services.wiki.services import WikiService +from metadata.shortname import roleToName, roleToTag +from utils.log import logger + + +class MaterialPlugin(Plugin): + """角色培养素材查询""" + + KEYBOARD = [[InlineKeyboardButton(text="查看角色培养素材列表并查询", switch_inline_query_current_chat="查看角色培养素材列表并查询")]] + + def __init__( + self, + cache_service: GameCacheService = None, + wiki_service: WikiService = None, + search_service: SearchServices = None, + ): + self.cache_service = cache_service + self.wiki_service = wiki_service + self.search_service = search_service + + @handler.command(command="material", block=False) + @handler.message(filters=filters.Regex("^角色培养素材查询(.*)"), block=False) + async def command_start(self, update: Update, context: CallbackContext) -> None: + message = update.effective_message + user = update.effective_user + args = self.get_args(context) + if len(args) >= 1: + character_name = args[0] + else: + reply_message = await message.reply_text( + "请回复你要查询的角色培养素材图鉴的角色名", + reply_markup=InlineKeyboardMarkup(self.KEYBOARD) + ) + if filters.ChatType.GROUPS.filter(reply_message): + self.add_delete_message_job(message) + self.add_delete_message_job(reply_message) + return + character_name = roleToName(character_name) + file_path = self.wiki_service.raider.raider_role_material_path / f"{character_name}.png" + if not file_path.exists(): + reply_message = await message.reply_text( + f"没有找到 {character_name} 的角色培养素材图鉴", reply_markup=InlineKeyboardMarkup(self.KEYBOARD) + ) + if filters.ChatType.GROUPS.filter(reply_message): + self.add_delete_message_job(message) + self.add_delete_message_job(reply_message) + return + logger.info("用户 %s[%s] 查询角色培养素材命令请求 || 参数 %s", user.full_name, user.id, character_name) + await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) + caption = "From 米游社@听语惊花" + if file_id := await self.cache_service.get_material_cache(character_name): + await message.reply_photo( + photo=file_id, + caption=caption, + filename=f"{character_name}.png", + allow_sending_without_reply=True, + parse_mode=ParseMode.HTML, + ) + else: + reply_photo = await message.reply_photo( + photo=open(file_path, "rb"), + caption=caption, + filename=f"{character_name}.png", + allow_sending_without_reply=True, + parse_mode=ParseMode.HTML, + ) + if reply_photo.photo: + tags = roleToTag(character_name) + photo_file_id = reply_photo.photo[0].file_id + await self.cache_service.set_material_cache(character_name, photo_file_id) + entry = StrategyEntry( + key=f"plugin:strategy:{character_name}", + title=character_name, + description=f"{character_name} 角色攻略", + tags=tags, + caption=caption, + parse_mode="HTML", + photo_file_id=photo_file_id, + ) + await self.search_service.add_entry(entry) diff --git a/plugins/starrail/strategy.py b/plugins/starrail/strategy.py index 944db71..8c8f32b 100644 --- a/plugins/starrail/strategy.py +++ b/plugins/starrail/strategy.py @@ -3,7 +3,7 @@ from telegram.constants import ChatAction, ParseMode from telegram.ext import CallbackContext, filters from core.plugin import Plugin, handler -from core.services.game.services import GameStrategyService +from core.services.game.services import GameCacheService from core.services.search.models import StrategyEntry from core.services.search.services import SearchServices from core.services.wiki.services import WikiService @@ -18,7 +18,7 @@ class StrategyPlugin(Plugin): def __init__( self, - cache_service: GameStrategyService = None, + cache_service: GameCacheService = None, wiki_service: WikiService = None, search_service: SearchServices = None, ): @@ -41,7 +41,7 @@ class StrategyPlugin(Plugin): self.add_delete_message_job(reply_message) return character_name = roleToName(character_name) - file_path = self.wiki_service.raider.raider_path / f"{character_name}.png" + file_path = self.wiki_service.raider.raider_role_path / f"{character_name}.png" if not file_path.exists(): reply_message = await message.reply_text( f"没有找到 {character_name} 的攻略", reply_markup=InlineKeyboardMarkup(self.KEYBOARD) @@ -52,28 +52,27 @@ class StrategyPlugin(Plugin): return logger.info("用户 %s[%s] 查询角色攻略命令请求 || 参数 %s", user.full_name, user.id, character_name) await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) - caption = "From 米游社" + caption = "From 米游社@听语惊花" if file_id := await self.cache_service.get_strategy_cache(character_name): - await message.reply_document( - document=file_id, + await message.reply_photo( + photo=file_id, caption=caption, filename=f"{character_name}.png", allow_sending_without_reply=True, parse_mode=ParseMode.HTML, ) else: - reply_document = await message.reply_document( - document=open(file_path, "rb"), + reply_photo = await message.reply_photo( + photo=open(file_path, "rb"), caption=caption, filename=f"{character_name}.png", allow_sending_without_reply=True, parse_mode=ParseMode.HTML, ) - if reply_document.document: + if reply_photo.photo: tags = roleToTag(character_name) - photo_file_id = reply_document.document.file_id - cid = self.wiki_service.raider.get_item_id(character_name) - await self.cache_service.set_strategy_cache(cid, photo_file_id) + photo_file_id = reply_photo.photo[0].file_id + await self.cache_service.set_strategy_cache(character_name, photo_file_id) entry = StrategyEntry( key=f"plugin:strategy:{character_name}", title=character_name, @@ -81,6 +80,6 @@ class StrategyPlugin(Plugin): tags=tags, caption=caption, parse_mode="HTML", - document_file_id=photo_file_id, + photo_file_id=photo_file_id, ) await self.search_service.add_entry(entry) diff --git a/resources/bot/help/background/starrail.png b/resources/bot/help/background/starrail.png deleted file mode 100644 index d177181e6a34a4963126049259adb07aa7079890..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19586 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 XF;)%!|7-wZ00000NkvXXu0mjfllgi{ diff --git a/resources/bot/help/help.html b/resources/bot/help/help.html index b36b410..543b8a7 100644 --- a/resources/bot/help/help.html +++ b/resources/bot/help/help.html @@ -26,25 +26,25 @@
- +

查询命令

- - - - +
+
/light_cone
+
查询光锥图鉴
+
/strategy
查询角色攻略
- - - - +
+
/material
+
角色培养素材查询
+
@@ -89,13 +89,13 @@ - - - - - - - +
+
+ /avatars + +
+
查询角色练度
+
@@ -239,10 +239,10 @@
@{{bot_username}} 角色名
查询角色攻略
- - - - +
+
@{{bot_username}} 光锥名
+
查询光锥信息
+