nonebot-plugin-osubot 6.19.0__py3-none-any.whl → 6.20.0__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.
Potentially problematic release.
This version of nonebot-plugin-osubot might be problematic. Click here for more details.
- nonebot_plugin_osubot/api.py +85 -39
- nonebot_plugin_osubot/draw/utils.py +6 -4
- nonebot_plugin_osubot/matcher/bp.py +8 -8
- {nonebot_plugin_osubot-6.19.0.dist-info → nonebot_plugin_osubot-6.20.0.dist-info}/METADATA +1 -1
- {nonebot_plugin_osubot-6.19.0.dist-info → nonebot_plugin_osubot-6.20.0.dist-info}/RECORD +6 -6
- {nonebot_plugin_osubot-6.19.0.dist-info → nonebot_plugin_osubot-6.20.0.dist-info}/WHEEL +0 -0
nonebot_plugin_osubot/api.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import random
|
|
2
3
|
from io import BytesIO
|
|
3
4
|
from urllib.parse import urlencode
|
|
@@ -73,6 +74,58 @@ async def get_headers() -> dict[str, str]:
|
|
|
73
74
|
return {"Authorization": f"Bearer {token}", "x-api-version": "20220705"}
|
|
74
75
|
|
|
75
76
|
|
|
77
|
+
async def fetch_score_batch(
|
|
78
|
+
uid: Union[int, str],
|
|
79
|
+
mode: str,
|
|
80
|
+
scope: str,
|
|
81
|
+
batch_size: int,
|
|
82
|
+
offset: int,
|
|
83
|
+
legacy_only: bool,
|
|
84
|
+
include_failed: bool,
|
|
85
|
+
) -> list[UnifiedScore]:
|
|
86
|
+
"""并发获取单次批次数据"""
|
|
87
|
+
url = (
|
|
88
|
+
f"{api}/users/{uid}/scores/{scope}?mode={mode}&limit={batch_size}"
|
|
89
|
+
f"&offset={offset}&legacy_only={int(legacy_only)}"
|
|
90
|
+
f"&include_fails={int(include_failed)}"
|
|
91
|
+
)
|
|
92
|
+
data = await make_request(url, await get_headers(), "未找到该玩家BP")
|
|
93
|
+
if not data:
|
|
94
|
+
return []
|
|
95
|
+
scores = [NewScore(**i) for i in data]
|
|
96
|
+
return [
|
|
97
|
+
UnifiedScore(
|
|
98
|
+
mods=i.mods,
|
|
99
|
+
ruleset_id=i.ruleset_id,
|
|
100
|
+
rank=i.rank,
|
|
101
|
+
accuracy=i.accuracy * 100,
|
|
102
|
+
total_score=i.total_score,
|
|
103
|
+
ended_at=datetime.strptime(i.ended_at.replace("Z", ""), "%Y-%m-%dT%H:%M:%S") + timedelta(hours=8),
|
|
104
|
+
max_combo=i.max_combo,
|
|
105
|
+
statistics=i.statistics,
|
|
106
|
+
legacy_total_score=i.legacy_total_score,
|
|
107
|
+
passed=i.passed,
|
|
108
|
+
beatmap=UnifiedBeatmap(
|
|
109
|
+
id=i.beatmap_id,
|
|
110
|
+
set_id=i.beatmapset.id,
|
|
111
|
+
artist=i.beatmapset.artist,
|
|
112
|
+
title=i.beatmapset.title,
|
|
113
|
+
version=i.beatmap.version,
|
|
114
|
+
creator=i.beatmapset.creator,
|
|
115
|
+
total_length=i.beatmap.total_length,
|
|
116
|
+
mode=i.beatmap.mode_int,
|
|
117
|
+
bpm=i.beatmap.bpm,
|
|
118
|
+
cs=i.beatmap.cs,
|
|
119
|
+
ar=i.beatmap.ar,
|
|
120
|
+
hp=i.beatmap.drain,
|
|
121
|
+
od=i.beatmap.accuracy,
|
|
122
|
+
stars=i.beatmap.difficulty_rating,
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
for i in scores
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
|
|
76
129
|
async def get_user_scores(
|
|
77
130
|
uid: Union[int, str],
|
|
78
131
|
mode: str,
|
|
@@ -81,47 +134,40 @@ async def get_user_scores(
|
|
|
81
134
|
legacy_only: bool = 0,
|
|
82
135
|
include_failed: bool = True,
|
|
83
136
|
offset: int = 0,
|
|
84
|
-
limit: int =
|
|
137
|
+
limit: int = 200,
|
|
85
138
|
) -> list[UnifiedScore]:
|
|
86
139
|
if source == "osu":
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
od=i.beatmap.accuracy,
|
|
119
|
-
stars=i.beatmap.difficulty_rating,
|
|
120
|
-
),
|
|
121
|
-
)
|
|
122
|
-
for i in scores
|
|
123
|
-
]
|
|
124
|
-
return unified_scores
|
|
140
|
+
if limit <= 0:
|
|
141
|
+
return []
|
|
142
|
+
|
|
143
|
+
# 计算需要多少次请求
|
|
144
|
+
# 计算需要多少批次
|
|
145
|
+
batch_size = 100
|
|
146
|
+
total_batches = (limit + batch_size - 1) // batch_size # ceiling(limit/batch_size)
|
|
147
|
+
all_scores = []
|
|
148
|
+
# 分批并发请求
|
|
149
|
+
for batch_idx in range(0, total_batches, 2):
|
|
150
|
+
current_batches = range(batch_idx, min(batch_idx + 2, total_batches))
|
|
151
|
+
|
|
152
|
+
# 生成 tasks(并发执行)
|
|
153
|
+
tasks = []
|
|
154
|
+
for batch_n in current_batches:
|
|
155
|
+
offset = batch_n * batch_size
|
|
156
|
+
actual_batch_size = min(batch_size, limit - len(all_scores) - offset)
|
|
157
|
+
|
|
158
|
+
if actual_batch_size <= 0:
|
|
159
|
+
continue # 已获取足够数据
|
|
160
|
+
|
|
161
|
+
task = fetch_score_batch(uid, mode, scope, actual_batch_size, offset, legacy_only, include_failed)
|
|
162
|
+
tasks.append(task)
|
|
163
|
+
# 并发请求当前批次
|
|
164
|
+
batch_results = await asyncio.gather(*tasks)
|
|
165
|
+
|
|
166
|
+
for batch_scores in batch_results:
|
|
167
|
+
all_scores.extend(batch_scores)
|
|
168
|
+
if len(all_scores) >= limit:
|
|
169
|
+
return all_scores[:limit] # 提前终止
|
|
170
|
+
return all_scores[:limit]
|
|
125
171
|
|
|
126
172
|
elif source == "ppysb":
|
|
127
173
|
url = f"https://api.ppy.sb/v1/get_player_scores?scope={scope}&id={uid}&mode={FGM[mode]}&limit={limit}&include_failed={int(include_failed)}"
|
|
@@ -414,13 +414,15 @@ def filter_scores_with_regex(scores_with_index, conditions):
|
|
|
414
414
|
|
|
415
415
|
def trim_text_with_ellipsis(text, max_width, font):
|
|
416
416
|
# 初始检查:空字符串或无需处理
|
|
417
|
-
|
|
417
|
+
bbox = font.getbbox(text)
|
|
418
|
+
text_width = bbox[2] - bbox[0]
|
|
419
|
+
if not text or text_width <= max_width:
|
|
418
420
|
return text
|
|
419
421
|
# 逐字符检查
|
|
420
422
|
ellipsis_symbol = "…"
|
|
421
|
-
ellipsis_width = font.getbbox("…")
|
|
423
|
+
ellipsis_width = font.getbbox("…")[2] - font.getbbox("…")[0]
|
|
422
424
|
# 确保最大宽度能至少容纳一个字符+省略号
|
|
423
|
-
if max_width < font.getbbox("A") + ellipsis_width:
|
|
425
|
+
if max_width < font.getbbox("A")[2] - font.getbbox("A")[0] + ellipsis_width:
|
|
424
426
|
return ellipsis_symbol
|
|
425
427
|
|
|
426
428
|
truncated_text = ""
|
|
@@ -428,7 +430,7 @@ def trim_text_with_ellipsis(text, max_width, font):
|
|
|
428
430
|
|
|
429
431
|
for char in text:
|
|
430
432
|
# 检查当前字符宽度 + 省略号宽度是否超标
|
|
431
|
-
char_width = font.getbbox(char)
|
|
433
|
+
char_width = font.getbbox(char)[2] - font.getbbox(char)[0]
|
|
432
434
|
if current_width + char_width + ellipsis_width > max_width:
|
|
433
435
|
break
|
|
434
436
|
truncated_text += char
|
|
@@ -25,8 +25,8 @@ async def _bp(state: T_State):
|
|
|
25
25
|
if not best.isdigit():
|
|
26
26
|
await UniMessage.text("只能接受纯数字的bp参数").finish(reply_to=True)
|
|
27
27
|
best = int(best)
|
|
28
|
-
if best <= 0 or best >
|
|
29
|
-
await UniMessage.text("只允许查询bp 1-
|
|
28
|
+
if best <= 0 or best > 200:
|
|
29
|
+
await UniMessage.text("只允许查询bp 1-200 的成绩").finish(reply_to=True)
|
|
30
30
|
try:
|
|
31
31
|
data = await draw_score(
|
|
32
32
|
"bp",
|
|
@@ -52,11 +52,11 @@ async def _pfm(state: T_State):
|
|
|
52
52
|
if "error" in state:
|
|
53
53
|
await UniMessage.text(state["error"]).finish(reply_to=True)
|
|
54
54
|
if not state["range"]:
|
|
55
|
-
state["range"] = "1-
|
|
55
|
+
state["range"] = "1-200"
|
|
56
56
|
ls = state["range"].split("-")
|
|
57
57
|
low, high = int(ls[0]), int(ls[1])
|
|
58
|
-
if not 0 < low < high <=
|
|
59
|
-
await UniMessage.text("仅支持查询bp1-
|
|
58
|
+
if not 0 < low < high <= 200:
|
|
59
|
+
await UniMessage.text("仅支持查询bp1-200").finish(reply_to=True)
|
|
60
60
|
try:
|
|
61
61
|
data = await draw_bp(
|
|
62
62
|
"bp",
|
|
@@ -84,11 +84,11 @@ async def _tbp(state: T_State):
|
|
|
84
84
|
if "error" in state:
|
|
85
85
|
await UniMessage.text(state["error"]).finish(reply_to=True)
|
|
86
86
|
if not state["range"]:
|
|
87
|
-
state["range"] = "1-
|
|
87
|
+
state["range"] = "1-200"
|
|
88
88
|
ls = state["range"].split("-")
|
|
89
89
|
low, high = int(ls[0]), int(ls[1])
|
|
90
|
-
if not 0 < low < high <=
|
|
91
|
-
await UniMessage.text("仅支持查询bp1-
|
|
90
|
+
if not 0 < low < high <= 200:
|
|
91
|
+
await UniMessage.text("仅支持查询bp1-200").finish(reply_to=True)
|
|
92
92
|
try:
|
|
93
93
|
data = await draw_bp(
|
|
94
94
|
"tbp",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
nonebot_plugin_osubot/__init__.py,sha256=Q-mTTnOIdKiKG6JrVm-kqpPrAhOP9lWyiKHNRqA7gpc,1478
|
|
2
|
-
nonebot_plugin_osubot/api.py,sha256=
|
|
2
|
+
nonebot_plugin_osubot/api.py,sha256=hBG_Ugmkwwdw99XNO--1Q8bzfibxbcH3aZHBbfOkEvc,16304
|
|
3
3
|
nonebot_plugin_osubot/beatmap_stats_moder.py,sha256=mNNTufc-gvO4NdYa3TnealSZI4-LBoiTlb599SeLBck,2915
|
|
4
4
|
nonebot_plugin_osubot/config.py,sha256=Ub2s5Ny09-d1ZwT6x8cirB6zWy0brtO-oZV3W0qEM5Q,311
|
|
5
5
|
nonebot_plugin_osubot/database/__init__.py,sha256=7CDo9xU_DGLQ6uTj_mU_Px92phg_DMU5mP6WvgOxFLY,101
|
|
@@ -49,7 +49,7 @@ nonebot_plugin_osubot/draw/templates/bpa_chart.html,sha256=cnpM0qRvvyCMTRP-mIOAB
|
|
|
49
49
|
nonebot_plugin_osubot/draw/templates/echarts.min.js,sha256=IF32ooP8NPIzQg_fs7lVHpwG92JcCPE1TZAEyFSgGZU,1022939
|
|
50
50
|
nonebot_plugin_osubot/draw/templates/mod_chart.html,sha256=Iz71KM5v9z_Rt2vqJ5WIZumRIHgDfcGIUmWGvVGZ-nQ,1508
|
|
51
51
|
nonebot_plugin_osubot/draw/templates/pp_rank_line_chart.html,sha256=Gyf-GR8ZBlWQTks0TlB3M8EWUBMVwiUaesFAmDISxLo,1417
|
|
52
|
-
nonebot_plugin_osubot/draw/utils.py,sha256=
|
|
52
|
+
nonebot_plugin_osubot/draw/utils.py,sha256=LZVDmrQizVwVFX0kDJISYYO68jmZbn5Xz40gV5bj8bo,15276
|
|
53
53
|
nonebot_plugin_osubot/exceptions.py,sha256=N_FsEk-9Eu2QnuznhdfWn6OoyA1HH73Q7bUaY89gVi0,40
|
|
54
54
|
nonebot_plugin_osubot/file.py,sha256=GhG54EdVsxFf8_8GZOPh4YGvw9iw5bAX9JFz4Mg4kMg,4379
|
|
55
55
|
nonebot_plugin_osubot/info/__init__.py,sha256=I7YlMQiuHExEeJWqyzZb2I-Vl2uql3Py2LdhSH2Z9N0,136
|
|
@@ -58,7 +58,7 @@ nonebot_plugin_osubot/info/bind.py,sha256=b2ua625hbYym7rpb-kLBB-VDP5YWFdmT5RweM5
|
|
|
58
58
|
nonebot_plugin_osubot/mania/__init__.py,sha256=XRPn563jDJiPohFekcoFFCqCJYznb-6uORneioZv4xI,5534
|
|
59
59
|
nonebot_plugin_osubot/matcher/__init__.py,sha256=yID7QcdQF6_Mouwbej3JwYUBbKSU3VQdrjq6B1Fz9P8,1331
|
|
60
60
|
nonebot_plugin_osubot/matcher/bind.py,sha256=QQJc2S7XFo5tu4CPloIET6fKaeiQixgb8M7QvULV6E0,2834
|
|
61
|
-
nonebot_plugin_osubot/matcher/bp.py,sha256=
|
|
61
|
+
nonebot_plugin_osubot/matcher/bp.py,sha256=GidJfuZ9lJ7LwMq126DDOwMksNUOz4Bkab83OlKg8t8,3983
|
|
62
62
|
nonebot_plugin_osubot/matcher/bp_analyze.py,sha256=S1dhYiGqtPQapJt4PB5mNKfpPbOpVNAqDIToNEJVpSY,3949
|
|
63
63
|
nonebot_plugin_osubot/matcher/getbg.py,sha256=Ar2yIST556MYRxzuXCLSDAMAmESRENN1fCty-kdH7PI,699
|
|
64
64
|
nonebot_plugin_osubot/matcher/guess.py,sha256=iE5oRZ3mDTC_wcjLJTyyAWlmnDzkAgzGN5rvoTIn0uM,24093
|
|
@@ -403,6 +403,6 @@ nonebot_plugin_osubot/schema/sayo_beatmap.py,sha256=lS1PQZ-HvHl0VhkzlI0-pNLeJrLY
|
|
|
403
403
|
nonebot_plugin_osubot/schema/score.py,sha256=zHU-w2e7RzMDL8vdPkX5vggcqalBo83JTvu96abcflo,3124
|
|
404
404
|
nonebot_plugin_osubot/schema/user.py,sha256=sxNmqymG_kIVuGuzfchSv9UML6NPG70cqo2_h5xDIpM,2250
|
|
405
405
|
nonebot_plugin_osubot/utils/__init__.py,sha256=pyv8XxBcCOeQVDj1E4dgvktzcefgQXfKBlarsYGx1sg,815
|
|
406
|
-
nonebot_plugin_osubot-6.
|
|
407
|
-
nonebot_plugin_osubot-6.
|
|
408
|
-
nonebot_plugin_osubot-6.
|
|
406
|
+
nonebot_plugin_osubot-6.20.0.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
407
|
+
nonebot_plugin_osubot-6.20.0.dist-info/METADATA,sha256=h46-68Jkbr_-bhXPbyK_BS-f7kVOO585n8TGDpPYijc,4476
|
|
408
|
+
nonebot_plugin_osubot-6.20.0.dist-info/RECORD,,
|
|
File without changes
|