nonebot-plugin-l4d2-server 1.0.0a1__py3-none-any.whl → 1.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. nonebot_plugin_l4d2_server/__init__.py +4 -4
  2. nonebot_plugin_l4d2_server/__main__.py +65 -14
  3. nonebot_plugin_l4d2_server/config.py +11 -0
  4. nonebot_plugin_l4d2_server/l4_anne/__init__.py +125 -0
  5. nonebot_plugin_l4d2_server/l4_anne/ranne.py +18 -0
  6. nonebot_plugin_l4d2_server/l4_help/Help.json +67 -22
  7. nonebot_plugin_l4d2_server/l4_help/__init__.py +2 -2
  8. nonebot_plugin_l4d2_server/l4_help/icon//344/273/213/347/273/215.png +0 -0
  9. nonebot_plugin_l4d2_server/l4_help/icon//344/273/273/345/212/241.png +0 -0
  10. nonebot_plugin_l4d2_server/l4_help/icon//344/277/241/346/201/257.png +0 -0
  11. nonebot_plugin_l4d2_server/l4_help/icon//345/205/254/345/221/212.png +0 -0
  12. nonebot_plugin_l4d2_server/l4_help/icon//345/210/200/345/211/221.png +0 -0
  13. nonebot_plugin_l4d2_server/l4_help/icon//345/210/207/346/215/242.png +0 -0
  14. nonebot_plugin_l4d2_server/l4_help/icon//345/210/240/351/231/244.png +0 -0
  15. nonebot_plugin_l4d2_server/l4_help/icon//345/210/267/346/226/260.png +0 -0
  16. nonebot_plugin_l4d2_server/l4_help/icon//345/215/241/347/273/204.png +0 -0
  17. nonebot_plugin_l4d2_server/l4_help/icon//345/223/252/351/207/214.png +0 -0
  18. nonebot_plugin_l4d2_server/l4_help/icon//345/234/260/345/233/276.png +0 -0
  19. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/205/245.png +0 -0
  20. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/207/272.png +0 -0
  21. nonebot_plugin_l4d2_server/l4_help/icon//345/275/261.png +0 -0
  22. nonebot_plugin_l4d2_server/l4_help/icon//346/213/274/345/233/276.png +0 -0
  23. nonebot_plugin_l4d2_server/l4_help/icon//346/216/242/347/264/242.png +0 -0
  24. nonebot_plugin_l4d2_server/l4_help/icon//346/216/250/351/200/201.png +0 -0
  25. nonebot_plugin_l4d2_server/l4_help/icon//346/224/266/351/233/206.png +0 -0
  26. nonebot_plugin_l4d2_server/l4_help/icon//346/224/273/347/225/245.png +0 -0
  27. nonebot_plugin_l4d2_server/l4_help/icon//346/233/264/346/226/260.png +0 -0
  28. nonebot_plugin_l4d2_server/l4_help/icon//346/235/220/346/226/231.png +0 -0
  29. nonebot_plugin_l4d2_server/l4_help/icon//346/237/245/350/257/242.png +0 -0
  30. nonebot_plugin_l4d2_server/l4_help/icon//346/240/241/351/252/214.png +0 -0
  31. nonebot_plugin_l4d2_server/l4_help/icon//346/257/217/346/234/210.png +0 -0
  32. nonebot_plugin_l4d2_server/l4_help/icon//346/267/261/346/270/212.png +0 -0
  33. nonebot_plugin_l4d2_server/l4_help/icon//346/267/273/345/212/240.png +0 -0
  34. nonebot_plugin_l4d2_server/l4_help/icon//346/270/205/351/231/244.png +0 -0
  35. nonebot_plugin_l4d2_server/l4_help/icon//347/212/266/346/200/201.png +0 -0
  36. nonebot_plugin_l4d2_server/l4_help/icon//347/255/276/345/210/260.png +0 -0
  37. nonebot_plugin_l4d2_server/l4_help/icon//347/273/221/345/256/232.png +0 -0
  38. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250.png +0 -0
  39. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250/346/203/205.png +0 -0
  40. nonebot_plugin_l4d2_server/l4_help/icon//350/247/222/350/211/262.png +0 -0
  41. nonebot_plugin_l4d2_server/l4_help/icon//350/256/260/345/275/225.png +0 -0
  42. nonebot_plugin_l4d2_server/l4_help/icon//351/205/215/347/275/256.png +0 -0
  43. nonebot_plugin_l4d2_server/l4_help/icon//351/207/215/345/220/257.png +0 -0
  44. nonebot_plugin_l4d2_server/l4_help/texture2d/badge.png +0 -0
  45. nonebot_plugin_l4d2_server/l4_help/texture2d/banner.png +0 -0
  46. nonebot_plugin_l4d2_server/l4_help/texture2d/bg.jpg +0 -0
  47. nonebot_plugin_l4d2_server/l4_help/texture2d/button.png +0 -0
  48. nonebot_plugin_l4d2_server/l4_help/texture2d/icon.png +0 -0
  49. nonebot_plugin_l4d2_server/l4_image/__init__.py +4 -4
  50. nonebot_plugin_l4d2_server/l4_image/anne_pil.py +18 -0
  51. nonebot_plugin_l4d2_server/l4_image/convert.py +9 -13
  52. nonebot_plugin_l4d2_server/l4_image/download.py +9 -7
  53. nonebot_plugin_l4d2_server/l4_image/html_img.py +47 -76
  54. nonebot_plugin_l4d2_server/l4_image/image_tools.py +19 -16
  55. nonebot_plugin_l4d2_server/l4_image/img/anne/back.png +0 -0
  56. nonebot_plugin_l4d2_server/l4_image/img/anne/back1.jpg +0 -0
  57. nonebot_plugin_l4d2_server/l4_image/img/head/head.png +0 -0
  58. nonebot_plugin_l4d2_server/l4_image/img/header/logo.png +0 -0
  59. nonebot_plugin_l4d2_server/l4_image/img/header/player1.jpg +0 -0
  60. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.html +17 -30
  61. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.png +0 -0
  62. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.html +17 -26
  63. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.png +0 -0
  64. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.html +48 -14
  65. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.png +0 -0
  66. nonebot_plugin_l4d2_server/l4_image/img/template/normal.html +14 -24
  67. nonebot_plugin_l4d2_server/{data/img → l4_image/img/template}/vac.png +0 -0
  68. nonebot_plugin_l4d2_server/l4_image/img/template/vac_white.png +0 -0
  69. nonebot_plugin_l4d2_server/l4_image/vtfs.py +3 -3
  70. nonebot_plugin_l4d2_server/l4_local/__init__.py +94 -0
  71. nonebot_plugin_l4d2_server/l4_local/file.py +105 -0
  72. nonebot_plugin_l4d2_server/l4_request/__init__.py +68 -9
  73. nonebot_plugin_l4d2_server/l4_request/draw_msg.py +38 -43
  74. nonebot_plugin_l4d2_server/l4_request/utils.py +0 -0
  75. nonebot_plugin_l4d2_server/utils/api/api.py +8 -2
  76. nonebot_plugin_l4d2_server/utils/api/models.py +108 -0
  77. nonebot_plugin_l4d2_server/utils/api/request.py +257 -39
  78. nonebot_plugin_l4d2_server/utils/database/models.py +12 -23
  79. nonebot_plugin_l4d2_server/utils/utils.py +22 -11
  80. {nonebot_plugin_l4d2_server-1.0.0a1.dist-info → nonebot_plugin_l4d2_server-1.0.0b1.dist-info}/METADATA +19 -11
  81. nonebot_plugin_l4d2_server-1.0.0b1.dist-info/RECORD +98 -0
  82. nonebot_plugin_l4d2_server/data/L4D2/image/head/head.png +0 -0
  83. nonebot_plugin_l4d2_server/data/L4D2/image/header/logo.png +0 -0
  84. nonebot_plugin_l4d2_server/data/L4D2/image/header/player1.jpg +0 -0
  85. nonebot_plugin_l4d2_server/data/L4D2/image/template/anne.html +0 -68
  86. nonebot_plugin_l4d2_server/data/L4D2/image/template/back.png +0 -0
  87. nonebot_plugin_l4d2_server/data/L4D2/image/template/fingerprint.svg +0 -15
  88. nonebot_plugin_l4d2_server/data/L4D2/image/template/group_ip.html +0 -258
  89. nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +0 -262
  90. nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +0 -269
  91. nonebot_plugin_l4d2_server/data/L4D2/image/template/ip.html +0 -54
  92. nonebot_plugin_l4d2_server/data/L4D2/image/template/l.svg +0 -10
  93. nonebot_plugin_l4d2_server/data/L4D2/image/template/m.svg +0 -1
  94. nonebot_plugin_l4d2_server/data/L4D2/image/template/vue.css +0 -531
  95. nonebot_plugin_l4d2_server/data/L4D2/image/template/w.svg +0 -1
  96. nonebot_plugin_l4d2_server/data/icon//344/273/213/347/273/215.png +0 -0
  97. nonebot_plugin_l4d2_server/data/icon//344/273/273/345/212/241.png +0 -0
  98. nonebot_plugin_l4d2_server/data/icon//344/277/241/346/201/257.png +0 -0
  99. nonebot_plugin_l4d2_server/data/icon//345/205/254/345/221/212.png +0 -0
  100. nonebot_plugin_l4d2_server/data/icon//345/210/200/345/211/221.png +0 -0
  101. nonebot_plugin_l4d2_server/data/icon//345/210/207/346/215/242.png +0 -0
  102. nonebot_plugin_l4d2_server/data/icon//345/210/240/351/231/244.png +0 -0
  103. nonebot_plugin_l4d2_server/data/icon//345/210/267/346/226/260.png +0 -0
  104. nonebot_plugin_l4d2_server/data/icon//345/215/241/347/273/204.png +0 -0
  105. nonebot_plugin_l4d2_server/data/icon//345/223/252/351/207/214.png +0 -0
  106. nonebot_plugin_l4d2_server/data/icon//345/234/260/345/233/276.png +0 -0
  107. nonebot_plugin_l4d2_server/data/icon//345/257/274/345/205/245.png +0 -0
  108. nonebot_plugin_l4d2_server/data/icon//345/257/274/345/207/272.png +0 -0
  109. nonebot_plugin_l4d2_server/data/icon//345/275/261.png +0 -0
  110. nonebot_plugin_l4d2_server/data/icon//346/213/274/345/233/276.png +0 -0
  111. nonebot_plugin_l4d2_server/data/icon//346/216/242/347/264/242.png +0 -0
  112. nonebot_plugin_l4d2_server/data/icon//346/216/250/351/200/201.png +0 -0
  113. nonebot_plugin_l4d2_server/data/icon//346/224/266/351/233/206.png +0 -0
  114. nonebot_plugin_l4d2_server/data/icon//346/224/273/347/225/245.png +0 -0
  115. nonebot_plugin_l4d2_server/data/icon//346/233/264/346/226/260.png +0 -0
  116. nonebot_plugin_l4d2_server/data/icon//346/235/220/346/226/231.png +0 -0
  117. nonebot_plugin_l4d2_server/data/icon//346/237/245/350/257/242.png +0 -0
  118. nonebot_plugin_l4d2_server/data/icon//346/240/241/351/252/214.png +0 -0
  119. nonebot_plugin_l4d2_server/data/icon//346/257/217/346/234/210.png +0 -0
  120. nonebot_plugin_l4d2_server/data/icon//346/267/261/346/270/212.png +0 -0
  121. nonebot_plugin_l4d2_server/data/icon//346/267/273/345/212/240.png +0 -0
  122. nonebot_plugin_l4d2_server/data/icon//346/270/205/351/231/244.png +0 -0
  123. nonebot_plugin_l4d2_server/data/icon//347/212/266/346/200/201.png +0 -0
  124. nonebot_plugin_l4d2_server/data/icon//347/255/276/345/210/260.png +0 -0
  125. nonebot_plugin_l4d2_server/data/icon//347/273/221/345/256/232.png +0 -0
  126. nonebot_plugin_l4d2_server/data/icon//350/241/250.png +0 -0
  127. nonebot_plugin_l4d2_server/data/icon//350/241/250/346/203/205.png +0 -0
  128. nonebot_plugin_l4d2_server/data/icon//350/247/222/350/211/262.png +0 -0
  129. nonebot_plugin_l4d2_server/data/icon//350/256/260/345/275/225.png +0 -0
  130. nonebot_plugin_l4d2_server/data/icon//351/205/215/347/275/256.png +0 -0
  131. nonebot_plugin_l4d2_server/data/icon//351/207/215/345/220/257.png +0 -0
  132. nonebot_plugin_l4d2_server/data/img/l4d2.png +0 -0
  133. nonebot_plugin_l4d2_server/data/img/linux.png +0 -0
  134. nonebot_plugin_l4d2_server/data/img/white.png +0 -0
  135. nonebot_plugin_l4d2_server/l4_image/img/template//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  136. nonebot_plugin_l4d2_server-1.0.0a1.dist-info/RECORD +0 -144
  137. {nonebot_plugin_l4d2_server-1.0.0a1.dist-info → nonebot_plugin_l4d2_server-1.0.0b1.dist-info}/WHEEL +0 -0
  138. {nonebot_plugin_l4d2_server-1.0.0a1.dist-info → nonebot_plugin_l4d2_server-1.0.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,4 @@
1
+ # coding=utf-8
1
2
  from typing import List, Optional, TypedDict
2
3
 
3
4
  import a2s
@@ -27,3 +28,110 @@ class OutServer(TypedDict):
27
28
  port: int
28
29
  command: str
29
30
  id_: int
31
+
32
+
33
+ class AnnePlayer(TypedDict):
34
+ mode: str
35
+ name: str
36
+ source: str
37
+ playtime: str
38
+
39
+
40
+ class AllServer(TypedDict):
41
+ command: str
42
+ active_server: int
43
+ max_server: int
44
+ active_player: int
45
+ max_player: int
46
+
47
+
48
+ class AnneSearch(TypedDict):
49
+ steamid: str
50
+ rank: str
51
+ name: str
52
+ score: str
53
+ play_time: str
54
+ last_time: str
55
+
56
+
57
+ class AnnePlayerDetail(TypedDict):
58
+ rank: int
59
+ source: str
60
+ avg_source: float
61
+ kills: str
62
+ kills_people: str
63
+ headshots: str
64
+ avg_headshots: float
65
+ map_play: str
66
+
67
+
68
+ class AnnePlayerError(TypedDict):
69
+ mistake_shout: str
70
+ kill_friend: str
71
+ down_friend: str
72
+ abandon_friend: str
73
+ put_into: str
74
+ agitate_witch: str
75
+
76
+
77
+ class AnnePlayerInfAvg(TypedDict):
78
+ avg_smoker: float
79
+ avg_boomer: float
80
+ avg_hunter: float
81
+ avg_charger: float
82
+ avg_spitter: float
83
+ avg_jockey: float
84
+ avg_tank: float
85
+
86
+
87
+ class AnnePlayerSur(TypedDict):
88
+ map_clear: str
89
+ prefect_into: str
90
+ get_oil: str
91
+ ammo_arrange: str
92
+ adrenaline_give: str
93
+ pills_give: str
94
+ """给药"""
95
+ first_aid_give: str
96
+ """给包"""
97
+ friend_up: str
98
+ diss_friend: str
99
+ save_friend: str
100
+ protect_friend: str
101
+ pro_from_smoker: str
102
+ pro_from_hunter: str
103
+ pro_from_charger: str
104
+ pro_from_jockey: str
105
+ melee_charge: str
106
+ """刀牛"""
107
+ tank_kill: str
108
+ witch_instantly_kill: str
109
+ """秒妹"""
110
+
111
+
112
+ class AnnePlayerInf(TypedDict):
113
+ sur_ace: str
114
+ sur_down: str
115
+ boommer_hit: str
116
+ hunter_prefect: str
117
+ hunter_success: str
118
+ tank_damage: str
119
+ charger_multiple: str
120
+
121
+
122
+ class AnnePlayerInfo(TypedDict):
123
+ name: str
124
+ avatar: str
125
+ steamid: str
126
+ playtime: str
127
+ lasttime: str
128
+
129
+
130
+ class AnnePlayer2(TypedDict):
131
+ kill_msg: str
132
+ info: AnnePlayerInfo
133
+ detail: AnnePlayerDetail
134
+ error: AnnePlayerError
135
+ inf_avg: AnnePlayerInfAvg
136
+ sur: AnnePlayerSur
137
+ inf: AnnePlayerInf
@@ -1,14 +1,28 @@
1
- import json as js
1
+ import asyncio
2
+ import contextlib
3
+ import socket
2
4
  from copy import deepcopy
3
- from typing import Any, Dict, List, Literal, Optional, Union
5
+ from typing import Any, Dict, List, Literal, Optional, Tuple, cast
4
6
 
5
7
  import a2s
8
+ import ujson as js
9
+ from bs4 import BeautifulSoup
6
10
  from httpx import AsyncClient
7
- from lxml import etree
8
11
 
12
+ # from nonebot.log import logger
9
13
  from ..utils import split_maohao
10
- from .api import anne_ban
11
- from .models import SourceBansInfo
14
+ from .api import AnnePlayerApi, AnneSearchApi, anne_ban
15
+ from .models import (
16
+ AnnePlayer2,
17
+ AnnePlayerDetail,
18
+ AnnePlayerError,
19
+ AnnePlayerInf,
20
+ AnnePlayerInfAvg,
21
+ AnnePlayerInfo,
22
+ AnnePlayerSur,
23
+ AnneSearch,
24
+ SourceBansInfo,
25
+ )
12
26
 
13
27
 
14
28
  class L4D2Api:
@@ -18,23 +32,75 @@ class L4D2Api:
18
32
  "(KHTML, like Gecko)"
19
33
  "Chrome/126.0.0.0"
20
34
  "Safari/537.36 Edg/126.0.0.0",
35
+ "Content-Type": "application/x-www-form-urlencoded",
21
36
  }
22
37
 
23
38
  async def a2s_info(
24
39
  self,
25
- host: str,
26
- port: int,
27
- ) -> a2s.SourceInfo:
28
- msg: a2s.SourceInfo = await a2s.ainfo((host, port))
29
- return msg
40
+ ip_list: List[Tuple[str, int]],
41
+ is_server: bool = True,
42
+ is_player: bool = False,
43
+ ) -> List[Tuple[a2s.SourceInfo, List[a2s.Player]]]:
44
+ msg_list: List[Tuple[a2s.SourceInfo, List[a2s.Player]]] = []
45
+ sorted_msg_list = []
46
+ tasks = [] # 用来保存异步任务
47
+ if ip_list != []:
48
+ for index, i in enumerate(ip_list):
49
+ try:
50
+ tasks.append(
51
+ asyncio.create_task(
52
+ self.process_message(
53
+ i,
54
+ index,
55
+ is_server,
56
+ is_player,
57
+ ),
58
+ ),
59
+ )
60
+ except ValueError:
61
+ continue # 处理异常情况
62
+
63
+ msg_list = await asyncio.gather(*tasks)
64
+ sorted_msg_list = sorted(msg_list, key=lambda x: x[0].steam_id)
65
+
66
+ return sorted_msg_list
30
67
 
31
- async def a2s_players(
68
+ async def process_message(
32
69
  self,
33
- host: str,
34
- port: int,
35
- ) -> List[a2s.Player]:
36
- msg: List[a2s.Player] = await a2s.aplayers((host, port))
37
- return msg
70
+ ip: Tuple[str, int],
71
+ index: int,
72
+ is_server: bool,
73
+ is_player: bool,
74
+ ):
75
+ server: a2s.SourceInfo = a2s.SourceInfo()
76
+ play: List[a2s.Player] = []
77
+ if is_server:
78
+ try:
79
+ server = await a2s.ainfo(ip)
80
+ if server is not None:
81
+ server.steam_id = index
82
+
83
+ except (
84
+ asyncio.exceptions.TimeoutError,
85
+ ConnectionRefusedError,
86
+ socket.gaierror,
87
+ ):
88
+ server.steam_id = index
89
+ server.player_count = 0
90
+ server.max_players = 0
91
+ server.server_name = "服务器无响应"
92
+ server.map_name = "无"
93
+ server.folder = "m"
94
+ server.vac_enabled = False
95
+
96
+ if is_player:
97
+ with contextlib.suppress(
98
+ asyncio.exceptions.TimeoutError,
99
+ ConnectionRefusedError,
100
+ socket.gaierror,
101
+ ):
102
+ play = await a2s.aplayers(ip)
103
+ return server, play
38
104
 
39
105
  async def _server_request(
40
106
  self,
@@ -45,7 +111,7 @@ class L4D2Api:
45
111
  json: Optional[Dict[str, Any]] = None,
46
112
  data: Optional[Dict[str, Any]] = None,
47
113
  is_json: bool = True,
48
- ) -> Union[Dict, int]:
114
+ ):
49
115
  header = deepcopy(self._HEADER)
50
116
 
51
117
  if json is not None:
@@ -85,35 +151,187 @@ class L4D2Api:
85
151
  ):
86
152
  return raw_data["result"]["error_code"]
87
153
  return raw_data
88
- html_content = resp.text
89
- return etree.HTML(html_content)
154
+ html_content = resp.content
155
+ return BeautifulSoup(html_content, "lxml")
90
156
 
91
- async def get_sourceban(self, name: str, url: str = anne_ban):
92
- tree = await self._server_request(
157
+ async def get_sourceban(self, url: str = anne_ban):
158
+ """从sourceban++获取服务器列表,目前未做名称处理"""
159
+ soup = await self._server_request(
93
160
  url=url,
94
161
  is_json=False,
95
- ) # type: ignore
96
- name = name
97
- # 检查响应状态码
162
+ )
98
163
 
99
- target_element = tree.xpath(
100
- "/html/body/main/div[3]/div[5]/div/div/table/tbody/tr",
164
+ if not isinstance(soup, BeautifulSoup):
165
+ return []
166
+ server_list = []
167
+ tbody = soup.select_one("tbody")
168
+ if tbody is None:
169
+ return []
170
+ tr_tags = tbody.select("tr")
171
+ for index, tr in enumerate(tr_tags):
172
+ td_tags = tr.select("td")
173
+ for num, td in enumerate(td_tags):
174
+ if num == 4:
175
+ host, port = split_maohao(td.text)
176
+ server_list.append(
177
+ SourceBansInfo(index=index, host=host, port=port),
178
+ )
179
+
180
+ return server_list
181
+
182
+ async def get_anne_steamid(self, name: str):
183
+ """从电信anne服搜索昵称获取steamid"""
184
+ soup = await self._server_request(
185
+ url=AnneSearchApi,
186
+ data={"search": name},
187
+ method="POST",
188
+ is_json=False,
101
189
  )
190
+ if not isinstance(soup, BeautifulSoup):
191
+ return None
102
192
  server_list = []
103
- # for tr in target_element:
104
- for tr in target_element:
105
- if tr.get("class") != "collapse":
193
+ tbody = soup.select_one("tbody")
194
+ if tbody is None:
195
+ return None
196
+ tr_tags = tbody.select("tr")
197
+ for tr in tr_tags:
198
+ onclick = tr.get("onclick")
199
+ if onclick is None or isinstance(onclick, list):
106
200
  continue
107
- index = 0
108
- for td in tr.xpath("./td"):
109
- if td.get("id") is not None or td.text == "\n":
110
- continue
111
- index += 1
112
- host, port = split_maohao(td.text)
113
- server_list.append(SourceBansInfo(index=index, host=host, port=port))
114
-
115
- # 通过一次请求,确定服务器的序号
116
- return server_list
201
+ steamid = onclick.split("steamid=")[1].replace("'", "")
202
+ td_tags = tr.select("td")
203
+ server_list.append(
204
+ {
205
+ "steamid": steamid,
206
+ "rank": td_tags[0].text.strip(),
207
+ "name": td_tags[1].text.strip(),
208
+ "score": td_tags[2].text.strip(),
209
+ "play_time": td_tags[3].text.strip(),
210
+ "last_time": td_tags,
211
+ },
212
+ )
213
+ print(server_list)
214
+ return cast(List[AnneSearch], server_list)
215
+
216
+ async def get_anne_playerdetail(self, steamid: str):
217
+ """从电信anne服通过steamid获取战绩"""
218
+ soup = await self._server_request(
219
+ url=AnnePlayerApi,
220
+ method="GET",
221
+ params={"steamid": steamid},
222
+ is_json=False,
223
+ )
224
+ if not isinstance(soup, BeautifulSoup):
225
+ return None
226
+
227
+ tbody = soup.find(
228
+ "div",
229
+ class_="content text-center text-md-left",
230
+ style="background-color: #f2f2f2;",
231
+ )
232
+ if tbody is None:
233
+ return None
234
+ kill_tag = tbody.find(
235
+ "div",
236
+ class_="card-body worldmap d-flex flex-column justify-content-center text-center",
237
+ )
238
+
239
+ tbody_tags = tbody.find_all(
240
+ "table",
241
+ class_="table content-table-noborder text-left",
242
+ )
243
+ print(len(tbody_tags))
244
+ info_tag = tbody_tags[0]
245
+ detail_tag = tbody_tags[1]
246
+ error_tag = tbody_tags[2]
247
+ inf_avg_tag = tbody_tags[3]
248
+ sur_tag = tbody_tags[4]
249
+ inf_tag = tbody_tags[5]
250
+
251
+ info_tr = info_tag.select("tr")
252
+ info_dict = {
253
+ "name": info_tr[0].select("td")[1].text.strip(),
254
+ "avatar": info_tr[1].select("td")[1].text.strip(),
255
+ "steamid": info_tr[2].select("td")[1].text.strip(),
256
+ "playtime": info_tr[3].select("td")[1].text.strip(),
257
+ "lasttime": info_tr[4].select("td")[1].text.strip(),
258
+ }
259
+ detail_tag = {
260
+ "rank": detail_tag.select("tr")[0].select("td")[1].text.strip(),
261
+ "source": detail_tag.select("tr")[1].select("td")[1].text.strip(),
262
+ "avg_source": detail_tag.select("tr")[2].select("td")[1].text.strip(),
263
+ "kills": detail_tag.select("tr")[3].select("td")[1].text.strip(),
264
+ "kills_people": detail_tag.select("tr")[4].select("td")[1].text.strip(),
265
+ "headshots": detail_tag.select("tr")[5].select("td")[1].text.strip(),
266
+ "avg_headshots": detail_tag.select("tr")[6].select("td")[1].text.strip(),
267
+ "map_play": detail_tag.select("tr")[7].select("td")[1].text.strip(),
268
+ }
269
+ error_tag = {
270
+ "mistake_shout": error_tag.select("tr")[0].select("td")[1].text.strip(),
271
+ "kill_friend": error_tag.select("tr")[1].select("td")[1].text.strip(),
272
+ "down_friend": error_tag.select("tr")[2].select("td")[1].text.strip(),
273
+ "abandon_friend": error_tag.select("tr")[3].select("td")[1].text.strip(),
274
+ "put_into": error_tag.select("tr")[4].select("td")[1].text.strip(),
275
+ "agitate_witch": error_tag.select("tr")[5].select("td")[1].text.strip(),
276
+ }
277
+ inf_avg_dict = {
278
+ "avg_smoker": inf_avg_tag.select("tr")[0].select("td")[1].text.strip(),
279
+ "avg_boomer": inf_avg_tag.select("tr")[1].select("td")[1].text.strip(),
280
+ "avg_hunter": inf_avg_tag.select("tr")[2].select("td")[1].text.strip(),
281
+ "avg_charger": inf_avg_tag.select("tr")[3].select("td")[1].text.strip(),
282
+ "avg_spitter": inf_avg_tag.select("tr")[4].select("td")[1].text.strip(),
283
+ "avg_jockey": inf_avg_tag.select("tr")[5].select("td")[1].text.strip(),
284
+ "avg_tank": inf_avg_tag.select("tr")[6].select("td")[1].text.strip(),
285
+ }
286
+ sur_dict = {
287
+ "map_clear": sur_tag.select("tr")[0].select("td")[1].text.strip(),
288
+ "prefect_into": sur_tag.select("tr")[1].select("td")[1].text.strip(),
289
+ "get_oil": sur_tag.select("tr")[2].select("td")[1].text.strip(),
290
+ "ammo_arrange": sur_tag.select("tr")[3].select("td")[1].text.strip(),
291
+ "adrenaline_give": sur_tag.select("tr")[4].select("td")[1].text.strip(),
292
+ "pills_give": sur_tag.select("tr")[5].select("td")[1].text.strip(),
293
+ "first_aid_give": sur_tag.select("tr")[6].select("td")[1].text.strip(),
294
+ "friend_up": sur_tag.select("tr")[7].select("td")[1].text.strip(),
295
+ "diss_friend": sur_tag.select("tr")[8].select("td")[1].text.strip(),
296
+ "save_friend": sur_tag.select("tr")[9].select("td")[1].text.strip(),
297
+ "protect_friend": sur_tag.select("tr")[10].select("td")[1].text.strip(),
298
+ "pro_from_smoker": sur_tag.select("tr")[11].select("td")[1].text.strip(),
299
+ "pro_from_hunter": sur_tag.select("tr")[12].select("td")[1].text.strip(),
300
+ "pro_from_charger": sur_tag.select("tr")[13].select("td")[1].text.strip(),
301
+ "pro_from_jockey": sur_tag.select("tr")[14].select("td")[1].text.strip(),
302
+ "melee_charge": sur_tag.select("tr")[15].select("td")[1].text.strip(),
303
+ "tank_kill": sur_tag.select("tr")[16].select("td")[1].text.strip(),
304
+ "witch_instantly_kill": sur_tag.select("tr")[17]
305
+ .select("td")[1]
306
+ .text.strip(),
307
+ }
308
+ inf_dict = {
309
+ "sur_ace": inf_tag.select("tr")[0].select("td")[1].text.strip(),
310
+ "sur_down": inf_tag.select("tr")[1].select("td")[1].text.strip(),
311
+ "boommer_hit": inf_tag.select("tr")[2].select("td")[1].text.strip(),
312
+ "hunter_prefect": inf_tag.select("tr")[3].select("td")[1].text.strip(),
313
+ "hunter_success": inf_tag.select("tr")[4].select("td")[1].text.strip(),
314
+ "tank_damage": inf_tag.select("tr")[5].select("td")[1].text.strip(),
315
+ "charger_multiple": inf_tag.select("tr")[6].select("td")[1].text.strip(),
316
+ }
317
+ info_dict = cast(AnnePlayerInfo, info_dict)
318
+ detail_dict = cast(AnnePlayerDetail, detail_tag)
319
+ error_dict = cast(AnnePlayerError, error_tag)
320
+ inf_avg_dict = cast(AnnePlayerInfAvg, inf_avg_dict)
321
+ sur_dict = cast(AnnePlayerSur, sur_dict)
322
+ inf_dict = cast(AnnePlayerInf, inf_dict)
323
+
324
+ out_dict = {
325
+ "kill_msg": kill_tag.text if kill_tag is not None else "",
326
+ "info": info_dict,
327
+ "detail": detail_dict,
328
+ "inf_avg": inf_avg_dict,
329
+ "sur": sur_dict,
330
+ "inf": inf_dict,
331
+ "error": error_dict,
332
+ }
333
+
334
+ return cast(AnnePlayer2, out_dict)
117
335
 
118
336
 
119
337
  L4API = L4D2Api()
@@ -1,29 +1,18 @@
1
- from pathlib import Path
1
+ from nonebot_plugin_tortoise_orm import add_model
2
+ from tortoise import fields
3
+ from tortoise.models import Model
2
4
 
3
- from nonebot import on_command
4
- from nonebot_plugin_datastore import get_plugin_data
5
- from sqlalchemy.orm import Mapped, mapped_column
5
+ add_model(__name__)
6
6
 
7
- plugin_data = get_plugin_data()
8
7
 
9
- # 定义模型
10
- DATA = get_plugin_data()
11
- DATA.set_migration_dir(Path("data/L4D2/") / "sql")
12
-
13
-
14
- class SteamUser(DATA.Model):
8
+ class SteamUser(Model):
15
9
  """个人资料"""
16
10
 
17
- SteamID: Mapped[str] = mapped_column(primary_key=True)
18
- SteamID64: Mapped[str]
19
- Name: Mapped[str]
20
-
21
-
22
- matcher = on_command("test")
11
+ userid = fields.BigIntField(pk=True)
12
+ SteamID = fields.TextField(null=True)
13
+ SteamID64 = fields.TextField(null=True)
14
+ Name = fields.TextField(null=True)
23
15
 
24
- # 数据库相关操作
25
- # @matcher.handle()
26
- # async def handle(session: AsyncSession = Depends(get_session)):
27
- # example = SteamUser(message="matcher")
28
- # session.add(example)
29
- # await session.commit()
16
+ class Meta: # type: ignore
17
+ table = "steam_user"
18
+ table_description = "个人资料"
@@ -5,8 +5,11 @@ from pathlib import Path
5
5
  from typing import Any, Dict, List, Optional, Tuple
6
6
 
7
7
  import aiofiles
8
+ import aiohttp
9
+ import nonebot
8
10
  from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
9
11
  from nonebot.log import logger
12
+ from nonebot_plugin_alconna import UniMessage
10
13
 
11
14
 
12
15
  async def get_file(url: str, down_file: Path):
@@ -37,7 +40,7 @@ def get_vpk(map_path: Path, file_: str = ".vpk") -> List[str]:
37
40
  def mes_list(mes: str, name_list: List[str]) -> str:
38
41
  if name_list:
39
42
  for idx, name in enumerate(name_list):
40
- mes += f"\n{idx+1}、{name}"
43
+ mes += f"\n{idx + 1}、{name}"
41
44
  return mes
42
45
 
43
46
 
@@ -72,16 +75,11 @@ def solve(msg: str):
72
75
  return "\n".join(lines)
73
76
 
74
77
 
75
- async def get_message_at(datas: str) -> List[int]:
76
- data: Dict[str, Any] = json.loads(datas)
77
- return [int(msg["data"]["qq"]) for msg in data["message"] if msg["type"] == "at"]
78
-
79
-
80
78
  def at_to_usrid(at: List[int]):
81
79
  return at[0] if at else None
82
80
 
83
81
 
84
- async def save_file(file: bytes, path_name):
82
+ async def save_file(file: bytes, path_name: str):
85
83
  """保存文件"""
86
84
  async with aiofiles.open(path_name, "wb") as files:
87
85
  await files.write(file)
@@ -149,7 +147,7 @@ def register_menu_func(
149
147
 
150
148
 
151
149
  def register_menu(*args, **kwargs):
152
- def decorator(f):
150
+ def decorator(f): # noqa: ANN001
153
151
  register_menu_func(*args, **kwargs)
154
152
  return f
155
153
 
@@ -177,10 +175,8 @@ def split_maohao(msg: str) -> Tuple[str, int]:
177
175
  return "", -1
178
176
 
179
177
 
180
- import aiohttp
181
-
182
178
  headers = {
183
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0", # noqa: E501
179
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0",
184
180
  }
185
181
 
186
182
 
@@ -202,3 +198,18 @@ async def url_to_msg(url: str):
202
198
  if response.status == 200:
203
199
  return await response.text()
204
200
  return None
201
+
202
+
203
+ async def get_message_at(datas: str) -> Optional[int]:
204
+ data: Dict[str, Any] = json.loads(datas)
205
+ at_list = [int(msg["data"]["qq"]) for msg in data["message"] if msg["type"] == "at"]
206
+ return at_list[0] if at_list else None
207
+
208
+
209
+ async def send_ip_msg(msg: str):
210
+ try:
211
+ await UniMessage.text(msg).finish()
212
+ except nonebot.adapters.qq:
213
+ msg_new = msg.split("\n")[:-2]
214
+ msg_out = "\n".join(msg_new)
215
+ await UniMessage.text(msg_out).send()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-l4d2-server
3
- Version: 1.0.0a1
3
+ Version: 1.0.0b1
4
4
  Summary: L4D2 server related operations plugin for NoneBot2
5
5
  Keywords: steam,game,l4d2,nonebot2,plugin
6
6
  Home-page: https://github.com/Agnes4m/nonebot_plugin_l4d2_server
@@ -19,12 +19,19 @@ Requires-Dist: nonebot2>=2.0.0
19
19
  Requires-Dist: nonebot-plugin-htmlrender>=0.3.0
20
20
  Requires-Dist: nonebot-adapter-onebot>=2.4.4
21
21
  Requires-Dist: nonebot-plugin-alconna>=0.50.0
22
+ Requires-Dist: nonebot_plugin_datastore>=1.3.0
23
+ Requires-Dist: nonebot-plugin-tortoise-orm>=0.1.4
22
24
  Requires-Dist: aiohttp>=3.8.4
23
25
  Requires-Dist: jinja2>=3.0.0
24
26
  Requires-Dist: srctools>=2.3.9
25
- Requires-Dist: bs4==0.0.1
26
- Requires-Dist: httpx>=0.22.0
27
+ Requires-Dist: httpx<0.24.1,>=0.22.0
28
+ Requires-Dist: msgspec>=0.18.0
27
29
  Requires-Dist: python-a2s>=1.3.0
30
+ Requires-Dist: ujson>=5.10.0
31
+ Requires-Dist: lxml>=5.2.2
32
+ Requires-Dist: rcon>=2.1.0
33
+ Requires-Dist: pillow>9
34
+ Requires-Dist: beautifulsoup4>=4.12.3
28
35
  Description-Content-Type: text/markdown
29
36
 
30
37
  <!-- markdownlint-disable MD026 MD031 MD033 MD036 MD041 MD046 MD051 -->
@@ -137,28 +144,29 @@ conda install nonebot-plugin-l4d2-server
137
144
 
138
145
  ## [数据结构](./docs/standand.md)
139
146
 
147
+ 暂未更新
148
+
140
149
  ## env设置
141
150
 
142
151
  """bash
143
- l4_anne: bool = False
152
+ l4_anne = False
144
153
  """是否启用anne电信服相关功能"""
145
- l4_enable: bool = True
154
+ l4_enable = True
146
155
  """是否全局启用求生功能"""
147
- l4_image: bool = False
156
+ l4_image = False
148
157
  """是否启用图片"""
149
- l4_connect: bool = True
158
+ l4_connect = True
150
159
  """是否在查服命令后加入connect ip"""
151
- l4_path: str = "data/L4D2"
160
+ l4_path = "data/L4D2"
152
161
  """插件数据路径"""
153
- l4_players: int = 4
162
+ l4_players = 4
154
163
  """查询总图的时候展示的用户数量"""
155
- l4_style: str = "default"
164
+ l4_style = "default"
156
165
  """图片风格,可选包括以下,默认简洁
157
166
  - 暗风格
158
167
  - 孤独摇滚
159
168
  - 电玩像素
160
169
  - 缤纷彩虹
161
- - 求生之路
162
170
  """
163
171
 
164
172
  ## 其他