nonebot-plugin-maimaidx 3.0.5__tar.gz → 3.0.6__tar.gz

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.
Files changed (83) hide show
  1. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/PKG-INFO +1 -1
  2. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/depend.py +42 -30
  3. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_alias.py +16 -10
  4. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_base.py +13 -5
  5. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_score.py +7 -4
  6. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_search.py +1 -1
  7. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_table.py +15 -9
  8. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/handler.py +21 -14
  9. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/service/__init__.py +34 -17
  10. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx.egg-info/PKG-INFO +1 -1
  11. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/pyproject.toml +1 -1
  12. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/LICENSE +0 -0
  13. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/README.md +0 -0
  14. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/__init__.py +0 -0
  15. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/__init__.py +0 -0
  16. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/commands/mai_guess.py +0 -0
  17. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/config.py +0 -0
  18. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/constants.py +0 -0
  19. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/alias_ws_push.py +0 -0
  20. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/divingfish/client.py +0 -0
  21. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/divingfish/exceptions.py +0 -0
  22. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/divingfish/models/__init__.py +0 -0
  23. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/divingfish/models/music.py +0 -0
  24. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/divingfish/models/score.py +0 -0
  25. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/exceptions.py +0 -0
  26. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/http.py +0 -0
  27. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/client.py +0 -0
  28. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/exceptions.py +0 -0
  29. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/__init__.py +0 -0
  30. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/base.py +0 -0
  31. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/collection.py +0 -0
  32. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/enum.py +0 -0
  33. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/music.py +0 -0
  34. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/oauth.py +0 -0
  35. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/player.py +0 -0
  36. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/lxns/models/score.py +0 -0
  37. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/client.py +0 -0
  38. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/exceptions.py +0 -0
  39. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/__init__.py +0 -0
  40. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/alias.py +0 -0
  41. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/enum.py +0 -0
  42. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/message.py +0 -0
  43. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/status.py +0 -0
  44. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/database/qq.py +0 -0
  45. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/handler_error.py +0 -0
  46. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/__init__.py +0 -0
  47. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/assets.py +0 -0
  48. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/base.py +0 -0
  49. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/best50.py +0 -0
  50. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/chart.py +0 -0
  51. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/info.py +0 -0
  52. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/plate_table.py +0 -0
  53. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/rating_table.py +0 -0
  54. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/score.py +0 -0
  55. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/song.py +0 -0
  56. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/tools.py +0 -0
  57. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/image/update_table.py +0 -0
  58. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/__init__.py +0 -0
  59. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/alias.py +0 -0
  60. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/alias_list.py +0 -0
  61. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/__init__.py +0 -0
  62. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/alias.py +0 -0
  63. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/best50.py +0 -0
  64. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/enum.py +0 -0
  65. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/guess.py +0 -0
  66. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/player.py +0 -0
  67. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/score.py +0 -0
  68. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/models/song.py +0 -0
  69. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/music_list.py +0 -0
  70. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/play_result.py +0 -0
  71. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/merge/player.py +0 -0
  72. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/service/diving_fish.py +0 -0
  73. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/service/lxns.py +0 -0
  74. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/service/yuzuchan.py +0 -0
  75. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/tool.py +0 -0
  76. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/core/utils/calc.py +0 -0
  77. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/maimaidxhelp.png +0 -0
  78. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx/resources.py +0 -0
  79. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx.egg-info/SOURCES.txt +0 -0
  80. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx.egg-info/dependency_links.txt +0 -0
  81. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx.egg-info/requires.txt +0 -0
  82. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/nonebot_plugin_maimaidx.egg-info/top_level.txt +0 -0
  83. {nonebot_plugin_maimaidx-3.0.5 → nonebot_plugin_maimaidx-3.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-maimaidx
3
- Version: 3.0.5
3
+ Version: 3.0.6
4
4
  Summary: maimaidx plugin for nonebot2
5
5
  Author-email: Yuri-YuzuChaN <806235364@qq.com>
6
6
  License-Expression: MIT
@@ -75,6 +75,14 @@ GetUserAndAuthOrNone = GetUserModel(auto_create=True, check_auth=True, check_ski
75
75
  """获取用户数据,若不存在则创建,并检查是否授权,未授权则返回`None`"""
76
76
 
77
77
 
78
+ def is_float(value: str) -> bool:
79
+ try:
80
+ float(value)
81
+ return True
82
+ except ValueError:
83
+ return False
84
+
85
+
78
86
  async def process_regex(
79
87
  matcher: Matcher, match: Match[str] = RegexMatched()
80
88
  ) -> tuple[list[Song], int]:
@@ -91,24 +99,26 @@ async def process_regex(
91
99
  page = 1
92
100
  match cmd:
93
101
  case None:
94
- match a_list:
95
- case [name]:
96
- title = name
97
- case [name, p_raw]:
98
- title, page = name, int(p_raw)
99
- case _:
100
- await matcher.finish(
101
- "没有找到这样的乐曲。\n※ 如果是别名请使用「XXX是什么歌」指令进行查询哦。",
102
- reply_message=True,
103
- )
102
+ if not a_list:
103
+ await matcher.finish(
104
+ "没有找到这样的乐曲。\n※ 如果是别名请使用「XXX是什么歌」指令进行查询哦。",
105
+ reply_message=True,
106
+ )
107
+ # 末尾为纯数字时视为页数,其余整体作为标题(支持含空格的标题)
108
+ if len(a_list) >= 2 and a_list[-1].isdigit():
109
+ title, page = " ".join(a_list[:-1]), int(a_list[-1])
110
+ else:
111
+ title = " ".join(a_list)
104
112
  result = mai.total_list.filter(title=title)
105
113
  case "定数":
106
114
  match a_list:
107
- case [ds]:
115
+ case [ds] if is_float(ds):
108
116
  ds1 = ds2 = float(ds)
109
- case [ds1_raw, ds2_raw]:
117
+ case [ds1_raw, ds2_raw] if is_float(ds1_raw) and is_float(ds2_raw):
110
118
  ds1, ds2 = float(ds1_raw), float(ds2_raw)
111
- case [ds1_raw, ds2_raw, p_raw]:
119
+ case [ds1_raw, ds2_raw, p_raw] if (
120
+ is_float(ds1_raw) and is_float(ds2_raw) and p_raw.isdigit()
121
+ ):
112
122
  ds1, ds2, page = float(ds1_raw), float(ds2_raw), int(p_raw)
113
123
  case _:
114
124
  await matcher.finish(
@@ -122,15 +132,17 @@ async def process_regex(
122
132
  result = mai.total_list.filter(level_value=(ds1, ds2))
123
133
  case "bpm":
124
134
  match a_list:
125
- case [bpm_raw]:
135
+ case [bpm_raw] if is_float(bpm_raw):
126
136
  result = mai.total_list.filter(bpm=float(bpm_raw))
127
- case [b1, b2]:
137
+ case [b1, b2] if is_float(b1) and is_float(b2):
128
138
  if float(b1) > float(b2):
129
- page = int(b2)
139
+ page = int(float(b2))
130
140
  result = mai.total_list.filter(bpm=float(b1))
131
141
  else:
132
142
  result = mai.total_list.filter(bpm=(float(b1), float(b2)))
133
- case [b1, b2, p_raw]:
143
+ case [b1, b2, p_raw] if (
144
+ is_float(b1) and is_float(b2) and p_raw.isdigit()
145
+ ):
134
146
  result = mai.total_list.filter(bpm=(float(b1), float(b2)))
135
147
  page = int(p_raw)
136
148
  case _:
@@ -143,19 +155,19 @@ async def process_regex(
143
155
  reply_message=True,
144
156
  )
145
157
  case "曲师" | "谱师":
146
- match a_list:
147
- case [name]:
148
- pass
149
- case [name, p_raw] if p_raw.isdigit():
150
- page = int(p_raw)
151
- case _:
152
- await matcher.finish(
153
- (
154
- f"{cmd}查歌参数错误,请输入正确格式,页数为可选:\n"
155
- f"{cmd}查歌「{cmd}」「页数」"
156
- ),
157
- reply_message=True,
158
- )
158
+ if not a_list:
159
+ await matcher.finish(
160
+ (
161
+ f"{cmd}查歌参数错误,请输入正确格式,页数为可选:\n"
162
+ f"{cmd}查歌「{cmd}」「页数」"
163
+ ),
164
+ reply_message=True,
165
+ )
166
+ # 末尾为纯数字时视为页数,其余整体作为曲师/谱师名(支持含空格的名字)
167
+ if len(a_list) >= 2 and a_list[-1].isdigit():
168
+ name, page = " ".join(a_list[:-1]), int(a_list[-1])
169
+ else:
170
+ name = " ".join(a_list)
159
171
  if cmd == "曲师":
160
172
  result = mai.total_list.filter(artist=name)
161
173
  else:
@@ -31,10 +31,10 @@ alias_apply = on_command(
31
31
  alias_agree = on_command("同意别名", aliases={"同意别称"})
32
32
  alias_status = on_command("当前投票", aliases={"当前别名投票", "当前别称投票"})
33
33
  alias_switch = on_regex(
34
- r"^([开启关闭]+)别名推送$", permission=SUPERUSER | GROUP_OWNER | GROUP_ADMIN
34
+ r"^(开启|关闭)别名推送$", permission=SUPERUSER | GROUP_OWNER | GROUP_ADMIN
35
35
  )
36
- alias_global_switch = on_regex(r"^全局([开启关闭]+)别名推送$", permission=SUPERUSER)
37
- alias_song = on_regex(r"^(id)?\s?(.+)\s?有什么别[名称]$", re.IGNORECASE)
36
+ alias_global_switch = on_regex(r"^全局(开启|关闭)别名推送$", permission=SUPERUSER)
37
+ alias_song = on_regex(r"^(id(?=[\s0-9]))?\s?(.+)\s?有什么别[名称]$", re.IGNORECASE)
38
38
 
39
39
 
40
40
  @update_alias.handle()
@@ -117,9 +117,11 @@ async def _(event: GroupMessageEvent, message: Message = CommandArg()):
117
117
  tag = message.extract_plain_text().strip().upper()
118
118
  api = YuzuChaNAPI()
119
119
  status = await api.post_agree_user(tag, event.user_id)
120
- await alias_agree.finish(status.message, reply_message=True)
121
- except ValueError as e:
122
- await alias_agree.finish(str(e), reply_message=True)
120
+ msg = status.message
121
+ except Exception as e:
122
+ log.error(traceback.format_exc())
123
+ msg = str(e)
124
+ await alias_agree.finish(msg, reply_message=True)
123
125
 
124
126
 
125
127
  @alias_status.handle()
@@ -131,7 +133,8 @@ async def _(message: Message = CommandArg()):
131
133
  if not status:
132
134
  await alias_status.finish("未查询到正在进行的别名投票", reply_message=True)
133
135
 
134
- page = max(min(int(args), len(status) // SONGS_PER_PAGE + 1), 1) if args else 1
136
+ total_pages = (len(status) + SONGS_PER_PAGE - 1) // SONGS_PER_PAGE
137
+ page = max(min(int(args), total_pages), 1) if args.isdigit() else 1
135
138
  result = []
136
139
  for num, _s in enumerate(status):
137
140
  if (page - 1) * SONGS_PER_PAGE <= num < page * SONGS_PER_PAGE:
@@ -146,7 +149,7 @@ async def _(message: Message = CommandArg()):
146
149
  - 票数:{_s.agree_votes}/{_s.votes}
147
150
  """)
148
151
  )
149
- result.append(f"第「{page}」页,共「{len(status) // SONGS_PER_PAGE + 1}」页")
152
+ result.append(f"第「{page}」页,共「{total_pages}」页")
150
153
  msg = MessageSegment.image(text_to_bytes_io("\n".join(result)))
151
154
  except Exception as e:
152
155
  log.error(traceback.format_exc())
@@ -195,11 +198,14 @@ async def _(match: Match[str] = RegexMatched()):
195
198
  reply_message=True,
196
199
  )
197
200
 
198
- if len(aliases[0].alias) == 1:
201
+ real_aliases = [
202
+ a for a in aliases[0].alias if a.lower() != aliases[0].song_name.lower()
203
+ ]
204
+ if not real_aliases:
199
205
  await alias_song.finish("该曲目没有别名", reply_message=True)
200
206
 
201
207
  msg = f"该曲目有以下别名:\nID:{aliases[0].song_id}\n"
202
- msg += "\n".join(aliases[0].alias)
208
+ msg += "\n".join(real_aliases)
203
209
  await alias_song.send(msg, reply_message=True)
204
210
 
205
211
 
@@ -206,7 +206,7 @@ async def _(
206
206
  ):
207
207
  if not match:
208
208
  await random_song.finish("参数错误,请重新发送随机谱面", reply_message=True)
209
- diff = match.group(1)
209
+ diff = (match.group(1) or "").lower()
210
210
  if diff == "dx":
211
211
  type_ = ["DX"]
212
212
  elif diff == "sd" or diff == "标准":
@@ -214,10 +214,15 @@ async def _(
214
214
  else:
215
215
  type_ = ["SD", "DX"]
216
216
  level = match.group(3)
217
- if match.group(2) == "":
218
- songs = mai.total_list.filter(level=level, type=type_)
219
- else:
220
- songs = mai.total_list.filter(level=level, type=type_)
217
+ color = match.group(2)
218
+ songs = mai.total_list.filter(level=level, type=type_)
219
+ if color:
220
+ ci = "绿黄红紫白".index(color)
221
+ songs = [
222
+ s
223
+ for s in songs
224
+ if len(s.difficulties) > ci and s.difficulties[ci].level == level
225
+ ]
221
226
  if len(songs) == 0:
222
227
  result = "没有这样的乐曲哦。"
223
228
  else:
@@ -265,3 +270,6 @@ async def _(user: User = Depends(GetOrCreateUser)):
265
270
  if rank.username == info.username:
266
271
  result = f"您的Rating为「{rank.ra}」,排名第「{num + 1}」名"
267
272
  await my_rating_ranking.finish(result, reply_message=True)
273
+ await my_rating_ranking.finish(
274
+ "未在查分器排行榜中找到您的记录。", reply_message=True
275
+ )
@@ -60,6 +60,8 @@ async def _(
60
60
  else:
61
61
  song_id = aliases[0].song_id
62
62
  song = mai.total_list.by_id(song_id)
63
+ if song is None:
64
+ await info.finish("未找到曲目", reply_message=True)
63
65
 
64
66
  result = await draw_play_data(user, song)
65
67
  await info.send(result, reply_message=True)
@@ -93,11 +95,10 @@ async def _(message: Message = CommandArg()):
93
95
  await ginfo.finish(msg.strip(), reply_message=True)
94
96
  else:
95
97
  song = mai.total_list.by_id(alias[0].song_id)
96
- stats = song.difficulties[level_index].stats
97
-
98
- if len(song.difficulties) == 4 and level_index == 4:
98
+ if level_index >= len(song.difficulties):
99
99
  await ginfo.finish("该乐曲没有这个等级", reply_message=True)
100
- if not song.difficulties[level_index]:
100
+ stats = song.difficulties[level_index].stats
101
+ if stats is None:
101
102
  await ginfo.finish("该等级没有统计信息", reply_message=True)
102
103
 
103
104
  data = await draw_song_galobal_data(song, level_index) + dedent(f"""\
@@ -140,6 +141,8 @@ async def _(message: Message = CommandArg()):
140
141
  chart_id = int(result.group(2))
141
142
  line = float(args[-1])
142
143
  song = mai.total_list.by_id(chart_id)
144
+ if song is None or level_index >= len(song.difficulties):
145
+ raise ValueError
143
146
  chart = song.difficulties[level_index]
144
147
  tap = int(chart.notes.tap)
145
148
  slide = int(chart.notes.slide)
@@ -95,7 +95,7 @@ async def _(
95
95
  await search_alias_song.finish(
96
96
  "您要找的是不是:" + await draw_chart_info(song, user), reply_message=True
97
97
  )
98
- if search_id := re.search(r"^id([0-9]*)$", name, re.IGNORECASE):
98
+ if search_id := re.search(r"^id([0-9]+)$", name, re.IGNORECASE):
99
99
  song = mai.total_list.by_id(int(search_id.group(1)))
100
100
  if not song:
101
101
  await search_alias_song.finish(
@@ -30,7 +30,7 @@ TABLE_PATTERN = (
30
30
  r"([極极将舞神者]舞?){}表?\s?([0-9]+)?$"
31
31
  )
32
32
  LEVEL_PATTERN = r"^([0-9]+\+?)\s?((?:a+|b+|c|d|s+|ap|fc|fs|fdx)\+?)\s?([\u4e00-\u9fa5]+)?\s?进度\s?([0-9]+)?$"
33
- LEVEL_LIST_PATTERN = r"([0-9]+\.?[0-9]?\+?)\s?分数列表\s?([0-9]+)?$"
33
+ LEVEL_LIST_PATTERN = r"^([0-9]+(?:\.[0-9]+)?\+?)\s?分数列表\s?([0-9]+)?$"
34
34
  CATEGORY_ALIAS = {
35
35
  "已完成": Category.COMPLETED,
36
36
  "未完成": Category.UNFINISHED,
@@ -87,6 +87,11 @@ async def _(match: Match[str] = RegexMatched(), user: User = Depends(GetUserAndA
87
87
  if ra in LEVEL_LIST[:6]:
88
88
  await rating_table_pfm.finish("只支持查询lv7-15的完成表。", reply_message=True)
89
89
  elif ra in LEVEL_LIST[6:]:
90
+ if plan and plan.lower() not in COMBO_PLUS:
91
+ await rating_table_pfm.finish(
92
+ "完成表目前仅支持「fc」「ap」计划,例如「13fc完成表」「13ap完成表」。",
93
+ reply_message=True,
94
+ )
90
95
  pic = await draw_rating_table(
91
96
  user, ra, True if plan and plan.lower() in COMBO_PLUS else False
92
97
  )
@@ -167,14 +172,15 @@ async def _(match: Match[str] = RegexMatched(), user: User = Depends(GetUserAndA
167
172
  )
168
173
  rating = match.group(1)
169
174
  page = match.group(2) or 1
170
- try:
171
- if "." in rating:
172
- rating = round(float(rating), 1)
173
- elif rating not in LEVEL_LIST:
174
- await level_score_list.finish("无此等级。", reply_message=True)
175
- except ValueError:
176
- if rating not in LEVEL_LIST:
177
- await level_score_list.finish("无此等级。", reply_message=True)
175
+ if "." in rating:
176
+ # 定数仅有一位小数,多位小数视为输入有误
177
+ if not re.fullmatch(r"[0-9]+\.[0-9]", rating):
178
+ await level_score_list.finish(
179
+ "输入有误,定数仅有一位小数。", reply_message=True
180
+ )
181
+ rating = round(float(rating), 1)
182
+ elif rating not in LEVEL_LIST:
183
+ await level_score_list.finish("无此等级。", reply_message=True)
178
184
 
179
185
  result = await draw_level_score_list(user, rating, int(page))
180
186
  await level_score_list.send(result, reply_message=True)
@@ -281,7 +281,7 @@ def get_rise_score_list(
281
281
  level_value=diff.level_value,
282
282
  old_rating=old_result.rating,
283
283
  old_achievements=old_result.achievements,
284
- old_rate=old_result.rate.value,
284
+ old_rate=old_result.rate.value if old_result.rate else "D",
285
285
  )
286
286
  rise_result.append(rise)
287
287
  break
@@ -417,9 +417,9 @@ async def get_mai_what(user: User) -> Song | None:
417
417
  if _ra != 0:
418
418
  ds = round(_ra / 22.4, 1)
419
419
  music_list = mai.total_list.filter(level_value=(ds, ds + 1))
420
- for _m in music_list:
421
- if int(_m.song_id) in ignore:
422
- music_list.remove(_m)
420
+ music_list = [m for m in music_list if int(m.song_id) not in ignore]
421
+ if not music_list:
422
+ return None
423
423
  return random.choice(music_list)
424
424
  return None
425
425
 
@@ -629,8 +629,11 @@ async def draw_level_progress(
629
629
  if plan_type == 2: # Sync
630
630
  if not res.fs:
631
631
  return False
632
- sync_list = SYNC_D_SP if res.fs in SYNC_D_SP else SYNC_SP
633
- return sync_list.index(res.fs) >= plan_value
632
+ if res.fs in SYNC_D_SP:
633
+ return SYNC_D_SP.index(res.fs) >= plan_value
634
+ if res.fs in SYNC_SP:
635
+ return SYNC_SP.index(res.fs) >= plan_value
636
+ return False
634
637
  return False
635
638
 
636
639
  completed: list[PlayedResult] = []
@@ -656,8 +659,14 @@ async def draw_level_progress(
656
659
  )
657
660
 
658
661
  sort_key = {0: "achievements", 1: "fc", 2: "fs"}.get(plan_type, "achievements")
659
- completed.sort(key=lambda x: getattr(x, sort_key) or "", reverse=True)
660
- unfinished.sort(key=lambda x: getattr(x, sort_key) or "", reverse=True)
662
+ sort_default = 0 if plan_type == 0 else ""
663
+
664
+ def _sort_value(res: PlayedResult):
665
+ value = getattr(res, sort_key)
666
+ return value if value is not None else sort_default
667
+
668
+ completed.sort(key=_sort_value, reverse=True)
669
+ unfinished.sort(key=_sort_value, reverse=True)
661
670
  notplayed.sort(key=lambda x: x.level_value, reverse=True)
662
671
 
663
672
  if category == Category.DEFAULT:
@@ -677,9 +686,8 @@ async def draw_level_progress(
677
686
  elif category in [Category.COMPLETED, Category.UNFINISHED]:
678
687
  data = completed if category == Category.COMPLETED else unfinished
679
688
  per_page = 80
680
- total_page = (len(data) - 1) // per_page + 1
681
- if page > total_page:
682
- page = total_page
689
+ total_page = max(1, (len(data) - 1) // per_page + 1)
690
+ page = max(1, min(page, total_page))
683
691
 
684
692
  display_data = data[(page - 1) * per_page : page * per_page]
685
693
  y_size = get_rows(len(display_data), 5) * 109
@@ -728,9 +736,8 @@ async def draw_level_score_list(
728
736
  )
729
737
 
730
738
  result_sum = len(new_play_result)
731
- end_page = (result_sum + 79) // 80
732
- if page > end_page:
733
- page = end_page
739
+ end_page = max(1, (result_sum + 79) // 80)
740
+ page = max(1, min(page, end_page))
734
741
 
735
742
  to_page = 80 if page < end_page else (result_sum % 80 or 80)
736
743
  line = (to_page + 4) // 5
@@ -10,6 +10,7 @@ from ..image.tools import image_to_base64, song_chart
10
10
  from ..merge import merge_alias_data, merge_music_data
11
11
  from ..merge.alias_list import AliasList
12
12
  from ..merge.models import (
13
+ Alias,
13
14
  AliasesPush,
14
15
  GuessDefaultData,
15
16
  GuessPicData,
@@ -151,6 +152,7 @@ class Guess:
151
152
  _group: dict[int, GuessDefaultData | GuessPicData] = {}
152
153
  switch: GuessSwitch
153
154
  hot_music_ids: list[int] = []
155
+ _guess_data: list[Song] = []
154
156
 
155
157
  def __init__(self) -> None:
156
158
  """猜歌类"""
@@ -170,17 +172,17 @@ class Guess:
170
172
  count += diff.stats.cnt if diff.stats.cnt else 0
171
173
  if count > 10000:
172
174
  self.hot_music_ids.append(song.song_id)
173
- self.guess_data = list(
175
+ self._guess_data = list(
174
176
  filter(lambda x: x.song_id in self.hot_music_ids, mai.total_list.root)
175
177
  )
176
178
 
177
179
  def start(self, gid: int):
178
180
  """开始猜歌"""
179
- self._group[gid] = self.guessData()
181
+ self._group[gid] = self.guess_data()
180
182
 
181
183
  def startpic(self, gid: int):
182
184
  """开始猜曲绘"""
183
- self._group[gid] = self.guesspicdata()
185
+ self._group[gid] = self.guess_pic_data()
184
186
 
185
187
  def calculate_frequency_weights(self, image: Image.Image) -> np.ndarray:
186
188
  """
@@ -214,7 +216,7 @@ class Guess:
214
216
  top_left_x = chosen_index % valid_regions.shape[1]
215
217
  return top_left_x, top_left_y
216
218
 
217
- def pic(self, song: Song) -> Image.Image:
219
+ def _pic(self, song: Song) -> Image.Image:
218
220
  """裁切曲绘"""
219
221
  im = Image.open(song_chart(song.song_id))
220
222
  w, h = im.size
@@ -226,19 +228,20 @@ class Guess:
226
228
  im = im.crop((x, y, x + w2, y + h2))
227
229
  return im
228
230
 
229
- def guesspicdata(self) -> GuessPicData:
231
+ def guess_pic_data(self) -> GuessPicData:
230
232
  """猜曲绘数据"""
231
- song = random.choice(self.guess_data)
232
- pic = self.pic(song)
233
- answer = mai.total_alias_list.by_id(song.song_id)[0].alias
234
- answer.append(song.song_id)
233
+ song = random.choice(self._guess_data)
234
+ pic = self._pic(song)
235
+ _alias = mai.total_alias_list.by_id(song.song_id)
236
+ answer = list(_alias[0].alias) if _alias else []
237
+ answer.append(str(song.song_id))
235
238
  return GuessPicData(
236
239
  song=song, img=image_to_base64(pic), answer=answer, end=False
237
240
  )
238
241
 
239
- def guessData(self) -> GuessDefaultData:
242
+ def guess_data(self) -> GuessDefaultData:
240
243
  """猜歌数据"""
241
- song = random.choice(self.guess_data)
244
+ song = random.choice(self._guess_data)
242
245
  guess_options = random.sample(
243
246
  [
244
247
  f"的 Expert 难度是 {song.difficulties[2].level}",
@@ -252,9 +255,10 @@ class Guess:
252
255
  ],
253
256
  6,
254
257
  )
255
- answer = mai.total_alias_list.by_id(song.song_id)[0].alias
256
- answer.append(song.song_id)
257
- pic = self.pic(song)
258
+ _alias = mai.total_alias_list.by_id(song.song_id)
259
+ answer = list(_alias[0].alias) if _alias else []
260
+ answer.append(str(song.song_id))
261
+ pic = self._pic(song)
258
262
  return GuessDefaultData(
259
263
  song=song,
260
264
  img=image_to_base64(pic),
@@ -300,11 +304,24 @@ async def update_local_alias(song_id: int, alias_name: str) -> bool:
300
304
  if local_alias_file.exists():
301
305
  local_alias_data = await openfile(local_alias_file)
302
306
 
303
- if song_id not in local_alias_data:
307
+ if song_id_key not in local_alias_data:
304
308
  local_alias_data[song_id_key] = []
309
+ if alias not in local_alias_data[song_id_key]:
310
+ local_alias_data[song_id_key].append(alias)
305
311
 
306
- local_alias_data[song_id_key].append(alias)
307
- mai.total_alias_list.by_id(song_id)[0].alias.append(alias)
312
+ entries = mai.total_alias_list.by_id(song_id)
313
+ if entries:
314
+ if alias not in entries[0].alias:
315
+ entries[0].alias.append(alias)
316
+ else:
317
+ _song = mai.total_list.by_id(song_id)
318
+ mai.total_alias_list.root.append(
319
+ Alias(
320
+ song_id=song_id,
321
+ song_name=_song.song_name if _song else "",
322
+ alias=[alias],
323
+ )
324
+ )
308
325
 
309
326
  await writefile(local_alias_file, local_alias_data)
310
327
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-maimaidx
3
- Version: 3.0.5
3
+ Version: 3.0.6
4
4
  Summary: maimaidx plugin for nonebot2
5
5
  Author-email: Yuri-YuzuChaN <806235364@qq.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-maimaidx"
3
- version = "3.0.5"
3
+ version = "3.0.6"
4
4
  authors = [
5
5
  { name="Yuri-YuzuChaN", email="806235364@qq.com" },
6
6
  ]