Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

当发送图片消息时,从消息事件中获取的图片消息段中似乎不包含有效的 URL 信息 #43

Open
jks15satoshi opened this issue Oct 10, 2024 · 3 comments

Comments

@jks15satoshi
Copy link
Contributor

jks15satoshi commented Oct 10, 2024

版本信息:

Python 版本:3.11.9
NoneBot 版本:2.3.3
Discord 适配器版本:0.1.8

问题描述:

如以下示例代码:

from nonebot import on_message
from nonebot.adapters.discord.event import MessageEvent
from nonebot.internal.adapter.event import Event

matcher = on_message()

@matcher.handle()
async def handle_message_event(base_event: Event, message_event: MessageEvent) -> None:
    await matcher.send(base_event.get_message())

在 Discord 发送一条图片消息,在调试器中尝试从事件中获取消息,似乎在消息段中不包含图片的 URL 信息:

>>> base_event.get_message()
[AttachmentSegment(type='attachment', data={'attachment': AttachmentSend(filename='-_.png', description=None), 'file': None})]
>>> message_event.get_message()
[AttachmentSegment(type='attachment', data={'attachment': AttachmentSend(filename='-_.png', description=None), 'file': None})]

而直接执行此处理器会抛出异常:

10-10 11:06:48 [ERROR] nonebot | Running Matcher(type='message', module=echomod_msgrelay.core, lineno=70) failed.
Traceback (most recent call last):
  File "/home/jks15satoshi/.pyenv/versions/3.11.9/lib/python3.11/runpy.py", line 198, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/home/jks15satoshi/.pyenv/versions/3.11.9/lib/python3.11/runpy.py", line 88, in _run_code
    exec(code, run_globals)
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
    cli.main()
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
    run()
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 284, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/home/jks15satoshi/.vscode-server/extensions/ms-python.debugpy-2024.10.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
    exec(code, run_globals)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/bot.py", line 18, in <module>
    nonebot.run()
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/__init__.py", line 335, in run
    get_driver().run(*args, **kwargs)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/drivers/fastapi.py", line 186, in run
    uvicorn.run(
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/uvicorn/main.py", line 579, in run
    server.run()
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 65, in run
    return asyncio.run(self.serve(sockets=sockets))
  File "/home/jks15satoshi/.pyenv/versions/3.11.9/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
  File "/home/jks15satoshi/.pyenv/versions/3.11.9/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/message.py", line 476, in check_and_run_matcher
    await _run_matcher(
> File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/message.py", line 428, in _run_matcher
    await matcher.run(bot, event, state, stack, dependency_cache)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/internal/matcher/matcher.py", line 850, in run
    await self.simple_run(bot, event, state, stack, dependency_cache)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/internal/matcher/matcher.py", line 825, in simple_run
    await handler(
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/dependencies/__init__.py", line 94, in __call__
    return await cast(Callable[..., Awaitable[R]], self.call)(**values)
  File "/home/jks15satoshi/Documents/Git/echodev/echomod/msgrelay/echomod_msgrelay/core.py", line 77, in handle_message_event
    await matcher.send(base_event.get_message())
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/internal/matcher/matcher.py", line 566, in send
    return await bot.send(event=event, message=_message, **kwargs)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/adapters/discord/bot.py", line 249, in send
    return await self.create_message(
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/internal/adapter/bot.py", line 122, in call_api
    raise exception
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/internal/adapter/bot.py", line 97, in call_api
    result = await self.adapter._call_api(self, api, **data)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/adapters/discord/adapter.py", line 455, in _call_api
    return await api_handler(self, bot, **data)
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/adapters/discord/api/handle.py", line 876, in _create_message
    return type_validate_python(MessageGet, await _request(adapter, bot, request))
  File "/home/jks15satoshi/Documents/Git/echodev/echobot/.venv/lib/python3.11/site-packages/nonebot/adapters/discord/api/request.py", line 39, in _request
    raise ActionFailed(data)
nonebot.adapters.discord.exception.ActionFailed: <ActionFailed: 400, code=50035, message=Invalid Form Body, data=None, errors={'attachments': {'0': {'id': {'_errors': [{'code': 'BASE_TYPE_REQUIRED', 'message': 'This field is required'}]}}}}>

事件信息如下(个人认为敏感的 ID 数据使用 *** 替换):

>>> base_event
GuildMessageCreateEvent(
    id=***, 
    channel_id=***,
    author=User(
        id=***, username='jks15satoshi', discriminator='0', global_name='Satoshi Jek', 
        avatar='6750c14af941fd419ca09fa72ca18f3f', bot=<UNSET>, system=<UNSET>, mfa_enabled=<UNSET>, 
        banner=<UNSET>, accent_color=<UNSET>, locale=<UNSET>, verified=<UNSET>, email=<UNSET>, 
        flags=<UNSET>, premium_type=<UNSET>, public_flags=<UserFlags: 0>, avatar_decoration=<UNSET>
    ), 
    content='', 
    timestamp=datetime.datetime(2024, 10, 10, 3, 24, 55, 511000, tzinfo=TzInfo(UTC)), 
    edited_timestamp=None, 
    tts=False, 
    mention_everyone=False, 
    mentions=[], 
    mention_roles=[], 
    mention_channels=<UNSET>, 
    attachments=[
        Attachment(
           id='***', filename='-_.png', description=<UNSET>, content_type='image/png', size=6772914, 
           url='https://cdn.discordapp.com/attachments/***/***/-_.png?ex=67089a87&is=67074907&hm=5036e7a9d7f5584696e9fc173a846cfcb383d11a2939127f19277de50a68b1e8&', 
           proxy_url='https://media.discordapp.net/attachments/***/***/-_.png?ex=67089a87&is=67074907&hm=5036e7a9d7f5584696e9fc173a846cfcb383d11a2939127f19277de50a68b1e8&', 
           height=1272, width=2158, ephemeral=<UNSET>, duration_secs=<UNSET>, waveform=<UNSET>
        )
    ], 
    embeds=[], 
    reactions=<UNSET>, 
    nonce='1293776249528778752', 
    pinned=False, 
    webhook_id=<UNSET>, 
    type=<MessageType.DEFAULT: 0>, 
    activity=<UNSET>, 
    application=<UNSET>, 
    application_id=<UNSET>, 
    message_reference=<UNSET>, 
    flags=<MessageFlag: 0>, 
    referenced_message=<UNSET>, 
    interaction=<UNSET>, 
    thread=<UNSET>, 
    components=[], 
    sticker_items=<UNSET>, 
    stickers=<UNSET>, 
    position=<UNSET>, 
    role_subscription_data=<UNSET>, 
    guild_id=***, 
    member=GuildMember(
        user=<UNSET>, nick='Satoshi Jek', avatar=None, roles=[***], 
        joined_at=datetime.datetime(2021, 1, 31, 15, 49, 57, 777000, tzinfo=TzInfo(UTC)), 
        premium_since=None, deaf=False, mute=False, flags=<GuildMemberFlags: 0>, pending=False, 
        permissions=<UNSET>, communication_disabled_until=None
    ), 
    to_me=False, 
    reply=None
)
@jks15satoshi
Copy link
Contributor Author

大概看了一下源码,MessageSegment.attachment 接受一个可选的 bytes 类型参数 content 表示附件内容:

@staticmethod
def attachment(
file: Union[str, File, AttachmentSend],
description: Optional[str] = None,
content: Optional[bytes] = None,
) -> "AttachmentSegment":

但奇怪的是 Message.from_guild_message 构造附件消息段时却似乎没有传过这个参数:

if message.attachments:
msg.extend(
MessageSegment.attachment(
AttachmentSend(
filename=attachment.filename,
description=(
attachment.description
if isinstance(attachment.description, str)
else None
),
)
)
for attachment in message.attachments
)

@Autuamn
Copy link
Contributor

Autuamn commented Oct 13, 2024

我想因为 AttachmentSegment 是给发送用的,不能从 url 发送文件,就没有预留传入 url 的地方

@jks15satoshi
Copy link
Contributor Author

jks15satoshi commented Oct 13, 2024

我想因为 AttachmentSegment 是给发送用的,不能从 url 发送文件,就没有预留传入 url 的地方

可以理解。不过确实会有通过 AttachmentSegment 获取到 URL 的需求(比如 Alconna 插件的 UniMessage 就是统一通过 event.get_message 获取消息内容,目前的实现就不能从消息段中拿到附件的 URL,实现跨频道或者跨平台消息转发就会有问题),所以我在想是不是应该允许接受一个 URL 参数比较合适,这样做跨平台兼容也会方便一些;至于发送带有 URL 参数的附件消息段时,在 api.utils.parse_data 或在任意构造创建消息事件前,请求 URL 获取附件的二进制数据(拍脑袋的想法,不见得合适)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants