From 08b4fc62aebe5e9f0f6aa323295dfd7de8add5e9 Mon Sep 17 00:00:00 2001 From: yzyyz1387 <1796031384@qq.com> Date: Sat, 30 Sep 2023 04:09:24 +0800 Subject: [PATCH] =?UTF-8?q?:memo:=20v0.1.10=20:bug:=20fix:=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=86=E4=B8=8B=E8=BD=BD=E5=8D=AB=E6=98=9F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=9A=84bug=20:sparkles:=20feat:=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=88=AA=E5=9B=BE=EF=BC=8C=E5=91=BD?= =?UTF-8?q?=E4=BB=A4`/s`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 +++++++- cqsat/config.py | 1 + cqsat/sat/__init__.py | 2 +- cqsat/sat/calculate_sat.py | 43 ++++++------- cqsat/sat/sat_handle.py | 45 +------------ cqsat/sat/shoot_handle.py | 128 +++++++++++++++++++++++++++++++++++++ cqsat/utils.py | 87 +++++++++++++++++++++++-- 7 files changed, 257 insertions(+), 76 deletions(-) create mode 100644 cqsat/sat/shoot_handle.py diff --git a/README.md b/README.md index 745e406..b72b990 100644 --- a/README.md +++ b/README.md @@ -208,15 +208,36 @@ nb plugin install nonebot-plugin-cqsat -### 查看Tevel系列卫星截图 -- 发送`/t` 即可查看网站https://www.df2et.de/tevel/的截图 - +### 查看相关网页截图 +- 发送`/s` 即可查看相关网站的截图 例如 `/s t a` + - t https://www.df2et.de/tevel/ + - a https://amsat.org/status/index.php + - css https://sathunt.com/ + - home https://github.com/yzyyz1387/cqsat + - [ ]... + - 机器人superuser可使用/截图指令 + +### /截图 +- 机器人superuser可使用/截图指令 + - `/截图 add url=xxx path=xxx cmd=xxx proxy=xxx **kwargs` + - url: 截图网址 + - path: 截图保存路径 + - cmd: 截图命令 + - kwargs: 其他参数 + - 若要使用代理,请在机器人`.env.*`配置`sat_proxy_url=http://xx:port` + - `/截图 del url=xxx path=xxx cmd=xxx` + - url /path /cmd 其中之一即可 + - `/截图 get` + - 查看当收录的截图支持列表 + - `/截图 default` + - 恢复默认 ### 娱乐信令 - 发送`/v` ,根据提示回复一条语音,即可对该语音加上信令音 - 可选参数 - `-p` 加前置音 例如:`/v -p` - `-n[数字]` 加噪音 例如:`/v -n5` + - 使用示例: `/v -n5 -p` ### 网格 【私聊、群内】 diff --git a/cqsat/config.py b/cqsat/config.py index b38f210..a84c206 100644 --- a/cqsat/config.py +++ b/cqsat/config.py @@ -14,6 +14,7 @@ class Config(BaseModel, extra=Extra.ignore): nonebot_plugin_go_cqhttp: Optional[bool] = False go_cqhttp_path: Optional[str] = './' + sat_proxy_url: Optional[str] = None global_config = get_driver().config diff --git a/cqsat/sat/__init__.py b/cqsat/sat/__init__.py index ad0562a..a2d3038 100644 --- a/cqsat/sat/__init__.py +++ b/cqsat/sat/__init__.py @@ -5,4 +5,4 @@ # @Email : youzyyz1384@qq.com # @File : __init__.py.py # @Software: PyCharm -from . import calculate_sat, sat_handle +from . import calculate_sat, sat_handle, shoot_handle, sat_shoot_url_bank diff --git a/cqsat/sat/calculate_sat.py b/cqsat/sat/calculate_sat.py index 0cba513..f1d348e 100644 --- a/cqsat/sat/calculate_sat.py +++ b/cqsat/sat/calculate_sat.py @@ -95,22 +95,21 @@ async def download_css_data(): async def download_ham_sat(): Path.mkdir(LOCAL) if not Path.exists(LOCAL) else ... await get_tian_gong() - url = "https://amsat.org/tle/current/nasabare.txt" if timeCompare(CACHE_OTHER, DATA_DICT): logger.info("读取在线数据...") - ham_sat_ = await http_get(url, type_='json') + ham_sat_ = (await http_get(url)) if not ham_sat_: logger.error(f"从 {url} 下载数据出错") return None else: logger.debug("写入本地数据...") - await write_(DATA_DICT, json.dumps(str(ham_sat_), ensure_ascii=False)) + await write_(HAM_SAT, ham_sat_) CACHE_OTHER.touch() return ham_sat_ else: logger.info("读取本地数据...") - ham_sat_ = json.loads(await read_all(DATA_DICT)) + ham_sat_ = await read_all(HAM_SAT) return ham_sat_ @@ -119,25 +118,23 @@ async def data2Tle() -> Dict[str, list]: 将在线数据转换成TLE轨道报 :return: """ - content = await download_ham_sat() - content = {k.upper(): v for k, v in content.items()} - if type(content) == dict: - return content - else: - logger.info("载入卫星TLE数据...") - count = 0 - data = {} - temp = [] - # 将数据分割成行TLE轨道报 - for line in content.split('\n'): - count += 1 - temp.append(line) - if count % 3 == 0: - data[temp[0]] = temp[1:] - count = 0 - temp = [] - await write_(DATA_DICT, json.dumps(data, ensure_ascii=False)) - return data + (await download_ham_sat()) + content = await read_all(HAM_SAT) + logger.info("载入卫星TLE数据...") + count = 0 + data = {} + temp = [] + # 将数据分割成行TLE轨道报 + for line in content.split('\n'): + count += 1 + temp.append(line) + if count % 3 == 0: + data[temp[0]] = temp[1:] + count = 0 + temp = [] + await write_(DATA_DICT, json.dumps(str(data), ensure_ascii=False)) + data = {k.upper(): v for k, v in data.items()} + return data async def calculate(name: str, location: list, time=ephem.now()) -> Optional[list]: diff --git a/cqsat/sat/sat_handle.py b/cqsat/sat/sat_handle.py index db87137..6d6faf9 100644 --- a/cqsat/sat/sat_handle.py +++ b/cqsat/sat/sat_handle.py @@ -224,34 +224,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State, args: Message = Comma for sat in sat_list: reply = "\n".join(sat) messages.append(reply) - if isinstance(event, GroupMessageEvent): - await bot.send_group_forward_msg( - group_id=event.group_id, - messages=[ - { - "type": "node", - "data": { - "name": "卫星列表", - "uin": bot.self_id, - "content": r - }, - } - for r in messages - ]) - else: - await bot.send_private_forward_msg( - user_id=bot.self_id, - messages=[ - { - "type": "node", - "data": { - "name": "卫星列表", - "uin": bot.self_id, - "content": r - }, - } - for r in messages - ]) + await send_forward_msg(bot, event, "收录卫星列表", messages) specified = on_command("查询卫星", aliases={"计算卫星"}, block=True) @@ -315,11 +288,10 @@ async def aps(): return today = datetime.now().strftime("%Y-%m-%d") try: - await download_ham_sat() + data = (await yaml_load(CONFIG)) except FileNotFoundError: - data = await download_ham_sat() - # FIXME ↑??? + data = await data2Tle() for group in data: for qq in data[group]: @@ -392,15 +364,4 @@ async def aps(): # 定时任务 -query_tevel = on_command("/小火车", aliases={"/t", "/查询小火车"}, block=True) - -@query_tevel.handle() -async def query_tevel_(bot: Bot, event: MessageEvent, state: T_State, args: Message = CommandArg()): - if not args: - url = "https://www.df2et.de/tevel/" - await shoot_scr(url, img_output=SHOOTS_OUT_PATH / "tevel.png") - try: - await query_tevel.send(MessageSegment.image(f"file:///{Path(SHOOTS_OUT_PATH / 'tevel.png').resolve()}")) - except: - await query_tevel.send("图片发送失败,哪里出错了?") diff --git a/cqsat/sat/shoot_handle.py b/cqsat/sat/shoot_handle.py new file mode 100644 index 0000000..7799f7f --- /dev/null +++ b/cqsat/sat/shoot_handle.py @@ -0,0 +1,128 @@ +# python3 +# -*- coding: utf-8 -*- +# @Time : 2023-09-29 16:19 +# @Author : yzyyz +# @Email : youzyyz1384@qq.com +# @File : shoot_handle.py +# @Software: PyCharm +import re +from datetime import datetime, timedelta + +from nonebot import on_command, require +from nonebot.adapters import Message +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageSegment, MessageEvent +from nonebot.adapters.onebot.v11.exception import ActionFailed +from nonebot.internal.params import ArgStr +from nonebot.params import CommandArg +from nonebot.permission import SUPERUSER +from nonebot.typing import T_State + +from .calculate_sat import download_ham_sat, data2Tle, calculate, get_tian_gong +from .sat_shoot_url_bank import * +from ..log import log +from ..path import * +from ..config import * +from ..utils import * + +if plugin_config.sat_proxy_url: + logger.info(plugin_config.sat_proxy_url) + +shoot_web = on_command("/s", aliases={"/S"}, block=True) + +url_bank = UrlBank() + + +@shoot_web.handle() +async def query_tevel_(bot: Bot, event: MessageEvent, state: T_State, args: Message = CommandArg()): + not_found = True + Iter_msgs = [] + for item in (url_bank.get()): + tips = "" + for k, v in item.items(): + if k in ['url', 'cmd']: + tips += f"{k}:{v}\n" + Iter_msgs.append(tips) + if args: + args = str(args).strip().split(" ") + for item in (url_bank.get()): + for arg in args: + if arg in item["cmd"]: + not_found = False + url = item["url"] + path = SHOOTS_OUT_PATH / item["path"] + locator = item.get("locator", "html") + time_out = item.get("time_out", 0) + proxy = item.get("proxy", None) + timeout = item.get("timeout", 30000) + if path.exists(): + last_time = datetime.fromtimestamp(path.stat().st_mtime) + TIME_NOW = (datetime.now()) + TIME_DIFF = TIME_NOW - last_time + if TIME_DIFF > timedelta(minutes=float(time_out)): + logger.info("超时,重新截图") + await shoot_scr(url, locator=locator, img_output=path, proxy=proxy, timeout=timeout) + else: + await shoot_scr(url, locator=locator, img_output=path, proxy=proxy, timeout=timeout) + try: + await shoot_web.send(MessageSegment.image(f"file:///{Path(path).resolve()}")) + except Exception as e: + await shoot_web.finish(f"图片发送失败,哪里出错了?\n{e}") + + if not args or not_found: + await shoot_web.send(f"请输入参数:\n例如:/s t a css\n支持的参数:") + await send_forward_msg(bot, event, "收录截图列表", Iter_msgs) + + +bank_handle = on_command("/截图", aliases={"/shoot"}, block=True, permission=SUPERUSER) + + +@bank_handle.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State, args: Message = CommandArg()): + if args: + + # args: add url=xxx cmd=xxx path=xxx locator=xxx + # 检查是否有中文、中文符号 + if re.findall(r'[\u4e00-\u9fa5,。?!:;“”‘’()【】、]', str(args)): + await bank_handle.finish( + "参数错误:不得包含中文字符\n/截图add url=xxx cmd=xxx path=xxx locator=xxx time_out=123 ...") + args = str(args).strip().split(" ") + keyword_ = {} + if args[0] == "add": + for arg in args: + if "=" in arg: + arg = arg.split("=") + keyword_[arg[0]] = (arg[1]).replace("]", "]").replace("[", "[").replace("=", "=") + if keyword_: + if not keyword_.get("url", None) or not keyword_.get("cmd", None) or not keyword_.get("path", None): + await bank_handle.finish("参数错误:\n/截图add url=xxx cmd=xxx path=xxx locator=xxx time_out=123 " + "...\n必须包含url、cmd、path") + url_bank.add(**keyword_) + await bank_handle.finish("添加成功") + else: + await bank_handle.finish("参数错误:\n/截图add url=xxx cmd=xxx path=xxx locator=xxx time_out=123 " + "...\n必须包含url、cmd、path") + elif args[0] == "del": + for arg in args: + if "=" in arg: + arg = arg.split("=") + keyword_[arg[0]] = arg[1].replace("]", "]").replace("[", "[").replace("=", "=") + if keyword_: + url_bank.remove(**keyword_) + await bank_handle.finish("删除成功") + else: + await bank_handle.finish("参数错误:\n/截图del url=xxx cmd=xxx path=xxx" + "...\n必须包含url、cmd、path其中之一") + elif args[0] == "get": + data = url_bank.get() + messages = [] + for i in data: + reply = "" + for k, v in i.items(): + if k in ['cmd', 'url', 'path']: + reply += f"{k}:{v}\n" + messages.append(reply) + + await send_forward_msg(bot, event, "收录截图列表", messages) + elif args[0] == "default": + url_bank.default() + await bank_handle.finish("恢复默认成功") diff --git a/cqsat/utils.py b/cqsat/utils.py index a8a8a76..a05322b 100644 --- a/cqsat/utils.py +++ b/cqsat/utils.py @@ -7,11 +7,11 @@ # @Software: PyCharm import json import random -from typing import Union, Optional, TextIO +from typing import Union, Optional, TextIO, Iterable import httpx import yaml -from nonebot.adapters.onebot.v11 import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent, GroupMessageEvent, Bot from nonebot.matcher import Matcher from .log import log @@ -54,7 +54,7 @@ async def http_post(url: str, data: dict) -> str: return "" -async def write_(path: str, data: str) -> None: +async def write_(path: Union[Path, str], data: str) -> None: """ 写入文件 :param path: 文件路径 @@ -63,7 +63,29 @@ async def write_(path: str, data: str) -> None: """ with open(path, 'w', encoding='utf-8') as f: f.write(data) - f.close() + + +def json_load(path) -> Optional[dict]: + """ + 加载json文件 + :return: Optional[dict] + """ + try: + with open(path, mode='r', encoding='utf-8') as f: + contents = json.load(f) + return contents + except FileNotFoundError: + return None + + +def json_upload(path, dict_content) -> None: + """ + 更新json文件 + :param path: 路径 + :param dict_content: python对象,字典 + """ + with open(path, mode='w', encoding='utf-8') as c: + c.write(json.dumps(dict_content, ensure_ascii=False, indent=2)) async def read_(path: Union[Path, str]) -> TextIO: @@ -245,11 +267,23 @@ async def send_ex( # FIXME 此处return无法访问,但是能跑? -async def shoot_scr(url, locator="html", img_output="out.png"): +async def shoot_scr(url, locator="html", img_output="out.png", proxy=None, timeout=30000) -> None: + """ + 网页截图 + :param url: 地址 + :param locator: 定位器 + :param img_output: 输出路径 + :param proxy: 代理地址 + :param timeout: 超时时间 + :return: + """ browser = await browser_init() - context = await browser.new_context(locale="zh-CN") + if proxy: + context = await browser.new_context(locale="zh-CN", proxy={"server": proxy}) + else: + context = await browser.new_context(locale="zh-CN") page = await context.new_page() - await page.goto(url) + await page.goto(url, timeout=timeout, wait_until="networkidle") await page.locator(locator).screenshot(path=img_output) await browser.close() @@ -270,3 +304,42 @@ def MsgText(data: str): return msg_text except: return '' + + +async def send_forward_msg(bot: Bot, event: MessageEvent, nickname: str, messages: Iterable): + """ + 转发消息 + :param bot: Bot + :param event: event + :param nickname: 昵称 + :param messages: 可迭代消息组 + :return: + """ + if isinstance(event, GroupMessageEvent): + await bot.send_group_forward_msg( + group_id=event.group_id, + messages=[ + { + "type": "node", + "data": { + "name": nickname, + "uin": bot.self_id, + "content": r + }, + } + for r in messages + ]) + else: + await bot.send_private_forward_msg( + user_id=bot.self_id, + messages=[ + { + "type": "node", + "data": { + "name": nickname, + "uin": bot.self_id, + "content": r + }, + } + for r in messages + ])