mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-16 04:35:49 +00:00
✨ Support genshin Chronicled wish
This commit is contained in:
parent
fd2cee4767
commit
451a062d6f
@ -1,6 +1,7 @@
|
||||
from metadata.pool.pool_200 import POOL_200
|
||||
from metadata.pool.pool_301 import POOL_301
|
||||
from metadata.pool.pool_302 import POOL_302
|
||||
from metadata.pool.pool_500 import POOL_500
|
||||
|
||||
|
||||
def get_pool_by_id(pool_type):
|
||||
@ -10,4 +11,6 @@ def get_pool_by_id(pool_type):
|
||||
return POOL_301
|
||||
if pool_type == 302:
|
||||
return POOL_302
|
||||
if pool_type == 500:
|
||||
return POOL_500
|
||||
return None
|
||||
|
9
metadata/pool/pool_500.py
Normal file
9
metadata/pool/pool_500.py
Normal file
@ -0,0 +1,9 @@
|
||||
POOL_500 = [
|
||||
{
|
||||
"five": ["晨风之诗"],
|
||||
"four": [],
|
||||
"name": "晨风之诗",
|
||||
"from": "2024-03-13 06:00:00",
|
||||
"to": "2024-04-02 17:59:59",
|
||||
},
|
||||
]
|
@ -1,7 +1,7 @@
|
||||
from simnet.models.genshin.wish import BannerType
|
||||
|
||||
PAIMONMOE_VERSION = 3
|
||||
UIGF_VERSION = "v2.4"
|
||||
UIGF_VERSION = "v3.0"
|
||||
|
||||
|
||||
GACHA_TYPE_LIST = {
|
||||
@ -10,4 +10,6 @@ GACHA_TYPE_LIST = {
|
||||
BannerType.WEAPON: "武器祈愿",
|
||||
BannerType.CHARACTER1: "角色祈愿",
|
||||
BannerType.CHARACTER2: "角色祈愿",
|
||||
BannerType.CHRONICLED: "集录祈愿",
|
||||
}
|
||||
GACHA_TYPE_LIST_REVERSE = {v: k for k, v in GACHA_TYPE_LIST.items()}
|
||||
|
@ -189,6 +189,10 @@ class GachaLog:
|
||||
new_num = 0
|
||||
for item_info in all_items:
|
||||
pool_name = GACHA_TYPE_LIST[BannerType(int(item_info.gacha_type))]
|
||||
if pool_name not in temp_id_data:
|
||||
temp_id_data[pool_name] = []
|
||||
if pool_name not in gacha_log.item_list:
|
||||
gacha_log.item_list[pool_name] = []
|
||||
if item_info.id not in temp_id_data[pool_name]:
|
||||
gacha_log.item_list[pool_name].append(item_info)
|
||||
temp_id_data[pool_name].append(item_info.id)
|
||||
@ -282,6 +286,10 @@ class GachaLog:
|
||||
),
|
||||
)
|
||||
|
||||
if pool_name not in temp_id_data:
|
||||
temp_id_data[pool_name] = []
|
||||
if pool_name not in gacha_log.item_list:
|
||||
gacha_log.item_list[pool_name] = []
|
||||
if item.id not in temp_id_data[pool_name]:
|
||||
gacha_log.item_list[pool_name].append(item)
|
||||
temp_id_data[pool_name].append(item.id)
|
||||
@ -328,7 +336,7 @@ class GachaLog:
|
||||
for item in data:
|
||||
count += 1
|
||||
if item.rank_type == "5":
|
||||
if item.item_type == "角色" and pool_name in {"角色祈愿", "常驻祈愿"}:
|
||||
if item.item_type == "角色" and pool_name in {"角色祈愿", "常驻祈愿", "集录祈愿"}:
|
||||
data = {
|
||||
"name": item.name,
|
||||
"icon": (await assets.avatar(roleToId(item.name)).icon()).as_uri(),
|
||||
@ -339,7 +347,7 @@ class GachaLog:
|
||||
"time": item.time,
|
||||
}
|
||||
result.append(FiveStarItem.construct(**data))
|
||||
elif item.item_type == "武器" and pool_name in {"武器祈愿", "常驻祈愿"}:
|
||||
elif item.item_type == "武器" and pool_name in {"武器祈愿", "常驻祈愿", "集录祈愿"}:
|
||||
data = {
|
||||
"name": item.name,
|
||||
"icon": (await assets.weapon(weaponToId(item.name)).icon()).as_uri(),
|
||||
@ -489,6 +497,37 @@ class GachaLog:
|
||||
],
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_500_pool_data(
|
||||
total: int, all_five: List[FiveStarItem], all_four: List[FourStarItem], no_five_star: int, no_four_star: int
|
||||
):
|
||||
# 总共五星
|
||||
five_star = len(all_five)
|
||||
# 五星平均
|
||||
five_star_avg = round((total - no_five_star) / five_star, 2) if five_star != 0 else 0
|
||||
# 四星角色
|
||||
four_star_character = len([i for i in all_four if i.type == "角色"])
|
||||
# 总共四星
|
||||
four_star = len(all_four)
|
||||
# 四星平均
|
||||
four_star_avg = round((total - no_four_star) / four_star, 2) if four_star != 0 else 0
|
||||
# 四星最多
|
||||
four_star_name_list = [i.name for i in all_four]
|
||||
four_star_max = max(four_star_name_list, key=four_star_name_list.count) if four_star_name_list else ""
|
||||
four_star_max_count = four_star_name_list.count(four_star_max)
|
||||
return [
|
||||
[
|
||||
{"num": no_five_star, "unit": "抽", "lable": "未出五星"},
|
||||
{"num": five_star, "unit": "个", "lable": "五星"},
|
||||
{"num": five_star_avg, "unit": "抽", "lable": "五星平均"},
|
||||
{"num": four_star_character, "unit": "个", "lable": "四星角色"},
|
||||
{"num": no_four_star, "unit": "抽", "lable": "未出四星"},
|
||||
{"num": four_star, "unit": "个", "lable": "四星"},
|
||||
{"num": four_star_avg, "unit": "抽", "lable": "四星平均"},
|
||||
{"num": four_star_max_count, "unit": four_star_max, "lable": "四星最多"},
|
||||
],
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def count_fortune(pool_name: str, summon_data, weapon: bool = False):
|
||||
"""
|
||||
@ -534,7 +573,7 @@ class GachaLog:
|
||||
all_five, no_five_star = await self.get_all_5_star_items(data, assets, pool_name)
|
||||
all_four, no_four_star = await self.get_all_4_star_items(data, assets)
|
||||
summon_data = None
|
||||
if pool == BannerType.CHARACTER1:
|
||||
if pool in [BannerType.CHARACTER1, BannerType.CHARACTER2]:
|
||||
summon_data = self.get_301_pool_data(total, all_five, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data)
|
||||
elif pool == BannerType.WEAPON:
|
||||
@ -543,6 +582,9 @@ class GachaLog:
|
||||
elif pool == BannerType.PERMANENT:
|
||||
summon_data = self.get_200_pool_data(total, all_five, all_four, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data)
|
||||
elif pool == BannerType.CHRONICLED:
|
||||
summon_data = self.get_500_pool_data(total, all_five, all_four, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data)
|
||||
last_time = data[0].time.strftime("%Y-%m-%d %H:%M")
|
||||
first_time = data[-1].time.strftime("%Y-%m-%d %H:%M")
|
||||
return {
|
||||
|
@ -51,8 +51,8 @@ class GachaItem(BaseModel):
|
||||
|
||||
@validator("gacha_type")
|
||||
def check_gacha_type(cls, v):
|
||||
if v not in {"100", "200", "301", "302", "400"}:
|
||||
raise ValueError(f"gacha_type must be 200, 301, 302 or 400, invalid value: {v}")
|
||||
if v not in {"100", "200", "301", "302", "400", "500"}:
|
||||
raise ValueError(f"gacha_type must be 200, 301, 302, 400, 500, invalid value: {v}")
|
||||
return v
|
||||
|
||||
@validator("item_type")
|
||||
@ -78,6 +78,7 @@ class GachaLogInfo(BaseModel):
|
||||
"武器祈愿": [],
|
||||
"常驻祈愿": [],
|
||||
"新手祈愿": [],
|
||||
"集录祈愿": [],
|
||||
}
|
||||
|
||||
@property
|
||||
@ -140,6 +141,7 @@ class UIGFGachaType(Enum):
|
||||
CHARACTER = "301"
|
||||
WEAPON = "302"
|
||||
CHARACTER2 = "400"
|
||||
CHRONICLED = "500"
|
||||
|
||||
|
||||
class UIGFItem(BaseModel):
|
||||
|
@ -1,5 +1,5 @@
|
||||
from io import BytesIO
|
||||
from typing import Optional, TYPE_CHECKING, List
|
||||
from typing import Optional, TYPE_CHECKING, List, Union, Tuple
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from aiofiles import open as async_open
|
||||
@ -18,8 +18,9 @@ from core.services.cookies import CookiesService
|
||||
from core.services.players import PlayersService
|
||||
from core.services.template.models import FileType
|
||||
from core.services.template.services import TemplateService
|
||||
from gram_core.config import config
|
||||
from metadata.scripts.paimon_moe import GACHA_LOG_PAIMON_MOE_PATH, update_paimon_moe_zh
|
||||
from modules.gacha_log.const import UIGF_VERSION
|
||||
from modules.gacha_log.const import UIGF_VERSION, GACHA_TYPE_LIST_REVERSE
|
||||
from modules.gacha_log.error import (
|
||||
GachaLogAccountNotFound,
|
||||
GachaLogAuthkeyTimeout,
|
||||
@ -32,6 +33,7 @@ from modules.gacha_log.error import (
|
||||
from modules.gacha_log.helpers import from_url_get_authkey
|
||||
from modules.gacha_log.log import GachaLog
|
||||
from modules.gacha_log.migrate import GachaLogMigrate
|
||||
from modules.gacha_log.models import GachaLogInfo
|
||||
from plugins.tools.genshin import PlayerNotFoundError
|
||||
from plugins.tools.player_info import PlayerInfoSystem
|
||||
from utils.log import logger
|
||||
@ -47,6 +49,7 @@ if TYPE_CHECKING:
|
||||
from telegram import Update, Message, User, Document
|
||||
from telegram.ext import ContextTypes
|
||||
from gram_core.services.players.models import Player
|
||||
from gram_core.services.template.models import RenderResult
|
||||
|
||||
INPUT_URL, INPUT_FILE, CONFIRM_DELETE = range(10100, 10103)
|
||||
|
||||
@ -78,6 +81,7 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
self.zh_dict = None
|
||||
self.gacha_log = GachaLog()
|
||||
self.player_info = player_info
|
||||
self.wish_photo = None
|
||||
|
||||
async def initialize(self) -> None:
|
||||
await update_paimon_moe_zh(False)
|
||||
@ -321,7 +325,7 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
path = await self.gacha_log.gacha_log_to_uigf(str(user.id), str(player_id))
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_DOCUMENT)
|
||||
await message.reply_document(document=open(path, "rb+"), caption="抽卡记录导出文件 - UIGF V2.3")
|
||||
await message.reply_document(document=open(path, "rb+"), caption=f"抽卡记录导出文件 - UIGF {UIGF_VERSION}")
|
||||
except GachaLogNotFound:
|
||||
logger.info("未找到用户 %s[%s] 的抽卡记录", user.full_name, user.id)
|
||||
buttons = [
|
||||
@ -356,43 +360,102 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
}
|
||||
await message.reply_text(f"{url}?{urlencode(params)}", disable_web_page_preview=True)
|
||||
|
||||
async def rander_wish_log_analysis(
|
||||
self, user_id: int, player_id: int, pool_type: BannerType
|
||||
) -> Union[str, "RenderResult"]:
|
||||
data = await self.gacha_log.get_analysis(user_id, player_id, pool_type, self.assets_service)
|
||||
if isinstance(data, str):
|
||||
return data
|
||||
name_card = await self.player_info.get_name_card(player_id, user_id)
|
||||
data["name_card"] = name_card
|
||||
png_data = await self.template_service.render(
|
||||
"genshin/wish_log/wish_log.jinja2",
|
||||
data,
|
||||
full_page=True,
|
||||
file_type=FileType.DOCUMENT if len(data.get("fiveLog")) > 300 else FileType.PHOTO,
|
||||
query_selector=".body_box",
|
||||
)
|
||||
return png_data
|
||||
|
||||
@staticmethod
|
||||
def gen_button(user_id: int, uid: int, info: "GachaLogInfo") -> List[List[InlineKeyboardButton]]:
|
||||
buttons = []
|
||||
pools = []
|
||||
skip_pools = ["新手祈愿"]
|
||||
for k, v in info.item_list.items():
|
||||
if k in skip_pools:
|
||||
continue
|
||||
if not v:
|
||||
continue
|
||||
pools.append(k)
|
||||
# 2 个一组
|
||||
for i in range(0, len(pools), 2):
|
||||
row = []
|
||||
for pool in pools[i : i + 2]:
|
||||
row.append(
|
||||
InlineKeyboardButton(
|
||||
pool,
|
||||
callback_data=f"get_wish_log|{user_id}|{uid}|{pool}",
|
||||
)
|
||||
)
|
||||
buttons.append(row)
|
||||
return buttons
|
||||
|
||||
async def wish_log_pool_choose(self, user_id: int, message: "Message"):
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
player_id = await self.get_player_id(user_id)
|
||||
gacha_log, status = await self.gacha_log.load_history_info(str(user_id), str(player_id))
|
||||
if not status:
|
||||
raise GachaLogNotFound
|
||||
buttons = self.gen_button(user_id, player_id, gacha_log)
|
||||
if isinstance(self.wish_photo, str):
|
||||
photo = self.wish_photo
|
||||
else:
|
||||
photo = open("resources/img/wish.jpg", "rb")
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
reply_message = await message.reply_photo(
|
||||
photo=photo,
|
||||
caption="请选择你要查询的卡池",
|
||||
reply_markup=InlineKeyboardMarkup(buttons),
|
||||
)
|
||||
if reply_message.photo:
|
||||
self.wish_photo = reply_message.photo[-1].file_id
|
||||
|
||||
async def wish_log_pool_send(self, user_id: int, uid: int, pool_type: "BannerType", message: "Message"):
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
uid = await self.get_player_id(user_id)
|
||||
png_data = await self.rander_wish_log_analysis(user_id, uid, pool_type)
|
||||
if isinstance(png_data, str):
|
||||
reply = await message.reply_text(png_data)
|
||||
else:
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
reply = await png_data.reply_photo(message)
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply)
|
||||
self.add_delete_message_job(message)
|
||||
|
||||
@handler.command(command="wish_log", block=False)
|
||||
@handler.command(command="gacha_log", block=False)
|
||||
@handler.message(filters=filters.Regex("^抽卡记录?(武器|角色|常驻|)$"), block=False)
|
||||
async def command_start_analysis(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
user_id = await self.get_real_user_id(update)
|
||||
message = update.effective_message
|
||||
pool_type = BannerType.CHARACTER1
|
||||
pool_type = None
|
||||
if args := self.get_args(context):
|
||||
if "武器" in args:
|
||||
if "角色" in args:
|
||||
pool_type = BannerType.CHARACTER1
|
||||
elif "武器" in args:
|
||||
pool_type = BannerType.WEAPON
|
||||
elif "常驻" in args:
|
||||
pool_type = BannerType.STANDARD
|
||||
self.log_user(update, logger.info, "抽卡记录命令请求 || 参数 %s", pool_type.name)
|
||||
elif "集录" in args:
|
||||
pool_type = BannerType.CHRONICLED
|
||||
self.log_user(update, logger.info, "抽卡记录命令请求 || 参数 %s", pool_type.name if pool_type else None)
|
||||
try:
|
||||
player_id = await self.get_player_id(user_id)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
data = await self.gacha_log.get_analysis(user_id, player_id, pool_type, self.assets_service)
|
||||
if isinstance(data, str):
|
||||
reply_message = await message.reply_text(data)
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=300)
|
||||
self.add_delete_message_job(message, delay=300)
|
||||
if pool_type is None:
|
||||
await self.wish_log_pool_choose(user_id, message)
|
||||
else:
|
||||
name_card = await self.player_info.get_name_card(player_id, user_id)
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
data["name_card"] = name_card
|
||||
png_data = await self.template_service.render(
|
||||
"genshin/wish_log/wish_log.jinja2",
|
||||
data,
|
||||
full_page=True,
|
||||
file_type=FileType.DOCUMENT if len(data.get("fiveLog")) > 300 else FileType.PHOTO,
|
||||
query_selector=".body_box",
|
||||
)
|
||||
if png_data.file_type == FileType.DOCUMENT:
|
||||
await png_data.reply_document(message, filename="抽卡记录.png")
|
||||
else:
|
||||
await png_data.reply_photo(message)
|
||||
await self.wish_log_pool_send(user_id, user_id, pool_type, message)
|
||||
except PlayerNotFoundError:
|
||||
await message.reply_text("该用户暂未绑定账号")
|
||||
except GachaLogNotFound:
|
||||
@ -402,6 +465,45 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
]
|
||||
await message.reply_text("派蒙没有找到你的抽卡记录,快来点击按钮私聊派蒙导入吧~", reply_markup=InlineKeyboardMarkup(buttons))
|
||||
|
||||
@handler.callback_query(pattern=r"^get_wish_log\|", block=False)
|
||||
async def get_wish_log(self, update: "Update", _: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
callback_query = update.callback_query
|
||||
user = callback_query.from_user
|
||||
message = callback_query.message
|
||||
|
||||
async def get_wish_log_callback(
|
||||
callback_query_data: str,
|
||||
) -> Tuple[str, int, int]:
|
||||
_data = callback_query_data.split("|")
|
||||
_user_id = int(_data[1])
|
||||
_uid = int(_data[2])
|
||||
_result = _data[3]
|
||||
logger.debug(
|
||||
"callback_query_data函数返回 result[%s] user_id[%s] uid[%s]",
|
||||
_result,
|
||||
_user_id,
|
||||
_uid,
|
||||
)
|
||||
return _result, _user_id, _uid
|
||||
|
||||
pool, user_id, uid = await get_wish_log_callback(callback_query.data)
|
||||
if user.id != user_id:
|
||||
await callback_query.answer(text="这不是你的按钮!\n" + config.notice.user_mismatch, show_alert=True)
|
||||
return
|
||||
pool_type = GACHA_TYPE_LIST_REVERSE.get(pool)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
try:
|
||||
png_data = await self.rander_wish_log_analysis(user_id, uid, pool_type)
|
||||
except GachaLogNotFound:
|
||||
png_data = "未找到抽卡记录"
|
||||
if isinstance(png_data, str):
|
||||
await callback_query.answer(png_data, show_alert=True)
|
||||
self.add_delete_message_job(message, delay=1)
|
||||
else:
|
||||
await callback_query.answer(text="正在渲染图片中 请稍等 请不要重复点击按钮", show_alert=False)
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
await png_data.edit_media(message)
|
||||
|
||||
@handler.command(command="wish_count", block=False)
|
||||
@handler.command(command="gacha_count", block=False)
|
||||
@handler.message(filters=filters.Regex("^抽卡统计?(武器|角色|常驻|仅五星|)$"), block=False)
|
||||
@ -415,6 +517,8 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
pool_type = BannerType.WEAPON
|
||||
elif "常驻" in args:
|
||||
pool_type = BannerType.STANDARD
|
||||
elif "集录" in args:
|
||||
pool_type = BannerType.CHRONICLED
|
||||
elif "仅五星" in args:
|
||||
all_five = True
|
||||
self.log_user(update, logger.info, "抽卡统计命令请求 || 参数 %s || 仅五星 %s", pool_type.name, all_five)
|
||||
|
@ -222,6 +222,10 @@ body {
|
||||
background-color: #757cc8;
|
||||
}
|
||||
|
||||
.label_500 {
|
||||
background-color: #757cc8;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
|
BIN
resources/img/wish.jpg
Normal file
BIN
resources/img/wish.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 359 KiB |
Loading…
Reference in New Issue
Block a user