Giter Club home page Giter Club logo

application's Introduction

此仓库已废弃, 请使用替代品 Ariadne; 本项目被标记为 v4, 相对的有 v4+(Ariadne) 与 v5(WIP, 尚未完工), 目前我推荐使用 Ariadne.

Graia Application for mirai-api-http

当前最新版本: PyPI
所需求的最低 CPython 版本: PyPI - Python Version
已确认可以在其上运行的 Python 实现: PyPI - Implementation

开始使用

文档地址: https://graia-document.vercel.app/
API 文档地址(使用 pdoc 生成): https://graiaproject.github.io/Application/graia/application/index.html

Tencent QQ 交流群: 邀请链接
Discussion: https://github.com/GraiaProject/Application/discussions

从 Pypi 安装

pip install graia-application-mirai
# 或使用 poetry
poetry add graia-application-mirai

从 Github 安装

pip install poetry
git clone https://github.com/GraiaProject/Application graia-app
cd graia-app
poetry install

作出贡献

Graia Framework 欢迎一切形式上的贡献(包括但不限于 Issues, Pull Requests, Good Idea 等)
我们希望能有更多优秀的开发者加入到对项目的贡献上来. 你的 Star 是对我们最大的支持和鼓励.

我们在这里写了你在贡献本项目及 Graia Project 时所可能需要注意的事项.

因为历史原因, 我们的文档, 即 Graia Document 目前急需改进和完善, 如果有意愿, 欢迎提起 Pull Request.

若你在使用的过程中遇到了问题, 欢迎提出聪明的问题, 也请不要使用糟糕的方式提问, 我们希望有人能让这个项目变得更好.

若在使用时发现了本项目的问题, 先检查文档中是否有提及这一情况, 若没有, 你可以在我们的问题追踪器处提出问题, 我们会尽快解决你发现的问题.

你也可以通过 Discussion/QQ 群等方式获取帮助,现在我们更推荐使用 Discussion.

若使用中发现了并非本项目导致的问题, 请先向其他项目汇报问题, 当然, 记得通知我.

鸣谢&相关项目

这些项目也很棒, 去他们的项目页看看, 点个 Star 以鼓励他们的开发工作, 毕竟没有他们也没有 Graia Framework.

特别感谢 mamoe 给我们带来这些精彩的项目:

  • mirai: 即 mirai-core, 一个高性能, 高可扩展性的 QQ 协议库
  • mirai-console: 一个基于 mirai 开发的插件式可扩展开发平台
  • mirai-api-http: 为本项目提供与 mirai 交互方式的 mirai-console 插件

Graia Application 基于以下独立 Graia Project 项目实现:

  • Broadcast Control: 扩展性强大, 模块间低耦合, 高灵活性的事件系统支持

Graia Application 同样还关联了其他 Graia Project 项目:

  • Components: 简单的消息链元素选择器
  • Template: 消息模板
  • Saya 为该项目提供了间接但简洁的模块管理系统. 文档
    • 关于 Saya: 这是一个全新的系统, 包含的潜力不亚于 Application, 并且实现了更方便的面向模块的 API, 但如果你需要应用到 Application 上, 则仍需要先学习相关的内容.

若有相关需求, 我们也强烈建议配合以下独立 Graia Project 项目使用:

  • Scheduler: 简洁的基于 asyncio 的定时任务实现.

作为学习目的, 主要维护者 GreyElaina 以个人名义重新以 AGPL-3.0 开源了 python-mirai, 即 Graia Application 的前身, 希望能为社区的发展助力:

  • python-mirai: 接口简洁, 支持 mirai-api-httpv1.6.x 版本. 一切的开始.

也感谢所有基于本项目开发的各位开发者, 请积极向上游项目反馈问题.

许可证

我们使用 GNU AGPLv3 作为本项目的开源许可证.

application's People

Contributors

djkcyl avatar greyelaina avatar i-love-study avatar kamaellee avatar karakoo avatar luoxhei avatar melonedo avatar nekodrider avatar serinanya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

application's Issues

使用graia-component-selector终端报错

描述你遇到的问题:

使用graia-component-selector显示导入包错误
复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 导入component
    image

  2. 运行报错
    image

检查graia-application-mirai及graia-component-selector版本为最新
image

运行环境:

  • 操作系统: [例如: Android(Termux), Android(MiraiAndroid)]win10 64位
  • mirai-core 版本:1.3.0
  • mirai-api-http 版本:1.7.4
  • graia-application-mirai 版本:0.1.1
  • 是否出现在机器人长期运行后: [是/否] 否

额外信息:

ws开启时shutdown报错

描述你遇到的问题:
开启 websocket 时,使用 CTRL+C 退出需要按两次:第一次输出 application shutdowned.;第二次输出报错 Task exception was never retrieved
PS: 我在 win10 下运行是正常的,不知道为什么 ubuntu 服务器上就会这样,可能跟 asyncio 在不同系统上面的实现有关。网上搜了下,相关的有个这个 python/asyncio#341

复现步骤:
入门文档 中的代码再给 app.launch_blocking() 加上 try/except KeyboardInterrupt

root@HostKvm-9cf9b6:~# python3.7 bot.py
[2020-11-09 00:10:42,700][INFO]: initializing app...
[2020-11-09 00:10:42,724][INFO]: detecting remote's version...
[2020-11-09 00:10:42,736][INFO]: detected remote's version: 1.8.4
[2020-11-09 00:10:42,739][INFO]: using pure websocket to receive event
[2020-11-09 00:10:42,739][INFO]: event receive method checked.
[2020-11-09 00:10:42,739][INFO]: this application's initialization has been completed.
[2020-11-09 00:10:42,740][INFO]: --- setting start ---
[2020-11-09 00:10:42,740][INFO]: broadcast using: <graia.broadcast.Broadcast object at 0x7f9ee7f9a4d0>
[2020-11-09 00:10:42,740][INFO]: enable log of chat: yes
[2020-11-09 00:10:42,740][INFO]: debug: no
[2020-11-09 00:10:42,740][INFO]: version(remote): 1.8.4
[2020-11-09 00:10:42,740][INFO]: --- setting end ---
[2020-11-09 00:10:42,741][INFO]: application has been initialized, used 0.0404s
^C[2020-11-09 00:10:47,871][INFO]: application shutdowned.
^C[2020-11-09 00:10:51,304][ERROR]: Task exception was never retrieved
future: <Task finished coro=<GraiaMiraiApplication.ws_all_poster() done, defined at /usr/local/lib/python3.7/dist-packages/graia/application/__init__.py:957> exception=KeyboardInterrupt()>
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/graia/application/__init__.py", line 1080, in launch_blocking
    loop.run_until_complete(self.getFetching()())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 566, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 534, in run_forever
    self._run_once()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 1735, in _run_once
    event_list = self._selector.select(timeout)
  File "/usr/lib/python3.7/selectors.py", line 468, in select
    fd_event_list = self._selector.poll(timeout, max_ev)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "bot.py", line 29, in <module>
    app.launch_blocking()
  File "/usr/local/lib/python3.7/dist-packages/graia/application/__init__.py", line 1083, in launch_blocking
    loop.run_until_complete(self.shutdown())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 566, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 534, in run_forever
    self._run_once()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 1771, in _run_once
    handle._run()
  File "/usr/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.7/dist-packages/graia/application/__init__.py", line 964, in ws_all_poster
    received_data = await connection.receive_json()
  File "/usr/local/lib/python3.7/dist-packages/aiohttp/client_ws.py", line 291, in receive_json
    data = await self.receive_str(timeout=timeout)
  File "/usr/local/lib/python3.7/dist-packages/aiohttp/client_ws.py", line 274, in receive_str
    msg = await self.receive(timeout)
KeyboardInterrupt

建议:
我自己简单改了下 graia/application/__init__.py 里的 shutdown

    async def shutdown(self):
        if self.broadcast is not None:
            loop = self.broadcast.loop
            try:
                await self.broadcast.layered_scheduler(
                    listener_generator=self.broadcast.default_listener_generator(ApplicationShutdowned),
                    event=ApplicationShutdowned(self)
                )
            except:
                self.logger.error("it seems our shutdown operator has been failed...check the remote alive.")
                traceback.print_exc()
        else:
            loop = loop or asyncio.get_event_loop()
        for t in asyncio.all_tasks(loop):
            if t == asyncio.current_task(loop):
                continue
            t.cancel()
            try:
                await t
            except asyncio.CancelledError:
                pass
        await self.signout()
        await self.session.close()
        self.logger.info("application shutdowned.")

Kanata匹配问题

描述你遇到的问题:

使用Kanata的时候,当同时有FullMatch和RequireParam时,假如发送信息只能够匹配FullMatch,就会触发错误

复现步骤:
该 BUG 会在进行以下操作后出现:
1.在bcc的dispatchers里填写 Kanata([FullMatch('anime'), RequireParam(name = 'tag')])
2.发送‘amine’

发生错误的代码

@bcc.receiver(GroupMessage, headless_decoraters = [Depend(judge.active_check_message)], dispatchers = [Kanata([FullMatch('anime'), RequireParam(name = 'tag')])])
async def anime(app: GraiaMiraiApplication, group: Group, message: MessageChain, member: Member, tag: MessageChain):
    ...

控制台日志输出截图:

image

运行环境:

  • 操作系统: Windows
  • mirai-core 版本: 1.0-M4
  • mirai-api-http 版本: 1.8.4
  • graia-application-mirai 版本: 0.10.11
  • 是否出现在机器人长期运行后: 否

额外信息:

Decorater 报错 TypeError

参考教程时发生错误
https://graia.originpages.com/#/suggests/donot_make_handler?id=%e8%bf%87%e6%bb%a4%e6%b6%88%e6%81%af

复现步骤:

def at_me(message: MessageChain):
    if message[At] != []:
        raise ExecutionStop()

@bcc.receiver("GroupMessage", priority=1, headless_decoraters=[Decorater(at_me)])
async def group_message_handler(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member):

控制台日志输出截图:

Traceback (most recent call last):
  File "/Users/dengwenhao/coding/learn/Application/demo.py", line 45, in <module>
    @bcc.receiver("GroupMessage", priority=1, headless_decoraters=[Decorater(at_me)])
  File "/usr/local/lib/python3.7/site-packages/graia/broadcast/entities/decorater.py", line 11, in __init__
    super().__init__(target=target, pre=pre)
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
[2020-08-06 01:06:07,694][ERROR]: Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x109854fd0>

运行环境:

  • 操作系统: [例如: Android(Termux), Android(MiraiAndroid)]
  • mirai-core 版本:latest
  • mirai-api-http 版本:latest
  • graia-application-mirai 版本:0.1.1 (pip3 install)
  • 是否出现在机器人长期运行后: [否]

Graia发送图片失败

描述你遇到的问题:
graia发送图片失败

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 使用Image.fromLocalFile指定图片路径
  2. 发送图片

控制台日志输出截图:

console:
image
graia:
[2020-08-18 22:07:52,182][INFO]: [BOT *****] Group(*****) <- [mirai:image:{1633C2F2-9DF3-1B70-2C24-86D1646BB55B}.mirai]

运行环境:

  • 操作系统: Windows10
  • mirai-core 版本: mirai-core-qqandroid-1.1.3
  • mirai-api-http 版本: mirai-api-http-v1.7.2
  • graia-application-mirai 版本: 0.1.13
  • 是否出现在机器人长期运行后: 否

额外信息:

image

[进度跟进] Mock Server for Graia Application

目前我们发现了一个问题: 当大型的应用部署时, 很难去避免一些问题, 这时候需要在开发环境进行测试, 而现今 Graia Application 因为目前的体量原因, 也需要这样一个单元测试架构, 去发现现有系统中潜在的问题.

现在要做的事情:

  • 基于 monkey patch like 的, 对 GraiaMiraiApplication 的网络IO进行劫持, 并输送到测试集中处理, 由程序内部校验提交数据正确性
  • (可能不会做) 一个基于 fastapimirai-api-http 模拟实现.

README is offending

若你在使用的过程中遇到了问题, 欢迎[提出聪明的问题](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md), 也请不要[像个弱智一样提问](https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways), 我们希望有人能让这个项目变得更好.

文檔中的言語略微粗魯,不太禮貌,容易勸退新手。希望能有所改進。

是否实现了sendImageMessage发送图片功能呢?

查看了下模块代码,好像并没有实现sendImageMessage发送图片功能,使用文档中也没有提到这个功能点。求教!
但是发现一个uploadImage上传图片到服务器的功能,返回的是imageId等相关的信息(这个接口用途又是什么呢?)多谢!

在mirai-console报错重启后 ,graia-application 不再能接收消息

描述你遇到的问题:
最近经常出现收不到消息的情况,今天专门去console看下啥情况,发现在mirai-console报错重启后 ,graia-application 不再能接收消息,但是mirai-console重启后是可以看到打印消息的

复现步骤:
该 BUG 会在进行以下操作后出现:
加入较多群(20个左右,其中5个比较火热)

控制台日志输出截图:

 11:13:55 [INFO] [BOT 3539347852] [❤群(123123)] Thaumiel(321321321) -> [mirai:source:650897,1066985371]**奶茶**
 11:14:03 [INFO] [NETWORK] Send: Heartbeat.Alive
 11:14:03 [INFO] [NETWORK] Recv: Heartbeat.Alive.Response
 11:14:10 [INFO] [BOT 3539347852] [❤群(123123)] 弟四号(321321879) -> [mirai:source:650898,2133225292][mirai:image:{1C311994-AA32-7E30-689C-929B150BE4B0}.mirai]
 11:15:03 [INFO] [NETWORK] Send: Heartbeat.Alive
 11:15:03 [INFO] [NETWORK] Recv: Heartbeat.Alive.Response
 11:15:10 [INFO] [BOT 123123123] [❤群(123123)] 学 长+我(123123123) -> [mirai:source:650899,-2064435564][mirai:image:{ADDAD040-FB69-60D9-C9E4-88A66D4266C0}.mirai] 
Exception in thread "DefaultDispatcher-worker-4" java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:377)
        at io.ktor.utils.io.nio.ChannelsKt.read(Channels.kt:135)
        at io.ktor.network.sockets.CIOReaderKt$attachForReadingDirectImpl$1$1$1.invokeSuspend(CIOReader.kt:90)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:175)
        at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:137)
        at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:108)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:308)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:318)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:250)
        at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKey(SelectorManagerSupport.kt:84)
        at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKeys(SelectorManagerSupport.kt:64)
        at io.ktor.network.selector.ActorSelectorManager.process(ActorSelectorManager.kt:73)
        at io.ktor.network.selector.ActorSelectorManager$process$1.invokeSuspend(ActorSelectorManager.kt)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Exception in thread "DefaultDispatcher-worker-4" java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:377)
        at io.ktor.utils.io.nio.ChannelsKt.read(Channels.kt:135)
        at io.ktor.network.sockets.CIOReaderKt$attachForReadingDirectImpl$1$1$1.invokeSuspend(CIOReader.kt:90)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:175)
        at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:137)
        at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:108)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:308)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:318)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:250)
        at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKey(SelectorManagerSupport.kt:84)
        at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKeys(SelectorManagerSupport.kt:64)
        at io.ktor.network.selector.ActorSelectorManager.process(ActorSelectorManager.kt:73)
        at io.ktor.network.selector.ActorSelectorManager$process$1.invokeSuspend(ActorSelectorManager.kt)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
SLF4J: Failed to load class "org.slf4j.impl.StaticMDCBinder".
SLF4J: Defaulting to no-operation MDCAdapter implementation.
SLF4J: See http://www.slf4j.org/codes.html#no_static_mdc_binder for further details.
 11:15:35 [INFO] [BOT 321123123] [❤群(123123)] 19 行管 河南 小吴(3219218293) -> [mirai:source:650900,1966226433]奶茶~
 11:16:03 [INFO] [NETWORK] Send: Heartbeat.Alive
 11:16:03 [INFO] [NETWORK] Recv: Heartbeat.Alive.Response
控制台恢复正常接收消息……

graia-application 没有输出,只是终止打印收到的消息
最后一条打印的消息是 『奶茶』
(第一行)

运行环境:

  • 操作系统: macos
  • mirai-core 版本:latest
  • mirai-api-http 版本:latest
  • graia-application-mirai 版本:0.1.1 (pip3 install)
  • 是否出现在机器人长期运行后: [否] 且经常出现

利用定时任务发送本地图片报错

描述你遇到的问题:
我利用loop.create_task创建一个定时任务用来发送图片,但是会报错
exception=LookupError(<ContextVar name='application' at 0x03A23338>)>

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. loop.create_task 创建一个定时任务
  2. 开始执行发送图片await app.sendGroupMessage(group,MessageChain.create([Image.fromLocalFile('1.jpg')])) 命令时

发生错误的代码

app = GraiaMiraiApplication(..)
async def reminder():
    while True:
        await asyncio.sleep(1)
        if is_time():
            await app.sendGroupMessage(group,MessageChain.create([Image.fromLocalFile('1.jpg')]))
loop.create_task(reminder())
app.launch_blocking()

控制台日志输出截图:

image
用的是miraiOK,没看到 mirai-console有什么输出

运行环境:

  • 操作系统: windows10
  • mirai-core 版本: mirai-core-qqandroid-1.1.3.jar
  • mirai-api-http 版本: mirai-api-http-v1.7.4.jar
  • graia-application-mirai 版本: 0.1.17
  • 是否出现在机器人长期运行后: 否

额外信息:

试了下发送文字消息是没问题的,不知道为什么发送图片时报错了,是我用法有问题吗?

发生错误不打印

描述你遇到的问题:

跟着文档中 从一个复读机开始 写了个复读机,运行 ”可以工作的代码“ 时没有输出错误消息,尝试加入其它错误均不会输出。根据下一步给 message 加上 .asSendable() 后可以正常运行复读。

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 运行 bot.py
  2. 私聊 复读吧!

控制台日志输出截图:

bot.py

import asyncio

from graia.application import GraiaMiraiApplication, Session
from graia.application.message.chain import MessageChain
from graia.application.friend import Friend
from graia.broadcast import Broadcast


loop = asyncio.get_event_loop()

bcc = Broadcast(loop=loop)
app = GraiaMiraiApplication(
    broadcast=bcc,
    connect_info=Session(
        host="http://localhost:8080", # 填入 httpapi 服务运行的地址
        authKey="1234567890", # 填入 authKey
        account=3424139009, # 你的机器人的 qq 号
        websocket=True # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作.
    )
)

@bcc.receiver("FriendMessage")
async def Friend_message_handler(app: GraiaMiraiApplication, message: MessageChain, friend: Friend):
    if message.asDisplay().startswith("复读"):
        await app.sendFriendMessage(friend, message)

app.launch_blocking()

mirai-console

 21:26:21 [INFO] [NETWORK] Send: OnlinePush.RespPush
 21:26:25 [INFO] [NETWORK] unknown group 528 type 0x0000000000000115, data: 08 9E D6 9B 87 0B 10 81 EE E0 E0 0C 1A 14 08 00 10 05 18 82 A1 A0 F9 05 20 02 28 FF FF FF FF 0F 32 00
 21:26:25 [INFO] [NETWORK] Send: OnlinePush.RespPush
 21:26:26 [INFO] [NETWORK] Send: MessageSvc.PbGetMsg
 21:26:26 [INFO] [NETWORK] Send: MessageSvc.PbDeleteMsg
 21:26:26 [INFO] [BOT 3424139009] SK_415(2967923486) -> [mirai:source:7281,-781614544]复读
 21:26:26 [INFO] [BOT 3424139009] SK_415(2967923486) -> [mirai:source:7283,574316507]复读吧!
 21:26:29 [INFO] [NETWORK] Send: OnlinePush.RespPush

graia-application 的控制台

[2020-08-03 21:26:11,667][INFO]: launching app...
[2020-08-03 21:26:11,884][INFO]: using pure websocket to receive event
[2020-08-03 21:26:11,884][INFO]: event reveiver running...

运行环境:

  • 操作系统: Win10 (MiraiOK)
  • mirai-core 版本: 1.1.3
  • mirai-api-http 版本: 1.7.3
  • graia-application-mirai 版本: 0.1.1
  • 是否出现在机器人长期运行后: 否

额外信息:

但愿不是因为我又弱智了,那以后真没脸提问了……

当要发送的消息符合某些条件时,Graia处理缓慢且消息无法成功发出

描述你遇到的问题:
若准备在群里发出的内容超过130个字(一个汉字、全角符号、中文标点都算一个字),且同时包含至少6个汉字和至少5个标点符号(不管是中文的还是英文的)的时候,当程序运行到sendGroupMessage(),就会卡住3s左右之后再发送。然后虽然mirai的控制台显示出了要发送的消息的内容,但实际上消息并没有发出,在同一个群的成员看不到Bot发送的消息。但是在私聊中没有这种现象。

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 将代码复制到本地文件test.py中,修改authKey和account
  2. 安装mirai-api-http,指定与之前相同的authKey并运行MiraiOK或mirai-console-loader
  3. 运行test.py,直到 application has been initialized, used x.xxxs 之后,在该机器人qq加入的群中发送任意消息并留意python控制台与Mirai控制台

发生错误的代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
from graia.application.entry import (GraiaMiraiApplication, Group, Friend, Member, MemberLeaveEventKick,
                                     MessageChain, Plain, Session)
from graia.broadcast import Broadcast

loop = asyncio.get_event_loop()

bcc = Broadcast(loop=loop)
app = GraiaMiraiApplication(
        broadcast=bcc,
        connect_info=Session(
                host='http://127.0.0.1:25567',  # 填入 httpapi 服务运行的地址
                authKey='mahuateng',  # 填入 authKey
                account=10001,  # 你的机器人的 qq 号
                websocket=True  # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作.
        )
)

msg = '啊啊啊啊啊啊。。。。。111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'


@bcc.receiver('GroupMessage')
async def group_message_handler(group: Group, message: MessageChain, member: Member, app: GraiaMiraiApplication):
    print('---START---')
    await app.sendGroupMessage(group, MessageChain(__root__=[
        Plain(msg)
    ]))
    print('---STOP---')
    print(group)
    print(member)
    print(message)


@bcc.receiver('FriendMessage')
async def friend_message_handler(friend: Friend, app: GraiaMiraiApplication):
    print('---START---')
    await app.sendFriendMessage(friend, MessageChain(__root__=[
        Plain(msg)
    ]))
    print('---STOP---')
    print(friend)


app.launch_blocking()

控制台日志输出截图:
Graia控制台
Mirai控制台
Q群

运行环境(测试过的):

  • 操作系统: Windows10 20H2 64位
  • mirai-core 版本: 1.3.1
  • mirai-api-http 版本: v1.8.4(基于这一个提交自己构建以用于新版本的mirai-console
  • mirai-consolemirai-console-terminal版本: 1.0-RC-1
  • graia-application-mirai 版本: 0.10.13
  • 是否出现在机器人长期运行后: 否

额外信息:
之前使用 Windows Server 2012 R2 64位 + MiraiOK + mirai-core-1.2.3 + mirai-api-http-1.8.4(官方发布版) + mirai-console-1.0-M4 也有一样的问题,但是当时不是130个字,会多一点,没具体测试过

这是我自己构建的mirai-api-http-v1.8.4.jar.zip

是否有定时事件的功能

类似nonebot的schedule。有的话麻烦给一下修饰器调用方法或者其他调用方法
麻烦了,谢谢!

行吧, 本项目不会停止更新, 别fork了

晨风的机器人被tx封也可能只是因为他盈利过多(一个授权200+),
所以被搞了, 而cq因为风险太大才主动关闭的(是否是tx胁迫我暂且蒙在鼓里),
其他的看cq就直接关闭我觉得十分谔谔, 但我认为mirai仍然会转生的,
到目前看, mirai是本地协议, 实现的基本能用, 鉴于tx的协议自带向上兼容(qq2009改改都能用),
所以不需要跑, 要跑的话也没法逃了.

尝试发送闪图时报错

描述你遇到的问题:
尝试发送闪图时报错

复现步骤:
该 BUG 会在进行以下操作后出现:
发送闪图

发生错误的代码
await app.sendGroupMessage(group, MessageChain.create([Image.fromLocalFile(Path(path)).asFlash()]))

控制台日志输出截图:
mirai-console控制台:
Snipaste_2020-08-29_21-50-17
Graia控制台:
Snipaste_2020-08-29_21-49-10

运行环境:

  • 操作系统: CentOS 8
  • mirai-core 版本: mirai-core-qqandroid-1.1.3
  • mirai-api-http 版本: mirai-api-http-v1.7.4
  • graia-application-mirai 版本: 0.1.10
  • 是否出现在机器人长期运行后: 否(尝试添加新功能)

额外信息:

临时会话消息事件无法触发

描述你遇到的问题:

复现步骤:
该 BUG 会在进行以下操作后出现:
写一段这样子的代码

@bcc.receiver("TempMessage")
async def temp_message_handler(app: GraiaMiraiApplication, message: MessageChain, temp: TempMessage):
    print(message.asDisplay())
    print(111)
    if message.asDisplay() == '你好':
        msg = '你好'
        await app.sendTempMessage(temp,MessageChain.create(\
                    [Plain(msg)]).asSendable())

然后尝试向机器人发送临时会话消息,graia控制台内没有任何反应
控制台日志输出截图:

image
image

运行环境:

  • 操作系统: windows
  • mirai-core 版本: 1.1.3
  • mirai-api-http 版本: 1.7.4
  • graia-application-mirai 版本: 0.1.1(pypi源没更新)
  • 是否出现在机器人长期运行后: 否

额外信息:

如何加入自己写的异步任务

现有 githublistener.py,可独立运行

from typing import Callable, List
import asyncio

import requests
import settings


async def event_handler(repo: str, req, Send):
    etag = None
    while True:
        if etag:
            req.headers.update({'If-None-Match': etag})
        _event = req.get(
            f'http://api.github.com.xiaojin233.cn/repos/{repo}/events?per_page=1')
        # Send(_event.status_code)
        hasXPollInterval = 'X-Poll-Interval' in _event.headers
        etag = _event.headers['ETag']
        x_poll_interval: int = int(
            _event.headers['X-Poll-Interval']) if hasXPollInterval else 60
        if _event.status_code == 200 and etag:
            _j = _event.json()
            for i in _j:
                thisType = i['type']
                if thisType == 'IssuesEvent':
                    await issuesOpend(repo, i['payload'], Send)
                elif thisType == 'PushEvent':
                    await pushEvent(repo, i, Send)
        await asyncio.sleep(x_poll_interval)


async def issuesOpend(repo: str, payload: dict, Send):
    this = payload['issue']
    if payload['action'] == 'opened':
        _number = this['number']
        _title = this['title']
        await Send(f'[{repo}] #{_number} {_title}')


async def pushEvent(repo: str, event: dict, Send):
    _operator = event['actor']['display_login']
    _commitsNumber = len(event['payload']['commits'])
    if _commitsNumber == 1:
        _desc = event['payload']['commits'][0]['message']
        await Send(
            f'[{repo}] {_operator} pushed {_commitsNumber} commit:\n{_desc}')
    else:
        await Send(f'[{repo}] {_operator} pushed {_commitsNumber} commits.')


req = requests.session()
req.headers.update({'Authorization': f'token {settings.github_access_token}'})
req.headers.update({'Accept': 'application/vnd.github.v3+json'})


def githubListener(send_func):
    l = list()
    loop = asyncio.get_event_loop()
    for repo in settings.github_listen_repos:
        l.append(event_handler(repo, req, send_func))
    loop.run_until_complete(asyncio.wait(l))

if __name__ == "__main__":
    async def s(m):
        print(m)
    githubListener(s)

我试图在 main.py 中调用它

# GitHub Listener
async def _send(message: str):
    await app.sendGroupMessage(settings.specialqq.commspt_group, MessageChain.create([Plain(message)]))
githubListener(_send)

但我知道这不行,因此来求教。我的目的是使这 2 个异步任务合并为一个任务运行(也就是一起运行了啦)

是否能同时连接多个 bot

类似nonebot,能否一个程序同时连接多个机器人,然后在调用的时候用类似于 bot_id 的参数来区分,有的话请问具体应该怎么做,感谢。

无法发送闪照

描述你遇到的问题:
无法发送闪照
复现步骤:
该 BUG 会在进行以下操作后出现:
发送闪照时程序出现异常并卡住

控制台日志输出截图:
mirai-console输出正常收到消息

[2020-08-15 18:52:28,083][INFO]: launching app...
[2020-08-15 18:52:28,325][INFO]: using pure websocket to receive event
[2020-08-15 18:52:28,326][INFO]: event reveiver running...
/usr/local/Cellar/[email protected]/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/graia/application/message/chain.py:155: RuntimeWarning: coroutine 'Image.fromLocalFile.._Image_Internal.toExternal.._flash_image_transfer' was never awaited
result.append(await run_always_await(i.toExternal(
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

运行环境:

  • 操作系统: MacOS 10.15.6
  • mirai-core 版本: 0.29.1
  • mirai-api-http 版本: 1.7.2
  • graia-application-mirai 版本: 0.1.11
  • 是否出现在机器人长期运行后: 否

额外信息:
群组消息和好友消息都是一样的报错

运行示例出错

描述你遇到的问题:
运行快速上手中的 bot.py 报错

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 将示例代码保存至 bot.py 运行

bot.py

from graia.broadcast import Broadcast
from graia.application import GraiaMiraiApplication, Session
from graia.application.message.chain import MessageChain
import asyncio

from graia.application.message.elements.internal import Plain
from graia.application.friend import Friend

loop = asyncio.get_event_loop()

bcc = Broadcast(loop=loop)
app = GraiaMiraiApplication(
    broadcast=bcc,
    connect_info=Session(
        host="http://localhost:8080", # 填入 httpapi 服务运行的地址
        authKey="graia-mirai-api-http-authkey", # 填入 authKey
        account=5234120587, # 你的机器人的 qq 号
        websocket=True # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作.
    )
)

@bcc.receiver("FriendMessage")
async def friend_message_listener(app: GraiaMiraiApplication, friend: Friend):
    await app.sendFriendMessage(friend, MessageChain(__root__=[
        Plain("Hello, World!")
    ]))

app.launch_blocking()

控制台日志输出截图:

Win10

[2020-08-03 11:08:35,230][INFO]: launching app...
[2020-08-03 11:08:39,236][INFO]: application shutdowning...
Traceback (most recent call last):
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 936, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 1025, in create_connection
    raise exceptions[0]
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 1010, in create_connection
    sock = await self._connect_sock(
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 924, in _connect_sock
    await self.sock_connect(sock, address)
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 702, in sock_connect
    return await self._proactor.connect(sock, address)
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\windows_events.py", line 808, in _poll
    value = callback(transferred, key, ov)
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\windows_events.py", line 595, in finish_connect
    ov.getresult()
ConnectionRefusedError: [WinError 1225] 远程计算机拒绝网络连接。

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 579, in launch_blocking
    fetch_method = loop.run_until_complete(self.launch())
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 543, in launch    
    await self.authenticate()
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 66, in authenticate
    async with self.session.post(self.url_gen("auth"), json={
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client.py", line 1012, in __aenter__
    self._resp = await self._coro
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client.py", line 480, in _request
    conn = await self._connector.connect(
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 523, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 858, in _create_connection 
    _, proto = await self._create_direct_connection(
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 1004, in _create_direct_connection
    raise last_exc
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 980, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\connector.py", line 943, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host localhost:8080 ssl:default [远程计算机拒绝网络连接。]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "e:/coding/mirai/bot.py", line 28, in <module>
    app.launch_blocking()
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 582, in launch_blocking
    loop.run_until_complete(self.shutdown())
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 572, in shutdown  
    await self.signout()
  File "C:\Users\songr\AppData\Local\Programs\Python\Python38\lib\site-packages\graia\application\__init__.py", line 88, in signout    
    raise InvaildSession("you should call 'authenticate' before this to get a sessionKey!")
graia.application.exceptions.InvaildSession: you should call 'authenticate' before this to get a sessionKey!

Centos7

[2020-08-03 11:12:13,714][INFO]: launching app...
[2020-08-03 11:12:13,726][INFO]: application shutdowning...
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 579, in launch_blocking
    fetch_method = loop.run_until_complete(self.launch())
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 543, in launch
    await self.authenticate()
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 69, in authenticate
    response.raise_for_status()
  File "/usr/local/lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 941, in raise_for_status
    raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 404, message='', url=URL('http://localhost:8080/auth')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "bot.py", line 28, in <module>
    app.launch_blocking()
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 582, in launch_blocking
    loop.run_until_complete(self.shutdown())
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 572, in shutdown
    await self.signout()
  File "/usr/local/lib/python3.8/site-packages/graia/application/__init__.py", line 88, in signout
    raise InvaildSession("you should call 'authenticate' before this to get a sessionKey!")
graia.application.exceptions.InvaildSession: you should call 'authenticate' before this to get a sessionKey!

运行环境:

  • 操作系统: Win10_x64, Centos7_x64
  • mirai-core 版本: 略
  • mirai-api-http 版本: 略
  • graia-application-mirai 版本: 0.1.0
  • 是否出现在机器人长期运行后: 否

额外信息:

前两天使用 0.0.6 版本时可以正常运行,昨晚升级为 0.1.0 后就出现这个报错。曾怀疑是自己电脑的问题,尝试了降级/重装 graia-application-mirai 和重启电脑,均无效。之后使用自己的阿里云尝试出现了相似的报错内容。因为判断该问题与 mirai-coremirai-api-http 无关,故省略。

PS: 第一次发 issue,如有问题还请指出。

Graia转换后的消息链缺失闪照元素

描述你遇到的问题:
如题。

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 写一个能够接收消息的方法,并打印消息链
  2. 在群内发送一张闪照
  3. 可以发现mirai-console处还能看到闪照元素,但是Graia转换后的消息链中缺失了闪照

发生错误的代码

@bcc.receiver("GroupMessage")
async def group_message_handler(app: GraiaMiraiApplication, message: MessageChain):
    print(message)

控制台日志输出截图:
image
image

运行环境:

  • 操作系统: Windows 10
  • mirai-core 版本: 1.3.3
  • mirai-api-http 版本: 1.8.4
  • graia-application-mirai 版本: 0.10.14
  • 是否出现在机器人长期运行后: 否

额外信息:

Bug report:收到xml消息后会意外退出

描述你遇到的问题:
在收到xml信息时客户端抛出错误并shut down

复现步骤:
该 BUG 会在进行以下操作后出现:
当接收到xml消息时会发生错误,
我的测试情景:
其他用户(或是其他机器人)给我方bot(私聊)发送一条基于xml的歌曲卡片信息,这时候graia-application就会shut down(这个情况平时基本遇不到,我是在看酷Q发送的歌曲卡片信息时意外发现的)

控制台日志输出截图:

mirai-console信息如下:
[mirai:service:2,<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] Butter-Fly" sourceMsgId="0" url="https://i.y.qq.com/v8/playsong.html?_wv=1&amp;songid=103178393&amp;souce=qqshare&amp;source=qqshare&amp;ADTAG=qqshare" flag="0" adverSign="0" multiMsgFlag="0"><item layout="2"><audio cover="http://imgcache.qq.com/music/photo/album_500/41/500_albumpic_1066541_0.jpg" src="http://apd-vlive.apdcdn.tc.qq.com/amobile.music.tc.qq.com/C400003XJxM604j9In.m4a?guid=667547133&amp;vkey=4BFF71E737EA556F0A35D94E93B83426F34A22417C3733FBC1B6C08337D4415138209B740FBF5EAF2BBA68D3CC824B6F06C94416FEA20CBC&amp;uin=0&amp;fromtag=38" /><title>Butter-Fly</title><summary>和田光司</summary></item><source name="QQ音乐" icon="https://i.gtimg.cn/open/app_icon/01/07/98/56/1101079856_100_m.png?date=20200807" url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app" a_actionData="com.tencent.qqmusic" i_actionData="tencent1101079856://" appid="1101079856" /></msg>]https://i.y.qq.com/v8/playsong.html?_wv=1&songid=103178393&souce=qqaio&ADTAG=aiodiange

graia-application错误信息如下:

[2020-08-07 18:21:53,473][INFO]: application shutdowning...
[2020-08-07 18:21:53,475][INFO]: goodbye :)
Traceback (most recent call last):
  File "bot.py", line 149, in <module>
    app.launch_blocking()
  File "D:\software\anaconda3\lib\site-packages\graia\application\__init__.py", line 580, in launch_blocking
    loop.run_until_complete(fetch_method)
  File "D:\software\anaconda3\lib\asyncio\base_events.py", line 583, in run_until_complete
    return future.result()
  File "D:\software\anaconda3\lib\site-packages\graia\application\__init__.py", line 523, in ws_all_poster
    event = await self.auto_parse_by_type(received_data)
  File "D:\software\anaconda3\lib\site-packages\graia\application\__init__.py", line 507, in auto_parse_by_type
    k: v for k, v in original_dict.items() if k != "type"
  File "pydantic\main.py", line 455, in pydantic.main.BaseModel.parse_obj
  File "D:\software\anaconda3\lib\site-packages\graia\broadcast\entities\event.py", line 31, in __init__
    super().__init__(**kwargs)
  File "pydantic\main.py", line 344, in pydantic.main.BaseModel.__init__
  File "pydantic\main.py", line 900, in pydantic.main.validate_model
  File "pydantic\fields.py", line 570, in pydantic.fields.ModelField.validate
  File "pydantic\fields.py", line 725, in pydantic.fields.ModelField._validate_singleton
  File "pydantic\fields.py", line 732, in pydantic.fields.ModelField._apply_validators
  File "pydantic\class_validators.py", line 311, in pydantic.class_validators._generic_validator_basic.lambda12
  File "pydantic\main.py", line 587, in pydantic.main.BaseModel.validate
  File "D:\software\anaconda3\lib\site-packages\graia\application\message\chain.py", line 38, in parse_obj
    handled_elements.append(iii.fromExternal(ii.parse_obj(i)))
  File "pydantic\main.py", line 455, in pydantic.main.BaseModel.parse_obj
  File "pydantic\main.py", line 344, in pydantic.main.BaseModel.__init__
  File "pydantic\main.py", line 874, in pydantic.main.validate_model
pydantic.errors.ConfigError: field "type" not yet prepared so type is still a ForwardRef, you might need to call Xml.update_forward_refs().

运行环境:

  • 操作系统: windows10
  • mirai-core 版本: 1.3.0
  • mirai-api-http 版本: dev1.7.4
  • graia-application-mirai 版本: 0.1.3
  • 是否出现在机器人长期运行后: [是/否] 否

第一步遇到问题

pip导入库结束,运行,遇到如下问题
没有找到模块 graia.application.message
和g.a.friend(这里简写了)
找了下源代码确实没有,pip尝试更新也没用

QQ群中一些信息获取不到

QQ群中无法获取某个发言用户的以下资料:
nickname:QQ网名(非群名片)
level:群中等级(如:冒泡)
性别
年龄
地区

翻看了下源码和mirai-api-http文档,好像目前版本并不支持这些基本信息(原来在酷q中能获取到)。
如果说法有误,请纠正,谢谢。

scheduler报错

描述你遇到的问题:
scheduler启动错误

复现步骤:
该 BUG 会在进行以下操作后出现:
1.写个scheduler(使用crontab)
2.在规定时间报错

发生错误的代码
Uploading S01005-122518(1)(1).jpg…

控制台日志输出截图:

运行环境:

  • 操作系统: Windows server 2016
  • mirai-core 版本: 1.3.0
  • mirai-api-http 版本: 1.8.2
  • graia-application-mirai 版本: 0.10.6
  • 是否出现在机器人长期运行后: 否

额外信息:

在以前的版本(忘记具体哪个版本)代码确认可以运行

[反面教材] 自造 Handler 的后果

我试图在 GroupMessage 的监听器中加入自己写的命令处理器,可结果并不如人意,Graia 似乎并没有正确地调用 group_message_listener 方法(至少我在 bot.pyprint('OK') 是失败的),请问这是框架的问题还是我的问题呢?如果问题在我,我该如何调整以达到目的?


bot.py

import asyncio

from graia.application.entry import (
    GraiaMiraiApplication, MessageChain,
    Member, Group, GroupMessage,
    Plain, At, Image
)
from graia.broadcast import Broadcast

from botpermissions import Permissions
from botmessages import BotMessage

bot_event_mapping = dict
bot_command = str

loop = asyncio.get_event_loop()
bcc = Broadcast(loop=loop)

class Bot(object):
    app: GraiaMiraiApplication

    member_join_event_mapping: bot_event_mapping = dict()
    group_message_commands_mapping: bot_event_mapping = dict()

    def __init__(self, connect_info: GraiaMiraiApplication) -> None:
        self.app = GraiaMiraiApplication(
            broadcast=bcc,
            connect_info=connect_info
        )

    def run(self) -> None:
        self.app.launch_blocking()

    def _findCmdFunc(self, cmd: bot_command):
        _mapping = self.group_message_commands_mapping
        if cmd in _mapping:
            return _mapping[cmd]
        else:
            return None

    def onCommand(self, cmd: bot_command):
        def deco(f):
            self.group_message_commands_mapping[cmd] = f
            print(self.group_message_commands_mapping)
            return f
        return deco

    @bcc.receiver("GroupMessage")
    async def group_message_listener(self, app: GraiaMiraiApplication, event: GroupMessage, group: Group):
        print('OK')
        bMessage = BotMessage(event)
        if bMessage.msg.cmd and not bMessage.permission.isBlocked:  # 如果有指令(带 $)且没有被封禁
            targetFunc = self._findCmdFunc(bMessage.cmd.cmd)
            print(targetFunc)
            messageList = targetFunc(bMessage=bMessage)
            await app.sendGroupMessage(group, MessageChain.create(messageList))

main.py

from bot import Bot
import settings

from graia.application.entry import (
    Plain, At, Image
)

bot = Bot(settings.connection_session)


@bot.onCommand(cmd='$test')
def test(bMessage) -> list:
    return [Plain('Nya!')]


if __name__ == "__main__":
    bot.run()

botmessage.py

from graia.application.entry import (
    Member, GroupMessage,
    MessageChain, Plain, At, Quote
)

from settings import SpecialQqNums
from botpermissions import Permissions


class BotMessage(object):
    '''MessageChain 解析器'''
    message_chain: MessageChain
    sender: Member

    permission: Permissions

    class msg(object):
        display: str = None
        plain: list = None
        at: list = None

    class quote(object):
        display: str = None

    class cmd(object):
        cmd: str = None
        args: list = None

    def __init__(self, _group_message: GroupMessage):
        '''初始化 BotMessage

        Args:
            _group_message: GroupMessage 对象 '''
        # 初始化
        self.message_chain = _group_message.messageChain
        self.sender = _group_message.sender

        # 设置对象属性
        self._setMsg()
        self._setCmd()
        self._setQuote()

    def _setMsg(self):
        '''设置消息本身'''
        self.msg.plain = self.message_chain.get(Plain)
        self.msg.at = self.message_chain.get(At)
        self.msg.display = self._getPlainsDisplay(self.msg.plain)

        # Constance 优化
        if self.sender.id == SpecialQqNums.constance:
            self.msg.display = self.msg.display.split(':', 1)[1]  # :后的为消息部分

    def _setQuote(self):
        '''设置被回复的原文'''
        _quote: Quote = self.message_chain.get(Quote)[0]  # Quote 只会有一个
        self.quote.display = self._getQuotePlainsDisplay(_quote.origin)

    def _setCmd(self):
        '''设置 cmd 相关'''
        _msg_plain = self.msg.display
        if '$' in _msg_plain:
            _spilted_message = _msg_plain.split(' ', 1)
            self.cmd.cmd = _spilted_message[0]
            self.cmd.args = _spilted_message[1] if len(
                _spilted_message) > 1 else None

    @staticmethod
    def _getPlainsDisplay(l: list) -> str:
        text = ''
        for _i in l:
            i_text = _i.text
            if _i.text.strip() != '':
                text = f'{text} {i_text}'
        return text.strip()

    @classmethod
    def _getQuotePlainsDisplay(cls, l: list):
        i_l = list()
        for _i in l:
            if isinstance(_i, Plain):
                i_l.append(_i)
        return cls._getPlainsDisplay(i_l)

回复消息中多余的at

描述你遇到的问题:
回复消息的解析可能存在问题

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 群内有人回复某一条消息的时候

运行环境:

  • 操作系统: [例如: Android(Termux), Android(MiraiAndroid)]
  • mirai-core 版本: 1.3.0
  • mirai-api-http 版本: 1.7.3
  • graia-application-mirai 版本: 0.1.5
  • 是否出现在机器人长期运行后: [否]

额外信息:
如果回复消息中包含qq自动添加的at行为则是:
image

[
    Source(id=19532, time=datetime.datetime(2020, 8, 8, 1, 29, 58, tzinfo=datetime.timezone.utc)),
    Quote(id=19527, groupId=xxxxxxxx, senderId=xxxxxxxx, targetId=601249169, origin=MessageChain(__root__=[Source(id=19527, time=datetime.datetime(2020, 8, 8, 1, 27, 3, tzinfo=datetime.timezone.utc)), Plain(type='Plain', text='1')])),
    At(type='At', target=xxxxxxxx, display='@雪洛千心山'),
    Plain(type='Plain', text=' '),
    At(type='At', target=xxxxxxxx, display='@雪洛千心山'),
    Plain(type='Plain', text=' 帮楼上百度')
]

如果回复消息中qq自动添加的at被删除之后则是:
image

[
    Source(id=19534, time=datetime.datetime(2020, 8, 8, 1, 36, 10, tzinfo=datetime.timezone.utc)),
    Quote(id=19527, groupId=xxxxxxxx, senderId=xxxxxxxx, targetId=xxxxxxxx, origin=MessageChain(__root__=[Source(id=19527, time=datetime.datetime(2020, 8, 8, 1, 27, 3, tzinfo=datetime.timezone.utc)), Plain(type='Plain', text='1')])),
    At(type='At', target=xxxxxxxx, display='@雪洛千心山'),
    Plain(type='Plain', text=' '),
    Plain(type='Plain', text='帮楼上百度')
]

请问如何获取好友/群聊列表

我的需求是在管理员在私聊发送拉黑指令之后 bot给被拉黑人发送一段消息.

不过我没法获取好友/群聊列表, 使用sendFriendMessage如果被拉黑人不是好友的话终端会报错.
我查看mirai-api-http管理相关是有这个方法的, 而后我在graia/application文件夹下文件并没有找到类似的方法.
谢谢!
(语序有点乱, 见谅...)

[feature request] 更详细的文档

能否在手册中对 MessageChain 中的 has, get, join 等函数做出一些讲解,我在使用中有很大的疑惑和不解 (根本不会用) .

FriendMessage无法获取MessageChain

from graia.broadcast import Broadcast
from graia.application import GraiaMiraiApplication, Session
import asyncio

from graia.application.protocol.entities.message.elements.internal import Plain

from graia.application.protocol.entities.message.chain import MessageChain
from graia.application.protocol.entities.targets.friend import Friend

......

@bcc.receiver("FriendMessage")
async def friend_message_listener(
    # message: MessageChain,
    friend: Friend,
    app: GraiaMiraiApplication,
):
    print('received message')

......

如上代码在收到信息时可以正常打出消息,但把message取消注释之后便不会进入到这个函数。类似代码处理GroupMessage时就没有这样的问题。

请问如何让机器人在群组中回复特定的人?

首先感谢大佬们提供mirai的python sdk,鞠躬……
我的需求是群里有人at了机器人之后,机器人可以通过回复(Quote)方式来回复该人(即构建如下图所示的一个MessageChain)。
回复
目前做出了以下尝试和探索:

  1. 我阅读了文档,发觉Quote元素不能被发送
  2. 查看了graia.application.message.elements.internal里的Quote类也没有得到什么启发
  3. 我不死心还去看了mirai别的sdk的文档,比如NodeMirai,发觉它有单独提供一个方法叫sendQuotedGroupMessage,但是目前本库没有这个方法。

我想请问目前的版本可以实现这个需求吗?不知道是不是我哪里看漏了,请大佬轻拍,(╥╯^╰╥)

通过http方式连接时fetchMessage出错

描述你遇到的问题:
启动bot时抛出异常并直接退出

Traceback (most recent call last):
  File "C:/Users/---/PycharmProjects/PixivBot/bot.py", line 83, in <module>
    app.launch_blocking()
  File "C:\Users\---\PycharmProjects\PixivBot\.venv\lib\site-packages\graia\application\__init__.py", line 893, in launch_blocking
    loop.run_until_complete(fetch_method)
  File "C:\Users\---\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 608, in run_until_complete
    return future.result()
  File "C:\Users\---\PycharmProjects\PixivBot\.venv\lib\site-packages\graia\application\__init__.py", line 844, in http_fetchmessage_poster
    data = await self.fetchMessage(fetch_num)
  File "C:\Users\---\PycharmProjects\PixivBot\.venv\lib\site-packages\graia\application\__init__.py", line 423, in fetchMessage
    result.append(await self.auto_parse_by_type(event))
  File "C:\Users\---\PycharmProjects\PixivBot\.venv\lib\site-packages\graia\application\__init__.py", line 810, in auto_parse_by_type
    if not original_dict.get("type") and not isinstance(original_dict.get("type"), str):
AttributeError: 'str' object has no attribute 'get'

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 使用websocket=False的方式初始化Session和GraiaMiraiApplication
  2. app.launch_blocking()

控制台日志输出截图:
TIM截图20200814141153

运行环境:

  • 操作系统: Windows
  • mirai-core 版本: 0.5.2
  • mirai-api-http 版本: 1.7.3
  • graia-application-mirai 版本: 0.1.10
  • 是否出现在机器人长期运行后: 否

额外信息:

MessageChain拼接函数参数问题

描述你遇到的问题:
MessageChain 类的 plusWith 和 join 使用时候遇到 TypeError: can only concatenate list (not "MessageChain") to list

@classmethod
def join(cls, *chains: "MessageChain") -> "MessageChain":
"""拼接参数中给出的所有消息链
Returns:
MessageChain: 拼接结果
"""
return cls.create(sum(chains, []))
def plusWith(self, *chains: "MessageChain") -> "MessageChain":
"""在现有的基础上将另一消息链拼接到原来实例的尾部, 并生成, 返回新的实例.
Returns:
MessageChain: 拼接结果
"""
return self.create(sum(chains, self.__root__))

建议:
不知道为啥三个方法只有 plus 方法写的是对的,是因为没返回值嘛233……
这里处理 chains 还是按照的 v3 的 MessageChain 类型,按照 v4 的 chains 应该传入 List[msg.__root__]
应该改成 return self.create(sum([i.__root__ for i in chains], self.__root__))

messageFromId报错AttributeError: module ' graia. application. event' has no attribute 'get '

环境:
mirai-console-1.0-M4.jar
mirai-console-pure-1.0-M4.jar
mirai-core-qqandroid-1.3.0.jar
mirai-api-http-v1.8.4.jar(mirai-api-http-v1.8.3.jar两个都测试过都这样)
graia最新版

源码:
'quote1 = await app.messageFromId(message.get(Quote)[0].origin).get(Source)[0].id

还测试过:

message.get(Quote)[0].id

message.get(Quote)[0.origin.get(Source)[0]

都会报错`

输出:
Traceback (most recent call last):
File "C: \data1\P\Python\mirai1\venv\tib\site- packages \graia\broadcast__ init__ py", line 163, in Executor
result = await run_ always_ await(
File "C: \data1\P\Python\mirai1 \venv\lib\site一packages \graia \broadcast\utilles.pY", line 10,in run_ always_ await
return await any_ callable
File "C:/data1/P/Python/mirai1/mirai1/bot1.py" Line 394, in group_ message_ handLer
quote1: GroupMessage = await app . messageFromId(message . get(Quote ) [@] . origin. get(Source)[@].id)
File "C: \data1\P\Python\mirai1\venv\Lib\site- packages\graia\application\utilles.py", line 15,in wrapper
return await func(self, *args, **kwargs )
File "C: \data1\P\Python\mirai1\venv\Lib\site -packages \graia \application\ . init__ .DY", line 628, in messageFromId
return await self . auto . parse_ by_ type (event)
File "C: \data1\P\Python\mirai1\venv\liblsite-packages \graia\application_ init__ 。 py", line 940, in auto_ parse_ by_ type
if not original_ dict.get("type") and not isinstance(originaL_ dict.get("type"), str):
AttributeError: module ' graia. application. event' has no attribute 'get '

边缘情况的处理, 可能包含健康检查等.

描述你遇到的问题:

在实现文档中的快速上手和复读机器人时,无法触发好友或群聊消息事件

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 将文档中的代码复制到本地文件bot.py中,修改authKey和account
  2. 安装mirai-api-http,指定与之前相同的authKey并运行MiraiOK
  3. 在MiraiOK的命令行界面中能正常收到消息
  4. 运行bot.py,直到event receiver running...之后无论是群聊还是好友消息都没有任何反应,在friend_message_listener中print也是无效
  5. 收到过一条重命名群名称的事件 [2020-08-09 10:11:48,028][ERROR]: received a unknown event: GroupNameChangeEvent{'type': 'GroupNameChangeEvent', 'origin': ......后略。说明graia是能和mirai-api-http通信的吧

控制台日志输出截图:

image
image

运行环境:

  • 操作系统: Windows
  • mirai-core 版本: 1.1.3
  • mirai-api-http 版本: 1.7.4
  • graia-application-mirai 版本: 0.1.5
  • 是否出现在机器人长期运行后: 否

原来mirai的一键包无法下载了,我借用了其他人分享的整合包,并删掉了无关插件,或许是其中某一步删多了?
谢谢~

使用getfriend出现问题

描述你遇到的问题:

在调用getfriend后,返回了一个coroutine对象,无法放入send friend message中

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. ...调用getFriend函数放入sendFriendMessage
  2. ...

发生错误的代码

await app.sendFriendMessage(app.getFriend(*******), MessageChain(root=[
Plain("test")
]))
控制台日志输出截图:

运行环境:

  • 操作系统: win10
  • mirai-core 版本:
  • mirai-api-http 版本:
  • graia-application-mirai 版本:
  • 是否出现在机器人长期运行后:

    额外信息:

如何获取好友发送的图片

我希望用机器人实现个投稿功能,后端处理发来的图片。但是Image类型里面并没有找到把Image转成Image_LocalFile的接口,请问该如何实现 已解决Image.url 直接下载就是了 关闭此issue

无法检测到闪照

描述你遇到的问题:

无法接收到闪照

复现步骤:
该 BUG 会在进行以下操作后出现:

  1. 接收闪照

控制台日志输出截图:

MessageChain显示
__root__=[Source(id=11246, time=datetime.datetime(2020, 8, 5, 8, 38, 17, tzinfo=datetime.timezone.utc))]
mirai端信息
16:38:17 [INFO] [BOT 1779803343] [测试(904763352)] ILS(1450069615) -> [mirai:source:11246,375979852][mirai:flash:{1457EE2F-7AEC-4DA8-D4EF-3CDE37F81146}.mirai]
运行环境:

  • 操作系统: Windows 10 x64
  • mirai-core 版本: 1.1.3
  • mirai-api-http 版本:1.7.3
  • graia-application-mirai 版本: 0.1.1
  • 是否出现在机器人长期运行后: 否

额外信息:

失踪的属性"app"

描述你遇到的问题:

似乎是意料之外的问题

复现步骤:
该 BUG 会在进行以下操作后出现:

  • 当我运行一个GraiaMiraiApplication实例时

发生错误的代码

@app.receiver("GroupMessage")
async def event_gm(mirai: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member):

    messages = message.toString()                   #留做刷屏和脏话的检测
    timestamp = message.__root__[0].time            #每条消息的时间
    membernames = member.memberName
    memberid = member.id                            #发送消息的人

    command = Features.Clear(messages)              #清洗文本,提取指令

    switch = {                                      #switch/case
            'text' : Plain,                         #消息组件复用
            'image' : Image.fromFileSystem,         #消息组件复用
            'xml' : Xml,                     #消息组件复用
            ':网抑云' : Features.Cloudmusic,
            ':image' : Features.Image,
            ':rss' : Features.RSS,
            ':zuan' : Features.Zuan,
            ':help' : Features.Help,
            'analysis': Features.Analysis
        }

    async def sendmessage(i):

        try:
            if i == 'analysis':
                try:
                    getmessages, infotype = switch[i](timestamp, membernames, memberid, messages)
                except TypeError:
                    return
            else:
                getmessages, infotype = switch[i]()
        except KeyError:                            #需要参数或者匹配的
            if re.match('^:ping', i):
                getmessages, infotype = Features.Ping(i)
            else:
                return

        await mirai.sendGroupMessage(
                group.id,
                [
                    At(target=memberid),
                    switch[infotype](getmessages)
                    ]
                )

    for i in command:                               #经过清洗提取的指令会逐一运行
        await sendmessage(i)

if __name__ == "__main__":
    mirai.launch_blocking()

控制台日志输出截图:

mirai-console那边没有问题

Traceback (most recent call last):
  File "Main.py", line 103, in <module>
    mirai.launch_blocking()
  File "/usr/lib/python3.8/site-packages/graia/application/__init__.py", line 1076, in launch_blocking
    loop.run_until_complete(self.initialize())
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/usr/lib/python3.8/site-packages/graia/application/__init__.py", line 997, in initialize
    self.broadcast.postEvent(ApplicationLaunched(self))
  File "/usr/lib/python3.8/site-packages/graia/application/event/lifecycle.py", line 9, in __init__
    self.app = app
AttributeError: 'ApplicationLaunched' object has no attribute 'app'

运行环境:

  • 操作系统: Manjaro[Linux>Terminal>MiraiOK]
  • mirai-core 版本: mirai-core-qqandroid-1.2.3
  • mirai-api-http 版本: v1.8.4
  • graia-application-mirai 版本: 0.10.10
  • 是否出现在机器人长期运行后: 否

额外信息:

快让我进Q群!

    我尝试过更改原app和mirai的实例名,但是无效
    看起来并不是与保留字冲突的原因

请问一下如何发送json类的消息,谢谢啦

作者大大想问一下如何发送json类的消息,我代码看了半天没搞清楚json消息如何构造....(plain和图片的构造都看懂了,弱鸡落泪),然后试了好久也没成功,谢谢啦

安装graia-component-selector引起的主程序回退问题

描述你遇到的问题:
ERROR: graia-component-selector 0.0.1 has requirement graia-application-mirai<0.0.6,>=0.0.5, but you'll have graia-application-mirai 0.1.1 which is incompatible.

复现步骤:
该 BUG 会在进行以下操作后出现:
pip install graia-component-selector

控制台日志输出截图:
^

运行环境:

  • 操作系统: Windows 10 x64
  • mirai-core 版本:1.3.0
  • mirai-api-http 版本:1.7.4
  • graia-application-mirai 版本:0.1.1 / 0.0.5?
  • 是否出现在机器人长期运行后: [是/否] 否

额外信息:
安装graia-component-selector的时候注意到自动把graia0.1.1的降级到了0.0.5 感觉有点奇怪所以过来提issue了

是否可以返回At对象的禁言状态

正在写的小项目有一个需求,在执行一个命令之前查询 @对象是否被禁言,如已被禁言就不执行。
如果能够返回 At对象 ismuted 的布尔就好了

无法解析mirai-api-http的版本号

描述你遇到的问题:
mah返回的版本号格式是v1.0.0,代码中使用int直接转换。

复现步骤:
每次打开graia都报一次。

发生错误的代码
hello world代码,就不发了

控制台日志输出截图:

[2020-10-26 09:49:43,964][INFO]: initializing app...
[2020-10-26 09:49:43,997][INFO]: detecting remote's version...
[2020-10-26 09:49:44,001][ERROR]: | failed to detect remote's version. |
[2020-10-26 09:49:44,010][ERROR]: | it seems that your version is less than 1.6.2, |
[2020-10-26 09:49:44,010][ERROR]: | this version of Graia Application may cause many issues, |
[2020-10-26 09:49:44,011][ERROR]: | so you had better to update your remote environment, |
[2020-10-26 09:49:44,011][ERROR]: | or you won't get our support! |
Traceback (most recent call last):
  File "D:\Code\GraiaApplicationMirai\src\graia\application\__init__.py", line 1005, in initialize
    await self.getVersion()
  File "D:\Code\GraiaApplicationMirai\src\graia\application\utilles.py", line 15, in wrapper
    return await func(self, *args, **kwargs)
  File "D:\Code\GraiaApplicationMirai\src\graia\application\__init__.py", line 149, in getVersion
    version = tuple(int(i) for i in data['data']['version'].split("."))
  File "D:\Code\GraiaApplicationMirai\src\graia\application\__init__.py", line 149, in <genexpr>
    version = tuple(int(i) for i in data['data']['version'].split("."))
ValueError: invalid literal for int() with base 10: 'v1'

运行环境:

  • 操作系统: windows 10 cmd
  • mirai-api-http 版本: 1.8.3
  • graia-application-mirai 版本: 0.10.10
  • 是否出现在机器人长期运行后: 否

额外信息:
报错里的是clone下来的版本。

群员被踢事件好像无法捕获

代码
@bcc.receiver("MemberLeaveEventKick")
async def member_leavekick(app: GraiaMiraiApplication, member: Member):
print(member.id)

是不是写错了?日志也没有任何反应,事件换成退群的可以正常运行

另外想问下如何@群成员

代码
await app.sendGroupMessage(group, MessageChain.create([At(member.id), Plain("测试")]))

提示错误
File "pydantic/main.py", line 334, in pydantic.main.BaseModel.init
TypeError: init() takes exactly 1 positional argument (2 given)

Kanata对于含引用的消息的判断

描述你遇到的问题:

通过Kanata来获取(过滤)消息时,碰到带有引用 / 回复的消息时会自动跳过。
复现步骤:
该 BUG 会在进行以下操作后出现:
1.一个使用Kanata的函数
2.发送带有引用的,正常情况下能触发的一句话
3.然后发现应该触发的函数没有触发

发生错误的代码

@bcc.receiver("GroupMessage",dispatchers=[Kanata([ 
    RegexMatch(r'[\s]*#test:[\s]*'), 
    RequireParam(name="test") 
])]) 
async def test_func(app:GraiaMiraiApplication,test:MessageChain,event:GroupMessage):
    pass

控制台日志输出截图:

mirai-console
graia

运行环境:

  • 操作系统: <!-- [例如: Android(Termux), Android(MiraiAndroid)

] -->Ubuntu 18.04

  • mirai-core 版本: mirai-console-1.0-M4.jar
  • mirai-api-http 版本: mirai-api-http-v1.8.3
  • graia-application-mirai 版本: 0.10.10
  • 是否出现在机器人长期运行后: 否

额外信息:

我个人认为是qq自动在引用消息后,正文前中额外添加了一个At

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.