维护花了一点时间,抱歉。。。。。。。。。
在本次攻击事件中暴露了一些网站安全性相关的问题。为了应对未来可能遭遇的各种类型的攻击。在这段时间里我们可能会进行各种安全相关的更新。
本次更新新增了发帖验证码系统,任何人发布新主题或者是回帖都需要完成验证码。
此外我们建立了MiraiForumGithub组织,开放了几个由我们编写的插件,欢迎大家提出意见或者是建议。如果无法通过论坛联系我们也可以通过组织联系我们。
请阅读: 论坛规则 常见问题QA 无法登录的临时处理方案
源代码和文档: mamoe/mirai, docs.mirai.mamoe.net
闲聊TG群: @mirai_mamoe, Gitter群 mamoe/mirai
使用俺维护的GOCQ维护分支:https://github.com/ProtocolScience/AstralGocq
登录流程巨大优化(如果出现签名异常,可以修改config移除ws协议的签名,该属于实验性特性)
开源了一个没有完全过检测的版本,可以正常运行高版本的so文件,希望起到抛砖引玉,促进研究的作用 https://github.com/zhaodice/Astral-QSignigngnn
——出现CC攻击后的措施——当服务器负载较大时,优先拒绝消耗量较大的IP的请求,如需IP白名单请联系。
——服务器目前开放的版本——9.0.55-9.0.95
9.1.0-9.1.15
(这就是直连的下场,由于被打流量打成黑洞,已无法连接)
服务器地址(自2024-08,租赁1年时间):http://8.216.82.28/
服务器地址(主要A,cloudflare):https://qsign.trpgbot.com
服务器地址(CDN线路):http://qsign-v3.trpgbot.com
服务器地址(端口转发,月流限制1G):http://qsign.w1.luyouxia.net
服务器地址(主要B,huggingface):https://zyr15r-astralqsign.hf.space
——注意事项——新的key:miraibbs
对本贴内容做了门户:https://qsign-guide.trpgbot.com/
1.服务器已全部迁移至主服务器,处理了一下主机的散热器问题,现在性能应该足够了。
2.除了 qsign.trpgbot.com ,其他的都是它的镜像,如果有条件也可以自己反向代理
ANDROID_PAD
{ "apk_id": "com.tencent.mobileqq", "app_id": 537220362, "sub_app_id": 537220362, "app_key": "0S200MNJT807V3GE", "sort_version_name": "9.0.56.16830", "build_time": 1713424357, "apk_sign": "a6b745bf24a2c277527716f6f36eb68d", "sdk_version": "6.0.0.2560", "sso_version": 21, "misc_bitmap": 150470524, "main_sig_map": 34869472, "sub_sig_map": 66560, "dump_time": 1713424357, "qua": "V1_AND_SQ_9.0.56_6372_YYB_D", "protocol_type": 6 } Mirai - 傻瓜式插件直接安装插件即可正常登录 https://github.com/MrXiaoM/fpv/releases/tag/v1.13.1
(它属于 fix-protocol-version 插件的开发分支,因为功能相同所以可能冲突,一山不容二虎哦,使用时请注意禁用相关插件)
mirai KFCFactory.json 使用配置:
{ "9.0.56": { "base_url": "https://qsign.trpgbot.com", "type": "fuqiuluo/unidbg-fetch-qsign", "key": "miraibbs" } }同时请另存为 协议配置文件(ANDROID_PAD)的数据内容到 ANDROID_PAD.json ,数据内容上文已给出
控制台输入 protocol load ANDROID_PAD
即可用ANDROID_PAD协议登录你的QQ
gocq config.yml使用配置:
sign-servers: - url: 'http://8.216.82.28/' key: 'miraibbs' authorization: '-' - url: https://qsign.trpgbot.com/' key: 'miraibbs' authorization: '-' auto-register: true同时请另存为 协议配置文件(ANDROID_PAD)的数据内容到 /data/versions/6.json ,数据内容上文已给出
测试结果607af2d3-ed77-49ea-a9b5-b3ac8adb98c4.png
新注册的账号使用本sign,在24小时后仍未出现冻结现象,证明已经通关。
有任何问题欢迎进行交流讨论,最后感谢fuqiuluo提供的unidbg调用思路以及各位逆向工作者的支持。
这一行代码报错
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/coroutines/EmptyCoroutineContext
at net.mamoe.mirai.utils.BotConfiguration.<init>(BotConfiguration.kt:64)
at net.mamoe.mirai.utils.BotConfiguration.<clinit>(BotConfiguration.kt:550)
at com.tugos.dst.admin.controller.MiraiBotExample.main(MiraiBotExample.java:16)
Caused by: java.lang.ClassNotFoundException: kotlin.coroutines.EmptyCoroutineContext
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 3 more
pom文件
<dependency> <groupId>net.mamoe</groupId> <artifactId>mirai-core-jvm</artifactId> <version>2.16.0</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> <version>1.9.0</version> </dependency>java版本1.8
“不好!这里要撑不下去了”
“A4 求救,A4 求救,A32 地区的沙雕数量超过阈值,即将突破防线!”
“什么!?啧。。”
“B8 已完成沙雕清除任务,现赶往 A32 地区”
“这样。。什么时候是个头啊。。”
如果想订阅本贴更新可以点击右上角铃铛🔔按钮
【持续时间】
1970.1.1 ~ 114514.12.31
【活动内容】
糟糕!沙雕小别墅遭到了从未知之处涌出的沙雕攻击,防御工事濒临崩溃,如果能用其他的方法击退它们的话。。
对了!沙雕图!
【参与方式】
在本贴中回复沙雕图,协助沙雕防御工事击退沙雕。
【活动奖励】
从其他 miraier 获取的沙雕图!是不是非常丰厚呢?
【注意事项】
遵守摸鱼区规则。
是沙雕图不是涩图!
【样例】
3c2dfb62-5555-4c00-a17b-d76715bf2088-image.png
开源/下载链接: https://github.com/MySoulcutting/BeautyPlugin
BeautyPluginBeautyPlugin 是一个基于Mirai用于浏览和查看小姐姐图片和视频的插件。该插件提供了群聊与私聊的方法,让用户可以轻松浏览和欣赏各种美丽的小姐姐图片和视频。
请不要评价此项目代码质量! 仅供学习参考,请勿用于非法用途。 功能 图片浏览: 查看各种小姐姐的图片。 视频播放: 观看小姐姐的视频内容。 分类浏览: 根据不同的分类浏览图片和视频。 图片分类 黑丝] [白丝] [美女] [原神] [jk] [acg] [妹子] [淘宝] [网红] [cos] [美腿] 使用方法 示例:/pic 黑丝 所有图片均来自网络接口, 如有图片不对还请见谅 视频分类 [jk] [欲梦] [女大] [热舞] [清纯] [白丝] [玉足] [蛇姐] [穿搭] [高质] [汉服] [黑丝] [变装] [萝莉] [甜妹] [小姐姐 [吊带] 使用方法 示例:/video 黑丝 所有视频均来自网络接口, 如有视频不对还请见谅 本项目所有资源均来自网络!如有问题与开发者无任何责任!版本:mirai-core-2.17.0
协议:ANDROID_PHONE
在群里发送视频,机器人服务报异常:
2025-02-13 16:48:49 E/Bot 机器人qq号: Exception on parsing packet.
java.lang.IllegalStateException: Exception in net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor@4a505ff2 while processing packet PbPushMsg.
at net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl.handleExceptionInProcess(NoticeProcessorPipeline.kt:105)
at net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl.handleExceptionInProcess(NoticeProcessorPipeline.kt:80)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process$suspendImpl(ProcessorPipeline.kt:289)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process(ProcessorPipeline.kt)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process$suspendImpl(ProcessorPipeline.kt:275)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process(ProcessorPipeline.kt)
at net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg.decode(OnlinePush.PbPushGroupMsg.kt:37)
at net.mamoe.mirai.internal.network.components.PacketCodecImpl.processBody(PacketCodec.kt:586)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline.processBody(CommonNetworkHandler.kt:158)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline.access$processBody(CommonNetworkHandler.kt:103)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline$1$3$1.invokeSuspend(CommonNetworkHandler.kt:127)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline$1$3$1.invoke(CommonNetworkHandler.kt)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline$1$3$1.invoke(CommonNetworkHandler.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at net.mamoe.mirai.internal.network.handler.CommonNetworkHandler$PacketDecodePipeline$1.invokeSuspend(CommonNetworkHandler.kt:127)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: Failed to transform internal message to facade message, msg=[Msg#664542228 {
contentHead=ContentHead#1124564697 {
pkgNum=0x00000001(1)
}
msgBody=MsgBody#368743498 {
richText=RichText#510310017 {
attr=Attr#1394834823 {
charSet=0x00000086(134)
fontName=宋体
pitchAndFamily=0x00000002(2)
random=0x11FD42F5(301810421)
size=0x0000000A(10)
time=0x67ADB1F1(1739436529)
}
elems=[Elem#650966069 {
commonElem=CommonElem#1018130843 {
businessType=0x00000015(21)
pbElem=0A FC 01 0A F5 01 0A 8A 01 08 DD 84 2A 12 20 64 63 62 33 38 66 38 64 38 64 64 33 39 36 37 36 31 36 36 32 32 34 39 63 64 30 36 38 34 66 61 38 1A 28 34 61 37 31 37 33 62 30 63 36 30 37 65 33 63 36 39 31 65 61 34 32 63 35 66 33 65 64 37 34 62 61 33 38 38 66 62 32 66 63 22 24 64 63 62 33 38 66 38 64 38 64 64 33 39 36 37 36 31 36 36 32 32 34 39 63 64 30 36 38 34 66 61 38 2E 6D 70 34 2A 08 08 02 10 00 18 00 20 00 30 B6 02 38 80 05 40 04 48 00 12 58 45 68 52 4B 63 58 4F 77 78 67 66 6A 78 70 48 71 51 73 58 7A 37 58 53 36 4F 49 2D 79 5F 42 6A 64 68 43 6F 67 68 77 73 6F 6E 74 69 39 67 36 4C 41 69 77 4D 79 42 48 42 79 62 32 52 51 67 50 55 6B 57 68 41 57 75 76 36 6C 68 48 6E 5F 4C 71 67 73 46 42 79 45 74 33 49 49 18 01 20 F1 E3 B6 BD 06 28 80 F5 24 30 00 28 01 32 00 0A FC 01 0A F5 01 0A 8A 01 08 EA 9E 01 12 20 38 38 62 38 61 34 34 34 61 62 35 31 31 31 35 30 62 31 32 64 32 35 39 34 64 39 30 66 36 31 34 63 1A 28 64 38 31 36 63 31 61 61 66 35 32 63 61 39 65 36 32 64 39 61 36 64 35 38 30 35 30 39 65 32 66 30 66 62 62 36 66 62 64 33 22 24 44 43 42 33 38 46 38 44 38 44 44 33 39 36 37 36 31 36 36 32 32 34 39 43 44 30 36 38 34 46 41 38 2E 70 6E 67 2A 08 08 01 10 00 18 00 20 00 30 B6 02 38 80 05 40 00 48 00 12 58 45 68 54 59 46 73 47 71 39 53 79 70 35 69 32 61 62 56 67 46 43 65 4C 77 2D 37 62 37 30 78 6A 71 6E 67 45 67 69 41 73 6F 77 6F 48 44 67 36 4C 41 69 77 4D 79 42 48 42 79 62 32 52 51 67 50 55 6B 57 68 42 43 76 32 4D 69 4D 61 36 41 72 45 34 5F 53 52 4C 69 77 30 53 53 18 01 20 F1 E3 B6 BD 06 28 80 F5 24 30 64 28 01 32 00 12 3E 0A 04 08 00 12 00 12 2E 08 02 10 02 1A 28 60 02 80 01 00 8A 01 20 64 63 62 33 38 66 38 64 38 64 64 33 39 36 37 36 31 36 36 32 32 34 39 63 64 30 36 38 34 66 61 38 1A 04 5A 00 62 00 50 00
serviceType=0x00000030(48)
}
}, Elem#650966069 {
elemFlags2=ElemFlags2#72429457 {
insts=[]
}
}, Elem#650966069 {
generalFlags=GeneralFlags#641615320 {
pbReserve=08 06 20 CB 50 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 01 10 29 90 04 80 80 80 10 B8 04 00 C0 04 00 CA 04 00 F8 04 80 80 08 80 05 41 88 05 00 D8 06 F9 01
}
}, Elem#650966069 {
extraInfo=ExtraInfo#613770739 {
flags=0x00000008(8)
groupMask=0x00000001(1)
level=0x00000001(1)
nick=发送人昵称
}
}]
}
}
msgHead=MsgHead#2073812536 {
fromAppid=0x000003E9(1001)
fromInstid=0x2005EC20(537259040)
fromUin=0x000000000EF9E982(发送人QQ号)
groupInfo=GroupInfo#875716453 {
groupCard=发送人昵称
groupCardType=0x00000002(2)
groupCode=0x000000002E9FF0C5(QQ群号)
groupInfoSeq=0x00000000000000C9(201)
groupLevel=0x00000001(1)
groupName=E6 9C BA E5 99 A8 E4 BA BA E6 B5 8B E8 AF 95
groupType=0x00000001(1)
}
isSrcMsg=false
msgFlag=0x00000008(8)
msgSeq=0x00000A44(2628)
msgTime=0x67ADB1F1(1739436529)
msgType=0x00000052(82)
msgUid=0x0100000011FD42F5(72057594339738357)
toUin=0x000000006D2E89C9(机器人QQ号)
}
}]
at net.mamoe.mirai.internal.message.ReceiveMessageHandlerKt.toMessageChain(ReceiveMessageHandler.kt:124)
at net.mamoe.mirai.internal.message.ReceiveMessageHandlerKt.toMessageChainOnline(ReceiveMessageHandler.kt:56)
at net.mamoe.mirai.internal.message.ReceiveMessageHandlerKt.toMessageChainOnline$default(ReceiveMessageHandler.kt:49)
at net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.processImpl(GroupMessageProcessor.kt:190)
at net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.processImpl(GroupMessageProcessor.kt:44)
at net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor.process(NoticeProcessorPipeline.kt:147)
at net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor.process(NoticeProcessorPipeline.kt:141)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process$suspendImpl(ProcessorPipeline.kt:287)
... 27 more
Caused by: kotlinx.serialization.MissingFieldException: Field 'noKeyDownloadInfo' is required for type with serial name 'net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.NewTechImageInfoMain', but it was missing
at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
at net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody$NewTechImageInfoMain.<init>(Msg.kt:764)
at net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody$NewTechImageInfoMain$$serializer.deserialize(Msg.kt:764)
at net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody$NewTechImageInfoMain$$serializer.deserialize(Msg.kt:764)
at kotlinx.serialization.protobuf.internal.ProtobufDecoder.decodeSerializableValue(ProtobufDecoding.kt:196)
at kotlinx.serialization.protobuf.internal.ProtobufTaggedDecoder.decodeSerializableElement(ProtobufTaggedDecoder.kt:82)
at net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody$NewTechImageInfo$$serializer.deserialize(Msg.kt:827)
at net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody$NewTechImageInfo$$serializer.deserialize(Msg.kt:827)
at kotlinx.serialization.protobuf.internal.ProtobufDecoder.decodeSerializableValue(ProtobufDecoding.kt:196)
at kotlinx.serialization.protobuf.internal.ProtobufDecoder.decodeSerializableValue(ProtobufDecoding.kt:186)
at kotlinx.serialization.protobuf.ProtoBuf.decodeFromByteArray(ProtoBuf.kt:137)
at net.mamoe.mirai.internal.utils.io.serialization.SerializationUtils__UtilsKt.loadAs(utils.kt:230)
at net.mamoe.mirai.internal.utils.io.serialization.SerializationUtils.loadAs(utils.kt:1)
at net.mamoe.mirai.internal.utils.io.serialization.SerializationUtils__UtilsKt.loadAs$default(utils.kt:225)
at net.mamoe.mirai.internal.utils.io.serialization.SerializationUtils.loadAs$default(utils.kt:1)
at net.mamoe.mirai.internal.message.image.OnlineNewTechImageImpl.<init>(OnlineImage.kt:150)
at net.mamoe.mirai.internal.message.protocol.impl.ImageProtocol$ImageDecoder.process(ImageProtocol.kt:93)
at net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderProcessor.process(MessageDecoder.kt:31)
at net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderProcessor.process(MessageDecoder.kt:24)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process$suspendImpl(ProcessorPipeline.kt:287)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process(ProcessorPipeline.kt)
at net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderPipelineImpl.process$suspendImpl(MessageDecoderPipeline.kt:57)
at net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderPipelineImpl.process(MessageDecoderPipeline.kt)
at net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderPipelineImpl.process(MessageDecoderPipeline.kt:36)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process$suspendImpl(ProcessorPipeline.kt:275)
at net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline.process(ProcessorPipeline.kt)
at net.mamoe.mirai.internal.message.protocol.MessageProtocolFacadeImpl$decode$1.invokeSuspend(MessageProtocolFacade.kt:307)
at net.mamoe.mirai.internal.message.protocol.MessageProtocolFacadeImpl$decode$1.invoke(MessageProtocolFacade.kt)
at net.mamoe.mirai.internal.message.protocol.MessageProtocolFacadeImpl$decode$1.invoke(MessageProtocolFacade.kt)
at net.mamoe.mirai.internal.utils.RunCoroutineInPlaceKt.runCoroutineInPlace(runCoroutineInPlace.kt:26)
at net.mamoe.mirai.internal.message.protocol.MessageProtocolFacadeImpl.decode(MessageProtocolFacade.kt:306)
at net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade$INSTANCE.decode(MessageProtocolFacade.kt)
at net.mamoe.mirai.internal.message.ReceiveMessageHandlerKt.toMessageChainImpl(ReceiveMessageHandler.kt:158)
at net.mamoe.mirai.internal.message.ReceiveMessageHandlerKt.toMessageChain(ReceiveMessageHandler.kt:122)
... 34 more
如题,错误如下
2025-02-13 02:06:42 I/main: Starting mirai-console... 2025-02-13 02:06:42 I/main: ===================================[ Mirai console 2.16.0 ]=================================== __ __ __ __ ______ __ | \ / \ \ | \/ \ | \ | ▓▓\ / ▓▓\▓▓ ______ ______ \▓▓ ▓▓▓▓▓▓\ ______ _______ _______ ______ | ▓▓ ______ | ▓▓▓\ / ▓▓▓ \/ \ | \| \ ▓▓ \▓▓/ \| \ / \/ \| ▓▓/ \ | ▓▓▓▓\ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓\ \▓▓▓▓▓▓\ ▓▓ ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ ▓▓ ▓▓▓▓▓▓\ | ▓▓\▓▓ ▓▓ ▓▓ ▓▓ ▓▓ \▓▓/ ▓▓ ▓▓ ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓\▓▓ \| ▓▓ | ▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ \▓▓▓| ▓▓ ▓▓ ▓▓ | ▓▓▓▓▓▓▓ ▓▓ ▓▓__/ \ ▓▓__/ ▓▓ ▓▓ | ▓▓_\▓▓▓▓▓▓\ ▓▓__/ ▓▓ ▓▓ ▓▓▓▓▓▓▓▓ | ▓▓ \▓ | ▓▓ ▓▓ ▓▓ \▓▓ ▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ ▓▓\▓▓ ▓▓ ▓▓\▓▓ \ \▓▓ \▓▓\▓▓\▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓▓▓▓▓▓ 2025-02-13 02:06:42 I/main: Backend: version 2.16.0, built on 2023-10-20 06:28:10. 2025-02-13 02:06:42 I/main: Frontend Terminal: version 2.16.0, provided by Mamoe Technologies 2025-02-13 02:06:42 I/main: Welcome to visit https://mirai.mamoe.net/ 2025-02-13 02:06:43 E/main: Failed to init MiraiConsole. net.mamoe.mirai.console.plugin.loader.PluginLoadException: Invalid plugin.yml in D:\fuwuqi\Mirai\plugins\luckperms-mirai-LuckPerms-Mirai-2.14.0-dev-7+null.jar at net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl$extractPlugins$filePlugins$4.invoke(BuiltInJvmPluginLoaderImpl.kt:276) at net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl$extractPlugins$filePlugins$4.invoke(BuiltInJvmPluginLoaderImpl.kt:261) at kotlin.sequences.FlatteningSequence$iterator$1.ensureItemIterator(Sequences.kt:315) at kotlin.sequences.FlatteningSequence$iterator$1.hasNext(Sequences.kt:303) at kotlin.sequences.TransformingSequence$iterator$1.hasNext(Sequences.kt:214) at kotlin.sequences.TransformingSequence$iterator$1.hasNext(Sequences.kt:214) at kotlin.sequences.SequencesKt___SequencesKt.toCollection(_Sequences.kt:787) at kotlin.sequences.SequencesKt___SequencesKt.toSet(_Sequences.kt:828) at net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl.extractPlugins(BuiltInJvmPluginLoaderImpl.kt:287) at net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl.listPlugins(BuiltInJvmPluginLoaderImpl.kt:72) at net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader$BuiltIn.listPlugins(JvmPluginLoader.kt) at net.mamoe.mirai.console.internal.plugin.PluginManagerImpl.listAndSortAllPlugins(PluginManagerImpl.kt:207) at net.mamoe.mirai.console.internal.plugin.PluginManagerImpl.findAndSortAllPluginsUsingBuiltInLoaders(PluginManagerImpl.kt:153) at net.mamoe.mirai.console.internal.plugin.PluginManagerImpl.loadAllPluginsUsingBuiltInLoaders$mirai_console(PluginManagerImpl.kt:163) at net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge.doStart$mirai_console(MiraiConsoleImplementationBridge.kt:303) at net.mamoe.mirai.console.MiraiConsoleImplementation$Companion.start(MiraiConsoleImplementation.kt:512) at net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader.startAsDaemon(MiraiConsoleTerminalLoader.kt:182) at net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader.startAsDaemon$default(MiraiConsoleTerminalLoader.kt:181) at net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader.main(MiraiConsoleTerminalLoader.kt:59) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.itxtech.mcl.Utility.bootJars(Utility.java:86) at org.itxtech.mcl.Utility.bootJars(Utility.java:76) at org.itxtech.mcl.Utility.bootMirai(Utility.java:98) at org.itxtech.mcl.module.builtin.Boot.boot(Boot.java:113) at org.itxtech.mcl.module.ModuleManager.phaseBoot(ModuleManager.java:123) at org.itxtech.mcl.Loader.lambda$start$4(Loader.java:196) at org.itxtech.mcl.Loader.tryCatching(Loader.java:151) at org.itxtech.mcl.Loader.start(Loader.java:196) at org.itxtech.mcl.Loader.main(Loader.java:84) Caused by: kotlinx.serialization.MissingFieldException: Field 'id' is required for type with serial name 'net.mamoe.mirai.console.plugin.jvm.SimpleJvmPluginDescription.SerialData', but it was missing at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20) at net.mamoe.mirai.console.plugin.jvm.SimpleJvmPluginDescription$SerialData.<init>(JvmPluginDescription.kt:254) at net.mamoe.mirai.console.plugin.jvm.SimpleJvmPluginDescription$SerialData$$serializer.deserialize(JvmPluginDescription.kt:254) at net.mamoe.mirai.console.plugin.jvm.SimpleJvmPluginDescription$SerialData$$serializer.deserialize(JvmPluginDescription.kt:254) at net.mamoe.yamlkt.Yaml.decodeFromString(Yaml.kt:162) at net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl$extractPlugins$filePlugins$4.invoke(BuiltInJvmPluginLoaderImpl.kt:270) ... 31 more已经尝试重新运行mcl,但无效
图片消息内容:
[{"type":"MessageSource","kind":"GROUP","botId":1831766333,"ids":[2574],"internalIds":[1280584505],"time":1739257169,"fromId":123456789,"targetId":782233797,"originalMessage":[{"type":"Image","imageId":"{57454715-A857-BAD2-D863-CA717CB64A5B}.jpg","size":275828,"imageType":"JPG","width":990,"height":990,"isEmoji":false}]},{"type":"Image","imageId":"{57454715-A857-BAD2-D863-CA717CB64A5B}.jpg","size":275828,"imageType":"JPG","width":990,"height":990,"isEmoji":false}] // 使用 [Builder] 构建图片 Image.Builder builder = Image.newBuilder(imageId); builder.setType(ImageType.valueOf(imageMessage.getImageType())); builder.setWidth(imageMessage.getWidth()); builder.setHeight(imageMessage.getHeight()); builder.setSize(imageMessage.getSize()); builder.setEmoji(imageMessage.getEmoji()); Image image = builder.build(); // 当图片在服务器上存在时返回 `true`, 这意味着图片可以直接发送. boolean uploaded = Image.isUploaded(image, event.getBot()); // 获取到图片地址,以便于下载或读取图片信息 String imageUrl = Image.queryUrl(image); System.out.println(imageId);图片消息:解析图片地址:http://gchat.qpic.cn/gchatpic_new/1831766333/0-0-57454715A857BAD2D863CA717CB64A5B/0?term=2
获取的图片地址不能访问
一个基于Mirai-http-api的 WebQQ
项目地址https://github.com/LazyCreeper/MiraiUI
这有啥用能在网页操作 Mirai 机器人。
运行环境任意 http 服务器,无需 php,mysql 环境
一些截图main
chat
本项目代码仅作为 vue 练手,可能会出现大量能跑但是屎山 💩 的代码或者一些魔法 🔮。请不要介意,如果你想的话可以提交pr😘。
啊还有,如果你指望这玩意能替代 QQ,那我建议你去找其他第三方客户端~
根据 Apache 协议开源
要饭0.01 也是爱
QR CODE
作为合格的 Miraier,一定曾想过在插件中加入图像合成功能,例如绘制每日发言排行榜,漂亮的签到卡片,或只是想给色图加个滤镜避免被 QQ 服务器吃掉。
开始进行图像处理的第一步当然是选择合适的 API,选择比努力更重要
在 JVM 平台上,有几个主流的图形处理方案可以选择:
Skia谷歌家的大小姐,地球上最流行的图形API,广泛应用于 Chromium、Android、Flutter 等知名软件中。
虽然笔者并未在 JVM 平台上直接使用过 Skia,但以下总结的优势来自于笔者在 Rust-Skia 中的经验:
性能:支持 GPU 加速,并允许编写 GPU 着色器(使用类似 GLSL 的 SKSL 语法)。 漂亮:相比于调教不足的 AWT,Skia 渲染的图像无需额外调教就十分精甚细腻。Skia 在 JVM 平台上的短板也很明显:
JNI:每个平台和架构都需要单独分发代码,且本地库编译后的文件大小约为 10MB。 文档:网上很难找到针对特定问题的 Java 绑定解决方案,相关的第三方库也很少。 编译:如果想要使用 Skia 的扩展功能(如 SVG 段落排版等),不得不经历一场痛苦的编译与配置过程,而且为每个平台交叉编译的方式与 JVM 平台的开发习惯并不匹配。 JavaFX十分古老的新技术,适合构建 UI 应用,文档和第三方库非常稀缺,因此后文不再提及。
AWT作为 JDK 的一部分,AWT 是 Java 中最为流行的图形 API,无需额外依赖,基于 AWT 的知名软件包括 JetBrains 全家桶 和 Eclipse。
与 Skia 相比,AWT 的优势如下:
生态:AWT 长期以来是 Java UI 和图像处理的唯一选择,因此可以找到详尽的文档资料,调教指南与第三方库(例如本文)。 依赖:捆绑在几乎所有 jvm 中,无需额外依赖。又不能选装,不用白不用劣势也很明显:
古老:AWT 不支持许多现代特性,例如彩色 emoji 字体和亚像素级抗锯齿等。 性能:编写高性能的代码需要付出大量的努力,尤其是在 AWT 中。 欠草:渲染漂亮图像的过程中会遇到许多迷惑的历史遗留特性,需要加大力度调教,这也是本文诞生的原因之一。总而言之,笔者强烈推荐大家选择 Skia。如果您不幸入坑了 AWT,希望本文能帮助你避开一些常见的坑。
AWT 七宗罪 锯齿在 AWT 诞生的年代,给文本和图片加上抗锯齿会严重降低性能,后来为了保证和之前版本的一致性,抗锯齿选项也没有默认启用。
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);e99f4b74-bb0a-49a9-940a-676df30bae1b-image.png
以上选项仅适用于文本与 Shape 抗锯齿,您会发现图片缩放绘制时还是会有锯齿和奇怪的像素点,这时就要说到...
重采样drawImage
想象一下这段代码
g2d.drawImage(img, x, y, w, h, null);这几乎是 AWT 中最常见的绘制图像操作,虽然速度很快,但对于缩放图像来说效果是相当糟糕的。
ee7b3aaf-b1b7-4c43-82f6-1ebebc068be3-image.png
所幸 AWT 中还有更漂亮的方法:
getScaledInstance
img.getScaledInstance(w, h, Image.SCALE_SMOOTH);5134b434-53a8-4a62-9027-6bf359f89fc7-image.png
确实漂亮了很多,然而代价是性能损失了几乎 1000 倍甚至 900 倍,在基准测试中,上个方法耗时为 0ms,这个方法耗时 771ms,很显然也是不能接受的。
可以看出,AWT 对图像的缩放算法相当糟糕,还好我们有更现代的第三方库:
Thumbnails.size
Thumbnails.of(image).size(w, h).asBufferedImage();143fefe2-8e96-4e5c-8408-e8ebfc30078f-image.png
得益于第三方库实现的快速重采样算法,缩放这张图片只花费了 94ms
回到 drawImage
在缩放图像分辨率与实际绘制分辨率相近的情况下,使用 Thumbnails.size 反而会造成额外的性能开销,经过古人的实践与总结,缩放倍率在 0.5 以内使用 drawImage 是最优解,超过此倍率就要引入额外的缩放流程来保证质量。
举例:
当原始分辨率为 200 * 200 时, 缩放到 101 * 101 或 299 * 299 应使用 drawImage; 缩放到 99 * 99 或 301 * 301 应加入额外的缩放流程。
网络请求 【Miraier 限定】 【腾讯粉丝福利】
聪明的 Miraier 应该也想到了从网络请求入手,请求更低分辨率的图像,既能减少图片下载时间又能提升缩放时的性能。
这是 Mirai 源码中获取用户头像的代码
public interface ContactOrBot : CoroutineScope { /** * 头像下载链接, 规格默认为 [AvatarSpec.LARGEST] */ public val avatarUrl: String get() = avatarUrl(spec = AvatarSpec.LARGEST) /** * 头像下载链接. * @param spec 头像的规格. */ @JvmName("getAvatarUrl") public fun avatarUrl(spec: AvatarSpec): String { return "http://q.qlogo.cn/g?b=qq&nk=${id}&s=${spec.size}" } }另外,域名为 gchat.qpic.cn 的图像貌似也可以请求低分辨率版本,但笔者没有在网上找到更多信息,希望大佬跟帖补充。
上文图像与基准测试引用自 Thumbnailator/wiki
文字排版研表究明,99% 的 AWT 用户在第一次绘制文本多行文本时,一定会写出这段代码:
g2d.drawString("多行\n文本", 20, 30);虽然几乎所有的图形 API 都会有这个问题,但 AWT 的高级排版类(例如 FlowLayout)是 Swing UI 专属,无法直接在图像内绘制文字。
在 Skia 中可以使用段落扩展来快速实现排版,AWT 又输
例如,在 AWT 中使用 LineBreakMeasurer 和 TextLayout 计算坐标实现基本的文本溢出换行:
public void paint(Graphics graphics) { Point2D pen = new Point2D(10, 20); Graphics2D g2d = (Graphics2D)graphics; FontRenderContext frc = g2d.getFontRenderContext(); LineBreakMeasurer measurer = new LineBreakMeasurer(styledText, frc); float wrappingWidth = getSize().width - 15; while (measurer.getPosition() < fStyledText.length()) { TextLayout layout = measurer.nextLayout(wrappingWidth); pen.y += (layout.getAscent()); float dx = layout.isLeftToRight() ? 0 : (wrappingWidth - layout.getAdvance()); layout.draw(graphics, pen.x + dx, pen.y); pen.y += layout.getDescent() + layout.getLeading(); } }(更多示例请参考 甲骨文官方文档)
当然,上方的代码只是甲骨文的卖家秀,实际渲染环境中没机会写出这么简洁的代码,因为会碰到更头痛的问题:
字体回退想象这样一个场景:
var font = StyleContext.getDefaultStyleContext().getFont("漂亮的英文字体", Font.PLAIN, 24); g2d.setFont(font); g2d.drawString("Hello 世界!", 20, 30);上方代码在 Windows 和 Linux 平台上会渲染为 【Hello 口口口】,在 Mac 平台上会正常渲染。
造成这种差异的原因是 JVM 逻辑字体配置 fontconfig.properties,仅在某些平台上生效,深层次的原因是 AWT 在不支持的平台上使用旧版本 HarfBuzz 进行整形,并不会自动回退为支持的字体。
对于这种情况的解决方案:
强迫用户使用 MacOS
强迫用户改用 JetBrainsRuntime JVM
自己实现字体回退逻辑:
例:
Font mainFont = StyleContext.getDefaultStyleContext().getFont("漂亮的英文字体", Font.PLAIN, 24); Font fallbackFont = StyleContext.getDefaultStyleContext().getFont("回退的中文字体", Font.PLAIN, 24); AttributedString str = new AttributedString("Hello 世界!"); int textLength = text.length(); result.addAttribute(TextAttribute.FONT, mainFont, 0, textLength); boolean fallback = false; int fallbackBegin = 0; for (int i = 0; i < text.length(); i++) { boolean curFallback = !mainFont.canDisplay(text.charAt(i)); if (curFallback != fallback) { fallback = curFallback; if (fallback) { fallbackBegin = i; } else { result.addAttribute(TextAttribute.FONT, fallbackFont, fallbackBegin, i); } } } g2d.drawString(str.getIterator(), 20, 30);聪明的读者一定已经发现:
上文中 LineBreakMeasurer () 构造函数刚好需要 str.getIterator() 获取的 AttributedCharacterIterator!
将两段代码结合一下刚好能实现最基础的文本段落渲染。
全局字体看到这里,大部分爱偷懒的 Miraier 都会想到【回退字体也太麻烦了,直接用中文字体渲染就好了】偷懒方案可跳转至下文 #偷懒的最终方案
这会导致以下问题:
无法渲染字体不支持的字符,例如 阿拉伯语,印地语 等。 无法同时用漂亮的英文字体和中文字体回退。 无法渲染 Emoji (很多用户的 ID 包含 Emoji,不能渲染的话就太糟了)于是诞生了终极方案:
默认字体无法显示,启用回退方案。 调用 GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts() 取得注册的所有字体进行遍历。 找到能显示的字体应用到字符。程序初始化时通过测试各语言码点分类进行性能优化:
遍历所有字体并测试各语言覆盖范围,例如 AB00-AB5F 范围为越南傣语,测试字体是否支持 AB00 渲染时快速判断字符码点范围查表找出回退字体需要注意的是:
Emoji 和部分扩展区字符会占用多个码点,超出 char 的范围,例如 Emoji 😊 为 Character.toChars(0x1F600)
Emoji 可能包含连字符 0x200d, 被连字符组合的 Emoji 不应该被分开渲染,例如 👩👩👧👧 包含 4 个子表情与 3 个连字符,占用 11 个 char
52e51909-d65e-4dd6-8cac-a18e9d6559be-image.png
Emoji 没有颜色😭868e08b0-817a-47b7-8716-89c0aee117a7-image.png
遗憾的是, AWT 使用的 HarfBuzz 版本不支持 CPAL, SBIX 等彩色字体扩展,只能通过定制 JVM 并替换 HarfBuzz 依赖解决。
万幸,JetBrains 在开发 IDE 时注意到了这点,目前在 AWT 平台渲染彩色 Emoji 唯一的解决方案是使用 JetBrainsRuntime JVM。
偷懒的最终方案在 AWT 中,可以使用 "Dialog" 获取当前系统字体, 而且在任何平台都能正确应用 JVM 逻辑字体配置 fontconfig.properties 中定义的回退方案。
没有调用 g2d.setFont() 时绘制的文字也会使用 "Dialog" 字体
var font = StyleContext.getDefaultStyleContext().getFont("Dialog", Font.PLAIN, 24); g2d.setFont(font);作为偷懒的惩罚,使用自定义字体时不支持的字符会变为 【口口口】,详见上文。
后话本来想写的 AWT 七宗罪只写了四条,请期待本贴持续更新。
最后,以上提到的几点在 Skia 中完全无需任何调教,笔者强烈推荐大家选择 Skia。
本贴欢迎提问 AWT 与 Rust-Skia 相关问题,别的我也不会。
本文随意转载,转载前请告知我。
CC-BY-NC-SA 4.0
相关链接: Petpet
RT
其实本来我的bot已经因为自己手贱登陆qq nt直接报废了,但是论坛里有佬提供了新的协议库,那这不赶紧复活bot都对不起这个新的协议库。
由于存在下载障碍,所以这里也搞了个存档,本帖中的相关标星*资源无法下载均可以从这里拿走,由于本帖不会进行版本跟进,若年代过于久远请以最新为准,本帖中的一些配置可能需要后续随着引用贴的更新进行调整。
https://orisland.lanzoul.com/b0maqsrkj
密码:53cs
本帖使用xshell+xftp作为ssh连接软件 *。
https://github.com/KasukuSakura/mirai-login-solver-sakura 任意手机模拟器(本教程以雷电为例,海外版没有广告,广告ptsd可以选海外版) .. 可选安装(插件) https://github.com/project-mirai/chat-command https://mirai.mamoe.net/topic/68/luckperms-mirai-高级权限服务插件 https://mirai.mamoe.net/topic/2645/今日运势插件 ... 详细步骤 注册一个qq号https://github.com/MrXiaoM/fpv (平替上面的fix-protocol-version,解决一些登录问题),本文基于fix-protocol-version官方版本进行配置,如果使用这个版本,可省略导入协议库和配置KFCFactory.json的过程,安装启动后直接进入登陆验证部分。
需绑定手机,非常不推荐使用一些批量注册的qq号,或者来源不明的qq号,这些账号被风控的可能性会更高,而且不安全,容易被杀。
准备一台服务器或vps请注意,为了bot能长期稳定运行考虑,应尽可能避免海外云主机。
阿里云,腾讯云,等等各大云服务厂商提供了各种型号的学生机供你选择。
从省钱划算的角度考虑,推荐考虑的配置为1c或2c配置,内存在1g到2g即可满足bot的运行需要,甚至还能再挂个宝塔,个人推荐最低使用轻量级云服务器即可,ecs或者类似的服务器也可以,这个没有特别大的区别。
我的阿里云学生机
900d+高可用性
当然因为bot本身不需要公网环境,所以如果你自己有闲置的服务器或者低功耗设备(比如nas,软路由等等),也可以在自己的服务器或者设备上进行bot搭建,相同网络环境下,机器人被搞的概率和频率会小的多。
系统选择使用centos8或者ubuntu/debian等。
本文以目前比较常用的Ubuntu22作为bot的搭建平台,且相同网络环境下进行(HomeLab,结尾有HomeLab相关硬件说明)。
如果你的bot搭建在云服务厂商的设备中,你可能需要使用vpn的方式将自己用来验证的设备链接到目标网络中避免错误代码237等错误。
本文默认你已经对ubuntu的apt源进行了更换,已经对ubuntu做了基本的初始配置,例如挂载磁盘,update等操作。
安装mirai如果你是在消费级硬件上进行搭建,请注意ubuntu时区可能有误,需要使用命令进行调整。
timedatectl set-timezone Asia/Shanghai
由于本文在进行编撰的过程中,mirai论坛本身处于被墙状态,mcl安装的必要资源package.json会出现问题,所以本文选择通用的安装方式,不使用mcl一键安装。若之后论坛网络访问恢复,更推荐考虑mcl一键安装更为省事,使用mcl一键安装可以跳转到下一章节--必要插件安装。
这里引用mcl项目提供的安装方案。
https://github.com/iTXTech/mcl-installer
为服务器安装java,不同系统以当前系统为准。
apt install openjdk-17-jre-headless -y安装完成后检查版本。
java -verison0856fce7-9fc1-4d87-9337-a4a24e9394dc-image.png
手动下载mcl压缩包
https://maven.aliyun.com/repository/public/org/itxtech/mcl/2.1.2/mcl-2.1.2.zip
解压到需要安装的mirai目录中,省事考虑可以对mirai文件夹整体给777权限。
本文默认mirai目录为/root/mirai,如果懒得对命令进行修改,请创建到相同目录。
chmod -R 777 /root/mirai
启动mcl.jar对mirai进行安装。
java -jar mcl.jar安装过程中你必须完整的看完mirai的用户须知,不可取消和跳过,这对于之后的排错和处理非常重要。
2024-07-04 07:36:14 I/main: mirai-console started successfully.
mirai本体基本安装完成。
ctrl + c或 exit退出mirai进行后续安装。
安装手机模拟器(本帖以雷电为例)
前往github,
下载fix-protocol-version *
https://github.com/cssxsh/fix-protocol-version/releases/download/v1.13.0/fix-protocol-version-1.13.0.mirai2.jar
下载mirai-login-solver-sakura *
https://github.com/KasukuSakura/mirai-login-solver-sakura/releases/download/v0.0.12/apk-release.apk
打开雷电模拟器,安装mirai-login-solver-sakura,打开备用。
a7b82986-695a-4625-bd7a-1f92fb0b1d60-image.png
f8671270-d47d-442c-b136-8fd77c0be17c-image.png
将fix-protocol-version上传到mirai目录下的plugins目录内,此时plugins内应包含三个文件。
26d00b95-23bc-47e0-aa8e-dcbb8c1b1fd1-image.png
前往下面的地址,本页后续还需要使用,不要关闭。
https://mirai.mamoe.net/topic/2673/试图复活qsign-基于9-0-56版本-再捞一把
复制协议配置文件
869c1c02-1d25-44bf-bf40-3bcf5d133d55-image.png
在mirai的根目录中输入命令
在控制台中右击屏幕,粘贴配置。
27633478-46bf-4d79-9c30-61d70b594ac6-image.png
进行保存退出。
ctrl + x
y
回车
忘掉之前启动mirai的方式,之后使用./mcl -u进行启动。
协议配置使用./mcl -u 启动mirai。
等待加载完成后输入命令
出现如下提示时协议信息导入完成。
11dcc05d-0e6e-4542-9886-4fbc967824af-image.png
检查当前的协议库中的协议版本。
e48dd4c5-8d25-49ce-a48d-5ba2c91577b0-image.png
退出mirai。
回到刚才的页面,复制该部分。
127c4fa5-e12c-4b49-bf85-4013126e5858-image.png
来到mirai根目录输入命令,
mv KFCFactory.json KFCFactory.json.bak nano KFCFactory.json将刚才复制的文本在这里粘贴并和之前一样进行保存,注意删除结尾的逗号。
1dbe92c1-5620-4958-bd83-ce7caa2a9824-image.png
使用命令重新启动mirai。
启动完成无报错后,则协议库配置完毕。
./mcl -u
请注意,下面的过程可能需要一些手速,过慢的验证您可能需要反复进行下面的步骤,过多的重试可能会增加账号冻结的风险性,请注意。
若在本阶段登录时出现了一些意料之外的错误和问题,请使用标头提到的1.13.1版本fix-protocol-version代替原本的1.13.0版本
登陆qq。
login botqq号 bot密码 ANDROID_PAD若之前的配置全部没有问题,在mirai启动后登陆账号密码会提示注册成功。
2024-07-04 16:23:04 I/UnidbgFetchQsign: Bot(1145141919) register, 注册成功了您嘞!之后可以在屏幕中找到下列类似地址,此时,需要尽可能快的将这串地址https://ti.qq.com/.... 复制到刚才开的模拟器中的框框中,并单击下一步.
[SliderCaptcha] Captcha link:https://ti.qq.com/safe/tools/captcha/sms-verify-login....b21712e8-98b2-4052-adfe-f01a297bf934-image.png
在经过简单的图形验证后,会弹出ticket,立即复制该ticket
791ef35f-4ae8-485a-8eed-fdb7606143f3-image.png
回到ssh,在ticket栏进行粘贴,并回车,如果一切顺利,你会看到下面图片中的显示,即确认发送手机验证码。
5a1d847f-53de-4377-a429-0ebb7531ea14-image.png
输入yes后回车,将手机上收到的验证码填入对应栏目后回车,登陆完成。
注意本阶段有一次发送短信前的确认步骤,手动输入yes,不要在上面步骤就开始傻等短信。
8317823b-7291-46cd-929c-d15d68a02c1c-image.png
mirai测试登陆过程全部结束。
为bot添加自动登录,让mirai每次启动后自动登录。
退出mirai,下面的步骤必须在退出mirai之后才能进行,下列命令的实际路径以你的本地mirai的为准。
nano /root/mirai/config/Console/AutoLogin.yml由于miria在退出时会回写配置,故所有的配置需在mirai关闭时进行。
在编辑器中添加你的bot信息,注意箭头这里必须修改为刚才导入的ANDROID_PAD,不能使用默认的ANDROID_PHONE.
6a5da3c1-f4ee-42dd-af98-55cdebd6359d-image.png
保存退出。
重新启动mirai,发现mirai自动登录完成。
3ae9b7a4-eccb-4d9e-b4c4-65ae3b561104-image.png
本项目不是必须安装的,只作为安装演示。
有些插件支持使用mcl进行安装,有些只能手动下载jar包上传plugins目录安装。
推荐安装Chat Command,luckperms - Mirai,前者为命令插件,后者为权限管理插件。
在mirai根目录执行此命令后,下次启动后会自动安装下载。
完成后./mcl -u,启动等待完成即可。
配置启动本文提供两种后台运行mirai的方式。
screen
screen为多重视窗管理程序
https://www.runoob.com/linux/linux-comm-screen.html
输入命令,创建mirai窗口
screen -S mirai在这个窗口中启动mirai.
使用这种方式方便随时管理和查看,以及sj(视奸)群友行为。
systemctl
systemctl是 Systemd 的主命令,用于管理系统。
https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
创建启动服务。
nano /etc/systemd/system/mirai.service将下面的内容写入文件保存,注意对需要的部分进行修改。
如ExecStart,WorkingDirectory的变量。
重载systemctl。
systemctl daemon-reload将bot启动设置为开机自启。
systemctl enable mirai.service启动mirai。
systemctl start mirai.service检查mirai状态。
systemctl status mirai.servicef33b4fbf-71bb-4054-bee1-0d8df7f07d4d-image.png
HomeLab相关推荐本章节为彩蛋部分,只为想在自家运行bot的选手提供一些参考。
mirai运行需要的性能很低,当然这个也和你安装的插件数量以及插件的代码效率相关。
所以如果你想在家里配置一台设备运行mirai,配置自然是越低越好,功耗自然是越低越好,最理想的方式是插个网线放窗台,使用免费的核聚变供电。
推荐硬件配置:
推荐使用纯ECC / Regecc(如果支持,大部分家用设备不支持后者,d5平台消费级主板只能使用消费级内存条)。
电源必须使用一线或准一线品质对于设备本身的稳定性至关重要。
推荐软件配置:
proxmox作为母鸡系统启动虚拟化。
目前测试该系统可以在消费级硬件无故障的情况下实现高负载400d+的使用,下图升级过版本,进行了一次停机,实际在线时间已经将近500d。
349f7c65-f4f0-49b3-811e-18833bbb54b9-image.png
2024.7.14 修复链接引用错误,添加其他更新版本的可用插件。
2024.7.26 补充了新版本fpv需要跳过的步骤。
好耶!
猛猛安装插件。
4090ed62-911b-4f6d-b9d2-a7553b13d8aa-image.png
debc154f-a95a-4239-9bc4-e769cc8e10fb-debbafd9be5fa72cce744811a38bbb18.png
07:37:00 [ERROR] Failed to fetch announcement for "org.bouncycastle:bcprov-jdk15on"
07:37:00 [ERROR] Failed to fetch MCL announcement.
07:37:00 [INFO] Verifying "net.mamoe:mirai-console" v2.14.0
07:37:03 [INFO] Verifying "org.bouncycastle:bcprov-jdk15on"
07:37:03 [ERROR] Failed to verify package "org.bouncycastle:bcprov-jdk15on"
07:37:03 [ERROR] javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:578)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123)
at org.itxtech.mcl.component.Repository.httpGet(Repository.java:211)
at org.itxtech.mcl.component.Repository.httpGet(Repository.java:206)
at org.itxtech.mcl.component.Repository.fetchPackage(Repository.java:84)
at org.itxtech.mcl.module.builtin.RepoCache$RepoWithCache.fetchPackage(RepoCache.java:88)
at org.itxtech.mcl.module.builtin.Updater.check(Updater.java:101)
at org.itxtech.mcl.module.builtin.Updater.load(Updater.java:60)
at org.itxtech.mcl.module.ModuleManager.phaseLoad(ModuleManager.java:117)
at org.itxtech.mcl.Loader.lambda$start$3(Loader.java:190)
at org.itxtech.mcl.Loader.tryCatching(Loader.java:151)
at org.itxtech.mcl.Loader.start(Loader.java:190)
适用于只使用overflow-core开发bot,并且使用spring自带的IoC能力的一套ws解决方案。可以避免早期overflow版本中反向websocket存在的各种问题。
定义handler class WSHandler : WebSocketHandler, IAdapter { override val scope = CoroutineScope(Dispatchers.IO) + SupervisorJob() override val logger: Logger = LoggerFactory.getLogger(ActionHandler::class.java) override val actionHandler: ActionHandler = ActionHandler(scope.coroutineContext[Job], logger) init { top.mrxiaom.overflow.internal.Overflow.setup() log.info("Youmu WebSocket 已接管默认Overflow Bot Handler,WSBufferSize: ${System.getProperty("org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE")}") } override fun afterConnectionEstablished(session: WebSocketSession) { //在这里进行鉴权 scope.launch { val botImpl = Bot( SpringDelegatedWebSocket(session), BotConfig(), actionHandler ) val versionInfo = botImpl.getVersionInfo() if (botImpl.onebotVersion == 12) { session.close(CloseStatus.PROTOCOL_ERROR.withReason("不支持的onebot版本:12")) return@launch } net.mamoe.mirai.Bot.getInstanceOrNull(botImpl.id)?.getOriginChannel() ?.close(CloseStatus.NORMAL.withReason("当前连接下线")) val bot = with(BotWrapper) { val result = runCatching { botImpl.wrap( configuration = BotConfiguration { botLoggerSupplier = { LoggerFactory.getLogger("Bot#${botImpl.id}").asMiraiLogger() } networkLoggerSupplier = { LoggerFactory.getLogger("Net#${botImpl.id}").asMiraiLogger() } } ) } if (result.isFailure) { session.close(CloseStatus.PROTOCOL_ERROR.withReason("无法实例化bot")) return@launch } result.getOrThrow() } log.info("Bot ${bot.id} 已连接,协议版本信息:$versionInfo") net.mamoe.mirai.Bot._instances[botImpl.id] = bot } } override fun handleMessage(session: WebSocketSession, message: WebSocketMessage<*>) { if (message is TextMessage) { val text = message.payload onReceiveMessage(text) } } override fun handleTransportError(session: WebSocketSession, exception: Throwable) { } @OptIn(MiraiInternalApi::class) override fun afterConnectionClosed(session: WebSocketSession, closeStatus: CloseStatus) { val bot = net.mamoe.mirai.Bot.instances.find { it.getOriginChannel() == session } if (bot !== null) { bot as BotWrapper bot.eventDispatcher.broadcastAsync(BotOfflineEvent.Dropped(bot, cause = RuntimeException("连接断开"))) net.mamoe.mirai.Bot._instances.remove(bot.id) log.info("${bot.id}断开连接") } } override fun supportsPartialMessages(): Boolean = false } 定义ws session的wrapper。overflow中未使用的方法均可以使用TODO替代。 class SpringDelegatedWebSocket(val delegated: WebSocketSession) : WebSocket { override fun close(p0: Int, p1: String?) { delegated.close(CloseStatus(p0, p1)) } override fun close(p0: Int) { delegated.close(CloseStatus(p0)) } override fun close() { delegated.close() } override fun closeConnection(p0: Int, p1: String?) { delegated.close(CloseStatus(p0, p1)) } override fun send(p0: String?) { delegated.sendMessage(TextMessage(p0!!)) } override fun send(p0: ByteBuffer?) { delegated.sendMessage(BinaryMessage(p0!!)) } override fun send(p0: ByteArray?) { delegated.sendMessage(BinaryMessage(p0!!)) } override fun sendFrame(p0: Framedata?) { TODO("Not yet implemented") } override fun sendFrame(p0: MutableCollection<Framedata>?) { TODO("Not yet implemented") } override fun sendPing() { delegated.sendMessage(PingMessage()) } override fun sendFragmentedFrame(p0: Opcode?, p1: ByteBuffer?, p2: Boolean) { TODO("Not yet implemented") } override fun hasBufferedData(): Boolean { TODO("Not yet implemented") } override fun getRemoteSocketAddress(): InetSocketAddress = delegated.remoteAddress!! override fun getLocalSocketAddress(): InetSocketAddress = delegated.localAddress!! override fun isOpen(): Boolean = delegated.isOpen override fun isClosing(): Boolean = !isOpen override fun isFlushAndClose(): Boolean { TODO("Not yet implemented") } override fun isClosed(): Boolean = !isOpen override fun getDraft(): Draft { TODO("Not yet implemented") } override fun getReadyState(): ReadyState { TODO("Not yet implemented") } override fun getResourceDescriptor(): String { TODO("Not yet implemented") } override fun <T : Any?> setAttachment(p0: T) { TODO("Not yet implemented") } override fun <T : Any?> getAttachment(): T { TODO("Not yet implemented") } override fun hasSSLSupport(): Boolean { TODO("Not yet implemented") } override fun getSSLSession(): SSLSession { TODO("Not yet implemented") } override fun getProtocol(): IProtocol { TODO("Not yet implemented") } } 最后自行注册即可 @Configuration @EnableWebSocket class WSConfig:WebSocketConfigurer { override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) { registry.addHandler( WSHandler(), "bot" ) } } 补一个上文中出现的工具类 @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") package top.kagg886.youmu.backend.socket import net.mamoe.mirai.Bot import org.springframework.web.socket.WebSocketSession import top.kagg886.youmu.bot.internal.spring.SpringDelegatedWebSocket import top.mrxiaom.overflow.internal.contact.BotWrapper import kotlin.reflect.KProperty1 import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.isAccessible fun Bot.getOriginChannel(): WebSocketSession { val prop = BotWrapper::class.memberProperties.first { it.name == "implBot" } as KProperty1<BotWrapper, cn.evolvefield.onebot.client.core.Bot> prop.isAccessible = true val wrapper = prop.get(this as BotWrapper).channel return (wrapper as SpringDelegatedWebSocket).delegated }最后附赠一套使用此方案部署在公网上的反向websocket bot:
wss://youmu.kagg886.top/bot
接入教程见此:部署bot
一个娱乐插件
被草和草人的都沉默了
指令可单独配置
可调整超人时间未到语句上传的图片
需要在
data/com.purewhite.entertainment/No
data/com.purewhite.entertainment/Yes
下塞入图片
插件启动后该文件夹会创建 直接塞入图片即可无需重启
众所周知,kaggle每周有30h的免费gpu时长,可以用来部署ai绘画服务让罗伯特调用,当你有7个账号的时候就可以无限续杯。
Achernar的作用
1.自动运行kaggle脚本,在运行一定时长后,自动切换账号并重新运行脚本,实现无限续杯。(kaggle脚本单次启动最多持续运行12h) 2.自动从cpolar获取最新的隧道url,同时将所有对本地3529端口的请求转发到隧道url。(用frp就用不到这个了) 项目地址 部署 安装python记住第一步勾选add to path就行了,剩下全默认。
安装依赖运行一键部署脚本.bat
使用见教程。
效果展示:
2.png 1.png
下载地址:
https://github.com/BigCherryBalls/MsgRankCard/tree/mirai_plugin
仓库地址
Bot is Watching you.👁️
若APIKey与欲查询的用户为同一个账号时,设置游戏私密功能将无效 新成就大约4分钟后才能被Bot发现 修改刷新间隔配置后需要重载插件依赖文件 libHarfBuzzSharp.dll libSkiaSharp.dll 放置在框架/加载器的 根目录 或者 x86 文件夹 或者 libraies 文件夹 Assets.zip 解压后放置在插件的数据目录内,保留 Assets 文件夹
5dfe2e77-1fe4-469c-91b2-ac26d0b8a6ac-image.png
7f17bccd-8625-48d2-841a-9c2fa50a14fc-image.png