nonebot-plugin-osubot 6.24.2__py3-none-any.whl → 6.25.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 +1 -1
- nonebot_plugin_osubot/file.py +176 -6
- nonebot_plugin_osubot/matcher/__init__.py +2 -0
- nonebot_plugin_osubot/matcher/map_convert.py +11 -8
- nonebot_plugin_osubot/matcher/osudl.py +5 -4
- nonebot_plugin_osubot/matcher/recommend.py +1 -1
- nonebot_plugin_osubot/network/first_response.py +1 -1
- {nonebot_plugin_osubot-6.24.2.dist-info → nonebot_plugin_osubot-6.25.0.dist-info}/METADATA +2 -1
- {nonebot_plugin_osubot-6.24.2.dist-info → nonebot_plugin_osubot-6.25.0.dist-info}/RECORD +10 -10
- {nonebot_plugin_osubot-6.24.2.dist-info → nonebot_plugin_osubot-6.25.0.dist-info}/WHEEL +0 -0
nonebot_plugin_osubot/api.py
CHANGED
nonebot_plugin_osubot/file.py
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hashlib
|
|
1
3
|
import re
|
|
4
|
+
import urllib
|
|
2
5
|
import random
|
|
3
6
|
import asyncio
|
|
7
|
+
import uuid
|
|
4
8
|
from pathlib import Path
|
|
5
9
|
from typing import Union, Optional
|
|
6
10
|
from io import BytesIO, TextIOWrapper
|
|
7
11
|
|
|
12
|
+
from nonebot.adapters.onebot.v11 import Bot
|
|
8
13
|
from nonebot.log import logger
|
|
9
14
|
|
|
10
15
|
from .schema import Badge
|
|
@@ -18,7 +23,6 @@ user_cache_path = Path() / "data" / "osu" / "user"
|
|
|
18
23
|
badge_cache_path = Path() / "data" / "osu" / "badge"
|
|
19
24
|
team_cache_path = Path() / "data" / "osu" / "team"
|
|
20
25
|
api_ls = [
|
|
21
|
-
"https://api.chimu.moe/v1/download/",
|
|
22
26
|
"https://osu.direct/api/d/",
|
|
23
27
|
"https://txy1.sayobot.cn/beatmaps/download/novideo/",
|
|
24
28
|
"https://catboy.best/d/",
|
|
@@ -35,16 +39,55 @@ if not team_cache_path.exists():
|
|
|
35
39
|
team_cache_path.mkdir(parents=True, exist_ok=True)
|
|
36
40
|
|
|
37
41
|
|
|
42
|
+
def extract_filename_from_headers(headers: dict[str, str]) -> Optional[str]:
|
|
43
|
+
"""
|
|
44
|
+
从 Content-Disposition 响应头中提取文件名,并处理 URL 编码。
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
headers: 响应头字典。
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
提取到的文件名字符串,如果失败则返回 None。
|
|
51
|
+
"""
|
|
52
|
+
disposition = headers.get("content-disposition", "")
|
|
53
|
+
if not disposition:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
match_utf8 = re.search(r"filename\*=(?:utf-8''|)(.+?)(?:;|$)", disposition, re.IGNORECASE)
|
|
57
|
+
|
|
58
|
+
if match_utf8:
|
|
59
|
+
# 提取匹配到的文件名部分
|
|
60
|
+
encoded_filename = match_utf8.group(1).strip('"').strip()
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
return urllib.parse.unquote(encoded_filename)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
# 如果解码失败,记录错误并尝试使用原始编码
|
|
66
|
+
print(f"警告: 解码 filename* 失败: {e}. 使用原始编码.")
|
|
67
|
+
return encoded_filename
|
|
68
|
+
|
|
69
|
+
match_normal = re.search(r"filename=\"?(.+?)\"?(\s|;|$)", disposition, re.IGNORECASE)
|
|
70
|
+
if match_normal:
|
|
71
|
+
# 普通 filename 字段也可能包含 URL 编码,进行解码
|
|
72
|
+
filename = match_normal.group(1).strip('"').strip()
|
|
73
|
+
try:
|
|
74
|
+
return urllib.parse.unquote(filename)
|
|
75
|
+
except Exception:
|
|
76
|
+
return filename
|
|
77
|
+
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
38
81
|
async def download_map(setid: int) -> Optional[Path]:
|
|
39
82
|
urls = [i + str(setid) for i in api_ls]
|
|
40
83
|
logger.info(f"开始下载地图: <{setid}>")
|
|
41
84
|
req = await get_first_response(urls)
|
|
42
|
-
filename =
|
|
85
|
+
filename = extract_filename_from_headers(req.headers)
|
|
43
86
|
filepath = map_path.parent / filename
|
|
44
|
-
with open(filepath, "wb") as f:
|
|
45
|
-
f.write(req.
|
|
87
|
+
with open(filepath.absolute(), "wb") as f:
|
|
88
|
+
f.write(req.content)
|
|
46
89
|
logger.info(f"地图: <{setid}> 下载完毕")
|
|
47
|
-
return filepath
|
|
90
|
+
return filepath.absolute()
|
|
48
91
|
|
|
49
92
|
|
|
50
93
|
@auto_retry
|
|
@@ -61,7 +104,7 @@ async def download_osu(set_id, map_id):
|
|
|
61
104
|
filepath = map_path / str(set_id) / filename
|
|
62
105
|
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
63
106
|
with open(filepath, "wb") as f:
|
|
64
|
-
f.write(req)
|
|
107
|
+
f.write(req.content)
|
|
65
108
|
return filepath
|
|
66
109
|
else:
|
|
67
110
|
raise Exception("下载出错,请稍后再试")
|
|
@@ -125,3 +168,130 @@ async def save_info_pic(user: str, byt: bytes):
|
|
|
125
168
|
path.mkdir()
|
|
126
169
|
with open(path / "info.png", "wb") as f:
|
|
127
170
|
f.write(BytesIO(byt).getvalue())
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def calculate_file_chunks(file_path: str, chunk_size: int = 1024 * 64) -> tuple[list[bytes], str, int]:
|
|
174
|
+
"""
|
|
175
|
+
计算文件分片和 SHA256
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
file_path: 文件路径
|
|
179
|
+
chunk_size: 分片大小(默认64KB)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
(chunks, sha256_hash, total_size)
|
|
183
|
+
"""
|
|
184
|
+
chunks = []
|
|
185
|
+
hasher = hashlib.sha256()
|
|
186
|
+
total_size = 0
|
|
187
|
+
|
|
188
|
+
with open(file_path, "rb") as f:
|
|
189
|
+
while True:
|
|
190
|
+
chunk = f.read(chunk_size)
|
|
191
|
+
if not chunk:
|
|
192
|
+
break
|
|
193
|
+
chunks.append(chunk)
|
|
194
|
+
hasher.update(chunk)
|
|
195
|
+
total_size += len(chunk)
|
|
196
|
+
|
|
197
|
+
sha256_hash = hasher.hexdigest()
|
|
198
|
+
|
|
199
|
+
return chunks, sha256_hash, total_size
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
MAX_CONCURRENT_UPLOADS = 20
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
async def _upload_chunk(
|
|
206
|
+
bot: "Bot",
|
|
207
|
+
stream_id: str,
|
|
208
|
+
chunk_data: bytes,
|
|
209
|
+
chunk_index: int,
|
|
210
|
+
total_chunks: int,
|
|
211
|
+
total_size: int,
|
|
212
|
+
sha256_hash: str,
|
|
213
|
+
filename: str,
|
|
214
|
+
semaphore: asyncio.Semaphore,
|
|
215
|
+
) -> None:
|
|
216
|
+
"""内部函数,用于异步上传单个文件分片"""
|
|
217
|
+
async with semaphore:
|
|
218
|
+
# 将分片数据编码为 base64
|
|
219
|
+
chunk_base64 = base64.b64encode(chunk_data).decode("utf-8")
|
|
220
|
+
|
|
221
|
+
# 构建参数
|
|
222
|
+
params = {
|
|
223
|
+
"stream_id": stream_id,
|
|
224
|
+
"chunk_data": chunk_base64,
|
|
225
|
+
"chunk_index": chunk_index,
|
|
226
|
+
"total_chunks": total_chunks,
|
|
227
|
+
"file_size": total_size,
|
|
228
|
+
"expected_sha256": sha256_hash,
|
|
229
|
+
"filename": filename,
|
|
230
|
+
"file_retention": 30 * 1000,
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# 发送分片
|
|
234
|
+
response = await bot.call_api("upload_file_stream", **params)
|
|
235
|
+
|
|
236
|
+
logger.info(
|
|
237
|
+
f"分片 {chunk_index + 1}/{total_chunks} 上传成功 "
|
|
238
|
+
f"(接收: {response.get('received_chunks', 0)}/{response.get('total_chunks', 0)})"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
async def upload_file_stream_batch(bot: Bot, file_path: Path, chunk_size: int = 1024 * 64) -> str:
|
|
243
|
+
"""
|
|
244
|
+
一次性批量上传文件流
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
bot: Bot 实例
|
|
248
|
+
file_path: 要上传的文件路径
|
|
249
|
+
chunk_size: 分片大小
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
上传完成后的文件路径
|
|
253
|
+
"""
|
|
254
|
+
if not file_path.exists():
|
|
255
|
+
raise FileNotFoundError(f"文件不存在: {file_path}")
|
|
256
|
+
|
|
257
|
+
# 分析文件
|
|
258
|
+
chunks, sha256_hash, total_size = calculate_file_chunks(str(file_path), chunk_size)
|
|
259
|
+
stream_id = str(uuid.uuid4())
|
|
260
|
+
|
|
261
|
+
logger.info(f"\n开始上传文件: {file_path.name}")
|
|
262
|
+
logger.info(f"流ID: {stream_id}")
|
|
263
|
+
|
|
264
|
+
# 一次性发送所有分片
|
|
265
|
+
total_chunks = len(chunks)
|
|
266
|
+
# 创建信号量,限制最大并发数
|
|
267
|
+
semaphore = asyncio.Semaphore(MAX_CONCURRENT_UPLOADS)
|
|
268
|
+
|
|
269
|
+
# 创建所有分片上传任务
|
|
270
|
+
upload_tasks = []
|
|
271
|
+
for chunk_index, chunk_data in enumerate(chunks):
|
|
272
|
+
task = _upload_chunk(
|
|
273
|
+
bot, stream_id, chunk_data, chunk_index, total_chunks, total_size, sha256_hash, file_path.name, semaphore
|
|
274
|
+
)
|
|
275
|
+
upload_tasks.append(task)
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
await asyncio.gather(*upload_tasks)
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.error(f"\n文件分片上传过程中发生错误: {e}")
|
|
281
|
+
# 这里可以选择执行清理逻辑,如通知服务器取消上传
|
|
282
|
+
raise e
|
|
283
|
+
|
|
284
|
+
# 发送完成信号
|
|
285
|
+
logger.info("\n所有分片发送完成,请求文件合并...")
|
|
286
|
+
complete_params = {"stream_id": stream_id, "is_complete": True}
|
|
287
|
+
|
|
288
|
+
response = await bot.call_api("upload_file_stream", **complete_params)
|
|
289
|
+
|
|
290
|
+
if response.get("status") == "file_complete":
|
|
291
|
+
logger.info("✅ 文件上传成功!")
|
|
292
|
+
logger.info(f" - 文件路径: {response.get('file_path')}")
|
|
293
|
+
logger.info(f" - 文件大小: {response.get('file_size')} 字节")
|
|
294
|
+
logger.info(f" - SHA256: {response.get('sha256')}")
|
|
295
|
+
return response.get("file_path")
|
|
296
|
+
else:
|
|
297
|
+
raise Exception(f"文件状态异常: {response}")
|
|
@@ -5,6 +5,7 @@ from .getbg import getbg
|
|
|
5
5
|
from .match import match
|
|
6
6
|
from .medal import medal
|
|
7
7
|
from .score import score
|
|
8
|
+
from .osudl import osudl
|
|
8
9
|
from .pr import pr, recent
|
|
9
10
|
from .rating import rating
|
|
10
11
|
from .history import history
|
|
@@ -57,4 +58,5 @@ __all__ = [
|
|
|
57
58
|
"match",
|
|
58
59
|
"rating",
|
|
59
60
|
"group_pp_rank",
|
|
61
|
+
"osudl",
|
|
60
62
|
]
|
|
@@ -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
|
|
@@ -10,6 +11,7 @@ from nonebot.params import CommandArg, ShellCommandArgv
|
|
|
10
11
|
from ..api import get_beatmapsets_info, osu_api
|
|
11
12
|
from ..mania import Options, convert_mania_map
|
|
12
13
|
from ..schema import Beatmap
|
|
14
|
+
from ..file import upload_file_stream_batch
|
|
13
15
|
|
|
14
16
|
parser = ArgumentParser("convert", description="变换mania谱面")
|
|
15
17
|
parser.add_argument("--set", type=int, help="要转换的谱面的setid")
|
|
@@ -38,7 +40,7 @@ async def _(argv: list[str] = ShellCommandArgv()):
|
|
|
38
40
|
return
|
|
39
41
|
options = Options(**vars(args))
|
|
40
42
|
if options.map:
|
|
41
|
-
map_data = await osu_api("map", options.map)
|
|
43
|
+
map_data = await osu_api("map", map_id=options.map)
|
|
42
44
|
mapinfo = Beatmap(**map_data)
|
|
43
45
|
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
44
46
|
options.set = mapinfo.beatmapset_id
|
|
@@ -67,7 +69,7 @@ change = on_command("倍速", priority=11, block=True)
|
|
|
67
69
|
|
|
68
70
|
|
|
69
71
|
@change.handle()
|
|
70
|
-
async def _(msg: Message = CommandArg()):
|
|
72
|
+
async def _(bot: Bot, event: GroupMessageEvent, msg: Message = CommandArg()):
|
|
71
73
|
args = msg.extract_plain_text().strip().split()
|
|
72
74
|
argv = ["--map"]
|
|
73
75
|
if not args:
|
|
@@ -88,7 +90,7 @@ async def _(msg: Message = CommandArg()):
|
|
|
88
90
|
args = parser.parse_args(argv)
|
|
89
91
|
options = Options(**vars(args))
|
|
90
92
|
if options.map:
|
|
91
|
-
map_data = await osu_api("map", options.map)
|
|
93
|
+
map_data = await osu_api("map", map_id=options.map)
|
|
92
94
|
mapinfo = Beatmap(**map_data)
|
|
93
95
|
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
94
96
|
options.set = mapinfo.beatmapset_id
|
|
@@ -97,9 +99,10 @@ async def _(msg: Message = CommandArg()):
|
|
|
97
99
|
if not osz_path:
|
|
98
100
|
await UniMessage.text("未找到该地图,请检查是否搞混了mapID与setID").finish(reply_to=True)
|
|
99
101
|
file_path = osz_path.absolute()
|
|
102
|
+
server_osz_path = await upload_file_stream_batch(bot, file_path)
|
|
103
|
+
|
|
100
104
|
try:
|
|
101
|
-
|
|
102
|
-
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)
|
|
103
106
|
except ActionFailed:
|
|
104
107
|
await UniMessage.text("上传文件失败,可能是群空间满或没有权限导致的").send(reply_to=True)
|
|
105
108
|
finally:
|
|
@@ -113,7 +116,7 @@ generate_full_ln = on_command("反键", priority=11, block=True)
|
|
|
113
116
|
|
|
114
117
|
|
|
115
118
|
@generate_full_ln.handle()
|
|
116
|
-
async def _(msg: Message = CommandArg()):
|
|
119
|
+
async def _(bot: Bot, event: GroupMessageEvent, msg: Message = CommandArg()):
|
|
117
120
|
args = msg.extract_plain_text().strip().split()
|
|
118
121
|
if not args:
|
|
119
122
|
await UniMessage.text("请输入需要转ln的地图setID").finish(reply_to=True)
|
|
@@ -133,9 +136,9 @@ async def _(msg: Message = CommandArg()):
|
|
|
133
136
|
if not osz_path:
|
|
134
137
|
await UniMessage.text("未找到该地图,请检查是否搞混了mapID与setID").finish(reply_to=True)
|
|
135
138
|
file_path = osz_path.absolute()
|
|
139
|
+
server_osz_path = await upload_file_stream_batch(bot, file_path)
|
|
136
140
|
try:
|
|
137
|
-
|
|
138
|
-
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)
|
|
139
142
|
except ActionFailed:
|
|
140
143
|
await UniMessage.text("上传文件失败,可能是群空间满或没有权限导致的").send(reply_to=True)
|
|
141
144
|
finally:
|
|
@@ -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,7 +43,7 @@ async def handle_recommend(state: T_State, matcher: type[Matcher]):
|
|
|
43
43
|
await matcher.finish("今天已经没有可以推荐的图啦,明天再来吧")
|
|
44
44
|
return None
|
|
45
45
|
bid = int(re.findall("https://osu.ppy.sh/beatmaps/(.*)", recommend_map.mapLink)[0])
|
|
46
|
-
map_data = await osu_api("map", bid)
|
|
46
|
+
map_data = await osu_api("map", map_id=bid)
|
|
47
47
|
map_info = Beatmap(**map_data)
|
|
48
48
|
sid = map_info.beatmapset_id
|
|
49
49
|
s = (
|
|
@@ -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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nonebot-plugin-osubot
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.25.0
|
|
4
4
|
Summary: OSUbot in NoneBot2
|
|
5
5
|
License: AGPL-3.0
|
|
6
6
|
Author-email: yaowan233 <572473053@qq.com>
|
|
@@ -8,6 +8,7 @@ Requires-Python: >=3.9.8,<3.13
|
|
|
8
8
|
Requires-Dist: expiringdict>=1.2.2
|
|
9
9
|
Requires-Dist: httpx>=0.23.3
|
|
10
10
|
Requires-Dist: matplotlib>=3.7.1
|
|
11
|
+
Requires-Dist: nonebot-adapter-onebot>=2.4.6
|
|
11
12
|
Requires-Dist: nonebot-plugin-alconna>=0.46.4
|
|
12
13
|
Requires-Dist: nonebot-plugin-apscheduler>=0.4.0
|
|
13
14
|
Requires-Dist: nonebot-plugin-htmlrender>=0.3.1
|
|
@@ -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=ZPbtDWz_zBUaL-3RnpXJuDhZ-RAVPCzvHp4MHShpGiE,16529
|
|
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/data/osu/1849145.osz,sha256=enbHOvDu6ZkvQBM7gtvgZBY-r0a7z87pG62Xm9hXUSI,6933013
|
|
@@ -93,12 +93,12 @@ nonebot_plugin_osubot/draw/templates/mod_chart.html,sha256=Iz71KM5v9z_Rt2vqJ5WIZ
|
|
|
93
93
|
nonebot_plugin_osubot/draw/templates/pp_rank_line_chart.html,sha256=Gyf-GR8ZBlWQTks0TlB3M8EWUBMVwiUaesFAmDISxLo,1417
|
|
94
94
|
nonebot_plugin_osubot/draw/utils.py,sha256=6QDbByPQZCxI0k_i5MsExyWZ-sHgJUw6nEWLv85IgLY,15826
|
|
95
95
|
nonebot_plugin_osubot/exceptions.py,sha256=N_FsEk-9Eu2QnuznhdfWn6OoyA1HH73Q7bUaY89gVi0,40
|
|
96
|
-
nonebot_plugin_osubot/file.py,sha256=
|
|
96
|
+
nonebot_plugin_osubot/file.py,sha256=p8E9oeopvMLT-T_b0PARZifOX_m1HXsxJGGtbZFMVfY,9387
|
|
97
97
|
nonebot_plugin_osubot/info/__init__.py,sha256=I7YlMQiuHExEeJWqyzZb2I-Vl2uql3Py2LdhSH2Z9N0,136
|
|
98
98
|
nonebot_plugin_osubot/info/bg.py,sha256=Icua4bS38k0c-WbLUjhfS4IXOF83bgyu_oa2HwX4ZEQ,1541
|
|
99
99
|
nonebot_plugin_osubot/info/bind.py,sha256=b2ua625hbYym7rpb-kLBB-VDP5YWFdmT5RweM58ggWw,4934
|
|
100
100
|
nonebot_plugin_osubot/mania/__init__.py,sha256=t5-24nd2FiZTKvMFvNg8ZV9Lp_OFSHjhj_gWUV3s1es,5560
|
|
101
|
-
nonebot_plugin_osubot/matcher/__init__.py,sha256=
|
|
101
|
+
nonebot_plugin_osubot/matcher/__init__.py,sha256=0f2_aeiBos3evT9eZRRh73Z0gpdwRcH8XpzUP6jbq-0,1369
|
|
102
102
|
nonebot_plugin_osubot/matcher/bind.py,sha256=QQJc2S7XFo5tu4CPloIET6fKaeiQixgb8M7QvULV6E0,2834
|
|
103
103
|
nonebot_plugin_osubot/matcher/bp.py,sha256=GidJfuZ9lJ7LwMq126DDOwMksNUOz4Bkab83OlKg8t8,3983
|
|
104
104
|
nonebot_plugin_osubot/matcher/bp_analyze.py,sha256=xi40HVOcTvmHWR4WNLm706126CulfpV5UP0500FNiD8,4159
|
|
@@ -107,17 +107,17 @@ nonebot_plugin_osubot/matcher/guess.py,sha256=Bv4Rt11eB65hdsPu6KhCjmEP1AacFUwA0u
|
|
|
107
107
|
nonebot_plugin_osubot/matcher/history.py,sha256=ZYkVJHdXuVJmhovRhwxFdqNp0o2uJJOACAZhhutyS3w,1577
|
|
108
108
|
nonebot_plugin_osubot/matcher/info.py,sha256=8CJHTOMTx_nzJ4ZwXo6ZfBwCuO3DtLprRX7jnMtPilk,858
|
|
109
109
|
nonebot_plugin_osubot/matcher/map.py,sha256=sFpOoFv63y-NOkCJhE6aW0DRYDl_8SoQOPsdq50QxT0,1404
|
|
110
|
-
nonebot_plugin_osubot/matcher/map_convert.py,sha256=
|
|
110
|
+
nonebot_plugin_osubot/matcher/map_convert.py,sha256=oklwbbcrEuous-mtHgGN3bN3PkDqKb95XXjIMSEp5Yk,6343
|
|
111
111
|
nonebot_plugin_osubot/matcher/match.py,sha256=uyrm8I_WgHK2ya1q46AUxNk_cQiKKh7GKlUzrrG1o7w,472
|
|
112
112
|
nonebot_plugin_osubot/matcher/medal.py,sha256=LZf8hlXGHy8mdK2l97SsYCChfYYovEDBGNbUPO3AOsw,2967
|
|
113
113
|
nonebot_plugin_osubot/matcher/mu.py,sha256=l3Ebz47o46EvN2nvo9-zzQI4CTaLMcd5XW0qljqSGIM,445
|
|
114
114
|
nonebot_plugin_osubot/matcher/osu_help.py,sha256=64rOkYEOETvU8AF__0xLZjVRs3cTac0D1XEultPK_kM,728
|
|
115
|
-
nonebot_plugin_osubot/matcher/osudl.py,sha256=
|
|
115
|
+
nonebot_plugin_osubot/matcher/osudl.py,sha256=aItoFVYgozZHINpBuWv38syixtTOtaTtyBpWKZo94uI,1091
|
|
116
116
|
nonebot_plugin_osubot/matcher/pr.py,sha256=xGjQvEJHmIZkq9luu8TtbjBB8FykGI4Wzi_-eXghOjQ,4951
|
|
117
117
|
nonebot_plugin_osubot/matcher/preview.py,sha256=22zNjRdpwxbmIsyZQlUE-qXQBCQCfP_2WobGP7nZZh4,2314
|
|
118
118
|
nonebot_plugin_osubot/matcher/rank.py,sha256=sFEim3cR_vswzLmbagjqy-ypolcprAxQpawiSEcFqEI,3619
|
|
119
119
|
nonebot_plugin_osubot/matcher/rating.py,sha256=JY1Q1ELU3Y1FhQ7kVWVkgVsYEVxkAcxjsoMcwC_u234,450
|
|
120
|
-
nonebot_plugin_osubot/matcher/recommend.py,sha256=
|
|
120
|
+
nonebot_plugin_osubot/matcher/recommend.py,sha256=4R8rzxi-tC7aCb__64KzAKZo_-ginSb_U0HWK6xaRmI,2528
|
|
121
121
|
nonebot_plugin_osubot/matcher/score.py,sha256=Nk6dpDlszKJKdboTSQRBf-wMGioHIPqKSVWrnT0Xbns,1212
|
|
122
122
|
nonebot_plugin_osubot/matcher/update.py,sha256=MHpxoJmU0hKW82XuM9YpyCxUUjjiNKwejnRgYwueR4Q,3168
|
|
123
123
|
nonebot_plugin_osubot/matcher/update_mode.py,sha256=0Wy6Y1-rN7XcqBZyo37mYFdixq-4HxCwZftUaiYhZqE,1602
|
|
@@ -126,7 +126,7 @@ nonebot_plugin_osubot/matcher/utils.py,sha256=gWmNa31wUxcY_PNSNLy348x5_7sTY9ttMK
|
|
|
126
126
|
nonebot_plugin_osubot/mods.py,sha256=vxIWYX0HwTxetPAHWZK5ojEMfqV9HFlWT0YC4Yncgb8,1402
|
|
127
127
|
nonebot_plugin_osubot/network/__init__.py,sha256=WOijcd81yhnpGKYeiDIOxbBDVI12GHPRGoOFfxrUuQk,61
|
|
128
128
|
nonebot_plugin_osubot/network/auto_retry.py,sha256=vDfYGbEVPF6WZLYXmRVkNvaxf6_6RyIqEAcA7TRwV_k,565
|
|
129
|
-
nonebot_plugin_osubot/network/first_response.py,sha256=
|
|
129
|
+
nonebot_plugin_osubot/network/first_response.py,sha256=jIYIF476aIUgpIcN08Wo8tXiwu0paNebCcaTuRPmlS4,924
|
|
130
130
|
nonebot_plugin_osubot/network/manager.py,sha256=x0GI1cFv3m3ZIS4oNJed197PaRo8_Vut_2J7m9ySV30,858
|
|
131
131
|
nonebot_plugin_osubot/osufile/Best Performance.png,sha256=qBNeZcym5vIqyE23K62ohjVBEPCjlNP9wQgXaT20XyY,704
|
|
132
132
|
nonebot_plugin_osubot/osufile/History Score.jpg,sha256=yv3-GaJ7sBAbAPMFlUeoyg1PzMhv31Ip5bC4H0qJfSA,836
|
|
@@ -447,6 +447,6 @@ nonebot_plugin_osubot/schema/ppysb/__init__.py,sha256=JK2Z4n44gUJPVKdETMJYJ5uIw-
|
|
|
447
447
|
nonebot_plugin_osubot/schema/score.py,sha256=o32jKDESzFwOFPZnzjKqxNIj0MPUL9mFvBqgaZARHac,3269
|
|
448
448
|
nonebot_plugin_osubot/schema/user.py,sha256=sxNmqymG_kIVuGuzfchSv9UML6NPG70cqo2_h5xDIpM,2250
|
|
449
449
|
nonebot_plugin_osubot/utils/__init__.py,sha256=pyv8XxBcCOeQVDj1E4dgvktzcefgQXfKBlarsYGx1sg,815
|
|
450
|
-
nonebot_plugin_osubot-6.
|
|
451
|
-
nonebot_plugin_osubot-6.
|
|
452
|
-
nonebot_plugin_osubot-6.
|
|
450
|
+
nonebot_plugin_osubot-6.25.0.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
451
|
+
nonebot_plugin_osubot-6.25.0.dist-info/METADATA,sha256=Sy7rPJeo1uzQ5ek4gPoImi2JtSt7Nvoe8y-eMIoQ6eQ,4521
|
|
452
|
+
nonebot_plugin_osubot-6.25.0.dist-info/RECORD,,
|
|
File without changes
|