diff --git a/UpdateLog.md b/UpdateLog.md index f699d6600..93e86600b 100644 --- a/UpdateLog.md +++ b/UpdateLog.md @@ -2,5 +2,7 @@ ## Main version 0 -### 0.3.0 -- 更新 \ No newline at end of file +### 0.6.0 +- 新增: 禁言群成员 +- 新增: 解禁群成员 +- 修复: ContactList key 无法匹配 \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3807824bb..d89790093 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.5.1 +mirai_version=0.6.0 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true # kotlin diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index 87ccf2b38..ea9ab3ae3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -59,7 +59,7 @@ inline fun Contact.withSession(block: BotSession.() -> R): R { /** * 只读联系人列表 */ -class ContactList @PublishedApi internal constructor(internal val delegate: MutableContactList) : Map by delegate { +class ContactList @PublishedApi internal constructor(internal val delegate: MutableContactList) : Map { /** * ID 列表的字符串表示. * 如: @@ -70,12 +70,41 @@ class ContactList @PublishedApi internal constructor(internal val d val idContentString: String get() = this.keys.joinToString(prefix = "[", postfix = "]") { it.toLong().toString() } override fun toString(): String = delegate.toString() + + + // TODO: 2019/12/2 应该使用属性代理, 但属性代理会导致 UInt 内联错误. 等待 kotlin 修复后替换 + + override val size: Int get() = delegate.size + override fun containsKey(key: UInt): Boolean = delegate.containsKey(key) + override fun containsValue(value: C): Boolean = delegate.containsValue(value) + override fun get(key: UInt): C? = delegate[key] + override fun isEmpty(): Boolean = delegate.isEmpty() + override val entries: MutableSet> get() = delegate.entries + override val keys: MutableSet get() = delegate.keys + override val values: MutableCollection get() = delegate.values } /** * 可修改联系人列表. 只会在内部使用. */ @PublishedApi -internal class MutableContactList : MutableMap by mutableMapOf() { +internal class MutableContactList : MutableMap { override fun toString(): String = asIterable().joinToString(separator = ", ", prefix = "ContactList(", postfix = ")") { it.value.toString() } + + + // TODO: 2019/12/2 应该使用属性代理, 但属性代理会导致 UInt 内联错误. 等待 kotlin 修复后替换 + private val delegate = mutableMapOf() + + override val size: Int get() = delegate.size + override fun containsKey(key: UInt): Boolean = delegate.containsKey(key) + override fun containsValue(value: C): Boolean = delegate.containsValue(value) + override fun get(key: UInt): C? = delegate[key] + override fun isEmpty(): Boolean = delegate.isEmpty() + override val entries: MutableSet> get() = delegate.entries + override val keys: MutableSet get() = delegate.keys + override val values: MutableCollection get() = delegate.values + override fun clear() = delegate.clear() + override fun put(key: UInt, value: C): C? = delegate.put(key, value) + override fun putAll(from: Map) = delegate.putAll(from) + override fun remove(key: UInt): C? = delegate.remove(key) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index b115d23bc..73aeed680 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -51,7 +51,7 @@ interface Group : Contact, Iterable { /** * 获取群成员. 若此 ID 的成员不存在, 则会抛出 [kotlin.NoSuchElementException] */ - suspend fun getMember(id: UInt): Member + fun getMember(id: UInt): Member /** * 更新群资料. 群资料会与服务器事件同步事件更新, 一般情况下不需要手动更新. diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index 74ce14bf3..d725fb31a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -1,9 +1,14 @@ +@file:Suppress("unused") + package net.mamoe.mirai.contact +import com.soywiz.klock.MonthSpan +import com.soywiz.klock.TimeSpan +import kotlin.time.Duration +import kotlin.time.ExperimentalTime + /** * 群成员. - * - * 使用 [QQ.equals]. 因此同 ID 的群成员和 QQ 是 `==` 的 */ interface Member : QQ, Contact { /** @@ -15,8 +20,45 @@ interface Member : QQ, Contact { * 权限 */ val permission: MemberPermission + + /** + * 禁言 + * + * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常. + * @return 若机器人无权限禁言这个群成员, 返回 `false` + */ + suspend fun mute(durationSeconds: Int): Boolean + + /** + * 解除禁言 + */ + suspend fun unmute() } +@ExperimentalTime +suspend inline fun Member.mute(duration: Duration) { + require(duration.inDays > 30) { "duration must be at most 1 month" } + require(duration.inSeconds > 0) { "duration must be greater than 0 second" } + this.mute(duration.inSeconds.toInt()) +} + +suspend inline fun Member.mute(duration: TimeSpan) { + require(duration.days > 30) { "duration must be at most 1 month" } + require(duration.microseconds > 0) { "duration must be greater than 0 second" } + this.mute(duration.seconds.toInt()) +} + +suspend inline fun Member.mute(duration: MonthSpan) { + require(duration.totalMonths == 1) { "if you pass a MonthSpan, it must be 1 month" } + this.mute(duration.totalMonths * 30 * 24 * 3600) +} + +@ExperimentalUnsignedTypes +suspend inline fun Member.mute(durationSeconds: UInt) { + require(durationSeconds.toInt() <= 30 * 24 * 3600) { "duration must be at most 1 month" } + this.mute(durationSeconds.toInt()) +} // same bin rep. + /** * 群成员的权限 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/internal/ContactImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/internal/ContactImpl.kt index 6f849518e..839548bb2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/internal/ContactImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/internal/ContactImpl.kt @@ -1,4 +1,4 @@ -@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "MemberVisibilityCanBePrivate") +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_UNSIGNED_LITERALS") package net.mamoe.mirai.contact.internal @@ -19,6 +19,7 @@ import net.mamoe.mirai.network.sessionKey import net.mamoe.mirai.qqAccount import net.mamoe.mirai.sendPacket import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.io.logStacktrace import net.mamoe.mirai.withSession import kotlin.coroutines.CoroutineContext @@ -45,6 +46,7 @@ internal suspend fun Group(bot: Bot, groupId: GroupId, context: CoroutineContext val info: RawGroupInfo = try { bot.withSession { GroupPacket.QueryGroupInfo(qqAccount, groupId.toInternalId(), sessionKey).sendAndExpect() } } catch (e: Exception) { + e.logStacktrace() error("Cannot obtain group info for id ${groupId.value}") } return GroupImpl(bot, groupId, context).apply { this.info = info.parseBy(this) } @@ -62,9 +64,9 @@ internal data class GroupImpl internal constructor(override val bot: Bot, val gr override val announcement: String get() = info.announcement override val members: ContactList get() = info.members - override suspend fun getMember(id: UInt): Member = + override fun getMember(id: UInt): Member = if (members.containsKey(id)) members[id]!! - else throw NoSuchElementException("No such member whose id is $id in group ${groupId.value.toLong()}") + else throw NoSuchElementException("No such member whose id is ${id.toLong()} in group ${groupId.value.toLong()}") override suspend fun sendMessage(message: MessageChain) { bot.sendPacket(GroupPacket.Message(bot.qqAccount, internalId, bot.sessionKey, message)) @@ -124,5 +126,25 @@ internal data class QQImpl internal constructor(override val bot: Bot, override */ @PublishedApi internal data class MemberImpl(private val delegate: QQ, override val group: Group, override val permission: MemberPermission) : QQ by delegate, Member { - override fun toString(): String = "Member(id=${this.id}, permission=$permission)" + override fun toString(): String = "Member(id=${this.id}, group=${group.id}, permission=$permission)" + + override suspend fun mute(durationSeconds: Int): Boolean = bot.withSession { + require(durationSeconds > 0) { "duration must be greater than 0 second" } + + if (permission == MemberPermission.OWNER) return false + + when (group.getMember(bot.qqAccount).permission) { + MemberPermission.MEMBER -> return false + MemberPermission.OPERATOR -> if (permission == MemberPermission.OPERATOR) return false + MemberPermission.OWNER -> { + } + } + + GroupPacket.Mute(qqAccount, group.internalId, sessionKey, id, durationSeconds.toUInt()).sendAndExpect() + return true + } + + override suspend fun unmute(): Unit = bot.withSession { + GroupPacket.Mute(qqAccount, group.internalId, sessionKey, id, 0u).sendAndExpect() + } } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt index c906c75a4..d1a56ce77 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt @@ -9,6 +9,7 @@ import net.mamoe.mirai.event.ListeningStatus import net.mamoe.mirai.event.Subscribable import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.utils.internal.inlinedRemoveIf +import net.mamoe.mirai.utils.io.logStacktrace import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext import kotlin.jvm.JvmField @@ -98,7 +99,8 @@ internal class Handler return try { withContext(context) { handler.invoke(event) }.also { if (it == ListeningStatus.STOPPED) this.complete() } } catch (e: Throwable) { - this.completeExceptionally(e) + e.logStacktrace() + //this.completeExceptionally(e) ListeningStatus.STOPPED } } @@ -131,7 +133,8 @@ internal class HandlerWithBot @PublishedApi internal construct return try { withContext(context) { bot.handler(event) }.also { if (it == ListeningStatus.STOPPED) complete() } } catch (e: Throwable) { - completeExceptionally(e) + e.logStacktrace() + //completeExceptionally(e) ListeningStatus.STOPPED } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/GroupPacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/GroupPacket.kt index 4765bf5f9..ca9b0f2f9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/GroupPacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/GroupPacket.kt @@ -50,7 +50,8 @@ data class RawGroupInfo( MemberImpl(this@RawGroupInfo.owner.qq(), group, MemberPermission.OWNER), this@RawGroupInfo.name, this@RawGroupInfo.announcement, - ContactList(this@RawGroupInfo.members.mapValuesTo(MutableContactList()) { MemberImpl(it.key.qq(), group, MemberPermission.OWNER) }) + ContactList(this@RawGroupInfo.members.mapValuesTo(MutableContactList()) { MemberImpl(it.key.qq(), group, it.value) } + .apply { put(owner, MemberImpl(owner.qq(), group, MemberPermission.OWNER)) }) ) } } @@ -119,6 +120,29 @@ object GroupPacket : SessionPacketFactory() { writeZero(4) } + /** + * 禁言群成员 + */ + @PacketVersion(date = "2019.12.2", timVersion = "2.3.2 (21173)") + fun Mute( + bot: UInt, + groupInternalId: GroupInternalId, + sessionKey: SessionKey, + target: UInt, + /** + * 0 为取消 + */ + timeSeconds: UInt + ): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "MuteMember") { + writeUByte(0x7Eu) + writeGroup(groupInternalId) + writeByte(0x20) + writeByte(0x00) + writeByte(0x01) + writeQQ(target) + writeUInt(timeSeconds) + } + interface GroupPacketResponse : Packet @NoLog @@ -126,11 +150,17 @@ object GroupPacket : SessionPacketFactory() { override fun toString(): String = "GroupPacket.MessageResponse" } + @NoLog + object MuteResponse : Packet, GroupPacketResponse { + override fun toString(): String = "GroupPacket.MuteResponse" + } + @PacketVersion(date = "2019.11.27", timVersion = "2.3.2 (21173)") @UseExperimental(ExperimentalStdlibApi::class) - override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupPacketResponse = handler.bot.withSession { + override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupPacketResponse { return when (readUByte().toUInt()) { 0x2Au -> MessageResponse + 0x7Eu -> MuteResponse // 成功: 7E 00 22 96 29 7B; 0x09u -> { if (readByte().toInt() == 0) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/EventPacketFactory.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/EventPacketFactory.kt index be59baf1a..492708f50 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/EventPacketFactory.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/EventPacketFactory.kt @@ -97,6 +97,7 @@ abstract class KnownEventParserAndHandler(override val id: USh FriendAddRequestEventPacket, MemberGoneEventPacketHandler, ConnectionOccupiedPacketHandler, - MemberJoinPacketHandler + MemberJoinPacketHandler, + MemberMuteEventPacketParserAndHandler ) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MemberMute.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MemberMute.kt new file mode 100644 index 000000000..0b3f03fbf --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MemberMute.kt @@ -0,0 +1,136 @@ +@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE") + +package net.mamoe.mirai.network.protocol.tim.packet.event + +import com.soywiz.klock.TimeSpan +import com.soywiz.klock.seconds +import com.soywiz.klock.toTimeString +import kotlinx.io.core.ByteReadPacket +import kotlinx.io.core.discardExact +import kotlinx.io.core.readUInt +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.getGroup +import net.mamoe.mirai.qqAccount + +// region mute +/** + * 某群成员被禁言事件 + */ +@Suppress("unused") +class MemberMuteEvent( + val member: Member, + override val duration: TimeSpan, + override val operator: Member +) : MuteEvent() { + override val group: Group get() = operator.group + override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${duration.toTimeString()}" +} + +/** + * 机器人被禁言事件 + */ +class BeingMutedEvent( + override val duration: TimeSpan, + override val operator: Member +) : MuteEvent() { + override val group: Group get() = operator.group + override fun toString(): String = "BeingMutedEvent(group=${group.id}, operator=${operator.id}, duration=${duration.toTimeString()}" +} + +sealed class MuteEvent : EventOfMute() { + abstract override val operator: Member + abstract override val group: Group + abstract val duration: TimeSpan +} +// endregion + +// region unmute +/** + * 某群成员被解除禁言事件 + */ +@Suppress("unused") +class MemberUnmuteEvent( + val member: Member, + override val operator: Member +) : UnmuteEvent() { + override val group: Group get() = operator.group + override fun toString(): String = "MemberUnmuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}" +} + +/** + * 机器人被解除禁言事件 + */ +class BeingUnmutedEvent( + override val operator: Member +) : UnmuteEvent() { + override val group: Group get() = operator.group + override fun toString(): String = "BeingUnmutedEvent(group=${group.id}, operator=${operator.id}" +} + +sealed class UnmuteEvent : EventOfMute() { + abstract override val operator: Member + abstract override val group: Group +} + +// endregion + +sealed class EventOfMute : EventPacket { + abstract val operator: Member + abstract val group: Group +} + +internal object MemberMuteEventPacketParserAndHandler : KnownEventParserAndHandler(0x02DCu) { + override suspend fun ByteReadPacket.parse(bot: Bot, identity: EventPacketIdentity): EventOfMute { + //取消 + //00 00 00 11 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 + // 01 01 + // 22 96 29 7B + // 0C 01 + // 3E 03 3F A2 + // 5D E5 12 EB + // 00 01 + // 76 E4 B8 DD + // 00 00 00 00 + + // 禁言 + //00 00 00 11 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 + // 01 + // 01 + // 22 96 29 7B + // 0C + // 01 + // 3E 03 3F A2 + // 5D E5 07 85 + // 00 + // 01 + // 76 E4 B8 DD + // 00 27 8D 00 + discardExact(19) + discardExact(2) + val group = bot.getGroup(readUInt()) + discardExact(2) + val operator = group.getMember(readUInt()) + discardExact(4) //time + discardExact(2) + val memberQQ = readUInt() + + val durationSeconds = readUInt().toInt() + return if (durationSeconds == 0) { + if (memberQQ == bot.qqAccount) { + BeingUnmutedEvent(operator) + } else { + MemberUnmuteEvent(group.getMember(memberQQ), operator) + } + } else { + val duration = durationSeconds.seconds + + if (memberQQ == bot.qqAccount) { + BeingMutedEvent(duration, operator) + } else { + MemberMuteEvent(group.getMember(memberQQ), duration, operator) + } + } + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/Message.kt index b0c273625..328f2bed7 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/Message.kt @@ -7,10 +7,7 @@ import kotlinx.io.core.String import kotlinx.io.core.discardExact import kotlinx.io.core.readUInt import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.BroadcastControllable import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.getGroup @@ -98,6 +95,7 @@ abstract class MessagePacketBase : EventPacket, BotEvent() { // region group message +@Suppress("unused") data class GroupMessage( val group: Group, val senderName: String, @@ -110,6 +108,11 @@ data class GroupMessage( ) : MessagePacket() { override val subject: Group get() = group + + + suspend inline fun At.member(): Member = group.getMember(this.target) + suspend inline fun UInt.member(): Member = group.getMember(this) + suspend inline fun Long.member(): Member = group.getMember(this.toUInt()) } @PacketVersion(date = "2019.11.2", timVersion = "2.3.2 (21173)") diff --git a/mirai-debug/src/main/kotlin/HexDebuggerGui.kt b/mirai-debug/src/main/kotlin/HexDebuggerGui.kt index 7b3df1271..973abc8eb 100644 --- a/mirai-debug/src/main/kotlin/HexDebuggerGui.kt +++ b/mirai-debug/src/main/kotlin/HexDebuggerGui.kt @@ -22,7 +22,7 @@ import java.awt.datatransfer.DataFlavor /** * How to run: * - * `gradle run` + * `gradle :mirai-debug:run` */ class Application : App(HexDebuggerGui::class, Styles::class) @@ -179,7 +179,7 @@ class HexDebuggerGui : View("s") { override val root = hbox { //prefWidth = 735.0 - minHeight = 240.0 + minHeight = 300.0 prefHeight = minHeight input = textarea { diff --git a/mirai-debug/src/main/kotlin/PacketDebuger.kt b/mirai-debug/src/main/kotlin/PacketDebuger.kt index e90db4fe5..97756a2af 100644 --- a/mirai-debug/src/main/kotlin/PacketDebuger.kt +++ b/mirai-debug/src/main/kotlin/PacketDebuger.kt @@ -116,8 +116,8 @@ object PacketDebugger { * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]` * 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey` */ - val sessionKey: SessionKey = SessionKey("F7 3C 31 B5 E1 F1 E5 6A FA F7 95 79 AE 19 30 01".hexToBytes()) - const val qq: UInt = 761025446u + val sessionKey: SessionKey = SessionKey("06 23 F8 09 0D 2D 37 BE 2E FE 90 3A 7D E5 8F B1".hexToBytes()) + const val qq: UInt = 1040400290u val IgnoredPacketIdList: List = listOf( KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE, @@ -152,7 +152,9 @@ object PacketDebugger { decodedBody = it.readBytes() ByteReadPacket(decodedBody) } - .decode(id, sequenceId, DebugNetworkHandler) + .runCatching { + decode(id, sequenceId, DebugNetworkHandler) + }.getOrElse { it.printStackTrace(); null } } } diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt index 985ad24a2..060f12c83 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt @@ -2,6 +2,8 @@ package demo.gentleman +import com.soywiz.klock.months +import com.soywiz.klock.seconds import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay @@ -9,8 +11,10 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import net.mamoe.mirai.* import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.contact.mute import net.mamoe.mirai.event.Subscribable import net.mamoe.mirai.event.subscribeAlways +import net.mamoe.mirai.event.subscribeGroupMessages import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.message.At import net.mamoe.mirai.message.Image @@ -59,17 +63,32 @@ suspend fun main() { it.approve() } + bot.subscribeGroupMessages { + "群资料" reply { + group.updateGroupInfo().toString().reply() + } + + startsWith("mt2months") { + val at: At by message + at.target.member().mute(1.months) + } + + startsWith("mute") { + val at: At by message + at.target.member().mute(30.seconds) + } + + startsWith("unmute") { + val at: At by message + at.target.member().unmute() + } + } + bot.subscribeMessages { case("at me") { At(sender).reply() } "你好" reply "你好!" - "群资料" reply { - if (this is GroupMessage) { - group.updateGroupInfo().toString().reply() - } - } - startsWith("profile", removePrefix = true) { val account = it.trim() if (account.isNotEmpty()) {