nonebot-plugin-l4d2-server 0.6.5__py3-none-any.whl → 1.0.0a1__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.
Files changed (186) hide show
  1. nonebot_plugin_l4d2_server/__init__.py +9 -93
  2. nonebot_plugin_l4d2_server/__main__.py +90 -0
  3. nonebot_plugin_l4d2_server/config.py +30 -0
  4. nonebot_plugin_l4d2_server/data/L4D2/image/head/head.png +0 -0
  5. nonebot_plugin_l4d2_server/data/L4D2/image/header/logo.png +0 -0
  6. nonebot_plugin_l4d2_server/data/L4D2/image/header/player1.jpg +0 -0
  7. nonebot_plugin_l4d2_server/data/L4D2/image/template/anne.html +50 -42
  8. nonebot_plugin_l4d2_server/data/L4D2/image/template/back.png +0 -0
  9. nonebot_plugin_l4d2_server/data/L4D2/image/template/group_ip.html +1 -2
  10. nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +1 -2
  11. nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +259 -221
  12. nonebot_plugin_l4d2_server/data/L4D2/image/template/ip.html +1 -2
  13. nonebot_plugin_l4d2_server/data/font/loli.ttf +0 -0
  14. nonebot_plugin_l4d2_server/data/icon//344/273/213/347/273/215.png +0 -0
  15. nonebot_plugin_l4d2_server/data/icon//344/273/273/345/212/241.png +0 -0
  16. nonebot_plugin_l4d2_server/data/icon//344/277/241/346/201/257.png +0 -0
  17. nonebot_plugin_l4d2_server/data/icon//345/205/254/345/221/212.png +0 -0
  18. nonebot_plugin_l4d2_server/data/icon//345/210/200/345/211/221.png +0 -0
  19. nonebot_plugin_l4d2_server/data/icon//345/210/207/346/215/242.png +0 -0
  20. nonebot_plugin_l4d2_server/data/icon//345/210/240/351/231/244.png +0 -0
  21. nonebot_plugin_l4d2_server/data/icon//345/210/267/346/226/260.png +0 -0
  22. nonebot_plugin_l4d2_server/data/icon//345/215/241/347/273/204.png +0 -0
  23. nonebot_plugin_l4d2_server/data/icon//345/223/252/351/207/214.png +0 -0
  24. nonebot_plugin_l4d2_server/data/icon//345/234/260/345/233/276.png +0 -0
  25. nonebot_plugin_l4d2_server/data/icon//345/257/274/345/205/245.png +0 -0
  26. nonebot_plugin_l4d2_server/data/icon//345/257/274/345/207/272.png +0 -0
  27. nonebot_plugin_l4d2_server/data/icon//345/275/261.png +0 -0
  28. nonebot_plugin_l4d2_server/data/icon//346/213/274/345/233/276.png +0 -0
  29. nonebot_plugin_l4d2_server/data/icon//346/216/242/347/264/242.png +0 -0
  30. nonebot_plugin_l4d2_server/data/icon//346/216/250/351/200/201.png +0 -0
  31. nonebot_plugin_l4d2_server/data/icon//346/224/266/351/233/206.png +0 -0
  32. nonebot_plugin_l4d2_server/data/icon//346/224/273/347/225/245.png +0 -0
  33. nonebot_plugin_l4d2_server/data/icon//346/233/264/346/226/260.png +0 -0
  34. nonebot_plugin_l4d2_server/data/icon//346/235/220/346/226/231.png +0 -0
  35. nonebot_plugin_l4d2_server/data/icon//346/237/245/350/257/242.png +0 -0
  36. nonebot_plugin_l4d2_server/data/icon//346/240/241/351/252/214.png +0 -0
  37. nonebot_plugin_l4d2_server/data/icon//346/257/217/346/234/210.png +0 -0
  38. nonebot_plugin_l4d2_server/data/icon//346/267/261/346/270/212.png +0 -0
  39. nonebot_plugin_l4d2_server/data/icon//346/267/273/345/212/240.png +0 -0
  40. nonebot_plugin_l4d2_server/data/icon//346/270/205/351/231/244.png +0 -0
  41. nonebot_plugin_l4d2_server/data/icon//347/212/266/346/200/201.png +0 -0
  42. nonebot_plugin_l4d2_server/data/icon//347/255/276/345/210/260.png +0 -0
  43. nonebot_plugin_l4d2_server/data/icon//347/273/221/345/256/232.png +0 -0
  44. nonebot_plugin_l4d2_server/data/icon//350/241/250.png +0 -0
  45. nonebot_plugin_l4d2_server/data/icon//350/241/250/346/203/205.png +0 -0
  46. nonebot_plugin_l4d2_server/data/icon//350/247/222/350/211/262.png +0 -0
  47. nonebot_plugin_l4d2_server/data/icon//350/256/260/345/275/225.png +0 -0
  48. nonebot_plugin_l4d2_server/data/icon//351/205/215/347/275/256.png +0 -0
  49. nonebot_plugin_l4d2_server/data/icon//351/207/215/345/220/257.png +0 -0
  50. nonebot_plugin_l4d2_server/data/img/l4d2.png +0 -0
  51. nonebot_plugin_l4d2_server/data/img/linux.png +0 -0
  52. nonebot_plugin_l4d2_server/data/img/vac.png +0 -0
  53. nonebot_plugin_l4d2_server/data/img/white.png +0 -0
  54. nonebot_plugin_l4d2_server/l4_help/Help.json +65 -0
  55. nonebot_plugin_l4d2_server/l4_help/__init__.py +57 -0
  56. nonebot_plugin_l4d2_server/l4_help/draw.py +206 -0
  57. nonebot_plugin_l4d2_server/l4_help/icon//344/273/213/347/273/215.png +0 -0
  58. nonebot_plugin_l4d2_server/l4_help/icon//344/273/273/345/212/241.png +0 -0
  59. nonebot_plugin_l4d2_server/l4_help/icon//344/277/241/346/201/257.png +0 -0
  60. nonebot_plugin_l4d2_server/l4_help/icon//345/205/254/345/221/212.png +0 -0
  61. nonebot_plugin_l4d2_server/l4_help/icon//345/210/200/345/211/221.png +0 -0
  62. nonebot_plugin_l4d2_server/l4_help/icon//345/210/207/346/215/242.png +0 -0
  63. nonebot_plugin_l4d2_server/l4_help/icon//345/210/240/351/231/244.png +0 -0
  64. nonebot_plugin_l4d2_server/l4_help/icon//345/210/267/346/226/260.png +0 -0
  65. nonebot_plugin_l4d2_server/l4_help/icon//345/215/241/347/273/204.png +0 -0
  66. nonebot_plugin_l4d2_server/l4_help/icon//345/223/252/351/207/214.png +0 -0
  67. nonebot_plugin_l4d2_server/l4_help/icon//345/234/260/345/233/276.png +0 -0
  68. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/205/245.png +0 -0
  69. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/207/272.png +0 -0
  70. nonebot_plugin_l4d2_server/l4_help/icon//345/275/261.png +0 -0
  71. nonebot_plugin_l4d2_server/l4_help/icon//346/213/274/345/233/276.png +0 -0
  72. nonebot_plugin_l4d2_server/l4_help/icon//346/216/242/347/264/242.png +0 -0
  73. nonebot_plugin_l4d2_server/l4_help/icon//346/216/250/351/200/201.png +0 -0
  74. nonebot_plugin_l4d2_server/l4_help/icon//346/224/266/351/233/206.png +0 -0
  75. nonebot_plugin_l4d2_server/l4_help/icon//346/224/273/347/225/245.png +0 -0
  76. nonebot_plugin_l4d2_server/l4_help/icon//346/233/264/346/226/260.png +0 -0
  77. nonebot_plugin_l4d2_server/l4_help/icon//346/235/220/346/226/231.png +0 -0
  78. nonebot_plugin_l4d2_server/l4_help/icon//346/237/245/350/257/242.png +0 -0
  79. nonebot_plugin_l4d2_server/l4_help/icon//346/240/241/351/252/214.png +0 -0
  80. nonebot_plugin_l4d2_server/l4_help/icon//346/257/217/346/234/210.png +0 -0
  81. nonebot_plugin_l4d2_server/l4_help/icon//346/267/261/346/270/212.png +0 -0
  82. nonebot_plugin_l4d2_server/l4_help/icon//346/267/273/345/212/240.png +0 -0
  83. nonebot_plugin_l4d2_server/l4_help/icon//346/270/205/351/231/244.png +0 -0
  84. nonebot_plugin_l4d2_server/l4_help/icon//347/212/266/346/200/201.png +0 -0
  85. nonebot_plugin_l4d2_server/l4_help/icon//347/255/276/345/210/260.png +0 -0
  86. nonebot_plugin_l4d2_server/l4_help/icon//347/273/221/345/256/232.png +0 -0
  87. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250.png +0 -0
  88. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250/346/203/205.png +0 -0
  89. nonebot_plugin_l4d2_server/l4_help/icon//350/247/222/350/211/262.png +0 -0
  90. nonebot_plugin_l4d2_server/l4_help/icon//350/256/260/345/275/225.png +0 -0
  91. nonebot_plugin_l4d2_server/l4_help/icon//351/205/215/347/275/256.png +0 -0
  92. nonebot_plugin_l4d2_server/l4_help/icon//351/207/215/345/220/257.png +0 -0
  93. nonebot_plugin_l4d2_server/l4_help/texture2d/badge.png +0 -0
  94. nonebot_plugin_l4d2_server/l4_help/texture2d/banner.png +0 -0
  95. nonebot_plugin_l4d2_server/l4_help/texture2d/bg.jpg +0 -0
  96. nonebot_plugin_l4d2_server/l4_help/texture2d/button.png +0 -0
  97. nonebot_plugin_l4d2_server/l4_help/texture2d/icon.png +0 -0
  98. nonebot_plugin_l4d2_server/l4_image/__init__.py +16 -0
  99. nonebot_plugin_l4d2_server/l4_image/convert.py +175 -0
  100. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/download.py +6 -30
  101. nonebot_plugin_l4d2_server/{l4d2_image/__init__.py → l4_image/html_img.py} +55 -45
  102. nonebot_plugin_l4d2_server/l4_image/image_tools.py +468 -0
  103. nonebot_plugin_l4d2_server/l4_image/img/anne/anne.html +60 -0
  104. nonebot_plugin_l4d2_server/l4_image/img/anne/back.png +0 -0
  105. nonebot_plugin_l4d2_server/l4_image/img/anne/group_ip.html +259 -0
  106. nonebot_plugin_l4d2_server/l4_image/img/anne/ip.html +55 -0
  107. nonebot_plugin_l4d2_server/l4_image/img/head/head.png +0 -0
  108. nonebot_plugin_l4d2_server/l4_image/img/header/logo.png +0 -0
  109. nonebot_plugin_l4d2_server/l4_image/img/header/player1.jpg +0 -0
  110. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.html +312 -0
  111. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.png +0 -0
  112. nonebot_plugin_l4d2_server/l4_image/img/template/HYPixel11pxU-2.ttf +0 -0
  113. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.html +350 -0
  114. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.png +0 -0
  115. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.html +321 -0
  116. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.png +0 -0
  117. nonebot_plugin_l4d2_server/l4_image/img/template/Tutumianhuatang-Bold-2.ttf +0 -0
  118. nonebot_plugin_l4d2_server/l4_image/img/template/bilibili.svg +1 -0
  119. nonebot_plugin_l4d2_server/l4_image/img/template/fingerprint.svg +15 -0
  120. nonebot_plugin_l4d2_server/l4_image/img/template/github.svg +1 -0
  121. nonebot_plugin_l4d2_server/l4_image/img/template/l.svg +9 -0
  122. nonebot_plugin_l4d2_server/l4_image/img/template/m.svg +1 -0
  123. nonebot_plugin_l4d2_server/l4_image/img/template/normal.html +257 -0
  124. nonebot_plugin_l4d2_server/l4_image/img/template/vue.css +531 -0
  125. nonebot_plugin_l4d2_server/l4_image/img/template/w.svg +1 -0
  126. nonebot_plugin_l4d2_server/l4_image/img/template//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  127. nonebot_plugin_l4d2_server/l4_image/model.py +15 -0
  128. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/vtfs.py +2 -0
  129. nonebot_plugin_l4d2_server/l4_request/__init__.py +84 -0
  130. nonebot_plugin_l4d2_server/l4_request/draw_msg.py +88 -0
  131. nonebot_plugin_l4d2_server/utils/api/api.py +4 -0
  132. nonebot_plugin_l4d2_server/utils/api/models.py +29 -0
  133. nonebot_plugin_l4d2_server/utils/api/request.py +119 -0
  134. nonebot_plugin_l4d2_server/utils/database/models.py +29 -0
  135. nonebot_plugin_l4d2_server/{l4d2_utils → utils}/utils.py +52 -55
  136. {nonebot_plugin_l4d2_server-0.6.5.dist-info → nonebot_plugin_l4d2_server-1.0.0a1.dist-info}/METADATA +47 -64
  137. nonebot_plugin_l4d2_server-1.0.0a1.dist-info/RECORD +144 -0
  138. {nonebot_plugin_l4d2_server-0.6.5.dist-info → nonebot_plugin_l4d2_server-1.0.0a1.dist-info}/WHEEL +1 -1
  139. nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +0 -95
  140. nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +0 -54
  141. nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +0 -79
  142. nonebot_plugin_l4d2_server/l4d2_anne/server.py +0 -47
  143. nonebot_plugin_l4d2_server/l4d2_anne/startand.py +0 -17
  144. nonebot_plugin_l4d2_server/l4d2_anne/utils.py +0 -294
  145. nonebot_plugin_l4d2_server/l4d2_data/__init__.py +0 -105
  146. nonebot_plugin_l4d2_server/l4d2_data/config.py +0 -18
  147. nonebot_plugin_l4d2_server/l4d2_data/database.py +0 -0
  148. nonebot_plugin_l4d2_server/l4d2_data/players.py +0 -100
  149. nonebot_plugin_l4d2_server/l4d2_data/serverip.py +0 -40
  150. nonebot_plugin_l4d2_server/l4d2_file/__init__.py +0 -223
  151. nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +0 -64
  152. nonebot_plugin_l4d2_server/l4d2_file/input_json.py +0 -77
  153. nonebot_plugin_l4d2_server/l4d2_file/remote.py +0 -86
  154. nonebot_plugin_l4d2_server/l4d2_file/utils.py +0 -104
  155. nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +0 -18
  156. nonebot_plugin_l4d2_server/l4d2_image/images.py +0 -96
  157. nonebot_plugin_l4d2_server/l4d2_image/one.py +0 -44
  158. nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +0 -32
  159. nonebot_plugin_l4d2_server/l4d2_image/steam.py +0 -63
  160. nonebot_plugin_l4d2_server/l4d2_push/__init__.py +0 -226
  161. nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +0 -326
  162. nonebot_plugin_l4d2_server/l4d2_queries/himi.py +0 -113
  163. nonebot_plugin_l4d2_server/l4d2_queries/local_ip.py +0 -41
  164. nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +0 -370
  165. nonebot_plugin_l4d2_server/l4d2_queries/send_msg.py +0 -131
  166. nonebot_plugin_l4d2_server/l4d2_queries/utils.py +0 -212
  167. nonebot_plugin_l4d2_server/l4d2_server/__init__.py +0 -118
  168. nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
  169. nonebot_plugin_l4d2_server/l4d2_server/rcon.py +0 -53
  170. nonebot_plugin_l4d2_server/l4d2_server/workshop.py +0 -82
  171. nonebot_plugin_l4d2_server/l4d2_update/__init__.py +0 -135
  172. nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +0 -45
  173. nonebot_plugin_l4d2_server/l4d2_update/restart.py +0 -69
  174. nonebot_plugin_l4d2_server/l4d2_update/update.py +0 -53
  175. nonebot_plugin_l4d2_server/l4d2_utils/classcal.py +0 -53
  176. nonebot_plugin_l4d2_server/l4d2_utils/command.py +0 -23
  177. nonebot_plugin_l4d2_server/l4d2_utils/config.py +0 -196
  178. nonebot_plugin_l4d2_server/l4d2_utils/message.py +0 -59
  179. nonebot_plugin_l4d2_server/l4d2_utils/rule.py +0 -35
  180. nonebot_plugin_l4d2_server/l4d2_utils/seach.py +0 -43
  181. nonebot_plugin_l4d2_server/l4d2_utils/txt_to_img.py +0 -32
  182. nonebot_plugin_l4d2_server/l4d2_web/web.py +0 -277
  183. nonebot_plugin_l4d2_server/l4d2_web/webUI.py +0 -498
  184. nonebot_plugin_l4d2_server/l4d2_web/webUI_s.py +0 -94
  185. nonebot_plugin_l4d2_server-0.6.5.dist-info/RECORD +0 -70
  186. {nonebot_plugin_l4d2_server-0.6.5.dist-info → nonebot_plugin_l4d2_server-1.0.0a1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,65 @@
1
+ {
2
+ "基础服务": {
3
+ "desc": "无需任何权限",
4
+ "data": [
5
+ {
6
+ "name": "l4全服",
7
+ "desc": "返回可以查询的所有服务器组",
8
+ "eg": "l4全服",
9
+ "need_ck": false,
10
+ "need_sk": false,
11
+ "need_admin": false
12
+ },
13
+ {
14
+ "name": "(组指令)",
15
+ "desc": "返回一个组的服务器信息",
16
+ "eg": "云",
17
+ "need_ck": false,
18
+ "need_sk": false,
19
+ "need_admin": false
20
+ },
21
+ {
22
+ "name": "雀魂切换uid",
23
+ "desc": "切换你的雀魂UID",
24
+ "eg": "雀魂切换uid123456",
25
+ "need_ck": false,
26
+ "need_sk": false,
27
+ "need_admin": false
28
+ }
29
+ ]
30
+ },
31
+ "查询服务": {
32
+ "desc": "查询一些基本信息, 需要在金之间拥有一定场次的对局",
33
+ "data": [
34
+ {
35
+ "name": "雀魂搜索",
36
+ "desc": "搜索雀魂玩家",
37
+ "eg": "雀魂搜索Wuyi",
38
+ "need_ck": true,
39
+ "need_sk": false,
40
+ "need_admin": false
41
+ },
42
+ {
43
+ "name": "雀魂查询",
44
+ "desc": "查询雀魂数据一览",
45
+ "eg": "雀魂查询1148850",
46
+ "need_ck": true,
47
+ "need_sk": false,
48
+ "need_admin": false
49
+ }
50
+ ]
51
+ },
52
+ "其他服务": {
53
+ "desc": "一些杂项服务",
54
+ "data": [
55
+ {
56
+ "name": "雀魂帮助",
57
+ "desc": "呼出该帮助界面",
58
+ "eg": "雀魂帮助",
59
+ "need_ck": false,
60
+ "need_sk": false,
61
+ "need_admin": false
62
+ }
63
+ ]
64
+ }
65
+ }
@@ -0,0 +1,57 @@
1
+ from pathlib import Path
2
+ from typing import Dict, Union
3
+
4
+ import aiofiles
5
+ from msgspec import json as msgjson
6
+ from PIL import Image
7
+
8
+ from ..config import ICONPATH
9
+ from ..l4_image.convert import core_font
10
+ from ..l4_image.model import PluginHelp
11
+ from .draw import get_help
12
+
13
+ __version__ = "1.0.0a1"
14
+ TEXT_PATH = Path(__file__).parent / "texture2d"
15
+ HELP_DATA = Path(__file__).parent / "Help.json"
16
+
17
+
18
+ async def get_help_data() -> Union[Dict[str, PluginHelp], None]:
19
+ if HELP_DATA.exists():
20
+ async with aiofiles.open(HELP_DATA, "rb") as file:
21
+ return msgjson.decode(
22
+ await file.read(),
23
+ type=Dict[str, PluginHelp],
24
+ )
25
+ return None
26
+
27
+
28
+ async def get_l4d2_core_help() -> Union[bytes, str]:
29
+ help_data = await get_help_data()
30
+ if help_data is None:
31
+ return "暂未找到帮助数据..."
32
+
33
+ bg_out = Image.open(TEXT_PATH / "bg.jpg")
34
+ bg_new = Image.new(
35
+ "RGBA",
36
+ (bg_out.width, bg_out.height),
37
+ (255, 255, 255, 100),
38
+ )
39
+ bg_out.paste(bg_new, None, bg_new)
40
+
41
+ return await get_help(
42
+ "CS2UID",
43
+ f"版本号:{__version__}",
44
+ help_data,
45
+ bg_out,
46
+ Image.open(TEXT_PATH / "icon.png"),
47
+ Image.open(TEXT_PATH / "badge.png"),
48
+ Image.open(TEXT_PATH / "banner.png"),
49
+ Image.open(TEXT_PATH / "button.png"),
50
+ core_font,
51
+ is_dark=False,
52
+ column=4,
53
+ is_gaussian=False,
54
+ text_color=(23, 67, 91),
55
+ sub_c=(49, 110, 144),
56
+ icon_path=ICONPATH,
57
+ )
@@ -0,0 +1,206 @@
1
+ from copy import deepcopy
2
+ from pathlib import Path
3
+ from typing import Callable, Dict, List, Optional, Tuple
4
+
5
+ from nonebot_plugin_datastore import get_plugin_data
6
+ from PIL import Image, ImageDraw, ImageFilter, ImageFont
7
+
8
+ from ..l4_image.convert import convert_img, pic_quality
9
+ from ..l4_image.image_tools import crop_center_img
10
+ from ..l4_image.model import PluginHelp
11
+
12
+ cache: Dict[str, int] = {}
13
+ Micon_path = Path(__file__).parent / "icon"
14
+ DEFAULT_ICON = Micon_path / "拼图.png"
15
+ plugin_data = get_plugin_data()
16
+
17
+
18
+ def cx(w: int, x: int) -> int:
19
+ return int((w - x) / 2)
20
+
21
+
22
+ def _get_icon(name: str, icon_path: Path) -> Optional[Image.Image]:
23
+ path = icon_path / f"{name}.png"
24
+ icon = None
25
+ if path.exists():
26
+ icon = Image.open(path)
27
+ else:
28
+ for i in icon_path.glob("*.png"):
29
+ if i.stem in name:
30
+ icon = Image.open(i)
31
+ break
32
+
33
+ return icon
34
+
35
+
36
+ def get_icon(name: str, icon_path: Optional[Path]) -> Image.Image:
37
+ if icon_path is not None:
38
+ icon = _get_icon(name, icon_path)
39
+ if icon is None:
40
+ icon = _get_icon(name, Micon_path)
41
+ else:
42
+ icon = _get_icon(name, Micon_path)
43
+
44
+ if icon is None:
45
+ icon = Image.open(DEFAULT_ICON)
46
+
47
+ return icon.resize((36, 36))
48
+
49
+
50
+ async def get_help(
51
+ name: str,
52
+ sub_text: str,
53
+ help_data: Dict[str, PluginHelp],
54
+ bg: Image.Image,
55
+ icon: Image.Image,
56
+ badge: Image.Image,
57
+ banner: Image.Image,
58
+ button: Image.Image,
59
+ font: Callable[[int], ImageFont.FreeTypeFont],
60
+ is_dark: bool = True,
61
+ text_color: Tuple[int, int, int] = (250, 250, 250),
62
+ sub_c: Optional[Tuple[int, int, int]] = None,
63
+ op_color: Optional[Tuple[int, int, int]] = None,
64
+ title_color: Tuple[int, int, int] = (250, 250, 250),
65
+ sub_title_color: Tuple[int, int, int] = (235, 235, 235),
66
+ sv_color: Tuple[int, int, int] = (250, 250, 250),
67
+ sv_desc_color: Tuple[int, int, int] = (235, 235, 235),
68
+ column: int = 5,
69
+ is_gaussian: bool = False,
70
+ gaussian_blur: int = 20,
71
+ is_icon: bool = True,
72
+ icon_path: Optional[Path] = None,
73
+ extra_message: Optional[List[str]] = None,
74
+ enable_cache: bool = True,
75
+ ) -> bytes:
76
+ if sub_c is None and is_dark:
77
+ sub_c = tuple(x - 50 if x > 50 else x for x in text_color) # type: ignore
78
+ elif sub_c is None and not is_dark:
79
+ sub_c = tuple(x + 50 if x < 205 else x for x in text_color) # type: ignore
80
+
81
+ if op_color is None and is_dark:
82
+ op_color = tuple(x - 90 if x > 90 else x for x in text_color) # type: ignore
83
+ elif op_color is None and not is_dark:
84
+ op_color = tuple(x + 90 if x < 160 else x for x in text_color) # type: ignore
85
+
86
+ _h = 600
87
+
88
+ if extra_message:
89
+ _h += 100
90
+
91
+ w, h = 50 + 260 * column, _h + 30
92
+ button_x = 260
93
+ button_y = 103 # 80
94
+
95
+ title = Image.new("RGBA", (w, _h))
96
+ icon = icon.resize((300, 300))
97
+
98
+ title.paste(icon, (cx(w, 300), 89), icon)
99
+ title.paste(badge, (cx(w, 900), 390), badge)
100
+ badge_s = badge.resize((720, 80))
101
+ title.paste(badge_s, (cx(w, 720), 480), badge_s)
102
+
103
+ title_draw = ImageDraw.Draw(title)
104
+
105
+ if extra_message:
106
+ all_lenth = 300 * (len(extra_message) - 1) + 720
107
+ first_x = (w - all_lenth) / 2
108
+ for _i, message in enumerate(extra_message):
109
+ _x = int(first_x + _i * 300)
110
+ title.paste(badge_s, (_x, 556), badge_s)
111
+ title_draw.text((_x + 360, 596), message, sub_c, font(26), "mm")
112
+
113
+ title_draw.text(
114
+ (cx(w, 0), 440),
115
+ f"{name} 帮助",
116
+ title_color,
117
+ font(36),
118
+ "mm",
119
+ )
120
+ title_draw.text((cx(w, 0), 520), sub_text, sub_title_color, font(26), "mm")
121
+
122
+ if is_dark:
123
+ icon_mask = Image.new("RGBA", (36, 36), (255, 255, 255))
124
+ else:
125
+ icon_mask = Image.new("RGBA", (36, 36), (10, 10, 10))
126
+
127
+ sv_img_list: List[Image.Image] = []
128
+ for sv_name in help_data:
129
+ tr_size = len(help_data[sv_name]["data"])
130
+ y = 100 + ((tr_size + column - 1) // column) * button_y
131
+ h += y
132
+
133
+ # 生成单个服务的背景, 依据默认column
134
+ sv_img = Image.new("RGBA", (w, y))
135
+ sv_data = help_data[sv_name]["data"]
136
+ sv_desc = help_data[sv_name]["desc"]
137
+
138
+ bc = deepcopy(banner)
139
+ bc_draw = ImageDraw.Draw(bc)
140
+ bc_draw.text((30, 25), sv_name, sv_color, font(35), "lm")
141
+
142
+ if hasattr(font, "getsize"):
143
+ size, _ = font(35).getsize(sv_name) # type: ignore
144
+ else:
145
+ bbox = font(35).getbbox(sv_name)
146
+ size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1]
147
+
148
+ bc_draw.text((42 + size, 30), sv_desc, sv_desc_color, font(20), "lm")
149
+ sv_img.paste(bc, (0, 10), bc)
150
+ # sv_img = easy_alpha_composite(sv_img, bc, (0, 10))
151
+
152
+ # 开始绘制各个按钮
153
+ for index, tr in enumerate(sv_data):
154
+ bt = deepcopy(button)
155
+ bt_draw = ImageDraw.Draw(bt)
156
+
157
+ # 限制长度
158
+ tr_name = tr["name"]
159
+
160
+ if is_icon:
161
+ f = 38
162
+ icon = get_icon(tr["name"], icon_path)
163
+ bt.paste(icon_mask, (14, 20), icon)
164
+ else:
165
+ f = 0
166
+
167
+ # 标题
168
+ bt_draw.text((20 + f, 28), tr_name, text_color, font(26), "lm")
169
+ # 使用范例
170
+ bt_draw.text((20 + f, 50), tr["eg"], sub_c, font(17), "lm")
171
+ # 简单介绍
172
+ bt_draw.text((20, 78), tr["desc"], op_color, font(16), "lm")
173
+
174
+ offset_x = button_x * (index % column)
175
+ offset_y = button_y * (index // column)
176
+ sv_img.paste(bt, (25 + offset_x, 83 + offset_y), bt)
177
+
178
+ sv_img_list.append(sv_img)
179
+
180
+ img = crop_center_img(bg, w, h)
181
+ if is_gaussian:
182
+ img = img.filter(ImageFilter.GaussianBlur(gaussian_blur))
183
+
184
+ img.paste(title, (0, 0), title)
185
+ temp = 0
186
+ for _sm in sv_img_list:
187
+ img.paste(_sm, (0, _h + temp), _sm)
188
+ temp += _sm.size[1]
189
+
190
+ img = img.convert("RGBA")
191
+ all_white = Image.new("RGBA", img.size, (255, 255, 255))
192
+ img = Image.alpha_composite(all_white, img)
193
+
194
+ img = img.convert("RGB")
195
+ help_path = plugin_data.data_dir.joinpath("help") / f"{name}.jpg"
196
+ help_path.parent.mkdir(parents=True, exist_ok=True)
197
+ if enable_cache:
198
+ img.save(
199
+ help_path,
200
+ "JPEG",
201
+ quality=pic_quality,
202
+ subsampling=0,
203
+ )
204
+ cache[name] = 1
205
+
206
+ return await convert_img(img)
@@ -0,0 +1,16 @@
1
+ from typing import List
2
+
3
+ from ..utils.api.models import OutServer
4
+ from .html_img import server_ip_pic
5
+
6
+
7
+ async def msg_to_image(server_dict: List[OutServer], mode="html"):
8
+ """信息构造图片"""
9
+ if mode == "html":
10
+ """用浏览器作图"""
11
+ return await server_ip_pic(server_dict)
12
+ if mode == "pil":
13
+ """用pil作图"""
14
+ return None
15
+ """返回文字"""
16
+ return None
@@ -0,0 +1,175 @@
1
+ from base64 import b64encode
2
+ from io import BytesIO
3
+ from pathlib import Path
4
+ from typing import Union, overload
5
+
6
+ import aiofiles
7
+ from nonebot.log import logger
8
+ from PIL import Image, ImageDraw, ImageFont
9
+
10
+ from .image_tools import draw_center_text_by_line
11
+
12
+ FONT_PATH = Path(__file__).parent.parent / "data/font/loli.ttf"
13
+ pic_quality: int = 95
14
+
15
+
16
+ def core_font(size: int) -> ImageFont.FreeTypeFont:
17
+ return ImageFont.truetype(str(FONT_PATH), size=size)
18
+
19
+
20
+ @overload
21
+ async def convert_img(
22
+ img: Image.Image,
23
+ is_base64: bool = False,
24
+ ) -> bytes:
25
+ ...
26
+
27
+
28
+ @overload
29
+ async def convert_img(
30
+ img: Image.Image,
31
+ is_base64: bool = True,
32
+ ) -> str:
33
+ ...
34
+
35
+
36
+ @overload
37
+ async def convert_img(
38
+ img: bytes,
39
+ is_base64: bool = False,
40
+ ) -> str:
41
+ ...
42
+
43
+
44
+ @overload
45
+ async def convert_img(
46
+ img: Path,
47
+ is_base64: bool = False,
48
+ ) -> str:
49
+ ...
50
+
51
+
52
+ async def convert_img(
53
+ img: Union[Image.Image, str, Path, bytes],
54
+ is_base64: bool = False,
55
+ ):
56
+ """
57
+ :说明:
58
+ 将PIL.Image对象转换为bytes或者base64格式。
59
+ :参数:
60
+ * img (Image): 图片。
61
+ * is_base64 (bool): 是否转换为base64格式, 不填默认转为bytes。
62
+ :返回:
63
+ * res: bytes对象或base64编码图片。
64
+ """
65
+ logger.info("处理图片中....")
66
+
67
+ if isinstance(img, Image.Image):
68
+ img = img.convert("RGB")
69
+ result_buffer = BytesIO()
70
+ img.save(result_buffer, format="JPEG", quality=95)
71
+ res = result_buffer.getvalue()
72
+ if is_base64:
73
+ res = "base64://" + b64encode(res).decode()
74
+ return res
75
+ if isinstance(img, bytes):
76
+ pass
77
+ else:
78
+ async with aiofiles.open(img, "rb") as fp:
79
+ img = await fp.read()
80
+
81
+ logger.success("图片处理完成!")
82
+
83
+ return f"base64://{b64encode(img).decode()}"
84
+
85
+
86
+ def convert_img_sync(img_path: Path):
87
+ with img_path.open("rb") as fp:
88
+ img = fp.read()
89
+
90
+ return f"base64://{b64encode(img).decode()}"
91
+
92
+
93
+ async def str_lenth(r: str, size: int, limit: int = 540) -> str:
94
+ result = ""
95
+ temp = 0
96
+ for i in r:
97
+ if i == "\n":
98
+ temp = 0
99
+ result += i
100
+ continue
101
+
102
+ if temp >= limit:
103
+ result += "\n" + i
104
+ temp = 0
105
+ else:
106
+ result += i
107
+
108
+ if i.isdigit():
109
+ temp += round(size / 10 * 6)
110
+ elif i == "/":
111
+ temp += round(size / 10 * 2.2)
112
+ elif i == ".":
113
+ temp += round(size / 10 * 3)
114
+ elif i == "%":
115
+ temp += round(size / 10 * 9.4)
116
+ else:
117
+ temp += size
118
+ return result
119
+
120
+
121
+ def get_str_size(
122
+ r: str,
123
+ font: ImageFont.FreeTypeFont,
124
+ limit: int = 540,
125
+ ) -> str:
126
+ result = ""
127
+ line = ""
128
+ for i in r:
129
+ if i == "\n":
130
+ result += f"{line}\n"
131
+ line = ""
132
+ continue
133
+
134
+ line += i
135
+
136
+ if hasattr(font, "getsize"):
137
+ size, _ = font.getsize(line) # type: ignore
138
+ else:
139
+ bbox = font.getbbox(line)
140
+ size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1]
141
+
142
+ if size >= limit:
143
+ result += f"{line}\n"
144
+ line = ""
145
+ else:
146
+ result += line
147
+ return result
148
+
149
+
150
+ def get_height(content: str, size: int) -> int:
151
+ line_count = content.count("\n")
152
+ return (line_count + 1) * size
153
+
154
+
155
+ async def text2pic(text: str, max_size: int = 800, font_size: int = 24):
156
+ if text.endswith("\n"):
157
+ text = text[:-1]
158
+
159
+ img = Image.new(
160
+ "RGB",
161
+ (max_size, len(text) * font_size // 3),
162
+ (255, 255, 255),
163
+ )
164
+ img_draw = ImageDraw.ImageDraw(img)
165
+ y = draw_center_text_by_line(
166
+ img_draw,
167
+ (50, 50),
168
+ text,
169
+ core_font(font_size),
170
+ "black",
171
+ max_size - 80,
172
+ True,
173
+ )
174
+ img = img.crop((0, 0, max_size, int(y + 80)))
175
+ return await convert_img(img)