nonebot-plugin-maimaidx 3.0.0__tar.gz → 3.0.2__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.0 → nonebot_plugin_maimaidx-3.0.2}/PKG-INFO +25 -17
  2. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/README.md +22 -16
  3. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/__init__.py +1 -1
  4. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_score.py +4 -3
  5. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_table.py +14 -1
  6. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/config.py +1 -1
  7. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/constants.py +0 -3
  8. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/assets.py +6 -13
  9. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/best50.py +1 -1
  10. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/plate_table.py +4 -2
  11. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/__init__.py +105 -22
  12. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/service/__init__.py +4 -1
  13. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/resources.py +12 -8
  14. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx.egg-info/PKG-INFO +25 -17
  15. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx.egg-info/requires.txt +2 -0
  16. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/pyproject.toml +4 -2
  17. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/LICENSE +0 -0
  18. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/__init__.py +0 -0
  19. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/depend.py +0 -0
  20. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_alias.py +0 -0
  21. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_base.py +0 -0
  22. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_guess.py +0 -0
  23. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/commands/mai_search.py +0 -0
  24. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/alias_ws_push.py +0 -0
  25. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/divingfish/client.py +0 -0
  26. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/divingfish/exceptions.py +0 -0
  27. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/divingfish/models/__init__.py +0 -0
  28. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/divingfish/models/music.py +0 -0
  29. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/divingfish/models/score.py +0 -0
  30. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/exceptions.py +0 -0
  31. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/http.py +0 -0
  32. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/client.py +0 -0
  33. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/exceptions.py +0 -0
  34. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/__init__.py +0 -0
  35. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/base.py +0 -0
  36. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/collection.py +0 -0
  37. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/enum.py +0 -0
  38. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/music.py +0 -0
  39. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/oauth.py +0 -0
  40. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/player.py +0 -0
  41. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/lxns/models/score.py +0 -0
  42. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/client.py +0 -0
  43. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/exceptions.py +0 -0
  44. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/__init__.py +0 -0
  45. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/alias.py +0 -0
  46. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/enum.py +0 -0
  47. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/message.py +0 -0
  48. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/clients/yuzuchan/models/status.py +0 -0
  49. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/database/qq.py +0 -0
  50. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/handler.py +0 -0
  51. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/handler_error.py +0 -0
  52. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/__init__.py +0 -0
  53. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/base.py +0 -0
  54. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/chart.py +0 -0
  55. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/info.py +0 -0
  56. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/rating_table.py +0 -0
  57. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/score.py +0 -0
  58. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/song.py +0 -0
  59. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/tools.py +0 -0
  60. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/image/update_table.py +0 -0
  61. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/alias.py +0 -0
  62. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/alias_list.py +0 -0
  63. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/__init__.py +0 -0
  64. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/alias.py +0 -0
  65. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/best50.py +0 -0
  66. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/enum.py +0 -0
  67. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/guess.py +0 -0
  68. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/player.py +0 -0
  69. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/score.py +0 -0
  70. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/models/song.py +0 -0
  71. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/music_list.py +0 -0
  72. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/play_result.py +0 -0
  73. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/merge/player.py +0 -0
  74. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/service/diving_fish.py +0 -0
  75. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/service/lxns.py +0 -0
  76. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/service/yuzuchan.py +0 -0
  77. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/tool.py +0 -0
  78. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/core/utils/calc.py +0 -0
  79. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx/maimaidxhelp.png +0 -0
  80. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx.egg-info/SOURCES.txt +0 -0
  81. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx.egg-info/dependency_links.txt +0 -0
  82. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/nonebot_plugin_maimaidx.egg-info/top_level.txt +0 -0
  83. {nonebot_plugin_maimaidx-3.0.0 → nonebot_plugin_maimaidx-3.0.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-maimaidx
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: maimaidx plugin for nonebot2
5
5
  Author-email: Yuri-YuzuChaN <806235364@qq.com>
6
6
  License-Expression: MIT
@@ -22,6 +22,8 @@ Requires-Dist: playwright>=1.52.0
22
22
  Requires-Dist: httpx-ws<1.0.0,>=0.7.2
23
23
  Requires-Dist: numpy<3.0.0,>=2.0.0
24
24
  Requires-Dist: pillow<12.0.0,>=10.0.0
25
+ Requires-Dist: sqlmodel>=0.0.38
26
+ Requires-Dist: aiosqlite>=0.22.1
25
27
  Dynamic: license-file
26
28
 
27
29
  <div align='center'>
@@ -54,6 +56,7 @@ Dynamic: license-file
54
56
  - 新增切换查分器功能
55
57
  - 新增 `ap50` 指令(仅限落雪查分器)
56
58
  - 新增 `lxbind`,`主题`,`数据源` 指令
59
+ - 新增 `牌子条件` 指令
57
60
  4. 修改了别名推送的发送方式,防止刷屏
58
61
  5. 修复了非常多的 BUG
59
62
 
@@ -90,7 +93,7 @@ Dynamic: license-file
90
93
 
91
94
  ## 配置
92
95
 
93
- 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static\data` 文件夹,字体文件放置到 `static\font` 文件夹
96
+ 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static/data` 文件夹,字体文件放置到 `static/font` 文件夹
94
97
 
95
98
  ## 对于美术的声明,请勿将绘图设计署名进行删除
96
99
 
@@ -101,21 +104,21 @@ Dynamic: license-file
101
104
  2. 配置可选项,请修改 `.env` 文件,并根据要求填写
102
105
 
103
106
  ```
104
- # maimaidx # 基本配置
105
- MAIMAIDX_PATH= # 静态文件夹路径,必须为绝对路径到 `\static`,例如:E:\SakuraBOT\nbstatic\maimaidx\static
106
- MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
107
- SAVE_IN_MEM=true # 是否将部分图片保存在内存
108
- ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
109
-
110
- # diving-fish # 水鱼查分器配置
111
- DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
112
- DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
113
-
114
- # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
115
- LXNS_DEV_TOKEN= # 开发者 token
116
- LX_CLIENT_ID= # OAuth 应用ID
117
- LX_CLIENT_SECRET= # OAuth 应用秘钥
118
- REDIRECT_URI= # OAuth 回调地址
107
+ # maimaidx # 基本配置
108
+ MAIMAIDX_PATH= # 必填项,静态文件夹路径,必须为绝对路径到 `/static`,例如:e:/SakuraBOT/nbstatic/maimaidx/static
109
+ MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
110
+ SAVE_IN_MEMORY=true # 是否将部分图片保存在内存
111
+ ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
112
+
113
+ # diving-fish # 水鱼查分器配置
114
+ DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
115
+ DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
116
+
117
+ # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
118
+ LXNS_DEV_TOKEN= # 开发者 token
119
+ LX_CLIENT_ID= # OAuth 应用ID
120
+ LX_CLIENT_SECRET= # OAuth 应用秘钥
121
+ REDIRECT_URI= # OAuth 回调地址
119
122
  ```
120
123
 
121
124
  > [!NOTE]
@@ -148,11 +151,16 @@ Dynamic: license-file
148
151
  - 新增切换查分器功能
149
152
  - 新增 `ap50` 指令(仅限落雪查分器)
150
153
  - 新增 `lxbind`,`主题`,`数据源` 指令
154
+ - 新增 `牌子条件` 指令
151
155
  4. 修改了别名推送的发送方式,防止刷屏
152
156
  5. 修复了非常多的 BUG
153
157
 
154
158
  </details>
155
159
 
160
+ ## 鸣谢
161
+
162
+ 感谢 [蓝色彗星](#) 提供的 `牌子条件` 指令图片
163
+
156
164
  ## License
157
165
 
158
166
  MIT
@@ -28,6 +28,7 @@
28
28
  - 新增切换查分器功能
29
29
  - 新增 `ap50` 指令(仅限落雪查分器)
30
30
  - 新增 `lxbind`,`主题`,`数据源` 指令
31
+ - 新增 `牌子条件` 指令
31
32
  4. 修改了别名推送的发送方式,防止刷屏
32
33
  5. 修复了非常多的 BUG
33
34
 
@@ -64,7 +65,7 @@
64
65
 
65
66
  ## 配置
66
67
 
67
- 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static\data` 文件夹,字体文件放置到 `static\font` 文件夹
68
+ 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static/data` 文件夹,字体文件放置到 `static/font` 文件夹
68
69
 
69
70
  ## 对于美术的声明,请勿将绘图设计署名进行删除
70
71
 
@@ -75,21 +76,21 @@
75
76
  2. 配置可选项,请修改 `.env` 文件,并根据要求填写
76
77
 
77
78
  ```
78
- # maimaidx # 基本配置
79
- MAIMAIDX_PATH= # 静态文件夹路径,必须为绝对路径到 `\static`,例如:E:\SakuraBOT\nbstatic\maimaidx\static
80
- MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
81
- SAVE_IN_MEM=true # 是否将部分图片保存在内存
82
- ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
83
-
84
- # diving-fish # 水鱼查分器配置
85
- DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
86
- DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
87
-
88
- # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
89
- LXNS_DEV_TOKEN= # 开发者 token
90
- LX_CLIENT_ID= # OAuth 应用ID
91
- LX_CLIENT_SECRET= # OAuth 应用秘钥
92
- REDIRECT_URI= # OAuth 回调地址
79
+ # maimaidx # 基本配置
80
+ MAIMAIDX_PATH= # 必填项,静态文件夹路径,必须为绝对路径到 `/static`,例如:e:/SakuraBOT/nbstatic/maimaidx/static
81
+ MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
82
+ SAVE_IN_MEMORY=true # 是否将部分图片保存在内存
83
+ ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
84
+
85
+ # diving-fish # 水鱼查分器配置
86
+ DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
87
+ DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
88
+
89
+ # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
90
+ LXNS_DEV_TOKEN= # 开发者 token
91
+ LX_CLIENT_ID= # OAuth 应用ID
92
+ LX_CLIENT_SECRET= # OAuth 应用秘钥
93
+ REDIRECT_URI= # OAuth 回调地址
93
94
  ```
94
95
 
95
96
  > [!NOTE]
@@ -122,11 +123,16 @@
122
123
  - 新增切换查分器功能
123
124
  - 新增 `ap50` 指令(仅限落雪查分器)
124
125
  - 新增 `lxbind`,`主题`,`数据源` 指令
126
+ - 新增 `牌子条件` 指令
125
127
  4. 修改了别名推送的发送方式,防止刷屏
126
128
  5. 修复了非常多的 BUG
127
129
 
128
130
  </details>
129
131
 
132
+ ## 鸣谢
133
+
134
+ 感谢 [蓝色彗星](#) 提供的 `牌子条件` 指令图片
135
+
130
136
  ## License
131
137
 
132
138
  MIT
@@ -82,7 +82,7 @@ async def get_music():
82
82
 
83
83
  if not list(plate_table_dir.iterdir()):
84
84
  log.opt(colors=True).warning(
85
- "<y>注意!注意!</y>未检测到牌子文件夹为空!"
85
+ "<y>注意!注意!</y>检测到牌子文件夹为空!"
86
86
  "可能导致「完成表」指令无法使用,"
87
87
  "请及时私聊BOT使用指令「更新完成表」进行生成。"
88
88
  )
@@ -10,6 +10,7 @@ from ..config import log
10
10
  from ..core.database.qq import User
11
11
  from ..core.handler import draw_best50, draw_play_data, draw_song_galobal_data
12
12
  from ..core.image.tools import text_to_bytes_io
13
+ from ..core.merge.models import ServiceName
13
14
  from ..core.service import mai
14
15
  from .depend import GetUserAndAuth
15
16
 
@@ -28,9 +29,9 @@ async def _(
28
29
  user: User = Depends(GetUserAndAuth),
29
30
  ):
30
31
  username = message.extract_plain_text().strip()
31
- result = await draw_best50(
32
- user, username=username, all_perfect=isinstance(matcher, ap50)
33
- )
32
+ if (is_ap := isinstance(matcher, ap50)) and user.service == ServiceName.DIVINGFISH:
33
+ await matcher.finish("AP50仅支持落雪查分器", reply_message=True)
34
+ result = await draw_best50(user, username=username, all_perfect=is_ap)
34
35
  await matcher.send(result, reply_message=True)
35
36
 
36
37
 
@@ -2,10 +2,11 @@ import re
2
2
  from re import Match
3
3
 
4
4
  from nonebot import on_fullmatch, on_regex
5
- from nonebot.adapters.onebot.v11 import PrivateMessageEvent
5
+ from nonebot.adapters.onebot.v11 import MessageSegment, PrivateMessageEvent
6
6
  from nonebot.matcher import Matcher
7
7
  from nonebot.params import Depends, RegexMatched
8
8
  from nonebot.permission import SUPERUSER
9
+ from PIL import Image
9
10
 
10
11
  from ..constants import COMBO_PLUS, LEVEL_LIST, PLATE_CN, RANK_PLUS, SYNC_PLUS
11
12
  from ..core.database.qq import User
@@ -17,8 +18,10 @@ from ..core.handler import (
17
18
  draw_rating_table,
18
19
  draw_rating_table_text,
19
20
  )
21
+ from ..core.image.tools import image_to_base64
20
22
  from ..core.image.update_table import UpdateTable
21
23
  from ..core.merge.models import Category
24
+ from ..resources import pic_dir
22
25
  from .depend import GetUserAndAuth
23
26
 
24
27
  RATING_PATTERN = r"^([0-9]+\+?)((s+|ap|fc|fs|fdx)\+?)?\s?完成表$"
@@ -40,6 +43,7 @@ update_table = on_fullmatch("更新定数表", permission=SUPERUSER)
40
43
  update_plate = on_fullmatch("更新完成表", permission=SUPERUSER)
41
44
  rating_table = on_regex(r"([0-9]+\+?)定数表")
42
45
  rating_table_pfm = on_regex(RATING_PATTERN, re.IGNORECASE)
46
+ plate_table_condition = on_fullmatch("牌子条件")
43
47
  plate_table_pfm = on_regex(TABLE_PATTERN.format("完成"))
44
48
  plate_progress = on_regex(TABLE_PATTERN.format("进度"))
45
49
  level_progress = on_regex(LEVEL_PATTERN, re.IGNORECASE)
@@ -91,6 +95,15 @@ async def _(match: Match[str] = RegexMatched(), user: User = Depends(GetUserAndA
91
95
  await rating_table_pfm.finish("无法识别的定数。", reply_message=True)
92
96
 
93
97
 
98
+ @plate_table_condition.handle()
99
+ async def _():
100
+ await plate_table_condition.send(
101
+ MessageSegment.image(
102
+ image_to_base64(Image.open(pic_dir / "table_condition.jpg"))
103
+ )
104
+ )
105
+
106
+
94
107
  @plate_table_pfm.handle()
95
108
  @plate_progress.handle()
96
109
  async def _(
@@ -10,7 +10,7 @@ class BaseConfig(BaseModel):
10
10
  maimaidx_alias_proxy: bool = False
11
11
  maimaidx_alias_push: bool = True
12
12
  save_in_memory: bool | None = True
13
- assets_online: bool | None = False
13
+ assets_online: bool | None = True
14
14
  bot_name: str = (
15
15
  list(driver.config.nickname)[0] if driver.config.nickname else "Sakura"
16
16
  )
@@ -1,7 +1,5 @@
1
1
  import uuid
2
2
 
3
- from .core.merge.models import Theme
4
-
5
3
  # vote
6
4
  VOTE_URL = "https://www.yuzuchan.moe/vote"
7
5
 
@@ -26,7 +24,6 @@ FORTUNE = [
26
24
  "打大歌",
27
25
  "推AP",
28
26
  ]
29
- THEME = {str(k): v for k, v in enumerate(Theme)}
30
27
  RANK_SP = [
31
28
  "d",
32
29
  "c",
@@ -78,10 +78,8 @@ class AssetsImage:
78
78
 
79
79
  def __init__(self) -> None:
80
80
  """静态资源类"""
81
- if maiconfig.save_in_memory:
81
+ if not maiconfig.save_in_memory:
82
82
  self._load_image()
83
- else:
84
- self.load_image()
85
83
 
86
84
  @staticmethod
87
85
  def _open_image(path: Path) -> Image.Image:
@@ -170,16 +168,11 @@ class AssetsImage:
170
168
  @classmethod
171
169
  def _load_image(cls) -> None:
172
170
  """将图片缓存在内存"""
173
- if AssetsImage._images_loaded:
171
+ if cls._images_loaded:
174
172
  return
175
173
  for name, image in cls._create_images().items():
176
- setattr(AssetsImage, name, image)
177
- AssetsImage._images_loaded = True
178
-
179
- def load_image(self) -> None:
180
- """不将图片缓存在内存,在需要用的时候加载"""
181
- for name, image in self._create_images().items():
182
- setattr(self, name, image)
174
+ setattr(cls, name, image)
175
+ cls._images_loaded = True
183
176
 
184
177
  def _themed_image(self, theme: Theme, name: str) -> Image.Image:
185
178
  """
@@ -193,9 +186,9 @@ class AssetsImage:
193
186
  """
194
187
  key = (theme, name)
195
188
  if maiconfig.save_in_memory:
196
- image = AssetsImage._themed_images.get(key)
189
+ image = self._themed_images.get(key)
197
190
  if image is None:
198
191
  image = self._open_image(pic_dir / theme.value / name)
199
- AssetsImage._themed_images[key] = image
192
+ self._themed_images[key] = image
200
193
  return image
201
194
  return self._open_image(pic_dir / theme.value / name)
@@ -83,7 +83,7 @@ class PlayerBest50(ScoreBaseImage):
83
83
  return f"UI_CMN_DXRating_Star_0{num_map[idx]}.png"
84
84
 
85
85
  async def _fetch_image(self, type: str, file_name: str) -> BytesIO | Path | None:
86
- file = f"UI_{type.capitalize()}_{file_name}.png"
86
+ file = f"UI_{type.capitalize()}_{file_name.zfill(6)}.png"
87
87
  if not maiconfig.assets_online:
88
88
  return static / "mai" / type / file
89
89
  return await online_assets(f"/{type}/{file}")
@@ -330,7 +330,7 @@ class DrawPlateTable(PlateTable):
330
330
 
331
331
  def _get_plate_icon(self, play: PlayedResult, plan: str) -> Image.Image:
332
332
  """获取完成表中已达成谱面的图标。"""
333
- if plan == "将":
333
+ if plan in ["将", "者"]:
334
334
  rate = compute_rating(play.level_value, play.achievements, onlyrate=True)
335
335
  return self._open_image(
336
336
  pic_dir / Theme.PRISM_PLUS.value / f"UI_TTR_Rank_{rate}.png"
@@ -370,7 +370,9 @@ class DrawPlateTable(PlateTable):
370
370
  play = song.results[index]
371
371
  im.alpha_composite(self._plate_complete_bg, (x + 1, y + 1))
372
372
  icon = self._get_plate_icon(play, self.plan)
373
- dest = (x, y + 22) if self.plan == "将" else (x + 10, y + 12)
373
+ dest = (
374
+ (x, y + 22) if self.plan in ["将", "者"] else (x + 10, y + 12)
375
+ )
374
376
  im.alpha_composite(icon, dest)
375
377
 
376
378
  for s_idx in song.qualified_slots:
@@ -1,14 +1,17 @@
1
1
  from collections import defaultdict
2
2
 
3
+ from ...constants import DX_CN_VERSION
3
4
  from ...resources import merge_alias_file, merge_music_file
4
5
  from ..clients.divingfish.models import Music, Notes1, Notes2, Stats
5
6
  from ..clients.lxns.models import (
6
7
  Aliases,
8
+ BuddyNotes,
7
9
  Notes,
8
10
  SongDifficulty,
9
11
  SongDifficultyUtage,
10
12
  Songs,
11
13
  )
14
+ from ..clients.lxns.models import Song as LXSong
12
15
  from ..clients.yuzuchan.models import Alias as YuzuAlias
13
16
  from ..tool import writefile
14
17
  from .alias_list import AliasList
@@ -33,6 +36,40 @@ def chart_notes_to_domain(notes: Notes1 | Notes2) -> Notes:
33
36
  )
34
37
 
35
38
 
39
+ def build_difficulty(
40
+ level_index: int,
41
+ level: str,
42
+ level_value: float,
43
+ note_designer: str,
44
+ notes: Notes,
45
+ ) -> Difficulties:
46
+ return Difficulties(
47
+ level_index=level_index,
48
+ level=level,
49
+ level_value=level_value,
50
+ note_designer=note_designer,
51
+ notes=notes,
52
+ dx_score=notes.total * 3,
53
+ stats=None,
54
+ )
55
+
56
+
57
+ def append_missing_difficulty(song: Song, diffs: list[SongDifficulty]) -> None:
58
+ if len(song.difficulties) == len(diffs):
59
+ return
60
+
61
+ diff = diffs[-1]
62
+ song.difficulties.append(
63
+ build_difficulty(
64
+ level_index=diff.difficulty,
65
+ level=diff.level,
66
+ level_value=diff.level_value,
67
+ note_designer=diff.note_designer,
68
+ notes=diff.notes,
69
+ )
70
+ )
71
+
72
+
36
73
  async def merge_music_data(
37
74
  *,
38
75
  diving_fish_list: list[Music],
@@ -82,53 +119,99 @@ async def merge_music_data(
82
119
 
83
120
  # lxns
84
121
  if lxns_list is not None:
122
+ _version = lxns_list.versions
123
+ ver_map = {v.version: v.title for v in _version}
124
+ new_version = _version[-1].version
85
125
 
86
126
  def set_version(
87
- sid: int, type_: list[SongDifficulty] | list[SongDifficultyUtage]
127
+ raw: LXSong,
128
+ ver_type: str,
129
+ sid: int,
130
+ diffs: list[SongDifficulty] | list[SongDifficultyUtage],
88
131
  ):
89
132
  song = song_map.get(sid)
90
- if song is None:
133
+ base = diffs[0]
134
+ if song is not None:
135
+ song.version_int = base.version
136
+ if isinstance(base, SongDifficultyUtage):
137
+ song.kanji = base.kanji
138
+ song.description = base.description
139
+ song.is_buddy = base.is_buddy
140
+ else:
141
+ append_missing_difficulty(song, diffs)
91
142
  return
92
143
 
93
- base = type_[0]
94
- song.version_int = base.version
144
+ _ver = base.version
145
+ diff_ver = _ver - _ver % 100
146
+
147
+ if sid > 100000:
148
+ if isinstance(base.notes, BuddyNotes):
149
+ _notes = [base.notes.left, base.notes.right]
150
+ else:
151
+ _notes = [base.notes]
152
+ difficulties = [
153
+ build_difficulty(
154
+ level_index=n,
155
+ level=base.level,
156
+ level_value=base.level_value,
157
+ note_designer=base.note_designer,
158
+ notes=notes,
159
+ )
160
+ for n, notes in enumerate(_notes)
161
+ ]
162
+ else:
163
+ difficulties = [
164
+ build_difficulty(
165
+ level_index=n,
166
+ level=d.level,
167
+ level_value=d.level_value,
168
+ note_designer=d.note_designer,
169
+ notes=d.notes,
170
+ )
171
+ for n, d in enumerate(diffs)
172
+ ]
173
+
174
+ song = Song(
175
+ song_id=sid,
176
+ song_name=raw.title,
177
+ artist=raw.artist,
178
+ genre=raw.genre,
179
+ bpm=raw.bpm,
180
+ version_str=DX_CN_VERSION.get(ver_map[diff_ver])[-1],
181
+ version_int=base.version,
182
+ type=ver_type,
183
+ isnew=new_version == base.version,
184
+ difficulties=difficulties,
185
+ )
186
+
95
187
  if isinstance(base, SongDifficultyUtage):
96
188
  song.kanji = base.kanji
97
189
  song.description = base.description
98
190
  song.is_buddy = base.is_buddy
99
- elif len(song.difficulties) != len(type_):
100
- _s = type_[-1]
101
- song.difficulties.append(
102
- Difficulties(
103
- level_index=_s.difficulty,
104
- level=_s.level,
105
- level_value=_s.level_value,
106
- note_designer=_s.note_designer,
107
- notes=_s.notes,
108
- dx_score=_s.notes.total * 3,
109
- stats=None,
110
- )
111
- )
191
+ else:
192
+ append_missing_difficulty(song, diffs)
193
+
194
+ song_map[sid] = song
112
195
 
113
196
  for _raw in lxns_list.songs:
114
197
  song_id = _raw.id
115
198
 
116
199
  if song_id < 1000:
117
200
  if _raw.difficulties.standard:
118
- set_version(song_id, _raw.difficulties.standard)
201
+ set_version(_raw, "SD", song_id, _raw.difficulties.standard)
119
202
 
120
203
  if _raw.difficulties.dx:
121
- set_version(song_id + 10000, _raw.difficulties.dx)
204
+ set_version(_raw, "DX", song_id + 10000, _raw.difficulties.dx)
122
205
 
123
206
  elif song_id < 100000:
124
207
  if _raw.difficulties.dx:
125
- set_version(song_id + 10000, _raw.difficulties.dx)
208
+ set_version(_raw, "DX", song_id + 10000, _raw.difficulties.dx)
126
209
 
127
210
  if _raw.difficulties.standard:
128
- set_version(song_id - 10000, _raw.difficulties.standard)
211
+ set_version(_raw, "SD", song_id - 10000, _raw.difficulties.standard)
129
212
  else:
130
213
  if _raw.difficulties.utage:
131
- set_version(song_id, _raw.difficulties.utage)
214
+ set_version(_raw, "DX", song_id, _raw.difficulties.utage)
132
215
 
133
216
  for sid, stat_list in stats_map.items():
134
217
  song = song_map.get(int(sid))
@@ -72,7 +72,10 @@ class MaiMusic:
72
72
  log.opt(colors=True).warning(
73
73
  "<r>未配置落雪开发者Token,跳过获取「落雪」别名数据源</r>"
74
74
  )
75
- local_alias_data = await openfile(local_alias_file)
75
+
76
+ local_alias_data = {}
77
+ if local_alias_file.exists():
78
+ local_alias_data = await openfile(local_alias_file)
76
79
  if not local_alias_data:
77
80
  local_alias_data = None
78
81
 
@@ -16,14 +16,18 @@ else:
16
16
  # 静态资源路径
17
17
  font_dir = static / "font"
18
18
  data_dir = static / "data"
19
- pic_dir = static / "mai" / "pic"
20
- cover_dir = static / "mai" / "cover"
21
- plate_dir = static / "mai" / "plate"
22
- shougou_dir = static / "mai" / "shougou"
23
- plate_version_dir = static / "mai" / "plate_version"
24
- plate_table_dir = static / "mai" / "plate_table"
25
- rating_table_dir = static / "mai" / "rating_table"
26
-
19
+ mai_dir = static / "mai"
20
+ pic_dir = mai_dir / "pic"
21
+ cover_dir = mai_dir / "cover"
22
+ plate_dir = mai_dir / "plate"
23
+ shougou_dir = mai_dir / "shougou"
24
+ plate_version_dir = mai_dir / "plate_version"
25
+ plate_table_dir = mai_dir / "plate_table"
26
+ rating_table_dir = mai_dir / "rating_table"
27
+
28
+ data_dir.mkdir(parents=True, exist_ok=True)
29
+ plate_table_dir.mkdir(parents=True, exist_ok=True)
30
+ rating_table_dir.mkdir(parents=True, exist_ok=True)
27
31
 
28
32
  # 路径文件
29
33
  pie_html_file = static / "temp_pie.html" # 饼图html文件
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-maimaidx
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: maimaidx plugin for nonebot2
5
5
  Author-email: Yuri-YuzuChaN <806235364@qq.com>
6
6
  License-Expression: MIT
@@ -22,6 +22,8 @@ Requires-Dist: playwright>=1.52.0
22
22
  Requires-Dist: httpx-ws<1.0.0,>=0.7.2
23
23
  Requires-Dist: numpy<3.0.0,>=2.0.0
24
24
  Requires-Dist: pillow<12.0.0,>=10.0.0
25
+ Requires-Dist: sqlmodel>=0.0.38
26
+ Requires-Dist: aiosqlite>=0.22.1
25
27
  Dynamic: license-file
26
28
 
27
29
  <div align='center'>
@@ -54,6 +56,7 @@ Dynamic: license-file
54
56
  - 新增切换查分器功能
55
57
  - 新增 `ap50` 指令(仅限落雪查分器)
56
58
  - 新增 `lxbind`,`主题`,`数据源` 指令
59
+ - 新增 `牌子条件` 指令
57
60
  4. 修改了别名推送的发送方式,防止刷屏
58
61
  5. 修复了非常多的 BUG
59
62
 
@@ -90,7 +93,7 @@ Dynamic: license-file
90
93
 
91
94
  ## 配置
92
95
 
93
- 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static\data` 文件夹,字体文件放置到 `static\font` 文件夹
96
+ 1. 下载静态资源文件,将该压缩文件解压后,将 `static` 文件夹复制到随意一个文件夹进行存放。对于先前使用过的开发者,请将原先 `static` 文件夹内的所有 `json` 文件放置到 `static/data` 文件夹,字体文件放置到 `static/font` 文件夹
94
97
 
95
98
  ## 对于美术的声明,请勿将绘图设计署名进行删除
96
99
 
@@ -101,21 +104,21 @@ Dynamic: license-file
101
104
  2. 配置可选项,请修改 `.env` 文件,并根据要求填写
102
105
 
103
106
  ```
104
- # maimaidx # 基本配置
105
- MAIMAIDX_PATH= # 静态文件夹路径,必须为绝对路径到 `\static`,例如:E:\SakuraBOT\nbstatic\maimaidx\static
106
- MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
107
- SAVE_IN_MEM=true # 是否将部分图片保存在内存
108
- ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
109
-
110
- # diving-fish # 水鱼查分器配置
111
- DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
112
- DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
113
-
114
- # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
115
- LXNS_DEV_TOKEN= # 开发者 token
116
- LX_CLIENT_ID= # OAuth 应用ID
117
- LX_CLIENT_SECRET= # OAuth 应用秘钥
118
- REDIRECT_URI= # OAuth 回调地址
107
+ # maimaidx # 基本配置
108
+ MAIMAIDX_PATH= # 必填项,静态文件夹路径,必须为绝对路径到 `/static`,例如:e:/SakuraBOT/nbstatic/maimaidx/static
109
+ MAIMAIDX_ALIAS_PROXY=false # 是否使用中转访问柚子别名服务器,适用于境内服务器
110
+ SAVE_IN_MEMORY=true # 是否将部分图片保存在内存
111
+ ASSETS_ONLINE=true # 对于有 `icon` 和 `plate` 资源的可将此项改为 `false`,如果没有请默认,否则使用落雪查分器时无法使用
112
+
113
+ # diving-fish # 水鱼查分器配置
114
+ DIVINGFISH_TOKEN= # 开发者 token,由于水鱼查分器修改了请求鉴权,未填写的仅可使用 `b50` 指令
115
+ DIVINGFISH_PROBER_PROXY=false # 是否使用中转访问水鱼查分器,适用于境外服务器
116
+
117
+ # lxns # 落雪查分器配置,均未填写将无法使用落雪查分器
118
+ LXNS_DEV_TOKEN= # 开发者 token
119
+ LX_CLIENT_ID= # OAuth 应用ID
120
+ LX_CLIENT_SECRET= # OAuth 应用秘钥
121
+ REDIRECT_URI= # OAuth 回调地址
119
122
  ```
120
123
 
121
124
  > [!NOTE]
@@ -148,11 +151,16 @@ Dynamic: license-file
148
151
  - 新增切换查分器功能
149
152
  - 新增 `ap50` 指令(仅限落雪查分器)
150
153
  - 新增 `lxbind`,`主题`,`数据源` 指令
154
+ - 新增 `牌子条件` 指令
151
155
  4. 修改了别名推送的发送方式,防止刷屏
152
156
  5. 修复了非常多的 BUG
153
157
 
154
158
  </details>
155
159
 
160
+ ## 鸣谢
161
+
162
+ 感谢 [蓝色彗星](#) 提供的 `牌子条件` 指令图片
163
+
156
164
  ## License
157
165
 
158
166
  MIT
@@ -9,3 +9,5 @@ playwright>=1.52.0
9
9
  httpx-ws<1.0.0,>=0.7.2
10
10
  numpy<3.0.0,>=2.0.0
11
11
  pillow<12.0.0,>=10.0.0
12
+ sqlmodel>=0.0.38
13
+ aiosqlite>=0.22.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-maimaidx"
3
- version = "3.0.0"
3
+ version = "3.0.2"
4
4
  authors = [
5
5
  { name="Yuri-YuzuChaN", email="806235364@qq.com" },
6
6
  ]
@@ -23,7 +23,9 @@ dependencies = [
23
23
  "playwright>=1.52.0",
24
24
  "httpx-ws>=0.7.2,<1.0.0",
25
25
  "numpy>=2.0.0,<3.0.0",
26
- "pillow>=10.0.0,<12.0.0"
26
+ "pillow>=10.0.0,<12.0.0",
27
+ "sqlmodel>=0.0.38",
28
+ "aiosqlite>=0.22.1"
27
29
  ]
28
30
 
29
31
  [project.urls]