番号插件新增封面全图模糊,发送前自动遮罩处理

变更项:

1. 在 fanhao_search 插件中新增全图高斯模糊处理函数,发送封面前统一执行。

2. 增加 cover_blur_enable 与 cover_blur_radius 配置项,支持开关和模糊强度调节。

3. 封面处理失败时回退原图并记录日志,保证主流程可用。

4. 初始化日志补充模糊配置参数,便于排查线上行为。
This commit is contained in:
liuwei
2026-04-22 12:29:11 +08:00
parent 62f7a9f2d4
commit 3e52ba2a82
2 changed files with 43 additions and 3 deletions

View File

@@ -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

View File

@@ -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:
"""从详情页 <p> 节点中提取纯文本值。
@@ -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()