From 268a9e0f5bc8249ab1deef05a55115b4847221e0 Mon Sep 17 00:00:00 2001 From: student_2333 Date: Mon, 4 Sep 2023 00:17:52 +0800 Subject: [PATCH] fix #39 & try 2 fix #45 --- README.md | 5 ++ nonebot_plugin_bawiki/__init__.py | 2 +- nonebot_plugin_bawiki/command/manga.py | 2 +- nonebot_plugin_bawiki/command/stu_fav.py | 6 +-- nonebot_plugin_bawiki/data/gamekee.py | 46 +++++-------------- nonebot_plugin_bawiki/resource/__init__.py | 5 ++ .../resource/res/js/gamekee_util.js | 39 ++++++++++++++++ nonebot_plugin_bawiki/util.py | 29 ++++++++++++ pyproject.toml | 2 +- 9 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 nonebot_plugin_bawiki/resource/res/js/gamekee_util.js diff --git a/README.md b/README.md index 7b19f11..408196d 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,11 @@ Telegram:[@lgc2333](https://t.me/lgc2333) ## 📝 更新日志 +### 0.8.6 + +- 修复 [#39](https://github.com/lgc-NB2Dev/nonebot-plugin-bawiki/issues/39) +- 尝试修复 [#45](https://github.com/lgc-NB2Dev/nonebot-plugin-bawiki/issues/45) + ### 0.8.5 - 修复 [#41](https://github.com/lgc-NB2Dev/nonebot-plugin-bawiki/issues/41) diff --git a/nonebot_plugin_bawiki/__init__.py b/nonebot_plugin_bawiki/__init__.py index 31764dc..668c52d 100644 --- a/nonebot_plugin_bawiki/__init__.py +++ b/nonebot_plugin_bawiki/__init__.py @@ -8,7 +8,7 @@ from .config import Cfg as Cfg # noqa: E402 from .help import extra, register_help_cmd, usage # noqa: E402 -__version__ = "0.8.5" +__version__ = "0.8.6" __plugin_meta__ = PluginMetadata( name="BAWiki", description="碧蓝档案Wiki插件", diff --git a/nonebot_plugin_bawiki/command/manga.py b/nonebot_plugin_bawiki/command/manga.py index cefaaf9..3a874d0 100644 --- a/nonebot_plugin_bawiki/command/manga.py +++ b/nonebot_plugin_bawiki/command/manga.py @@ -81,7 +81,7 @@ async def get_pic(url): content = await get_manga_content(manga.cid) pics = await asyncio.gather(*[get_pic(x) for x in content.images]) except Exception: - logger.exception("获取漫画失败") + logger.exception(f"获取 CID {manga.cid} 漫画失败") await matcher.finish("获取漫画失败,请检查后台输出") image_seg = [MessageSegment.image(x) for x in pics] diff --git a/nonebot_plugin_bawiki/command/stu_fav.py b/nonebot_plugin_bawiki/command/stu_fav.py index bd7a8c5..1723abb 100644 --- a/nonebot_plugin_bawiki/command/stu_fav.py +++ b/nonebot_plugin_bawiki/command/stu_fav.py @@ -88,8 +88,7 @@ async def get_l2d(stu_name): if not (lvl := stu["MemoryLobby"]): await matcher.finish("该学生没有L2D") - im = MessageSegment.text(f'{stu["Name"]} 在羁绊等级 {lvl[0]} 时即可解锁L2D\n') - image_seg = None + im = Message() + f'{stu["Name"]} 在羁绊等级 {lvl[0]} 时即可解锁L2D\n' if p := await get_l2d(await schale_to_gamekee(arg)): images = await asyncio.gather(*[async_req(x, raw=True) for x in p]) image_seg = "L2D预览:" + Message(MessageSegment.image(x) for x in images) @@ -101,9 +100,10 @@ async def get_l2d(stu_name): "- GameKee页面爬取不到角色L2D图片\n" "- GameKee和插件没有收录该学生的L2D\n" ) + await matcher.finish(im) try: - await matcher.finish(im) + await matcher.finish(im + image_seg) except ActionFailed: if image_seg: await matcher.finish(im + "抱歉,L2D 图片被 tx 风控了,或许是因为太涩了……") diff --git a/nonebot_plugin_bawiki/data/gamekee.py b/nonebot_plugin_bawiki/data/gamekee.py index 0135bd5..1b85cf8 100644 --- a/nonebot_plugin_bawiki/data/gamekee.py +++ b/nonebot_plugin_bawiki/data/gamekee.py @@ -10,16 +10,17 @@ from bs4 import BeautifulSoup, PageElement, ResultSet, Tag from nonebot import logger -from nonebot.adapters.onebot.v11 import MessageSegment +from nonebot.adapters.onebot.v11 import Message, MessageSegment from nonebot.internal.matcher import Matcher from nonebot_plugin_htmlrender import get_new_page +from PIL import Image from PIL.Image import Resampling from pil_utils import BuildImage, text2image from playwright.async_api import Page from ..config import config -from ..resource import RES_CALENDER_BANNER, RES_GRADIENT_BG -from ..util import async_req, parse_time_delta +from ..resource import GAMEKEE_UTIL_JS, RES_CALENDER_BANNER, RES_GRADIENT_BG +from ..util import async_req, i2b, parse_time_delta, split_pic async def game_kee_request(url: str, **kwargs) -> Union[List, Dict[str, Any]]: @@ -75,37 +76,11 @@ def game_kee_page_url(sid: int) -> str: return f"{config.ba_gamekee_url}{sid}.html" -GAMEKEE_WIKI_PAGE_JS = """() => { - // 给内容加上 padding - document.querySelector('div.wiki-detail-body').style.padding = '20px'; - - // 隐藏 Header 避免遮挡页面 - document.querySelector('div.wiki-header').style.display = 'none'; - - // 隐藏关注按钮 - document.querySelector('div.user-box > button').style.display = 'none'; - - // 删掉视频播放器 - for (const it of document.querySelectorAll('div.video-play-wrapper')) - it.remove(); - - // 展开所有选项卡内容 - for (const it of document.querySelectorAll('div.slide-item')) - it.classList.add('active'); - - // 删掉点赞和收藏按钮 - document.querySelector('div.article-options').remove(); - - // 删掉底部边距 - document.querySelector('div.wiki-detail-body').style.marginBottom = '0'; -};""" - - -async def game_kee_get_page(url: str) -> bytes: +async def game_kee_get_page(url: str) -> List[BytesIO]: async with cast(Page, get_new_page()) as page: await page.goto(url, timeout=60 * 1000) - await page.evaluate(GAMEKEE_WIKI_PAGE_JS) + await page.evaluate(GAMEKEE_UTIL_JS) # 展开折叠的语音 folds = await page.query_selector_all("div.fold-table-btn") @@ -116,7 +91,10 @@ async def game_kee_get_page(url: str) -> bytes: element = await page.query_selector("div.wiki-detail-body") if not element: raise ValueError - return await element.screenshot(type="jpeg") + + pic_bytes = await element.screenshot(type="jpeg") + pic = Image.open(BytesIO(pic_bytes)) + return list(map(i2b, split_pic(pic))) async def send_wiki_page(sid: int, matcher: Matcher) -> NoReturn: @@ -124,12 +102,12 @@ async def send_wiki_page(sid: int, matcher: Matcher) -> NoReturn: await matcher.send(f"请稍等,正在截取Wiki页面……\n{url}") try: - img = await game_kee_get_page(url) + images = await game_kee_get_page(url) except Exception: logger.exception(f"截取wiki页面出错 {url}") await matcher.finish("截取页面出错,请检查后台输出") - await matcher.finish(MessageSegment.image(img)) + await matcher.finish(Message(MessageSegment.image(x) for x in images)) async def game_kee_calender() -> Union[List[MessageSegment], str]: diff --git a/nonebot_plugin_bawiki/resource/__init__.py b/nonebot_plugin_bawiki/resource/__init__.py index 8f2089d..eefd21e 100644 --- a/nonebot_plugin_bawiki/resource/__init__.py +++ b/nonebot_plugin_bawiki/resource/__init__.py @@ -33,3 +33,8 @@ RES_GACHA_PICKUP = BuildImage.open(RES_PATH / "gacha_pickup.png") RES_GACHA_STAR = BuildImage.open(RES_PATH / "gacha_star.png") RES_GACHA_STU_ERR = BuildImage.open(RES_PATH / "gacha_stu_err.png") + +RES_JS_DIR = RES_PATH / "js" +RES_GAMEKEE_UTIL_JS_PATH = RES_JS_DIR / "gamekee_util.js" + +GAMEKEE_UTIL_JS = RES_GAMEKEE_UTIL_JS_PATH.read_text(encoding="u8") diff --git a/nonebot_plugin_bawiki/resource/res/js/gamekee_util.js b/nonebot_plugin_bawiki/resource/res/js/gamekee_util.js new file mode 100644 index 0000000..531d033 --- /dev/null +++ b/nonebot_plugin_bawiki/resource/res/js/gamekee_util.js @@ -0,0 +1,39 @@ +() => { + /** + * @param {string} selector + * @param {(obj: HTMLElement) => any} callback + */ + const executeIfExist = (selector, callback) => { + const obj = document.querySelector(selector); + if (obj) callback(obj); + }; + + // 给内容加上 padding + executeIfExist('div.wiki-detail-body', (obj) => (obj.style.padding = '20px')); + + // 隐藏 Header 避免遮挡页面 + executeIfExist('div.wiki-header', (obj) => (obj.style.display = 'none')); + + // 隐藏关注按钮 + executeIfExist( + 'div.user-box > button', + (obj) => (obj.style.display = 'none') + ); + + // 删掉视频播放器 + for (const it of document.querySelectorAll('div.video-play-wrapper')) + it.remove(); + + // 展开所有选项卡内容 + for (const it of document.querySelectorAll('div.slide-item')) + it.classList.add('active'); + + // 删掉点赞和收藏按钮 + executeIfExist('div.article-options', (obj) => obj.remove()); + + // 删掉底部边距 + executeIfExist( + 'div.wiki-detail-body', + (obj) => (obj.style.marginBottom = '0') + ); +}; diff --git a/nonebot_plugin_bawiki/util.py b/nonebot_plugin_bawiki/util.py index c48b97e..6d9af46 100644 --- a/nonebot_plugin_bawiki/util.py +++ b/nonebot_plugin_bawiki/util.py @@ -1,6 +1,7 @@ import datetime import json from dataclasses import dataclass +from io import BytesIO from typing import ( Any, Dict, @@ -206,3 +207,31 @@ def split_list(li: Iterable[T], length: int) -> List[List[T]]: if tmp: latest.append(tmp) return latest + + +def split_pic(pic: Image.Image, max_height: int = 4096) -> List[Image.Image]: + pw, ph = pic.size + if ph <= max_height: + return [pic] + + ret = [] + need_merge_last = ph % max_height < max_height // 2 + iter_times = ph // max_height + + now_h = 0 + for i in range(iter_times): + if i == iter_times - 1 and need_merge_last: + ret.append(pic.crop((0, now_h, pw, ph))) + break + + ret.append(pic.crop((0, now_h, pw, now_h + max_height))) + now_h += max_height + + return ret + + +def i2b(image: Image.Image, img_format: str = "JPEG") -> BytesIO: + buf = BytesIO() + image.save(buf, img_format) + buf.seek(0) + return buf diff --git a/pyproject.toml b/pyproject.toml index d24598b..5fd6111 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "nonebot-plugin-bawiki" -version = "0.8.5" +version = "0.8.6" description = "A nonebot2 plugin for Blue Archive." authors = [{ name = "student_2333", email = "lgc2333@126.com" }] dependencies = [