nonebot-plugin-osubot 6.22.1__py3-none-any.whl → 6.26.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nonebot_plugin_osubot/api.py +13 -7
- nonebot_plugin_osubot/config.py +10 -10
- nonebot_plugin_osubot/draw/bmap.py +20 -22
- nonebot_plugin_osubot/draw/bp.py +3 -13
- nonebot_plugin_osubot/draw/catch_preview.py +2 -16
- nonebot_plugin_osubot/draw/echarts.py +8 -1
- nonebot_plugin_osubot/draw/info.py +59 -207
- nonebot_plugin_osubot/draw/info_templates/index.html +507 -0
- nonebot_plugin_osubot/draw/info_templates/output.css +2 -0
- nonebot_plugin_osubot/draw/map.py +9 -11
- nonebot_plugin_osubot/draw/osu_preview.py +50 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/css/style.css +258 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/README.md +109 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/beatmap.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/hitobject.js +29 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/point.js +55 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/scroll.js +45 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/timingpoint.js +35 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/LegacyRandom.js +81 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/PalpableCatchHitObject.js +53 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/bananashower.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/catch.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/fruit.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/juicestream.js +176 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/hitnote.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/holdnote.js +37 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/mania.js +164 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/preview.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/bezier2.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/catmullcurve.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/centripetalcatmullrom.js +30 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/circumstancedcircle.js +47 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curve.js +25 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curvetype.js +17 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/equaldistancemulticurve.js +70 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/linearbezier.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/hitcircle.js +85 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/slider.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/spinner.js +56 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/standard.js +170 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/donkat.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/drumroll.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/shaker.js +58 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/taiko.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/util.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/pic.html +110 -0
- nonebot_plugin_osubot/draw/rating.py +6 -3
- nonebot_plugin_osubot/draw/score.py +23 -81
- nonebot_plugin_osubot/draw/taiko_preview.py +14 -13
- nonebot_plugin_osubot/draw/templates/bpa_chart.html +1 -1
- nonebot_plugin_osubot/draw/utils.py +162 -16
- nonebot_plugin_osubot/file.py +184 -31
- nonebot_plugin_osubot/mania/__init__.py +9 -10
- nonebot_plugin_osubot/matcher/__init__.py +2 -0
- nonebot_plugin_osubot/matcher/bp_analyze.py +14 -9
- nonebot_plugin_osubot/matcher/guess.py +250 -294
- nonebot_plugin_osubot/matcher/map_convert.py +21 -13
- nonebot_plugin_osubot/matcher/medal.py +1 -1
- nonebot_plugin_osubot/matcher/osudl.py +5 -4
- nonebot_plugin_osubot/matcher/pr.py +0 -4
- nonebot_plugin_osubot/matcher/preview.py +10 -3
- nonebot_plugin_osubot/matcher/recommend.py +7 -12
- nonebot_plugin_osubot/mods.py +62 -61
- nonebot_plugin_osubot/network/first_response.py +1 -1
- nonebot_plugin_osubot/osufile/mods/AP.png +0 -0
- nonebot_plugin_osubot/osufile/mods/CL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/DT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/EZ.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FI.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/MR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NC.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/PF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/RX.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SO.png +0 -0
- nonebot_plugin_osubot/osufile/mods/TD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/V2.png +0 -0
- nonebot_plugin_osubot/pp.py +7 -0
- nonebot_plugin_osubot/schema/__init__.py +0 -2
- nonebot_plugin_osubot/schema/beatmapsets.py +42 -0
- nonebot_plugin_osubot/schema/draw_info.py +54 -0
- nonebot_plugin_osubot/schema/score.py +2 -0
- nonebot_plugin_osubot/schema/user.py +1 -0
- {nonebot_plugin_osubot-6.22.1.dist-info → nonebot_plugin_osubot-6.26.4.dist-info}/METADATA +18 -17
- {nonebot_plugin_osubot-6.22.1.dist-info → nonebot_plugin_osubot-6.26.4.dist-info}/RECORD +95 -52
- nonebot_plugin_osubot-6.26.4.dist-info/WHEEL +4 -0
- nonebot_plugin_osubot/schema/sayo_beatmap.py +0 -59
- nonebot_plugin_osubot-6.22.1.dist-info/WHEEL +0 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
+
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
|
3
4
|
from nonebot.rule import ArgumentParser
|
|
4
5
|
from nonebot.internal.adapter import Message
|
|
5
6
|
from nonebot_plugin_alconna import UniMessage
|
|
@@ -7,8 +8,10 @@ from nonebot import on_command, on_shell_command
|
|
|
7
8
|
from nonebot.exception import ParserExit, ActionFailed
|
|
8
9
|
from nonebot.params import CommandArg, ShellCommandArgv
|
|
9
10
|
|
|
10
|
-
from ..api import
|
|
11
|
+
from ..api import get_beatmapsets_info, osu_api
|
|
11
12
|
from ..mania import Options, convert_mania_map
|
|
13
|
+
from ..schema import Beatmap
|
|
14
|
+
from ..file import upload_file_stream_batch
|
|
12
15
|
|
|
13
16
|
parser = ArgumentParser("convert", description="变换mania谱面")
|
|
14
17
|
parser.add_argument("--set", type=int, help="要转换的谱面的setid")
|
|
@@ -37,9 +40,11 @@ async def _(argv: list[str] = ShellCommandArgv()):
|
|
|
37
40
|
return
|
|
38
41
|
options = Options(**vars(args))
|
|
39
42
|
if options.map:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
map_data = await osu_api("map", map_id=options.map)
|
|
44
|
+
mapinfo = Beatmap(**map_data)
|
|
45
|
+
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
46
|
+
options.set = mapinfo.beatmapset_id
|
|
47
|
+
options.beatmapsets = beatmapsets_info
|
|
43
48
|
if not options.set:
|
|
44
49
|
await UniMessage.text("请提供需要转换的谱面setid").finish(reply_to=True)
|
|
45
50
|
if options.nln and options.fln:
|
|
@@ -64,7 +69,7 @@ change = on_command("倍速", priority=11, block=True)
|
|
|
64
69
|
|
|
65
70
|
|
|
66
71
|
@change.handle()
|
|
67
|
-
async def _(msg: Message = CommandArg()):
|
|
72
|
+
async def _(bot: Bot, event: GroupMessageEvent, msg: Message = CommandArg()):
|
|
68
73
|
args = msg.extract_plain_text().strip().split()
|
|
69
74
|
argv = ["--map"]
|
|
70
75
|
if not args:
|
|
@@ -85,16 +90,19 @@ async def _(msg: Message = CommandArg()):
|
|
|
85
90
|
args = parser.parse_args(argv)
|
|
86
91
|
options = Options(**vars(args))
|
|
87
92
|
if options.map:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
map_data = await osu_api("map", map_id=options.map)
|
|
94
|
+
mapinfo = Beatmap(**map_data)
|
|
95
|
+
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
96
|
+
options.set = mapinfo.beatmapset_id
|
|
97
|
+
options.beatmapsets = beatmapsets_info
|
|
91
98
|
osz_path = await convert_mania_map(options)
|
|
92
99
|
if not osz_path:
|
|
93
100
|
await UniMessage.text("未找到该地图,请检查是否搞混了mapID与setID").finish(reply_to=True)
|
|
94
101
|
file_path = osz_path.absolute()
|
|
102
|
+
server_osz_path = await upload_file_stream_batch(bot, file_path)
|
|
103
|
+
|
|
95
104
|
try:
|
|
96
|
-
|
|
97
|
-
await UniMessage.file(raw=f.read()).send()
|
|
105
|
+
await bot.call_api("upload_group_file", group_id=event.group_id, file=server_osz_path, name=osz_path.name)
|
|
98
106
|
except ActionFailed:
|
|
99
107
|
await UniMessage.text("上传文件失败,可能是群空间满或没有权限导致的").send(reply_to=True)
|
|
100
108
|
finally:
|
|
@@ -108,7 +116,7 @@ generate_full_ln = on_command("反键", priority=11, block=True)
|
|
|
108
116
|
|
|
109
117
|
|
|
110
118
|
@generate_full_ln.handle()
|
|
111
|
-
async def _(msg: Message = CommandArg()):
|
|
119
|
+
async def _(bot: Bot, event: GroupMessageEvent, msg: Message = CommandArg()):
|
|
112
120
|
args = msg.extract_plain_text().strip().split()
|
|
113
121
|
if not args:
|
|
114
122
|
await UniMessage.text("请输入需要转ln的地图setID").finish(reply_to=True)
|
|
@@ -128,9 +136,9 @@ async def _(msg: Message = CommandArg()):
|
|
|
128
136
|
if not osz_path:
|
|
129
137
|
await UniMessage.text("未找到该地图,请检查是否搞混了mapID与setID").finish(reply_to=True)
|
|
130
138
|
file_path = osz_path.absolute()
|
|
139
|
+
server_osz_path = await upload_file_stream_batch(bot, file_path)
|
|
131
140
|
try:
|
|
132
|
-
|
|
133
|
-
await UniMessage.file(raw=f.read()).send()
|
|
141
|
+
await bot.call_api("upload_group_file", group_id=event.group_id, file=server_osz_path, name=osz_path.name)
|
|
134
142
|
except ActionFailed:
|
|
135
143
|
await UniMessage.text("上传文件失败,可能是群空间满或没有权限导致的").send(reply_to=True)
|
|
136
144
|
finally:
|
|
@@ -69,6 +69,6 @@ async def _(msg: Message = CommandArg()):
|
|
|
69
69
|
for beatmap in medal_data["beatmaps"]:
|
|
70
70
|
msg += (
|
|
71
71
|
f"{beatmap['SongTitle']} [{beatmap['DifficultyName']}]\n{beatmap['Difficulty']}⭐\n"
|
|
72
|
-
+ f"https://osu.ppy.sh/b/{beatmap['BeatmapID']}"
|
|
72
|
+
+ f"https://osu.ppy.sh/b/{beatmap['BeatmapID']}\n"
|
|
73
73
|
)
|
|
74
74
|
await msg.send()
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
from nonebot import on_command
|
|
2
|
+
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
|
2
3
|
from nonebot.params import CommandArg
|
|
3
4
|
from nonebot.internal.adapter import Message
|
|
4
5
|
from nonebot_plugin_alconna import UniMessage
|
|
5
6
|
|
|
6
|
-
from ..file import download_map
|
|
7
|
+
from ..file import download_map, upload_file_stream_batch
|
|
7
8
|
|
|
8
9
|
osudl = on_command("osudl", priority=11, block=True)
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@osudl.handle()
|
|
12
|
-
async def _osudl(setid: Message = CommandArg()):
|
|
13
|
+
async def _osudl(bot: Bot, event: GroupMessageEvent, setid: Message = CommandArg()):
|
|
13
14
|
setid = setid.extract_plain_text().strip()
|
|
14
15
|
if not setid or not setid.isdigit():
|
|
15
16
|
await UniMessage.text("请输入正确的地图ID").send(reply_to=True)
|
|
16
17
|
osz_path = await download_map(int(setid))
|
|
17
|
-
|
|
18
|
+
server_osz_path = await upload_file_stream_batch(bot, osz_path)
|
|
18
19
|
try:
|
|
19
|
-
await
|
|
20
|
+
await bot.call_api("upload_group_file", group_id=event.group_id, file=server_osz_path, name=osz_path.name)
|
|
20
21
|
except Exception:
|
|
21
22
|
await UniMessage.text("上传文件失败,可能是群空间满或没有权限导致的").send(reply_to=True)
|
|
22
23
|
finally:
|
|
@@ -43,8 +43,6 @@ async def _recent(event: Event, state: T_State):
|
|
|
43
43
|
f"在查找用户:{state['username']} {NGM[state['mode']]}模式"
|
|
44
44
|
f" {lazer_mode}{mods} 最近{state['range']}成绩时 {str(e)}"
|
|
45
45
|
).finish(reply_to=True)
|
|
46
|
-
if not player.lazer_mode:
|
|
47
|
-
scores = [i for i in scores if any(mod.acronym == "CL" for mod in i.mods)]
|
|
48
46
|
for score in scores:
|
|
49
47
|
cal_score_info(player.lazer_mode, score)
|
|
50
48
|
pic = await draw_pfm("relist", state["user"], scores, scores, mode, state["source"], is_lazer=player.lazer_mode)
|
|
@@ -99,8 +97,6 @@ async def _pr(event: Event, state: T_State):
|
|
|
99
97
|
f"在查找用户:{state['username']} {NGM[state['mode']]}模式"
|
|
100
98
|
f" {lazer_mode}{mods} 最近{state['range']}成绩时 {str(e)}"
|
|
101
99
|
).finish(reply_to=True)
|
|
102
|
-
if not player.lazer_mode:
|
|
103
|
-
scores = [i for i in scores if any(mod.acronym == "CL" for mod in i.mods)]
|
|
104
100
|
for score_info in scores:
|
|
105
101
|
cal_score_info(player.lazer_mode, score_info)
|
|
106
102
|
pic = await draw_pfm(
|
|
@@ -5,9 +5,10 @@ from nonebot_plugin_alconna import UniMessage
|
|
|
5
5
|
from ..utils import NGM
|
|
6
6
|
from ..api import osu_api
|
|
7
7
|
from .utils import split_msg
|
|
8
|
-
from ..file import
|
|
8
|
+
from ..file import download_osu
|
|
9
9
|
from ..exceptions import NetworkError
|
|
10
10
|
from ..mania import generate_preview_pic
|
|
11
|
+
from ..draw.osu_preview import draw_osu_preview
|
|
11
12
|
from ..draw.catch_preview import draw_cath_preview
|
|
12
13
|
from ..draw.taiko_preview import parse_map, map_to_image
|
|
13
14
|
|
|
@@ -24,7 +25,7 @@ async def _(state: T_State):
|
|
|
24
25
|
except NetworkError as e:
|
|
25
26
|
await UniMessage.text(f"查找map_id:{osu_id} 信息时 {str(e)}").finish(reply_to=True)
|
|
26
27
|
if state["mode"] == "3":
|
|
27
|
-
osu = await
|
|
28
|
+
osu = await download_osu(data["beatmapset_id"], int(osu_id))
|
|
28
29
|
if state["_prefix"]["command"][0] == "完整预览":
|
|
29
30
|
pic = await generate_preview_pic(osu, True)
|
|
30
31
|
else:
|
|
@@ -34,10 +35,16 @@ async def _(state: T_State):
|
|
|
34
35
|
pic = await draw_cath_preview(int(osu_id), data["beatmapset_id"], state["mods"])
|
|
35
36
|
await UniMessage.image(raw=pic).finish(reply_to=True)
|
|
36
37
|
elif state["mode"] == "1":
|
|
37
|
-
osu = await
|
|
38
|
+
osu = await download_osu(data["beatmapset_id"], int(osu_id))
|
|
38
39
|
beatmap = parse_map(osu)
|
|
39
40
|
pic = map_to_image(beatmap)
|
|
40
41
|
await UniMessage.image(raw=pic).finish(reply_to=True)
|
|
42
|
+
elif state["mode"] == "0":
|
|
43
|
+
pic = await draw_osu_preview(int(osu_id), data["beatmapset_id"])
|
|
44
|
+
msg = UniMessage.image(raw=pic) + UniMessage.text(
|
|
45
|
+
f"点击预览:\nhttps://beatmap.try-z.net/?b={osu_id}\nhttps://beatmap.try-z.net/dev/?b={osu_id}"
|
|
46
|
+
)
|
|
47
|
+
await msg.finish(reply_to=True)
|
|
41
48
|
elif not (0 <= int(state["mode"]) <= 3):
|
|
42
49
|
await UniMessage.text("模式应为0-3!\n0: std\n1:taiko\n2:ctb\n3: mania").finish()
|
|
43
50
|
else:
|
|
@@ -2,14 +2,14 @@ import re
|
|
|
2
2
|
from random import shuffle
|
|
3
3
|
|
|
4
4
|
from nonebot import on_command
|
|
5
|
-
from nonebot.log import logger
|
|
6
5
|
from nonebot.typing import T_State
|
|
7
6
|
from expiringdict import ExpiringDict
|
|
8
7
|
from nonebot.internal.matcher import Matcher
|
|
9
8
|
from nonebot_plugin_alconna import UniMessage
|
|
10
9
|
|
|
11
10
|
from .utils import split_msg
|
|
12
|
-
from ..api import get_recommend, update_recommend,
|
|
11
|
+
from ..api import get_recommend, update_recommend, osu_api
|
|
12
|
+
from ..schema import Beatmap
|
|
13
13
|
|
|
14
14
|
recommend = on_command("推荐", priority=11, block=True, aliases={"recommend", "推荐铺面", "推荐谱面"})
|
|
15
15
|
recommend_cache = ExpiringDict(1000, 60 * 60 * 12)
|
|
@@ -41,23 +41,18 @@ async def handle_recommend(state: T_State, matcher: type[Matcher]):
|
|
|
41
41
|
break
|
|
42
42
|
else:
|
|
43
43
|
await matcher.finish("今天已经没有可以推荐的图啦,明天再来吧")
|
|
44
|
+
return None
|
|
44
45
|
bid = int(re.findall("https://osu.ppy.sh/beatmaps/(.*)", recommend_map.mapLink)[0])
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if i.bid == bid:
|
|
49
|
-
bg = i.bg
|
|
50
|
-
break
|
|
51
|
-
else:
|
|
52
|
-
bg = ""
|
|
53
|
-
logger.error(f"出现问题: 有问题的是{bid}, {sid}")
|
|
46
|
+
map_data = await osu_api("map", map_id=bid)
|
|
47
|
+
map_info = Beatmap(**map_data)
|
|
48
|
+
sid = map_info.beatmapset_id
|
|
54
49
|
s = (
|
|
55
50
|
f"推荐的铺面是{recommend_map.mapName} ⭐{round(recommend_map.difficulty, 2)}\n{''.join(recommend_map.mod)}\n"
|
|
56
51
|
f"预计pp为{round(recommend_map.predictPP, 2)}\n提升概率为{round(recommend_map.passPercent * 100, 2)}%\n"
|
|
57
52
|
f"{recommend_map.mapLink}\nhttps://kitsu.moe/api/d/{sid}\n"
|
|
58
53
|
f"https://txy1.sayobot.cn/beatmaps/download/novideo/{sid}"
|
|
59
54
|
)
|
|
60
|
-
pic_url = f"https://
|
|
55
|
+
pic_url = f"https://osu.direct/api/media/background/{bid}"
|
|
61
56
|
return pic_url, s
|
|
62
57
|
|
|
63
58
|
|
nonebot_plugin_osubot/mods.py
CHANGED
|
@@ -1,61 +1,62 @@
|
|
|
1
|
-
from .schema.score import Mod, UnifiedScore
|
|
2
|
-
|
|
3
|
-
mods_dic = {
|
|
4
|
-
"CL": 0,
|
|
5
|
-
"NO": 0,
|
|
6
|
-
"NF": 1 << 0,
|
|
7
|
-
"EZ": 1 << 1,
|
|
8
|
-
"TD": 1 << 2,
|
|
9
|
-
"HD": 1 << 3,
|
|
10
|
-
"HR": 1 << 4,
|
|
11
|
-
"SD": 1 << 5,
|
|
12
|
-
"DT": 1 << 6,
|
|
13
|
-
"RX": 1 << 7,
|
|
14
|
-
"HT": 1 << 8,
|
|
15
|
-
"NC": 1 << 9,
|
|
16
|
-
"FL": 1 << 10,
|
|
17
|
-
"AT": 1 << 11,
|
|
18
|
-
"SO": 1 << 12,
|
|
19
|
-
"RX2": 1 << 13,
|
|
20
|
-
"PF": 1 << 14,
|
|
21
|
-
"4K": 1 << 15,
|
|
22
|
-
"5K": 1 << 16,
|
|
23
|
-
"6K": 1 << 17,
|
|
24
|
-
"7K": 1 << 18,
|
|
25
|
-
"8K": 1 << 19,
|
|
26
|
-
"FI": 1 << 20,
|
|
27
|
-
"RD": 1 << 21,
|
|
28
|
-
"Cinema": 1 << 22,
|
|
29
|
-
"TG": 1 << 23,
|
|
30
|
-
"9K": 1 << 24,
|
|
31
|
-
"KC": 1 << 25,
|
|
32
|
-
"1K": 1 << 26,
|
|
33
|
-
"3K": 1 << 27,
|
|
34
|
-
"2K": 1 << 28,
|
|
35
|
-
"V2": 1 << 29,
|
|
36
|
-
"MR": 1 << 30,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def get_mods(mods: int) -> list[Mod]:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
from .schema.score import Mod, UnifiedScore
|
|
2
|
+
|
|
3
|
+
mods_dic = {
|
|
4
|
+
"CL": 0,
|
|
5
|
+
"NO": 0,
|
|
6
|
+
"NF": 1 << 0,
|
|
7
|
+
"EZ": 1 << 1,
|
|
8
|
+
"TD": 1 << 2,
|
|
9
|
+
"HD": 1 << 3,
|
|
10
|
+
"HR": 1 << 4,
|
|
11
|
+
"SD": 1 << 5,
|
|
12
|
+
"DT": 1 << 6,
|
|
13
|
+
"RX": 1 << 7,
|
|
14
|
+
"HT": 1 << 8,
|
|
15
|
+
"NC": 1 << 9,
|
|
16
|
+
"FL": 1 << 10,
|
|
17
|
+
"AT": 1 << 11,
|
|
18
|
+
"SO": 1 << 12,
|
|
19
|
+
"RX2": 1 << 13,
|
|
20
|
+
"PF": 1 << 14,
|
|
21
|
+
"4K": 1 << 15,
|
|
22
|
+
"5K": 1 << 16,
|
|
23
|
+
"6K": 1 << 17,
|
|
24
|
+
"7K": 1 << 18,
|
|
25
|
+
"8K": 1 << 19,
|
|
26
|
+
"FI": 1 << 20,
|
|
27
|
+
"RD": 1 << 21,
|
|
28
|
+
"Cinema": 1 << 22,
|
|
29
|
+
"TG": 1 << 23,
|
|
30
|
+
"9K": 1 << 24,
|
|
31
|
+
"KC": 1 << 25,
|
|
32
|
+
"1K": 1 << 26,
|
|
33
|
+
"3K": 1 << 27,
|
|
34
|
+
"2K": 1 << 28,
|
|
35
|
+
"V2": 1 << 29,
|
|
36
|
+
"MR": 1 << 30,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_mods(mods: int) -> list[Mod]:
|
|
41
|
+
# Avoid copying the dictionary by iterating directly and filtering
|
|
42
|
+
result = [Mod(acronym=mod) for mod, bit in mods_dic.items() if mod not in ("CL", "NO") and mods & bit]
|
|
43
|
+
return result + [Mod(acronym="CL")]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_mods_list(score_ls: list[UnifiedScore], mods: list[str]) -> list[int]:
|
|
47
|
+
if not mods:
|
|
48
|
+
return list(range(len(score_ls)))
|
|
49
|
+
# Optimize: create the set once instead of on every iteration
|
|
50
|
+
mods_set = set(mods)
|
|
51
|
+
mods_index_ls = []
|
|
52
|
+
for i, score in enumerate(score_ls):
|
|
53
|
+
if score.mods and mods_set.issubset(j.acronym for j in score.mods):
|
|
54
|
+
mods_index_ls.append(i)
|
|
55
|
+
return mods_index_ls
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def calc_mods(mods: list[Mod]) -> int:
|
|
59
|
+
num = 0
|
|
60
|
+
for mod in mods:
|
|
61
|
+
num ^= mods_dic.get(mod.acronym, 0)
|
|
62
|
+
return num
|
|
@@ -25,6 +25,6 @@ async def get_first_response(urls: list[str]):
|
|
|
25
25
|
for task in done:
|
|
26
26
|
response = task.result()
|
|
27
27
|
if response is not None and response.status_code == 200:
|
|
28
|
-
return response
|
|
28
|
+
return response
|
|
29
29
|
tasks = [task for task in tasks if not task.done()]
|
|
30
30
|
return None
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
nonebot_plugin_osubot/pp.py
CHANGED
|
@@ -3,6 +3,7 @@ import importlib.metadata
|
|
|
3
3
|
|
|
4
4
|
from rosu_pp_py import Beatmap, Strains, GameMode, Performance, PerformanceAttributes
|
|
5
5
|
|
|
6
|
+
from .exceptions import NetworkError
|
|
6
7
|
from .schema.score import UnifiedScore
|
|
7
8
|
|
|
8
9
|
is_v2 = importlib.metadata.version("pydantic").startswith("2")
|
|
@@ -10,6 +11,8 @@ is_v2 = importlib.metadata.version("pydantic").startswith("2")
|
|
|
10
11
|
|
|
11
12
|
def cal_pp(score: UnifiedScore, path: str, is_lazer: bool) -> PerformanceAttributes:
|
|
12
13
|
beatmap = Beatmap(path=path)
|
|
14
|
+
if beatmap.is_suspicious():
|
|
15
|
+
raise NetworkError("这似乎不是一个正常谱面 OAO")
|
|
13
16
|
convert_mode(score, beatmap)
|
|
14
17
|
c = Performance(
|
|
15
18
|
accuracy=score.accuracy,
|
|
@@ -31,6 +34,8 @@ def cal_pp(score: UnifiedScore, path: str, is_lazer: bool) -> PerformanceAttribu
|
|
|
31
34
|
|
|
32
35
|
def get_if_pp_ss_pp(score: UnifiedScore, path: str, is_lazer: bool) -> tuple:
|
|
33
36
|
beatmap = Beatmap(path=path)
|
|
37
|
+
if beatmap.is_suspicious():
|
|
38
|
+
return "nan", "nan"
|
|
34
39
|
convert_mode(score, beatmap)
|
|
35
40
|
total = beatmap.n_objects
|
|
36
41
|
passed = score.statistics.great + score.statistics.miss + score.statistics.ok + score.statistics.meh
|
|
@@ -62,6 +67,8 @@ def get_if_pp_ss_pp(score: UnifiedScore, path: str, is_lazer: bool) -> tuple:
|
|
|
62
67
|
|
|
63
68
|
def get_ss_pp(path: str, mods: int, is_lazer) -> PerformanceAttributes:
|
|
64
69
|
beatmap = Beatmap(path=path)
|
|
70
|
+
if beatmap.is_suspicious():
|
|
71
|
+
raise NetworkError("这似乎不是一个正常谱面 OAO")
|
|
65
72
|
c = Performance(accuracy=100, mods=mods, lazer=is_lazer)
|
|
66
73
|
ss_pp_info = c.calculate(beatmap)
|
|
67
74
|
return ss_pp_info
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from .user import User, Badge
|
|
2
2
|
from .match import Game, Match
|
|
3
3
|
from .alphaosu import RecommendData
|
|
4
|
-
from .sayo_beatmap import SayoBeatmap
|
|
5
4
|
from .score import Score, NewScore, BeatmapUserScore
|
|
6
5
|
from .beatmap import Beatmap, Beatmapset, SeasonalBackgrounds
|
|
7
6
|
|
|
@@ -14,7 +13,6 @@ __all__ = [
|
|
|
14
13
|
"Beatmap",
|
|
15
14
|
"Beatmapset",
|
|
16
15
|
"SeasonalBackgrounds",
|
|
17
|
-
"SayoBeatmap",
|
|
18
16
|
"RecommendData",
|
|
19
17
|
"Match",
|
|
20
18
|
"Game",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from .basemodel import Base
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BidData(Base):
|
|
6
|
+
id: int
|
|
7
|
+
mode_int: int
|
|
8
|
+
version: str
|
|
9
|
+
total_length: int
|
|
10
|
+
cs: float
|
|
11
|
+
ar: float
|
|
12
|
+
accuracy: float
|
|
13
|
+
drain: float
|
|
14
|
+
difficulty_rating: float
|
|
15
|
+
count_circles: int
|
|
16
|
+
count_sliders: int
|
|
17
|
+
count_spinners: int
|
|
18
|
+
max_combo: Optional[int] = None
|
|
19
|
+
playcount: int
|
|
20
|
+
passcount: int
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BeatmapSets(Base):
|
|
24
|
+
id: int
|
|
25
|
+
ranked: int
|
|
26
|
+
title: str
|
|
27
|
+
artist: str
|
|
28
|
+
title_unicode: str
|
|
29
|
+
artist_unicode: str
|
|
30
|
+
creator: str
|
|
31
|
+
user_id: int
|
|
32
|
+
source: str
|
|
33
|
+
last_updated: str
|
|
34
|
+
ranked_date: Optional[str]
|
|
35
|
+
bpm: float
|
|
36
|
+
favourite_count: int
|
|
37
|
+
video: bool
|
|
38
|
+
storyboard: bool
|
|
39
|
+
tags: str
|
|
40
|
+
language_id: int
|
|
41
|
+
genre_id: int
|
|
42
|
+
beatmaps: list[BidData]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from .user import Badge, Level, GradeCounts
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Statistics(BaseModel):
|
|
9
|
+
"""用户统计数据"""
|
|
10
|
+
|
|
11
|
+
level: Level
|
|
12
|
+
global_rank: Optional[int] = None # 全球排名
|
|
13
|
+
global_rank_percent: Optional[float] = None # 全球排名百分比
|
|
14
|
+
country_rank: Optional[int] = None # 国家/地区排名
|
|
15
|
+
pp: float
|
|
16
|
+
grade_counts: GradeCounts
|
|
17
|
+
ranked_score: int
|
|
18
|
+
hit_accuracy: float
|
|
19
|
+
play_count: int
|
|
20
|
+
total_score: int
|
|
21
|
+
total_hits: int
|
|
22
|
+
play_time: int
|
|
23
|
+
maximum_combo: int
|
|
24
|
+
replays_watched_by_others: int
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Team(BaseModel):
|
|
28
|
+
"""用户战队信息(为绘图用途专门创建的模型,若无数据则为 null)"""
|
|
29
|
+
|
|
30
|
+
name: str
|
|
31
|
+
flag_url: str
|
|
32
|
+
|
|
33
|
+
# 启用 extra="allow" 可以允许接收更多未定义的字段
|
|
34
|
+
class Config:
|
|
35
|
+
extra = "allow"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DrawUser(BaseModel):
|
|
39
|
+
"""Osu! 用户信息根模型"""
|
|
40
|
+
|
|
41
|
+
id: int
|
|
42
|
+
username: str
|
|
43
|
+
country_code: str # e.g., "AU"
|
|
44
|
+
team: Optional[Team] = None
|
|
45
|
+
footer: str # e.g., "2025/11/07 14:11:45 | 数据对比于4天前"
|
|
46
|
+
mode: str # e.g., "STD"
|
|
47
|
+
badges: Optional[list[Badge]] = None
|
|
48
|
+
statistics: Optional[Statistics] = None
|
|
49
|
+
rank_change: Optional[str] = None
|
|
50
|
+
country_rank_change: Optional[str] = None
|
|
51
|
+
pp_change: Optional[str] = None
|
|
52
|
+
acc_change: Optional[str] = None
|
|
53
|
+
pc_change: Optional[str] = None
|
|
54
|
+
hits_change: Optional[str] = None
|
|
@@ -114,6 +114,7 @@ class UnifiedBeatmap(Base):
|
|
|
114
114
|
hp: float
|
|
115
115
|
stars: float
|
|
116
116
|
user_id: Optional[int] = None
|
|
117
|
+
convert: Optional[bool] = False
|
|
117
118
|
|
|
118
119
|
|
|
119
120
|
class UnifiedScore(Base):
|
|
@@ -129,3 +130,4 @@ class UnifiedScore(Base):
|
|
|
129
130
|
beatmap: Optional[UnifiedBeatmap] = None
|
|
130
131
|
passed: bool
|
|
131
132
|
pp: Optional[float] = None
|
|
133
|
+
beatmapset: Optional[Beatmapset] = None
|
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 6.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: nonebot_plugin_osubot
|
|
3
|
+
Version: 6.26.4
|
|
4
4
|
Summary: OSUbot in NoneBot2
|
|
5
|
-
|
|
5
|
+
Author: yaowan233
|
|
6
6
|
Author-email: yaowan233 <572473053@qq.com>
|
|
7
|
-
|
|
7
|
+
License: AGPL-3.0
|
|
8
|
+
Requires-Dist: nonebot2>=2.3.0
|
|
9
|
+
Requires-Dist: pydantic>=1.10.0,!=2.5.0,!=2.5.1,<3.0.0
|
|
10
|
+
Requires-Dist: nonebot-plugin-alconna>=0.46.4
|
|
11
|
+
Requires-Dist: nonebot-plugin-session~=0.3
|
|
12
|
+
Requires-Dist: pillow>=9.2.0
|
|
8
13
|
Requires-Dist: expiringdict>=1.2.2
|
|
14
|
+
Requires-Dist: nonebot-plugin-apscheduler>=0.4.0
|
|
15
|
+
Requires-Dist: tortoise-orm>=0.20.0
|
|
16
|
+
Requires-Dist: nonebot-plugin-tortoise-orm>=0.1.4
|
|
17
|
+
Requires-Dist: rosu-pp-py==3.1.0
|
|
18
|
+
Requires-Dist: reamber>=0.2.1
|
|
9
19
|
Requires-Dist: httpx>=0.23.3
|
|
20
|
+
Requires-Dist: typing-extensions>=4.11.0
|
|
10
21
|
Requires-Dist: matplotlib>=3.7.1
|
|
11
|
-
Requires-Dist: nonebot-plugin-alconna>=0.46.4
|
|
12
|
-
Requires-Dist: nonebot-plugin-apscheduler>=0.4.0
|
|
13
22
|
Requires-Dist: nonebot-plugin-htmlrender>=0.3.1
|
|
14
|
-
Requires-Dist: nonebot-plugin-session~=0.3
|
|
15
|
-
Requires-Dist: nonebot-plugin-tortoise-orm>=0.1.4
|
|
16
23
|
Requires-Dist: nonebot-plugin-waiter>=0.6.1
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-
|
|
19
|
-
Requires-Dist: pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0
|
|
20
|
-
Requires-Dist: reamber>=0.2.1
|
|
21
|
-
Requires-Dist: rosu-pp-py==3.0.0
|
|
22
|
-
Requires-Dist: tortoise-orm>=0.20.0
|
|
23
|
-
Requires-Dist: typing_extensions>=4.11.0
|
|
24
|
+
Requires-Dist: nonebot-adapter-onebot>=2.4.6
|
|
25
|
+
Requires-Python: >=3.9.8, <3.13
|
|
24
26
|
Project-URL: Homepage, https://github.com/yaowan233/nonebot-plugin-osubot
|
|
25
27
|
Project-URL: Repository, https://github.com/yaowan233/nonebot-plugin-osubot
|
|
26
28
|
Description-Content-Type: text/markdown
|
|
@@ -130,4 +132,3 @@ _✨ NoneBot osubot ✨_
|
|
|
130
132
|
如果遇到任何问题,欢迎提各种issue来反馈bug
|
|
131
133
|
你也可以加群(228986744)来进行反馈!
|
|
132
134
|

|
|
133
|
-
|