├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── renovate.json └── workflows │ └── python-publish.yml ├── LICENSE ├── README.md ├── nonebot_plugin_blacklist └── __init__.py └── pyproject.toml /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 问题汇报 2 | description: 汇报错误或意外行为 3 | labels: [ bug ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | [GitHub Issues](https://github.com/tkgs0/nonebot-plugin-blacklist/issues) 专门用于错误报告和功能需求,这意味着我们不接受使用问题。如果您打开的问题不符合要求,它将会被无条件关闭。 9 | 10 | 有关使用问题,请通过以下途径: 11 | 12 | - 阅读文档以解决 13 | - 在社区内寻求他人解答 14 | - 在 [GitHub Discussions](https://github.com/tkgs0/nonebot-plugin-blacklist/discussions) 上提问 15 | - 在网络中搜索是否有人遇到过类似的问题 16 | 17 | 如果您不知道如何有效、精准地提出一个问题,我们建议您先阅读[《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)。 18 | 19 | 最后,请记得遵守我们的社区准则,友好交流。 20 | 21 | - type: markdown 22 | attributes: 23 | value: "## 注意事项" 24 | - type: markdown 25 | attributes: 26 | value: | 27 | 在提 issue 前请确保你仔细阅读过文档,搜索过现有的 issue ,并确保你使用的是最新的 nonebot-plugin-blacklist 。 28 | 29 | 在启动本项目出现错误时,你可以无视堆栈 (stack) 相关的信息,但错误信息 (Error: xxxxx) 请认真看看,自己稍微翻译翻译就知道大体意思,大部分问题你都可以在本项目文档或搜索引擎中找到解答。 30 | 31 | **这些 issue 不会被受理:** 32 | 33 | 1. 文档中有提到的 34 | 2. 使用的 nonebot-plugin-blacklist 不是最新的 35 | 3. 大部分“连接失败”问题,请自己排查配置等原因 36 | 37 | - type: checkboxes 38 | attributes: 39 | label: 报告清单 40 | description: 请确认您已遵守所有必选项。 41 | options: 42 | - label: 我已仔细阅读并了解上述注意事项。 43 | required: true 44 | - label: 我已使用最新版本测试过,确认问题依旧存在。 45 | required: true 46 | - label: 我确定在 [GitHub Issues](https://github.com/tkgs0/nonebot-plugin-blacklist/issues) 中没有相同或相似的问题。 47 | required: true 48 | 49 | - type: input 50 | attributes: 51 | label: nonebot-plugin-blacklist 52 | placeholder: 你所使用的 nonebot-plugin-blacklist 版本 53 | validations: 54 | required: true 55 | 56 | - type: input 57 | attributes: 58 | label: client 59 | placeholder: 你所使用的协议端名称以及其版本 60 | validations: 61 | required: true 62 | 63 | - type: input 64 | attributes: 65 | label: nonebot-adapter 66 | placeholder: 你所使用的适配器名称以及其版本 67 | validations: 68 | required: true 69 | 70 | - type: input 71 | attributes: 72 | label: nonebot 73 | placeholder: 你所使用的 nonebot 版本 74 | validations: 75 | required: true 76 | 77 | - type: input 78 | attributes: 79 | label: Python 80 | placeholder: 你所使用的 Python 版本 81 | validations: 82 | required: true 83 | 84 | - type: input 85 | attributes: 86 | label: 操作系统 87 | placeholder: 你所使用的操作系统以及其版本 88 | validations: 89 | required: true 90 | 91 | - type: textarea 92 | id: installed_packages 93 | attributes: 94 | label: 列出安装的 Python 包 95 | placeholder: 把 pip freeze -l 执行的结果贴到此处。 96 | description: 如果你不是通过 pip 或 nb-cli 下载的 nonebot-plugin-blacklist ,请把你安装的 Python 包列出来。 97 | validations: 98 | required: false 99 | 100 | - type: textarea 101 | id: problem_description 102 | attributes: 103 | label: 问题描述 104 | description: 请清晰简洁地说明问题是什么,并解释您是如何遇到此问题的,以及您为此做出的尝试。 105 | validations: 106 | required: true 107 | 108 | - type: textarea 109 | id: reproduction 110 | attributes: 111 | label: 复现步骤 112 | description: | 113 | 提供能复现此问题的详细操作步骤。如果可能,请尝试提供一个可复现的测试用例,该测试用例是发生问题所需的最低限度。 114 | 推荐阅读:[《如何创建一个最小的、可复现的示例》](https://stackoverflow.com/help/minimal-reproducible-example) 115 | placeholder: "1. 当......\n2. 然后......\n3. 发生......" 116 | validations: 117 | required: true 118 | 119 | - type: textarea 120 | id: expectation 121 | attributes: 122 | label: 期望行为 123 | placeholder: 期望的正常行为是怎么样的? 124 | validations: 125 | required: false 126 | 127 | - type: textarea 128 | id: actuality 129 | attributes: 130 | label: 实际行为 131 | placeholder: 实际上发生了什么? 132 | validations: 133 | required: true 134 | 135 | - type: textarea 136 | id: log 137 | attributes: 138 | label: 日志信息 139 | description: | 140 | 提供有助于诊断问题的任何日志和完整的错误信息。 141 | 可截图,可粘贴文本,可上传日志文件,如粘贴文本请务必用 markdown 代码块包裹。 142 | placeholder: 请注意将您的敏感信息从日志中过滤或替换。 143 | validations: 144 | required: true 145 | 146 | - type: textarea 147 | id: other 148 | attributes: 149 | label: 额外补充 150 | description: | 151 | 在此处添加相关的任何其他上下文或截图,或者您觉得有帮助的信息。 152 | - 问题相关截图,例如机器人回复异常时的聊天截图 153 | - 可能与 bug 有关的配置内容 154 | validations: 155 | required: false 156 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: ✨ 功能需求 2 | description: 为项目提出一个新的想法或建议 3 | labels: [ enhancement ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | [GitHub Issues](https://github.com/tkgs0/nonebot-plugin-blacklist/issues) 专门用于错误报告和功能需求,这意味着我们不接受使用问题。如果您打开的问题不符合要求,它将会被无条件关闭。 9 | 10 | 有关使用问题,请通过以下途径: 11 | 12 | - 阅读文档以解决 13 | - 在社区内寻求他人解答 14 | - 在 [GitHub Discussions](https://github.com/tkgs0/nonebot-plugin-blacklist/discussions) 上提问 15 | - 在网络中搜索是否有人遇到过类似的问题 16 | 17 | 如果您不知道如何有效、精准地提出一个问题,我们建议您先阅读[《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)。 18 | 19 | 最后,请记得遵守我们的社区准则,友好交流。 20 | 21 | - type: markdown 22 | attributes: 23 | value: "## 注意事项" 24 | - type: markdown 25 | attributes: 26 | value: | 27 | 在提 issue 前请确保你仔细阅读过文档,搜索过现有的 issue ,并确保你使用的是最新的 nonebot-plugin-blacklist ,避免发生 “提出的需求是已经实现了的” 这种令人哭笑不得的情况。 28 | 29 | - type: checkboxes 30 | attributes: 31 | label: 报告清单 32 | description: 请确认您已遵守所有必选项。 33 | options: 34 | - label: 我已仔细阅读并了解上述注意事项。 35 | required: true 36 | - label: 我已使用最新版本测试过,确认功能并未实现。 37 | required: true 38 | - label: 我确定在 [GitHub Issues](https://github.com/tkgs0/nonebot-plugin-blacklist/issues) 中没有相同或相似的需求。 39 | required: true 40 | - label: 我有足够的时间和能力,愿意为此提交 [PR](https://github.com/tkgs0/nonebot-plugin-blacklist/pulls) 来实现功能。 41 | required: false 42 | 43 | - type: textarea 44 | attributes: 45 | label: 您希望能解决什么样的问题? 46 | description: 请简要地说明是什么问题导致您想要一个新功能。也许我们可以提出一种现有的解决办法。 47 | validations: 48 | required: true 49 | 50 | - type: textarea 51 | attributes: 52 | label: 您想要的解决方案 53 | description: 请说明您希望使用什么样的方法解决上述问题。 54 | validations: 55 | required: true 56 | 57 | - type: textarea 58 | attributes: 59 | label: 您考虑过的替代方案 60 | description: 除了上述方法以外,您还考虑过哪些其他的实现方式? 61 | validations: 62 | required: false 63 | 64 | - type: textarea 65 | attributes: 66 | label: 实现的功能是什么样的? 67 | description: | 68 | 提供功能在实现后如何使用的代码示例。 69 | 请注意,您可以使用 Markdown 来设置代码块的格式。 70 | 尽可能多地提供细节。您希望它如何使用的示例代码会有所帮助。 71 | validations: 72 | required: false 73 | 74 | - type: textarea 75 | attributes: 76 | label: 额外补充 77 | description: 在此处添加相关的任何其他上下文或截图,或者您觉得有帮助的信息。 78 | validations: 79 | required: false 80 | 81 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | "schedule:weekends" 5 | ], 6 | "dependencyDashboard": false, 7 | "rangeStrategy": "bump", 8 | "enabledManagers": [ 9 | "github-actions", 10 | "poetry", 11 | "pre-commit" 12 | ], 13 | "pre-commit": { 14 | "enabled": true 15 | }, 16 | "packageRules": [ 17 | { 18 | "matchPackagePatterns": [ 19 | "*" 20 | ], 21 | "matchUpdateTypes": [ 22 | "minor", 23 | "patch" 24 | ], 25 | "groupName": "all non-major dependencies", 26 | "groupSlug": "all-minor-patch", 27 | "labels": [ 28 | "dependencies" 29 | ], 30 | "automerge": true 31 | }, 32 | { 33 | "matchPackagePatterns": [ 34 | "*" 35 | ], 36 | "matchUpdateTypes": [ 37 | "major" 38 | ], 39 | "labels": [ 40 | "dependencies", 41 | "breaking" 42 | ] 43 | }, 44 | { 45 | "description": "disable python updates for poetry manager", 46 | "matchPackageNames": ["python"], 47 | "matchManagers": ["poetry"], 48 | "enabled": false 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Publish Python 🐍 distributions 📦 to PyPI 3 | 4 | on: 5 | push: 6 | tags: 7 | - '*' 8 | 9 | jobs: 10 | deploy: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Set up Python 17 | uses: actions/setup-python@v5 18 | with: 19 | python-version: "3.x" 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install build 24 | - name: Build package 25 | run: python -m build 26 | - name: Publish package 27 | uses: pypa/gh-action-pypi-publish@release/v1 28 | with: 29 | user: __token__ 30 | password: ${{ secrets.PYPI_API_TOKEN }} 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 月ヶ瀬 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | NoneBotPluginLogo 3 |
4 |

NoneBotPluginText

5 |
6 | 7 |
8 | 9 | # nonebot-plugin-blacklist 10 | 11 | _✨ NoneBot 黑名单插件 ✨_ 12 | 13 | 14 | 15 | license 16 | 17 | 18 | pypi 19 | 20 | 21 | python 22 | 23 | 24 | nonebot 25 | 26 | 27 | onebot 28 | 29 | 30 |
31 | 32 | 33 | ## 📖 介绍 34 | 35 | 基于 [A-kirami](https://github.com/A-kirami) 大佬的 [黑白名单](https://github.com/A-kirami/nonebot-plugin-namelist) 插件 魔改(?)的仅黑名单插件 36 | 37 | 超级用户不受黑名单影响 38 | 39 | ## 💿 安装 40 | 41 | **nb-cli安装, 包管理器安装 二选一** 42 | 43 |
44 | 使用 nb-cli 安装 45 | 46 | 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装 47 | 48 | nb plugin install nonebot-plugin-blacklist 49 | 50 |
51 | 52 |
53 | 使用包管理器安装 54 | 55 | 在 nonebot2 项目的插件目录下, 打开命令行, 56 | 57 | **根据你使用的包管理器, 输入相应的安装命令** 58 | 59 |
60 | pip 61 | 62 | pip install nonebot-plugin-blacklist 63 | 64 |
65 |
66 | pdm 67 | 68 | pdm add nonebot-plugin-blacklist 69 | 70 |
71 |
72 | poetry 73 | 74 | poetry add nonebot-plugin-blacklist 75 | 76 |
77 |
78 | conda 79 | 80 | conda install nonebot-plugin-blacklist 81 | 82 |
83 | 84 | 打开 bot项目下的 `pyproject.toml` 文件, 85 | 86 | 在其 `plugins` 里加入 `nonebot_plugin_blacklist` 87 | 88 | plugins = ["nonebot_plugin_blacklist"] 89 | 90 |
91 | 92 | 93 | ## 🎉 使用 94 | 95 | **总开关** 96 | ``` 97 | 群聊静默/静默群聊 98 | 99 | 群聊响应/响应群聊 100 | 101 | 私聊静默/静默私聊 102 | 103 | 私聊响应/响应私聊 104 | ``` 105 | 106 | **拉黑** 107 | ``` 108 | 拉黑用户 qq qq1 qq2 109 | 拉黑群 qq qq1 qq2 110 | 拉黑私聊 qq qq1 qq2 111 | 拉黑所有群 112 | 拉黑所有好友 113 | ``` 114 | 115 | **解禁** 116 | ``` 117 | 解禁用户 qq qq1 qq2 118 | 解禁群 qq qq1 qq2 119 | 解禁私聊 qq qq1 qq2 120 | 解禁所有群 121 | 解禁所有好友 122 | ``` 123 | 124 | **查看黑名单** 125 | ``` 126 | 查看用户黑名单 bot 127 | 查看群聊黑名单 bot 128 | 查看私聊黑名单 bot 129 | 130 | 重置黑名单 bot bot1 bot2 ... 131 | 重置所有黑名单 132 | 133 | ## 不指定bot则为当前bot 134 | ``` 135 | 136 | **被禁言自动屏蔽该群** 137 | ``` 138 | 自觉静默开 139 | 自觉静默关 140 | ``` 141 | 142 | 群内发送 `/静默` `/响应` 可快捷拉黑/解禁当前群聊 143 | 144 | `拉黑所有` 只对已添加的群/好友生效 145 | 146 | ## ⚠️ 注意事项 147 | 148 | **本插件目前仅支持 nonebot2 + onebot.v11 的使用方式, 一切非此二者结合的使用方式造成的问题请自行探索解决, 或者使用其他插件** 149 | -------------------------------------------------------------------------------- /nonebot_plugin_blacklist/__init__.py: -------------------------------------------------------------------------------- 1 | import asyncio, random, unicodedata 2 | from pathlib import Path 3 | from typing import Literal 4 | 5 | from nonebot import get_driver, on_command, on_notice 6 | from nonebot.plugin import PluginMetadata 7 | from nonebot.log import logger 8 | from nonebot.matcher import Matcher 9 | from nonebot.adapters.onebot.v11 import ( 10 | Bot, 11 | Message, 12 | Event, 13 | MessageEvent, 14 | GroupMessageEvent, 15 | GroupBanNoticeEvent, 16 | ) 17 | from nonebot.exception import IgnoredException 18 | from nonebot.message import event_preprocessor 19 | from nonebot.permission import SUPERUSER 20 | from nonebot.params import CommandArg 21 | 22 | import ujson as json 23 | 24 | 25 | usage: str =""" 26 | 27 | 指令表: 28 | 静默(响应)私聊(群聊) 29 | 30 | 拉黑(解禁)用户(群/私聊) qq qq1 qq2 ... 31 | 拉黑(解禁)所有好友(群) 32 | 自觉静默开(关) 33 | 34 | 查看用户(群聊/私聊)黑名单 bot 35 | 重置黑名单 bot bot1 bot2 ... 36 | 重置所有黑名单 37 | 38 | # 不指定bot则为当前bot 39 | 40 | # 群内发送 "/静默" "/响应" 可快捷拉黑/解禁当前群聊 41 | # "拉黑所有" 只对已添加的群/好友生效 42 | 43 | """.strip() 44 | 45 | 46 | __plugin_meta__ = PluginMetadata( 47 | name="黑名单", 48 | description="黑名单插件", 49 | usage=usage, 50 | type="application", 51 | homepage="https://github.com/tkgs0/nonebot-plugin-blacklist", 52 | supported_adapters={"~onebot.v11"}, 53 | extra={ 54 | "author": "月ヶ瀬" 55 | } 56 | ) 57 | 58 | 59 | superusers = get_driver().config.superusers 60 | 61 | file_path = Path() / 'data' / 'blacklist' / 'blacklist.json' 62 | file_path.parent.mkdir(parents=True, exist_ok=True) 63 | 64 | blacklist = ( 65 | json.loads(file_path.read_text('utf-8')) 66 | if file_path.is_file() 67 | else {} 68 | ) 69 | 70 | template = { 71 | 'private': False, 72 | 'group': True, 73 | 'privlist': [], 74 | 'grouplist': [], 75 | 'userlist': [], 76 | 'ban_auto_sleep': True 77 | } 78 | 79 | 80 | def save_blacklist() -> None: 81 | file_path.write_text( 82 | json.dumps( 83 | blacklist, 84 | ensure_ascii=False, 85 | escape_forward_slashes=False, 86 | indent=2 87 | ), 88 | encoding='utf-8' 89 | ) 90 | 91 | 92 | def check_self_id(self_id) -> str: 93 | self_id = f'{self_id}' 94 | temp: dict = {} 95 | temp.update(template) 96 | 97 | try: 98 | if not blacklist.get(self_id): 99 | blacklist.update({ 100 | self_id: temp 101 | }) 102 | save_blacklist() 103 | for i in template: 104 | if blacklist[self_id].get(i) == None: 105 | blacklist[self_id].update({i: temp[i]}) 106 | save_blacklist() 107 | except Exception: 108 | blacklist.update({ 109 | self_id: temp 110 | }) 111 | save_blacklist() 112 | 113 | return self_id 114 | 115 | 116 | def is_number(s: str) -> bool: 117 | try: 118 | float(s) 119 | return True 120 | except ValueError: 121 | pass 122 | try: 123 | unicodedata.numeric(s) 124 | return True 125 | except (TypeError, ValueError): 126 | pass 127 | return False 128 | 129 | 130 | @event_preprocessor 131 | def blacklist_processor(event: Event): 132 | self_id = check_self_id(event.self_id) 133 | uid = vars(event).get('user_id') 134 | gid = vars(event).get('group_id') 135 | 136 | if uid and f'{uid}' in superusers: 137 | return 138 | 139 | if gid and (not blacklist[self_id]['group'] or f'{gid}' in blacklist[self_id]['grouplist']): 140 | logger.debug(f'群聊 {gid} 在 {self_id} 黑名单中, 忽略本次消息') 141 | raise IgnoredException('黑名单群组') 142 | 143 | if uid and f'{uid}' in blacklist[self_id]['userlist']: 144 | logger.debug(f'用户 {uid} 在 {self_id} 黑名单中, 忽略本次消息') 145 | raise IgnoredException('黑名单用户') 146 | 147 | if not gid and uid: 148 | if not blacklist[self_id]['private'] or f'{uid}' in blacklist[self_id]['privlist']: 149 | logger.debug(f'私聊 {uid} 在 {self_id} 黑名单中, 忽略本次消息') 150 | raise IgnoredException('黑名单会话') 151 | 152 | 153 | def handle_msg( 154 | self_id, 155 | arg, 156 | mode: Literal['add', 'del'], 157 | type_: Literal['userlist', 'grouplist', 'privlist'], 158 | ) -> str: 159 | uids = arg.extract_plain_text().strip().split() 160 | if not uids: 161 | return '用法: \n拉黑(解禁)用户(群/私聊) qq qq1 qq2 ...' 162 | for uid in uids: 163 | if not is_number(uid): 164 | return '参数错误, id必须是数字..' 165 | msg = handle_blacklist(self_id, uids, mode, type_) 166 | return msg 167 | 168 | 169 | def handle_blacklist( 170 | self_id, 171 | uids: list, 172 | mode: Literal['add', 'del'], 173 | type_: Literal['userlist', 'grouplist', 'privlist'], 174 | ) -> str: 175 | self_id = check_self_id(self_id) 176 | 177 | types = { 178 | 'userlist': '用户', 179 | 'grouplist': '群聊', 180 | 'privlist': '私聊', 181 | } 182 | 183 | if mode == 'add': 184 | blacklist[self_id][type_].extend(uids) 185 | blacklist[self_id][type_] = list(set(blacklist[self_id][type_])) 186 | _mode = '拉黑' 187 | elif mode == 'del': 188 | blacklist[self_id][type_] = [uid for uid in blacklist[self_id][type_] if uid not in uids] 189 | _mode = '解禁' 190 | save_blacklist() 191 | _type = types[type_] 192 | return f"已{_mode} {len(uids)} 个{_type}: {', '.join(uids)}" 193 | 194 | 195 | add_userlist = on_command('拉黑用户', aliases={'屏蔽用户'}, permission=SUPERUSER, priority=1, block=True) 196 | 197 | @add_userlist.handle() 198 | async def add_user_list(event: MessageEvent, arg: Message = CommandArg()): 199 | if uids := [at.data['qq'] for at in event.get_message()['at']]: 200 | msg = handle_blacklist(event.self_id, uids, 'add', 'userlist') 201 | await add_userlist.finish(msg) 202 | msg = handle_msg(event.self_id, arg, 'add', 'userlist') 203 | await add_userlist.finish(msg) 204 | 205 | 206 | add_grouplist = on_command('拉黑群', aliases={'屏蔽群'}, permission=SUPERUSER, priority=1, block=True) 207 | 208 | @add_grouplist.handle() 209 | async def add_group_list(event: MessageEvent, arg: Message = CommandArg()): 210 | msg = handle_msg(event.self_id, arg, 'add', 'grouplist') 211 | await add_grouplist.finish(msg) 212 | 213 | 214 | add_privlist = on_command('拉黑私聊', aliases={'屏蔽私聊'}, permission=SUPERUSER, priority=1, block=True) 215 | 216 | @add_privlist.handle() 217 | async def add_priv_list(event: MessageEvent, arg: Message = CommandArg()): 218 | if uids := [at.data['qq'] for at in event.get_message()['at']]: 219 | msg = handle_blacklist(event.self_id, uids, 'add', 'privlist') 220 | await add_privlist.finish(msg) 221 | msg = handle_msg(event.self_id, arg, 'add', 'privlist') 222 | await add_privlist.finish(msg) 223 | 224 | 225 | del_userlist = on_command('解禁用户', aliases={'解封用户'}, permission=SUPERUSER, priority=1, block=True) 226 | 227 | @del_userlist.handle() 228 | async def del_user_list(event: MessageEvent, arg: Message = CommandArg()): 229 | if uids := [at.data['qq'] for at in event.get_message()['at']]: 230 | msg = handle_blacklist(event.self_id, uids, 'del', 'userlist') 231 | await del_userlist.finish(msg) 232 | msg = handle_msg(event.self_id, arg, 'del', 'userlist') 233 | await del_userlist.finish(msg) 234 | 235 | 236 | del_grouplist = on_command('解禁群', aliases={'解封群'}, permission=SUPERUSER, priority=1, block=True) 237 | 238 | @del_grouplist.handle() 239 | async def del_group_list(event: MessageEvent, arg: Message = CommandArg()): 240 | msg = handle_msg(event.self_id, arg, 'del', 'grouplist') 241 | await del_grouplist.finish(msg) 242 | 243 | 244 | del_privlist = on_command('解禁私聊', aliases={'解封私聊'}, permission=SUPERUSER, priority=1, block=True) 245 | 246 | @del_privlist.handle() 247 | async def del_priv_list(event: MessageEvent, arg: Message = CommandArg()): 248 | if uids := [at.data['qq'] for at in event.get_message()['at']]: 249 | msg = handle_blacklist(event.self_id, uids, 'del', 'privlist') 250 | await del_privlist.finish(msg) 251 | msg = handle_msg(event.self_id, arg, 'del', 'privlist') 252 | await del_privlist.finish(msg) 253 | 254 | 255 | check_userlist = on_command('查看用户黑名单', permission=SUPERUSER, priority=1, block=True) 256 | 257 | @check_userlist.handle() 258 | async def check_user_list(event: MessageEvent, args: Message = CommandArg()): 259 | arg = args.extract_plain_text().strip() 260 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 261 | uids = blacklist[self_id]['userlist'] 262 | await check_userlist.finish(f"{self_id}\n当前已屏蔽 {len(uids)} 个用户: {', '.join(uids)}") 263 | 264 | 265 | check_grouplist = on_command('查看群聊黑名单', permission=SUPERUSER, priority=1, block=True) 266 | 267 | @check_grouplist.handle() 268 | async def check_group_list(event: MessageEvent, args: Message = CommandArg()): 269 | arg = args.extract_plain_text().strip() 270 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 271 | gids = blacklist[self_id]['grouplist'] 272 | await check_grouplist.finish(f"{self_id}\n群聊状态: {'响应' if blacklist[self_id]['group'] else '静默'}\n自觉静默: {'开' if blacklist[self_id]['ban_auto_sleep'] else '关'}\n当前已屏蔽 {len(gids)} 个群聊: {', '.join(gids)}") 273 | 274 | 275 | check_privlist = on_command('查看私聊黑名单', permission=SUPERUSER, priority=1, block=True) 276 | 277 | @check_privlist.handle() 278 | async def check_priv_list(event: MessageEvent, args: Message = CommandArg()): 279 | arg = args.extract_plain_text().strip() 280 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 281 | uids = blacklist[self_id]['privlist'] 282 | await check_privlist.finish(f"{self_id}\n私聊状态: {'响应' if blacklist[self_id]['private'] else '静默'}\n当前已屏蔽 {len(uids)} 个私聊: {', '.join(uids)}") 283 | 284 | 285 | enable_group = on_command('群聊响应', aliases={'响应群聊'}, permission=SUPERUSER, priority=1, block=True) 286 | 287 | @enable_group.handle() 288 | async def _(event: MessageEvent, args: Message = CommandArg()): 289 | arg = args.extract_plain_text().strip() 290 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 291 | blacklist[self_id]['group'] = True 292 | save_blacklist() 293 | await enable_group.finish(f'{self_id} 群聊响应.') 294 | 295 | 296 | disable_group = on_command('群聊静默', aliases={'静默群聊'}, permission=SUPERUSER, priority=1, block=True) 297 | 298 | @disable_group.handle() 299 | async def _(event: MessageEvent, args: Message = CommandArg()): 300 | arg = args.extract_plain_text().strip() 301 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 302 | blacklist[self_id]['group'] = False 303 | save_blacklist() 304 | await disable_group.finish(f'{self_id} 群聊静默.') 305 | 306 | 307 | enable_private = on_command('私聊响应', aliases={'响应私聊'}, permission=SUPERUSER, priority=1, block=True) 308 | 309 | @enable_private.handle() 310 | async def _(event: MessageEvent, args: Message = CommandArg()): 311 | arg = args.extract_plain_text().strip() 312 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 313 | blacklist[self_id]['private'] = True 314 | save_blacklist() 315 | await enable_private.finish(f'{self_id} 私聊响应.') 316 | 317 | 318 | disable_private = on_command('私聊静默', aliases={'静默私聊'}, permission=SUPERUSER, priority=1, block=True) 319 | 320 | @disable_private.handle() 321 | async def _(event: MessageEvent, args: Message = CommandArg()): 322 | arg = args.extract_plain_text().strip() 323 | self_id = check_self_id(arg) if is_number(arg) else check_self_id(event.self_id) 324 | blacklist[self_id]['private'] = False 325 | save_blacklist() 326 | await disable_private.finish(f'{self_id} 私聊静默.') 327 | 328 | 329 | add_group = on_command('/静默', permission=SUPERUSER, priority=1, block=True) 330 | 331 | @add_group.handle() 332 | async def add_group_(event: GroupMessageEvent): 333 | handle_blacklist(event.self_id, [f'{event.group_id}'], 'add', 'grouplist') 334 | await add_group.finish('那我先去睡觉了...') 335 | 336 | 337 | del_group = on_command('/响应', permission=SUPERUSER, priority=1, block=True) 338 | 339 | @del_group.handle() 340 | async def del_group_(event: GroupMessageEvent): 341 | handle_blacklist(event.self_id, [f'{event.group_id}'], 'del', 'grouplist') 342 | await del_group.finish('呜......醒来力...') 343 | 344 | 345 | add_all_group = on_command('拉黑所有群', aliases={'屏蔽所有群'}, permission=SUPERUSER, priority=1, block=True) 346 | 347 | @add_all_group.handle() 348 | async def add_all_group_(bot: Bot, event: MessageEvent): 349 | gl = await bot.get_group_list() 350 | gids = ['{group_id}'.format_map(g) for g in gl] 351 | handle_blacklist(event.self_id, gids, 'add', 'grouplist') 352 | await add_all_group.finish(f'已拉黑 {len(gids)} 个群聊') 353 | 354 | 355 | del_all_group = on_command('解禁所有群', aliases={'解封所有群'}, permission=SUPERUSER, priority=1, block=True) 356 | 357 | @del_all_group.handle() 358 | async def del_all_group_(event: MessageEvent): 359 | self_id = check_self_id(event.self_id) 360 | n = len(blacklist[self_id]['grouplist']) 361 | blacklist[self_id]['grouplist'].clear() 362 | save_blacklist() 363 | await del_all_group.finish(f'已解禁 {n} 个群聊') 364 | 365 | 366 | add_all_friend = on_command('拉黑所有好友', aliases={'屏蔽所有好友'}, permission=SUPERUSER, priority=1, block=True) 367 | 368 | @add_all_friend.handle() 369 | async def add_all_friend_(bot: Bot, event: MessageEvent): 370 | gl = await bot.get_friend_list() 371 | uids = ['{user_id}'.format_map(g) for g in gl] 372 | handle_blacklist(event.self_id, uids, 'add', 'userlist') 373 | await add_all_friend.finish(f'已拉黑 {len(uids)} 个用户') 374 | 375 | 376 | del_all_friend = on_command('解禁所有好友', aliases={'解封所有好友'}, permission=SUPERUSER, priority=1, block=True) 377 | 378 | @del_all_friend.handle() 379 | async def del_all_friend_(event: MessageEvent): 380 | self_id = check_self_id(event.self_id) 381 | n = len(blacklist[self_id]['userlist']) 382 | blacklist[self_id]['userlist'].clear() 383 | save_blacklist() 384 | await del_all_friend.finish(f'已解禁 {n} 个用户') 385 | 386 | 387 | reset_all_blacklist = on_command('重置所有黑名单', aliases={'清空所有黑名单'}, permission=SUPERUSER, priority=1, block=True) 388 | 389 | @reset_all_blacklist.got('FLAG', prompt='确定重置所有黑名单? (y/n)') 390 | async def reset_all_list(matcher: Matcher): 391 | flag = matcher.state['FLAG'].extract_plain_text().strip() 392 | if flag.lower() in ['y', 'yes', 'true']: 393 | blacklist.clear() 394 | save_blacklist() 395 | await reset_all_blacklist.finish('已重置所有黑名单') 396 | else: 397 | await reset_all_blacklist.finish('操作已取消') 398 | 399 | 400 | reset_blacklist = on_command('重置黑名单', aliases={'清空黑名单'}, permission=SUPERUSER, priority=1, block=True) 401 | 402 | @reset_blacklist.handle() 403 | async def _(matcher: Matcher, args: Message = CommandArg()): 404 | matcher.state["ARGS"] = args.extract_plain_text().strip() 405 | 406 | @reset_blacklist.got('FLAG', prompt='确定重置黑名单? (y/n)') 407 | async def reset_list(event: MessageEvent, matcher: Matcher): 408 | args = matcher.state['ARGS'] 409 | flag = matcher.state['FLAG'].extract_plain_text().strip() 410 | 411 | uids = args.strip().split() 412 | uids = [check_self_id(i) for i in uids if is_number(i)] or [check_self_id(event.self_id)] 413 | 414 | if flag.lower() in ['y', 'yes', 'true']: 415 | for i in uids: 416 | blacklist.pop(i) 417 | save_blacklist() 418 | await reset_blacklist.finish(f'已重置{len(uids)}个黑名单') 419 | else: 420 | await reset_blacklist.finish('操作已取消') 421 | 422 | 423 | @on_notice(priority=2, block=False).handle() 424 | async def _(bot: Bot, event: GroupBanNoticeEvent): 425 | self_id = check_self_id(event.self_id) 426 | 427 | if event.is_tome() and event.duration: 428 | msg = f"在群聊 {event.group_id} 受到 {event.operator_id} 禁言" 429 | logger.info(f'{self_id} {msg}') 430 | if blacklist[self_id]['ban_auto_sleep']: 431 | handle_blacklist(self_id, [f'{event.group_id}'], 'add', 'grouplist') 432 | for superuser in bot.config.superusers: 433 | await bot.send_private_msg( 434 | user_id=int(superuser), 435 | message=f'ⓘ{msg}, 已自动拉黑该群聊.' 436 | ) 437 | await asyncio.sleep(random.random()+1) 438 | 439 | 440 | ban_auto_sleep = on_command('自觉静默', permission=SUPERUSER, priority=1, block=True) 441 | 442 | @ban_auto_sleep.handle() 443 | async def _(event: MessageEvent, arg: Message = CommandArg()): 444 | self_id = check_self_id(event.self_id) 445 | msg = arg.extract_plain_text().strip() 446 | 447 | if not msg or msg.startswith('开'): 448 | blacklist[self_id]['ban_auto_sleep'] = True 449 | text = '自觉静默已开启.' 450 | elif msg.startswith('关'): 451 | blacklist[self_id]['ban_auto_sleep'] = False 452 | text = '自觉静默已关闭.' 453 | else: 454 | return 455 | save_blacklist() 456 | await ban_auto_sleep.finish(text) 457 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "nonebot-plugin-blacklist" 3 | version = "1.4.3" 4 | description = "Blacklist in NoneBot2" 5 | authors = ["月ヶ瀬"] 6 | license = "MIT" 7 | readme = "README.md" 8 | packages = [ 9 | { include = "nonebot_plugin_blacklist" }, 10 | ] 11 | homepage = "https://github.com/tkgs0/nonebot-plugin-blacklist" 12 | repository = "https://github.com/tkgs0/nonebot-plugin-blacklist" 13 | keywords = ["nonebot", "blacklist"] 14 | 15 | [tool.poetry.dependencies] 16 | python = "^3.9" 17 | nonebot2 = "^2.3.1" 18 | nonebot-adapter-onebot = "^2.4.1" 19 | ujson = ">=5.2.0" 20 | 21 | [tool.poetry.dev-dependencies] 22 | 23 | [tool.mypy] 24 | python_version = "3.9" 25 | ignore_missing_imports = true 26 | implicit_reexport = true 27 | pretty = true 28 | show_error_codes = true 29 | strict = true 30 | 31 | [build-system] 32 | requires = ["poetry-core>=1.0.0"] 33 | build-backend = "poetry.core.masonry.api" 34 | 35 | --------------------------------------------------------------------------------