upd mai
This commit is contained in:
parent
401d797f10
commit
370cb4abe5
9 changed files with 428 additions and 357 deletions
|
@ -15,7 +15,7 @@ from .song import get_song_info
|
|||
from .utils import get_userinfo
|
||||
|
||||
arc = module('arcaea', developers=['OasisAkari'], desc='{arcaea.help.desc}',
|
||||
alias={'b30': 'arcaea b30', 'a': 'arcaea', 'arc': 'arcaea'})
|
||||
alias=['a', 'arc'])
|
||||
webrender = Config('web_render')
|
||||
assets_path = os.path.abspath('./assets/arcaea')
|
||||
api = Config("botarcapi_url")
|
||||
|
|
|
@ -63,7 +63,7 @@ async def exchange(base_currency, target_currency, amount: float, msg):
|
|||
raise NoReportException(f"{error_type}")
|
||||
|
||||
|
||||
@excr.regex(r"(\d+(\.\d+)?)?\s?([a-zA-Z]{3})[兑|换|兌|換]([a-zA-Z]{3})", desc='{exchange_rate.help.regex.desc}')
|
||||
@excr.regex(r"(\d+(\.\d+)?)?\s?([a-zA-Z]{3})\s?[兑|换|兌|換]\s?([a-zA-Z]{3})", desc='{exchange_rate.help.regex.desc}')
|
||||
async def _(msg: Bot.MessageSession):
|
||||
groups = msg.matched_msg.groups()
|
||||
amount = groups[0] if groups[0] else '1'
|
||||
|
|
|
@ -1,2 +1,348 @@
|
|||
from .maimai import *
|
||||
from .regex import *
|
||||
from core.builtins import Bot, Plain, Image as BImage
|
||||
from core.builtins import command_prefix
|
||||
from core.component import module
|
||||
from core.logger import Logger
|
||||
from core.utils.image import msgchain2image
|
||||
from modules.maimai.libraries.maimai_best_50 import generate
|
||||
from modules.maimai.libraries.maimaidx_api_data import get_alias, get_rank
|
||||
from modules.maimai.libraries.maimaidx_music import *
|
||||
from .regex import *
|
||||
|
||||
total_list = TotalList()
|
||||
|
||||
diff_label = ['Basic', 'Advanced', 'Expert', 'Master', 'Re:MASTER']
|
||||
diff_label_abbr = ['bas', 'adv', 'exp', 'mas', 'rem']
|
||||
diff_label_zhs = ['绿', '黄', '红', '紫', '白']
|
||||
diff_label_zht = ['綠', '黃', '紅']
|
||||
|
||||
|
||||
def song_txt(music: Music):
|
||||
return [Plain(f"{music.id} {music.title}{' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"https://www.diving-fish.com/covers/{get_cover_len5_id(music.id)}.png", ),
|
||||
Plain(f"\n{'/'.join(str(ds) for ds in music.ds)}")]
|
||||
|
||||
|
||||
def get_diff(diff):
|
||||
diff = diff.lower()
|
||||
diff_label_lower = [label.lower() for label in diff_label]
|
||||
|
||||
if diff in diff_label_zhs:
|
||||
level = diff_label_zhs.index(diff)
|
||||
elif diff in diff_label_zht:
|
||||
level = diff_label_zht.index(diff)
|
||||
elif diff in diff_label_abbr:
|
||||
level = diff_label_abbr.index(diff)
|
||||
elif diff in diff_label_lower:
|
||||
level = diff_label_lower.index(diff)
|
||||
else:
|
||||
level = None
|
||||
return level
|
||||
|
||||
|
||||
mai = module('maimai', developers=['mai-bot', 'OasisAkari', 'DoroWolf'], alias='mai',
|
||||
desc='{maimai.help.desc}')
|
||||
|
||||
|
||||
@mai.handle('level <level> {{maimai.help.level}}')
|
||||
async def _(msg: Bot.MessageSession, level: str):
|
||||
result_set = await diff_level_q(level)
|
||||
s = msg.locale.t("maimai.message.level", level=level) + "\n"
|
||||
for elem in result_set:
|
||||
s += f"{elem[0]} {elem[1]}{' (DX)' if elem[5] == 'DX' else ''} {elem[3]} {elem[4]} ({elem[2]})\n"
|
||||
if len(result_set) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(result_set) <= 10:
|
||||
await msg.finish(s.strip())
|
||||
else:
|
||||
img = await msgchain2image([Plain(s)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
async def diff_level_q(level):
|
||||
result_set = []
|
||||
music_data = (await total_list.get()).filter(level=level)
|
||||
for music in sorted(music_data, key=lambda i: int(i['id'])):
|
||||
for i in music.diff:
|
||||
result_set.append(
|
||||
(music['id'],
|
||||
music['title'],
|
||||
music['ds'][i],
|
||||
diff_label[i],
|
||||
music['level'][i],
|
||||
music['type']))
|
||||
return result_set
|
||||
|
||||
|
||||
@mai.handle('base <rating> [<rating_max>] {{maimai.help.base}}')
|
||||
async def _(msg: Bot.MessageSession, rating: float, rating_max: float = None):
|
||||
if rating_max is not None:
|
||||
if rating > rating_max:
|
||||
return await msg.finish(msg.locale.t('error.range.invalid'))
|
||||
result_set = await base_level_q(rating, rating_max)
|
||||
s = msg.locale.t("maimai.message.base.range", rating=round(rating, 1), rating_max=round(rating_max, 1)) + "\n"
|
||||
else:
|
||||
result_set = await base_level_q(rating)
|
||||
s = msg.locale.t("maimai.message.base", rating=round(rating, 1)) + "\n"
|
||||
for elem in result_set:
|
||||
s += f"{elem[0]} {elem[1]}{' (DX)' if elem[5] == 'DX' else ''} {elem[3]} {elem[4]} ({elem[2]})\n"
|
||||
if len(result_set) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(result_set) > 200:
|
||||
return await msg.finish(msg.locale.t("maimai.message.too_much", length=len(result_set)))
|
||||
if len(result_set) <= 10:
|
||||
await msg.finish(s.strip())
|
||||
else:
|
||||
img = await msgchain2image([Plain(s)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
async def base_level_q(ds1, ds2=None):
|
||||
result_set = []
|
||||
if ds2 is not None:
|
||||
music_data = (await total_list.get()).filter(ds=(ds1, ds2))
|
||||
else:
|
||||
music_data = (await total_list.get()).filter(ds=ds1)
|
||||
for music in sorted(music_data, key=lambda i: int(i['id'])):
|
||||
for i in music.diff:
|
||||
result_set.append(
|
||||
(music['id'],
|
||||
music['title'],
|
||||
music['ds'][i],
|
||||
diff_label[i],
|
||||
music['level'][i],
|
||||
music['type']))
|
||||
return result_set
|
||||
|
||||
|
||||
@mai.handle('search <keyword> {{maimai.help.search}}')
|
||||
async def _(msg: Bot.MessageSession, keyword: str):
|
||||
name = keyword.strip()
|
||||
res = (await total_list.get()).filter(title_search=name)
|
||||
if len(res) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(res) > 200:
|
||||
return await msg.finish(msg.locale.t("maimai.message.too_much", length=len(res)))
|
||||
else:
|
||||
search_result = msg.locale.t("maimai.message.search", keyword=name) + "\n"
|
||||
for music in sorted(res, key=lambda i: int(i['id'])):
|
||||
search_result += f"{music['id']} {music['title']}{' (DX)' if music['type'] == 'DX' else ''}\n"
|
||||
if len(res) <= 10:
|
||||
await msg.finish([Plain(search_result.strip())])
|
||||
else:
|
||||
img = await msgchain2image([Plain(search_result)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('alias <sid> {{maimai.help.alias}}')
|
||||
async def _(msg: Bot.MessageSession, sid: str):
|
||||
if not sid.isdigit():
|
||||
await msg.finish(msg.locale.t('maimai.message.error.non_digital'))
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
title = f"{music['title']}{' (DX)' if music['type'] == 'DX' else ''}"
|
||||
alias = await get_alias(sid)
|
||||
if len(alias) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.alias_not_found"))
|
||||
else:
|
||||
result = msg.locale.t("maimai.message.alias", title=title) + "\n"
|
||||
result += "\n".join(alias)
|
||||
await msg.finish([Plain(result.strip())])
|
||||
|
||||
|
||||
@mai.handle('b40 [<username>] {{maimai.help.b40}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender, 'b50': True}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username, 'b50': True}
|
||||
await msg.sendMessage(msg.locale.t("maimai.message.b40.deprecated"))
|
||||
img, success = await generate(payload)
|
||||
if success == 400:
|
||||
await msg.finish(msg.locale.t("maimai.message.user_not_found"))
|
||||
elif success == 403:
|
||||
await msg.finish(msg.locale.t("maimai.message.forbidden"))
|
||||
else:
|
||||
if img:
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('b50 [<username>] {{maimai.help.b50}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender, 'b50': True}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username, 'b50': True}
|
||||
img, success = await generate(payload)
|
||||
if success == 400:
|
||||
await msg.finish(msg.locale.t("maimai.message.user_not_found"))
|
||||
elif success == 403:
|
||||
await msg.finish(msg.locale.t("maimai.message.forbidden"))
|
||||
else:
|
||||
if img:
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('rank [<username>] {{maimai.help.rank}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username}
|
||||
|
||||
result = await get_rank(msg, payload)
|
||||
time, total_rank, average_rating, username, rating, rank, surpassing_rate = result
|
||||
formatted_average_rating = "{:.4f}".format(average_rating)
|
||||
formatted_surpassing_rate = "{:.2f}".format(surpassing_rate)
|
||||
|
||||
await msg.finish(msg.locale.t('maimai.message.rank', time=time, total_rank=total_rank, user=username,
|
||||
rating=rating, rank=rank, average_rating=formatted_average_rating,
|
||||
surpassing_rate=formatted_surpassing_rate))
|
||||
|
||||
|
||||
@mai.handle('random <diff+level> [<dx_type>] {{maimai.help.random.filter}}')
|
||||
async def _(msg: Bot.MessageSession, dx_type: str = None):
|
||||
filter = msg.parsed_msg['<diff+level>']
|
||||
level = ''
|
||||
diff = ''
|
||||
try:
|
||||
if dx_type in ["dx", "DX"]:
|
||||
dx_type = ["DX"]
|
||||
elif dx_type in ["sd", "SD", "标准", "標準"]:
|
||||
dx_type = ["SD"]
|
||||
else:
|
||||
dx_type = ["SD", "DX"]
|
||||
|
||||
for char in filter:
|
||||
if char.isdigit() or char == '+':
|
||||
level += char
|
||||
else:
|
||||
diff += char
|
||||
|
||||
if level == "":
|
||||
if diff == "#":
|
||||
music_data = (await total_list.get()).filter(type=dx_type)
|
||||
else:
|
||||
raise ValueError
|
||||
else:
|
||||
if diff == "":
|
||||
music_data = (await total_list.get()).filter(level=level, type=dx_type)
|
||||
else:
|
||||
music_data = (await total_list.get()).filter(level=level, diff=[get_diff(diff)], type=dx_type)
|
||||
|
||||
if len(music_data) == 0:
|
||||
rand_result = msg.locale.t("maimai.message.music_not_found")
|
||||
else:
|
||||
rand_result = song_txt(music_data.random())
|
||||
await msg.finish(rand_result)
|
||||
except Exception as e:
|
||||
Logger.error(e)
|
||||
await msg.finish(msg.locale.t("maimai.message.random.error"))
|
||||
|
||||
|
||||
@mai.handle('random {{maimai.help.random}}')
|
||||
async def _(msg: Bot.MessageSession):
|
||||
await msg.finish(song_txt((await total_list.get()).random()))
|
||||
|
||||
|
||||
@mai.handle('song <id_or_alias> [<diff>] {{maimai.help.song}}')
|
||||
async def _(msg: Bot.MessageSession, id_or_alias: str, diff: str = None):
|
||||
if id_or_alias.isdigit():
|
||||
sid = id_or_alias
|
||||
else:
|
||||
sid_list = await get_alias(id_or_alias, get_music=True)
|
||||
if len(sid_list) == 0:
|
||||
await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
elif len(sid_list) > 1:
|
||||
res = msg.locale.t("maimai.message.song.prompt") + "\n"
|
||||
for sid in sorted(sid_list, key=int):
|
||||
s = (await total_list.get()).by_id(sid)
|
||||
res += f"{s['id']} {s['title']}{' (DX)' if s['type'] == 'DX' else ''}\n"
|
||||
await msg.finish(res.strip())
|
||||
else:
|
||||
sid = str(sid_list[0])
|
||||
|
||||
if diff is not None:
|
||||
diff_index = get_diff(diff)
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
if music is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.chart_not_found"))
|
||||
chart = music['charts'][diff_index]
|
||||
ds = music['ds'][diff_index]
|
||||
level = music['level'][diff_index]
|
||||
file = f"https://www.diving-fish.com/covers/{get_cover_len5_id(music['id'])}.png"
|
||||
if len(chart['notes']) == 4:
|
||||
msg = msg.locale.t(
|
||||
"maimai.message.song.sd",
|
||||
diff=diff_label[diff_index],
|
||||
level=level,
|
||||
ds=ds,
|
||||
tap=chart['notes'][0],
|
||||
hold=chart['notes'][1],
|
||||
slide=chart['notes'][2],
|
||||
brk=chart['notes'][3],
|
||||
charter=chart['charter'])
|
||||
else:
|
||||
msg = msg.locale.t(
|
||||
"maimai.message.song.dx",
|
||||
diff=diff_label[diff_index],
|
||||
level=level,
|
||||
ds=ds,
|
||||
tap=chart['notes'][0],
|
||||
hold=chart['notes'][1],
|
||||
slide=chart['notes'][2],
|
||||
touch=chart['notes'][3],
|
||||
brk=chart['notes'][4],
|
||||
charter=chart['charter'])
|
||||
await msg.finish(
|
||||
[Plain(f"{music['id']} {music['title']} {' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"{file}"), Plain(msg)])
|
||||
else:
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
if music is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
file = f"https://www.diving-fish.com/covers/{get_cover_len5_id(music['id'])}.png"
|
||||
await msg.finish(
|
||||
[Plain(f"{music['id']} {music['title']} {' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"{file}"),
|
||||
Plain(msg.locale.t("maimai.message.song",
|
||||
artist=music['basic_info']['artist'], genre=music['basic_info']['genre'],
|
||||
bpm=music['basic_info']['bpm'], version=music['basic_info']['from'],
|
||||
level='/'.join((str(ds) for ds in music['ds']))))])
|
||||
|
||||
|
||||
@mai.handle('scoreline <sid> <diff> <scoreline> {{maimai.help.scoreline}}')
|
||||
async def _(msg: Bot.MessageSession, diff: str, sid: str, scoreline: float):
|
||||
try:
|
||||
diff_index = get_diff(diff)
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
chart: Dict[Any] = music['charts'][diff_index]
|
||||
tap = int(chart['notes'][0])
|
||||
slide = int(chart['notes'][2])
|
||||
hold = int(chart['notes'][1])
|
||||
touch = int(chart['notes'][3]) if len(chart['notes']) == 5 else 0
|
||||
brk = int(chart['notes'][-1])
|
||||
total_score = 500 * tap + slide * 1500 + hold * 1000 + touch * 500 + brk * 2500
|
||||
break_bonus = 0.01 / brk
|
||||
break_50_reduce = total_score * break_bonus / 4
|
||||
reduce = 101 - scoreline
|
||||
if reduce <= 0 or reduce >= 101:
|
||||
raise ValueError
|
||||
tap_great = "{:.2f}".format(total_score * reduce / 10000)
|
||||
tap_great_prop = "{:.4f}".format(10000 / total_score)
|
||||
b2t_great = "{:.3f}".format(break_50_reduce / 100)
|
||||
b2t_great_prop = "{:.4f}".format(break_50_reduce / total_score * 100)
|
||||
await msg.finish(f'''{music['title']}{' (DX)' if music['type'] == 'DX' else ''} {diff_label[diff_index]}
|
||||
{msg.locale.t('maimai.message.scoreline',
|
||||
scoreline=scoreline,
|
||||
tap_great=tap_great,
|
||||
tap_great_prop=tap_great_prop,
|
||||
brk=brk,
|
||||
b2t_great=b2t_great,
|
||||
b2t_great_prop=b2t_great_prop)}''')
|
||||
except Exception:
|
||||
await msg.finish(msg.locale.t('maimai.message.scoreline.error', prefix=command_prefix[0]))
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import time
|
||||
|
||||
|
||||
def hash_(s):
|
||||
days = int(time.strftime("%d", time.localtime(time.time()))) + 31 * int(
|
||||
time.strftime("%m", time.localtime(time.time()))) + 77
|
||||
return (days * hash(s)) >> 8
|
|
@ -2,7 +2,7 @@
|
|||
"maimai.help.b40": "查询 B40 信息。(已弃用)",
|
||||
"maimai.help.b50": "查询 B50 信息。(仅限大陆版舞萌)",
|
||||
"maimai.help.desc": "查询 Maimai 相关内容。",
|
||||
"maimai.help.inner": "根据定数或定数范围搜索歌曲。",
|
||||
"maimai.help.base": "根据定数或定数范围搜索歌曲。",
|
||||
"maimai.help.level": "根据等级搜索歌曲。",
|
||||
"maimai.help.random": "随机一首歌曲。",
|
||||
"maimai.help.random.filter": "随机一首指定条件的歌曲,输入为“#”则表示无条件。",
|
||||
|
@ -10,8 +10,8 @@
|
|||
"maimai.help.song": "查询 Maimai 歌曲或谱面的信息。",
|
||||
"maimai.message.chart_not_found": "未找到符合要求的谱面。",
|
||||
"maimai.message.forbidden": "此用户禁止了其他人获取数据。",
|
||||
"maimai.message.inner": "以下为定数 ${rating} 的曲目列表:",
|
||||
"maimai.message.inner.range": "以下为定数 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.base": "以下为定数 ${rating} 的曲目列表:",
|
||||
"maimai.message.base.range": "以下为定数 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.level": "以下为难度 ${level} 的曲目列表:",
|
||||
"maimai.message.music_not_found": "未找到符合要求的歌曲。",
|
||||
"maimai.message.no_username": "请提供用户名!",
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
"maimai.help.b40": "查询 B40 信息。(已弃用)",
|
||||
"maimai.help.b50": "查询 B50 信息。(仅限大陆版 Maimai)",
|
||||
"maimai.help.desc": "查询 Maimai 相关内容。",
|
||||
"maimai.help.inner": "根据定数或定数范围搜索歌曲。",
|
||||
"maimai.help.base": "根据定数或定数范围搜索歌曲。",
|
||||
"maimai.help.level": "根据等级搜索歌曲。",
|
||||
"maimai.help.random": "随机一首歌曲。",
|
||||
"maimai.help.maimai_regex.desc": "更方便地使用 Maimai 相关命令。",
|
||||
"maimai.help.maimai_regex.song": "<ID 或别名>是什么歌 输入 ID 或别名查询歌曲,ID 前需加入“id”",
|
||||
"maimai.help.maimai_regex.random": "Maimai什么 随机一首歌曲",
|
||||
"maimai.help.maimai_regex.random.filter": "随个[dx/标准][绿黄红紫白]<难度> 随机一首指定条件的歌曲",
|
||||
"maimai.help.random.filter": "随机一首指定条件的歌曲,输入为“#”则表示无条件。",
|
||||
"maimai.help.rank": "查看用户在查分器上的分数排行。",
|
||||
"maimai.help.scoreline": "查询歌曲的分数线。",
|
||||
|
@ -19,8 +21,8 @@
|
|||
"maimai.message.chart_not_found": "未找到符合要求的谱面。",
|
||||
"maimai.message.error.non_digital": "发生错误:歌曲 ID 必须为数字!",
|
||||
"maimai.message.forbidden": "此用户禁止了其他人获取数据。",
|
||||
"maimai.message.inner": "以下为定数 ${rating} 的曲目列表:",
|
||||
"maimai.message.inner.range": "以下为定数 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.base": "以下为定数 ${rating} 的曲目列表:",
|
||||
"maimai.message.base.range": "以下为定数 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.level": "以下为难度 ${level} 的曲目列表:",
|
||||
"maimai.message.music_not_found": "未找到符合要求的歌曲。",
|
||||
"maimai.message.no_username": "请提供用户名!",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"maimai.help.b40": "查詢 B40 訊息。(已棄用)",
|
||||
"maimai.help.b50": "查詢 B50 訊息。(僅限中國版 Maimai)",
|
||||
"maimai.help.desc": "查詢 Maimai 相關的內容。",
|
||||
"maimai.help.inner": "依據定數或定數範圍內搜尋歌曲。",
|
||||
"maimai.help.base": "依據定數或定數範圍內搜尋歌曲。",
|
||||
"maimai.help.level": "依據等級搜尋歌曲。",
|
||||
"maimai.help.random": "隨機一首歌曲。",
|
||||
"maimai.help.random.filter": "隨機一首指定條件的歌曲,輸入為「#」則表示無條件。",
|
||||
|
@ -10,8 +10,8 @@
|
|||
"maimai.help.song": "查詢 Maimai 歌曲或譜面的訊息。",
|
||||
"maimai.message.chart_not_found": "未找到符合要求的譜面。",
|
||||
"maimai.message.forbidden": "此使用者禁止了其他人取得資料。",
|
||||
"maimai.message.inner": "以下為定數 ${rating} 的曲目列表:",
|
||||
"maimai.message.inner.range": "以下為定數 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.base": "以下為定數 ${rating} 的曲目列表:",
|
||||
"maimai.message.base.range": "以下為定數 ${rating}-${rating_max} 的曲目列表:",
|
||||
"maimai.message.level": "以下為難度 ${level} 的曲目列表:",
|
||||
"maimai.message.music_not_found": "未找到符合要求的歌曲。",
|
||||
"maimai.message.no_username": "請提供使用者名稱!",
|
||||
|
|
|
@ -1,334 +0,0 @@
|
|||
from core.builtins import Bot, Plain, Image as BImage
|
||||
from core.builtins import command_prefix
|
||||
from core.component import module
|
||||
from core.logger import Logger
|
||||
from core.utils.image import msgchain2image
|
||||
from modules.maimai.libraries.maimai_best_50 import generate
|
||||
from modules.maimai.libraries.maimaidx_api_data import get_alias, get_rank
|
||||
from modules.maimai.libraries.maimaidx_music import *
|
||||
|
||||
total_list = TotalList()
|
||||
|
||||
diff_label = ['Basic', 'Advanced', 'Expert', 'Master', 'Re:MASTER']
|
||||
diff_label_abbr = ['bas', 'adv', 'exp', 'mas', 'rem']
|
||||
diff_label_zhs = ['绿', '黄', '红', '紫', '白']
|
||||
diff_label_zht = ['綠', '黃', '紅']
|
||||
|
||||
|
||||
def song_txt(music: Music):
|
||||
return [Plain(f"{music.id} {music.title}{' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"https://www.diving-fish.com/covers/{get_cover_len5_id(music.id)}.png", ),
|
||||
Plain(f"\n{'/'.join(str(ds) for ds in music.ds)}")]
|
||||
|
||||
|
||||
def get_diff(diff):
|
||||
diff = diff.lower()
|
||||
diff_label_lower = [label.lower() for label in diff_label]
|
||||
|
||||
if diff in diff_label_zhs:
|
||||
level = diff_label_zhs.index(diff)
|
||||
elif diff in diff_label_zht:
|
||||
level = diff_label_zht.index(diff)
|
||||
elif diff in diff_label_abbr:
|
||||
level = diff_label_abbr.index(diff)
|
||||
elif diff in diff_label_lower:
|
||||
level = diff_label_lower.index(diff)
|
||||
else:
|
||||
level = None
|
||||
return level
|
||||
|
||||
|
||||
mai = module('maimai', developers=['mai-bot', 'OasisAkari', 'DoroWolf'], alias='mai',
|
||||
desc='{maimai.help.desc}')
|
||||
|
||||
|
||||
@mai.handle('level <level> {{maimai.help.level}}')
|
||||
async def _(msg: Bot.MessageSession, level: str):
|
||||
result_set = await diff_level_q(level)
|
||||
s = msg.locale.t("maimai.message.level", level=level) + "\n"
|
||||
for elem in result_set:
|
||||
s += f"{elem[0]} {elem[1]}{' (DX)' if elem[5] == 'DX' else ''} {elem[3]} {elem[4]} ({elem[2]})\n"
|
||||
if len(result_set) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(result_set) <= 10:
|
||||
await msg.finish(s.strip())
|
||||
else:
|
||||
img = await msgchain2image([Plain(s)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
async def diff_level_q(level):
|
||||
result_set = []
|
||||
music_data = (await total_list.get()).filter(level=level)
|
||||
for music in sorted(music_data, key=lambda i: int(i['id'])):
|
||||
for i in music.diff:
|
||||
result_set.append(
|
||||
(music['id'],
|
||||
music['title'],
|
||||
music['ds'][i],
|
||||
diff_label[i],
|
||||
music['level'][i],
|
||||
music['type']))
|
||||
return result_set
|
||||
|
||||
|
||||
@mai.handle('inner <rating> [<rating_max>] {{maimai.help.inner}}')
|
||||
async def _(msg: Bot.MessageSession, rating: float, rating_max: float = None):
|
||||
if rating_max is not None:
|
||||
if rating > rating_max:
|
||||
return await msg.finish(msg.locale.t('error.range.invalid'))
|
||||
result_set = await inner_level_q(rating, rating_max)
|
||||
s = msg.locale.t("maimai.message.inner.range", rating=round(rating, 1), rating_max=round(rating_max, 1)) + "\n"
|
||||
else:
|
||||
result_set = await inner_level_q(rating)
|
||||
s = msg.locale.t("maimai.message.inner", rating=round(rating, 1)) + "\n"
|
||||
for elem in result_set:
|
||||
s += f"{elem[0]} {elem[1]}{' (DX)' if elem[5] == 'DX' else ''} {elem[3]} {elem[4]} ({elem[2]})\n"
|
||||
if len(result_set) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(result_set) > 200:
|
||||
return await msg.finish(msg.locale.t("maimai.message.too_much", length=len(result_set)))
|
||||
if len(result_set) <= 10:
|
||||
await msg.finish(s.strip())
|
||||
else:
|
||||
img = await msgchain2image([Plain(s)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
async def inner_level_q(ds1, ds2=None):
|
||||
result_set = []
|
||||
if ds2 is not None:
|
||||
music_data = (await total_list.get()).filter(ds=(ds1, ds2))
|
||||
else:
|
||||
music_data = (await total_list.get()).filter(ds=ds1)
|
||||
for music in sorted(music_data, key=lambda i: int(i['id'])):
|
||||
for i in music.diff:
|
||||
result_set.append(
|
||||
(music['id'],
|
||||
music['title'],
|
||||
music['ds'][i],
|
||||
diff_label[i],
|
||||
music['level'][i],
|
||||
music['type']))
|
||||
return result_set
|
||||
|
||||
|
||||
@mai.handle('search <keyword> {{maimai.help.search}}')
|
||||
async def _(msg: Bot.MessageSession, keyword: str):
|
||||
name = keyword.strip()
|
||||
res = (await total_list.get()).filter(title_search=name)
|
||||
if len(res) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
if len(res) > 200:
|
||||
return await msg.finish(msg.locale.t("maimai.message.too_much", length=len(res)))
|
||||
else:
|
||||
search_result = msg.locale.t("maimai.message.search", keyword=name) + "\n"
|
||||
for music in sorted(res, key=lambda i: int(i['id'])):
|
||||
search_result += f"{music['id']} {music['title']}{' (DX)' if music['type'] == 'DX' else ''}\n"
|
||||
if len(res) <= 10:
|
||||
await msg.finish([Plain(search_result.strip())])
|
||||
else:
|
||||
img = await msgchain2image([Plain(search_result)])
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('alias <sid> {{maimai.help.alias}}')
|
||||
async def _(msg: Bot.MessageSession, sid: str):
|
||||
if not sid.isdigit():
|
||||
await msg.finish(msg.locale.t('maimai.message.error.non_digital'))
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
title = f"{music['title']}{' (DX)' if music['type'] == 'DX' else ''}"
|
||||
alias = await get_alias(sid)
|
||||
if len(alias) == 0:
|
||||
return await msg.finish(msg.locale.t("maimai.message.alias_not_found"))
|
||||
else:
|
||||
result = msg.locale.t("maimai.message.alias", title=title) + "\n"
|
||||
result += "\n".join(alias)
|
||||
await msg.finish([Plain(result.strip())])
|
||||
|
||||
|
||||
@mai.handle('b40 [<username>] {{maimai.help.b40}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender, 'b50': True}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username, 'b50': True}
|
||||
await msg.sendMessage(msg.locale.t("maimai.message.b40.deprecated"))
|
||||
img, success = await generate(payload)
|
||||
if success == 400:
|
||||
await msg.finish(msg.locale.t("maimai.message.user_not_found"))
|
||||
elif success == 403:
|
||||
await msg.finish(msg.locale.t("maimai.message.forbidden"))
|
||||
else:
|
||||
if img:
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('b50 [<username>] {{maimai.help.b50}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender, 'b50': True}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username, 'b50': True}
|
||||
img, success = await generate(payload)
|
||||
if success == 400:
|
||||
await msg.finish(msg.locale.t("maimai.message.user_not_found"))
|
||||
elif success == 403:
|
||||
await msg.finish(msg.locale.t("maimai.message.forbidden"))
|
||||
else:
|
||||
if img:
|
||||
await msg.finish([BImage(img)])
|
||||
|
||||
|
||||
@mai.handle('rank [<username>] {{maimai.help.rank}}')
|
||||
async def _(msg: Bot.MessageSession, username: str = None):
|
||||
if username is None and msg.target.senderFrom == "QQ":
|
||||
payload = {'qq': msg.session.sender}
|
||||
else:
|
||||
if username is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.no_username"))
|
||||
payload = {'username': username}
|
||||
|
||||
result = await get_rank(msg, payload)
|
||||
time, total_rank, average_rating, username, rating, rank, surpassing_rate = result
|
||||
formatted_average_rating = "{:.4f}".format(average_rating)
|
||||
formatted_surpassing_rate = "{:.2f}".format(surpassing_rate)
|
||||
|
||||
await msg.finish(msg.locale.t('maimai.message.rank', time=time, total_rank=total_rank, user=username,
|
||||
rating=rating, rank=rank, average_rating=formatted_average_rating,
|
||||
surpassing_rate=formatted_surpassing_rate))
|
||||
|
||||
|
||||
@mai.handle('random <diff+level> [<dx_type>] {{maimai.help.random.filter}}')
|
||||
async def _(msg: Bot.MessageSession, dx_type: str = None):
|
||||
filter = msg.parsed_msg['<diff+level>']
|
||||
level = ''
|
||||
diff = ''
|
||||
try:
|
||||
if dx_type in ["dx", "DX"]:
|
||||
dx_type = ["DX"]
|
||||
elif dx_type in ["sd", "SD", "标准", "標準"]:
|
||||
dx_type = ["SD"]
|
||||
else:
|
||||
dx_type = ["SD", "DX"]
|
||||
|
||||
for char in filter:
|
||||
if char.isdigit() or char == '+':
|
||||
level += char
|
||||
else:
|
||||
diff += char
|
||||
|
||||
if level == "":
|
||||
if diff == "#":
|
||||
music_data = (await total_list.get()).filter(type=dx_type)
|
||||
else:
|
||||
raise ValueError
|
||||
else:
|
||||
if diff == "":
|
||||
music_data = (await total_list.get()).filter(level=level, type=dx_type)
|
||||
else:
|
||||
music_data = (await total_list.get()).filter(level=level, diff=[get_diff(diff)], type=dx_type)
|
||||
|
||||
if len(music_data) == 0:
|
||||
rand_result = msg.locale.t("maimai.message.music_not_found")
|
||||
else:
|
||||
rand_result = song_txt(music_data.random())
|
||||
await msg.finish(rand_result)
|
||||
except Exception as e:
|
||||
Logger.error(e)
|
||||
await msg.finish(msg.locale.t("maimai.message.random.error"))
|
||||
|
||||
|
||||
@mai.handle('random {{maimai.help.random}}')
|
||||
async def _(msg: Bot.MessageSession):
|
||||
await msg.finish(song_txt((await total_list.get()).random()))
|
||||
|
||||
|
||||
@mai.handle('song <sid> [<diff>] {{maimai.help.song}}')
|
||||
async def _(msg: Bot.MessageSession, sid: str, diff: str = None):
|
||||
if not sid.isdigit():
|
||||
await msg.finish(msg.locale.t('maimai.message.error.non_digital'))
|
||||
if diff is not None:
|
||||
diff_index = get_diff(diff)
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
if music is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.chart_not_found"))
|
||||
chart = music['charts'][diff_index]
|
||||
ds = music['ds'][diff_index]
|
||||
level = music['level'][diff_index]
|
||||
file = f"https://www.diving-fish.com/covers/{get_cover_len5_id(music['id'])}.png"
|
||||
if len(chart['notes']) == 4:
|
||||
msg = msg.locale.t(
|
||||
"maimai.message.song.sd",
|
||||
diff=diff_label[diff_index],
|
||||
level=level,
|
||||
ds=ds,
|
||||
tap=chart['notes'][0],
|
||||
hold=chart['notes'][1],
|
||||
slide=chart['notes'][2],
|
||||
brk=chart['notes'][3],
|
||||
charter=chart['charter'])
|
||||
else:
|
||||
msg = msg.locale.t(
|
||||
"maimai.message.song.dx",
|
||||
diff=diff_label[diff_index],
|
||||
level=level,
|
||||
ds=ds,
|
||||
tap=chart['notes'][0],
|
||||
hold=chart['notes'][1],
|
||||
slide=chart['notes'][2],
|
||||
touch=chart['notes'][3],
|
||||
brk=chart['notes'][4],
|
||||
charter=chart['charter'])
|
||||
await msg.finish(
|
||||
[Plain(f"{music['id']} {music['title']} {' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"{file}"), Plain(msg)])
|
||||
else:
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
if music is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
file = f"https://www.diving-fish.com/covers/{get_cover_len5_id(music['id'])}.png"
|
||||
await msg.finish(
|
||||
[Plain(f"{music['id']} {music['title']} {' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"{file}"),
|
||||
Plain(msg.locale.t("maimai.message.song",
|
||||
artist=music['basic_info']['artist'], genre=music['basic_info']['genre'],
|
||||
bpm=music['basic_info']['bpm'], version=music['basic_info']['from'],
|
||||
level='/'.join((str(ds) for ds in music['ds']))))])
|
||||
|
||||
|
||||
@mai.handle('scoreline <sid> <diff> <scoreline> {{maimai.help.scoreline}}')
|
||||
async def _(msg: Bot.MessageSession, diff: str, sid: str, scoreline: float):
|
||||
try:
|
||||
diff_index = get_diff(diff)
|
||||
music = (await total_list.get()).by_id(sid)
|
||||
chart: Dict[Any] = music['charts'][diff_index]
|
||||
tap = int(chart['notes'][0])
|
||||
slide = int(chart['notes'][2])
|
||||
hold = int(chart['notes'][1])
|
||||
touch = int(chart['notes'][3]) if len(chart['notes']) == 5 else 0
|
||||
brk = int(chart['notes'][-1])
|
||||
total_score = 500 * tap + slide * 1500 + hold * 1000 + touch * 500 + brk * 2500
|
||||
break_bonus = 0.01 / brk
|
||||
break_50_reduce = total_score * break_bonus / 4
|
||||
reduce = 101 - scoreline
|
||||
if reduce <= 0 or reduce >= 101:
|
||||
raise ValueError
|
||||
tap_great = "{:.2f}".format(total_score * reduce / 10000)
|
||||
tap_great_prop = "{:.4f}".format(10000 / total_score)
|
||||
b2t_great = "{:.3f}".format(break_50_reduce / 100)
|
||||
b2t_great_prop = "{:.4f}".format(break_50_reduce / total_score * 100)
|
||||
await msg.finish(f'''{music['title']}{' (DX)' if music['type'] == 'DX' else ''} {diff_label[diff_index]}
|
||||
{msg.locale.t('maimai.message.scoreline',
|
||||
scoreline=scoreline,
|
||||
tap_great=tap_great,
|
||||
tap_great_prop=tap_great_prop,
|
||||
brk=brk,
|
||||
b2t_great=b2t_great,
|
||||
b2t_great_prop=b2t_great_prop)}''')
|
||||
except Exception:
|
||||
await msg.finish(msg.locale.t('maimai.message.scoreline.error', prefix=command_prefix[0]))
|
|
@ -1,5 +1,6 @@
|
|||
import re
|
||||
|
||||
from core.logger import Logger
|
||||
from core.builtins import Bot, Plain, Image as BImage
|
||||
from core.component import module
|
||||
from modules.maimai.libraries.maimaidx_api_data import get_alias
|
||||
|
@ -7,18 +8,47 @@ from modules.maimai.libraries.maimaidx_music import *
|
|||
|
||||
total_list = TotalList()
|
||||
|
||||
diff_label = ['Basic', 'Advanced', 'Expert', 'Master', 'Re:MASTER']
|
||||
diff_label_abbr = ['bas', 'adv', 'exp', 'mas', 'rem']
|
||||
diff_label_zhs = ['绿', '黄', '红', '紫', '白']
|
||||
diff_label_zht = ['綠', '黃', '紅']
|
||||
|
||||
|
||||
def song_txt(music: Music):
|
||||
return [Plain(f"{music.id} {music.title}{' (DX)' if music['type'] == 'DX' else ''}\n"),
|
||||
BImage(f"https://www.diving-fish.com/covers/{get_cover_len5_id(music.id)}.png", ),
|
||||
Plain(f"\n{'/'.join(str(ds) for ds in music.ds)}")]
|
||||
|
||||
|
||||
def get_diff(diff):
|
||||
diff = diff.lower()
|
||||
diff_label_lower = [label.lower() for label in diff_label]
|
||||
|
||||
if diff in diff_label_zhs:
|
||||
level = diff_label_zhs.index(diff)
|
||||
elif diff in diff_label_zht:
|
||||
level = diff_label_zht.index(diff)
|
||||
elif diff in diff_label_abbr:
|
||||
level = diff_label_abbr.index(diff)
|
||||
elif diff in diff_label_lower:
|
||||
level = diff_label_lower.index(diff)
|
||||
else:
|
||||
level = None
|
||||
return level
|
||||
|
||||
|
||||
mai_regex = module('maimai_regex',
|
||||
desc='{maimai.help.maimai_regex.desc}', recommend_modules=['maimai'],
|
||||
alias='mai_regex', developers=['DoroWolf'])
|
||||
|
||||
|
||||
@mai_regex.handle(re.compile(r"(.+)是什么歌"), desc='{maimai.help.maimai_regex.song}')
|
||||
@mai_regex.handle(re.compile(r"(.+)\s?是(什么|什麼)歌"), desc='{maimai.help.maimai_regex.song}')
|
||||
async def _(msg: Bot.MessageSession):
|
||||
name = msg.matched_msg.groups()[0].strip()
|
||||
if name == "":
|
||||
return
|
||||
elif name.lower().startswith("id"):
|
||||
music = (await total_list.get()).by_id(name[2:])
|
||||
elif name.isdigit():
|
||||
music = (await total_list.get()).by_id(name)
|
||||
if music is None:
|
||||
await msg.finish(msg.locale.t("maimai.message.music_not_found"))
|
||||
else:
|
||||
|
@ -42,3 +72,37 @@ async def _(msg: Bot.MessageSession):
|
|||
artist=music['basic_info']['artist'], genre=music['basic_info']['genre'],
|
||||
bpm=music['basic_info']['bpm'], version=music['basic_info']['from'],
|
||||
level='/'.join((str(ds) for ds in music['ds']))))])
|
||||
|
||||
|
||||
@mai_regex.handle(re.compile(r"(随个|隨個)\s?((?:dx|DX|sd|SD|标准|標準)\s?)?([绿綠黄黃红紅紫白]?)\s?([0-9]+\+?)"),
|
||||
desc="{maimai.help.maimai_regex.random.filter}")
|
||||
async def _(msg: Bot.MessageSession):
|
||||
res = msg.matched_msg
|
||||
if res:
|
||||
try:
|
||||
if res.groups()[1] in ["dx", "DX"]:
|
||||
tp = ["DX"]
|
||||
elif res.groups()[1] in ["sd", "SD"] or res.groups()[1] in ["标准", "標準"]:
|
||||
tp = ["SD"]
|
||||
else:
|
||||
tp = ["SD", "DX"]
|
||||
level = res.groups()[3]
|
||||
if res.groups()[2] == "":
|
||||
music_data = (await total_list.get()).filter(level=level, type=tp)
|
||||
else:
|
||||
music_data = (await total_list.get()).filter(level=level, diff=get_diff(res.groups()[3]),
|
||||
type=tp)
|
||||
if len(music_data) == 0:
|
||||
rand_result = msg.locale.t("maimai.message.music_not_found")
|
||||
else:
|
||||
rand_result = song_txt(music_data.random())
|
||||
await msg.finish(rand_result)
|
||||
except Exception as e:
|
||||
Logger.error(e)
|
||||
await msg.finish(msg.locale.t("maimai.message.random.error"))
|
||||
|
||||
|
||||
|
||||
@mai_regex.handle(re.compile(r".*\s?(M|m)aimai\s?.*(什么|什麼)"), desc='{maimai.help.maimai_regex.random}')
|
||||
async def _(msg: Bot.MessageSession):
|
||||
await msg.finish(song_txt((await total_list.get()).random()))
|
||||
|
|
Reference in a new issue