nonebot-plugin-l4d2-server 0.6.6__py3-none-any.whl → 1.0.0a2__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 (147) hide show
  1. nonebot_plugin_l4d2_server/__init__.py +10 -93
  2. nonebot_plugin_l4d2_server/__main__.py +140 -0
  3. nonebot_plugin_l4d2_server/config.py +35 -0
  4. nonebot_plugin_l4d2_server/data/font/loli.ttf +0 -0
  5. nonebot_plugin_l4d2_server/l4_anne/__init__.py +124 -0
  6. nonebot_plugin_l4d2_server/l4_anne/ranne.py +18 -0
  7. nonebot_plugin_l4d2_server/l4_help/Help.json +102 -0
  8. nonebot_plugin_l4d2_server/l4_help/__init__.py +57 -0
  9. nonebot_plugin_l4d2_server/l4_help/draw.py +206 -0
  10. nonebot_plugin_l4d2_server/l4_help/icon//344/273/213/347/273/215.png +0 -0
  11. nonebot_plugin_l4d2_server/l4_help/icon//344/273/273/345/212/241.png +0 -0
  12. nonebot_plugin_l4d2_server/l4_help/icon//344/277/241/346/201/257.png +0 -0
  13. nonebot_plugin_l4d2_server/l4_help/icon//345/205/254/345/221/212.png +0 -0
  14. nonebot_plugin_l4d2_server/l4_help/icon//345/210/200/345/211/221.png +0 -0
  15. nonebot_plugin_l4d2_server/l4_help/icon//345/210/207/346/215/242.png +0 -0
  16. nonebot_plugin_l4d2_server/l4_help/icon//345/210/240/351/231/244.png +0 -0
  17. nonebot_plugin_l4d2_server/l4_help/icon//345/210/267/346/226/260.png +0 -0
  18. nonebot_plugin_l4d2_server/l4_help/icon//345/215/241/347/273/204.png +0 -0
  19. nonebot_plugin_l4d2_server/l4_help/icon//345/223/252/351/207/214.png +0 -0
  20. nonebot_plugin_l4d2_server/l4_help/icon//345/234/260/345/233/276.png +0 -0
  21. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/205/245.png +0 -0
  22. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/207/272.png +0 -0
  23. nonebot_plugin_l4d2_server/l4_help/icon//345/275/261.png +0 -0
  24. nonebot_plugin_l4d2_server/l4_help/icon//346/213/274/345/233/276.png +0 -0
  25. nonebot_plugin_l4d2_server/l4_help/icon//346/216/242/347/264/242.png +0 -0
  26. nonebot_plugin_l4d2_server/l4_help/icon//346/216/250/351/200/201.png +0 -0
  27. nonebot_plugin_l4d2_server/l4_help/icon//346/224/266/351/233/206.png +0 -0
  28. nonebot_plugin_l4d2_server/l4_help/icon//346/224/273/347/225/245.png +0 -0
  29. nonebot_plugin_l4d2_server/l4_help/icon//346/233/264/346/226/260.png +0 -0
  30. nonebot_plugin_l4d2_server/l4_help/icon//346/235/220/346/226/231.png +0 -0
  31. nonebot_plugin_l4d2_server/l4_help/icon//346/237/245/350/257/242.png +0 -0
  32. nonebot_plugin_l4d2_server/l4_help/icon//346/240/241/351/252/214.png +0 -0
  33. nonebot_plugin_l4d2_server/l4_help/icon//346/257/217/346/234/210.png +0 -0
  34. nonebot_plugin_l4d2_server/l4_help/icon//346/267/261/346/270/212.png +0 -0
  35. nonebot_plugin_l4d2_server/l4_help/icon//346/267/273/345/212/240.png +0 -0
  36. nonebot_plugin_l4d2_server/l4_help/icon//346/270/205/351/231/244.png +0 -0
  37. nonebot_plugin_l4d2_server/l4_help/icon//347/212/266/346/200/201.png +0 -0
  38. nonebot_plugin_l4d2_server/l4_help/icon//347/255/276/345/210/260.png +0 -0
  39. nonebot_plugin_l4d2_server/l4_help/icon//347/273/221/345/256/232.png +0 -0
  40. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250.png +0 -0
  41. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250/346/203/205.png +0 -0
  42. nonebot_plugin_l4d2_server/l4_help/icon//350/247/222/350/211/262.png +0 -0
  43. nonebot_plugin_l4d2_server/l4_help/icon//350/256/260/345/275/225.png +0 -0
  44. nonebot_plugin_l4d2_server/l4_help/icon//351/205/215/347/275/256.png +0 -0
  45. nonebot_plugin_l4d2_server/l4_help/icon//351/207/215/345/220/257.png +0 -0
  46. nonebot_plugin_l4d2_server/l4_help/texture2d/badge.png +0 -0
  47. nonebot_plugin_l4d2_server/l4_help/texture2d/banner.png +0 -0
  48. nonebot_plugin_l4d2_server/l4_help/texture2d/bg.jpg +0 -0
  49. nonebot_plugin_l4d2_server/l4_help/texture2d/button.png +0 -0
  50. nonebot_plugin_l4d2_server/l4_help/texture2d/icon.png +0 -0
  51. nonebot_plugin_l4d2_server/l4_image/__init__.py +16 -0
  52. nonebot_plugin_l4d2_server/l4_image/anne_pil.py +17 -0
  53. nonebot_plugin_l4d2_server/l4_image/convert.py +175 -0
  54. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/download.py +11 -35
  55. nonebot_plugin_l4d2_server/l4_image/html_img.py +105 -0
  56. nonebot_plugin_l4d2_server/l4_image/image_tools.py +468 -0
  57. nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/back.png +0 -0
  58. nonebot_plugin_l4d2_server/l4_image/img/anne/back1.jpg +0 -0
  59. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/head/head.png +0 -0
  60. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/logo.png +0 -0
  61. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/player1.jpg +0 -0
  62. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.html +299 -0
  63. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.png +0 -0
  64. nonebot_plugin_l4d2_server/l4_image/img/template/HYPixel11pxU-2.ttf +0 -0
  65. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.html +341 -0
  66. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.png +0 -0
  67. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.html +355 -0
  68. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.png +0 -0
  69. nonebot_plugin_l4d2_server/l4_image/img/template/Tutumianhuatang-Bold-2.ttf +0 -0
  70. nonebot_plugin_l4d2_server/l4_image/img/template/bilibili.svg +1 -0
  71. nonebot_plugin_l4d2_server/l4_image/img/template/github.svg +1 -0
  72. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/l.svg +0 -1
  73. nonebot_plugin_l4d2_server/l4_image/img/template/m.svg +1 -0
  74. nonebot_plugin_l4d2_server/l4_image/img/template/normal.html +247 -0
  75. nonebot_plugin_l4d2_server/l4_image/img/template/vac.png +0 -0
  76. nonebot_plugin_l4d2_server/l4_image/img/template/vac_white.png +0 -0
  77. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/w.svg +1 -1
  78. nonebot_plugin_l4d2_server/l4_image/model.py +15 -0
  79. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/vtfs.py +4 -2
  80. nonebot_plugin_l4d2_server/l4_request/__init__.py +143 -0
  81. nonebot_plugin_l4d2_server/l4_request/draw_msg.py +83 -0
  82. nonebot_plugin_l4d2_server/utils/api/api.py +10 -0
  83. nonebot_plugin_l4d2_server/utils/api/models.py +137 -0
  84. nonebot_plugin_l4d2_server/utils/api/request.py +337 -0
  85. nonebot_plugin_l4d2_server/utils/database/models.py +18 -0
  86. nonebot_plugin_l4d2_server/{l4d2_utils → utils}/utils.py +60 -63
  87. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/METADATA +57 -66
  88. nonebot_plugin_l4d2_server-1.0.0a2.dist-info/RECORD +96 -0
  89. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/WHEEL +1 -1
  90. nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +0 -263
  91. nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +0 -231
  92. nonebot_plugin_l4d2_server/data/L4D2/image/template/m.svg +0 -1
  93. nonebot_plugin_l4d2_server/data/img/white.png +0 -0
  94. nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +0 -95
  95. nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +0 -54
  96. nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +0 -79
  97. nonebot_plugin_l4d2_server/l4d2_anne/server.py +0 -47
  98. nonebot_plugin_l4d2_server/l4d2_anne/startand.py +0 -17
  99. nonebot_plugin_l4d2_server/l4d2_anne/utils.py +0 -294
  100. nonebot_plugin_l4d2_server/l4d2_data/__init__.py +0 -105
  101. nonebot_plugin_l4d2_server/l4d2_data/config.py +0 -18
  102. nonebot_plugin_l4d2_server/l4d2_data/players.py +0 -100
  103. nonebot_plugin_l4d2_server/l4d2_data/serverip.py +0 -40
  104. nonebot_plugin_l4d2_server/l4d2_file/__init__.py +0 -222
  105. nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +0 -64
  106. nonebot_plugin_l4d2_server/l4d2_file/input_json.py +0 -77
  107. nonebot_plugin_l4d2_server/l4d2_file/remote.py +0 -86
  108. nonebot_plugin_l4d2_server/l4d2_file/utils.py +0 -104
  109. nonebot_plugin_l4d2_server/l4d2_image/__init__.py +0 -125
  110. nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +0 -18
  111. nonebot_plugin_l4d2_server/l4d2_image/images.py +0 -92
  112. nonebot_plugin_l4d2_server/l4d2_image/one.py +0 -44
  113. nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +0 -32
  114. nonebot_plugin_l4d2_server/l4d2_image/steam.py +0 -63
  115. nonebot_plugin_l4d2_server/l4d2_push/__init__.py +0 -225
  116. nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +0 -326
  117. nonebot_plugin_l4d2_server/l4d2_queries/himi.py +0 -113
  118. nonebot_plugin_l4d2_server/l4d2_queries/local_ip.py +0 -41
  119. nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +0 -370
  120. nonebot_plugin_l4d2_server/l4d2_queries/send_msg.py +0 -131
  121. nonebot_plugin_l4d2_server/l4d2_queries/utils.py +0 -212
  122. nonebot_plugin_l4d2_server/l4d2_server/__init__.py +0 -118
  123. nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
  124. nonebot_plugin_l4d2_server/l4d2_server/rcon.py +0 -53
  125. nonebot_plugin_l4d2_server/l4d2_server/workshop.py +0 -82
  126. nonebot_plugin_l4d2_server/l4d2_update/__init__.py +0 -137
  127. nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +0 -45
  128. nonebot_plugin_l4d2_server/l4d2_update/restart.py +0 -69
  129. nonebot_plugin_l4d2_server/l4d2_update/update.py +0 -53
  130. nonebot_plugin_l4d2_server/l4d2_utils/classcal.py +0 -53
  131. nonebot_plugin_l4d2_server/l4d2_utils/command.py +0 -23
  132. nonebot_plugin_l4d2_server/l4d2_utils/config.py +0 -201
  133. nonebot_plugin_l4d2_server/l4d2_utils/message.py +0 -59
  134. nonebot_plugin_l4d2_server/l4d2_utils/rule.py +0 -35
  135. nonebot_plugin_l4d2_server/l4d2_utils/seach.py +0 -43
  136. nonebot_plugin_l4d2_server/l4d2_utils/txt_to_img.py +0 -32
  137. nonebot_plugin_l4d2_server/l4d2_web/web.py +0 -277
  138. nonebot_plugin_l4d2_server/l4d2_web/webUI.py +0 -506
  139. nonebot_plugin_l4d2_server/l4d2_web/webUI_s.py +0 -94
  140. nonebot_plugin_l4d2_server-0.6.6.dist-info/RECORD +0 -70
  141. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/anne.html +0 -0
  142. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/group_ip.html +0 -0
  143. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/ip.html +0 -0
  144. /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/fingerprint.svg +0 -0
  145. /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/vue.css +0 -0
  146. /nonebot_plugin_l4d2_server/{l4d2_data/database.py → l4_request/utils.py} +0 -0
  147. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -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 # noqa:
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_: str = "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,17 @@
1
+ from pathlib import Path
2
+
3
+ from nonebot_plugin_l4d2_server.utils.api.models import AnnePlayer2
4
+ from PIL import Image, ImageFont
5
+
6
+ from ..config import config
7
+
8
+ font = ImageFont.truetype(config.l4_font)
9
+
10
+ anne_path = Path(__file__).parent / "img" / "anne"
11
+
12
+
13
+ async def anne_player_info(msg: AnnePlayer2):
14
+ back_img = Image.open(anne_path / "back1.jpg")
15
+ base_img = Image.new("RGBA", (back_img.size), (255, 255, 255, 50))
16
+ back_img.paste(base_img, (0, 0), base_img)
17
+ return msg
@@ -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, # noqa: FBT003
173
+ )
174
+ img = img.crop((0, 0, max_size, int(y + 80)))
175
+ return await convert_img(img)
@@ -3,15 +3,16 @@ import hashlib
3
3
  import io
4
4
  import os
5
5
  import random
6
+ from pathlib import Path
6
7
 
7
8
  import httpx
8
9
  from nonebot.log import logger
9
10
  from PIL import Image, ImageDraw
10
11
  from PIL.Image import Image as ImageS
11
12
 
12
- from ..l4d2_utils.config import PLAYERSDATA, TEXT_PATH
13
+ from ..config import DATAOUT
13
14
 
14
- # from .steam import web_player
15
+ TEXT_PATH = Path(__file__).parent
15
16
 
16
17
 
17
18
  async def download_url(url: str) -> bytes:
@@ -32,7 +33,7 @@ async def download_url(url: str) -> bytes:
32
33
  async def download_head(user_id: str) -> bytes:
33
34
  url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640"
34
35
  data = await download_url(url)
35
- if hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e":
36
+ if hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e": # noqa: S324
36
37
  url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=100"
37
38
  data = await download_url(url)
38
39
  return data
@@ -49,18 +50,18 @@ def square_to_circle(im: ImageS):
49
50
  return im
50
51
 
51
52
 
52
- async def get_head_by_user_id_and_save(user_id):
53
+ async def get_head_by_user_id_and_save(user_id: str):
53
54
  """qq转头像"""
54
55
  user_id = str(user_id)
55
56
 
56
- user_head_path = PLAYERSDATA / user_id / "HEAD.png"
57
+ user_head_path = DATAOUT / user_id / "HEAD.png"
57
58
  default_header_path = TEXT_PATH / "header"
58
59
  default_head_path = TEXT_PATH / "head"
59
60
  default_header = default_header_path / random.choice(
60
61
  os.listdir(default_header_path),
61
62
  )
62
63
  default_head = default_head_path / random.choice(os.listdir(default_head_path))
63
- ## im头像 im2头像框 im3合成
64
+ # im头像 im2头像框 im3合成
64
65
  if user_head_path.exists():
65
66
  logger.info("使用本地头像")
66
67
  im = Image.open(user_head_path).resize((280, 280)).convert("RGBA")
@@ -77,42 +78,17 @@ async def get_head_by_user_id_and_save(user_id):
77
78
  .resize((280, 280))
78
79
  .convert("RGBA")
79
80
  )
80
- if not (PLAYERSDATA / user_id).exists(): # 用户文件夹不存在
81
- (PLAYERSDATA / user_id).mkdir(parents=True, exist_ok=True)
81
+ if not (DATAOUT / user_id).exists(): # 用户文件夹不存在
82
+ (DATAOUT / user_id).mkdir(parents=True, exist_ok=True)
82
83
  im.save(user_head_path, "PNG")
83
84
  except Exception:
84
85
  logger.error("获取失败")
85
86
  return None
86
87
  im2 = Image.open(default_head).resize((450, 450)).convert("RGBA")
87
88
  im3 = Image.new("RGBA", im2.size, (255, 255, 255, 0))
88
- r, g, b, a1 = im.split()
89
- r, g, b, a2 = im2.split()
89
+ _, _, _, a1 = im.split()
90
+ _, _, _, a2 = im2.split()
90
91
  im = square_to_circle(im)
91
92
  im3.paste(im, (75, 75), mask=a1)
92
93
  im3.paste(im2, mask=a2)
93
94
  return im3
94
-
95
-
96
- # async def get_head_steam_and_save(user_id:str,urls):
97
- # """保存steam头像"""
98
- # user_head_path = PLAYERSDATA / str(user_id) / 'HEAD.png'
99
- # # default_head_path = TEXT_PATH / "template/player.jpg"
100
- # ## im头像 im2头像框 im3合成
101
- # if os.path.exists(user_head_path):
102
- # logger.info("使用本地头像")
103
- # im = Image.open(user_head_path).resize((280, 280)).convert("RGBA")
104
- # else:
105
- # # if user_id == "1145149191810":
106
- # # logger.info("使用默认头像")
107
- # # im = Image.open(default_head_path).resize((300, 300)).convert("RGBA")
108
- # # else:
109
- # try:
110
- # logger.info("正在下载头像")
111
- # image_bytes = await web_player(urls)
112
- # im = Image.open(io.BytesIO(image_bytes)).resize((280, 280)).convert("RGBA") # noqa: E501
113
- # if not os.path.exists(PLAYERSDATA / user_id):#用户文件夹不存在
114
- # os.makedirs(PLAYERSDATA / user_id)
115
- # im.save(user_head_path, "PNG")
116
- # except TimeoutError:
117
- # logger.error("获取失败")
118
- # return im