nonebot-plugin-l4d2-server 0.5.1__py3-none-any.whl → 0.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. LICENSE +674 -674
  2. README.md +373 -359
  3. nonebot_plugin_l4d2_server/__init__.py +13 -13
  4. nonebot_plugin_l4d2_server/command.py +232 -232
  5. nonebot_plugin_l4d2_server/config.py +209 -210
  6. nonebot_plugin_l4d2_server/data/L4D2/image/template/anne.html +60 -60
  7. nonebot_plugin_l4d2_server/data/L4D2/image/template/fingerprint.svg +15 -15
  8. nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html +233 -233
  9. nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html +231 -231
  10. nonebot_plugin_l4d2_server/data/L4D2/image/template/ip.html +48 -48
  11. nonebot_plugin_l4d2_server/data/L4D2/image/template/l.svg +9 -9
  12. nonebot_plugin_l4d2_server/l4d2_anne/__init__.py +251 -251
  13. nonebot_plugin_l4d2_server/l4d2_anne/analysis.py +51 -51
  14. nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py +75 -75
  15. nonebot_plugin_l4d2_server/l4d2_anne/server.py +65 -65
  16. nonebot_plugin_l4d2_server/l4d2_anne/startand.py +17 -17
  17. nonebot_plugin_l4d2_server/l4d2_data/__init__.py +91 -91
  18. nonebot_plugin_l4d2_server/l4d2_data/config.py +17 -17
  19. nonebot_plugin_l4d2_server/l4d2_data/database.py +0 -0
  20. nonebot_plugin_l4d2_server/l4d2_data/players.py +87 -87
  21. nonebot_plugin_l4d2_server/l4d2_data/serverip.py +32 -32
  22. nonebot_plugin_l4d2_server/l4d2_file/__init__.py +122 -122
  23. nonebot_plugin_l4d2_server/l4d2_file/ayromote.py +56 -56
  24. nonebot_plugin_l4d2_server/l4d2_file/remote.py +63 -63
  25. nonebot_plugin_l4d2_server/l4d2_image/__init__.py +103 -103
  26. nonebot_plugin_l4d2_server/l4d2_image/download.py +101 -101
  27. nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py +32 -32
  28. nonebot_plugin_l4d2_server/l4d2_image/image.py +292 -0
  29. nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py +32 -32
  30. nonebot_plugin_l4d2_server/l4d2_image/steam.py +83 -83
  31. nonebot_plugin_l4d2_server/l4d2_image/vtfs.py +40 -40
  32. nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +114 -114
  33. nonebot_plugin_l4d2_server/l4d2_queries/api.py +43 -43
  34. nonebot_plugin_l4d2_server/l4d2_queries/ohter.py +35 -35
  35. nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +288 -288
  36. nonebot_plugin_l4d2_server/l4d2_server/__init__.py +61 -61
  37. nonebot_plugin_l4d2_server/l4d2_server/index.py +0 -0
  38. nonebot_plugin_l4d2_server/l4d2_server/rcon.py +28 -28
  39. nonebot_plugin_l4d2_server/l4d2_server/workshop.py +50 -50
  40. nonebot_plugin_l4d2_server/l4d2_update/__init__.py +143 -0
  41. nonebot_plugin_l4d2_server/l4d2_update/draw_update_log.py +41 -0
  42. nonebot_plugin_l4d2_server/l4d2_update/restart.py +67 -0
  43. nonebot_plugin_l4d2_server/l4d2_update/texture2d/art.png +0 -0
  44. nonebot_plugin_l4d2_server/l4d2_update/texture2d/bento.png +0 -0
  45. nonebot_plugin_l4d2_server/l4d2_update/texture2d/bug.png +0 -0
  46. nonebot_plugin_l4d2_server/l4d2_update/texture2d/feat.png +0 -0
  47. nonebot_plugin_l4d2_server/l4d2_update/texture2d/log_title.png +0 -0
  48. nonebot_plugin_l4d2_server/l4d2_update/texture2d/other.png +0 -0
  49. nonebot_plugin_l4d2_server/l4d2_update/texture2d/zap.png +0 -0
  50. nonebot_plugin_l4d2_server/l4d2_update/update.py +65 -0
  51. nonebot_plugin_l4d2_server/l4d2_web/web.py +234 -252
  52. nonebot_plugin_l4d2_server/l4d2_web/webUI.py +241 -245
  53. nonebot_plugin_l4d2_server/message.py +58 -58
  54. nonebot_plugin_l4d2_server/rule.py +15 -0
  55. nonebot_plugin_l4d2_server/seach.py +33 -33
  56. nonebot_plugin_l4d2_server/txt_to_img.py +64 -64
  57. nonebot_plugin_l4d2_server/utils.py +297 -272
  58. {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/LICENSE +674 -674
  59. {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/METADATA +19 -4
  60. nonebot_plugin_l4d2_server-0.5.3.dist-info/RECORD +68 -0
  61. {nonebot_plugin_l4d2_server-0.5.1.dist-info → nonebot_plugin_l4d2_server-0.5.3.dist-info}/WHEEL +1 -1
  62. nonebot_plugin_l4d2_server/chrome.py +0 -45
  63. nonebot_plugin_l4d2_server-0.5.1.dist-info/RECORD +0 -54
@@ -1,62 +1,62 @@
1
- import asyncio
2
- from rcon.source.proto import Packet,Type
3
- from rcon.source.async_rcon import communicate,close
4
-
5
- async def main(host):
6
- host = '43.142.178.212'
7
- port = 40003
8
- password = '1145149191810'
9
- encoding = 'utf-8'
10
-
11
- # Connect to RCON server
12
-
13
-
14
- # Main loop
15
- while True:
16
- # Read user input
17
- command = input('> ')
18
- if not command:
19
- break
20
-
21
- # 连接服务器
22
- reader, writer = await asyncio.open_connection(host, port)
23
- login = Packet.make_login(password, encoding=encoding)
24
- response = await communicate(reader, writer, login)
25
-
26
- # 等待 SERVERDATA_AUTH_RESPONSE 数据包
27
- while response.type != Type.SERVERDATA_AUTH_RESPONSE:
28
- response = await Packet.aread(reader)
29
-
30
- if response.id == -1:
31
- await close(writer)
32
- raise WrongPassword()
33
-
34
- # 循环接收用户输入并发送指令
35
- while True:
36
- try:
37
- command = input('请输入指令:')
38
-
39
- except EOFError:
40
- break
41
-
42
- if command=='停止':
43
- break
44
- # 发送指令
45
-
46
- command = f'say {command}'
47
- request = Packet.make_command(command, encoding=encoding)
48
- response = await communicate(reader, writer, request)
49
-
50
- # if response.id != request.id:
51
- # raise SessionTimeout()
52
-
53
- print(response.payload.decode(encoding, errors='ignore'))
54
-
55
- # 断开连接
56
- await close(writer)
57
-
58
- class WrongPassword(Exception):
59
- """Indicates a wrong password."""
60
-
61
- class SessionTimeout(Exception):
1
+ import asyncio
2
+ from rcon.source.proto import Packet,Type
3
+ from rcon.source.async_rcon import communicate,close
4
+
5
+ async def main(host):
6
+ host = '43.142.178.212'
7
+ port = 40003
8
+ password = '1145149191810'
9
+ encoding = 'utf-8'
10
+
11
+ # Connect to RCON server
12
+
13
+
14
+ # Main loop
15
+ while True:
16
+ # Read user input
17
+ command = input('> ')
18
+ if not command:
19
+ break
20
+
21
+ # 连接服务器
22
+ reader, writer = await asyncio.open_connection(host, port)
23
+ login = Packet.make_login(password, encoding=encoding)
24
+ response = await communicate(reader, writer, login)
25
+
26
+ # 等待 SERVERDATA_AUTH_RESPONSE 数据包
27
+ while response.type != Type.SERVERDATA_AUTH_RESPONSE:
28
+ response = await Packet.aread(reader)
29
+
30
+ if response.id == -1:
31
+ await close(writer)
32
+ raise WrongPassword()
33
+
34
+ # 循环接收用户输入并发送指令
35
+ while True:
36
+ try:
37
+ command = input('请输入指令:')
38
+
39
+ except EOFError:
40
+ break
41
+
42
+ if command=='停止':
43
+ break
44
+ # 发送指令
45
+
46
+ command = f'say {command}'
47
+ request = Packet.make_command(command, encoding=encoding)
48
+ response = await communicate(reader, writer, request)
49
+
50
+ # if response.id != request.id:
51
+ # raise SessionTimeout()
52
+
53
+ print(response.payload.decode(encoding, errors='ignore'))
54
+
55
+ # 断开连接
56
+ await close(writer)
57
+
58
+ class WrongPassword(Exception):
59
+ """Indicates a wrong password."""
60
+
61
+ class SessionTimeout(Exception):
62
62
  """Indicates that the session timed out."""
File without changes
@@ -1,29 +1,29 @@
1
- from rcon.source import rcon
2
- import asyncio
3
- from pathlib import Path
4
- from ..config import l4_config,CHECK_FILE
5
- # from ..config import l4_rcon,l4_host,l4_port,l4_rcon
6
-
7
-
8
- async def rcon_server(PASSWORD:str,msg:str):
9
- # response = await rcon(command=msg, host=l4_host, port=l4_port, passwd=PASSWORD,encoding='utf-8')
10
- # return response
11
- try:
12
- response = await asyncio.wait_for(rcon(command=msg, host=l4_config.l4_ipall[CHECK_FILE]['host'], port = l4_config.l4_ipall[CHECK_FILE]['port'], passwd=PASSWORD), timeout=30)
13
- return response
14
- except asyncio.TimeoutError:
15
- return '超时'
16
-
17
- async def read_server_cfg_rcon():
18
- """如果没有输入rcon,尝试自动获取"""
19
- if not l4_config.l4_ipall[CHECK_FILE]['rcon']:
20
- cfg_server = Path(l4_config.l4_ipall[CHECK_FILE]['location'],'left4dead2/cfg/server.cfg')
21
- with open(cfg_server,'r')as cfg:
22
- content:str = cfg.read()
23
- lines = content.split('\n')
24
- for line in lines:
25
- if line.startswith('rcon_password'):
26
- password = line.split(' ')[-1]
27
- password = password.strip('"')
28
- return password
1
+ from rcon.source import rcon
2
+ import asyncio
3
+ from pathlib import Path
4
+ from ..config import l4_config,CHECK_FILE
5
+ # from ..config import l4_rcon,l4_host,l4_port,l4_rcon
6
+
7
+
8
+ async def rcon_server(PASSWORD:str,msg:str):
9
+ # response = await rcon(command=msg, host=l4_host, port=l4_port, passwd=PASSWORD,encoding='utf-8')
10
+ # return response
11
+ try:
12
+ response = await asyncio.wait_for(rcon(command=msg, host=l4_config.l4_ipall[CHECK_FILE]['host'], port = l4_config.l4_ipall[CHECK_FILE]['port'], passwd=PASSWORD), timeout=30)
13
+ return response
14
+ except asyncio.TimeoutError:
15
+ return '超时'
16
+
17
+ async def read_server_cfg_rcon():
18
+ """如果没有输入rcon,尝试自动获取"""
19
+ if not l4_config.l4_ipall[CHECK_FILE]['rcon']:
20
+ cfg_server = Path(l4_config.l4_ipall[CHECK_FILE]['location'],'left4dead2/cfg/server.cfg')
21
+ with open(cfg_server,'r')as cfg:
22
+ content:str = cfg.read()
23
+ lines = content.split('\n')
24
+ for line in lines:
25
+ if line.startswith('rcon_password'):
26
+ password = line.split(' ')[-1]
27
+ password = password.strip('"')
28
+ return password
29
29
  return l4_config.l4_ipall[CHECK_FILE]['rcon']
@@ -1,50 +1,50 @@
1
- import httpx
2
- from nonebot.log import logger
3
- try:
4
- import ujson as json
5
- except:
6
- import json
7
-
8
- async def workshop_to_dict(msg:str):
9
- """把创意工坊的id,转化为信息字典"""
10
- i = await api_get_json(msg)
11
-
12
- # 处理是否是多地图文件
13
- if i['file_url'] == i['preview_url']:
14
- return await primary_map(i)
15
- else:
16
- return await only_map(i)
17
-
18
-
19
- async def api_get_json(msg:str) ->dict:
20
- url_serach = 'https://db.steamworkshopdownloader.io/prod/api/details/file'
21
- data = f'[{msg}]'
22
- headers = {
23
- 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
24
- }
25
- data = httpx.post(url=url_serach,headers= headers,data=data).content.decode('utf-8')
26
- logger.info(data)
27
- out = {}
28
- data = data[1:-1]
29
- data = json.loads(data)
30
- return data
31
-
32
-
33
- async def only_map(i:dict):
34
- """单地图下载"""
35
- out = {}
36
- out['名字'] = i['title']
37
- out['游戏'] = i['app_name']
38
- out['下载地址'] = i['file_url']
39
- out['图片地址'] = i['preview_url']
40
- out['细节'] = i['file_description']
41
- return out
42
-
43
- async def primary_map(i):
44
- """主地图返回多地图参数"""
45
- map_list = []
46
- map_list.append(i)
47
- for one in i['children']:
48
- map_list.append(await api_get_json(one['publishedfileid']))
49
- return map_list
50
-
1
+ import httpx
2
+ from nonebot.log import logger
3
+ try:
4
+ import ujson as json
5
+ except:
6
+ import json
7
+
8
+ async def workshop_to_dict(msg:str):
9
+ """把创意工坊的id,转化为信息字典"""
10
+ i = await api_get_json(msg)
11
+
12
+ # 处理是否是多地图文件
13
+ if i['file_url'] == i['preview_url']:
14
+ return await primary_map(i)
15
+ else:
16
+ return await only_map(i)
17
+
18
+
19
+ async def api_get_json(msg:str) ->dict:
20
+ url_serach = 'https://db.steamworkshopdownloader.io/prod/api/details/file'
21
+ data = f'[{msg}]'
22
+ headers = {
23
+ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0'
24
+ }
25
+ data = httpx.post(url=url_serach,headers= headers,data=data).content.decode('utf-8')
26
+ logger.info(data)
27
+ out = {}
28
+ data = data[1:-1]
29
+ data = json.loads(data)
30
+ return data
31
+
32
+
33
+ async def only_map(i:dict):
34
+ """单地图下载"""
35
+ out = {}
36
+ out['名字'] = i['title']
37
+ out['游戏'] = i['app_name']
38
+ out['下载地址'] = i['file_url']
39
+ out['图片地址'] = i['preview_url']
40
+ out['细节'] = i['file_description']
41
+ return out
42
+
43
+ async def primary_map(i):
44
+ """主地图返回多地图参数"""
45
+ map_list = []
46
+ map_list.append(i)
47
+ for one in i['children']:
48
+ map_list.append(await api_get_json(one['publishedfileid']))
49
+ return map_list
50
+
@@ -0,0 +1,143 @@
1
+ from typing import Any, Tuple
2
+
3
+ from nonebot.log import logger
4
+ from nonebot.matcher import Matcher
5
+ from nonebot.params import RegexGroup
6
+ from nonebot.permission import SUPERUSER
7
+ from nonebot import get_bot, on_regex, get_driver, on_command
8
+ from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment
9
+
10
+ from ..utils import register_menu
11
+ from ..rule import FullCommand
12
+ from .draw_update_log import draw_update_log_img
13
+ from .restart import restart_message, restart_genshinuid
14
+
15
+ l4d_restart = on_command('l4重启', rule=FullCommand())
16
+ get_update_log = on_command('更新记录', rule=FullCommand())
17
+ l4d_update = on_regex(
18
+ r'^(l4d)(强行)?(强制)?(更新)$',
19
+ block=True,
20
+ )
21
+
22
+
23
+ driver = get_driver()
24
+
25
+
26
+ @driver.on_bot_connect
27
+ async def _():
28
+ logger.info('检查遗留信息...')
29
+ bot = get_bot()
30
+ update_log = await restart_message()
31
+ if update_log == {}:
32
+ return
33
+ if update_log['send_type'] == 'group':
34
+ await bot.call_api(
35
+ api='send_group_msg',
36
+ group_id=update_log['send_to'],
37
+ message=update_log['msg'],
38
+ )
39
+ else:
40
+ await bot.call_api(
41
+ api='send_private_msg',
42
+ user_id=update_log['send_to'],
43
+ message=update_log['msg'],
44
+ )
45
+ logger.info('遗留信息检查完毕!')
46
+
47
+
48
+ @get_update_log.handle()
49
+ @register_menu(
50
+ '更新记录',
51
+ '更新记录',
52
+ '查看插件最近的更新记录',
53
+ detail_des=(
54
+ '介绍:\n'
55
+ '查看插件最近的有效Git更新记录\n'
56
+ ' \n'
57
+ '指令:\n'
58
+ '- <ft color=(238,120,0)>更新记录</ft>'
59
+ ),
60
+ )
61
+ async def send_updatelog_msg(
62
+ matcher: Matcher,
63
+ ):
64
+ im = await draw_update_log_img(is_update=False)
65
+ logger.info('正在执行[更新记录]...')
66
+ if isinstance(im, str):
67
+ await matcher.finish(im)
68
+ elif isinstance(im, bytes):
69
+ await matcher.finish(MessageSegment.image(im))
70
+ else:
71
+ await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
72
+
73
+
74
+ @l4d_restart.handle()
75
+ @register_menu(
76
+ '重启Bot',
77
+ 'l4重启',
78
+ '重启Bot框架',
79
+ trigger_method='超级用户指令',
80
+ detail_des=(
81
+ '介绍:\n' '重启Bot框架\n' ' \n' '指令:\n' '- <ft color=(238,120,0)>l4重启</ft>'
82
+ ),
83
+ )
84
+ async def send_restart_msg(
85
+ bot: Bot,
86
+ event: MessageEvent,
87
+ matcher: Matcher,
88
+ ):
89
+ if not await SUPERUSER(bot, event):
90
+ return
91
+ logger.warning('开始执行[重启]')
92
+ qid = event.user_id
93
+ if len(event.get_session_id().split('_')) == 3:
94
+ send_id = event.get_session_id().split('_')[1]
95
+ send_type = 'group'
96
+ else:
97
+ send_id = qid
98
+ send_type = 'private'
99
+ await matcher.send('正在执行[l4重启]...')
100
+ await restart_genshinuid(send_type, str(send_id))
101
+
102
+
103
+ @l4d_update.handle()
104
+ @register_menu(
105
+ '更新插件',
106
+ 'l4更新',
107
+ '手动更新插件',
108
+ detail_des=(
109
+ '介绍:\n'
110
+ '手动更新插件(执行 git pull)\n'
111
+ '每加上一个可选参数,执行等级加1\n'
112
+ '当执行等级≥1时会还原上次更改,等级≥2时会清空暂存\n'
113
+ ' \n'
114
+ '指令:\n'
115
+ '- <ft color=(238,120,0)>l4d</ft>'
116
+ '<ft color=(125,125,125)>(强行)(强制)</ft>'
117
+ '<ft color=(238,120,0)>更新</ft>'
118
+ ),
119
+ )
120
+ async def send_update_msg(
121
+ bot: Bot,
122
+ event: MessageEvent,
123
+ matcher: Matcher,
124
+ args: Tuple[Any, ...] = RegexGroup(),
125
+ ):
126
+ if not await SUPERUSER(bot, event):
127
+ return
128
+
129
+ logger.info('[l4d更新] 正在执行 ...')
130
+ level = 2
131
+ if args[1] is None:
132
+ level -= 1
133
+ if args[2] is None:
134
+ level -= 1
135
+ logger.info(f'[l4d更新] 更新等级为{level}')
136
+ await matcher.send(f'开始执行[l4d更新], 执行等级为{level}')
137
+ im = await draw_update_log_img(level)
138
+ if isinstance(im, str):
139
+ await matcher.finish(im)
140
+ elif isinstance(im, bytes):
141
+ await matcher.finish(MessageSegment.image(im))
142
+ else:
143
+ await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
@@ -0,0 +1,41 @@
1
+ from pathlib import Path
2
+ from typing import Union
3
+
4
+ # from PIL import Image, ImageDraw
5
+
6
+ from .update import update_from_git
7
+ # from ..l4d2_image.image import convert_img
8
+ # from ..l4d2_image.image import get_color_bg
9
+ # from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
10
+
11
+ R_PATH = Path(__file__).parent
12
+ TEXT_PATH = R_PATH / 'texture2d'
13
+
14
+ # gs_font_30 = genshin_font_origin(30)
15
+ black_color = (24, 24, 24)
16
+
17
+ log_config = {
18
+ 'key': '✨🐛🎨⚡🍱♻️',
19
+ 'num': 18,
20
+ }
21
+
22
+ log_map = {'✨': 'feat', '🐛': 'bug', '🍱': 'bento', '⚡️': 'zap', '🎨': 'art'}
23
+
24
+
25
+ async def draw_update_log_img(
26
+ level: int = 0,
27
+ repo_path: Union[str, Path, None] = None,
28
+ is_update: bool = True,
29
+ ) -> Union[bytes, str]:
30
+ log_list = await update_from_git(level, repo_path, log_config, is_update)
31
+ if len(log_list) == 0:
32
+ return '更新失败!更多错误信息请查看控制台...\n' \
33
+ '>> 可以尝试使用\n' \
34
+ '>> [gs强制更新](危险)\n' \
35
+ '>> [gs强行强制更新](超级危险)!'
36
+
37
+ result = 'L4D2Bot 更新记录\n\n'
38
+ for log in log_list:
39
+ result += f'- {log[2:]}\n'
40
+
41
+ return result
@@ -0,0 +1,67 @@
1
+ import os
2
+ import sys
3
+ import json
4
+ import time
5
+ import platform
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+ # from ..utils.db_operation.db_operation import config_check
10
+
11
+ bot_start = Path().cwd() / 'bot.py'
12
+ restart_sh_path = Path().cwd() / 'gs_restart.sh'
13
+ update_log_path = Path(__file__).parent / 'update_log.json'
14
+
15
+ _restart_sh = '''#!/bin/bash
16
+ kill -9 {}
17
+ {} &'''
18
+
19
+
20
+ async def get_restart_sh(extra: str) -> str:
21
+ args = f'{extra} {str(bot_start.absolute())}'
22
+ return _restart_sh.format(str(bot_start.absolute()), args)
23
+
24
+
25
+ async def restart_genshinuid(send_type: str, send_id: str) -> None:
26
+ # extra = ''
27
+ # if await config_check('UsePoetry'):
28
+ # extra = 'poetry run '
29
+ extra = sys.executable
30
+ restart_sh = await get_restart_sh(extra)
31
+ if not restart_sh_path.exists():
32
+ with open(restart_sh_path, "w", encoding="utf8") as f:
33
+ f.write(restart_sh)
34
+ if platform.system() == 'Linux':
35
+ os.system(f'chmod +x {str(restart_sh_path)}')
36
+ os.system(f'chmod +x {str(bot_start)}')
37
+ now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
38
+ update_log = {
39
+ 'type': 'restart',
40
+ 'msg': '重启完成!',
41
+ 'send_type': send_type,
42
+ 'send_to': send_id,
43
+ 'time': now_time,
44
+ }
45
+ with open(str(update_log_path), 'w', encoding='utf-8') as f:
46
+ json.dump(update_log, f)
47
+ if platform.system() == 'Linux':
48
+ os.execl(str(restart_sh_path), ' ')
49
+ else:
50
+ pid = os.getpid()
51
+ subprocess.Popen(
52
+ f'taskkill /F /PID {pid} & {extra} {bot_start}',
53
+ shell=True,
54
+ )
55
+
56
+
57
+ async def restart_message() -> dict:
58
+ if update_log_path.exists():
59
+ with open(update_log_path, 'r', encoding='utf-8') as f:
60
+ update_log = json.load(f)
61
+ msg = f'{update_log["msg"]}\n重启时间:{update_log["time"]}'
62
+ update_log['msg'] = msg
63
+ os.remove(update_log_path)
64
+ os.remove(restart_sh_path)
65
+ return update_log
66
+ else:
67
+ return {}
@@ -0,0 +1,65 @@
1
+ from pathlib import Path
2
+ from typing import List, Union
3
+
4
+ import git
5
+ from nonebot.log import logger
6
+ from git.exc import GitCommandError
7
+
8
+
9
+ async def update_from_git(
10
+ level: int = 0,
11
+ repo_path: Union[str, Path, None] = None,
12
+ log_config: dict = {
13
+ 'key': '✨🐛',
14
+ 'num': 7,
15
+ },
16
+ is_update: bool = True,
17
+ ) -> List[str]:
18
+ if repo_path is None:
19
+ repo_path = Path(__file__).parents[2]
20
+ repo = git.Repo(repo_path) # type: ignore
21
+ o = repo.remotes.origin
22
+
23
+ if is_update:
24
+ # 清空暂存
25
+ if level >= 2:
26
+ logger.warning('[gs更新] 正在执行 git clean --xdf')
27
+ repo.git.clean('-xdf')
28
+ # 还原上次更改
29
+ if level >= 1:
30
+ logger.warning('[gs更新] 正在执行 git reset --hard')
31
+ repo.git.reset('--hard')
32
+
33
+ try:
34
+ pull_log = o.pull()
35
+ logger.info(f'[gs更新] {pull_log}')
36
+ except GitCommandError as e:
37
+ logger.warning(e)
38
+ return []
39
+
40
+ commits = list(repo.iter_commits(max_count=40))
41
+ log_list = []
42
+ for commit in commits:
43
+ if isinstance(commit.message, str):
44
+ for key in log_config['key']:
45
+ if key in commit.message:
46
+ log_list.append(commit.message.replace('\n', ''))
47
+ if len(log_list) >= log_config['num']:
48
+ break
49
+ return log_list
50
+
51
+
52
+ async def update_genshinuid(
53
+ level: int = 0, repo_path: Union[str, Path, None] = None
54
+ ) -> str:
55
+ log_list = await update_from_git(level, repo_path)
56
+ if len(log_list) == 0:
57
+ return (
58
+ '更新失败!更多错误信息请查看控制台...\n '
59
+ '>> 可以尝试使用\n '
60
+ '>> [gs强制更新](危险)\n '
61
+ '>> [gs强行强制更新](超级危险)!'
62
+ )
63
+ log = '\n'.join(log_list)
64
+ logger.info(f'[gs更新]\n{log}')
65
+ return f'更新成功!\n >> 最近有效更新为:\n{log}'