From fabeb4711fdeef6a8eeb41b111de0d9c9abb027c Mon Sep 17 00:00:00 2001 From: HibiKier <775757368@qq.com> Date: Tue, 28 May 2024 14:22:24 +0800 Subject: [PATCH] =?UTF-8?q?feat=E2=9C=A8:=20=E5=A4=8D=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 121 +++++++++++++++++++++++- pyproject.toml | 1 + zhenxun/plugins/fudu.py | 172 +++++++++++++++++++++++++++++++++++ zhenxun/utils/image_utils.py | 17 ++++ 4 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 zhenxun/plugins/fudu.py diff --git a/poetry.lock b/poetry.lock index f1770cb4..2c7c7abd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -910,6 +910,28 @@ type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" reference = "ali" +[[package]] +name = "imagehash" +version = "4.3.1" +description = "Image Hashing library" +optional = false +python-versions = "*" +files = [ + {file = "ImageHash-4.3.1-py2.py3-none-any.whl", hash = "sha256:5ad9a5cde14fe255745a8245677293ac0d67f09c330986a351f34b614ba62fb5"}, + {file = "ImageHash-4.3.1.tar.gz", hash = "sha256:7038d1b7f9e0585beb3dd8c0a956f02b95a346c0b5f24a9e8cc03ebadaf0aa70"}, +] + +[package.dependencies] +numpy = "*" +pillow = "*" +PyWavelets = "*" +scipy = "*" + +[package.source] +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" +reference = "ali" + [[package]] name = "iso8601" version = "1.1.0" @@ -2225,6 +2247,56 @@ type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" reference = "ali" +[[package]] +name = "pywavelets" +version = "1.6.0" +description = "PyWavelets, wavelet transform module" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pywavelets-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ddc1ff5ad706313d930f857f9656f565dfb81b85bbe58a9db16ad8fa7d1537c5"}, + {file = "pywavelets-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:78feab4e0c25fa32034b6b64cb854c6ce15663b4f0ffb25d8f0ee58915300f9b"}, + {file = "pywavelets-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be36f08efe9bc3abf40cf40cd2ee0aa0db26e4894e13ce5ac178442864161e8c"}, + {file = "pywavelets-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0595c51472c9c5724fe087cb73e2797053fd25c788d6553fdad6ff61abc60e91"}, + {file = "pywavelets-1.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:058a750477dde633ac53b8806f835af3559d52db6532fb2b93c1f4b5441365b8"}, + {file = "pywavelets-1.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:538795d9c4181152b414285b5a7f72ac52581ecdcdce74b6cca3fa0b8a5ab0aa"}, + {file = "pywavelets-1.6.0-cp310-cp310-win32.whl", hash = "sha256:47de024ba4f9df97e98b5f540340e1a9edd82d2c477450bef8c9b5381487128e"}, + {file = "pywavelets-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e2c44760c0906ddf2176920a2613287f6eea947f166ce7eee9546081b06a6835"}, + {file = "pywavelets-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d91aaaf6de53b758bcdc96c81cdb5a8607758602be49f691188c0e108cf1e738"}, + {file = "pywavelets-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b5302edb6d1d1ff6636d37c9ff29c4892f2a3648d736cc1df01f3f36e25c8cf"}, + {file = "pywavelets-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5e655446e37a3c87213d5c6386b86f65c4d61736b4432d720171e7dd6523d6a"}, + {file = "pywavelets-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ec7d69b746a0eaa327b829a3252a63619f2345e263177be5dd9bf30d7933c8d"}, + {file = "pywavelets-1.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:97ea9613bd6b7108ebb44b709060adc7e2d5fac73be7152342bdd5513d75f84e"}, + {file = "pywavelets-1.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:48b3813c6d1a7a8194f37dbb5dbbdf2fe1112152c91445ea2e54f64ff6350c36"}, + {file = "pywavelets-1.6.0-cp311-cp311-win32.whl", hash = "sha256:4ffb484d096a5eb10af7121e0203546a03e1369328df321a33ef91f67bac40cf"}, + {file = "pywavelets-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:274bc47b289585383aa65519b3fcae5b4dee5e31db3d4198d4fad701a70e59f7"}, + {file = "pywavelets-1.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d6ec113386a432e04103f95e351d2657b42145bd1e1ed26513423391bcb5f011"}, + {file = "pywavelets-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab652112d3932d21f020e281e06926a751354c2b5629fb716f5eb9d0104b84e5"}, + {file = "pywavelets-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47b0314a22616c5f3f08760f0e00b4a15b7c7dadca5e39bb701cf7869a4207c5"}, + {file = "pywavelets-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138471513bc0a4cd2ddc4e50c7ec04e3468c268e101a0d02f698f6aedd1d5e79"}, + {file = "pywavelets-1.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67936491ae3e5f957c428e34fdaed21f131535b8d60c7c729a1b539ce8864837"}, + {file = "pywavelets-1.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:dd798cee3d28fb3d32a26a00d9831a20bf316c36d685e4ced01b4e4a8f36f5ce"}, + {file = "pywavelets-1.6.0-cp312-cp312-win32.whl", hash = "sha256:e772f7f0c16bfc3be8ac3cd10d29a9920bb7a39781358856223c491b899e6e79"}, + {file = "pywavelets-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:4ef15a63a72afa67ae9f4f3b06c95c5382730fb3075e668d49a880e65f2f089c"}, + {file = "pywavelets-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:627df378e63e9c789b6f2e7060cb4264ebae6f6b0efc1da287a2c060de454a1f"}, + {file = "pywavelets-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a413b51dc19e05243fe0b0864a8e8a16b5ca9bf2e4713da00a95b1b5747a5367"}, + {file = "pywavelets-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be615c6c1873e189c265d4a76d1751ec49b17e29725e6dd2e9c74f1868f590b7"}, + {file = "pywavelets-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4021ef69ec9f3862f66580fc4417be728bd78722914394594b48212fd1fcaf21"}, + {file = "pywavelets-1.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8fbf7b61b28b5457693c034e58a01622756d1fd60a80ae13ac5888b1d3e57e80"}, + {file = "pywavelets-1.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f58ddbb0a6cd243928876edfc463b990763a24fb94498607d6fea690e32cca4c"}, + {file = "pywavelets-1.6.0-cp39-cp39-win32.whl", hash = "sha256:42a22e68e345b6de7d387ef752111ab4530c98048d2b4bdac8ceefb078b4ead6"}, + {file = "pywavelets-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:32198de321892743c1a3d1957fe1cd8a8ecc078bfbba6b8f3982518e897271d7"}, + {file = "pywavelets-1.6.0.tar.gz", hash = "sha256:ea027c70977122c5fc27b2510f0a0d9528f9c3df6ea3e4c577ca55fd00325a5b"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<3" + +[package.source] +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" +reference = "ali" + [[package]] name = "pyyaml" version = "6.0.1" @@ -2445,6 +2517,53 @@ type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" reference = "ali" +[[package]] +name = "scipy" +version = "1.13.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[package.source] +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" +reference = "ali" + [[package]] name = "sgmllib3k" version = "1.0.0" @@ -3284,4 +3403,4 @@ reference = "ali" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "76aa9b04323c716cda8d3e79a552d35c3f2d96eac39682c6c9c6b59291cbd398" +content-hash = "c1da4a148819ff244d291be9ca67466a07d994f29d2c1821a2e640997bfe617c" diff --git a/pyproject.toml b/pyproject.toml index d218ba31..9181a780 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ lxml = "^5.1.0" psutil = "^5.9.8" feedparser = "^6.0.11" opencv-python = "^4.9.0.80" +imagehash = "^4.3.1" [tool.poetry.dev-dependencies] diff --git a/zhenxun/plugins/fudu.py b/zhenxun/plugins/fudu.py new file mode 100644 index 00000000..bb00565d --- /dev/null +++ b/zhenxun/plugins/fudu.py @@ -0,0 +1,172 @@ +import random + +from nonebot import on_message +from nonebot.adapters import Event +from nonebot.plugin import PluginMetadata +from nonebot_plugin_alconna import Image as alcImg +from nonebot_plugin_alconna import UniMsg +from nonebot_plugin_saa import Image, MessageFactory, Text +from nonebot_plugin_session import EventSession + +from zhenxun.configs.config import NICKNAME, Config +from zhenxun.configs.path_config import TEMP_PATH +from zhenxun.configs.utils import PluginExtraData, RegisterConfig, Task +from zhenxun.models.task_info import TaskInfo +from zhenxun.services.log import logger +from zhenxun.utils.enum import PluginType +from zhenxun.utils.http_utils import AsyncHttpx +from zhenxun.utils.image_utils import get_img_hash +from zhenxun.utils.rules import ensure_group + +__plugin_meta__ = PluginMetadata( + name="复读", + description="群友的本质是什么?是复读机哒!", + usage=""" + usage: + 重复3次相同的消息时会复读 + """.strip(), + extra=PluginExtraData( + author="HibiKier", + version="0.1", + menu_type="其他", + plugin_type=PluginType.HIDDEN, + tasks=[Task(module="fudu", name="复读")], + configs=[ + RegisterConfig( + key="FUDU_PROBABILITY", + value=0.7, + help="复读概率", + default_value=0.7, + type=float, + ), + RegisterConfig( + module="_task", + key="DEFAULT_FUDU", + value=True, + help="被动 复读 进群默认开关状态", + default_value=True, + type=bool, + ), + ], + ).dict(), +) + + +class Fudu: + def __init__(self): + self.data = {} + + def append(self, key, content): + self._create(key) + self.data[key]["data"].append(content) + + def clear(self, key): + self._create(key) + self.data[key]["data"] = [] + self.data[key]["is_repeater"] = False + + def size(self, key) -> int: + self._create(key) + return len(self.data[key]["data"]) + + def check(self, key, content) -> bool: + self._create(key) + return self.data[key]["data"][0] == content + + def get(self, key): + self._create(key) + return self.data[key]["data"][0] + + def is_repeater(self, key): + self._create(key) + return self.data[key]["is_repeater"] + + def set_repeater(self, key): + self._create(key) + self.data[key]["is_repeater"] = True + + def _create(self, key): + if self.data.get(key) is None: + self.data[key] = {"is_repeater": False, "data": []} + + +_manage = Fudu() + + +_matcher = on_message(rule=ensure_group, priority=999) + + +@_matcher.handle() +async def _(message: UniMsg, event: Event, session: EventSession): + task = await TaskInfo.get_or_none(module="fudu") + if task and not task.status: + return + if event.is_tome(): + return + group_id = session.id2 or "" + plain_text = message.extract_plain_text() + image_list = [] + for m in message: + if isinstance(m, alcImg): + if m.url: + image_list.append(m.url) + if not plain_text and not image_list: + return + if plain_text and plain_text.startswith(f"@可爱的{NICKNAME}"): + await Text("复制粘贴的虚空艾特?").send(reply=True) + if image_list: + img_hash = await get_fudu_img_hash(image_list[0], group_id) + else: + img_hash = "" + add_msg = plain_text + "|-|" + img_hash + if _manage.size(group_id) == 0: + _manage.append(group_id, add_msg) + elif _manage.check(group_id, add_msg): + _manage.append(group_id, add_msg) + else: + _manage.clear(group_id) + _manage.append(group_id, add_msg) + if _manage.size(group_id) > 2: + if random.random() < Config.get_config( + "fudu", "FUDU_PROBABILITY" + ) and not _manage.is_repeater(group_id): + if random.random() < 0.2: + if plain_text.endswith("打断施法!"): + await Text("打断" + plain_text).finish() + else: + await Text("打断施法!").finish() + _manage.set_repeater(group_id) + rst = None + if image_list and plain_text: + rst = MessageFactory( + [Text(plain_text), Image(TEMP_PATH / f"compare_{group_id}_img.jpg")] + ) + elif image_list: + rst = Image(TEMP_PATH / f"compare_{group_id}_img.jpg") + elif plain_text: + rst = Text(plain_text) + if rst: + await rst.finish() + + +async def get_fudu_img_hash(url: str, group_id: str) -> str: + """下载图片获取哈希值 + + 参数: + url: 图片url + group_id: 群组id + + 返回: + str: 哈希值 + """ + try: + if await AsyncHttpx.download_file( + url, TEMP_PATH / f"compare_{group_id}_img.jpg" + ): + img_hash = get_img_hash(TEMP_PATH / f"compare_{group_id}_img.jpg") + return str(img_hash) + else: + logger.warning(f"复读下载图片失败...") + except Exception as e: + logger.warning(f"复读读取图片Hash出错 {type(e)}:{e}") + return "" diff --git a/zhenxun/utils/image_utils.py b/zhenxun/utils/image_utils.py index 4dadb7ff..dfd03d29 100644 --- a/zhenxun/utils/image_utils.py +++ b/zhenxun/utils/image_utils.py @@ -5,7 +5,10 @@ from pathlib import Path from typing import Awaitable, Callable import cv2 +import imagehash +from imagehash import ImageHash from nonebot.utils import is_coroutine_callable +from PIL import Image from zhenxun.configs.path_config import IMAGE_PATH @@ -364,3 +367,17 @@ def compressed_image( cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio)) ) cv2.imwrite(str(out_file.absolute()), img) + + +def get_img_hash(image_file: str | Path) -> str: + """获取图片的hash值 + + 参数: + image_file: 图片文件路径 + + 返回: + str: 哈希值 + """ + with open(image_file, "rb") as fp: + hash_value = imagehash.average_hash(Image.open(fp)) + return str(hash_value)