nonebot-plugin-send-anything-anywhere


Namenonebot-plugin-send-anything-anywhere JSON
Version 0.6.1 PyPI version JSON
download
home_pageNone
SummaryAn adaptor for nonebot2 adaptors
upload_time2024-04-09 08:51:58
maintainerNone
docs_urlNone
authorfelinae98
requires_python<4.0,>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">

~logo征集中,假装有图片~

# Nonebot Plugin<br>Send Anything Anywhere

你只管业务实现,把发送交给我们 | [文档](https://send-anything-anywhere.felinae98.cn/)

![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/felinae98/nonebot-plugin-send-anything-anywhere/test.yml)
[![codecov](https://codecov.io/gh/MountainDash/nonebot-plugin-send-anything-anywhere/graph/badge.svg?token=7EV2hcYx8d)](https://codecov.io/gh/MountainDash/nonebot-plugin-send-anything-anywhere)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nonebot-plugin-send-anything-anywhere)
![PyPI](https://img.shields.io/pypi/v/nonebot-plugin-send-anything-anywhere)
![GitHub](https://img.shields.io/github/license/felinae98/nonebot-plugin-send-anything-anywhere)

</div>

这个插件可以做什么

- 为常见的消息类型提供抽象类,自适应转换成对应 adapter 的消息
- 提供一套统一的,符合直觉的发送接口
- 为复杂的消息提供易用的生成接口(规划中)

本插件通过传入 bot 的类型来自适应生成对应 bot adapter 所使用的 Message

## 安装

- 使用 nb-cli 安装  
  `nb plugin install nonebot-plugin-send-anything-anywhere`
- 使用 poetry 安装  
  `poetry add nonebot-plugin-send-anything-anywhere`
- 使用 pip 安装  
  `pip install nonebot-plugin-send-anything-anywhere`

## 使用

在 handler 中回复消息的情况:

```python
@matcher.handle()
async def handle(event: MessageEvent):
    # 直接调用 MessageFactory.send() 在 handler 中回复消息
    await MessageFactory("你好").send(reply=True, at_sender=True)
    await MessageFactory("需要回复的内容").send()
    await matcher.finish()
```

主动发送的情况:

```python
from nonebot_plugin_saa import TargetQQGroup

# 发送目标为群号 114514 的群聊
target = TargetQQGroup(group_id=114514)
await MessageFactory("早上好").send_to(target)
```

从消息事件中提取发送目标:

```python
from nonebot_plugin_saa import extract_target, get_target, SaaTarget

@matcher.handle()
async def handle(event: MessageEvent, bot: Bot):
    # 只有混入了 Specifier 的 PlatformTarget(例如 OpenID 版 QQ)需要传入 bot
    target = extract_target(event, bot)

@matcher.handle()
async def handle(target: SaaTarget):
    ...
```

发送目标的序列化与反序列化:

```python
from nonebot_plugin_saa import PlatformTarget, TargetQQPrivate

target = TargetQQPrivate(user_id=112233)
serialized_target = target.json()
deserialized_target = PlatformTarget.deserialize(serialized_target)
assert deserialized_target == target
```

## 支持情况

✅:支持 ✖️:支持不了 🚧:等待适配

### 支持的 adapter

| OneBot v11 | OneBot v12 | Kaiheila | Telegram | Feishu | Red | DoDo |
| :--------: | :--------: | :------: | :------: | :----: | :-: | :--: |
|     ✅     |     ✅     |    ✅    |    ✅    |   ✅   | ✅  |  ✅  |

### 支持的消息类型

|      | OneBot v11 | OneBot v12 | 开黑啦 | Telegram | Feishu | Red | DoDo |
| :--: | :--------: | :--------: | :----: | :------: | :----: | :-: | :--: |
| 文字 |     ✅     |     ✅     |   ✅   |    ✅    |   ✅   | ✅  |  ✅  |
| 图片 |     ✅     |     ✅     |   ✅   |    ✅    |   ✅   | ✅  |  ✅  |
|  at  |     ✅     |     ✅     |   ✅   |    ✅    |   ✅   | ✅  |  ✅  |
| 回复 |     ✅     |     ✅     |   ✅   |    ✅    |   ✅   | 🚧  |  ✅  |

### 支持的发送目标

|                        | OneBot v11 | OneBot v12 | Kaiheila | Telegram | Feishu | Red | DoDo |
| :--------------------: | :--------: | :--------: | :------: | :------: | :----: | :-: | :--: |
|         QQ 群          |     ✅     |     ✅     |          |          |        | ✅  |      |
|        QQ 私聊         |     ✅     |     ✅     |          |          |        | ✅  |      |
|   QQ 频道子频道消息    |            |     ✅     |          |          |        |     |      |
|      QQ 频道私聊       |            |     ✅     |          |          |        |     |      |
|    开黑啦私聊/频道     |            |            |    ✅    |          |        |     |      |
| Telegram 普通对话/频道 |            |            |          |    ✅    |        |     |      |
|     飞书私聊/群聊      |            |            |          |          |   ✅   |     |      |
|     DoDo 私聊/群聊     |            |            |          |          |        |     |  ✅  |

注:对于使用 Onebot v12,但是没有专门适配的发送目标,使用了 TargetOB12Unknow 来保证其可以正常使用

## 问题与例子

因为在现在的 Nonebot 插件开发中,消息的构建和发送是和 adapter 高度耦合的,这导致一个插件要适配不同的 adapter 是困难的

before:

```python
from nonebot.adapters.onebot.v11.event import MessageEvent as V11MessageEvent
from nonebot.adapters.onebot.v11.message import MessageSegment as V11MessageSegment
from nonebot.adapters.onebot.v12.event import MessageEvent as V12MessageEvent
from nonebot.adapters.onebot.v12.message import MessageSegment as V12MessageSegment
from nonebot.adapters.onebot.v12.bot import Bot as V12Bot

pic_matcher = nonebot.on_command('发送图片')

@pic_matcher.handle()
async def _handle_v11(event: V11MessageEvent):
    pic_content = ...
    msg = V11MessageSegment.image(pic_content) + V11MessageSegment.text("这是你要的图片")
    await pic_matcher.finish(msg)

@pic_matcher.handle()
async def _handle_v12(bot: V12Bot, event: V12MessageEvent):
    pic_content = ...
    pic_file = await bot.upload_file(type='data', name='image', data=pic_content)
    msg = V12MessageSegment.image(pic_file['file_id']) + V12MessageSegment.text("这是你要的图片")
    await pic_matcher.finish(msg)
```

现在只需要:

```python
from nonebot.adapters.onebot.v11.event import MessageEvent as V11MessageEvent
from nonebot.adapters.onebot.v12.event import MessageEvent as V12MessageEvent
from nonebot.internal.adapter.bot import Bot
from nonebot_plugin_saa import Image, Text, MessageFactory

pic_matcher = nonebot.on_command('发送图片')

@pic_matcher.handle()
async def _handle_v12(bot: Bot, event: Union[V12MessageEvent, V11MessageEvent]):
    pic_content = ...
    msg_builder = MessageFactory([
        Image(pic_content), Text("这是你要的图片")
    ])
    # or msg_builder = Image(pic_content) + Text("这是你要的图片")
    await msg_builder.send()
    await pic_matcher.finish()
```

## 类似项目

- [nonebot-plugin-all4one](https://github.com/nonepkg/nonebot-plugin-all4one) 解决了类似的问题,但是用了不同路径
- [nonebot-plugin-params](https://github.com/iyume/nonebot-plugin-params) 通过 Rule 定制订阅的平台,与本插件联合使用也许会有奇效

## License

MIT


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "nonebot-plugin-send-anything-anywhere",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "felinae98",
    "author_email": "731499577@qq.com",
    "download_url": "https://files.pythonhosted.org/packages/8a/2d/300a2220249e02d7663ec77f9c0ee195268fcaa2e00934c4205c0eafbdcd/nonebot_plugin_send_anything_anywhere-0.6.1.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n\n~logo\u5f81\u96c6\u4e2d\uff0c\u5047\u88c5\u6709\u56fe\u7247~\n\n# Nonebot Plugin<br>Send Anything Anywhere\n\n\u4f60\u53ea\u7ba1\u4e1a\u52a1\u5b9e\u73b0\uff0c\u628a\u53d1\u9001\u4ea4\u7ed9\u6211\u4eec | [\u6587\u6863](https://send-anything-anywhere.felinae98.cn/)\n\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/felinae98/nonebot-plugin-send-anything-anywhere/test.yml)\n[![codecov](https://codecov.io/gh/MountainDash/nonebot-plugin-send-anything-anywhere/graph/badge.svg?token=7EV2hcYx8d)](https://codecov.io/gh/MountainDash/nonebot-plugin-send-anything-anywhere)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nonebot-plugin-send-anything-anywhere)\n![PyPI](https://img.shields.io/pypi/v/nonebot-plugin-send-anything-anywhere)\n![GitHub](https://img.shields.io/github/license/felinae98/nonebot-plugin-send-anything-anywhere)\n\n</div>\n\n\u8fd9\u4e2a\u63d2\u4ef6\u53ef\u4ee5\u505a\u4ec0\u4e48\n\n- \u4e3a\u5e38\u89c1\u7684\u6d88\u606f\u7c7b\u578b\u63d0\u4f9b\u62bd\u8c61\u7c7b\uff0c\u81ea\u9002\u5e94\u8f6c\u6362\u6210\u5bf9\u5e94 adapter \u7684\u6d88\u606f\n- \u63d0\u4f9b\u4e00\u5957\u7edf\u4e00\u7684\uff0c\u7b26\u5408\u76f4\u89c9\u7684\u53d1\u9001\u63a5\u53e3\n- \u4e3a\u590d\u6742\u7684\u6d88\u606f\u63d0\u4f9b\u6613\u7528\u7684\u751f\u6210\u63a5\u53e3\uff08\u89c4\u5212\u4e2d\uff09\n\n\u672c\u63d2\u4ef6\u901a\u8fc7\u4f20\u5165 bot \u7684\u7c7b\u578b\u6765\u81ea\u9002\u5e94\u751f\u6210\u5bf9\u5e94 bot adapter \u6240\u4f7f\u7528\u7684 Message\n\n## \u5b89\u88c5\n\n- \u4f7f\u7528 nb-cli \u5b89\u88c5  \n  `nb plugin install nonebot-plugin-send-anything-anywhere`\n- \u4f7f\u7528 poetry \u5b89\u88c5  \n  `poetry add nonebot-plugin-send-anything-anywhere`\n- \u4f7f\u7528 pip \u5b89\u88c5  \n  `pip install nonebot-plugin-send-anything-anywhere`\n\n## \u4f7f\u7528\n\n\u5728 handler \u4e2d\u56de\u590d\u6d88\u606f\u7684\u60c5\u51b5\uff1a\n\n```python\n@matcher.handle()\nasync def handle(event: MessageEvent):\n    # \u76f4\u63a5\u8c03\u7528 MessageFactory.send() \u5728 handler \u4e2d\u56de\u590d\u6d88\u606f\n    await MessageFactory(\"\u4f60\u597d\").send(reply=True, at_sender=True)\n    await MessageFactory(\"\u9700\u8981\u56de\u590d\u7684\u5185\u5bb9\").send()\n    await matcher.finish()\n```\n\n\u4e3b\u52a8\u53d1\u9001\u7684\u60c5\u51b5\uff1a\n\n```python\nfrom nonebot_plugin_saa import TargetQQGroup\n\n# \u53d1\u9001\u76ee\u6807\u4e3a\u7fa4\u53f7 114514 \u7684\u7fa4\u804a\ntarget = TargetQQGroup(group_id=114514)\nawait MessageFactory(\"\u65e9\u4e0a\u597d\").send_to(target)\n```\n\n\u4ece\u6d88\u606f\u4e8b\u4ef6\u4e2d\u63d0\u53d6\u53d1\u9001\u76ee\u6807:\n\n```python\nfrom nonebot_plugin_saa import extract_target, get_target, SaaTarget\n\n@matcher.handle()\nasync def handle(event: MessageEvent, bot: Bot):\n    # \u53ea\u6709\u6df7\u5165\u4e86 Specifier \u7684 PlatformTarget\uff08\u4f8b\u5982 OpenID \u7248 QQ\uff09\u9700\u8981\u4f20\u5165 bot\n    target = extract_target(event, bot)\n\n@matcher.handle()\nasync def handle(target: SaaTarget):\n    ...\n```\n\n\u53d1\u9001\u76ee\u6807\u7684\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316:\n\n```python\nfrom nonebot_plugin_saa import PlatformTarget, TargetQQPrivate\n\ntarget = TargetQQPrivate(user_id=112233)\nserialized_target = target.json()\ndeserialized_target = PlatformTarget.deserialize(serialized_target)\nassert deserialized_target == target\n```\n\n## \u652f\u6301\u60c5\u51b5\n\n\u2705:\u652f\u6301 \u2716\ufe0f:\u652f\u6301\u4e0d\u4e86 \ud83d\udea7:\u7b49\u5f85\u9002\u914d\n\n### \u652f\u6301\u7684 adapter\n\n| OneBot v11 | OneBot v12 | Kaiheila | Telegram | Feishu | Red | DoDo |\n| :--------: | :--------: | :------: | :------: | :----: | :-: | :--: |\n|     \u2705     |     \u2705     |    \u2705    |    \u2705    |   \u2705   | \u2705  |  \u2705  |\n\n### \u652f\u6301\u7684\u6d88\u606f\u7c7b\u578b\n\n|      | OneBot v11 | OneBot v12 | \u5f00\u9ed1\u5566 | Telegram | Feishu | Red | DoDo |\n| :--: | :--------: | :--------: | :----: | :------: | :----: | :-: | :--: |\n| \u6587\u5b57 |     \u2705     |     \u2705     |   \u2705   |    \u2705    |   \u2705   | \u2705  |  \u2705  |\n| \u56fe\u7247 |     \u2705     |     \u2705     |   \u2705   |    \u2705    |   \u2705   | \u2705  |  \u2705  |\n|  at  |     \u2705     |     \u2705     |   \u2705   |    \u2705    |   \u2705   | \u2705  |  \u2705  |\n| \u56de\u590d |     \u2705     |     \u2705     |   \u2705   |    \u2705    |   \u2705   | \ud83d\udea7  |  \u2705  |\n\n### \u652f\u6301\u7684\u53d1\u9001\u76ee\u6807\n\n|                        | OneBot v11 | OneBot v12 | Kaiheila | Telegram | Feishu | Red | DoDo |\n| :--------------------: | :--------: | :--------: | :------: | :------: | :----: | :-: | :--: |\n|         QQ \u7fa4          |     \u2705     |     \u2705     |          |          |        | \u2705  |      |\n|        QQ \u79c1\u804a         |     \u2705     |     \u2705     |          |          |        | \u2705  |      |\n|   QQ \u9891\u9053\u5b50\u9891\u9053\u6d88\u606f    |            |     \u2705     |          |          |        |     |      |\n|      QQ \u9891\u9053\u79c1\u804a       |            |     \u2705     |          |          |        |     |      |\n|    \u5f00\u9ed1\u5566\u79c1\u804a/\u9891\u9053     |            |            |    \u2705    |          |        |     |      |\n| Telegram \u666e\u901a\u5bf9\u8bdd/\u9891\u9053 |            |            |          |    \u2705    |        |     |      |\n|     \u98de\u4e66\u79c1\u804a/\u7fa4\u804a      |            |            |          |          |   \u2705   |     |      |\n|     DoDo \u79c1\u804a/\u7fa4\u804a     |            |            |          |          |        |     |  \u2705  |\n\n\u6ce8\uff1a\u5bf9\u4e8e\u4f7f\u7528 Onebot v12\uff0c\u4f46\u662f\u6ca1\u6709\u4e13\u95e8\u9002\u914d\u7684\u53d1\u9001\u76ee\u6807\uff0c\u4f7f\u7528\u4e86 TargetOB12Unknow \u6765\u4fdd\u8bc1\u5176\u53ef\u4ee5\u6b63\u5e38\u4f7f\u7528\n\n## \u95ee\u9898\u4e0e\u4f8b\u5b50\n\n\u56e0\u4e3a\u5728\u73b0\u5728\u7684 Nonebot \u63d2\u4ef6\u5f00\u53d1\u4e2d\uff0c\u6d88\u606f\u7684\u6784\u5efa\u548c\u53d1\u9001\u662f\u548c adapter \u9ad8\u5ea6\u8026\u5408\u7684\uff0c\u8fd9\u5bfc\u81f4\u4e00\u4e2a\u63d2\u4ef6\u8981\u9002\u914d\u4e0d\u540c\u7684 adapter \u662f\u56f0\u96be\u7684\n\nbefore:\n\n```python\nfrom nonebot.adapters.onebot.v11.event import MessageEvent as V11MessageEvent\nfrom nonebot.adapters.onebot.v11.message import MessageSegment as V11MessageSegment\nfrom nonebot.adapters.onebot.v12.event import MessageEvent as V12MessageEvent\nfrom nonebot.adapters.onebot.v12.message import MessageSegment as V12MessageSegment\nfrom nonebot.adapters.onebot.v12.bot import Bot as V12Bot\n\npic_matcher = nonebot.on_command('\u53d1\u9001\u56fe\u7247')\n\n@pic_matcher.handle()\nasync def _handle_v11(event: V11MessageEvent):\n    pic_content = ...\n    msg = V11MessageSegment.image(pic_content) + V11MessageSegment.text(\"\u8fd9\u662f\u4f60\u8981\u7684\u56fe\u7247\")\n    await pic_matcher.finish(msg)\n\n@pic_matcher.handle()\nasync def _handle_v12(bot: V12Bot, event: V12MessageEvent):\n    pic_content = ...\n    pic_file = await bot.upload_file(type='data', name='image', data=pic_content)\n    msg = V12MessageSegment.image(pic_file['file_id']) + V12MessageSegment.text(\"\u8fd9\u662f\u4f60\u8981\u7684\u56fe\u7247\")\n    await pic_matcher.finish(msg)\n```\n\n\u73b0\u5728\u53ea\u9700\u8981:\n\n```python\nfrom nonebot.adapters.onebot.v11.event import MessageEvent as V11MessageEvent\nfrom nonebot.adapters.onebot.v12.event import MessageEvent as V12MessageEvent\nfrom nonebot.internal.adapter.bot import Bot\nfrom nonebot_plugin_saa import Image, Text, MessageFactory\n\npic_matcher = nonebot.on_command('\u53d1\u9001\u56fe\u7247')\n\n@pic_matcher.handle()\nasync def _handle_v12(bot: Bot, event: Union[V12MessageEvent, V11MessageEvent]):\n    pic_content = ...\n    msg_builder = MessageFactory([\n        Image(pic_content), Text(\"\u8fd9\u662f\u4f60\u8981\u7684\u56fe\u7247\")\n    ])\n    # or msg_builder = Image(pic_content) + Text(\"\u8fd9\u662f\u4f60\u8981\u7684\u56fe\u7247\")\n    await msg_builder.send()\n    await pic_matcher.finish()\n```\n\n## \u7c7b\u4f3c\u9879\u76ee\n\n- [nonebot-plugin-all4one](https://github.com/nonepkg/nonebot-plugin-all4one) \u89e3\u51b3\u4e86\u7c7b\u4f3c\u7684\u95ee\u9898\uff0c\u4f46\u662f\u7528\u4e86\u4e0d\u540c\u8def\u5f84\n- [nonebot-plugin-params](https://github.com/iyume/nonebot-plugin-params) \u901a\u8fc7 Rule \u5b9a\u5236\u8ba2\u9605\u7684\u5e73\u53f0\uff0c\u4e0e\u672c\u63d2\u4ef6\u8054\u5408\u4f7f\u7528\u4e5f\u8bb8\u4f1a\u6709\u5947\u6548\n\n## License\n\nMIT\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "An adaptor for nonebot2 adaptors",
    "version": "0.6.1",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ccf6032af0428462e1393329c724de76cae788753bc5d08350a9bd767caff4ed",
                "md5": "878fb8e19c224445b68528951dd9b667",
                "sha256": "d1ac0df520f950b61ff27d3abda39c4bb2023797f3b7df2a23517ad53f3a7f29"
            },
            "downloads": -1,
            "filename": "nonebot_plugin_send_anything_anywhere-0.6.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "878fb8e19c224445b68528951dd9b667",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 42864,
            "upload_time": "2024-04-09T08:51:57",
            "upload_time_iso_8601": "2024-04-09T08:51:57.533296Z",
            "url": "https://files.pythonhosted.org/packages/cc/f6/032af0428462e1393329c724de76cae788753bc5d08350a9bd767caff4ed/nonebot_plugin_send_anything_anywhere-0.6.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8a2d300a2220249e02d7663ec77f9c0ee195268fcaa2e00934c4205c0eafbdcd",
                "md5": "0c9a38851a2a34553bb95d326fda18ca",
                "sha256": "89a695c5e356a423b8641f79082353b50ee431585988de2c2ae77f8ea00ac3e9"
            },
            "downloads": -1,
            "filename": "nonebot_plugin_send_anything_anywhere-0.6.1.tar.gz",
            "has_sig": false,
            "md5_digest": "0c9a38851a2a34553bb95d326fda18ca",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 30888,
            "upload_time": "2024-04-09T08:51:58",
            "upload_time_iso_8601": "2024-04-09T08:51:58.707460Z",
            "url": "https://files.pythonhosted.org/packages/8a/2d/300a2220249e02d7663ec77f9c0ee195268fcaa2e00934c4205c0eafbdcd/nonebot_plugin_send_anything_anywhere-0.6.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-09 08:51:58",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "nonebot-plugin-send-anything-anywhere"
}
        
Elapsed time: 0.22219s