nonebot-plugin-l4d2-server 0.6.6__py3-none-any.whl → 1.0.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. nonebot_plugin_l4d2_server/__init__.py +10 -93
  2. nonebot_plugin_l4d2_server/__main__.py +140 -0
  3. nonebot_plugin_l4d2_server/config.py +35 -0
  4. nonebot_plugin_l4d2_server/data/font/loli.ttf +0 -0
  5. nonebot_plugin_l4d2_server/l4_anne/__init__.py +124 -0
  6. nonebot_plugin_l4d2_server/l4_anne/ranne.py +18 -0
  7. nonebot_plugin_l4d2_server/l4_help/Help.json +102 -0
  8. nonebot_plugin_l4d2_server/l4_help/__init__.py +57 -0
  9. nonebot_plugin_l4d2_server/l4_help/draw.py +206 -0
  10. nonebot_plugin_l4d2_server/l4_help/icon//344/273/213/347/273/215.png +0 -0
  11. nonebot_plugin_l4d2_server/l4_help/icon//344/273/273/345/212/241.png +0 -0
  12. nonebot_plugin_l4d2_server/l4_help/icon//344/277/241/346/201/257.png +0 -0
  13. nonebot_plugin_l4d2_server/l4_help/icon//345/205/254/345/221/212.png +0 -0
  14. nonebot_plugin_l4d2_server/l4_help/icon//345/210/200/345/211/221.png +0 -0
  15. nonebot_plugin_l4d2_server/l4_help/icon//345/210/207/346/215/242.png +0 -0
  16. nonebot_plugin_l4d2_server/l4_help/icon//345/210/240/351/231/244.png +0 -0
  17. nonebot_plugin_l4d2_server/l4_help/icon//345/210/267/346/226/260.png +0 -0
  18. nonebot_plugin_l4d2_server/l4_help/icon//345/215/241/347/273/204.png +0 -0
  19. nonebot_plugin_l4d2_server/l4_help/icon//345/223/252/351/207/214.png +0 -0
  20. nonebot_plugin_l4d2_server/l4_help/icon//345/234/260/345/233/276.png +0 -0
  21. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/205/245.png +0 -0
  22. nonebot_plugin_l4d2_server/l4_help/icon//345/257/274/345/207/272.png +0 -0
  23. nonebot_plugin_l4d2_server/l4_help/icon//345/275/261.png +0 -0
  24. nonebot_plugin_l4d2_server/l4_help/icon//346/213/274/345/233/276.png +0 -0
  25. nonebot_plugin_l4d2_server/l4_help/icon//346/216/242/347/264/242.png +0 -0
  26. nonebot_plugin_l4d2_server/l4_help/icon//346/216/250/351/200/201.png +0 -0
  27. nonebot_plugin_l4d2_server/l4_help/icon//346/224/266/351/233/206.png +0 -0
  28. nonebot_plugin_l4d2_server/l4_help/icon//346/224/273/347/225/245.png +0 -0
  29. nonebot_plugin_l4d2_server/l4_help/icon//346/233/264/346/226/260.png +0 -0
  30. nonebot_plugin_l4d2_server/l4_help/icon//346/235/220/346/226/231.png +0 -0
  31. nonebot_plugin_l4d2_server/l4_help/icon//346/237/245/350/257/242.png +0 -0
  32. nonebot_plugin_l4d2_server/l4_help/icon//346/240/241/351/252/214.png +0 -0
  33. nonebot_plugin_l4d2_server/l4_help/icon//346/257/217/346/234/210.png +0 -0
  34. nonebot_plugin_l4d2_server/l4_help/icon//346/267/261/346/270/212.png +0 -0
  35. nonebot_plugin_l4d2_server/l4_help/icon//346/267/273/345/212/240.png +0 -0
  36. nonebot_plugin_l4d2_server/l4_help/icon//346/270/205/351/231/244.png +0 -0
  37. nonebot_plugin_l4d2_server/l4_help/icon//347/212/266/346/200/201.png +0 -0
  38. nonebot_plugin_l4d2_server/l4_help/icon//347/255/276/345/210/260.png +0 -0
  39. nonebot_plugin_l4d2_server/l4_help/icon//347/273/221/345/256/232.png +0 -0
  40. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250.png +0 -0
  41. nonebot_plugin_l4d2_server/l4_help/icon//350/241/250/346/203/205.png +0 -0
  42. nonebot_plugin_l4d2_server/l4_help/icon//350/247/222/350/211/262.png +0 -0
  43. nonebot_plugin_l4d2_server/l4_help/icon//350/256/260/345/275/225.png +0 -0
  44. nonebot_plugin_l4d2_server/l4_help/icon//351/205/215/347/275/256.png +0 -0
  45. nonebot_plugin_l4d2_server/l4_help/icon//351/207/215/345/220/257.png +0 -0
  46. nonebot_plugin_l4d2_server/l4_help/texture2d/badge.png +0 -0
  47. nonebot_plugin_l4d2_server/l4_help/texture2d/banner.png +0 -0
  48. nonebot_plugin_l4d2_server/l4_help/texture2d/bg.jpg +0 -0
  49. nonebot_plugin_l4d2_server/l4_help/texture2d/button.png +0 -0
  50. nonebot_plugin_l4d2_server/l4_help/texture2d/icon.png +0 -0
  51. nonebot_plugin_l4d2_server/l4_image/__init__.py +16 -0
  52. nonebot_plugin_l4d2_server/l4_image/anne_pil.py +17 -0
  53. nonebot_plugin_l4d2_server/l4_image/convert.py +175 -0
  54. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/download.py +11 -35
  55. nonebot_plugin_l4d2_server/l4_image/html_img.py +105 -0
  56. nonebot_plugin_l4d2_server/l4_image/image_tools.py +468 -0
  57. nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/back.png +0 -0
  58. nonebot_plugin_l4d2_server/l4_image/img/anne/back1.jpg +0 -0
  59. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/head/head.png +0 -0
  60. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/logo.png +0 -0
  61. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/header/player1.jpg +0 -0
  62. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.html +299 -0
  63. nonebot_plugin_l4d2_server/l4_image/img/template/Bocchi_The_Rock.png +0 -0
  64. nonebot_plugin_l4d2_server/l4_image/img/template/HYPixel11pxU-2.ttf +0 -0
  65. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.html +341 -0
  66. nonebot_plugin_l4d2_server/l4_image/img/template/Pixel.png +0 -0
  67. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.html +355 -0
  68. nonebot_plugin_l4d2_server/l4_image/img/template/Rainbow.png +0 -0
  69. nonebot_plugin_l4d2_server/l4_image/img/template/Tutumianhuatang-Bold-2.ttf +0 -0
  70. nonebot_plugin_l4d2_server/l4_image/img/template/bilibili.svg +1 -0
  71. nonebot_plugin_l4d2_server/l4_image/img/template/github.svg +1 -0
  72. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/l.svg +0 -1
  73. nonebot_plugin_l4d2_server/l4_image/img/template/m.svg +1 -0
  74. nonebot_plugin_l4d2_server/l4_image/img/template/normal.html +247 -0
  75. nonebot_plugin_l4d2_server/l4_image/img/template/vac.png +0 -0
  76. nonebot_plugin_l4d2_server/l4_image/img/template/vac_white.png +0 -0
  77. nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/w.svg +1 -1
  78. nonebot_plugin_l4d2_server/l4_image/model.py +15 -0
  79. nonebot_plugin_l4d2_server/{l4d2_image → l4_image}/vtfs.py +4 -2
  80. nonebot_plugin_l4d2_server/l4_request/__init__.py +143 -0
  81. nonebot_plugin_l4d2_server/l4_request/draw_msg.py +83 -0
  82. nonebot_plugin_l4d2_server/utils/api/api.py +10 -0
  83. nonebot_plugin_l4d2_server/utils/api/models.py +137 -0
  84. nonebot_plugin_l4d2_server/utils/api/request.py +337 -0
  85. nonebot_plugin_l4d2_server/utils/database/models.py +18 -0
  86. nonebot_plugin_l4d2_server/{l4d2_utils → utils}/utils.py +60 -63
  87. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/METADATA +57 -66
  88. nonebot_plugin_l4d2_server-1.0.0a2.dist-info/RECORD +96 -0
  89. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/WHEEL +1 -1
  90. nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +0 -263
  91. nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +0 -231
  92. nonebot_plugin_l4d2_server/data/L4D2/image/template/m.svg +0 -1
  93. nonebot_plugin_l4d2_server/data/img/white.png +0 -0
  94. nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +0 -95
  95. nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +0 -54
  96. nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +0 -79
  97. nonebot_plugin_l4d2_server/l4d2_anne/server.py +0 -47
  98. nonebot_plugin_l4d2_server/l4d2_anne/startand.py +0 -17
  99. nonebot_plugin_l4d2_server/l4d2_anne/utils.py +0 -294
  100. nonebot_plugin_l4d2_server/l4d2_data/__init__.py +0 -105
  101. nonebot_plugin_l4d2_server/l4d2_data/config.py +0 -18
  102. nonebot_plugin_l4d2_server/l4d2_data/players.py +0 -100
  103. nonebot_plugin_l4d2_server/l4d2_data/serverip.py +0 -40
  104. nonebot_plugin_l4d2_server/l4d2_file/__init__.py +0 -222
  105. nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +0 -64
  106. nonebot_plugin_l4d2_server/l4d2_file/input_json.py +0 -77
  107. nonebot_plugin_l4d2_server/l4d2_file/remote.py +0 -86
  108. nonebot_plugin_l4d2_server/l4d2_file/utils.py +0 -104
  109. nonebot_plugin_l4d2_server/l4d2_image/__init__.py +0 -125
  110. nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +0 -18
  111. nonebot_plugin_l4d2_server/l4d2_image/images.py +0 -92
  112. nonebot_plugin_l4d2_server/l4d2_image/one.py +0 -44
  113. nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +0 -32
  114. nonebot_plugin_l4d2_server/l4d2_image/steam.py +0 -63
  115. nonebot_plugin_l4d2_server/l4d2_push/__init__.py +0 -225
  116. nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +0 -326
  117. nonebot_plugin_l4d2_server/l4d2_queries/himi.py +0 -113
  118. nonebot_plugin_l4d2_server/l4d2_queries/local_ip.py +0 -41
  119. nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +0 -370
  120. nonebot_plugin_l4d2_server/l4d2_queries/send_msg.py +0 -131
  121. nonebot_plugin_l4d2_server/l4d2_queries/utils.py +0 -212
  122. nonebot_plugin_l4d2_server/l4d2_server/__init__.py +0 -118
  123. nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
  124. nonebot_plugin_l4d2_server/l4d2_server/rcon.py +0 -53
  125. nonebot_plugin_l4d2_server/l4d2_server/workshop.py +0 -82
  126. nonebot_plugin_l4d2_server/l4d2_update/__init__.py +0 -137
  127. nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +0 -45
  128. nonebot_plugin_l4d2_server/l4d2_update/restart.py +0 -69
  129. nonebot_plugin_l4d2_server/l4d2_update/update.py +0 -53
  130. nonebot_plugin_l4d2_server/l4d2_utils/classcal.py +0 -53
  131. nonebot_plugin_l4d2_server/l4d2_utils/command.py +0 -23
  132. nonebot_plugin_l4d2_server/l4d2_utils/config.py +0 -201
  133. nonebot_plugin_l4d2_server/l4d2_utils/message.py +0 -59
  134. nonebot_plugin_l4d2_server/l4d2_utils/rule.py +0 -35
  135. nonebot_plugin_l4d2_server/l4d2_utils/seach.py +0 -43
  136. nonebot_plugin_l4d2_server/l4d2_utils/txt_to_img.py +0 -32
  137. nonebot_plugin_l4d2_server/l4d2_web/web.py +0 -277
  138. nonebot_plugin_l4d2_server/l4d2_web/webUI.py +0 -506
  139. nonebot_plugin_l4d2_server/l4d2_web/webUI_s.py +0 -94
  140. nonebot_plugin_l4d2_server-0.6.6.dist-info/RECORD +0 -70
  141. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/anne.html +0 -0
  142. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/group_ip.html +0 -0
  143. /nonebot_plugin_l4d2_server/{data/L4D2/image/template → l4_image/img/anne}/ip.html +0 -0
  144. /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/fingerprint.svg +0 -0
  145. /nonebot_plugin_l4d2_server/{data/L4D2/image → l4_image/img}/template/vue.css +0 -0
  146. /nonebot_plugin_l4d2_server/{l4d2_data/database.py → l4_request/utils.py} +0 -0
  147. {nonebot_plugin_l4d2_server-0.6.6.dist-info → nonebot_plugin_l4d2_server-1.0.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,277 +0,0 @@
1
- import datetime
2
- from pathlib import Path
3
- from typing import Optional
4
-
5
- from fastapi import Depends, FastAPI, Header, HTTPException
6
- from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
7
- from jose import jwt
8
- from jose.exceptions import ExpiredSignatureError, JWTError
9
- from nonebot import get_adapter, get_app, get_driver, logger
10
- from nonebot.adapters.onebot.v11 import Adapter
11
-
12
- from ..l4d2_queries.qqgroup import qq_ip_querie
13
- from ..l4d2_utils.config import UserModel, config_manager
14
- from ..l4d2_utils.utils import split_maohao
15
- from .webUI import admin_app, login_page
16
- from .webUI_s import user_app
17
-
18
- CONFIG_PATH = Path() / "data" / "L4D2" / "l4d2.yml"
19
-
20
- CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
21
-
22
- driver = get_driver()
23
-
24
-
25
- requestAdaptor = """
26
- requestAdaptor(api) {
27
- api.headers["token"] = localStorage.getItem("token");
28
- return api;
29
- },
30
- """ # noqa: N816
31
- responseAdaptor = """
32
- responseAdaptor(api, payload, query, request, response) {
33
- if (response.data.detail == '登录验证失败或已失效,请重新登录') {
34
- window.location.href = '/l4d2/login'
35
- window.localStorage.clear()
36
- window.sessionStorage.clear()
37
- window.alert('登录验证失败或已失效,请重新登录')
38
- }
39
- return payload
40
- },
41
- """ # noqa: N816
42
-
43
-
44
- def authentication():
45
- def inner(token: Optional[str] = Header(...)):
46
- try:
47
- if not token:
48
- raise HTTPException( # noqa: TRY301
49
- status_code=400,
50
- detail="登录验证失败或已失效,请重新登录",
51
- )
52
- payload = jwt.decode(
53
- token,
54
- config_manager.config.web_secret_key,
55
- algorithms="HS256",
56
- )
57
- if (
58
- not (username := payload.get("username"))
59
- or username != config_manager.config.web_username
60
- ):
61
- raise HTTPException( # noqa: TRY301
62
- status_code=400,
63
- detail="登录验证失败或已失效,请重新登录",
64
- ) # noqa: E501
65
- except (JWTError, ExpiredSignatureError, AttributeError):
66
- raise HTTPException( # noqa: B904, TRY200
67
- status_code=400,
68
- detail="登录验证失败或已失效,请重新登录",
69
- )
70
-
71
- return Depends(inner)
72
-
73
-
74
- COMMAND_START = driver.config.command_start.copy()
75
- if "" in COMMAND_START:
76
- COMMAND_START.remove("")
77
-
78
-
79
- @driver.on_startup
80
- async def init_web():
81
- if not config_manager.config.total_enable:
82
- return
83
- app: FastAPI = get_app()
84
- logger.success("成功加载网页控制台")
85
-
86
- @app.post("/l4d2/api/login", response_class=JSONResponse)
87
- async def login(user: UserModel):
88
- if (
89
- user.username != config_manager.config.web_username
90
- or user.password != config_manager.config.web_password
91
- ):
92
- return {"status": -100, "msg": "登录失败,请确认用户ID和密码无误"}
93
- token = jwt.encode(
94
- {
95
- "username": user.username,
96
- "exp": datetime.datetime.now(datetime.timezone.utc)
97
- + datetime.timedelta(minutes=30),
98
- },
99
- config_manager.config.web_secret_key,
100
- algorithm="HS256",
101
- )
102
- return {"status": 0, "msg": "登录成功", "data": {"token": token}}
103
-
104
- @app.get(
105
- "/l4d2/api/get_group_list",
106
- response_class=JSONResponse,
107
- dependencies=[authentication()],
108
- )
109
- async def get_group_list_api():
110
- try:
111
- bots = get_adapter(Adapter).bots
112
- if len(bots) == 0:
113
- return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}
114
- bot = next(iter(bots.values()))
115
- group_list = await bot.get_group_list()
116
- group_list = [
117
- {
118
- "label": f'{group["group_name"]}({group["group_id"]})',
119
- "value": group["group_id"],
120
- }
121
- for group in group_list
122
- ]
123
- if True:
124
- return {"status": 0, "msg": "ok", "data": {"group_list": group_list}}
125
- except ValueError:
126
- return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}
127
-
128
- @app.post(
129
- "/l4d2/api/l4d2_global_config",
130
- response_class=JSONResponse,
131
- dependencies=[authentication()],
132
- )
133
- async def post_l4d2_global_config(data: dict):
134
- config_manager.config.update(**data)
135
- config_manager.save()
136
- return {"status": 0, "msg": "保存成功"}
137
-
138
- @app.get(
139
- "/l4d2/api/l4d2_global_config",
140
- response_class=JSONResponse,
141
- dependencies=[authentication()],
142
- )
143
- async def get_l4d2_global_config():
144
- try:
145
- bots = get_adapter(Adapter).bots
146
- if len(bots) == 0:
147
- return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}
148
- bot = next(iter(bots.values()))
149
- groups = await bot.get_group_list()
150
- member_list = []
151
- for group in groups:
152
- members = await bot.get_group_member_list(group_id=group["group_id"])
153
- member_list.extend(
154
- [
155
- {
156
- "label": f'{member["nickname"] or member["card"]}({member["user_id"]})', # noqa: E501
157
- "value": member["user_id"],
158
- }
159
- for member in members
160
- ],
161
- )
162
- config = config_manager.config.dict(exclude={"group_config"})
163
- config["member_list"] = member_list
164
- config["l4_styles"] = ["standard", "black"]
165
- if True:
166
- return config
167
- except ValueError:
168
- return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}
169
-
170
- @app.get("/l4d2/api/user/get_query_contexts", response_class=JSONResponse)
171
- @app.get(
172
- "/l4d2/api/get_query_contexts",
173
- response_class=JSONResponse,
174
- dependencies=[authentication()],
175
- )
176
- async def get_query_context():
177
- try:
178
- from ..l4d2_queries.local_ip import ALL_HOST
179
-
180
- this_ips = ALL_HOST
181
- ip_lists = []
182
- for ip_list, v in this_ips.items():
183
- for d in v:
184
- host, port = split_maohao(d["ip"])
185
- ip_lists.append((d["id"], ip_list, host, port))
186
- data_dict = await qq_ip_querie(ip_lists)
187
- if not data_dict:
188
- return {"status": -100, "msg": "返回失败,请确保有可用的服务器ip"}
189
- data_list = data_dict["msg_list"]
190
- # logger.info(data_list)
191
- return {
192
- "status": 0,
193
- "msg": "ok",
194
- "data": {
195
- "items": data_list,
196
- "total": len(data_list),
197
- },
198
- }
199
- except ValueError:
200
- return {"status": -100, "msg": "返回失败,请确保网络连接正常"}
201
-
202
- @app.get(
203
- "/l4d2/api/get_l4d2_messages",
204
- response_class=JSONResponse,
205
- dependencies=[authentication()],
206
- )
207
- async def get_l4d2_messages():
208
- try:
209
- l4_ipall = config_manager.config.l4_ipall
210
-
211
- return {
212
- "status": 0,
213
- "msg": "ok",
214
- "data": {
215
- "server_list": [
216
- {"label": item["server_id"], "value": item["id_rank"]}
217
- for item in l4_ipall
218
- ],
219
- },
220
- }
221
- except ValueError:
222
- return {"status": -100, "msg": "返回失败,请确保网络连接正常"}
223
-
224
- @app.get(
225
- "/l4d2/api/l4d2_server_config",
226
- response_class=JSONResponse,
227
- dependencies=[authentication()],
228
- )
229
- async def get_l4d2_server_config(id_rank: str):
230
- try:
231
- l4_ipall = config_manager.config.l4_ipall
232
- config = {}
233
- for item in l4_ipall:
234
- if item["id_rank"] == id_rank:
235
- item["place"] = item["place"] is True or item["place"] is True
236
- config = item
237
- break
238
- if True:
239
- return {"status": 0, "msg": "ok", "data": config}
240
- except ValueError:
241
- return {"status": -100, "msg": "返回失败,请确保网络连接正常"}
242
-
243
- @app.post(
244
- "/l4d2/api/l4d2_server_config",
245
- response_class=JSONResponse,
246
- dependencies=[authentication()],
247
- )
248
- async def post_l4d2_server_config(id_rank: str, data: dict):
249
- for one in config_manager.config.l4_ipall:
250
- if one["id_rank"] == id_rank:
251
- one.update(**data)
252
- config_manager.save()
253
- return {"status": 0, "msg": "保存成功"}
254
-
255
- @app.get("/l4d2", response_class=RedirectResponse)
256
- async def redirect_page():
257
- return RedirectResponse("/l4d2/login")
258
-
259
- @app.get("/l4d2/login", response_class=HTMLResponse)
260
- async def login_page_app():
261
- return login_page.render(site_title="登录 | l4d2 后台管理", theme="ang")
262
-
263
- @app.get("/l4d2/admin", response_class=HTMLResponse)
264
- async def admin_page_app():
265
- return admin_app.render(
266
- site_title="l4d2-l4d2 后台管理",
267
- theme="ang",
268
- requestAdaptor=requestAdaptor,
269
- responseAdaptor=responseAdaptor,
270
- )
271
-
272
- @app.get("/l4d2/user", response_class=HTMLResponse)
273
- async def user_page_app():
274
- return user_app.render(
275
- site_title="l4d2服务器查询",
276
- theme="ang",
277
- )