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.
- nonebot_plugin_l4d2_server/__init__.py +10 -93
- nonebot_plugin_l4d2_server/__main__.py +140 -0
- nonebot_plugin_l4d2_server/config.py +35 -0
- nonebot_plugin_l4d2_server/data/font/loli.ttf +0 -0
- nonebot_plugin_l4d2_server/l4_anne/__init__.py +124 -0
- nonebot_plugin_l4d2_server/l4_anne/ranne.py +18 -0
- nonebot_plugin_l4d2_server/l4_help/Help.json +102 -0
- nonebot_plugin_l4d2_server/l4_help/__init__.py +57 -0
- nonebot_plugin_l4d2_server/l4_help/draw.py +206 -0
- nonebot_plugin_l4d2_server/l4_help/icon//344/273/213/347/273/215.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//344/273/273/345/212/241.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//344/277/241/346/201/257.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/205/254/345/221/212.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/210/200/345/211/221.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/210/207/346/215/242.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/210/240/351/231/244.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/210/267/346/226/260.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/215/241/347/273/204.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/223/252/351/207/214.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/234/260/345/233/276.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/205/245.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/207/272.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//345/275/261.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/213/274/345/233/276.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/216/242/347/264/242.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/216/250/351/200/201.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/224/266/351/233/206.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/224/273/347/225/245.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/233/264/346/226/260.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/235/220/346/226/231.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/237/245/350/257/242.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/240/241/351/252/214.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/257/217/346/234/210.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/267/261/346/270/212.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/267/273/345/212/240.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//346/270/205/351/231/244.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//347/212/266/346/200/201.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//347/255/276/345/210/260.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//347/273/221/345/256/232.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//350/241/250.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//350/241/250/346/203/205.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//350/247/222/350/211/262.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//350/256/260/345/275/225.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//351/205/215/347/275/256.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/icon//351/207/215/345/220/257.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/texture2d/badge.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/texture2d/banner.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/texture2d/bg.jpg +0 -0
- nonebot_plugin_l4d2_server/l4_help/texture2d/button.png +0 -0
- nonebot_plugin_l4d2_server/l4_help/texture2d/icon.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/__init__.py +16 -0
- nonebot_plugin_l4d2_server/l4_image/anne_pil.py +17 -0
- nonebot_plugin_l4d2_server/l4_image/convert.py +175 -0
- nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/download.py +11 -35
- nonebot_plugin_l4d2_server/l4_image/html_img.py +105 -0
- nonebot_plugin_l4d2_server/l4_image/image_tools.py +468 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/back.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/anne/back1.jpg +0 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/head/head.png +0 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/logo.png +0 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/player1.jpg +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.html +299 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/HYPixel11pxU-2.ttf +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.html +341 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.html +355 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/Tutumianhuatang-Bold-2.ttf +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/bilibili.svg +1 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/github.svg +1 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/l.svg +0 -1
- nonebot_plugin_l4d2_server/l4_image/img/template/m.svg +1 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/normal.html +247 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/vac.png +0 -0
- nonebot_plugin_l4d2_server/l4_image/img/template/vac_white.png +0 -0
- nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/w.svg +1 -1
- nonebot_plugin_l4d2_server/l4_image/model.py +15 -0
- nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/vtfs.py +4 -2
- nonebot_plugin_l4d2_server/l4_request/__init__.py +143 -0
- nonebot_plugin_l4d2_server/l4_request/draw_msg.py +83 -0
- nonebot_plugin_l4d2_server/utils/api/api.py +10 -0
- nonebot_plugin_l4d2_server/utils/api/models.py +137 -0
- nonebot_plugin_l4d2_server/utils/api/request.py +337 -0
- nonebot_plugin_l4d2_server/utils/database/models.py +18 -0
- nonebot_plugin_l4d2_server/{l4d2_utils → utils}/utils.py +60 -63
- {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/METADATA +57 -66
- nonebot_plugin_l4d2_server-1.0.0a2.dist-info/RECORD +96 -0
- {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/WHEEL +1 -1
- nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +0 -263
- nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +0 -231
- nonebot_plugin_l4d2_server/data/L4D2/image/template/m.svg +0 -1
- nonebot_plugin_l4d2_server/data/img/white.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +0 -95
- nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +0 -54
- nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +0 -79
- nonebot_plugin_l4d2_server/l4d2_anne/server.py +0 -47
- nonebot_plugin_l4d2_server/l4d2_anne/startand.py +0 -17
- nonebot_plugin_l4d2_server/l4d2_anne/utils.py +0 -294
- nonebot_plugin_l4d2_server/l4d2_data/__init__.py +0 -105
- nonebot_plugin_l4d2_server/l4d2_data/config.py +0 -18
- nonebot_plugin_l4d2_server/l4d2_data/players.py +0 -100
- nonebot_plugin_l4d2_server/l4d2_data/serverip.py +0 -40
- nonebot_plugin_l4d2_server/l4d2_file/__init__.py +0 -222
- nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +0 -64
- nonebot_plugin_l4d2_server/l4d2_file/input_json.py +0 -77
- nonebot_plugin_l4d2_server/l4d2_file/remote.py +0 -86
- nonebot_plugin_l4d2_server/l4d2_file/utils.py +0 -104
- nonebot_plugin_l4d2_server/l4d2_image/__init__.py +0 -125
- nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +0 -18
- nonebot_plugin_l4d2_server/l4d2_image/images.py +0 -92
- nonebot_plugin_l4d2_server/l4d2_image/one.py +0 -44
- nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +0 -32
- nonebot_plugin_l4d2_server/l4d2_image/steam.py +0 -63
- nonebot_plugin_l4d2_server/l4d2_push/__init__.py +0 -225
- nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +0 -326
- nonebot_plugin_l4d2_server/l4d2_queries/himi.py +0 -113
- nonebot_plugin_l4d2_server/l4d2_queries/local_ip.py +0 -41
- nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +0 -370
- nonebot_plugin_l4d2_server/l4d2_queries/send_msg.py +0 -131
- nonebot_plugin_l4d2_server/l4d2_queries/utils.py +0 -212
- nonebot_plugin_l4d2_server/l4d2_server/__init__.py +0 -118
- nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
- nonebot_plugin_l4d2_server/l4d2_server/rcon.py +0 -53
- nonebot_plugin_l4d2_server/l4d2_server/workshop.py +0 -82
- nonebot_plugin_l4d2_server/l4d2_update/__init__.py +0 -137
- nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +0 -45
- nonebot_plugin_l4d2_server/l4d2_update/restart.py +0 -69
- nonebot_plugin_l4d2_server/l4d2_update/update.py +0 -53
- nonebot_plugin_l4d2_server/l4d2_utils/classcal.py +0 -53
- nonebot_plugin_l4d2_server/l4d2_utils/command.py +0 -23
- nonebot_plugin_l4d2_server/l4d2_utils/config.py +0 -201
- nonebot_plugin_l4d2_server/l4d2_utils/message.py +0 -59
- nonebot_plugin_l4d2_server/l4d2_utils/rule.py +0 -35
- nonebot_plugin_l4d2_server/l4d2_utils/seach.py +0 -43
- nonebot_plugin_l4d2_server/l4d2_utils/txt_to_img.py +0 -32
- nonebot_plugin_l4d2_server/l4d2_web/web.py +0 -277
- nonebot_plugin_l4d2_server/l4d2_web/webUI.py +0 -506
- nonebot_plugin_l4d2_server/l4d2_web/webUI_s.py +0 -94
- nonebot_plugin_l4d2_server-0.6.6.dist-info/RECORD +0 -70
- /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/anne.html +0 -0
- /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/group_ip.html +0 -0
- /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/ip.html +0 -0
- /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/fingerprint.svg +0 -0
- /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/vue.css +0 -0
- /nonebot_plugin_l4d2_server/{l4d2_data/database.py → l4_request/utils.py} +0 -0
- {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)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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 ..
|
13
|
+
from ..config import DATAOUT
|
13
14
|
|
14
|
-
|
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 =
|
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
|
-
|
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 (
|
81
|
-
(
|
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
|
-
|
89
|
-
|
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
|