nonebot-plugin-l4d2-server 1.0.1__py3-none-any.whl → 1.0.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.
@@ -18,6 +18,7 @@
18
18
  from pathlib import Path
19
19
  from typing import TYPE_CHECKING, List, Optional
20
20
 
21
+ import aiofiles
21
22
  import ujson as json
22
23
  from nonebot.adapters import Message
23
24
  from nonebot.log import logger
@@ -35,7 +36,7 @@ from .l4_request import (
35
36
  get_ip_server,
36
37
  get_server_detail,
37
38
  reload_ip,
38
- tj_request
39
+ tj_request,
39
40
  )
40
41
  from .utils.api.request import L4API
41
42
 
@@ -54,6 +55,8 @@ l4_find_player = on_command("l4find", aliases={"l4查找"})
54
55
  ld_tj = on_command("tj", aliases={"探监"})
55
56
  ld_zl = on_command("zl")
56
57
  ld_kl = on_command("kl")
58
+ config_path = Path(config.l4_path) / "config.json"
59
+
57
60
 
58
61
  @l4_help.handle()
59
62
  async def _(matcher: Matcher):
@@ -102,17 +105,27 @@ async def _(
102
105
  async def _(
103
106
  args: Message = CommandArg(),
104
107
  ):
108
+ # 以后有时间补img格式
105
109
  msg: str = args.extract_plain_text().strip()
106
110
  tag_list: List[str] = msg.split(" ", maxsplit=1)
107
- if len(tag_list) < 2:
108
- return await UniMessage.text("格式错误,正确格式:/l4find 组名 玩家名").finish()
109
- group, name = tag_list
110
- out: List[OutServer] = await get_server_detail(group, is_img=False) # type: ignore
111
- out_msg = "未找到玩家"
112
- for one in out:
113
- for player in one["player"]:
114
- if name in player.name:
115
- out_msg = await get_ip_server(f"{one['host']}:{one['port']}")
111
+ if len(tag_list) == 1:
112
+ await UniMessage.text("未设置组,正在全服查找,时间较长").send()
113
+ name = tag_list[0]
114
+ out: List[OutServer] = await get_server_detail(is_img=False) # type: ignore
115
+ out_msg = "未找到玩家"
116
+ for one in out:
117
+ for player in one["player"]:
118
+ if name in player.name:
119
+ out_msg = await get_ip_server(f"{one['host']}:{one['port']}")
120
+ if len(tag_list) == 2:
121
+ group, name = tag_list
122
+ await UniMessage.text(f"正在查询{group}组").send()
123
+ out: List[OutServer] = await get_server_detail(group, is_img=False) # type: ignore
124
+ out_msg = "未找到玩家"
125
+ for one in out:
126
+ for player in one["player"]:
127
+ if name in player.name:
128
+ out_msg = await get_ip_server(f"{one['host']}:{one['port']}")
116
129
 
117
130
  return await UniMessage.text(out_msg).finish()
118
131
 
@@ -149,18 +162,18 @@ async def _(args: Message = CommandArg()):
149
162
  logger.info(f"重载{tag}的ip")
150
163
  await L4API.get_sourceban(tag, url)
151
164
  await UniMessage.text("重载ip完成").finish()
152
-
165
+
153
166
 
154
167
  l4_add_ban = on_command("l4addban", aliases={"l4添加ban"})
168
+
169
+
155
170
  @l4_add_ban.handle()
156
171
  async def _(args: Message = CommandArg()):
157
172
  arg = args.extract_plain_text().strip().split(" ")
158
-
173
+
159
174
  if len(arg) != 2:
160
175
  await UniMessage.text("请在命令后增加响应指令名和网址").finish()
161
-
162
- config_path = Path(config.l4_path) / "config.json"
163
-
176
+
164
177
  if not config_path.is_file():
165
178
  config_data = {}
166
179
  else:
@@ -169,61 +182,70 @@ async def _(args: Message = CommandArg()):
169
182
  config_data = json.load(f)
170
183
  except (json.JSONDecodeError, FileNotFoundError):
171
184
  config_data = {}
172
-
185
+
173
186
  config_data.update({arg[0]: arg[1]})
174
-
187
+
175
188
  try:
176
189
  with config_path.open("w") as f:
177
190
  json.dump(config_data, f, ensure_ascii=False, indent=4)
178
191
  except IOError as e:
179
192
  await UniMessage.text(f"文件写入失败: {e}").finish()
180
-
193
+
181
194
  await L4API.get_sourceban(arg[0], arg[1])
182
195
  await UniMessage.text(f"添加成功\n组名: {arg[0]}\n网址: {arg[1]}").finish()
183
-
196
+
184
197
 
185
198
  l4_del_ban = on_command("l4delban", aliases={"l4删除ban", "l4移除ban"})
199
+
200
+
186
201
  @l4_del_ban.handle()
187
- async def _(args: Message = CommandArg()):
202
+ async def _(args: Message = CommandArg()):
188
203
  arg = args.extract_plain_text().strip().split(" ")
189
- if len(arg) not in [1,2]:
204
+ if len(arg) not in [1, 2]:
190
205
  await UniMessage.text("请在命令后增加响应指令名或者带响应网址").finish()
191
206
  elif len(arg) == 1:
192
207
  if not Path(Path(config.l4_path) / "config.json").is_file():
193
208
  await UniMessage.text("没有添加过组名").finish()
194
209
  else:
195
- with (Path(config.l4_path) / "config.json").open("r", encoding="utf-8") as f:
210
+ with (Path(config.l4_path) / "config.json").open(
211
+ "r",
212
+ encoding="utf-8",
213
+ ) as f:
196
214
  content = f.read().strip()
197
- config_data = json.loads(content)
215
+ config_data = json.loads(content)
198
216
  if arg[0] not in config_data:
199
217
  await UniMessage.text("没有添加过这个组").finish()
200
218
  else:
201
219
  del config_data[arg[0]]
202
- with Path(Path(config.l4_path) / "config.json").open("w") as f:
203
- json.dump(config_data, f,ensure_ascii=False,indent=4)
204
- await UniMessage.text(f"删除成功,组名:{arg[0]}").finish()
220
+ async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
221
+ json.dump(config_data, f, ensure_ascii=False, indent=4)
222
+ await UniMessage.text(f"删除成功,组名:{arg[0]}").finish()
205
223
  elif len(arg) == 2:
206
224
  if not Path(Path(config.l4_path) / "config.json").is_file():
207
225
  await UniMessage.text("没有添加过组名").finish()
208
226
  else:
209
- with (Path(config.l4_path) / "config.json").open("r", encoding="utf-8") as f:
227
+ with (Path(config.l4_path) / "config.json").open(
228
+ "r",
229
+ encoding="utf-8",
230
+ ) as f:
210
231
  content = f.read().strip()
211
232
  config_datas = json.loads(content)
212
233
  if arg[0] not in config_datas:
213
234
  await UniMessage.text("没有添加过这个组").finish()
214
235
  else:
215
236
  config_datas[arg[0]] = arg[1]
216
- with Path(Path(config.l4_path) / "config.json").open("w") as f:
217
- json.dump(config_datas, f,ensure_ascii=False,indent=4)
237
+ async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
238
+ json.dump(config_datas, f, ensure_ascii=False, indent=4)
218
239
  await UniMessage.text(f"修改成功,组名:{arg[0]},网址:{arg[1]}").finish()
219
-
220
-
240
+
241
+
221
242
  @ld_tj.handle()
222
243
  async def _(matcher: Matcher):
223
244
  await matcher.send("正在寻找牢房信息")
224
- await matcher.finish(await tj_request("云","tj"))
225
-
245
+ await matcher.finish(await tj_request("云", "tj"))
246
+
247
+
226
248
  @ld_zl.handle()
227
249
  async def _(matcher: Matcher):
228
250
  await matcher.send("正在寻找牢房信息")
229
- await matcher.finish(await tj_request("云","zl"))
251
+ await matcher.finish(await tj_request("云", "zl"))
@@ -1,10 +1,14 @@
1
1
  from pathlib import Path
2
2
 
3
3
  from nonebot import get_plugin_config
4
+ from nonebot.log import logger
4
5
  from pydantic import BaseModel
5
6
 
6
7
  DATAPATH = Path(__file__).parent.joinpath("data")
7
8
  DATAOUT = Path("data/L4D2")
9
+ if not Path(DATAOUT / "l4d2.json").exists():
10
+ logger.info("文件 l4d2.json 不存在,已创建并初始化为 {}")
11
+ Path(DATAOUT / "l4d2.json").write_text("{}", encoding="utf-8")
8
12
  print(DATAOUT.absolute())
9
13
  server_all_path = DATAOUT / "l4d2"
10
14
  server_all_path.mkdir(parents=True, exist_ok=True)
@@ -10,7 +10,7 @@ from ..l4_image.convert import core_font
10
10
  from ..l4_image.model import PluginHelp
11
11
  from .draw import get_help
12
12
 
13
- __version__ = "1.0.1"
13
+ __version__ = "1.0.3"
14
14
  TEXT_PATH = Path(__file__).parent / "texture2d"
15
15
  HELP_DATA = Path(__file__).parent / "Help.json"
16
16
 
@@ -13,7 +13,9 @@ from .file import updown_l4d2_vpk
13
13
  try:
14
14
  vpk_path = config.l4_local[map_index]
15
15
  except IndexError:
16
- logger.warning("未填写本地服务器路径,如果想要使用本地服务器功能,请填写本地服务器路径")
16
+ logger.warning(
17
+ "未填写本地服务器路径,如果想要使用本地服务器功能,请填写本地服务器路径",
18
+ )
17
19
  vpk_path = ""
18
20
 
19
21
  local_path_list = config.l4_local
@@ -2,16 +2,19 @@ import random
2
2
  from typing import Dict, List, Optional, cast
3
3
 
4
4
  from nonebot.log import logger
5
+
5
6
  from ..config import server_all_path
6
7
  from ..l4_image import msg_to_image
7
8
  from ..utils.api.models import AllServer, NserverOut, OutServer
8
- from ..utils.utils import split_maohao
9
- from .draw_msg import draw_one_ip, get_much_server, convert_duration
10
9
  from ..utils.api.request import L4API
10
+ from ..utils.utils import split_maohao
11
+ from .draw_msg import convert_duration, draw_one_ip, get_much_server
12
+
11
13
  try:
12
14
  import ujson as json
13
15
  except ImportError:
14
16
  import json
17
+
15
18
  from ..config import config
16
19
 
17
20
  # 获取全部服务器信息
@@ -20,6 +23,16 @@ COMMAND = set()
20
23
 
21
24
 
22
25
  async def get_all_server_detail():
26
+ """
27
+ 获取所有服务器的详细信息。
28
+
29
+ Args:
30
+
31
+
32
+ Returns:
33
+ str: 包含所有服务器详细信息的字符串。
34
+
35
+ """
23
36
  out_list: List[AllServer] = []
24
37
  for group in ALLHOST:
25
38
  msg_list = await get_group_detail(group)
@@ -47,16 +60,38 @@ async def get_all_server_detail():
47
60
  # to do作图,先用文字凑合
48
61
  out_msg = ""
49
62
  for one in out_list:
50
- out_msg += f"{one['command']} | 服务器{one['active_server']}/{one['max_server']} | 玩家{one['active_player']}/{one['max_player']}\n"
63
+ if one["max_player"]:
64
+ out_msg += f"{one['command']} | 服务器{one['active_server']}/{one['max_server']} | 玩家{one['active_player']}/{one['max_player']}\n"
65
+ else:
66
+ continue
51
67
  return out_msg
52
68
 
53
69
 
54
70
  async def get_server_detail(
55
- command: str,
71
+ command: str = "",
56
72
  _id: Optional[str] = None,
57
73
  is_img: bool = True,
58
74
  ):
59
- server_json = ALLHOST.get(command)
75
+ """
76
+ 异步获取服务器详细信息。
77
+
78
+ Args:
79
+ command (str): 服务器组名。
80
+ _id (Optional[str], optional): 服务器ID。默认为None。
81
+ is_img (bool, optional): 是否返回图片格式的信息。默认为True。
82
+
83
+ Returns:
84
+ Union[bytes, List[OutServer], None]: 返回服务器详细信息。如果为图片格式,返回bytes类型;
85
+ 如果不是图片格式,返回List[OutServer]类型;如果未找到服务器组,返回None。
86
+
87
+ """
88
+ if command:
89
+ server_json = ALLHOST.get(command)
90
+ else:
91
+ server_json = []
92
+ for servers in ALLHOST.values():
93
+ server_json.extend(servers)
94
+
60
95
  logger.info(server_json)
61
96
  if server_json is None:
62
97
  logger.warning("未找到这个组")
@@ -110,100 +145,139 @@ def reload_ip():
110
145
  # print("正在读取json文件")
111
146
  group_ip = []
112
147
  for item in server_all_path.iterdir():
113
- if item.is_file():
114
- if item.name.endswith("json"):
115
- json_data = json.loads(item.read_text(encoding="utf-8"))
116
- group_server = cast(Dict[str, List[NserverOut]], json_data)
117
-
118
- for group, group_ip in group_server.items():
119
- # 处理ip,host,port关系
120
- for one_ip in group_ip:
121
- if one_ip.get("ip"):
122
- if one_ip.get("host") and one_ip.get("port"):
123
- pass
124
- if one_ip.get("host") and not one_ip.get("port"):
125
- one_ip["port"] = 20715
126
- if not one_ip.get("host"):
127
- one_ip["host"], one_ip["port"] = split_maohao(
128
- one_ip.get("ip"),
129
- )
148
+ if item.is_file() and item.name.endswith("json"):
149
+ json_data = json.loads(item.read_text(encoding="utf-8"))
150
+ group_server = cast(Dict[str, List[NserverOut]], json_data)
151
+
152
+ for group, group_ip in group_server.items():
153
+ # 处理ip,host,port关系
154
+ for one_ip in group_ip:
155
+ if one_ip.get("ip"):
156
+ if one_ip.get("host") and one_ip.get("port"):
157
+ pass
158
+ if one_ip.get("host") and not one_ip.get("port"):
159
+ one_ip["port"] = 20715
160
+ if not one_ip.get("host"):
161
+ one_ip["host"], one_ip["port"] = split_maohao(
162
+ one_ip.get("ip"),
163
+ )
164
+ else:
165
+ if one_ip.get("host") and one_ip.get("port"):
166
+ one_ip["ip"] = f'{one_ip["host"]}:{one_ip["port"]}'
167
+ if one_ip.get("host") and not one_ip.get("port"):
168
+ one_ip["ip"] = f'{one_ip["host"]}:20715'
130
169
  else:
131
- if one_ip.get("host") and one_ip.get("port"):
132
- one_ip["ip"] = f'{one_ip["host"]}:{one_ip["port"]}'
133
- if one_ip.get("host") and not one_ip.get("port"):
134
- one_ip["ip"] = f'{one_ip["host"]}:20715'
135
- else:
136
- logger.warning(f"{one_ip} 没有ip")
170
+ logger.warning(f"{one_ip} 没有ip")
137
171
 
138
- ALLHOST.update({group: group_ip})
139
- COMMAND.add(group)
140
- logger.success(f"成功加载 {item.name.split('.')[0]} {len(group_ip)}个")
172
+ ALLHOST.update({group: group_ip})
173
+ COMMAND.add(group)
174
+ logger.success(f"成功加载 {item.name.split('.')[0]} {len(group_ip)}个")
141
175
 
142
- if item.name.endswith("txt"):
143
- """to do"""
144
176
 
145
- async def tj_request(command: str = "云",tj ="tj"):
177
+ async def tj_request(command: str = "云", tj="tj"):
178
+ map_type = "普通药役"
146
179
  server_json = ALLHOST.get(command)
147
180
  logger.info(server_json)
148
181
  if server_json is None:
149
182
  logger.warning("未找到这个组")
150
- return None
151
- # 返回单个
152
- logger.info("正在anne电信服务器信息")
183
+ return None
184
+
185
+ logger.info("正在获取电信服务器信息")
153
186
  player_msg = ""
154
187
  right_ip = []
155
- for i in server_json:
156
- ser_list = await L4API.a2s_info([(i["host"], i["port"])], is_player=True)
188
+
189
+ async def _filter_servers(servers: list, tj_mode: str) -> list:
190
+ """筛选符合条件的服务器
191
+ Args:
192
+ servers: 服务器列表
193
+ tj_mode: 筛选模式('tj'或'zl')
194
+ Returns:
195
+ 符合条件的服务器列表
196
+ """
197
+ filtered = []
198
+ for i in servers:
199
+ ser_list = await L4API.a2s_info([(i["host"], i["port"])], is_player=True)
200
+ if not ser_list:
201
+ continue
202
+
203
+ srv = ser_list[0][0]
204
+ players = ser_list[0][1]
205
+
206
+ if tj_mode == "tj" and map_type in srv.map_name:
207
+ score = sum(p.score for p in players[:4])
208
+ t = srv.map_name.split("[")[-1].split("特")[0]
209
+ if t.isdigit() and int(t) * 50 < score:
210
+ logger.info(
211
+ f"符合TJ条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 分数: {score}",
212
+ )
213
+ filtered.append(i)
214
+ elif tj_mode == "zl" and map_type in srv.map_name and len(players) <= 4:
215
+ logger.info(
216
+ f"符合ZL条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 玩家数: {len(players)}",
217
+ )
218
+ filtered.append(i)
219
+ return filtered
220
+
221
+ async def _format_players(player_list: list) -> str:
222
+ """格式化玩家信息
223
+ Args:
224
+ player_list: 玩家对象列表
225
+ Returns:
226
+ 格式化后的玩家信息字符串
227
+ """
228
+ durations = [await convert_duration(p.duration) for p in player_list]
229
+ max_duration_len = max(len(str(d)) for d in durations)
230
+ max_score_len = max(len(str(p.score)) for p in player_list)
231
+ return "\n".join(
232
+ f"[{p.score:>{max_score_len}}] | {durations[i]:^{max_duration_len}} | {p.name[0]}***{p.name[-1]}"
233
+ for i, p in enumerate(player_list)
234
+ )
235
+
236
+ def _build_message(srv_info, players_msg: str, selected_srv: dict) -> str:
237
+ """构建服务器信息消息
238
+ Args:
239
+ srv_info: 服务器信息对象
240
+ players_msg: 格式化后的玩家信息
241
+ selected_srv: 选中的服务器信息
242
+ Returns:
243
+ 完整的消息字符串
244
+ """
245
+ msg = f"""*{srv_info.server_name}*
246
+ 游戏: {srv_info.folder}
247
+ 地图: {srv_info.map_name}
248
+ 人数: {srv_info.player_count}/{srv_info.max_players}"""
249
+ if srv_info.ping is not None:
250
+ msg += f"\nping: {srv_info.ping * 1000:.0f}ms\n{players_msg}"
251
+ if config.l4_show_ip:
252
+ msg += f"\nconnect {selected_srv['host']}:{selected_srv['port']}"
253
+ return msg
254
+
255
+ try:
256
+ right_ip = await _filter_servers(server_json, tj)
257
+
258
+ if not right_ip:
259
+ logger.warning("没有找到符合条件的服务器")
260
+ return "没有符合条件的服务器"
261
+
262
+ logger.info(
263
+ f"符合条件的服务器列表: {[f'{ip['host']}:{ip['port']}' for ip in right_ip]}",
264
+ )
265
+ s = random.choice(right_ip)
266
+ logger.info(f"最终选择的服务器: {s['host']}:{s['port']}")
267
+ ser_list = await L4API.a2s_info([(s["host"], s["port"])], is_player=True)
268
+ if not ser_list:
269
+ return "获取服务器信息失败"
270
+
157
271
  one_server = ser_list[0][0]
158
272
  one_player = ser_list[0][1]
159
-
160
- # 判断坐牢条件
161
- if tj == "tj":
162
- if "普通药役" in one_server.map_name:
163
- score: int = 0
164
- for index, player in enumerate(one_player, 1):
165
- if index > 4:
166
- break
167
- score += player.score
168
-
169
- t = one_server.map_name.split("[")[-1].split("特")[0]
170
- if int(t)*50 < score:
171
- right_ip.append(i)
172
- if tj == "zl":
173
- if "普通药役" in one_server.map_name and len(one_player) <= 4:
174
- right_ip.append(i)
175
-
176
-
177
- if not right_ip:
178
- return "没有符合条件的服务器"
179
-
180
- s = random.choice(right_ip)
181
- ser_list = await L4API.a2s_info([(s["host"], s["port"])], is_player=True)
182
- one_server = ser_list[0][0]
183
- one_player = ser_list[0][1]
184
- if len(one_player):
185
- max_duration_len = max(
186
- [len(str(await convert_duration(i.duration))) for i in one_player],
187
- )
188
- max_score_len = max(len(str(i.score)) for i in one_player)
189
-
190
- for player in one_player:
191
- soc = "[{:>{}}]".format(player.score, max_score_len)
192
- chines_dur = await convert_duration(player.duration)
193
- dur = "{:^{}}".format(chines_dur, max_duration_len)
194
- name = f"{player.name[0]}***{player.name[-1]}"
195
- player_msg += f"{soc} | {dur} | {name} \n"
196
- else:
197
- player_msg = "服务器感觉很安静啊"
198
- msg = f"""*{one_server.server_name}*
199
- 游戏: {one_server.folder}
200
- 地图: {one_server.map_name}
201
- 人数: {one_server.player_count}/{one_server.max_players}"""
202
- if one_server.ping is not None:
203
- msg += f"""
204
- ping: {one_server.ping * 1000:.0f}ms
205
- {player_msg}"""
206
- if config.l4_show_ip:
207
- msg += f"""
208
- connect {s["host"]}:{s["port"]}"""
209
- return msg
273
+
274
+ if one_player:
275
+ player_msg = await _format_players(one_player)
276
+ else:
277
+ player_msg = "服务器感觉很安静啊"
278
+
279
+ return _build_message(one_server, player_msg, s)
280
+
281
+ except Exception as e:
282
+ logger.error(f"tj_request error: {e}")
283
+ return "获取服务器信息时出错"
@@ -32,7 +32,7 @@ async def draw_one_ip(host: str, port: int):
32
32
  name_leg = len(player.name)
33
33
  if name_leg > 2:
34
34
  xing = "*" * (name_leg - 2)
35
- name = f"{player.name[0]}xing{player.name[-1]}"
35
+ name = f"{player.name[0]}{xing}{player.name[-1]}"
36
36
  else:
37
37
  name = player.name
38
38
  player_msg += f"{soc} | {dur} | {name} \n"
@@ -77,6 +77,12 @@ async def get_much_server(server_json: List[NserverOut], command: str):
77
77
 
78
78
 
79
79
  async def convert_duration(duration: float) -> str:
80
+ """Convert duration in seconds to human-readable string format (e.g. '1h 30m 15s')
81
+ Args:
82
+ duration: Duration in seconds
83
+ Returns:
84
+ Formatted time string
85
+ """
80
86
  minutes, seconds = divmod(duration, 60)
81
87
  hours, minutes = divmod(minutes, 60)
82
88
  time_str = ""
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from typing import Any, Dict, List, Literal, Optional, Tuple, cast
7
7
 
8
8
  import a2s
9
+ import aiofiles
9
10
  import ujson as js
10
11
  import ujson as json
11
12
  from bs4 import BeautifulSoup
@@ -28,6 +29,8 @@ from .models import (
28
29
  SourceBansInfo,
29
30
  )
30
31
 
32
+ config_path = Path(config.l4_path) / "config.json"
33
+
31
34
 
32
35
  class L4D2Api:
33
36
  ssl_verify = False
@@ -76,11 +79,11 @@ class L4D2Api:
76
79
  is_server: bool,
77
80
  is_player: bool,
78
81
  ):
79
- server: a2s.SourceInfo = a2s.SourceInfo()
80
82
  play: List[a2s.Player] = []
81
83
  if is_server:
82
84
  try:
83
- server = await a2s.ainfo(ip)
85
+ server: a2s.SourceInfo = await a2s.ainfo(ip, timeout=3, encoding="utf8")
86
+
84
87
  if server is not None:
85
88
  server.steam_id = index
86
89
 
@@ -89,6 +92,25 @@ class L4D2Api:
89
92
  ConnectionRefusedError,
90
93
  socket.gaierror,
91
94
  ):
95
+ server: a2s.SourceInfo = a2s.SourceInfo(
96
+ protocol=0,
97
+ server_name="服务器无响应",
98
+ map_name="无",
99
+ folder="m",
100
+ game="L4D2",
101
+ app_id=114514,
102
+ steam_id=index,
103
+ player_count=0,
104
+ max_players=0,
105
+ bot_count=0,
106
+ server_type="w",
107
+ platform="w",
108
+ password_protected=False,
109
+ vac_enabled=False,
110
+ version="1.0",
111
+ edf=0,
112
+ ping=0,
113
+ )
92
114
  server.steam_id = index
93
115
  server.player_count = 0
94
116
  server.max_players = 0
@@ -103,7 +125,7 @@ class L4D2Api:
103
125
  ConnectionRefusedError,
104
126
  socket.gaierror,
105
127
  ):
106
- play = await a2s.aplayers(ip)
128
+ play = await a2s.aplayers(ip, timeout=3, encoding="utf8")
107
129
  return server, play
108
130
 
109
131
  async def _server_request(
@@ -158,7 +180,7 @@ class L4D2Api:
158
180
  html_content = resp.content
159
181
  return BeautifulSoup(html_content, "lxml")
160
182
 
161
- async def get_sourceban(self, tag:str = "云", url: str = anne_ban):
183
+ async def get_sourceban(self, tag: str = "云", url: str = anne_ban):
162
184
  """从sourceban++获取服务器列表,目前未做名称处理"""
163
185
  if not (url.startswith(("http://", "https://"))):
164
186
  url = "http://" + url # 默认添加 http://
@@ -184,23 +206,25 @@ class L4D2Api:
184
206
  )
185
207
 
186
208
  if not Path(Path(config.l4_path) / "config.json").is_file():
187
- with Path(Path(config.l4_path) / "config.json").open("w") as f:
188
- f.write("{}")
209
+ async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
210
+ await f.write("{}")
189
211
  with (Path(config.l4_path) / "config.json").open("r", encoding="utf-8") as f:
190
212
  content = f.read().strip()
191
213
  ip_json = json.loads(content)
192
214
  if tag in ip_json:
193
215
  url = ip_json[tag]
194
- with (Path(Path(config.l4_path) / f"l4d2/{tag}.json")).open("w") as f:
216
+ tag_path = Path(Path(config.l4_path) / f"l4d2/{tag}.json")
217
+
218
+ async with aiofiles.open(tag_path, "w", encoding="utf-8") as f:
195
219
  print(Path(Path(config.l4_path) / f"l4d2/{tag}.json"))
196
220
  up_data = {}
197
221
  for server in server_list:
198
222
  new_dict = {}
199
- new_dict["id"] = int(server.index )+ 1
223
+ new_dict["id"] = int(server.index) + 1
200
224
  new_dict["ip"] = server.host + ":" + str(server.port)
201
225
  up_data.update(new_dict)
202
226
  print(up_data)
203
- json.dump(up_data, f)
227
+ json.dump(up_data, f, ensure_ascii=False, indent=4)
204
228
  return server_list
205
229
 
206
230
  async def get_anne_steamid(self, name: str):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-l4d2-server
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: L4D2 server related operations plugin for NoneBot2
5
5
  Keywords: steam,game,l4d2,nonebot2,plugin
6
6
  Author-Email: Agnes_Digital <Z735803792@163.com>
@@ -11,10 +11,12 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.9
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
14
15
  Classifier: Operating System :: OS Independent
15
16
  Project-URL: homepage, https://github.com/Agnes4m/nonebot_plugin_l4d2_server
16
17
  Requires-Python: <4.0,>=3.9
17
18
  Requires-Dist: nonebot2>=2.0.0
19
+ Requires-Dist: nonebot2[fastapi]>=2.3.3
18
20
  Requires-Dist: nonebot-plugin-htmlrender>=0.3.0
19
21
  Requires-Dist: nonebot-adapter-onebot>=2.4.4
20
22
  Requires-Dist: nonebot-plugin-alconna>=0.50.0
@@ -25,12 +27,15 @@ Requires-Dist: jinja2>=3.0.0
25
27
  Requires-Dist: srctools>=2.3.9
26
28
  Requires-Dist: httpx<0.24.1,>=0.22.0
27
29
  Requires-Dist: msgspec>=0.18.0
28
- Requires-Dist: python-a2s>=1.3.0
30
+ Requires-Dist: python-a2s>=1.4.1
29
31
  Requires-Dist: ujson>=5.10.0
30
32
  Requires-Dist: lxml>=5.2.2
31
33
  Requires-Dist: rcon>=2.1.0
32
- Requires-Dist: pillow>9
34
+ Requires-Dist: pillow>10
33
35
  Requires-Dist: beautifulsoup4>=4.12.3
36
+ Requires-Dist: rarfile>=4.2
37
+ Requires-Dist: pyunpack>=0.3
38
+ Requires-Dist: aiofiles>=24.1.0
34
39
  Description-Content-Type: text/markdown
35
40
 
36
41
  <!-- markdownlint-disable MD026 MD031 MD033 MD036 MD041 MD046 MD051 -->
@@ -1,15 +1,15 @@
1
- nonebot_plugin_l4d2_server-1.0.1.dist-info/METADATA,sha256=qUgbCb3s-Ok_j3XIc9tpnUJbl7i-mW8TwDoDVd9Ep90,6507
2
- nonebot_plugin_l4d2_server-1.0.1.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- nonebot_plugin_l4d2_server-1.0.1.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- nonebot_plugin_l4d2_server-1.0.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1
+ nonebot_plugin_l4d2_server-1.0.3.dist-info/METADATA,sha256=po5LeZo-Nk7oQNuaxa5Ve_3AANnFc4RxG8fnBbcqeK0,6688
2
+ nonebot_plugin_l4d2_server-1.0.3.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
+ nonebot_plugin_l4d2_server-1.0.3.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ nonebot_plugin_l4d2_server-1.0.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
5
5
  nonebot_plugin_l4d2_server/__init__.py,sha256=PIufOk1bxOx-nYqdoinoB7BcntIETNFwfzqKnmu-teE,1624
6
- nonebot_plugin_l4d2_server/__main__.py,sha256=8bIrOWQo9tZA1VdPiUzGe_akSea-C4OWRw7AX7T9F5E,7956
7
- nonebot_plugin_l4d2_server/config.py,sha256=CavZ4EGdLvooVrUeP8zGsbZ0TJNsxGl2WT9rpyJtvhw,1175
6
+ nonebot_plugin_l4d2_server/__main__.py,sha256=AGqPjt0O6dW_E3D93hcqehtsPsvzSRC1qEtx6HqEAGo,8455
7
+ nonebot_plugin_l4d2_server/config.py,sha256=ZLYJr9lVs1Q5en1m4EA0wF7H366EVm8-6AnN8dcyy7c,1394
8
8
  nonebot_plugin_l4d2_server/data/font/loli.ttf,sha256=Yrh-RPoCrn1-NG94DR0x20ASXYUt8g3Ep6BCt3CdOFk,11125812
9
9
  nonebot_plugin_l4d2_server/l4_anne/__init__.py,sha256=zX4kTu4LAsqm7_li0-GcihnbYI65SBPkfUCPTs79U8k,4124
10
10
  nonebot_plugin_l4d2_server/l4_anne/ranne.py,sha256=vtNQJ-74rJiwVI3IYS3ZgFk_LaCviKU1yxrGk3DFvQs,532
11
11
  nonebot_plugin_l4d2_server/l4_help/Help.json,sha256=hz_k-qmGmGJKwCa8wmkHTLzXu6C-G-E_g7xdK-t6fNk,2673
12
- nonebot_plugin_l4d2_server/l4_help/__init__.py,sha256=UJZpNCbZY5_jkY_SsTWjy1Et4CzGGBkjckoCeKUsVJM,1535
12
+ nonebot_plugin_l4d2_server/l4_help/__init__.py,sha256=YNR3eob0XvRb_-4wIP9ZcSMey0RuFS4RlHMZ217Bn0E,1535
13
13
  nonebot_plugin_l4d2_server/l4_help/draw.py,sha256=y6yDPUnoZFvwly8cf7g9HRpT1JXTxyA9DC1TuvUinTM,6448
14
14
  nonebot_plugin_l4d2_server/l4_help/icon/介绍.png,sha256=3QC6A38QC-7gDBxmtQSQdbsz7hsefU5LL-oZmJ41zTk,3806
15
15
  nonebot_plugin_l4d2_server/l4_help/icon/任务.png,sha256=nyZ4_kM21ZO95nwanCFnUfCGX-PkmJXYQf9OrJVKomY,3782
@@ -86,14 +86,14 @@ nonebot_plugin_l4d2_server/l4_image/img/template/vue.css,sha256=2sGjCFrR-3tFMB_x
86
86
  nonebot_plugin_l4d2_server/l4_image/img/template/w.svg,sha256=LnctC2mVwjdhRMiS9ffrjUX-9KGwqb6OMmpJXvVXl70,486
87
87
  nonebot_plugin_l4d2_server/l4_image/model.py,sha256=FGsCvf_BKbRNJUVy6I5BKnArMY-3JEIdqeX2gs93E5o,231
88
88
  nonebot_plugin_l4d2_server/l4_image/vtfs.py,sha256=He_7zzEIOip8MXP55TS7aWPbzo6ac0wPf602nN3GWZM,1461
89
- nonebot_plugin_l4d2_server/l4_local/__init__.py,sha256=09AnKq-D5rM4pdDGXOWtbXdpSnghliEU7sR-kubqf00,3588
89
+ nonebot_plugin_l4d2_server/l4_local/__init__.py,sha256=nz9KUxmuvRrryHakQQ4B30oC9jeGWZ3sON1tCKb-lS0,3603
90
90
  nonebot_plugin_l4d2_server/l4_local/file.py,sha256=hew1Y8kV3uSZvUGplmi09EGKC89-sUJWsWV7SCEstI8,3067
91
- nonebot_plugin_l4d2_server/l4_request/__init__.py,sha256=sS0X4R2eW-GFjXZKt3z6hV69qQNPM7JqZjsq0S7Pahg,7180
92
- nonebot_plugin_l4d2_server/l4_request/draw_msg.py,sha256=92_UaCpXNP-8wowuJ1JYkQi-Rw0DVJiNq_S4wZ0SaOE,2695
91
+ nonebot_plugin_l4d2_server/l4_request/__init__.py,sha256=ukb90pROfHtLbIRSya5pRAGSpzB9Bb5gPi3kAH2-41Y,9588
92
+ nonebot_plugin_l4d2_server/l4_request/draw_msg.py,sha256=efmlEBqbbOozf50InPNqONGIZ0D2hI4xAGPDROIcHBY,2883
93
93
  nonebot_plugin_l4d2_server/l4_request/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
94
  nonebot_plugin_l4d2_server/utils/api/api.py,sha256=auvDicCEKwvnm6EJYeCxCtugFby61K-zAmmaRWWEwtM,296
95
95
  nonebot_plugin_l4d2_server/utils/api/models.py,sha256=EKAAM5RsFK-hV-a80tc4r35ToNRhnCWVuQ-7imwBjwE,2386
96
- nonebot_plugin_l4d2_server/utils/api/request.py,sha256=LVC7wZN9r5_VjFnMzuETmppaMOOmDsNxUE12TKlnmKI,14112
96
+ nonebot_plugin_l4d2_server/utils/api/request.py,sha256=hugBaPBK-gUr5Xemyk7dSHP1JlzYrEZcXPinkNX0AuU,14987
97
97
  nonebot_plugin_l4d2_server/utils/database/models.py,sha256=SLdcgwsn39r_ZkcBoqf4MLX1EfpCOjGBwWcR16u9Bqo,454
98
98
  nonebot_plugin_l4d2_server/utils/utils.py,sha256=C-QzwtUCbq7QXmHplpmo3OTKbRztE1W7V-IywvufDl0,5971
99
- nonebot_plugin_l4d2_server-1.0.1.dist-info/RECORD,,
99
+ nonebot_plugin_l4d2_server-1.0.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.3)
2
+ Generator: pdm-backend (2.4.4)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any