diff --git a/README.md b/README.md index 24caa17b..0272c760 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,15 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__ ## 更新 +### 2022/5/22 \[v0.1.5.4] + +* 使用action自动更新poetry.lock [@pull/515](https://github.com/HibiKier/zhenxun_bot/pull/515) +* fix(bilibili_sub): card is None and timeout [@pull/516](https://github.com/HibiKier/zhenxun_bot/pull/516) +* 修复了epic有时获取新免费游戏消息时获取不到图片 +* 修复好感度满时签到出错(虽然是不可能满的 +* 修复原神资源图标下载路径错误 +* 修复自动更新群组可能失败 + ### 2022/5/21 * 修复搜番无结果时报错无正确反馈 @@ -279,7 +288,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__ * fix: 更改p搜api,解决p搜无法使用的问题 [@pull/155](https://github.com/HibiKier/zhenxun_bot/pull/155) -### 2022/5/9 +### 2022/5/9 \[v0.1.5.3] * 替换了疫情API * 修复了私聊.ban/.unban出错 diff --git a/__version__ b/__version__ index ac0eeee1..287794ee 100644 --- a/__version__ +++ b/__version__ @@ -1 +1 @@ -__version__: v0.1.5.3 \ No newline at end of file +__version__: v0.1.5.4 diff --git a/basic_plugins/super_cmd/manager_group.py b/basic_plugins/super_cmd/manager_group.py index 27445265..272e0098 100755 --- a/basic_plugins/super_cmd/manager_group.py +++ b/basic_plugins/super_cmd/manager_group.py @@ -92,7 +92,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): level = 0 if not msg: await add_group_level.finish("用法:修改群权限 [group] [level]") - msg = msg.split(" ") + msg = msg.split() if len(msg) < 2: await add_group_level.finish("参数不完全..[group] [level]") if is_number(msg[0]) and is_number(msg[1]): diff --git a/basic_plugins/super_cmd/update_friend_group_info.py b/basic_plugins/super_cmd/update_friend_group_info.py index c0479624..8f528c78 100755 --- a/basic_plugins/super_cmd/update_friend_group_info.py +++ b/basic_plugins/super_cmd/update_friend_group_info.py @@ -45,6 +45,7 @@ async def _(): group_info["group_name"], group_info["max_member_count"], group_info["member_count"], + 1 ): num += 1 logger.info(f"自动更新群组 {g} 信息成功") diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py index db024e19..1f0a7397 100755 --- a/plugins/ai/__init__.py +++ b/plugins/ai/__init__.py @@ -37,7 +37,7 @@ Config.add_plugin_config( "alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token" ) -ai = on_message(rule=to_me(), priority=8) +ai = on_message(rule=to_me(), priority=998) @ai.handle() diff --git a/plugins/bilibili_sub/data_source.py b/plugins/bilibili_sub/data_source.py index d495572a..7aefedae 100755 --- a/plugins/bilibili_sub/data_source.py +++ b/plugins/bilibili_sub/data_source.py @@ -324,7 +324,7 @@ async def get_user_dynamic( wait_until="networkidle", timeout=10000, ) - await page.set_viewport_size({"width": 2560, "height": 1080}) + await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s # 删除置顶 await page.evaluate( """ @@ -334,11 +334,11 @@ async def get_user_dynamic( } """ ) - card = await page.query_selector(".bili-dyn-list__item") + card = page.locator(".bili-dyn-list__item").first + await card.wait_for() # 截图并保存 await card.screenshot( path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg", - timeout=100000, ) except Exception as e: logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}") diff --git a/plugins/bt/data_source.py b/plugins/bt/data_source.py index a7754625..283d3399 100755 --- a/plugins/bt/data_source.py +++ b/plugins/bt/data_source.py @@ -3,10 +3,10 @@ from configs.config import Config from bs4 import BeautifulSoup import platform -if platform.system() == "Windows": - import asyncio - - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) +# if platform.system() == "Windows": +# import asyncio +# +# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) url = "http://www.eclzz.mobi" diff --git a/plugins/check_zhenxun_update/data_source.py b/plugins/check_zhenxun_update/data_source.py index ce02ac84..21c2fa44 100755 --- a/plugins/check_zhenxun_update/data_source.py +++ b/plugins/check_zhenxun_update/data_source.py @@ -14,9 +14,9 @@ import tarfile import shutil import os -if str(platform.system()).lower() == "windows": - policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(policy) +# if str(platform.system()).lower() == "windows": +# policy = asyncio.WindowsSelectorEventLoopPolicy() +# asyncio.set_event_loop_policy(policy) driver = nonebot.get_driver() diff --git a/plugins/epic/data_source.py b/plugins/epic/data_source.py index e8785054..a4399f7d 100755 --- a/plugins/epic/data_source.py +++ b/plugins/epic/data_source.py @@ -1,58 +1,34 @@ -from httpx import AsyncClient from datetime import datetime from nonebot.log import logger from nonebot.adapters.onebot.v11 import Bot from configs.config import NICKNAME +from utils.http_utils import AsyncHttpx # 获取所有 Epic Game Store 促销游戏 # 方法参考:RSSHub /epicgames 路由 # https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js async def get_epic_game(): - # 现在没用 graphql 辣 - """prv_graphql Code - epic_url = "https://www.epicgames.com/store/backend/graphql-proxy" - headers = { - "Referer": "https://www.epicgames.com/store/zh-CN/", - "Content-Type": "application/json; charset=utf-8", - } - data = { - "query": "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, $keywords: String, $locale: String, $namespace: String, $sortBy: String, $sortDir: String, $start: Int, $tag: String, $withPrice: Boolean = false, $withPromotions: Boolean = false) {\n Catalog {\n searchStore(allowCountries: $allowCountries, category: $category, count: $count, country: $country, keywords: $keywords, locale: $locale, namespace: $namespace, sortBy: $sortBy, sortDir: $sortDir, start: $start, tag: $tag) {\n elements {\n title\n id\n namespace\n description\n effectiveDate\n keyImages {\n type\n url\n }\n seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n items {\n id\n namespace\n }\n customAttributes {\n key\n value\n }\n categories {\n path\n }\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n voucherDiscount\n discount\n currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n id\n endDate\n discountSetting {\n discountType\n }\n }\n }\n }\n promotions(category: $category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n }\n }\n paging {\n count\n total\n }\n }\n }\n}\n", - "variables": { - "allowCountries": "CN", - "category": "freegames", - "count": 1000, - "country": "CN", - "locale": "zh-CN", - "sortBy": "effectiveDate", - "sortDir": "asc", - "withPrice": True, - "withPromotions": True, - }, - } - """ - epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN" headers = { "Referer": "https://www.epicgames.com/store/zh-CN/", "Content-Type": "application/json; charset=utf-8", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", } - async with AsyncClient(headers=headers) as client: - try: - res = await client.get(epic_url, timeout=10.0) - res_json = res.json() - games = res_json["data"]["Catalog"]["searchStore"]["elements"] - return games - except Exception as e: - logger.error(str(e)) - return None + try: + res = await AsyncHttpx.get(epic_url, headers=headers, timeout=10) + res_json = res.json() + games = res_json["data"]["Catalog"]["searchStore"]["elements"] + return games + except Exception as e: + logger.error(f"Epic 访问接口错误 {type(e)}:{e}") + return None # 获取 Epic Game Store 免费游戏信息 # 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例 # https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py -async def get_epic_free(bot: Bot, Type_Event: str): +async def get_epic_free(bot: Bot, type_event: str): games = await get_epic_game() if not games: return "Epic 可能又抽风啦,请稍后再试(", 404 @@ -81,7 +57,7 @@ async def get_epic_free(bot: Bot, Type_Event: str): end_date = datetime.fromisoformat(end_date_iso).strftime( "%b.%d %H:%M" ) - if Type_Event == "Group": + if type_event == "Group": _message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format( game_corp, game_name, game_price, start_date, end_date ) @@ -101,8 +77,19 @@ async def get_epic_free(bot: Bot, Type_Event: str): msg_list.append(msg) else: for image in game["keyImages"]: - if image["type"] == "Thumbnail": + if ( + image.get("url") + and not game_thumbnail + and image["type"] + in [ + "Thumbnail", + "VaultOpened", + "DieselStoreFrontWide", + "OfferImageWide", + ] + ): game_thumbnail = image["url"] + break for pair in game["customAttributes"]: if pair["key"] == "developerName": game_dev = pair["value"] @@ -127,7 +114,7 @@ async def get_epic_free(bot: Bot, Type_Event: str): game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format( game_url_part ) - if Type_Event == "Group": + if type_event == "Group": _message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format( game_thumbnail, game_name, diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py index d5465ce2..eb71e58a 100755 --- a/plugins/genshin/query_resource_points/query_resource.py +++ b/plugins/genshin/query_resource_points/query_resource.py @@ -1,3 +1,4 @@ +from pathlib import Path from typing import Tuple, Optional, List from configs.path_config import IMAGE_PATH, TEXT_PATH from utils.message_builder import image @@ -136,7 +137,7 @@ async def download_resource_data(semaphore: Semaphore): asyncio.ensure_future( download_image( img_url, - f"{icon_path}/{id_}.png", + icon_path / f"{id_}.png", semaphore, True, ) @@ -178,7 +179,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False): map_url = _map_data["url"] await download_image( map_url, - f"{map_path}/{idx}.png", + map_path / f"{idx}.png", semaphore, force_flag=flag, ) @@ -227,15 +228,14 @@ async def download_resource_type(): except (TimeoutError, ConnectTimeout): logger.warning("下载原神资源类型数据超时....") except Exception as e: - logger.error(f"载原神资源类型数据超时 {type(e)}:{e}") + logger.error(f"载原神资源类型数据错误 {type(e)}:{e}") # 初始化资源图标 -def gen_icon(icon: str): +def gen_icon(icon: Path): A = BuildImage(0, 0, background=f"{icon_path}/box.png") B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png") - icon_ = icon_path / f"{icon}" - icon_img = BuildImage(115, 115, background=icon_) + icon_img = BuildImage(115, 115, background=icon) icon_img.circle() B.paste(icon_img, (17, 10), True) B.paste(A, alpha=True) @@ -246,14 +246,14 @@ def gen_icon(icon: str): # 下载图片 async def download_image( img_url: str, - path: str, + path: Path, semaphore: Semaphore, gen_flag: bool = False, force_flag: bool = False, ): async with semaphore: try: - if not os.path.exists(path) or not is_valid or force_flag: + if not path.exists() or not is_valid(path) or force_flag: if await AsyncHttpx.download_file(img_url, path, timeout=10): logger.info(f"下载原神资源图标:{img_url}") if gen_flag: diff --git a/plugins/pid_search.py b/plugins/pid_search.py index d795a10c..dfd75277 100755 --- a/plugins/pid_search.py +++ b/plugins/pid_search.py @@ -1,7 +1,9 @@ from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State -from utils.utils import is_number + +from configs.config import Config +from utils.utils import is_number, change_pixiv_image_links from utils.message_builder import image from services.log import logger from asyncio.exceptions import TimeoutError @@ -31,8 +33,6 @@ __plugin_settings__ = { pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True) -url = "https://api.obfs.dev/api/pixiv/" - @pid_search.handle() async def _h(event: MessageEvent, state: T_State, arg: Message = CommandArg()): @@ -50,6 +50,7 @@ headers = { @pid_search.got("pid", prompt="需要查询的图片PID是?") async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")): + url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/" if pid in ["取消", "算了"]: await pid_search.finish("已取消操作...") if not is_number(pid): @@ -68,6 +69,8 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")): except Exception as e: await pid_search.finish(f"发生了一些错误..{type(e)}:{e}") else: + if data.get("error"): + await pid_search.finish(data["error"]["user_message"], at_sender=True) data = data["illust"] if not data["width"] and not data["height"]: await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True) @@ -82,6 +85,7 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")): for image_url in data["meta_pages"]: image_list.append(image_url["image_urls"]["original"]) for i, img_url in enumerate(image_list): + img_url = change_pixiv_image_links(img_url) if not await AsyncHttpx.download_file( img_url, IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png", diff --git a/plugins/pix_gallery/_data_source.py b/plugins/pix_gallery/_data_source.py index 5fb2faf1..f991c66e 100644 --- a/plugins/pix_gallery/_data_source.py +++ b/plugins/pix_gallery/_data_source.py @@ -20,9 +20,9 @@ try: except ModuleNotFoundError: import json -if str(platform.system()).lower() == "windows": - policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(policy) +# if str(platform.system()).lower() == "windows": +# policy = asyncio.WindowsSelectorEventLoopPolicy() +# asyncio.set_event_loop_policy(policy) headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" diff --git a/plugins/pixiv_rank_search/data_source.py b/plugins/pixiv_rank_search/data_source.py index 82d3b068..83792a49 100755 --- a/plugins/pixiv_rank_search/data_source.py +++ b/plugins/pixiv_rank_search/data_source.py @@ -8,10 +8,10 @@ from services.log import logger from pathlib import Path import platform -if platform.system() == "Windows": - import asyncio - - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) +# if platform.system() == "Windows": +# import asyncio +# +# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) headers = { diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py index a73f7655..4d109ab3 100755 --- a/plugins/sign_in/utils.py +++ b/plugins/sign_in/utils.py @@ -55,13 +55,10 @@ async def get_card( date = datetime.now().date() _type = "view" if is_card_view else "sign" card_file = ( - Path(SIGN_TODAY_CARD_PATH) - / f"{user_id}_{user.group_id}_{_type}_{date}.png" + Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.group_id}_{_type}_{date}.png" ) if card_file.exists(): - return image( - f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card" - ) + return image(f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card") else: if add_impression == -1: card_file = ( @@ -75,9 +72,7 @@ async def get_card( ) is_card_view = True ava = BytesIO(await get_user_avatar(user_id)) - uid = await GroupInfoUser.get_group_member_uid( - user.user_qq, user.group_id - ) + uid = await GroupInfoUser.get_group_member_uid(user.user_qq, user.group_id) impression_list = None if is_card_view: _, impression_list, _ = await SignGroupUser.get_all_impression( @@ -128,9 +123,13 @@ def _generate_card( level, next_impression, previous_impression = get_level_and_next_impression( user.impression ) + interpolation = next_impression - user.impression + if level == "9": + level = "8" + interpolation = 0 info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]") info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}") - info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度") + info_img.text((0, 40), f"· 距离升级还差 {interpolation:.2f} 好感度") bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png") bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png") @@ -240,7 +239,9 @@ def _generate_card( f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}", ) today_data.text((0, 25), f"总金币:{gold}") - default_setu_prob = Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100 + default_setu_prob = ( + Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100 + ) today_data.text( (0, 50), f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%", @@ -286,12 +287,8 @@ def _generate_card( bk.paste(today_sign_text_img, (550, 180), True) bk.paste(today_data, (580, 220), True) bk.paste(watermark, (15, 400), True) - bk.save( - SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png" - ) - return image( - f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card" - ) + bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png") + return image(f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card") def generate_progress_bar_pic(): diff --git a/plugins/update_gocqhttp/data_source.py b/plugins/update_gocqhttp/data_source.py index 9383648d..1572e90e 100755 --- a/plugins/update_gocqhttp/data_source.py +++ b/plugins/update_gocqhttp/data_source.py @@ -5,8 +5,8 @@ import asyncio import platform import os -if platform.system() == "Windows": - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) +# if platform.system() == "Windows": +# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) url = "https://github.com/Mrs4s/go-cqhttp/releases" diff --git a/utils/image_utils.py b/utils/image_utils.py index 471f0535..7280f4a7 100755 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -121,7 +121,7 @@ def fig2b64(plt_: plt) -> str: return "base64://" + base64_str -def is_valid(file: str) -> bool: +def is_valid(file: Union[str, Path]) -> bool: """ 说明: 判断图片是否损坏 diff --git a/utils/utils.py b/utils/utils.py index 7133da6a..581c7df5 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,7 +1,7 @@ from datetime import datetime from collections import defaultdict from nonebot import require -from configs.config import SYSTEM_PROXY +from configs.config import SYSTEM_PROXY, Config from typing import List, Union, Optional, Type, Any from nonebot.adapters.onebot.v11 import Bot, Message from nonebot.matcher import matchers, Matcher @@ -389,6 +389,8 @@ def change_pixiv_image_links( url = img_sp[0] img_type = img_sp[1] url = url.replace("original", "master") + f"_master1200.{img_type}" + if not nginx_url: + nginx_url = Config.get_config("pixiv", "PIXIV_NGINX_URL") if nginx_url: url = ( url.replace("i.pximg.net", nginx_url)