nonebot-adapter-discord


Namenonebot-adapter-discord JSON
Version 0.1.8 PyPI version JSON
download
home_pagehttps://github.com/nonebot/adapter-discord
SummaryDiscord adapter for nonebot2
upload_time2024-06-23 14:42:29
maintainerNone
docs_urlNone
authorCMHopeSunshine
requires_python<4.0,>=3.9
licenseMIT
keywords nonebot discord bot
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
  <a href="https://nonebot.dev/"><img src="https://raw.githubusercontent.com/nonebot/adapter-discord/master/assets/logo.png" width="200" height="200" alt="nonebot-adapter-discord"></a>
</p>

<div align="center">

# NoneBot-Adapter-Discord

_✨ Discord 协议适配 ✨_

</div>

## 安装

通过 `nb adapter install nonebot-adapter-discord` 安装本适配器。

或在 `nb create` 创建项目时选择 `Discord` 适配器。

可通过 `pip install git+https://github.com/nonebot/adapter-discord.git@master` 安装开发中版本。

由于 [Discord 文档](https://discord.com/developers/docs/intro)存在部分表述不清的地方,并且结构复杂,存在很多 `partial object`,
需要更多实际测试以找出问题,欢迎提出 ISSUE 反馈。

## 配置

修改 NoneBot 配置文件 `.env` 或者 `.env.*`。

### Driver

参考 [driver](https://v2.nonebot.dev/docs/tutorial/configuration#driver) 配置项,添加 `ForwardDriver` 支持。

如:

```dotenv
DRIVER=~httpx+~websockets
```

### DISCORD_BOTS

配置机器人帐号,如:

```dotenv
DISCORD_BOTS='
[
  {
    "token": "xxx",
    "intent": {
      "guild_messages": true,
      "direct_messages": true
    },
    "application_commands": {"*": ["*"]}
  }
]
'

# application_commands的{"*": ["*"]}代表将全部应用命令注册为全局应用命令
# {"admin": ["123", "456"]}则代表将admin命令注册为id是123、456服务器的局部命令,其余命令不注册
```

### DISCORD_COMPRESS

是否启用数据压缩,默认为 `False`,如:

```dotenv
DISCORD_COMPRESS=True
```

### DISCORD_API_VERSION

Discord API 版本,默认为 `10`,如:

```dotenv
DISCORD_API_VERSION=10
```

### DISCORD_API_TIMEOUT

Discord API 超时时间,默认为 `30` 秒,如:

```dotenv
DISCORD_API_TIMEOUT=15.0
```

### DISCORD_HANDLE_SELF_MESSAGE

是否处理自己发送的消息,默认为 `False`,如:

```dotenv
DISCORD_HANDLE_SELF_MESSAGE=True
```

### DISCORD_PROXY

代理设置,默认无,如:

```dotenv
DISCORD_PROXY='http://127.0.0.1:6666'
```

## 插件示例

以下是一个简单的插件示例,展示各种消息段:

```python
import datetime

from nonebot import on_command
from nonebot.params import CommandArg

from nonebot.adapters.discord import Bot, MessageEvent, MessageSegment, Message
from nonebot.adapters.discord.api import *

matcher = on_command('send')


@matcher.handle()
async def ready(bot: Bot, event: MessageEvent, msg: Message = CommandArg()):
    # 调用discord的api
    self_info = await bot.get_current_user()  # 获取机器人自身信息
    user = await bot.get_user(user_id=event.user_id)  # 获取指定用户信息
    ...
    # 各种消息段
    msg = msg.extract_plain_text()
    if msg == 'mention_me':
        # 发送一个提及你的消息
        await matcher.finish(MessageSegment.mention_user(event.user_id))
    elif msg == 'time':
        # 发送一个时间,使用相对时间(RelativeTime)样式
        await matcher.finish(MessageSegment.timestamp(datetime.datetime.now(),
                                                      style=TimeStampStyle.RelativeTime))
    elif msg == 'mention_everyone':
        # 发送一个提及全体成员的消息
        await matcher.finish(MessageSegment.mention_everyone())
    elif msg == 'mention_channel':
        # 发送一个提及当前频道的消息
        await matcher.finish(MessageSegment.mention_channel(event.channel_id))
    elif msg == 'embed':
        # 发送一个嵌套消息,其中包含a embed标题,nonebot logo描述和来自网络url的logo图片
        await matcher.finish(MessageSegment.embed(
            Embed(title='a embed',
                  type=EmbedTypes.image,
                  description='nonebot logo',
                  image=EmbedImage(
                      url='https://v2.nonebot.dev/logo.png'))))
    elif msg == 'attachment':
        # 发送一个附件,其中包含来自本地的logo.png图片
        with open('logo.png', 'rb') as f:
            await matcher.finish(MessageSegment.attachment(file='logo.png',
                                                           content=f.read()))
    elif msg == 'component':
        # 发送一个复杂消息,其中包含一个当前时间,一个字符串选择菜单,一个用户选择菜单和一个按钮
        time_now = MessageSegment.timestamp(datetime.datetime.now())
        string_select = MessageSegment.component(
            SelectMenu(type=ComponentType.StringSelect,
                       custom_id='string select',
                       placeholder='select a value',
                       options=[
                           SelectOption(label='A', value='a'),
                           SelectOption(label='B', value='b'),
                           SelectOption(label='C', value='c')]))
        select = MessageSegment.component(SelectMenu(
            type=ComponentType.UserInput,
            custom_id='user_input',
            placeholder='please select a user'))
        button = MessageSegment.component(
            Button(label='button',
                   custom_id='button',
                   style=ButtonStyle.Primary))
        await matcher.finish('now time:' + time_now + string_select + select + button)
    else:
        # 发送一个文本消息
        await matcher.finish(MessageSegment.text(msg))
```

以下是一个 Discord 斜杠命令的插件示例:

```python
import asyncio
from typing import Optional

from nonebot.adapters.discord.api import (
    IntegerOption,
    NumberOption,
    StringOption,
    SubCommandOption,
    User,
    UserOption,
)
from nonebot.adapters.discord.commands import (
    CommandOption,
    on_slash_command,
)

matcher = on_slash_command(
    name="permission",
    description="权限管理",
    options=[
        SubCommandOption(
            name="add",
            description="添加",
            options=[
                StringOption(
                    name="plugin",
                    description="插件名",
                    required=True,
                ),
                IntegerOption(
                    name="priority",
                    description="优先级",
                    required=False,
                ),
            ],
        ),
        SubCommandOption(
            name="remove",
            description="移除",
            options=[
                StringOption(name="plugin", description="插件名", required=True),
                NumberOption(name="time", description="时长", required=False),
            ],
        ),
        SubCommandOption(
            name="ban",
            description="禁用",
            options=[
                UserOption(name="user", description="用户", required=False),
            ],
        ),
    ],
)


@matcher.handle_sub_command("add")
async def handle_user_add(
    plugin: CommandOption[str], priority: CommandOption[Optional[int]]
):
    await matcher.send_deferred_response()
    await asyncio.sleep(2)
    await matcher.edit_response(f"你添加了插件 {plugin},优先级 {priority}")
    await asyncio.sleep(2)
    fm = await matcher.send_followup_msg(
        f"你添加了插件 {plugin},优先级 {priority} (新消息)"
    )
    await asyncio.sleep(2)
    await matcher.edit_followup_msg(
        fm.id, f"你添加了插件 {plugin},优先级 {priority} (新消息修改后)"
    )


@matcher.handle_sub_command("remove")
async def handle_user_remove(
    plugin: CommandOption[str], time: CommandOption[Optional[float]]
):
    await matcher.send(f"你移除了插件 {plugin},时长 {time}")


@matcher.handle_sub_command("ban")
async def handle_admin_ban(user: CommandOption[User]):
    await matcher.finish(f"你禁用了用户 {user.username}")
```


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/nonebot/adapter-discord",
    "name": "nonebot-adapter-discord",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.9",
    "maintainer_email": null,
    "keywords": "nonebot, discord, bot",
    "author": "CMHopeSunshine",
    "author_email": "277073121@qq.com",
    "download_url": "https://files.pythonhosted.org/packages/46/fc/2834ee3648ea7dae98417ff022bc7c1fe9a00160a07f9f9c0619541d3709/nonebot_adapter_discord-0.1.8.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\n  <a href=\"https://nonebot.dev/\"><img src=\"https://raw.githubusercontent.com/nonebot/adapter-discord/master/assets/logo.png\" width=\"200\" height=\"200\" alt=\"nonebot-adapter-discord\"></a>\n</p>\n\n<div align=\"center\">\n\n# NoneBot-Adapter-Discord\n\n_\u2728 Discord \u534f\u8bae\u9002\u914d \u2728_\n\n</div>\n\n## \u5b89\u88c5\n\n\u901a\u8fc7 `nb adapter install nonebot-adapter-discord` \u5b89\u88c5\u672c\u9002\u914d\u5668\u3002\n\n\u6216\u5728 `nb create` \u521b\u5efa\u9879\u76ee\u65f6\u9009\u62e9 `Discord` \u9002\u914d\u5668\u3002\n\n\u53ef\u901a\u8fc7 `pip install git+https://github.com/nonebot/adapter-discord.git@master` \u5b89\u88c5\u5f00\u53d1\u4e2d\u7248\u672c\u3002\n\n\u7531\u4e8e [Discord \u6587\u6863](https://discord.com/developers/docs/intro)\u5b58\u5728\u90e8\u5206\u8868\u8ff0\u4e0d\u6e05\u7684\u5730\u65b9\uff0c\u5e76\u4e14\u7ed3\u6784\u590d\u6742\uff0c\u5b58\u5728\u5f88\u591a `partial object`\uff0c\n\u9700\u8981\u66f4\u591a\u5b9e\u9645\u6d4b\u8bd5\u4ee5\u627e\u51fa\u95ee\u9898\uff0c\u6b22\u8fce\u63d0\u51fa ISSUE \u53cd\u9988\u3002\n\n## \u914d\u7f6e\n\n\u4fee\u6539 NoneBot \u914d\u7f6e\u6587\u4ef6 `.env` \u6216\u8005 `.env.*`\u3002\n\n### Driver\n\n\u53c2\u8003 [driver](https://v2.nonebot.dev/docs/tutorial/configuration#driver) \u914d\u7f6e\u9879\uff0c\u6dfb\u52a0 `ForwardDriver` \u652f\u6301\u3002\n\n\u5982\uff1a\n\n```dotenv\nDRIVER=~httpx+~websockets\n```\n\n### DISCORD_BOTS\n\n\u914d\u7f6e\u673a\u5668\u4eba\u5e10\u53f7\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_BOTS='\n[\n  {\n    \"token\": \"xxx\",\n    \"intent\": {\n      \"guild_messages\": true,\n      \"direct_messages\": true\n    },\n    \"application_commands\": {\"*\": [\"*\"]}\n  }\n]\n'\n\n# application_commands\u7684{\"*\": [\"*\"]}\u4ee3\u8868\u5c06\u5168\u90e8\u5e94\u7528\u547d\u4ee4\u6ce8\u518c\u4e3a\u5168\u5c40\u5e94\u7528\u547d\u4ee4\n# {\"admin\": [\"123\", \"456\"]}\u5219\u4ee3\u8868\u5c06admin\u547d\u4ee4\u6ce8\u518c\u4e3aid\u662f123\u3001456\u670d\u52a1\u5668\u7684\u5c40\u90e8\u547d\u4ee4\uff0c\u5176\u4f59\u547d\u4ee4\u4e0d\u6ce8\u518c\n```\n\n### DISCORD_COMPRESS\n\n\u662f\u5426\u542f\u7528\u6570\u636e\u538b\u7f29\uff0c\u9ed8\u8ba4\u4e3a `False`\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_COMPRESS=True\n```\n\n### DISCORD_API_VERSION\n\nDiscord API \u7248\u672c\uff0c\u9ed8\u8ba4\u4e3a `10`\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_API_VERSION=10\n```\n\n### DISCORD_API_TIMEOUT\n\nDiscord API \u8d85\u65f6\u65f6\u95f4\uff0c\u9ed8\u8ba4\u4e3a `30` \u79d2\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_API_TIMEOUT=15.0\n```\n\n### DISCORD_HANDLE_SELF_MESSAGE\n\n\u662f\u5426\u5904\u7406\u81ea\u5df1\u53d1\u9001\u7684\u6d88\u606f\uff0c\u9ed8\u8ba4\u4e3a `False`\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_HANDLE_SELF_MESSAGE=True\n```\n\n### DISCORD_PROXY\n\n\u4ee3\u7406\u8bbe\u7f6e\uff0c\u9ed8\u8ba4\u65e0\uff0c\u5982\uff1a\n\n```dotenv\nDISCORD_PROXY='http://127.0.0.1:6666'\n```\n\n## \u63d2\u4ef6\u793a\u4f8b\n\n\u4ee5\u4e0b\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u63d2\u4ef6\u793a\u4f8b\uff0c\u5c55\u793a\u5404\u79cd\u6d88\u606f\u6bb5\uff1a\n\n```python\nimport datetime\n\nfrom nonebot import on_command\nfrom nonebot.params import CommandArg\n\nfrom nonebot.adapters.discord import Bot, MessageEvent, MessageSegment, Message\nfrom nonebot.adapters.discord.api import *\n\nmatcher = on_command('send')\n\n\n@matcher.handle()\nasync def ready(bot: Bot, event: MessageEvent, msg: Message = CommandArg()):\n    # \u8c03\u7528discord\u7684api\n    self_info = await bot.get_current_user()  # \u83b7\u53d6\u673a\u5668\u4eba\u81ea\u8eab\u4fe1\u606f\n    user = await bot.get_user(user_id=event.user_id)  # \u83b7\u53d6\u6307\u5b9a\u7528\u6237\u4fe1\u606f\n    ...\n    # \u5404\u79cd\u6d88\u606f\u6bb5\n    msg = msg.extract_plain_text()\n    if msg == 'mention_me':\n        # \u53d1\u9001\u4e00\u4e2a\u63d0\u53ca\u4f60\u7684\u6d88\u606f\n        await matcher.finish(MessageSegment.mention_user(event.user_id))\n    elif msg == 'time':\n        # \u53d1\u9001\u4e00\u4e2a\u65f6\u95f4\uff0c\u4f7f\u7528\u76f8\u5bf9\u65f6\u95f4\uff08RelativeTime\uff09\u6837\u5f0f\n        await matcher.finish(MessageSegment.timestamp(datetime.datetime.now(),\n                                                      style=TimeStampStyle.RelativeTime))\n    elif msg == 'mention_everyone':\n        # \u53d1\u9001\u4e00\u4e2a\u63d0\u53ca\u5168\u4f53\u6210\u5458\u7684\u6d88\u606f\n        await matcher.finish(MessageSegment.mention_everyone())\n    elif msg == 'mention_channel':\n        # \u53d1\u9001\u4e00\u4e2a\u63d0\u53ca\u5f53\u524d\u9891\u9053\u7684\u6d88\u606f\n        await matcher.finish(MessageSegment.mention_channel(event.channel_id))\n    elif msg == 'embed':\n        # \u53d1\u9001\u4e00\u4e2a\u5d4c\u5957\u6d88\u606f\uff0c\u5176\u4e2d\u5305\u542ba embed\u6807\u9898\uff0cnonebot logo\u63cf\u8ff0\u548c\u6765\u81ea\u7f51\u7edcurl\u7684logo\u56fe\u7247\n        await matcher.finish(MessageSegment.embed(\n            Embed(title='a embed',\n                  type=EmbedTypes.image,\n                  description='nonebot logo',\n                  image=EmbedImage(\n                      url='https://v2.nonebot.dev/logo.png'))))\n    elif msg == 'attachment':\n        # \u53d1\u9001\u4e00\u4e2a\u9644\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u6765\u81ea\u672c\u5730\u7684logo.png\u56fe\u7247\n        with open('logo.png', 'rb') as f:\n            await matcher.finish(MessageSegment.attachment(file='logo.png',\n                                                           content=f.read()))\n    elif msg == 'component':\n        # \u53d1\u9001\u4e00\u4e2a\u590d\u6742\u6d88\u606f\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5f53\u524d\u65f6\u95f4\uff0c\u4e00\u4e2a\u5b57\u7b26\u4e32\u9009\u62e9\u83dc\u5355\uff0c\u4e00\u4e2a\u7528\u6237\u9009\u62e9\u83dc\u5355\u548c\u4e00\u4e2a\u6309\u94ae\n        time_now = MessageSegment.timestamp(datetime.datetime.now())\n        string_select = MessageSegment.component(\n            SelectMenu(type=ComponentType.StringSelect,\n                       custom_id='string select',\n                       placeholder='select a value',\n                       options=[\n                           SelectOption(label='A', value='a'),\n                           SelectOption(label='B', value='b'),\n                           SelectOption(label='C', value='c')]))\n        select = MessageSegment.component(SelectMenu(\n            type=ComponentType.UserInput,\n            custom_id='user_input',\n            placeholder='please select a user'))\n        button = MessageSegment.component(\n            Button(label='button',\n                   custom_id='button',\n                   style=ButtonStyle.Primary))\n        await matcher.finish('now time:' + time_now + string_select + select + button)\n    else:\n        # \u53d1\u9001\u4e00\u4e2a\u6587\u672c\u6d88\u606f\n        await matcher.finish(MessageSegment.text(msg))\n```\n\n\u4ee5\u4e0b\u662f\u4e00\u4e2a Discord \u659c\u6760\u547d\u4ee4\u7684\u63d2\u4ef6\u793a\u4f8b\uff1a\n\n```python\nimport asyncio\nfrom typing import Optional\n\nfrom nonebot.adapters.discord.api import (\n    IntegerOption,\n    NumberOption,\n    StringOption,\n    SubCommandOption,\n    User,\n    UserOption,\n)\nfrom nonebot.adapters.discord.commands import (\n    CommandOption,\n    on_slash_command,\n)\n\nmatcher = on_slash_command(\n    name=\"permission\",\n    description=\"\u6743\u9650\u7ba1\u7406\",\n    options=[\n        SubCommandOption(\n            name=\"add\",\n            description=\"\u6dfb\u52a0\",\n            options=[\n                StringOption(\n                    name=\"plugin\",\n                    description=\"\u63d2\u4ef6\u540d\",\n                    required=True,\n                ),\n                IntegerOption(\n                    name=\"priority\",\n                    description=\"\u4f18\u5148\u7ea7\",\n                    required=False,\n                ),\n            ],\n        ),\n        SubCommandOption(\n            name=\"remove\",\n            description=\"\u79fb\u9664\",\n            options=[\n                StringOption(name=\"plugin\", description=\"\u63d2\u4ef6\u540d\", required=True),\n                NumberOption(name=\"time\", description=\"\u65f6\u957f\", required=False),\n            ],\n        ),\n        SubCommandOption(\n            name=\"ban\",\n            description=\"\u7981\u7528\",\n            options=[\n                UserOption(name=\"user\", description=\"\u7528\u6237\", required=False),\n            ],\n        ),\n    ],\n)\n\n\n@matcher.handle_sub_command(\"add\")\nasync def handle_user_add(\n    plugin: CommandOption[str], priority: CommandOption[Optional[int]]\n):\n    await matcher.send_deferred_response()\n    await asyncio.sleep(2)\n    await matcher.edit_response(f\"\u4f60\u6dfb\u52a0\u4e86\u63d2\u4ef6 {plugin}\uff0c\u4f18\u5148\u7ea7 {priority}\")\n    await asyncio.sleep(2)\n    fm = await matcher.send_followup_msg(\n        f\"\u4f60\u6dfb\u52a0\u4e86\u63d2\u4ef6 {plugin}\uff0c\u4f18\u5148\u7ea7 {priority} (\u65b0\u6d88\u606f)\"\n    )\n    await asyncio.sleep(2)\n    await matcher.edit_followup_msg(\n        fm.id, f\"\u4f60\u6dfb\u52a0\u4e86\u63d2\u4ef6 {plugin}\uff0c\u4f18\u5148\u7ea7 {priority} (\u65b0\u6d88\u606f\u4fee\u6539\u540e)\"\n    )\n\n\n@matcher.handle_sub_command(\"remove\")\nasync def handle_user_remove(\n    plugin: CommandOption[str], time: CommandOption[Optional[float]]\n):\n    await matcher.send(f\"\u4f60\u79fb\u9664\u4e86\u63d2\u4ef6 {plugin}\uff0c\u65f6\u957f {time}\")\n\n\n@matcher.handle_sub_command(\"ban\")\nasync def handle_admin_ban(user: CommandOption[User]):\n    await matcher.finish(f\"\u4f60\u7981\u7528\u4e86\u7528\u6237 {user.username}\")\n```\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Discord adapter for nonebot2",
    "version": "0.1.8",
    "project_urls": {
        "Documentation": "https://github.com/nonebot/adapter-discord",
        "Homepage": "https://github.com/nonebot/adapter-discord",
        "Repository": "https://github.com/nonebot/adapter-discord"
    },
    "split_keywords": [
        "nonebot",
        " discord",
        " bot"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "80af67716a868ee65c4dd7ab0f0cd24181dce6c856786efd3837c2274afb884d",
                "md5": "b026e7c0d8fe5933105ea8dc002c212c",
                "sha256": "d063bf524f6a75c5c123f2d04227e0ec62c2433f56b28fb92fa5eb2aebef1c16"
            },
            "downloads": -1,
            "filename": "nonebot_adapter_discord-0.1.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b026e7c0d8fe5933105ea8dc002c212c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.9",
            "size": 78480,
            "upload_time": "2024-06-23T14:42:27",
            "upload_time_iso_8601": "2024-06-23T14:42:27.537266Z",
            "url": "https://files.pythonhosted.org/packages/80/af/67716a868ee65c4dd7ab0f0cd24181dce6c856786efd3837c2274afb884d/nonebot_adapter_discord-0.1.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "46fc2834ee3648ea7dae98417ff022bc7c1fe9a00160a07f9f9c0619541d3709",
                "md5": "f75867840fd9760fcd8b6f73fd7ffbbc",
                "sha256": "5d3a7a8e0ab23b7ae84551b479c40c5d09733b15d09538d64765c5af54721781"
            },
            "downloads": -1,
            "filename": "nonebot_adapter_discord-0.1.8.tar.gz",
            "has_sig": false,
            "md5_digest": "f75867840fd9760fcd8b6f73fd7ffbbc",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.9",
            "size": 75182,
            "upload_time": "2024-06-23T14:42:29",
            "upload_time_iso_8601": "2024-06-23T14:42:29.321012Z",
            "url": "https://files.pythonhosted.org/packages/46/fc/2834ee3648ea7dae98417ff022bc7c1fe9a00160a07f9f9c0619541d3709/nonebot_adapter_discord-0.1.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-06-23 14:42:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "nonebot",
    "github_project": "adapter-discord",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "nonebot-adapter-discord"
}
        
Elapsed time: 0.87669s