nonebot-plugin-l4d2-server 1.0.3__py3-none-any.whl → 1.0.5__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.
@@ -1,56 +1,193 @@
1
1
  import asyncio
2
2
 
3
3
  # from logging import log
4
+ import io
5
+ from pathlib import Path
4
6
  from typing import List, Tuple
5
7
 
8
+ from nonebot.log import logger
9
+ from PIL import Image, ImageDraw, ImageFont
10
+
6
11
  from ..config import config
7
12
  from ..utils.api.models import NserverOut, OutServer
8
13
  from ..utils.api.request import L4API
9
14
 
10
15
 
11
- async def draw_one_ip(host: str, port: int):
16
+ async def draw_one_ip(host: str, port: int, is_img: bool = config.l4_image):
12
17
  """输出单个ip"""
13
- # 先用文字凑合
14
18
  try:
15
19
  ser_list = await L4API.a2s_info([(host, port)], is_player=True)
16
20
  except asyncio.exceptions.TimeoutError:
17
21
  return "服务器无响应"
18
- player_msg = ""
19
22
  one_server = ser_list[0][0]
20
23
  one_player = ser_list[0][1]
21
24
 
22
- if len(one_player):
23
- max_duration_len = max(
24
- [len(str(await convert_duration(i.duration))) for i in one_player],
25
- )
26
- max_score_len = max(len(str(i.score)) for i in one_player)
27
-
28
- for player in one_player:
29
- soc = "[{:>{}}]".format(player.score, max_score_len)
30
- chines_dur = await convert_duration(player.duration)
31
- dur = "{:^{}}".format(chines_dur, max_duration_len)
32
- name_leg = len(player.name)
33
- if name_leg > 2:
34
- xing = "*" * (name_leg - 2)
35
- name = f"{player.name[0]}{xing}{player.name[-1]}"
36
- else:
37
- name = player.name
38
- player_msg += f"{soc} | {dur} | {name} \n"
39
- else:
40
- player_msg = "服务器感觉很安静啊"
41
-
42
- msg = f"""*{one_server.server_name}*
43
- 游戏: {one_server.folder}
44
- 地图: {one_server.map_name}
45
- 人数: {one_server.player_count}/{one_server.max_players}"""
46
- if one_server.ping is not None:
47
- msg += f"""
48
- ping: {one_server.ping * 1000:.0f}ms
49
- {player_msg}"""
50
- if config.l4_show_ip:
51
- msg += f"""
25
+ async def format_player_info(players: list) -> str:
26
+ """格式化玩家信息
27
+ Args:
28
+ players: 玩家对象列表
29
+ Returns:
30
+ 格式化后的玩家信息字符串
31
+ """
32
+ player_msg = ""
33
+ if len(players):
34
+ max_duration_len = max(
35
+ [len(str(await convert_duration(i.duration))) for i in players],
36
+ )
37
+ max_score_len = max(len(str(i.score)) for i in players)
38
+
39
+ for player in players:
40
+ soc = "[{:>{}}]".format(player.score, max_score_len)
41
+ chines_dur = await convert_duration(player.duration)
42
+ dur = "{:^{}}".format(chines_dur, max_duration_len)
43
+ name_leg = len(player.name)
44
+ if name_leg > 2:
45
+ xing = ":)" * (name_leg - 2)
46
+ name = f"{player.name[0]}{xing}{player.name[-1]}"
47
+ else:
48
+ name = player.name
49
+ player_msg += f"{soc} | {dur} | {name} \n"
50
+ else:
51
+ player_msg = "服务器感觉很安静啊"
52
+ return player_msg
53
+
54
+ def build_server_message(server, player_info: str) -> str:
55
+ """构建服务器信息消息
56
+ Args:
57
+ server: 服务器对象
58
+ player_info: 格式化后的玩家信息字符串
59
+ Returns:
60
+ 完整的服务器信息字符串
61
+ """
62
+ msg = f"""-{server.server_name}-
63
+ 游戏: {server.folder}
64
+ 地图: {server.map_name}
65
+ 人数: {server.player_count}/{server.max_players}"""
66
+ if server.ping is not None:
67
+ msg += f"""
68
+ ping: {server.ping * 1000:.0f}ms
69
+ {player_info}"""
70
+ if config.l4_show_ip:
71
+ msg += f"""
52
72
  connect {host}:{port}"""
53
- return msg
73
+ return msg
74
+
75
+ def draw_text_on_image(
76
+ text: str,
77
+ font: ImageFont.FreeTypeFont,
78
+ draw: ImageDraw.ImageDraw,
79
+ ) -> Image.Image: # type: ignore # 明确返回类型
80
+ """在图片上绘制文本
81
+ Args:
82
+ text: 要绘制的文本
83
+ font: PIL字体对象
84
+ draw: PIL绘图对象
85
+ Returns:
86
+ 包含绘制文本的PIL图片对象
87
+ """
88
+ try:
89
+ # 分割文本为标题行和内容行
90
+ lines = text.split("\n")
91
+ if not lines:
92
+ return Image.new("RGB", (600, 400), color=(73, 109, 137))
93
+
94
+ title = lines[0]
95
+ content = "\n".join(lines[1:]) if len(lines) > 1 else ""
96
+
97
+ # 计算各部分文字尺寸
98
+ title_bbox = font.getbbox(title)
99
+ title_width = title_bbox[2] - title_bbox[0]
100
+ title_height = title_bbox[3] - title_bbox[1]
101
+
102
+ content_width = 0
103
+ content_height = 0
104
+ if content:
105
+ content_lines = content.split("\n")
106
+ line_height = font.getbbox("A")[3] - font.getbbox("A")[1]
107
+ content_height = len(content_lines) * line_height
108
+ content_width = max(
109
+ font.getbbox(line)[2] - font.getbbox(line)[0]
110
+ for line in content_lines
111
+ )
112
+
113
+ # 计算图片尺寸
114
+ margin = 20
115
+ line_spacing = 5
116
+ img_width = max(title_width, content_width) + 2 * margin
117
+ content_lines_count = len(content.split("\n")) if content else 0
118
+ img_height = max(
119
+ title_height
120
+ + content_height
121
+ + (line_spacing + 1) * max(0, content_lines_count - 1)
122
+ + 2 * margin,
123
+ 300,
124
+ )
125
+
126
+ # 加载背景图片
127
+ bg_path = (
128
+ Path(__file__).parent.parent / "l4_image" / "img" / "anne" / "back.png"
129
+ )
130
+ try:
131
+ img = Image.open(bg_path)
132
+ # 调整背景图尺寸
133
+ img = img.resize((int(img_width), int(img_height)))
134
+ logger.info(f"图片像素大小: {img.width}x{img.height}")
135
+ draw = ImageDraw.Draw(img)
136
+
137
+ title_x = (img_width - title_width) // 2
138
+ title_y = margin
139
+ draw.text((title_x, title_y), title, font=font, fill=(255, 255, 255))
140
+
141
+ if content:
142
+ content_x = margin
143
+ content_y = title_y + title_height + margin
144
+ draw.text(
145
+ (content_x, content_y),
146
+ content,
147
+ font=font,
148
+ fill=(255, 255, 255),
149
+ spacing=line_spacing,
150
+ )
151
+
152
+ return img
153
+ except Exception as e:
154
+ logger.error(f"加载背景图片失败: {e}")
155
+ img = Image.new(
156
+ "RGB",
157
+ (int(img_width), int(img_height)),
158
+ color=(73, 109, 137),
159
+ )
160
+ draw = ImageDraw.Draw(img)
161
+ draw.text((title_x, title_y), title, font=font, fill=(255, 255, 255))
162
+ if content:
163
+ draw.text(
164
+ (content_x, content_y),
165
+ content,
166
+ font=font,
167
+ fill=(255, 255, 255),
168
+ spacing=line_spacing,
169
+ )
170
+ return img
171
+ except Exception as e:
172
+ logger.error(f"绘制图片时出错: {e}")
173
+ error_img = Image.new("RGB", (600, 400), color=(255, 0, 0))
174
+ error_draw = ImageDraw.Draw(error_img)
175
+ error_draw.text((10, 10), "图片生成失败", fill=(255, 255, 255))
176
+ return error_img
177
+
178
+ player_info = await format_player_info(one_player)
179
+ server_message = build_server_message(one_server, player_info)
180
+
181
+ if is_img:
182
+ # 加载字体
183
+ font_path = Path(__file__).parent.parent / "data" / "font" / "loli.ttf"
184
+ font = ImageFont.truetype(str(font_path), 18)
185
+ draw = ImageDraw.Draw(Image.new("RGB", (600, 400), color=(73, 109, 137)))
186
+ img = draw_text_on_image(server_message, font, draw)
187
+ img_byte_arr = io.BytesIO()
188
+ img.save(img_byte_arr, format="PNG")
189
+ return img_byte_arr.getvalue()
190
+ return server_message
54
191
 
55
192
 
56
193
  async def get_much_server(server_json: List[NserverOut], command: str):
@@ -64,7 +201,7 @@ async def get_much_server(server_json: List[NserverOut], command: str):
64
201
  for index, i in enumerate(all_server):
65
202
  out_server.append(
66
203
  {
67
- "server": i[0],
204
+ "server": i[0], # type: ignore
68
205
  "player": i[1],
69
206
  "host": server_json[index]["host"],
70
207
  "port": server_json[index]["port"],
@@ -0,0 +1,176 @@
1
+ from typing import Dict, List, Optional, Tuple, Union, cast
2
+
3
+ from nonebot.log import logger
4
+
5
+ from ..l4_image import msg_to_image
6
+ from ..utils.api.models import NserverOut
7
+ from ..utils.api.request import L4API
8
+ from .draw_msg import convert_duration, draw_one_ip, get_much_server
9
+
10
+
11
+ def _get_server_json(
12
+ command: str,
13
+ allhost: Dict[str, List[NserverOut]],
14
+ ) -> Optional[list]:
15
+ """
16
+ 根据命令获取服务器JSON列表
17
+
18
+ Args:
19
+ command (str): 服务器组名
20
+ ALLHOST (Dict): 全局服务器字典
21
+
22
+ Returns:
23
+ Optional[list]: 服务器JSON列表,未找到组时返回None
24
+ """
25
+ if command:
26
+ return allhost.get(command)
27
+ server_json = []
28
+ for servers in allhost.values():
29
+ server_json.extend(servers)
30
+ return server_json
31
+
32
+
33
+ async def _handle_group_info(
34
+ server_json: list,
35
+ command: str,
36
+ is_img: bool,
37
+ ) -> Union[bytes, str, None]:
38
+ """
39
+ 处理服务器组信息请求
40
+
41
+ Args:
42
+ server_json (list): 服务器JSON列表
43
+ command (str): 服务器组名
44
+ is_img (bool): 是否返回图片格式
45
+
46
+ Returns:
47
+ Union[bytes, str, None]: 图片格式返回bytes,否则返回服务器列表
48
+ """
49
+ logger.info(f"正在请求组服务器信息 {command}")
50
+ server_dict = await get_much_server(server_json, command)
51
+ if is_img:
52
+ return await msg_to_image(server_dict)
53
+ return str(server_dict)
54
+
55
+
56
+ async def get_single_server_info(
57
+ server_json: list,
58
+ _id: str,
59
+ ) -> Optional[Tuple[str, int]]:
60
+ """
61
+ 获取单个服务器的host和port信息
62
+
63
+ Args:
64
+ server_json (list): 服务器JSON列表
65
+ _id (str): 服务器ID
66
+
67
+ Returns:
68
+ Optional[Tuple[str, int]]: 返回(host, port)元组,未找到返回None
69
+ """
70
+ logger.info("正在获取单服务器信息")
71
+ for i in server_json:
72
+ if str(_id) == str(i["id"]):
73
+ return i["host"], i["port"]
74
+ return None
75
+
76
+
77
+ async def _handle_single_server(
78
+ server_json: list,
79
+ _id: str,
80
+ is_img: bool,
81
+ ) -> Union[bytes, str, None]:
82
+ """
83
+ 处理单个服务器信息请求
84
+
85
+ Args:
86
+ server_json (list): 服务器JSON列表
87
+ _id (str): 服务器ID
88
+ is_img (bool): 是否返回图片格式
89
+
90
+ Returns:
91
+ Union[bytes, str, None]: 找到服务器时返回信息,否则返回None
92
+ """
93
+ server_info = await get_single_server_info(server_json, _id)
94
+ if server_info is None:
95
+ return None
96
+
97
+ host, port = server_info
98
+ out_msg = await draw_one_ip(host, port)
99
+ if is_img:
100
+ return cast(bytes, out_msg)
101
+ return out_msg
102
+
103
+
104
+ async def _filter_servers(
105
+ servers: list,
106
+ tj_mode: str,
107
+ map_type: str = "普通药役",
108
+ ) -> list:
109
+ """筛选符合条件的服务器
110
+ Args:
111
+ servers: 服务器列表
112
+ tj_mode: 筛选模式('tj'或'zl')
113
+ map_type: 地图类型筛选条件
114
+ Returns:
115
+ 符合条件的服务器列表
116
+ """
117
+ filtered = []
118
+ for i in servers:
119
+ ser_list = await L4API.a2s_info([(i["host"], i["port"])], is_player=True)
120
+ if not ser_list:
121
+ continue
122
+
123
+ srv = ser_list[0][0]
124
+ players = ser_list[0][1]
125
+
126
+ if tj_mode == "tj" and map_type in srv.map_name:
127
+ score = sum(p.score for p in players[:4])
128
+ t = srv.map_name.split("[")[-1].split("特")[0]
129
+ if t.isdigit() and int(t) * 50 < score:
130
+ logger.info(
131
+ f"符合TJ条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 分数: {score}",
132
+ )
133
+ filtered.append(i)
134
+ elif tj_mode == "zl" and map_type in srv.map_name and len(players) <= 4:
135
+ logger.info(
136
+ f"符合ZL条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 玩家数: {len(players)}",
137
+ )
138
+ filtered.append(i)
139
+ return filtered
140
+
141
+
142
+ async def _format_players(player_list: list) -> str:
143
+ """格式化玩家信息
144
+ Args:
145
+ player_list: 玩家对象列表
146
+ Returns:
147
+ 格式化后的玩家信息字符串
148
+ """
149
+ durations = [await convert_duration(p.duration) for p in player_list]
150
+ max_duration_len = max(len(str(d)) for d in durations)
151
+ max_score_len = max(len(str(p.score)) for p in player_list)
152
+ return "\n".join(
153
+ f"[{p.score:>{max_score_len}}] | {durations[i]:^{max_duration_len}} | {p.name[0]}***{p.name[-1]}"
154
+ for i, p in enumerate(player_list)
155
+ )
156
+
157
+
158
+ def _build_message(srv_info, players_msg: str, selected_srv: dict, config) -> str:
159
+ """构建服务器信息消息
160
+ Args:
161
+ srv_info: 服务器信息对象
162
+ players_msg: 格式化后的玩家信息
163
+ selected_srv: 选中的服务器信息
164
+ config: 配置对象
165
+ Returns:
166
+ 完整的消息字符串
167
+ """
168
+ msg = f"""*{srv_info.server_name}*
169
+ 游戏: {srv_info.folder}
170
+ 地图: {srv_info.map_name}
171
+ 人数: {srv_info.player_count}/{srv_info.max_players}"""
172
+ if srv_info.ping is not None:
173
+ msg += f"\nping: {srv_info.ping * 1000:.0f}ms\n{players_msg}"
174
+ if config.l4_show_ip:
175
+ msg += f"\nconnect {selected_srv['host']}:{selected_srv['port']}"
176
+ return msg
@@ -22,7 +22,7 @@ class NserverOut(TypedDict):
22
22
 
23
23
 
24
24
  class OutServer(TypedDict):
25
- server: a2s.SourceInfo
25
+ server: a2s.SourceInfo[str]
26
26
  player: List[a2s.Player]
27
27
  host: str
28
28
  port: int
@@ -3,18 +3,17 @@ import contextlib
3
3
  import socket
4
4
  from copy import deepcopy
5
5
  from pathlib import Path
6
- from typing import Any, Dict, List, Literal, Optional, Tuple, cast
6
+ from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
7
7
 
8
8
  import a2s
9
9
  import aiofiles
10
10
  import ujson as js
11
11
  import ujson as json
12
- from bs4 import BeautifulSoup
12
+ from bs4 import BeautifulSoup, Tag
13
13
  from httpx import AsyncClient
14
+ from nonebot.log import logger
14
15
 
15
16
  from ...config import config
16
-
17
- # from nonebot.log import logger
18
17
  from ..utils import split_maohao
19
18
  from .api import AnnePlayerApi, AnneSearchApi, anne_ban
20
19
  from .models import (
@@ -42,35 +41,57 @@ class L4D2Api:
42
41
  "Content-Type": "application/x-www-form-urlencoded",
43
42
  }
44
43
 
44
+ def safe_select(self, element: Optional[Tag], selector: str) -> List[Any]:
45
+ """安全地调用 select 方法"""
46
+ if isinstance(element, Tag):
47
+ return element.select(selector)
48
+ return []
49
+
50
+ def safe_find_all(
51
+ self,
52
+ element: Optional[Tag],
53
+ tag: str,
54
+ class_: str = "",
55
+ ) -> List[Any]:
56
+ """安全地调用 find_all 方法"""
57
+ if isinstance(element, Tag):
58
+ return element.find_all(tag, class_=class_)
59
+ return []
60
+
45
61
  async def a2s_info(
46
62
  self,
47
63
  ip_list: List[Tuple[str, int]],
48
64
  is_server: bool = True,
49
65
  is_player: bool = False,
50
- ) -> List[Tuple[a2s.SourceInfo, List[a2s.Player]]]:
51
- msg_list: List[Tuple[a2s.SourceInfo, List[a2s.Player]]] = []
52
- sorted_msg_list = []
53
- tasks = [] # 用来保存异步任务
54
- if ip_list != []:
55
- for index, i in enumerate(ip_list):
56
- try:
57
- tasks.append(
58
- asyncio.create_task(
59
- self.process_message(
60
- i,
61
- index,
62
- is_server,
63
- is_player,
64
- ),
65
- ),
66
- )
67
- except ValueError:
68
- continue # 处理异常情况
66
+ ) -> List[
67
+ Tuple[Union[a2s.SourceInfo[str], a2s.GoldSrcInfo[str]], List[a2s.Player]]
68
+ ]:
69
+ msg_list: List[
70
+ Tuple[Union[a2s.SourceInfo[str], a2s.GoldSrcInfo[str]], List[a2s.Player]]
71
+ ] = []
72
+
73
+ if ip_list:
74
+ tasks = [
75
+ asyncio.create_task(
76
+ self.process_message(ip, index, is_server, is_player),
77
+ )
78
+ for index, ip in enumerate(ip_list)
79
+ ]
69
80
 
70
- msg_list = await asyncio.gather(*tasks)
71
- sorted_msg_list = sorted(msg_list, key=lambda x: x[0].steam_id)
81
+ try:
82
+ results = await asyncio.gather(*tasks)
83
+ msg_list = [r for r in results if r is not None]
84
+ except Exception as e:
85
+ logger.error(f"获取服务器信息时发生错误: {e}")
72
86
 
73
- return sorted_msg_list
87
+ # 使用稳定的排序方式,避免服务器频繁变动位置
88
+ return sorted(
89
+ msg_list,
90
+ key=lambda x: (
91
+ getattr(x[0], "steam_id", float("inf")) is None,
92
+ getattr(x[0], "steam_id", float("inf")),
93
+ ),
94
+ )
74
95
 
75
96
  async def process_message(
76
97
  self,
@@ -80,19 +101,24 @@ class L4D2Api:
80
101
  is_player: bool,
81
102
  ):
82
103
  play: List[a2s.Player] = []
104
+ server: Union[a2s.SourceInfo, a2s.GoldSrcInfo]
83
105
  if is_server:
84
106
  try:
85
- server: a2s.SourceInfo = await a2s.ainfo(ip, timeout=3, encoding="utf8")
107
+ server = await a2s.ainfo(
108
+ ip,
109
+ timeout=3,
110
+ encoding="utf8",
111
+ )
86
112
 
87
113
  if server is not None:
88
- server.steam_id = index
114
+ server.steam_id = index # type: ignore
89
115
 
90
116
  except (
91
117
  asyncio.exceptions.TimeoutError,
92
118
  ConnectionRefusedError,
93
119
  socket.gaierror,
94
120
  ):
95
- server: a2s.SourceInfo = a2s.SourceInfo(
121
+ server = a2s.SourceInfo(
96
122
  protocol=0,
97
123
  server_name="服务器无响应",
98
124
  map_name="无",
@@ -137,7 +163,7 @@ class L4D2Api:
137
163
  json: Optional[Dict[str, Any]] = None,
138
164
  data: Optional[Dict[str, Any]] = None,
139
165
  is_json: bool = True,
140
- ):
166
+ ) -> Union[Dict[str, Any], BeautifulSoup]: # type: ignore
141
167
  header = deepcopy(self._HEADER)
142
168
 
143
169
  if json is not None:
@@ -181,7 +207,17 @@ class L4D2Api:
181
207
  return BeautifulSoup(html_content, "lxml")
182
208
 
183
209
  async def get_sourceban(self, tag: str = "云", url: str = anne_ban):
184
- """从sourceban++获取服务器列表,目前未做名称处理"""
210
+ """
211
+ 异步函数,从sourceban++获取服务器列表,目前未做名称处理。
212
+
213
+ Args:
214
+ tag (str): 用于标识不同来源的标签,默认为"云"。
215
+ url (str): SourceBan的URL,默认为anne_ban。
216
+
217
+ Returns:
218
+ list: 包含服务器信息的列表。
219
+
220
+ """
185
221
  if not (url.startswith(("http://", "https://"))):
186
222
  url = "http://" + url # 默认添加 http://
187
223
  soup = await self._server_request(
@@ -216,14 +252,12 @@ class L4D2Api:
216
252
  tag_path = Path(Path(config.l4_path) / f"l4d2/{tag}.json")
217
253
 
218
254
  async with aiofiles.open(tag_path, "w", encoding="utf-8") as f:
219
- print(Path(Path(config.l4_path) / f"l4d2/{tag}.json"))
220
255
  up_data = {}
221
256
  for server in server_list:
222
257
  new_dict = {}
223
258
  new_dict["id"] = int(server.index) + 1
224
259
  new_dict["ip"] = server.host + ":" + str(server.port)
225
260
  up_data.update(new_dict)
226
- print(up_data)
227
261
  json.dump(up_data, f, ensure_ascii=False, indent=4)
228
262
  return server_list
229
263
 
@@ -258,7 +292,7 @@ class L4D2Api:
258
292
  "last_time": td_tags,
259
293
  },
260
294
  )
261
- print(server_list)
295
+ logger.debug(server_list)
262
296
  return cast(List[AnneSearch], server_list)
263
297
 
264
298
  async def get_anne_playerdetail(self, steamid: str):
@@ -272,14 +306,14 @@ class L4D2Api:
272
306
  if not isinstance(soup, BeautifulSoup):
273
307
  return None
274
308
 
275
- tbody = soup.find(
309
+ tbody = cast(BeautifulSoup, soup).find(
276
310
  "div",
277
311
  class_="content text-center text-md-left",
278
312
  style="background-color: #f2f2f2;",
279
313
  )
280
314
  if tbody is None:
281
315
  return None
282
- kill_tag = tbody.find(
316
+ kill_tag = cast(BeautifulSoup, tbody).find(
283
317
  "div",
284
318
  class_="card-body worldmap d-flex flex-column justify-content-center text-center",
285
319
  )
@@ -288,7 +322,7 @@ class L4D2Api:
288
322
  "table",
289
323
  class_="table content-table-noborder text-left",
290
324
  )
291
- print(len(tbody_tags))
325
+
292
326
  info_tag = tbody_tags[0]
293
327
  detail_tag = tbody_tags[1]
294
328
  error_tag = tbody_tags[2]
@@ -0,0 +1,30 @@
1
+ from typing import Union
2
+
3
+ from nonebot_plugin_alconna import UniMessage
4
+
5
+
6
+ async def out_msg_out(
7
+ msg: Union[str, bytes, UniMessage],
8
+ is_connect: bool = False,
9
+ host: str = "",
10
+ port: str = "",
11
+ ):
12
+ """
13
+ 统一消息输出函数
14
+
15
+ Args:
16
+ msg: 要输出的消息内容
17
+ is_connect: 是否为连接消息
18
+ host: 服务器地址
19
+ port: 服务器端口
20
+ """
21
+ if isinstance(msg, UniMessage):
22
+ return await msg.finish()
23
+ if isinstance(msg, str):
24
+ await UniMessage.text(msg).finish()
25
+ if is_connect:
26
+ out = UniMessage.image(raw=msg) + UniMessage.text(
27
+ f"连接到服务器: {host}:{port}",
28
+ )
29
+ return await out.finish()
30
+ return await UniMessage.image(raw=msg).finish()
@@ -7,6 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
7
7
  import aiofiles
8
8
  import aiohttp
9
9
  import nonebot
10
+ from aiohttp import ClientTimeout
10
11
  from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
11
12
  from nonebot.log import logger
12
13
  from nonebot_plugin_alconna import UniMessage
@@ -184,7 +185,11 @@ async def url_to_byte(url: str):
184
185
  """获取URL数据的字节流"""
185
186
 
186
187
  async with aiohttp.ClientSession() as session:
187
- async with session.get(url, headers=headers, timeout=600) as response:
188
+ async with session.get(
189
+ url,
190
+ headers=headers,
191
+ timeout=ClientTimeout(total=600),
192
+ ) as response:
188
193
  if response.status == 200:
189
194
  return await response.read()
190
195
  return None
@@ -194,7 +199,11 @@ async def url_to_msg(url: str):
194
199
  """获取URL数据的字节流"""
195
200
 
196
201
  async with aiohttp.ClientSession() as session:
197
- async with session.get(url, headers=headers, timeout=600) as response:
202
+ async with session.get(
203
+ url,
204
+ headers=headers,
205
+ timeout=ClientTimeout(total=600),
206
+ ) as response:
198
207
  if response.status == 200:
199
208
  return await response.text()
200
209
  return None