nonebot-plugin-l4d2-server 0.5.1__py3-none-any.whl → 0.5.3__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.
- LICENSE +674 -674
- README.md +373 -359
- nonebot_plugin_l4d2_server/__init__.py +13 -13
- nonebot_plugin_l4d2_server/command.py +232 -232
- nonebot_plugin_l4d2_server/config.py +209 -210
- nonebot_plugin_l4d2_server/data/L4D2/image/template/anne.html +60 -60
- nonebot_plugin_l4d2_server/data/L4D2/image/template/fingerprint.svg +15 -15
- nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +233 -233
- nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +231 -231
- nonebot_plugin_l4d2_server/data/L4D2/image/template/ip.html +48 -48
- nonebot_plugin_l4d2_server/data/L4D2/image/template/l.svg +9 -9
- nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +251 -251
- nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +51 -51
- nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +75 -75
- nonebot_plugin_l4d2_server/l4d2_anne/server.py +65 -65
- nonebot_plugin_l4d2_server/l4d2_anne/startand.py +17 -17
- nonebot_plugin_l4d2_server/l4d2_data/__init__.py +91 -91
- nonebot_plugin_l4d2_server/l4d2_data/config.py +17 -17
- nonebot_plugin_l4d2_server/l4d2_data/database.py +0 -0
- nonebot_plugin_l4d2_server/l4d2_data/players.py +87 -87
- nonebot_plugin_l4d2_server/l4d2_data/serverip.py +32 -32
- nonebot_plugin_l4d2_server/l4d2_file/__init__.py +122 -122
- nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +56 -56
- nonebot_plugin_l4d2_server/l4d2_file/remote.py +63 -63
- nonebot_plugin_l4d2_server/l4d2_image/__init__.py +103 -103
- nonebot_plugin_l4d2_server/l4d2_image/download.py +101 -101
- nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +32 -32
- nonebot_plugin_l4d2_server/l4d2_image/image.py +292 -0
- nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +32 -32
- nonebot_plugin_l4d2_server/l4d2_image/steam.py +83 -83
- nonebot_plugin_l4d2_server/l4d2_image/vtfs.py +40 -40
- nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +114 -114
- nonebot_plugin_l4d2_server/l4d2_queries/api.py +43 -43
- nonebot_plugin_l4d2_server/l4d2_queries/ohter.py +35 -35
- nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +288 -288
- nonebot_plugin_l4d2_server/l4d2_server/__init__.py +61 -61
- nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
- nonebot_plugin_l4d2_server/l4d2_server/rcon.py +28 -28
- nonebot_plugin_l4d2_server/l4d2_server/workshop.py +50 -50
- nonebot_plugin_l4d2_server/l4d2_update/__init__.py +143 -0
- nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +41 -0
- nonebot_plugin_l4d2_server/l4d2_update/restart.py +67 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/art.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/bento.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/bug.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/feat.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/log_title.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/other.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/texture2d/zap.png +0 -0
- nonebot_plugin_l4d2_server/l4d2_update/update.py +65 -0
- nonebot_plugin_l4d2_server/l4d2_web/web.py +234 -252
- nonebot_plugin_l4d2_server/l4d2_web/webUI.py +241 -245
- nonebot_plugin_l4d2_server/message.py +58 -58
- nonebot_plugin_l4d2_server/rule.py +15 -0
- nonebot_plugin_l4d2_server/seach.py +33 -33
- nonebot_plugin_l4d2_server/txt_to_img.py +64 -64
- nonebot_plugin_l4d2_server/utils.py +297 -272
- {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/LICENSE +674 -674
- {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/METADATA +19 -4
- nonebot_plugin_l4d2_server-0.5.3.dist-info/RECORD +68 -0
- {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/WHEEL +1 -1
- nonebot_plugin_l4d2_server/chrome.py +0 -45
- nonebot_plugin_l4d2_server-0.5.1.dist-info/RECORD +0 -54
@@ -0,0 +1,292 @@
|
|
1
|
+
from io import BytesIO
|
2
|
+
from pathlib import Path
|
3
|
+
from base64 import b64encode
|
4
|
+
from typing import Union, overload
|
5
|
+
from typing import Union,Tuple,Optional
|
6
|
+
import math
|
7
|
+
import random
|
8
|
+
|
9
|
+
import aiofiles
|
10
|
+
from PIL import Image
|
11
|
+
from httpx import get
|
12
|
+
import sys
|
13
|
+
from pathlib import Path
|
14
|
+
|
15
|
+
MAIN_PATH = Path() / 'data' / 'GenshinUID'
|
16
|
+
sys.path.append(str(MAIN_PATH))
|
17
|
+
CONFIG_PATH = MAIN_PATH / 'config.json'
|
18
|
+
RESOURCE_PATH = MAIN_PATH / 'resource'
|
19
|
+
WIKI_PATH = MAIN_PATH / 'wiki'
|
20
|
+
CU_BG_PATH = MAIN_PATH / 'bg'
|
21
|
+
CU_CHBG_PATH = MAIN_PATH / 'chbg'
|
22
|
+
WEAPON_PATH = RESOURCE_PATH / 'weapon'
|
23
|
+
GACHA_IMG_PATH = RESOURCE_PATH / 'gacha_img'
|
24
|
+
CHAR_PATH = RESOURCE_PATH / 'chars'
|
25
|
+
CHAR_STAND_PATH = RESOURCE_PATH / 'char_stand'
|
26
|
+
CHAR_SIDE_PATH = RESOURCE_PATH / 'char_side'
|
27
|
+
CHAR_NAMECARD_PATH = RESOURCE_PATH / 'char_namecard'
|
28
|
+
REL_PATH = RESOURCE_PATH / 'reliquaries'
|
29
|
+
ICON_PATH = RESOURCE_PATH / 'icon'
|
30
|
+
TEMP_PATH = RESOURCE_PATH / 'temp'
|
31
|
+
CARD_PATH = RESOURCE_PATH / 'card'
|
32
|
+
GUIDE_PATH = WIKI_PATH / 'guide'
|
33
|
+
TEXT2D_PATH = Path(__file__).parents[2] / 'resource' / 'texture2d'
|
34
|
+
|
35
|
+
PLAYER_PATH = MAIN_PATH / 'players'
|
36
|
+
|
37
|
+
|
38
|
+
TEXT2D_PATH = Path(__file__).parents[2] / 'resource' / 'texture2d'
|
39
|
+
FETTER_PATH = TEXT2D_PATH / 'fetter'
|
40
|
+
TALENT_PATH = TEXT2D_PATH / 'talent'
|
41
|
+
WEAPON_BG_PATH = TEXT2D_PATH / 'weapon'
|
42
|
+
WEAPON_AFFIX_PATH = TEXT2D_PATH / 'weapon_affix'
|
43
|
+
LEVEL_PATH = TEXT2D_PATH / 'level'
|
44
|
+
|
45
|
+
BG_PATH = Path(__file__).parent / 'bg'
|
46
|
+
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
47
|
+
ring_pic = Image.open(TEXT_PATH / 'ring.png')
|
48
|
+
mask_pic = Image.open(TEXT_PATH / 'mask.png')
|
49
|
+
NM_BG_PATH = BG_PATH / 'nm_bg'
|
50
|
+
SP_BG_PATH = BG_PATH / 'sp_bg'@overload
|
51
|
+
|
52
|
+
if list(CU_BG_PATH.iterdir()) != []:
|
53
|
+
bg_path = CU_BG_PATH
|
54
|
+
else:
|
55
|
+
bg_path = NM_BG_PATH
|
56
|
+
|
57
|
+
async def convert_img(img: Image.Image, is_base64: bool = False) -> bytes:
|
58
|
+
...
|
59
|
+
|
60
|
+
|
61
|
+
@overload
|
62
|
+
async def convert_img(img: Image.Image, is_base64: bool = True) -> str:
|
63
|
+
...
|
64
|
+
|
65
|
+
|
66
|
+
@overload
|
67
|
+
async def convert_img(img: bytes, is_base64: bool = False) -> str:
|
68
|
+
...
|
69
|
+
|
70
|
+
|
71
|
+
@overload
|
72
|
+
async def convert_img(img: Path, is_base64: bool = False) -> str:
|
73
|
+
...
|
74
|
+
|
75
|
+
|
76
|
+
async def convert_img(
|
77
|
+
img: Union[Image.Image, str, Path, bytes], is_base64: bool = False
|
78
|
+
):
|
79
|
+
"""
|
80
|
+
:说明:
|
81
|
+
将PIL.Image对象转换为bytes或者base64格式。
|
82
|
+
:参数:
|
83
|
+
* img (Image): 图片。
|
84
|
+
* is_base64 (bool): 是否转换为base64格式, 不填默认转为bytes。
|
85
|
+
:返回:
|
86
|
+
* res: bytes对象或base64编码图片。
|
87
|
+
"""
|
88
|
+
if isinstance(img, Image.Image):
|
89
|
+
img = img.convert('RGB')
|
90
|
+
result_buffer = BytesIO()
|
91
|
+
img.save(result_buffer, format='PNG', quality=80, subsampling=0)
|
92
|
+
res = result_buffer.getvalue()
|
93
|
+
if is_base64:
|
94
|
+
res = 'base64://' + b64encode(res).decode()
|
95
|
+
return res
|
96
|
+
elif isinstance(img, bytes):
|
97
|
+
pass
|
98
|
+
else:
|
99
|
+
async with aiofiles.open(img, 'rb') as fp:
|
100
|
+
img = await fp.read()
|
101
|
+
return f'[CQ:image,file=base64://{b64encode(img).decode()}]'
|
102
|
+
|
103
|
+
|
104
|
+
async def get_color_bg(
|
105
|
+
based_w: int, based_h: int, bg: Optional[str] = None
|
106
|
+
) -> Image.Image:
|
107
|
+
image = ''
|
108
|
+
if bg:
|
109
|
+
path = SP_BG_PATH / f'{bg}.jpg'
|
110
|
+
if path.exists():
|
111
|
+
image = Image.open(path)
|
112
|
+
CI_img = CustomizeImage(image, based_w, based_h)
|
113
|
+
img = CI_img.bg_img
|
114
|
+
color = CI_img.bg_color
|
115
|
+
color_mask = Image.new('RGBA', (based_w, based_h), color)
|
116
|
+
enka_mask = Image.open(TEXT2D_PATH / 'mask.png').resize((based_w, based_h))
|
117
|
+
img.paste(color_mask, (0, 0), enka_mask)
|
118
|
+
return img
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
class CustomizeImage:
|
123
|
+
def __init__(
|
124
|
+
self, image: Union[str, Image.Image], based_w: int, based_h: int
|
125
|
+
) -> None:
|
126
|
+
|
127
|
+
self.bg_img = self.get_image(image, based_w, based_h)
|
128
|
+
self.bg_color = self.get_bg_color(self.bg_img, is_light=True)
|
129
|
+
self.text_color = self.get_text_color(self.bg_color)
|
130
|
+
self.highlight_color = self.get_highlight_color(self.bg_color)
|
131
|
+
self.char_color = self.get_char_color(self.bg_color)
|
132
|
+
self.bg_detail_color = self.get_bg_detail_color(self.bg_color)
|
133
|
+
self.char_high_color = self.get_char_high_color(self.bg_color)
|
134
|
+
|
135
|
+
@staticmethod
|
136
|
+
def get_image(
|
137
|
+
image: Union[str, Image.Image], based_w: int, based_h: int
|
138
|
+
) -> Image.Image:
|
139
|
+
# 获取背景图片
|
140
|
+
if isinstance(image, Image.Image):
|
141
|
+
edit_bg = image
|
142
|
+
elif image:
|
143
|
+
edit_bg = Image.open(BytesIO(get(image).content)).convert('RGBA')
|
144
|
+
else:
|
145
|
+
path = random.choice(list(bg_path.iterdir()))
|
146
|
+
edit_bg = Image.open(path).convert('RGBA')
|
147
|
+
|
148
|
+
# 确定图片的长宽
|
149
|
+
bg_img = crop_center_img(edit_bg, based_w, based_h)
|
150
|
+
return bg_img
|
151
|
+
|
152
|
+
@staticmethod
|
153
|
+
def get_dominant_color(pil_img: Image.Image) -> Tuple[int, int, int]:
|
154
|
+
img = pil_img.copy()
|
155
|
+
img = img.convert("RGBA")
|
156
|
+
img = img.resize((1, 1), resample=0)
|
157
|
+
dominant_color = img.getpixel((0, 0))
|
158
|
+
return dominant_color
|
159
|
+
|
160
|
+
@staticmethod
|
161
|
+
def get_bg_color(
|
162
|
+
edit_bg: Image.Image, is_light: Optional[bool] = False
|
163
|
+
) -> Tuple[int, int, int]:
|
164
|
+
# 获取背景主色
|
165
|
+
color = 8
|
166
|
+
q = edit_bg.quantize(colors=color, method=2)
|
167
|
+
bg_color = (0, 0, 0)
|
168
|
+
if is_light:
|
169
|
+
based_light = 195
|
170
|
+
else:
|
171
|
+
based_light = 120
|
172
|
+
temp = 9999
|
173
|
+
for i in range(color):
|
174
|
+
bg = tuple(
|
175
|
+
q.getpalette()[ # type:ignore
|
176
|
+
i * 3 : (i * 3) + 3 # noqa:E203
|
177
|
+
]
|
178
|
+
)
|
179
|
+
light_value = bg[0] * 0.3 + bg[1] * 0.6 + bg[2] * 0.1
|
180
|
+
if abs(light_value - based_light) < temp:
|
181
|
+
bg_color = bg
|
182
|
+
temp = abs(light_value - based_light)
|
183
|
+
return bg_color
|
184
|
+
|
185
|
+
@staticmethod
|
186
|
+
def get_text_color(bg_color: Tuple[int, int, int]) -> Tuple[int, int, int]:
|
187
|
+
# 通过背景主色(bg_color)确定文字主色
|
188
|
+
r = 125
|
189
|
+
if max(*bg_color) > 255 - r:
|
190
|
+
r *= -1
|
191
|
+
text_color = (
|
192
|
+
math.floor(bg_color[0] + r if bg_color[0] + r <= 255 else 255),
|
193
|
+
math.floor(bg_color[1] + r if bg_color[1] + r <= 255 else 255),
|
194
|
+
math.floor(bg_color[2] + r if bg_color[2] + r <= 255 else 255),
|
195
|
+
)
|
196
|
+
return text_color
|
197
|
+
|
198
|
+
@staticmethod
|
199
|
+
def get_char_color(bg_color: Tuple[int, int, int]) -> Tuple[int, int, int]:
|
200
|
+
r = 140
|
201
|
+
if max(*bg_color) > 255 - r:
|
202
|
+
r *= -1
|
203
|
+
char_color = (
|
204
|
+
math.floor(bg_color[0] + 5 if bg_color[0] + r <= 255 else 255),
|
205
|
+
math.floor(bg_color[1] + 5 if bg_color[1] + r <= 255 else 255),
|
206
|
+
math.floor(bg_color[2] + 5 if bg_color[2] + r <= 255 else 255),
|
207
|
+
)
|
208
|
+
return char_color
|
209
|
+
|
210
|
+
@staticmethod
|
211
|
+
def get_char_high_color(
|
212
|
+
bg_color: Tuple[int, int, int]
|
213
|
+
) -> Tuple[int, int, int]:
|
214
|
+
r = 140
|
215
|
+
d = 20
|
216
|
+
if max(*bg_color) > 255 - r:
|
217
|
+
r *= -1
|
218
|
+
char_color = (
|
219
|
+
math.floor(bg_color[0] + d if bg_color[0] + r <= 255 else 255),
|
220
|
+
math.floor(bg_color[1] + d if bg_color[1] + r <= 255 else 255),
|
221
|
+
math.floor(bg_color[2] + d if bg_color[2] + r <= 255 else 255),
|
222
|
+
)
|
223
|
+
return char_color
|
224
|
+
|
225
|
+
@staticmethod
|
226
|
+
def get_bg_detail_color(
|
227
|
+
bg_color: Tuple[int, int, int]
|
228
|
+
) -> Tuple[int, int, int]:
|
229
|
+
r = 140
|
230
|
+
if max(*bg_color) > 255 - r:
|
231
|
+
r *= -1
|
232
|
+
bg_detail_color = (
|
233
|
+
math.floor(bg_color[0] - 20 if bg_color[0] + r <= 255 else 255),
|
234
|
+
math.floor(bg_color[1] - 20 if bg_color[1] + r <= 255 else 255),
|
235
|
+
math.floor(bg_color[2] - 20 if bg_color[2] + r <= 255 else 255),
|
236
|
+
)
|
237
|
+
return bg_detail_color
|
238
|
+
|
239
|
+
@staticmethod
|
240
|
+
def get_highlight_color(
|
241
|
+
color: Tuple[int, int, int]
|
242
|
+
) -> Tuple[int, int, int]:
|
243
|
+
red_color = color[0]
|
244
|
+
green_color = color[1]
|
245
|
+
blue_color = color[2]
|
246
|
+
|
247
|
+
highlight_color = {
|
248
|
+
'red': red_color - 127 if red_color > 127 else 127,
|
249
|
+
'green': green_color - 127 if green_color > 127 else 127,
|
250
|
+
'blue': blue_color - 127 if blue_color > 127 else 127,
|
251
|
+
}
|
252
|
+
|
253
|
+
max_color = max(highlight_color.values())
|
254
|
+
|
255
|
+
name = ''
|
256
|
+
for _highlight_color in highlight_color:
|
257
|
+
if highlight_color[_highlight_color] == max_color:
|
258
|
+
name = str(_highlight_color)
|
259
|
+
|
260
|
+
if name == 'red':
|
261
|
+
return red_color, highlight_color['green'], highlight_color['blue']
|
262
|
+
elif name == 'green':
|
263
|
+
return highlight_color['red'], green_color, highlight_color['blue']
|
264
|
+
elif name == 'blue':
|
265
|
+
return highlight_color['red'], highlight_color['green'], blue_color
|
266
|
+
else:
|
267
|
+
return 0, 0, 0 # Error
|
268
|
+
|
269
|
+
|
270
|
+
def crop_center_img(
|
271
|
+
img: Image.Image, based_w: int, based_h: int
|
272
|
+
) -> Image.Image:
|
273
|
+
# 确定图片的长宽
|
274
|
+
based_scale = '%.3f' % (based_w / based_h)
|
275
|
+
w, h = img.size
|
276
|
+
scale_f = '%.3f' % (w / h)
|
277
|
+
new_w = math.ceil(based_h * float(scale_f))
|
278
|
+
new_h = math.ceil(based_w / float(scale_f))
|
279
|
+
if scale_f > based_scale:
|
280
|
+
resize_img = img.resize((new_w, based_h), Image.ANTIALIAS)
|
281
|
+
x1 = int(new_w / 2 - based_w / 2)
|
282
|
+
y1 = 0
|
283
|
+
x2 = int(new_w / 2 + based_w / 2)
|
284
|
+
y2 = based_h
|
285
|
+
else:
|
286
|
+
resize_img = img.resize((based_w, new_h), Image.ANTIALIAS)
|
287
|
+
x1 = 0
|
288
|
+
y1 = int(new_h / 2 - based_h / 2)
|
289
|
+
x2 = based_w
|
290
|
+
y2 = int(new_h / 2 + based_h / 2)
|
291
|
+
crop_img = resize_img.crop((x1, y1, x2, y2))
|
292
|
+
return crop_img
|
@@ -1,32 +1,32 @@
|
|
1
|
-
from io import BytesIO
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Union
|
4
|
-
from base64 import b64encode
|
5
|
-
|
6
|
-
from PIL import Image
|
7
|
-
|
8
|
-
|
9
|
-
async def convert_img(
|
10
|
-
img: Union[Image.Image, str, Path, bytes], is_base64: bool = False
|
11
|
-
):
|
12
|
-
"""
|
13
|
-
:说明:
|
14
|
-
将PIL.Image对象转换为bytes或者base64格式。
|
15
|
-
:参数:
|
16
|
-
* img (Image): 图片。
|
17
|
-
* is_base64 (bool): 是否转换为base64格式, 不填默认转为bytes。
|
18
|
-
:返回:
|
19
|
-
* res: bytes对象或base64编码图片。
|
20
|
-
"""
|
21
|
-
if isinstance(img, Image.Image):
|
22
|
-
img = img.convert('RGBA')
|
23
|
-
result_buffer = BytesIO()
|
24
|
-
img.save(result_buffer, format='PNG', quality=80, subsampling=0)
|
25
|
-
res = result_buffer.getvalue()
|
26
|
-
if is_base64:
|
27
|
-
res = b64encode(res).decode()
|
28
|
-
return res
|
29
|
-
elif isinstance(img, bytes):
|
30
|
-
return b64encode(img).decode()
|
31
|
-
else:
|
32
|
-
return f'[CQ:image,file=file:///{str(img)}]'
|
1
|
+
from io import BytesIO
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Union
|
4
|
+
from base64 import b64encode
|
5
|
+
|
6
|
+
from PIL import Image
|
7
|
+
|
8
|
+
|
9
|
+
async def convert_img(
|
10
|
+
img: Union[Image.Image, str, Path, bytes], is_base64: bool = False
|
11
|
+
):
|
12
|
+
"""
|
13
|
+
:说明:
|
14
|
+
将PIL.Image对象转换为bytes或者base64格式。
|
15
|
+
:参数:
|
16
|
+
* img (Image): 图片。
|
17
|
+
* is_base64 (bool): 是否转换为base64格式, 不填默认转为bytes。
|
18
|
+
:返回:
|
19
|
+
* res: bytes对象或base64编码图片。
|
20
|
+
"""
|
21
|
+
if isinstance(img, Image.Image):
|
22
|
+
img = img.convert('RGBA')
|
23
|
+
result_buffer = BytesIO()
|
24
|
+
img.save(result_buffer, format='PNG', quality=80, subsampling=0)
|
25
|
+
res = result_buffer.getvalue()
|
26
|
+
if is_base64:
|
27
|
+
res = b64encode(res).decode()
|
28
|
+
return res
|
29
|
+
elif isinstance(img, bytes):
|
30
|
+
return b64encode(img).decode()
|
31
|
+
else:
|
32
|
+
return f'[CQ:image,file=file:///{str(img)}]'
|
@@ -1,83 +1,83 @@
|
|
1
|
-
# from PIL import Image
|
2
|
-
import httpx
|
3
|
-
import aiohttp
|
4
|
-
# from bs4 import BeautifulSoup
|
5
|
-
from urllib.parse import unquote
|
6
|
-
|
7
|
-
|
8
|
-
# async def web_player(url) -> Image :
|
9
|
-
# """steam个人资料获取头像"""
|
10
|
-
# data = BeautifulSoup(await url_for_byte(url), 'html.parser')
|
11
|
-
# print(data)
|
12
|
-
# head = data.find("div", class_="playerAvatarAutoSizeInner")
|
13
|
-
# img_elements = head.find_all("img")
|
14
|
-
# if len(img_elements)== 1:
|
15
|
-
# for img_element in img_elements:
|
16
|
-
# head = await url_for_byte(img_element["src"])
|
17
|
-
# im = Image.open(io.BytesIO(head)).resize((225, 225)).convert("RGBA")
|
18
|
-
# if len(img_elements) == 2:
|
19
|
-
# head,headd = img_elements
|
20
|
-
# head = await url_for_byte(img_element["src"])
|
21
|
-
# head = await url_for_byte(img_element["src"])
|
22
|
-
# # 下面是边框,不一定有
|
23
|
-
# try:
|
24
|
-
# headd = data.select("html.responsive body.flat_page.profile_page.has_profile_background.GhostTheme.responsive_page div.responsive_page_frame.with_header div.responsive_page_content div#responsive_page_template_content.responsive_page_template_content div.no_header.profile_page.has_profile_background div.profile_header_bg div.profile_header_bg_texture div.profile_header div.profile_header_content div.playerAvatar.profile_header_size.in-game div.playerAvatarAutoSizeInner div.profile_avatar_frame img")
|
25
|
-
# im2 = Image.open(io.BytesIO(headd)).resize((185, 185)).convert("RGBA")
|
26
|
-
# r, g, b, a2 = im2.split()
|
27
|
-
# # im.paste(im2,(20,20),mask=a2)
|
28
|
-
# except IndexError:
|
29
|
-
# pass
|
30
|
-
# return im
|
31
|
-
|
32
|
-
# async def url_for_byte(url):
|
33
|
-
# """所有代理_url终将绳之以法"""
|
34
|
-
# if not l4_proxies:
|
35
|
-
# print("代理不存在")
|
36
|
-
# data = await url_to_byte(url)
|
37
|
-
# headers = {
|
38
|
-
# 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
39
|
-
# }
|
40
|
-
# data = httpx.get(url,headers=headers,proxies=l4_proxies,timeout=60,verify=False).content
|
41
|
-
# return data
|
42
|
-
async def url_to_byte(url:str,filename:str =''):
|
43
|
-
"""获取URL数据的字节流"""
|
44
|
-
headers = {
|
45
|
-
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
46
|
-
}
|
47
|
-
async with aiohttp.ClientSession() as session:
|
48
|
-
async with session.get(url, headers=headers, timeout=600) as response:
|
49
|
-
if response.status == 200:
|
50
|
-
return await response.read()
|
51
|
-
else:
|
52
|
-
return None
|
53
|
-
|
54
|
-
async def url_to_byte_name(url:str,filename:str =''):
|
55
|
-
"""获取URL数据的字节流"""
|
56
|
-
headers = {
|
57
|
-
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
58
|
-
}
|
59
|
-
if filename == "htp":
|
60
|
-
response = httpx.get(url,headers=headers,timeout=600)
|
61
|
-
content_disposition:str = response.headers.get("Content-Disposition")
|
62
|
-
if not content_disposition:
|
63
|
-
return None
|
64
|
-
elif "''" in content_disposition:
|
65
|
-
file_name = content_disposition.split("''")[-1]
|
66
|
-
else:
|
67
|
-
file_name = content_disposition
|
68
|
-
file_name = unquote(file_name)
|
69
|
-
return [response.read(),file_name]
|
70
|
-
else:
|
71
|
-
async with aiohttp.ClientSession() as session:
|
72
|
-
async with session.get(url, headers=headers, timeout=600) as response:
|
73
|
-
content_disposition:str = response.headers.get("Content-Disposition")
|
74
|
-
if "''" in content_disposition:
|
75
|
-
file_name = content_disposition.split("''")[-1]
|
76
|
-
else:
|
77
|
-
file_name = content_disposition
|
78
|
-
file_name = unquote(file_name)
|
79
|
-
if response.status == 200:
|
80
|
-
return [await response.read(),file_name]
|
81
|
-
else:
|
82
|
-
return None
|
83
|
-
|
1
|
+
# from PIL import Image
|
2
|
+
import httpx
|
3
|
+
import aiohttp
|
4
|
+
# from bs4 import BeautifulSoup
|
5
|
+
from urllib.parse import unquote
|
6
|
+
|
7
|
+
|
8
|
+
# async def web_player(url) -> Image :
|
9
|
+
# """steam个人资料获取头像"""
|
10
|
+
# data = BeautifulSoup(await url_for_byte(url), 'html.parser')
|
11
|
+
# print(data)
|
12
|
+
# head = data.find("div", class_="playerAvatarAutoSizeInner")
|
13
|
+
# img_elements = head.find_all("img")
|
14
|
+
# if len(img_elements)== 1:
|
15
|
+
# for img_element in img_elements:
|
16
|
+
# head = await url_for_byte(img_element["src"])
|
17
|
+
# im = Image.open(io.BytesIO(head)).resize((225, 225)).convert("RGBA")
|
18
|
+
# if len(img_elements) == 2:
|
19
|
+
# head,headd = img_elements
|
20
|
+
# head = await url_for_byte(img_element["src"])
|
21
|
+
# head = await url_for_byte(img_element["src"])
|
22
|
+
# # 下面是边框,不一定有
|
23
|
+
# try:
|
24
|
+
# headd = data.select("html.responsive body.flat_page.profile_page.has_profile_background.GhostTheme.responsive_page div.responsive_page_frame.with_header div.responsive_page_content div#responsive_page_template_content.responsive_page_template_content div.no_header.profile_page.has_profile_background div.profile_header_bg div.profile_header_bg_texture div.profile_header div.profile_header_content div.playerAvatar.profile_header_size.in-game div.playerAvatarAutoSizeInner div.profile_avatar_frame img")
|
25
|
+
# im2 = Image.open(io.BytesIO(headd)).resize((185, 185)).convert("RGBA")
|
26
|
+
# r, g, b, a2 = im2.split()
|
27
|
+
# # im.paste(im2,(20,20),mask=a2)
|
28
|
+
# except IndexError:
|
29
|
+
# pass
|
30
|
+
# return im
|
31
|
+
|
32
|
+
# async def url_for_byte(url):
|
33
|
+
# """所有代理_url终将绳之以法"""
|
34
|
+
# if not l4_proxies:
|
35
|
+
# print("代理不存在")
|
36
|
+
# data = await url_to_byte(url)
|
37
|
+
# headers = {
|
38
|
+
# 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
39
|
+
# }
|
40
|
+
# data = httpx.get(url,headers=headers,proxies=l4_proxies,timeout=60,verify=False).content
|
41
|
+
# return data
|
42
|
+
async def url_to_byte(url:str,filename:str =''):
|
43
|
+
"""获取URL数据的字节流"""
|
44
|
+
headers = {
|
45
|
+
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
46
|
+
}
|
47
|
+
async with aiohttp.ClientSession() as session:
|
48
|
+
async with session.get(url, headers=headers, timeout=600) as response:
|
49
|
+
if response.status == 200:
|
50
|
+
return await response.read()
|
51
|
+
else:
|
52
|
+
return None
|
53
|
+
|
54
|
+
async def url_to_byte_name(url:str,filename:str =''):
|
55
|
+
"""获取URL数据的字节流"""
|
56
|
+
headers = {
|
57
|
+
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
|
58
|
+
}
|
59
|
+
if filename == "htp":
|
60
|
+
response = httpx.get(url,headers=headers,timeout=600)
|
61
|
+
content_disposition:str = response.headers.get("Content-Disposition")
|
62
|
+
if not content_disposition:
|
63
|
+
return None
|
64
|
+
elif "''" in content_disposition:
|
65
|
+
file_name = content_disposition.split("''")[-1]
|
66
|
+
else:
|
67
|
+
file_name = content_disposition
|
68
|
+
file_name = unquote(file_name)
|
69
|
+
return [response.read(),file_name]
|
70
|
+
else:
|
71
|
+
async with aiohttp.ClientSession() as session:
|
72
|
+
async with session.get(url, headers=headers, timeout=600) as response:
|
73
|
+
content_disposition:str = response.headers.get("Content-Disposition")
|
74
|
+
if "''" in content_disposition:
|
75
|
+
file_name = content_disposition.split("''")[-1]
|
76
|
+
else:
|
77
|
+
file_name = content_disposition
|
78
|
+
file_name = unquote(file_name)
|
79
|
+
if response.status == 200:
|
80
|
+
return [await response.read(),file_name]
|
81
|
+
else:
|
82
|
+
return None
|
83
|
+
|
@@ -1,40 +1,40 @@
|
|
1
|
-
|
2
|
-
from PIL import Image
|
3
|
-
from nonebot.log import logger
|
4
|
-
from io import BytesIO
|
5
|
-
# import sys
|
6
|
-
# sys.modules["srctools._cy_vtf_readwrite"] = None
|
7
|
-
from srctools.vtf import VTF, ImageFormats
|
8
|
-
|
9
|
-
async def img_to_vtf(pic_byte:bytes,tag) -> BytesIO:
|
10
|
-
pic = BytesIO(pic_byte)
|
11
|
-
pic = Image.open(pic).convert('RGBA')
|
12
|
-
vtf_io = BytesIO()
|
13
|
-
vtf_ = VTF(1024, 1024, fmt = ImageFormats.DXT5,thumb_fmt = ImageFormats.DXT1,version=(7,2))
|
14
|
-
if tag == '覆盖':
|
15
|
-
logger.info(tag)
|
16
|
-
img2 = Image.new('RGBA',(1024, 1024), (255, 255, 255,0))
|
17
|
-
r, g, b, a = pic.split()
|
18
|
-
img2.paste(pic,mask=a)
|
19
|
-
pic = pic.resize((1024,1024))
|
20
|
-
elif tag == '填充':
|
21
|
-
w, h = pic.size
|
22
|
-
if w > h:
|
23
|
-
ratio = 1024/w
|
24
|
-
new_width = 1024
|
25
|
-
new_height = int(h * ratio)
|
26
|
-
else:
|
27
|
-
ratio = 1024/h
|
28
|
-
new_height = 1024
|
29
|
-
new_width = int(w * ratio)
|
30
|
-
pic = pic.resize((new_width, new_height), Image.ANTIALIAS)
|
31
|
-
background = Image.new('RGBA', (1024, 1024), (255, 255, 255, 0))
|
32
|
-
background.paste(pic, ((1024-new_width)//2, (1024-new_height)//2))
|
33
|
-
pic = background
|
34
|
-
else:
|
35
|
-
logger.info('拉伸')
|
36
|
-
pic = pic.resize((1024,1024))
|
37
|
-
largest_frame = vtf_.get()
|
38
|
-
largest_frame.copy_from(pic.tobytes(), ImageFormats.RGBA8888)
|
39
|
-
vtf_.save(vtf_io,version=(7,2))
|
40
|
-
return vtf_io
|
1
|
+
|
2
|
+
from PIL import Image
|
3
|
+
from nonebot.log import logger
|
4
|
+
from io import BytesIO
|
5
|
+
# import sys
|
6
|
+
# sys.modules["srctools._cy_vtf_readwrite"] = None
|
7
|
+
from srctools.vtf import VTF, ImageFormats
|
8
|
+
|
9
|
+
async def img_to_vtf(pic_byte:bytes,tag) -> BytesIO:
|
10
|
+
pic = BytesIO(pic_byte)
|
11
|
+
pic = Image.open(pic).convert('RGBA')
|
12
|
+
vtf_io = BytesIO()
|
13
|
+
vtf_ = VTF(1024, 1024, fmt = ImageFormats.DXT5,thumb_fmt = ImageFormats.DXT1,version=(7,2))
|
14
|
+
if tag == '覆盖':
|
15
|
+
logger.info(tag)
|
16
|
+
img2 = Image.new('RGBA',(1024, 1024), (255, 255, 255,0))
|
17
|
+
r, g, b, a = pic.split()
|
18
|
+
img2.paste(pic,mask=a)
|
19
|
+
pic = pic.resize((1024,1024))
|
20
|
+
elif tag == '填充':
|
21
|
+
w, h = pic.size
|
22
|
+
if w > h:
|
23
|
+
ratio = 1024/w
|
24
|
+
new_width = 1024
|
25
|
+
new_height = int(h * ratio)
|
26
|
+
else:
|
27
|
+
ratio = 1024/h
|
28
|
+
new_height = 1024
|
29
|
+
new_width = int(w * ratio)
|
30
|
+
pic = pic.resize((new_width, new_height), Image.ANTIALIAS)
|
31
|
+
background = Image.new('RGBA', (1024, 1024), (255, 255, 255, 0))
|
32
|
+
background.paste(pic, ((1024-new_width)//2, (1024-new_height)//2))
|
33
|
+
pic = background
|
34
|
+
else:
|
35
|
+
logger.info('拉伸')
|
36
|
+
pic = pic.resize((1024,1024))
|
37
|
+
largest_frame = vtf_.get()
|
38
|
+
largest_frame.copy_from(pic.tobytes(), ImageFormats.RGBA8888)
|
39
|
+
vtf_.save(vtf_io,version=(7,2))
|
40
|
+
return vtf_io
|