diff --git a/plugins/fanhao_search/config.toml b/plugins/fanhao_search/config.toml index 180620f..9c8fd89 100644 --- a/plugins/fanhao_search/config.toml +++ b/plugins/fanhao_search/config.toml @@ -20,9 +20,14 @@ http_proxy = "" allow_download_link = true # 是否发送封面预览图(默认关闭) -allow_preview_cover = false +allow_preview_cover = true # 当开启磁力时,是否优先返回“带字幕”磁力 prefer_subtitle_magnet = true +# 封面图是否开启全图模糊(建议开启) +cover_blur_enable = true + +# 全图模糊强度(高斯半径,数值越大越模糊) +cover_blur_radius = 18 diff --git a/plugins/fanhao_search/main.py b/plugins/fanhao_search/main.py index be8791f..c58cd11 100644 --- a/plugins/fanhao_search/main.py +++ b/plugins/fanhao_search/main.py @@ -1,10 +1,12 @@ from typing import Any, Dict, List, Optional, Tuple import re from urllib.parse import urljoin +import io import aiohttp from bs4 import BeautifulSoup from loguru import logger +from PIL import Image, ImageFilter from base.plugin_common.message_plugin_interface import MessagePluginInterface from base.plugin_common.plugin_interface import PluginStatus @@ -73,6 +75,9 @@ class FanhaoSearchPlugin(MessagePluginInterface): self.allow_download_link = False self.allow_preview_cover = False self.prefer_subtitle_magnet = True + # 封面图降敏配置:默认开启全图模糊,降低群内图片内容风险。 + self.cover_blur_enable = True + self.cover_blur_radius = 18 def initialize(self, context: Dict[str, Any]) -> bool: """初始化插件配置。""" @@ -90,11 +95,14 @@ class FanhaoSearchPlugin(MessagePluginInterface): self.allow_download_link = bool(cfg.get("allow_download_link", False)) self.allow_preview_cover = bool(cfg.get("allow_preview_cover", False)) self.prefer_subtitle_magnet = bool(cfg.get("prefer_subtitle_magnet", True)) + self.cover_blur_enable = bool(cfg.get("cover_blur_enable", True)) + self.cover_blur_radius = max(1, int(cfg.get("cover_blur_radius", 18) or 18)) self.LOG.info( f"[{self.name}] 初始化完成: enable={self.enable}, commands={self._commands}, " f"base_url={self.javbus_base_url}, allow_download_link={self.allow_download_link}, " - f"allow_preview_cover={self.allow_preview_cover}, timeout={self.request_timeout_seconds}s" + f"allow_preview_cover={self.allow_preview_cover}, cover_blur_enable={self.cover_blur_enable}, " + f"cover_blur_radius={self.cover_blur_radius}, timeout={self.request_timeout_seconds}s" ) return True @@ -176,6 +184,32 @@ class FanhaoSearchPlugin(MessagePluginInterface): raise RuntimeError(f"图片下载失败 status={resp.status}, url={url}") return await resp.read() + def _apply_full_blur_to_image_bytes(self, image_bytes: bytes) -> bytes: + """对图片执行全图高斯模糊。 + + 设计说明: + 1. 这里使用 Pillow 的 GaussianBlur 对整图处理,不做局部区域判断; + 2. 输出统一转为 JPEG,避免源图格式差异导致发送失败; + 3. 若处理异常则回退原图,保证主流程可用性。 + """ + if not image_bytes: + return image_bytes + if not self.cover_blur_enable: + return image_bytes + try: + with Image.open(io.BytesIO(image_bytes)) as image: + # 转为 RGB 统一颜色空间,避免 RGBA 保存 JPEG 报错。 + if image.mode in ("RGBA", "P"): + image = image.convert("RGB") + # 全图高斯模糊,半径可在配置中调整。 + blurred = image.filter(ImageFilter.GaussianBlur(radius=float(self.cover_blur_radius))) + output = io.BytesIO() + blurred.save(output, format="JPEG", quality=88) + return output.getvalue() + except Exception as e: + self.LOG.warning(f"[{self.name}] 封面全图模糊失败,回退原图: error={e}") + return image_bytes + @staticmethod def _extract_plain_value_from_info_p(info_p) -> str: """从详情页

节点中提取纯文本值。 @@ -462,6 +496,8 @@ class FanhaoSearchPlugin(MessagePluginInterface): if cover_url: try: cover_bytes = await self._http_get_bytes(cover_url, referer=detail_url) + # 发送前执行全图模糊,避免直接发送原始封面。 + cover_bytes = self._apply_full_blur_to_image_bytes(cover_bytes) await bot.send_image_message(target, cover_bytes) except Exception as cover_error: self.LOG.warning(f"[{self.name}] 封面发送失败: code={normalized_code}, error={cover_error}") @@ -475,4 +511,3 @@ class FanhaoSearchPlugin(MessagePluginInterface): def get_plugin(): """返回插件实例。""" return FanhaoSearchPlugin() -