nonebot-plugin-osubot 6.20.1__py3-none-any.whl → 6.22.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 +9 -6
- nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/catch.js +4 -3
- nonebot_plugin_osubot/draw/catch_preview_templates/pic.html +2 -2
- nonebot_plugin_osubot/draw/score.py +207 -143
- nonebot_plugin_osubot/draw/static.py +4 -2
- nonebot_plugin_osubot/draw/templates/bpa_chart.html +1 -1
- nonebot_plugin_osubot/draw/utils.py +23 -7
- nonebot_plugin_osubot/matcher/bp_analyze.py +3 -10
- nonebot_plugin_osubot/matcher/guess.py +40 -40
- nonebot_plugin_osubot/matcher/utils.py +6 -4
- nonebot_plugin_osubot/network/manager.py +30 -0
- nonebot_plugin_osubot/osufile/pfm_ctb.png +0 -0
- nonebot_plugin_osubot/osufile/pfm_mania.png +0 -0
- nonebot_plugin_osubot/osufile/pfm_std.png +0 -0
- nonebot_plugin_osubot/osufile/pfm_taiko.png +0 -0
- nonebot_plugin_osubot/osufile/work/stardiff.png +0 -0
- nonebot_plugin_osubot/schema/score.py +2 -0
- {nonebot_plugin_osubot-6.20.1.dist-info → nonebot_plugin_osubot-6.22.0.dist-info}/METADATA +1 -1
- {nonebot_plugin_osubot-6.20.1.dist-info → nonebot_plugin_osubot-6.22.0.dist-info}/RECORD +20 -18
- {nonebot_plugin_osubot-6.20.1.dist-info → nonebot_plugin_osubot-6.22.0.dist-info}/WHEEL +0 -0
nonebot_plugin_osubot/api.py
CHANGED
|
@@ -8,8 +8,9 @@ from typing import Union, Literal, Optional
|
|
|
8
8
|
from nonebot.log import logger
|
|
9
9
|
from expiringdict import ExpiringDict
|
|
10
10
|
from nonebot import get_plugin_config
|
|
11
|
-
from httpx import Response
|
|
11
|
+
from httpx import Response
|
|
12
12
|
|
|
13
|
+
from .network.manager import network_manager
|
|
13
14
|
from .utils import FGM
|
|
14
15
|
from .config import Config
|
|
15
16
|
from .mods import get_mods
|
|
@@ -25,7 +26,6 @@ api = "https://osu.ppy.sh/api/v2"
|
|
|
25
26
|
sayoapi = "https://api.sayobot.cn"
|
|
26
27
|
cache = ExpiringDict(max_len=1, max_age_seconds=86400)
|
|
27
28
|
plugin_config = get_plugin_config(Config)
|
|
28
|
-
proxy = plugin_config.osu_proxy
|
|
29
29
|
|
|
30
30
|
key = plugin_config.osu_key
|
|
31
31
|
client_id = plugin_config.osu_client
|
|
@@ -34,15 +34,15 @@ bg_url = plugin_config.info_bg
|
|
|
34
34
|
|
|
35
35
|
@auto_retry
|
|
36
36
|
async def safe_async_get(url, headers: Optional[dict] = None, params: Optional[dict] = None) -> Response:
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
client = await network_manager.get_client()
|
|
38
|
+
req = await client.get(url, headers=headers, params=params)
|
|
39
39
|
return req
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
@auto_retry
|
|
43
43
|
async def safe_async_post(url, headers=None, data=None, json=None) -> Response:
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
client = await network_manager.get_client()
|
|
45
|
+
req = await client.post(url, headers=headers, data=data, json=json)
|
|
46
46
|
return req
|
|
47
47
|
|
|
48
48
|
|
|
@@ -105,8 +105,10 @@ async def fetch_score_batch(
|
|
|
105
105
|
statistics=i.statistics,
|
|
106
106
|
legacy_total_score=i.legacy_total_score,
|
|
107
107
|
passed=i.passed,
|
|
108
|
+
pp=i.pp,
|
|
108
109
|
beatmap=UnifiedBeatmap(
|
|
109
110
|
id=i.beatmap_id,
|
|
111
|
+
user_id=i.beatmap.user_id,
|
|
110
112
|
set_id=i.beatmapset.id,
|
|
111
113
|
artist=i.beatmapset.artist,
|
|
112
114
|
title=i.beatmapset.title,
|
|
@@ -198,6 +200,7 @@ async def get_user_scores(
|
|
|
198
200
|
),
|
|
199
201
|
beatmap=UnifiedBeatmap(
|
|
200
202
|
id=i.beatmap.id,
|
|
203
|
+
user_id=i.beatmap.user_id,
|
|
201
204
|
set_id=i.beatmap.set_id,
|
|
202
205
|
artist=i.beatmap.artist,
|
|
203
206
|
title=i.beatmap.title,
|
|
@@ -673,9 +673,10 @@ Catch.prototype.draw2 = function (SCALE, SPEED = 1, params = {}) {
|
|
|
673
673
|
// 按总物件数/时间控制密度
|
|
674
674
|
let totalTime = this.fullCatchObjects[this.fullCatchObjects.length - 1].time - this.fullCatchObjects[0].time;
|
|
675
675
|
if (this.fullCatchObjects.length * 1000 / totalTime > 2) comboSplit = Math.ceil(this.fullCatchObjects.length * 1000 / totalTime) * 10;
|
|
676
|
-
// 按0.5
|
|
677
|
-
let roundBy = Math.pow(10, comboSplit.toString().length) * 0.5;
|
|
676
|
+
// 按0.5*(10^(位数-1&&最小为2))修约 60=>50 270=>250 820=>800 1434=>1500 1834=>2000
|
|
677
|
+
let roundBy = Math.pow(10, Math.max(comboSplit.toString().length - 1, 2)) * 0.5;
|
|
678
678
|
comboSplit = Math.round(comboSplit / roundBy) * roundBy;
|
|
679
|
+
if (comboSplit <= 0) comboSplit = 20;
|
|
679
680
|
for (let i = 0; i < this.fullCatchObjects.length; i++) {
|
|
680
681
|
let showCombo = null;
|
|
681
682
|
if (objs[i].type === "Fruit" || objs[i].type === "Droplet") {
|
|
@@ -799,4 +800,4 @@ Catch.prototype.processProgressBar = function (ctx, totalTime) {
|
|
|
799
800
|
ctx.fillRect(ctxwidth * time / totalTime, 0, ctxwidth * (endtime - time) / totalTime, ctxheight);
|
|
800
801
|
}
|
|
801
802
|
}
|
|
802
|
-
};
|
|
803
|
+
};
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
const createImg = function () {
|
|
43
43
|
const self = this;
|
|
44
|
-
const osufile =
|
|
44
|
+
const osufile = {{ osu_file|tojson }};
|
|
45
45
|
let SPEED = 1;
|
|
46
46
|
let mods = {
|
|
47
47
|
HR: {{ is_hr }},
|
|
@@ -85,4 +85,4 @@
|
|
|
85
85
|
</script>
|
|
86
86
|
</body>
|
|
87
87
|
|
|
88
|
-
</html>
|
|
88
|
+
</html>
|
|
@@ -28,19 +28,25 @@ from .utils import (
|
|
|
28
28
|
open_user_icon,
|
|
29
29
|
filter_scores_with_regex,
|
|
30
30
|
trim_text_with_ellipsis,
|
|
31
|
+
draw_text_with_outline,
|
|
31
32
|
)
|
|
32
33
|
from .static import (
|
|
33
34
|
Image,
|
|
34
35
|
IconLs,
|
|
35
|
-
|
|
36
|
+
Venera_60,
|
|
37
|
+
Torus_Regular_15,
|
|
36
38
|
Torus_Regular_20,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
Torus_Regular_25,
|
|
40
|
+
Torus_Regular_50,
|
|
41
|
+
Torus_Regular_60,
|
|
42
|
+
Torus_SemiBold_15,
|
|
39
43
|
Torus_SemiBold_20,
|
|
40
44
|
Torus_SemiBold_25,
|
|
41
45
|
Torus_SemiBold_30,
|
|
42
46
|
osufile,
|
|
43
47
|
extra_30,
|
|
48
|
+
Stardiff,
|
|
49
|
+
Stars,
|
|
44
50
|
)
|
|
45
51
|
|
|
46
52
|
|
|
@@ -197,15 +203,23 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
197
203
|
original_ss_pp_info = get_ss_pp(str(osu.absolute()), 0, is_lazer)
|
|
198
204
|
if_pp, ss_pp = get_if_pp_ss_pp(score_info, str(osu.absolute()), is_lazer)
|
|
199
205
|
# 新建图片
|
|
200
|
-
im = Image.new("RGBA", (
|
|
206
|
+
im = Image.new("RGBA", (1280, 720))
|
|
201
207
|
draw = ImageDraw.Draw(im)
|
|
202
208
|
# 获取cover并裁剪,高斯,降低亮度
|
|
203
209
|
try:
|
|
204
210
|
bg = await get_bg(mapinfo.id, mapinfo.beatmapset_id)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
cover_crop_left = await crop_bg((1280, 720), bg)
|
|
212
|
+
cover_gb_left = cover_crop_left.filter(ImageFilter.GaussianBlur(10))
|
|
213
|
+
cover_gb_left = ImageEnhance.Brightness(cover_gb_left).enhance(1)
|
|
214
|
+
cover_img_left = ImageEnhance.Brightness(cover_gb_left).enhance(2 / 4.0)
|
|
215
|
+
im.alpha_composite(cover_img_left, (0, 0))
|
|
216
|
+
# 新小图 BG
|
|
217
|
+
cover_crop_right = await crop_bg((650, 270), bg)
|
|
218
|
+
cover_gb_right = cover_crop_right.filter(ImageFilter.GaussianBlur(1))
|
|
219
|
+
cover_gb_right = ImageEnhance.Brightness(cover_gb_right).enhance(0.9)
|
|
220
|
+
cover_img_right = ImageEnhance.Brightness(cover_gb_right).enhance(1)
|
|
221
|
+
cover_img_right = draw_fillet(cover_img_right, 15)
|
|
222
|
+
im.alpha_composite(cover_img_right, (0, 50))
|
|
209
223
|
except NetworkError:
|
|
210
224
|
...
|
|
211
225
|
# 获取成绩背景做底图
|
|
@@ -213,58 +227,70 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
213
227
|
recent_bg = Image.open(bg).convert("RGBA")
|
|
214
228
|
im.alpha_composite(recent_bg)
|
|
215
229
|
# 模式
|
|
216
|
-
|
|
230
|
+
draw_text_with_outline(
|
|
231
|
+
draw,
|
|
232
|
+
(30, 80),
|
|
233
|
+
IconLs[score_info.ruleset_id],
|
|
234
|
+
extra_30,
|
|
235
|
+
anchor="lm",
|
|
236
|
+
fill=(255, 255, 255, 255),
|
|
237
|
+
)
|
|
217
238
|
# 难度星星
|
|
218
|
-
stars_bg = stars_diff(pp_info.difficulty.stars)
|
|
239
|
+
stars_bg = stars_diff(pp_info.difficulty.stars, Stars)
|
|
219
240
|
stars_img = stars_bg.resize((85, 37))
|
|
220
|
-
im.alpha_composite(stars_img, (
|
|
241
|
+
im.alpha_composite(stars_img, (552, 67))
|
|
242
|
+
# 难度竖条
|
|
243
|
+
star_bg = stars_diff(pp_info.difficulty.stars, Stardiff)
|
|
244
|
+
star_img = star_bg.resize((20, 271))
|
|
245
|
+
im.alpha_composite(star_img, (0, 50))
|
|
246
|
+
# 星级
|
|
221
247
|
if pp_info.difficulty.stars < 6.5:
|
|
222
248
|
color = (0, 0, 0, 255)
|
|
223
249
|
else:
|
|
224
250
|
color = (255, 217, 102, 255)
|
|
225
|
-
|
|
251
|
+
|
|
226
252
|
draw.text(
|
|
227
|
-
(
|
|
253
|
+
(556, 85),
|
|
228
254
|
f"★{pp_info.difficulty.stars:.2f}",
|
|
229
255
|
font=Torus_SemiBold_20,
|
|
230
256
|
anchor="lm",
|
|
231
257
|
fill=color,
|
|
232
258
|
)
|
|
233
259
|
# mods
|
|
234
|
-
if any(i in score_info.mods for i in (Mod(acronym="HD"), Mod(acronym="FL"), Mod(acronym="FI"))):
|
|
235
|
-
|
|
236
|
-
else:
|
|
237
|
-
|
|
260
|
+
# if any(i in score_info.mods for i in (Mod(acronym="HD"), Mod(acronym="FL"), Mod(acronym="FI"))):
|
|
261
|
+
# ranking = ["XH", "SH", "A", "B", "C", "D", "F"]
|
|
262
|
+
# else:
|
|
263
|
+
# ranking = ["X", "S", "A", "B", "C", "D", "F"]
|
|
238
264
|
if score_info.mods:
|
|
239
265
|
for mods_num, s_mods in enumerate(score_info.mods):
|
|
240
266
|
mods_bg = osufile / "mods" / f"{s_mods.acronym}.png"
|
|
241
267
|
try:
|
|
242
268
|
mods_img = Image.open(mods_bg).convert("RGBA")
|
|
243
|
-
im.alpha_composite(mods_img, (
|
|
269
|
+
im.alpha_composite(mods_img, (880 + 50 * mods_num, 100))
|
|
244
270
|
except FileNotFoundError:
|
|
245
271
|
pass
|
|
246
272
|
# 成绩S-F
|
|
247
|
-
rank_ok = False
|
|
248
|
-
for rank_num, i in enumerate(ranking):
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
273
|
+
# rank_ok = False
|
|
274
|
+
# for rank_num, i in enumerate(ranking):
|
|
275
|
+
# rank_img = osufile / "ranking" / f"ranking-{i}.png"
|
|
276
|
+
# if rank_ok:
|
|
277
|
+
# rank_b = Image.open(rank_img).convert("RGBA").resize((48, 24))
|
|
278
|
+
# rank_new = Image.new("RGBA", rank_b.size, (0, 0, 0, 0))
|
|
279
|
+
# rank_bg = Image.blend(rank_new, rank_b, 0.5)
|
|
280
|
+
# elif i != score_info.rank:
|
|
281
|
+
# rank_b = Image.open(rank_img).convert("RGBA").resize((48, 24))
|
|
282
|
+
# rank_new = Image.new("RGBA", rank_b.size, (0, 0, 0, 0))
|
|
283
|
+
# rank_bg = Image.blend(rank_new, rank_b, 0.2)
|
|
284
|
+
# else:
|
|
285
|
+
# rank_bg = Image.open(rank_img).convert("RGBA").resize((48, 24))
|
|
286
|
+
# rank_ok = True
|
|
287
|
+
# im.alpha_composite(rank_bg, (75, 163 + 39 * rank_num))
|
|
262
288
|
# 成绩+acc
|
|
263
289
|
im = draw_acc(im, score_info.accuracy, score_info.ruleset_id)
|
|
264
290
|
# 地区
|
|
265
291
|
country = osufile / "flags" / f"{info.country_code}.png"
|
|
266
292
|
country_bg = Image.open(country).convert("RGBA").resize((66, 45))
|
|
267
|
-
im.alpha_composite(country_bg, (
|
|
293
|
+
im.alpha_composite(country_bg, (208, 597))
|
|
268
294
|
if info.team and info.team.flag_url:
|
|
269
295
|
team_path = team_cache_path / f"{info.team.id}.png"
|
|
270
296
|
if not team_path.exists():
|
|
@@ -273,11 +299,11 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
273
299
|
team_img.save(team_path)
|
|
274
300
|
try:
|
|
275
301
|
team_img = Image.open(team_path).convert("RGBA").resize((80, 40))
|
|
276
|
-
im.alpha_composite(team_img, (
|
|
302
|
+
im.alpha_composite(team_img, (208, 660))
|
|
277
303
|
except UnidentifiedImageError:
|
|
278
304
|
team_path.unlink()
|
|
279
305
|
raise NetworkError("team 图片下载错误,请重试!")
|
|
280
|
-
draw.text((
|
|
306
|
+
draw.text((297, 675), info.team.name, font=Torus_Regular_20, anchor="lt")
|
|
281
307
|
# supporter
|
|
282
308
|
# if info.is_supporter:
|
|
283
309
|
# im.alpha_composite(SupporterBg.resize((40, 40)), (250, 640))
|
|
@@ -309,38 +335,38 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
309
335
|
]
|
|
310
336
|
|
|
311
337
|
for num, (orig, new) in enumerate(zip(original_mapdiff, mapdiff)):
|
|
312
|
-
orig_difflen = int(
|
|
313
|
-
new_difflen = int(
|
|
338
|
+
orig_difflen = int(400 * max(0, orig) / 10) if orig <= 10 else 400
|
|
339
|
+
new_difflen = int(400 * max(0, new) / 10) if new <= 10 else 400
|
|
314
340
|
if is_close(new, orig):
|
|
315
341
|
color = (255, 255, 255, 255)
|
|
316
342
|
diff_len = Image.new("RGBA", (orig_difflen, 8), color)
|
|
317
|
-
im.alpha_composite(diff_len, (
|
|
343
|
+
im.alpha_composite(diff_len, (165, 352 + 35 * num))
|
|
318
344
|
elif new > orig and not (score_info.ruleset_id == 3 and mapinfo.mode == "osu"):
|
|
319
345
|
color = (198, 92, 102, 255)
|
|
320
346
|
orig_color = (246, 136, 144, 255)
|
|
321
347
|
new_diff_len = Image.new("RGBA", (new_difflen, 8), color)
|
|
322
|
-
im.alpha_composite(new_diff_len, (
|
|
348
|
+
im.alpha_composite(new_diff_len, (165, 352 + 35 * num))
|
|
323
349
|
orig_diff_len = Image.new("RGBA", (orig_difflen, 8), orig_color)
|
|
324
|
-
im.alpha_composite(orig_diff_len, (
|
|
350
|
+
im.alpha_composite(orig_diff_len, (165, 352 + 35 * num))
|
|
325
351
|
elif new < orig and not (score_info.ruleset_id == 3 and mapinfo.mode == "osu"):
|
|
326
352
|
color = (161, 212, 238, 255)
|
|
327
353
|
orig_color = (255, 255, 255, 255)
|
|
328
354
|
orig_diff_len = Image.new("RGBA", (orig_difflen, 8), orig_color)
|
|
329
|
-
im.alpha_composite(orig_diff_len, (
|
|
355
|
+
im.alpha_composite(orig_diff_len, (165, 352 + 35 * num))
|
|
330
356
|
new_diff_len = Image.new("RGBA", (new_difflen, 8), color)
|
|
331
|
-
im.alpha_composite(new_diff_len, (
|
|
357
|
+
im.alpha_composite(new_diff_len, (165, 352 + 35 * num))
|
|
332
358
|
else:
|
|
333
359
|
raise Exception("没有这种情况")
|
|
334
360
|
if new == round(new):
|
|
335
361
|
draw.text(
|
|
336
|
-
(
|
|
362
|
+
(610, 355 + 35 * num),
|
|
337
363
|
f"{new:.0f}",
|
|
338
364
|
font=Torus_SemiBold_20,
|
|
339
365
|
anchor="mm",
|
|
340
366
|
)
|
|
341
367
|
else:
|
|
342
368
|
draw.text(
|
|
343
|
-
(
|
|
369
|
+
(610, 355 + 35 * num),
|
|
344
370
|
f"{new:.2f}" if new != round(new, 1) else f"{new:.1f}",
|
|
345
371
|
font=Torus_SemiBold_20,
|
|
346
372
|
anchor="mm",
|
|
@@ -351,253 +377,291 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
351
377
|
if stars > original_stars:
|
|
352
378
|
color = (198, 92, 102, 255)
|
|
353
379
|
orig_color = (246, 111, 34, 255)
|
|
354
|
-
new_difflen = int(
|
|
380
|
+
new_difflen = int(400 * max(0.0, stars) / 10) if stars <= 10 else 400
|
|
355
381
|
new_diff_len = Image.new("RGBA", (new_difflen, 8), color)
|
|
356
|
-
im.alpha_composite(new_diff_len, (
|
|
357
|
-
orig_difflen = int(
|
|
382
|
+
im.alpha_composite(new_diff_len, (165, 490))
|
|
383
|
+
orig_difflen = int(400 * max(0.0, original_stars) / 10) if original_stars <= 10 else 400
|
|
358
384
|
orig_diff_len = Image.new("RGBA", (orig_difflen, 8), orig_color)
|
|
359
|
-
im.alpha_composite(orig_diff_len, (
|
|
385
|
+
im.alpha_composite(orig_diff_len, (165, 490))
|
|
360
386
|
elif stars < original_stars:
|
|
361
387
|
color = (161, 187, 127, 255)
|
|
362
388
|
orig_color = (255, 204, 34, 255)
|
|
363
|
-
orig_difflen = int(
|
|
389
|
+
orig_difflen = int(400 * max(0.0, original_stars) / 10) if original_stars <= 10 else 400
|
|
364
390
|
orig_diff_len = Image.new("RGBA", (orig_difflen, 8), orig_color)
|
|
365
|
-
im.alpha_composite(orig_diff_len, (
|
|
366
|
-
new_difflen = int(
|
|
391
|
+
im.alpha_composite(orig_diff_len, (165, 490))
|
|
392
|
+
new_difflen = int(400 * max(0.0, stars) / 10) if stars <= 10 else 400
|
|
367
393
|
new_diff_len = Image.new("RGBA", (new_difflen, 8), color)
|
|
368
|
-
im.alpha_composite(new_diff_len, (
|
|
394
|
+
im.alpha_composite(new_diff_len, (165, 490))
|
|
369
395
|
else:
|
|
370
396
|
color = (255, 204, 34, 255)
|
|
371
|
-
difflen = int(
|
|
397
|
+
difflen = int(400 * stars / 10) if stars <= 10 else 400
|
|
372
398
|
diff_len = Image.new("RGBA", (difflen, 8), color)
|
|
373
|
-
im.alpha_composite(diff_len, (
|
|
374
|
-
draw.text((
|
|
399
|
+
im.alpha_composite(diff_len, (165, 490))
|
|
400
|
+
draw.text((610, 493), f"{stars:.2f}", font=Torus_SemiBold_20, anchor="mm")
|
|
375
401
|
# 时长 - 滑条
|
|
376
|
-
diff_info =
|
|
402
|
+
diff_info = [
|
|
377
403
|
calc_songlen(mapinfo.total_length),
|
|
378
404
|
f"{mapinfo.bpm:.1f}",
|
|
379
405
|
mapinfo.count_circles,
|
|
380
406
|
mapinfo.count_sliders,
|
|
381
|
-
)
|
|
407
|
+
] + ([mapinfo.count_spinners] if score_info.ruleset_id != 3 else [])
|
|
382
408
|
for num, i in enumerate(diff_info):
|
|
383
|
-
|
|
384
|
-
|
|
409
|
+
draw_text_with_outline(
|
|
410
|
+
draw,
|
|
411
|
+
(70 + 120 * num, 300),
|
|
385
412
|
f"{i}",
|
|
386
413
|
font=Torus_Regular_20,
|
|
387
414
|
anchor="lm",
|
|
388
415
|
fill=(255, 204, 34, 255),
|
|
389
416
|
)
|
|
390
417
|
# 状态
|
|
391
|
-
|
|
418
|
+
draw_text_with_outline(
|
|
419
|
+
draw,
|
|
420
|
+
(595, 115),
|
|
421
|
+
mapinfo.status.capitalize(),
|
|
422
|
+
Torus_SemiBold_15,
|
|
423
|
+
anchor="mm",
|
|
424
|
+
fill=(255, 255, 255, 255),
|
|
425
|
+
)
|
|
426
|
+
# setid
|
|
427
|
+
draw.text((32, 25), f"Setid:{mapinfo.beatmapset_id}", font=Torus_SemiBold_20, anchor="lm")
|
|
392
428
|
# mapid
|
|
393
|
-
draw.text((
|
|
429
|
+
draw.text((650, 25), f"Mapid: {mapinfo.id}", font=Torus_SemiBold_20, anchor="rm")
|
|
394
430
|
# 曲名
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
431
|
+
title = trim_text_with_ellipsis(mapinfo.beatmapset.title, 600, Torus_SemiBold_30)
|
|
432
|
+
draw_text_with_outline(
|
|
433
|
+
draw,
|
|
434
|
+
(30, 200),
|
|
435
|
+
title,
|
|
436
|
+
Torus_SemiBold_30,
|
|
437
|
+
anchor="lm",
|
|
438
|
+
fill=(255, 255, 255, 255),
|
|
439
|
+
)
|
|
440
|
+
# 艺术家
|
|
441
|
+
artist = trim_text_with_ellipsis(mapinfo.beatmapset.artist, 600, Torus_SemiBold_20)
|
|
442
|
+
draw_text_with_outline(
|
|
443
|
+
draw,
|
|
444
|
+
(30, 230),
|
|
445
|
+
artist,
|
|
446
|
+
Torus_SemiBold_20,
|
|
399
447
|
anchor="lm",
|
|
448
|
+
fill=(255, 255, 255, 255),
|
|
400
449
|
)
|
|
401
|
-
#
|
|
450
|
+
# mapper
|
|
402
451
|
if mapinfo.owners:
|
|
403
452
|
owner_names = [owner.username for owner in mapinfo.owners]
|
|
404
453
|
owners_str = ", ".join(owner_names)
|
|
405
|
-
mapper = f"
|
|
454
|
+
mapper = f"谱师: {owners_str}"
|
|
406
455
|
|
|
407
456
|
else:
|
|
408
|
-
mapper = f"
|
|
409
|
-
mapper = trim_text_with_ellipsis(mapper,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
(
|
|
457
|
+
mapper = f"谱师: {mapinfo.beatmapset.creator}"
|
|
458
|
+
mapper = trim_text_with_ellipsis(mapper, 600, Torus_SemiBold_15)
|
|
459
|
+
draw_text_with_outline(
|
|
460
|
+
draw,
|
|
461
|
+
(30, 265),
|
|
413
462
|
mapper,
|
|
414
|
-
|
|
463
|
+
Torus_SemiBold_15,
|
|
464
|
+
anchor="lm",
|
|
465
|
+
fill=(255, 255, 255, 255),
|
|
466
|
+
)
|
|
467
|
+
# 谱面版本
|
|
468
|
+
version = trim_text_with_ellipsis(mapinfo.version, 450, Torus_SemiBold_15)
|
|
469
|
+
draw_text_with_outline(
|
|
470
|
+
draw,
|
|
471
|
+
(65, 80),
|
|
472
|
+
version,
|
|
473
|
+
Torus_SemiBold_15,
|
|
415
474
|
anchor="lm",
|
|
475
|
+
fill=(255, 255, 255, 255),
|
|
416
476
|
)
|
|
417
477
|
# 评价
|
|
418
|
-
draw.text((
|
|
478
|
+
draw.text((772, 185), score_info.rank, font=Venera_60, anchor="mm")
|
|
419
479
|
# 分数
|
|
420
480
|
draw.text(
|
|
421
|
-
(
|
|
481
|
+
(880, 165),
|
|
422
482
|
f"{score_info.legacy_total_score or score_info.total_score:,}",
|
|
423
|
-
font=
|
|
483
|
+
font=Torus_Regular_60,
|
|
424
484
|
anchor="lm",
|
|
425
485
|
)
|
|
426
486
|
# 时间
|
|
427
|
-
draw.text((
|
|
428
|
-
draw.text((
|
|
487
|
+
draw.text((883, 230), "达成时间:", font=Torus_SemiBold_20, anchor="lm")
|
|
488
|
+
draw.text((985, 230), score_info.ended_at.strftime("%Y-%m-%d %H:%M:%S"), font=Torus_SemiBold_20, anchor="lm")
|
|
429
489
|
# 全球排名
|
|
430
|
-
draw.text((
|
|
490
|
+
draw.text((883, 260), "全球排行:" if grank else "", font=Torus_SemiBold_20, anchor="lm")
|
|
491
|
+
draw.text((985, 260), f"#{grank}" if grank else "", font=Torus_SemiBold_25, anchor="lm")
|
|
431
492
|
# 左下玩家名
|
|
432
|
-
draw.text((
|
|
493
|
+
draw.text((208, 550), info.username, font=Torus_SemiBold_30, anchor="lm")
|
|
433
494
|
# 国内排名
|
|
434
495
|
draw.text(
|
|
435
|
-
(
|
|
496
|
+
(283, 630),
|
|
436
497
|
f"#{info.statistics.country_rank}",
|
|
437
498
|
font=Torus_SemiBold_25,
|
|
438
499
|
anchor="lm",
|
|
439
500
|
)
|
|
440
501
|
if score_info.ruleset_id in {0, 4, 8}:
|
|
441
|
-
draw.text((
|
|
442
|
-
draw.text((
|
|
443
|
-
draw.text((
|
|
444
|
-
draw.text((
|
|
445
|
-
draw.text((
|
|
446
|
-
draw.text((
|
|
502
|
+
draw.text((1066, 393), ss_pp, font=Torus_Regular_25, anchor="mm")
|
|
503
|
+
draw.text((933, 393), if_pp, font=Torus_Regular_25, anchor="mm")
|
|
504
|
+
draw.text((768, 438), f"{pp_info.pp:.0f}", font=Torus_Regular_50, anchor="mm")
|
|
505
|
+
draw.text((933, 482), f"{pp_info.pp_aim:.0f}", font=Torus_Regular_25, anchor="mm")
|
|
506
|
+
draw.text((1066, 482), f"{pp_info.pp_speed:.0f}", font=Torus_Regular_25, anchor="mm")
|
|
507
|
+
draw.text((1200, 482), f"{pp_info.pp_accuracy:.0f}", font=Torus_Regular_25, anchor="mm")
|
|
447
508
|
draw.text(
|
|
448
|
-
(
|
|
509
|
+
(768, 577),
|
|
449
510
|
f"{score_info.accuracy:.2f}%",
|
|
450
|
-
font=
|
|
511
|
+
font=Torus_Regular_25,
|
|
451
512
|
anchor="mm",
|
|
452
513
|
)
|
|
453
514
|
draw.text(
|
|
454
|
-
(
|
|
515
|
+
(768, 666),
|
|
455
516
|
f"{score_info.max_combo:,}/{pp_info.difficulty.max_combo}",
|
|
456
|
-
font=
|
|
517
|
+
font=Torus_Regular_25,
|
|
457
518
|
anchor="mm",
|
|
458
519
|
)
|
|
459
520
|
draw.text(
|
|
460
|
-
(
|
|
521
|
+
(933, 577),
|
|
461
522
|
f"{score_info.statistics.great or 0}",
|
|
462
|
-
font=
|
|
523
|
+
font=Torus_Regular_25,
|
|
463
524
|
anchor="mm",
|
|
464
525
|
)
|
|
465
526
|
draw.text(
|
|
466
|
-
(
|
|
527
|
+
(1066, 577),
|
|
467
528
|
f"{score_info.statistics.ok or 0}",
|
|
468
|
-
font=
|
|
529
|
+
font=Torus_Regular_25,
|
|
469
530
|
anchor="mm",
|
|
470
531
|
)
|
|
471
532
|
draw.text(
|
|
472
|
-
(
|
|
533
|
+
(933, 666),
|
|
473
534
|
f"{score_info.statistics.meh or 0}",
|
|
474
|
-
font=
|
|
535
|
+
font=Torus_Regular_25,
|
|
475
536
|
anchor="mm",
|
|
476
537
|
)
|
|
477
538
|
draw.text(
|
|
478
|
-
(
|
|
539
|
+
(1066, 666),
|
|
479
540
|
f"{score_info.statistics.miss or 0}",
|
|
480
|
-
font=
|
|
541
|
+
font=Torus_Regular_25,
|
|
481
542
|
anchor="mm",
|
|
482
543
|
)
|
|
483
544
|
elif score_info.ruleset_id in {1, 5}:
|
|
484
545
|
draw.text(
|
|
485
|
-
(
|
|
546
|
+
(768, 577),
|
|
486
547
|
f"{score_info.accuracy:.2f}%",
|
|
487
|
-
font=
|
|
548
|
+
font=Torus_Regular_25,
|
|
488
549
|
anchor="mm",
|
|
489
550
|
)
|
|
490
|
-
draw.text((
|
|
491
|
-
draw.text((
|
|
551
|
+
draw.text((768, 666), f"{score_info.max_combo:,}", font=Torus_Regular_25, anchor="mm")
|
|
552
|
+
draw.text((768, 438), f"{pp_info.pp:.0f}", font=Torus_Regular_50, anchor="mm")
|
|
553
|
+
draw.text((933, 393), f"{ss_pp}", font=Torus_Regular_25, anchor="mm")
|
|
492
554
|
draw.text(
|
|
493
|
-
(
|
|
555
|
+
(933, 577),
|
|
494
556
|
f"{score_info.statistics.great or 0}",
|
|
495
|
-
font=
|
|
557
|
+
font=Torus_Regular_25,
|
|
496
558
|
anchor="mm",
|
|
497
559
|
)
|
|
498
560
|
draw.text(
|
|
499
|
-
(
|
|
561
|
+
(1066, 577),
|
|
500
562
|
f"{score_info.statistics.ok or 0}",
|
|
501
|
-
font=
|
|
563
|
+
font=Torus_Regular_25,
|
|
502
564
|
anchor="mm",
|
|
503
565
|
)
|
|
504
566
|
draw.text(
|
|
505
|
-
(
|
|
567
|
+
(933, 666),
|
|
506
568
|
f"{score_info.statistics.miss or 0}",
|
|
507
|
-
font=
|
|
569
|
+
font=Torus_Regular_25,
|
|
508
570
|
anchor="mm",
|
|
509
571
|
)
|
|
510
572
|
elif score_info.ruleset_id in {2, 6}:
|
|
511
573
|
draw.text(
|
|
512
|
-
(
|
|
574
|
+
(768, 577),
|
|
513
575
|
f"{score_info.accuracy:.2f}%",
|
|
514
|
-
font=
|
|
576
|
+
font=Torus_Regular_25,
|
|
515
577
|
anchor="mm",
|
|
516
578
|
)
|
|
517
579
|
draw.text(
|
|
518
|
-
(
|
|
580
|
+
(768, 666),
|
|
519
581
|
f"{score_info.max_combo}/{pp_info.difficulty.max_combo}",
|
|
520
|
-
font=
|
|
582
|
+
font=Torus_Regular_25,
|
|
521
583
|
anchor="mm",
|
|
522
584
|
)
|
|
523
|
-
draw.text((
|
|
585
|
+
draw.text((768, 438), f"{pp_info.pp:.0f}", font=Torus_Regular_50, anchor="mm")
|
|
586
|
+
draw.text((933, 393), f"{ss_pp}", font=Torus_Regular_25, anchor="mm")
|
|
524
587
|
draw.text(
|
|
525
|
-
(
|
|
588
|
+
(933, 577),
|
|
526
589
|
f"{score_info.statistics.great or 0}",
|
|
527
|
-
font=
|
|
590
|
+
font=Torus_Regular_25,
|
|
528
591
|
anchor="mm",
|
|
529
592
|
)
|
|
530
593
|
draw.text(
|
|
531
|
-
(
|
|
594
|
+
(1066, 577),
|
|
532
595
|
f"{score_info.statistics.large_tick_hit or 0}",
|
|
533
|
-
font=
|
|
596
|
+
font=Torus_Regular_25,
|
|
534
597
|
anchor="mm",
|
|
535
598
|
)
|
|
536
599
|
draw.text(
|
|
537
|
-
(
|
|
600
|
+
(933, 666),
|
|
538
601
|
f"{score_info.statistics.small_tick_miss or 0}",
|
|
539
|
-
font=
|
|
602
|
+
font=Torus_Regular_25,
|
|
540
603
|
anchor="mm",
|
|
541
604
|
)
|
|
542
605
|
draw.text(
|
|
543
|
-
(
|
|
606
|
+
(1066, 666),
|
|
544
607
|
f"{score_info.statistics.miss or 0}",
|
|
545
|
-
font=
|
|
608
|
+
font=Torus_Regular_25,
|
|
546
609
|
anchor="mm",
|
|
547
610
|
)
|
|
548
611
|
else:
|
|
549
612
|
draw.text(
|
|
550
|
-
(
|
|
613
|
+
(933, 600),
|
|
551
614
|
(
|
|
552
615
|
f"{score_info.statistics.perfect / score_info.statistics.great:.1f}:1"
|
|
553
616
|
if (score_info.statistics.great or 0) != 0
|
|
554
617
|
else "∞:1"
|
|
555
618
|
),
|
|
556
|
-
font=
|
|
619
|
+
font=Torus_Regular_15,
|
|
557
620
|
anchor="mm",
|
|
558
621
|
)
|
|
559
622
|
draw.text(
|
|
560
|
-
(
|
|
623
|
+
(768, 577),
|
|
561
624
|
f"{score_info.accuracy:.2f}%",
|
|
562
|
-
font=
|
|
625
|
+
font=Torus_Regular_25,
|
|
563
626
|
anchor="mm",
|
|
564
627
|
)
|
|
565
|
-
draw.text((
|
|
566
|
-
draw.text((
|
|
628
|
+
draw.text((768, 666), f"{score_info.max_combo}", font=Torus_Regular_25, anchor="mm")
|
|
629
|
+
draw.text((768, 438), f"{pp_info.pp:.0f}", font=Torus_Regular_50, anchor="mm")
|
|
630
|
+
draw.text((933, 393), f"{ss_pp}", font=Torus_Regular_25, anchor="mm")
|
|
567
631
|
draw.text(
|
|
568
|
-
(
|
|
632
|
+
(933, 577),
|
|
569
633
|
f"{score_info.statistics.perfect or 0}",
|
|
570
|
-
font=
|
|
634
|
+
font=Torus_Regular_25,
|
|
571
635
|
anchor="mm",
|
|
572
636
|
)
|
|
573
637
|
draw.text(
|
|
574
|
-
(
|
|
638
|
+
(1066, 577),
|
|
575
639
|
f"{score_info.statistics.great or 0}",
|
|
576
|
-
font=
|
|
640
|
+
font=Torus_Regular_25,
|
|
577
641
|
anchor="mm",
|
|
578
642
|
)
|
|
579
643
|
draw.text(
|
|
580
|
-
(
|
|
644
|
+
(1200, 577),
|
|
581
645
|
f"{score_info.statistics.good or 0}",
|
|
582
|
-
font=
|
|
646
|
+
font=Torus_Regular_25,
|
|
583
647
|
anchor="mm",
|
|
584
648
|
)
|
|
585
649
|
draw.text(
|
|
586
|
-
(
|
|
650
|
+
(933, 666),
|
|
587
651
|
f"{score_info.statistics.ok or 0}",
|
|
588
|
-
font=
|
|
652
|
+
font=Torus_Regular_25,
|
|
589
653
|
anchor="mm",
|
|
590
654
|
)
|
|
591
655
|
draw.text(
|
|
592
|
-
(
|
|
656
|
+
(1066, 666),
|
|
593
657
|
f"{score_info.statistics.meh or 0}",
|
|
594
|
-
font=
|
|
658
|
+
font=Torus_Regular_25,
|
|
595
659
|
anchor="mm",
|
|
596
660
|
)
|
|
597
661
|
draw.text(
|
|
598
|
-
(
|
|
662
|
+
(1200, 666),
|
|
599
663
|
f"{score_info.statistics.miss or 0}",
|
|
600
|
-
font=
|
|
664
|
+
font=Torus_Regular_25,
|
|
601
665
|
anchor="mm",
|
|
602
666
|
)
|
|
603
667
|
user_icon = await open_user_icon(info, source)
|
|
@@ -607,7 +671,7 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
607
671
|
if not getattr(user_icon, "is_animated", False):
|
|
608
672
|
icon_bg = user_icon.convert("RGBA").resize((170, 170))
|
|
609
673
|
icon_img = draw_fillet(icon_bg, 15)
|
|
610
|
-
im.alpha_composite(icon_img, (
|
|
674
|
+
im.alpha_composite(icon_img, (27, 532))
|
|
611
675
|
byt = BytesIO()
|
|
612
676
|
im.convert("RGB").save(byt, "jpeg")
|
|
613
677
|
im.close()
|
|
@@ -620,7 +684,7 @@ async def draw_score_pic(score_info: UnifiedScore, info: UnifiedUser, map_json,
|
|
|
620
684
|
# 创建一个新的 RGBA 图片,将 PNG 图片作为背景,将当前帧添加到背景上
|
|
621
685
|
rgba_frame = Image.new("RGBA", im.size, (0, 0, 0, 0))
|
|
622
686
|
rgba_frame.paste(im, (0, 0), im)
|
|
623
|
-
rgba_frame.paste(gif_frame, (
|
|
687
|
+
rgba_frame.paste(gif_frame, (27, 532), gif_frame)
|
|
624
688
|
# 将 RGBA 图片转换为 RGB 模式,并添加到 GIF 图片中
|
|
625
689
|
gif_frames.append(rgba_frame)
|
|
626
690
|
gif_bytes = BytesIO()
|
|
@@ -15,14 +15,15 @@ Torus_Regular_35 = ImageFont.truetype(str(osufile / "fonts" / "Torus Regular.otf
|
|
|
15
15
|
Torus_Regular_40 = ImageFont.truetype(str(osufile / "fonts" / "Torus Regular.otf"), 40)
|
|
16
16
|
Torus_Regular_45 = ImageFont.truetype(str(osufile / "fonts" / "Torus Regular.otf"), 45)
|
|
17
17
|
Torus_Regular_50 = ImageFont.truetype(str(osufile / "fonts" / "Torus Regular.otf"), 50)
|
|
18
|
-
|
|
18
|
+
Torus_Regular_60 = ImageFont.truetype(str(osufile / "fonts" / "Torus Regular.otf"), 60)
|
|
19
|
+
Torus_SemiBold_15 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 15)
|
|
19
20
|
Torus_SemiBold_20 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 20)
|
|
20
21
|
Torus_SemiBold_25 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 25)
|
|
21
22
|
Torus_SemiBold_30 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 30)
|
|
22
23
|
Torus_SemiBold_40 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 40)
|
|
23
24
|
Torus_SemiBold_45 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 45)
|
|
24
25
|
Torus_SemiBold_50 = ImageFont.truetype(str(osufile / "fonts" / "Torus SemiBold.otf"), 50)
|
|
25
|
-
|
|
26
|
+
Venera_60 = ImageFont.truetype(str(osufile / "fonts" / "Venera.otf"), 60)
|
|
26
27
|
extra_30 = ImageFont.truetype(str(osufile / "fonts" / "Extra.otf"), 30)
|
|
27
28
|
|
|
28
29
|
InfoImg = Image.open(osufile / "info.png").convert("RGBA")
|
|
@@ -36,6 +37,7 @@ MapBg = Image.open(osufile / "beatmapinfo.png").convert("RGBA")
|
|
|
36
37
|
MapBg1 = Image.open(osufile / "maniabeatmapinfo.png").convert("RGBA")
|
|
37
38
|
BarImg = Image.open(osufile / "work" / "bmap.png").convert("RGBA")
|
|
38
39
|
Stars = Image.open(osufile / "work" / "stars.png").convert("RGBA")
|
|
40
|
+
Stardiff = Image.open(osufile / "work" / "stardiff.png").convert("RGBA")
|
|
39
41
|
TeamBlue = Image.open(osufile / "match" / "team_blue.png").convert("RGBA")
|
|
40
42
|
TeamRed = Image.open(osufile / "match" / "team_red.png").convert("RGBA")
|
|
41
43
|
MpLink = Image.open(osufile / "match" / "mplink.png").convert("RGBA")
|
|
@@ -6,13 +6,14 @@ from io import BytesIO
|
|
|
6
6
|
from typing import Union, Optional
|
|
7
7
|
from difflib import SequenceMatcher
|
|
8
8
|
|
|
9
|
+
from PIL.ImageFile import ImageFile
|
|
9
10
|
from matplotlib.figure import Figure
|
|
10
11
|
from PIL import ImageDraw, ImageFilter, ImageEnhance, UnidentifiedImageError
|
|
11
12
|
|
|
12
13
|
from ..schema.user import UnifiedUser
|
|
13
14
|
from ..schema import SeasonalBackgrounds
|
|
14
15
|
from ..api import safe_async_get, get_seasonal_bg
|
|
15
|
-
from .static import Path, Image,
|
|
16
|
+
from .static import Path, Image, ColorArr, np, osufile
|
|
16
17
|
from ..file import map_path, download_osu, get_projectimg, user_cache_path, team_cache_path
|
|
17
18
|
|
|
18
19
|
|
|
@@ -120,8 +121,8 @@ def draw_acc(img: Image, acc: float, mode: int):
|
|
|
120
121
|
ax.clear()
|
|
121
122
|
fig.clf()
|
|
122
123
|
fig.clear()
|
|
123
|
-
score_acc_img = Image.open(acc_img).convert("RGBA").resize((
|
|
124
|
-
img.alpha_composite(score_acc_img, (
|
|
124
|
+
score_acc_img = Image.open(acc_img).convert("RGBA").resize((384, 288))
|
|
125
|
+
img.alpha_composite(score_acc_img, (580, 35))
|
|
125
126
|
return img
|
|
126
127
|
|
|
127
128
|
|
|
@@ -183,7 +184,7 @@ async def crop_bg(size: tuple[int, int], path: Union[str, Path, BytesIO, Image.I
|
|
|
183
184
|
return sf
|
|
184
185
|
|
|
185
186
|
|
|
186
|
-
def stars_diff(stars: float):
|
|
187
|
+
def stars_diff(stars: float, stars_bg: ImageFile):
|
|
187
188
|
if stars < 0.1:
|
|
188
189
|
r, g, b = 170, 170, 170
|
|
189
190
|
elif stars >= 9:
|
|
@@ -192,10 +193,10 @@ def stars_diff(stars: float):
|
|
|
192
193
|
# 颜色取色参考 https://github.com/ppy/osu-web/blob/97997d9c7b7f9c49f9b3cdd776c71afb9872c34b/resources/js/utils/beatmap-helper.ts#L20
|
|
193
194
|
r, g, b, _a = ColorArr[int(stars * 100)]
|
|
194
195
|
# 打开底图
|
|
195
|
-
xx, yy =
|
|
196
|
+
xx, yy = stars_bg.size
|
|
196
197
|
# 填充背景
|
|
197
|
-
img = Image.new("RGBA",
|
|
198
|
-
img.paste(
|
|
198
|
+
img = Image.new("RGBA", stars_bg.size, (r, g, b))
|
|
199
|
+
img.paste(stars_bg, (0, 0, xx, yy), stars_bg)
|
|
199
200
|
# 把白色变透明
|
|
200
201
|
arr = np.array(img)
|
|
201
202
|
# 创建mask,将白色替换为True,其他颜色替换为False
|
|
@@ -438,3 +439,18 @@ def trim_text_with_ellipsis(text, max_width, font):
|
|
|
438
439
|
|
|
439
440
|
# 返回截断后的字符串 + 省略号
|
|
440
441
|
return truncated_text + ellipsis_symbol if truncated_text else ellipsis_symbol
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
# 字体描边函数
|
|
445
|
+
def draw_text_with_outline(draw, position, text, font, anchor, fill):
|
|
446
|
+
for dx in [-1, 0, 1]:
|
|
447
|
+
for dy in [-1, 0, 1]:
|
|
448
|
+
if dx != 0 or dy != 0:
|
|
449
|
+
draw.text(
|
|
450
|
+
(position[0] + dx, position[1] + dy),
|
|
451
|
+
text,
|
|
452
|
+
font=font,
|
|
453
|
+
anchor=anchor,
|
|
454
|
+
fill=(0, 0, 0, 255),
|
|
455
|
+
)
|
|
456
|
+
draw.text(position, text, font=font, anchor=anchor, fill=fill)
|
|
@@ -7,9 +7,8 @@ from nonebot_plugin_alconna import UniMessage
|
|
|
7
7
|
|
|
8
8
|
from ..utils import NGM
|
|
9
9
|
from .utils import split_msg
|
|
10
|
-
from ..schema import NewScore
|
|
11
10
|
from ..database import UserData
|
|
12
|
-
from ..api import
|
|
11
|
+
from ..api import get_user_scores, get_users
|
|
13
12
|
from ..exceptions import NetworkError
|
|
14
13
|
from ..draw.score import cal_score_info
|
|
15
14
|
from ..draw.echarts import draw_bpa_plot
|
|
@@ -35,17 +34,11 @@ async def _(event: Event, state: T_State):
|
|
|
35
34
|
uid = state["user"]
|
|
36
35
|
lazer_mode = "lazer模式下" if state["is_lazer"] else "stable模式下"
|
|
37
36
|
try:
|
|
38
|
-
|
|
39
|
-
"bp",
|
|
40
|
-
uid,
|
|
41
|
-
NGM[state["mode"]],
|
|
42
|
-
legacy_only=int(not user.lazer_mode),
|
|
43
|
-
)
|
|
37
|
+
score_ls = await get_user_scores(uid, NGM[state["mode"]], "best", legacy_only=not state["is_lazer"])
|
|
44
38
|
except NetworkError as e:
|
|
45
39
|
await UniMessage.text(
|
|
46
40
|
f"在查找用户:{state['username']} {NGM[state['mode']]}模式 {lazer_mode}时 {str(e)}"
|
|
47
41
|
).finish(reply_to=True)
|
|
48
|
-
score_ls = [NewScore(**i) for i in bp_info]
|
|
49
42
|
for score in score_ls:
|
|
50
43
|
for mod in score.mods:
|
|
51
44
|
if mod.acronym == "DT" or mod.acronym == "NC":
|
|
@@ -106,6 +99,6 @@ async def _(event: Event, state: T_State):
|
|
|
106
99
|
mapper_pp_data.append({"name": user_dic.get(mapper, ""), "value": round(pp, 2)})
|
|
107
100
|
if len(mapper_pp_data) > 20:
|
|
108
101
|
mapper_pp_data = mapper_pp_data[:20]
|
|
109
|
-
name = f"{
|
|
102
|
+
name = f"{state['username']} {NGM[state['mode']]} 模式 "
|
|
110
103
|
byt = await draw_bpa_plot(name, pp_ls, length_ls, pp_data, mapper_pp_data)
|
|
111
104
|
await UniMessage.image(raw=byt).finish(reply_to=True)
|
|
@@ -16,6 +16,8 @@ from nonebot.internal.rule import Rule, Event
|
|
|
16
16
|
from nonebot_plugin_alconna import At, UniMsg, UniMessage
|
|
17
17
|
from nonebot_plugin_session import SessionId, SessionIdType
|
|
18
18
|
|
|
19
|
+
from ..draw.taiko_preview import parse_map, map_to_image
|
|
20
|
+
from ..schema.score import UnifiedScore
|
|
19
21
|
from ..utils import NGM
|
|
20
22
|
from ..info import get_bg
|
|
21
23
|
from .utils import split_msg
|
|
@@ -23,7 +25,7 @@ from ..schema import NewScore
|
|
|
23
25
|
from ..exceptions import NetworkError
|
|
24
26
|
from ..database.models import UserData
|
|
25
27
|
from ..mania import generate_preview_pic
|
|
26
|
-
from ..api import
|
|
28
|
+
from ..api import safe_async_get, get_user_scores
|
|
27
29
|
from ..file import map_path, download_tmp_osu
|
|
28
30
|
from ..draw.catch_preview import draw_cath_preview
|
|
29
31
|
|
|
@@ -46,23 +48,27 @@ data_path = Path() / "data" / "osu"
|
|
|
46
48
|
pcm_path = data_path / "out.pcm"
|
|
47
49
|
|
|
48
50
|
|
|
49
|
-
async def get_random_beatmap_set(binded_id, group_id
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
async def get_random_beatmap_set(binded_id, group_id) -> (UnifiedScore, str):
|
|
52
|
+
# 获取已猜过的歌曲集合
|
|
53
|
+
guessed_songs = guess_song_cache[group_id]
|
|
54
|
+
available_scores = []
|
|
55
|
+
for user_id in binded_id:
|
|
56
|
+
try:
|
|
57
|
+
user = await UserData.filter(user_id=user_id).first()
|
|
58
|
+
if not user:
|
|
59
|
+
continue
|
|
60
|
+
bp_info = await get_user_scores(user.osu_id, NGM[str(user.osu_mode)], "best")
|
|
61
|
+
# 过滤掉已猜过的歌曲
|
|
62
|
+
unguessed_scores = [(score, user.osu_name) for score in bp_info if score.beatmapset.id not in guessed_songs]
|
|
63
|
+
available_scores.extend(unguessed_scores)
|
|
64
|
+
except NetworkError:
|
|
65
|
+
continue # 跳过网络错误的用户,继续尝试其他用户
|
|
66
|
+
if not available_scores:
|
|
67
|
+
return None, None # 所有歌曲都被猜过了
|
|
68
|
+
# 随机选择一个未猜过的成绩
|
|
69
|
+
selected_score, osu_name = random.choice(available_scores)
|
|
70
|
+
guess_song_cache[group_id].add(selected_score.beatmapset.id)
|
|
71
|
+
return selected_score, osu_name
|
|
66
72
|
|
|
67
73
|
|
|
68
74
|
@guess_audio.handle(parameterless=[split_msg()])
|
|
@@ -89,12 +95,11 @@ async def _(
|
|
|
89
95
|
if not user_data:
|
|
90
96
|
await UniMessage.text("该用户未绑定osu账号").finish(reply_to=True)
|
|
91
97
|
try:
|
|
92
|
-
|
|
98
|
+
bp_ls = await get_user_scores(user_data.osu_id, NGM[state["mode"]], "best")
|
|
93
99
|
except NetworkError as e:
|
|
94
100
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
95
101
|
reply_to=True
|
|
96
102
|
)
|
|
97
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
98
103
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[group_id]]
|
|
99
104
|
if not filtered_bp_ls:
|
|
100
105
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -103,12 +108,11 @@ async def _(
|
|
|
103
108
|
selected_user = user_data.osu_name
|
|
104
109
|
elif state["user"]:
|
|
105
110
|
try:
|
|
106
|
-
|
|
111
|
+
bp_ls = await get_user_scores(state["user"], NGM[state["mode"]], "best")
|
|
107
112
|
except NetworkError as e:
|
|
108
113
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
109
114
|
reply_to=True
|
|
110
115
|
)
|
|
111
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
112
116
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[group_id]]
|
|
113
117
|
if not filtered_bp_ls:
|
|
114
118
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -354,12 +358,11 @@ async def _(
|
|
|
354
358
|
if not user_data:
|
|
355
359
|
await UniMessage.text("该用户未绑定osu账号").finish(reply_to=True)
|
|
356
360
|
try:
|
|
357
|
-
|
|
361
|
+
bp_ls = await get_user_scores(user_data.osu_id, NGM[state["mode"]], "best")
|
|
358
362
|
except NetworkError as e:
|
|
359
363
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
360
364
|
reply_to=True
|
|
361
365
|
)
|
|
362
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
363
366
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[session_id]]
|
|
364
367
|
if not filtered_bp_ls:
|
|
365
368
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -368,12 +371,11 @@ async def _(
|
|
|
368
371
|
selected_user = user_data.osu_name
|
|
369
372
|
elif state["user"]:
|
|
370
373
|
try:
|
|
371
|
-
|
|
374
|
+
bp_ls = await get_user_scores(state["user"], NGM[state["mode"]], "best")
|
|
372
375
|
except NetworkError as e:
|
|
373
376
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
374
377
|
reply_to=True
|
|
375
378
|
)
|
|
376
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
377
379
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[session_id]]
|
|
378
380
|
if not filtered_bp_ls:
|
|
379
381
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -422,7 +424,7 @@ async def _(
|
|
|
422
424
|
await UniMessage.text("由于未绑定OSU账号,本次随机选择模式进行猜歌\n" + state["error"]).send(reply_to=True)
|
|
423
425
|
else:
|
|
424
426
|
mode = state["mode"]
|
|
425
|
-
if mode == "0"
|
|
427
|
+
if mode == "0":
|
|
426
428
|
await UniMessage.text("该模式暂不支持猜歌").finish(reply_to=True)
|
|
427
429
|
binded_id = await UserData.filter(osu_mode=mode).values_list("user_id", flat=True)
|
|
428
430
|
if not binded_id:
|
|
@@ -435,12 +437,11 @@ async def _(
|
|
|
435
437
|
if not user_data:
|
|
436
438
|
await UniMessage.text("该用户未绑定osu账号").finish(reply_to=True)
|
|
437
439
|
try:
|
|
438
|
-
|
|
440
|
+
bp_ls = await get_user_scores(user_data.osu_id, NGM[state["mode"]], "best")
|
|
439
441
|
except NetworkError as e:
|
|
440
442
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
441
443
|
reply_to=True
|
|
442
444
|
)
|
|
443
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
444
445
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[session_id]]
|
|
445
446
|
if not filtered_bp_ls:
|
|
446
447
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -449,12 +450,11 @@ async def _(
|
|
|
449
450
|
guess_song_cache[session_id].add(selected_score.beatmapset.id)
|
|
450
451
|
elif state["user"]:
|
|
451
452
|
try:
|
|
452
|
-
|
|
453
|
+
bp_ls = await get_user_scores(state["user"], NGM[state["mode"]], "best")
|
|
453
454
|
except NetworkError as e:
|
|
454
455
|
await UniMessage.text(f"在查找用户:{state['username']} {NGM[state['mode']]}模式bp时 {str(e)}").finish(
|
|
455
456
|
reply_to=True
|
|
456
457
|
)
|
|
457
|
-
bp_ls = [NewScore(**i) for i in bp_info]
|
|
458
458
|
filtered_bp_ls = [i for i in bp_ls if i.beatmapset.id not in guess_song_cache[session_id]]
|
|
459
459
|
if not filtered_bp_ls:
|
|
460
460
|
await UniMessage.text(state["username"] + "的bp已经被你们猜过一遍了 -_-").finish(reply_to=True)
|
|
@@ -471,18 +471,18 @@ async def _(
|
|
|
471
471
|
chart_set_timeout(matcher, session_id)
|
|
472
472
|
if mode == "3":
|
|
473
473
|
osu = await download_tmp_osu(selected_score.beatmap.id)
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
474
|
+
pic = await generate_preview_pic(osu)
|
|
475
|
+
elif mode == "1":
|
|
476
|
+
osu = await download_tmp_osu(selected_score.beatmap.id)
|
|
477
|
+
beatmap = parse_map(osu)
|
|
478
|
+
pic = map_to_image(beatmap)
|
|
479
479
|
else:
|
|
480
480
|
mods = [i.acronym for i in selected_score.mods]
|
|
481
481
|
pic = await draw_cath_preview(selected_score.beatmap.id, selected_score.beatmapset.id, mods)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
482
|
+
await (
|
|
483
|
+
UniMessage.text(f"开始谱面猜歌游戏,猜猜下面谱面的曲名吧,该曲抽选自 {selected_user} 的bp")
|
|
484
|
+
+ UniMessage.image(raw=pic)
|
|
485
|
+
).finish()
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
@chart_word_matcher.handle()
|
|
@@ -33,7 +33,9 @@ def split_msg():
|
|
|
33
33
|
state["query"] = []
|
|
34
34
|
state["target"] = None
|
|
35
35
|
state["is_lazer"] = True if not user_data else user_data.lazer_mode
|
|
36
|
-
arg =
|
|
36
|
+
arg = (
|
|
37
|
+
arg.extract_plain_text().strip().replace("=", "=").replace(":", ":").replace("&", "&").replace("#", "#")
|
|
38
|
+
)
|
|
37
39
|
matches = re.findall(pattern, arg)
|
|
38
40
|
for match in matches:
|
|
39
41
|
if match[0]:
|
|
@@ -85,9 +87,9 @@ def split_msg():
|
|
|
85
87
|
if state["source"] == "ppysb" and not arg.strip():
|
|
86
88
|
sb_user_data = await SbUserData.get_or_none(user_id=qq)
|
|
87
89
|
if sb_user_data:
|
|
88
|
-
state["user"] = sb_user_data.osu_id
|
|
89
|
-
state["username"] = sb_user_data.osu_name
|
|
90
|
+
state["user"] = sb_user_data.osu_id
|
|
91
|
+
state["username"] = sb_user_data.osu_name
|
|
90
92
|
else:
|
|
91
|
-
state["error"] = "该账号尚未绑定sb 服务器,请输入 /sbbind 用户名 绑定账号"
|
|
93
|
+
state["error"] = "该账号尚未绑定 sb 服务器,请输入 /sbbind 用户名 绑定账号"
|
|
92
94
|
|
|
93
95
|
return Depends(dependency)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import asyncio
|
|
3
|
+
from ..config import Config
|
|
4
|
+
from httpx import AsyncClient
|
|
5
|
+
from nonebot import get_plugin_config
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
plugin_config = get_plugin_config(Config)
|
|
9
|
+
proxy = plugin_config.osu_proxy
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class NetworkManager:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self._client = None
|
|
15
|
+
self._lock = asyncio.Lock()
|
|
16
|
+
|
|
17
|
+
async def get_client(self) -> AsyncClient:
|
|
18
|
+
if self._client is None:
|
|
19
|
+
async with self._lock:
|
|
20
|
+
if self._client is None:
|
|
21
|
+
self._client = AsyncClient(
|
|
22
|
+
proxy=proxy,
|
|
23
|
+
follow_redirects=True,
|
|
24
|
+
limits=httpx.Limits(max_keepalive_connections=20, max_connections=100, keepalive_expiry=30),
|
|
25
|
+
timeout=httpx.Timeout(30.0),
|
|
26
|
+
)
|
|
27
|
+
return self._client
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
network_manager = NetworkManager()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -113,6 +113,7 @@ class UnifiedBeatmap(Base):
|
|
|
113
113
|
ar: float
|
|
114
114
|
hp: float
|
|
115
115
|
stars: float
|
|
116
|
+
user_id: int
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
class UnifiedScore(Base):
|
|
@@ -127,3 +128,4 @@ class UnifiedScore(Base):
|
|
|
127
128
|
statistics: NewStatistics
|
|
128
129
|
beatmap: Optional[UnifiedBeatmap] = None
|
|
129
130
|
passed: bool
|
|
131
|
+
pp: Optional[float] = None
|
|
@@ -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=-KTefbeRJJwXD0I2hywJfD3ogpLyrrphJoZGoru_3U4,16410
|
|
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
|
|
@@ -17,7 +17,7 @@ nonebot_plugin_osubot/draw/catch_preview_templates/js/beatmap/timingpoint.js,sha
|
|
|
17
17
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/LegacyRandom.js,sha256=HDiks3FCVQBtVK5VzN7YV9Ekkk_WHYi0fPk3-XCQaj8,2155
|
|
18
18
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/PalpableCatchHitObject.js,sha256=CnUBiIkAqFUaCrc5TXRtL_fuK20NeK1yMti1Sp4dJAE,5702
|
|
19
19
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/bananashower.js,sha256=sPISMifUWVXK9nXuOD7JUPeXBNPBKquiDNKpYzbSJyg,988
|
|
20
|
-
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/catch.js,sha256=
|
|
20
|
+
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/catch.js,sha256=uLbMrZBZfvj1YxJVIeirFWVVJ2apLPfB1VY_KHq-hSE,34561
|
|
21
21
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/fruit.js,sha256=ABvFMbmXP0t5wACUhSVbu8sVJ845mWJ9sWiQJtMV5co,437
|
|
22
22
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/catch/juicestream.js,sha256=kWjmPtT_UgnUlg5G-_8q-1AyNTv6GLRp0bOOfiMcojc,7347
|
|
23
23
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/fakeaudio.js,sha256=gJrdVwNrAVjWx80z_XkzybL9ldfV97nKl7k1v7NulBg,1211
|
|
@@ -36,20 +36,20 @@ nonebot_plugin_osubot/draw/catch_preview_templates/js/standard/spinner.js,sha256
|
|
|
36
36
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/util.js,sha256=XveUlX-d0vrUnXaGbR8y428s6Nw2zhDR235pFko_MxM,1504
|
|
37
37
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/viewbox.js,sha256=RPsUyoKNAQub2n7oUGwWyFppZu0iVuy6DD5gggQZS3E,1641
|
|
38
38
|
nonebot_plugin_osubot/draw/catch_preview_templates/js/zip.min.js,sha256=pQmrVxuGCMeLS-XS3QsVhzjwap28fr9Ya083uPlg1sM,86405
|
|
39
|
-
nonebot_plugin_osubot/draw/catch_preview_templates/pic.html,sha256=
|
|
39
|
+
nonebot_plugin_osubot/draw/catch_preview_templates/pic.html,sha256=jwPxxyYFLGpbD29h8u_j3LBY33ya7BS2R_t95EldAmk,3092
|
|
40
40
|
nonebot_plugin_osubot/draw/echarts.py,sha256=OzL_397yWrDAIXsEWf72hAiqdIUBz1D182cli6ORD6s,1037
|
|
41
41
|
nonebot_plugin_osubot/draw/info.py,sha256=i2YcJmSdTpwhZl_nDe7GJv4jQTB8_9oBfpq2Zw2hwo0,11162
|
|
42
42
|
nonebot_plugin_osubot/draw/map.py,sha256=4M8xRd0dIbC5g1s8I4eTZ3vRglM6r_TSznFOZ62K2wk,8654
|
|
43
43
|
nonebot_plugin_osubot/draw/match_history.py,sha256=GBJl6lAA27U7NSMC2isEzD_YsoIPAeG6ijDu7Oflcl0,997
|
|
44
44
|
nonebot_plugin_osubot/draw/rating.py,sha256=pA7mGLI4IujmYB6kQf_tSkR7mZGpUAVLRLyaAsZhqTM,20397
|
|
45
|
-
nonebot_plugin_osubot/draw/score.py,sha256=
|
|
46
|
-
nonebot_plugin_osubot/draw/static.py,sha256=
|
|
45
|
+
nonebot_plugin_osubot/draw/score.py,sha256=z7HNBOFVHaarbeo2FK8vIpoGVhu47E2BgCqG_axTwSo,29610
|
|
46
|
+
nonebot_plugin_osubot/draw/static.py,sha256=wdlzNO3xyiauKiMLr_h-B9uAsFU7fX_Y-fOusYKZP3k,4132
|
|
47
47
|
nonebot_plugin_osubot/draw/taiko_preview.py,sha256=tqhuHSdxUJEuXqKHMJDeSLdusuJhSnMMiaG5FbUnaJw,11441
|
|
48
|
-
nonebot_plugin_osubot/draw/templates/bpa_chart.html,sha256=
|
|
48
|
+
nonebot_plugin_osubot/draw/templates/bpa_chart.html,sha256=R-fO46HtmC4y3brMFGz6MQkna8ke7WGHVIgUnvcY248,7012
|
|
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=6QDbByPQZCxI0k_i5MsExyWZ-sHgJUw6nEWLv85IgLY,15826
|
|
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
|
|
@@ -59,9 +59,9 @@ nonebot_plugin_osubot/mania/__init__.py,sha256=XRPn563jDJiPohFekcoFFCqCJYznb-6uO
|
|
|
59
59
|
nonebot_plugin_osubot/matcher/__init__.py,sha256=yID7QcdQF6_Mouwbej3JwYUBbKSU3VQdrjq6B1Fz9P8,1331
|
|
60
60
|
nonebot_plugin_osubot/matcher/bind.py,sha256=QQJc2S7XFo5tu4CPloIET6fKaeiQixgb8M7QvULV6E0,2834
|
|
61
61
|
nonebot_plugin_osubot/matcher/bp.py,sha256=GidJfuZ9lJ7LwMq126DDOwMksNUOz4Bkab83OlKg8t8,3983
|
|
62
|
-
nonebot_plugin_osubot/matcher/bp_analyze.py,sha256=
|
|
62
|
+
nonebot_plugin_osubot/matcher/bp_analyze.py,sha256=L2ccAi7TQvpD036DyA27D8wuiqBBkcfLT0ldk_Apv8w,3820
|
|
63
63
|
nonebot_plugin_osubot/matcher/getbg.py,sha256=Ar2yIST556MYRxzuXCLSDAMAmESRENN1fCty-kdH7PI,699
|
|
64
|
-
nonebot_plugin_osubot/matcher/guess.py,sha256=
|
|
64
|
+
nonebot_plugin_osubot/matcher/guess.py,sha256=QmD-a88pnPfSSBAvSpD2tlHDGMRpYWqtxfNuLsHuBYM,24144
|
|
65
65
|
nonebot_plugin_osubot/matcher/history.py,sha256=ZYkVJHdXuVJmhovRhwxFdqNp0o2uJJOACAZhhutyS3w,1577
|
|
66
66
|
nonebot_plugin_osubot/matcher/info.py,sha256=8CJHTOMTx_nzJ4ZwXo6ZfBwCuO3DtLprRX7jnMtPilk,858
|
|
67
67
|
nonebot_plugin_osubot/matcher/map.py,sha256=sFpOoFv63y-NOkCJhE6aW0DRYDl_8SoQOPsdq50QxT0,1404
|
|
@@ -80,11 +80,12 @@ nonebot_plugin_osubot/matcher/score.py,sha256=Nk6dpDlszKJKdboTSQRBf-wMGioHIPqKSV
|
|
|
80
80
|
nonebot_plugin_osubot/matcher/update.py,sha256=MHpxoJmU0hKW82XuM9YpyCxUUjjiNKwejnRgYwueR4Q,3168
|
|
81
81
|
nonebot_plugin_osubot/matcher/update_mode.py,sha256=0Wy6Y1-rN7XcqBZyo37mYFdixq-4HxCwZftUaiYhZqE,1602
|
|
82
82
|
nonebot_plugin_osubot/matcher/url_match.py,sha256=opx4DYSQ83tk0qlMOBirl4TC49WXHgMZ04lMr9NCHNs,746
|
|
83
|
-
nonebot_plugin_osubot/matcher/utils.py,sha256=
|
|
83
|
+
nonebot_plugin_osubot/matcher/utils.py,sha256=gWmNa31wUxcY_PNSNLy348x5_7sTY9ttMKH-5V5jkuE,4304
|
|
84
84
|
nonebot_plugin_osubot/mods.py,sha256=vxIWYX0HwTxetPAHWZK5ojEMfqV9HFlWT0YC4Yncgb8,1402
|
|
85
85
|
nonebot_plugin_osubot/network/__init__.py,sha256=WOijcd81yhnpGKYeiDIOxbBDVI12GHPRGoOFfxrUuQk,61
|
|
86
86
|
nonebot_plugin_osubot/network/auto_retry.py,sha256=vDfYGbEVPF6WZLYXmRVkNvaxf6_6RyIqEAcA7TRwV_k,565
|
|
87
87
|
nonebot_plugin_osubot/network/first_response.py,sha256=zETRc6g0AG8ExLyHZTLUl7uzUCdUVIL0IfxvdEtCPt0,932
|
|
88
|
+
nonebot_plugin_osubot/network/manager.py,sha256=x0GI1cFv3m3ZIS4oNJed197PaRo8_Vut_2J7m9ySV30,858
|
|
88
89
|
nonebot_plugin_osubot/osufile/Best Performance.png,sha256=qBNeZcym5vIqyE23K62ohjVBEPCjlNP9wQgXaT20XyY,704
|
|
89
90
|
nonebot_plugin_osubot/osufile/History Score.jpg,sha256=yv3-GaJ7sBAbAPMFlUeoyg1PzMhv31Ip5bC4H0qJfSA,836
|
|
90
91
|
nonebot_plugin_osubot/osufile/beatmapinfo.png,sha256=QQjMIGgAdvH6VKgHrrCZWasawsBb95erij4a_B0gjwA,30694
|
|
@@ -372,10 +373,10 @@ nonebot_plugin_osubot/osufile/mods/SD.png,sha256=JptCZkXv8kOpIksYimWdC7hRJXShL7N
|
|
|
372
373
|
nonebot_plugin_osubot/osufile/mods/SO.png,sha256=qKPoP-LXNU3nSVn8e7z2d6LddFOG-v4gbBEUOb6BtXU,1493
|
|
373
374
|
nonebot_plugin_osubot/osufile/mods/TD.png,sha256=ZAprUMXNcqs_tXPF0HU34qa_NUZo6U-NemMjVxBOk10,1309
|
|
374
375
|
nonebot_plugin_osubot/osufile/mods/V2.png,sha256=Y3ju7KMECnGiECRM1MnZUuuwQqbflkdz6I7XjCCTw2E,1354
|
|
375
|
-
nonebot_plugin_osubot/osufile/pfm_ctb.png,sha256=
|
|
376
|
-
nonebot_plugin_osubot/osufile/pfm_mania.png,sha256=
|
|
377
|
-
nonebot_plugin_osubot/osufile/pfm_std.png,sha256=
|
|
378
|
-
nonebot_plugin_osubot/osufile/pfm_taiko.png,sha256=
|
|
376
|
+
nonebot_plugin_osubot/osufile/pfm_ctb.png,sha256=9JJu8J1gR_nQhb1EWOuJUOjNitYK_gcH6MRGiYtvsGI,53451
|
|
377
|
+
nonebot_plugin_osubot/osufile/pfm_mania.png,sha256=PKlAezcKALo0UMnrYvTCL3pd-oJNEU76qLVPhfDLFdk,52208
|
|
378
|
+
nonebot_plugin_osubot/osufile/pfm_std.png,sha256=ts7e7IUeoalLuw0Pww0X3trXUpZwnWRsOqdQ1RzcdFM,57032
|
|
379
|
+
nonebot_plugin_osubot/osufile/pfm_taiko.png,sha256=7OAhXVfL_j7pZ4MZAXexgSMNmUyVNsvvq1Ij2XzFEgc,55756
|
|
379
380
|
nonebot_plugin_osubot/osufile/ranking/ranking-A.png,sha256=nA4kI67IbnC-gfu1pCnPupHC45Uoqa6LYmJKawzV_L0,4364
|
|
380
381
|
nonebot_plugin_osubot/osufile/ranking/ranking-B.png,sha256=KJCEGr7OkQ12rqng6_JL9r6qLTAclPO_PtHHmLFQooY,4214
|
|
381
382
|
nonebot_plugin_osubot/osufile/ranking/ranking-C.png,sha256=SsIWOTOymgMze521v4G_rdqL6QqpE64R1dhxpmhzBAc,3862
|
|
@@ -389,6 +390,7 @@ nonebot_plugin_osubot/osufile/work/bmap.png,sha256=Uc2znhA_SQ5Zc5MxdtIlnK2YlkhQS
|
|
|
389
390
|
nonebot_plugin_osubot/osufile/work/center.png,sha256=AJkhRnPCv1aYPg5nLV2ZCtDGo3lPzP3orT62DvS3c_4,83
|
|
390
391
|
nonebot_plugin_osubot/osufile/work/left.png,sha256=wJtK_kGmtRumI3F-vK0cl2Q2N1v7DB5bc9qofe4LyqI,128
|
|
391
392
|
nonebot_plugin_osubot/osufile/work/right.png,sha256=WKkaefFr5C_pdm9mFMyYMUS_BNzMPATmqlvebVU36OY,136
|
|
393
|
+
nonebot_plugin_osubot/osufile/work/stardiff.png,sha256=mBPOspsqNr1FkDolzTpnyIz-8NIKfrYn_dXi_eMS34s,156
|
|
392
394
|
nonebot_plugin_osubot/osufile/work/stars.png,sha256=zifMmxxjOGzSZAm1tr-3ky_yy18p1bbjgkl3zYRMcp4,305
|
|
393
395
|
nonebot_plugin_osubot/osufile/work/stars_expertplus.png,sha256=cmfpErs-flPxHEhVmS9H8vy8H7mrChvV_Q4A77oSVFY,517
|
|
394
396
|
nonebot_plugin_osubot/osufile/work/suppoter.png,sha256=4V4eNhB8_8KIXsQ1jzFyHUkicKPb5LPehoIcri4h8E4,16061
|
|
@@ -400,9 +402,9 @@ nonebot_plugin_osubot/schema/beatmap.py,sha256=UnobfZEHq1V2HG-A4j3BECubO-dB1JzTM
|
|
|
400
402
|
nonebot_plugin_osubot/schema/match.py,sha256=lR3pGNVR9K_5GZAdOLG6Ki-W3fwJvgMlNhYOzKNE3lg,494
|
|
401
403
|
nonebot_plugin_osubot/schema/ppysb/__init__.py,sha256=JK2Z4n44gUJPVKdETMJYJ5uIw-4a8T50y6j5n-YrlYM,1375
|
|
402
404
|
nonebot_plugin_osubot/schema/sayo_beatmap.py,sha256=lS1PQZ-HvHl0VhkzlI0-pNLeJrLYWVqmKAo6xZr5I2U,959
|
|
403
|
-
nonebot_plugin_osubot/schema/score.py,sha256=
|
|
405
|
+
nonebot_plugin_osubot/schema/score.py,sha256=Qtvs5Hfvw5m2b00e8ZjrcrLGDyL4lqDspRwrkORY-xU,3172
|
|
404
406
|
nonebot_plugin_osubot/schema/user.py,sha256=sxNmqymG_kIVuGuzfchSv9UML6NPG70cqo2_h5xDIpM,2250
|
|
405
407
|
nonebot_plugin_osubot/utils/__init__.py,sha256=pyv8XxBcCOeQVDj1E4dgvktzcefgQXfKBlarsYGx1sg,815
|
|
406
|
-
nonebot_plugin_osubot-6.
|
|
407
|
-
nonebot_plugin_osubot-6.
|
|
408
|
-
nonebot_plugin_osubot-6.
|
|
408
|
+
nonebot_plugin_osubot-6.22.0.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
409
|
+
nonebot_plugin_osubot-6.22.0.dist-info/METADATA,sha256=VsdL1bH40h2QTlFxd3MxYe48g5QgvzFSClziBS9u5EA,4476
|
|
410
|
+
nonebot_plugin_osubot-6.22.0.dist-info/RECORD,,
|
|
File without changes
|