From 71b338384e2dce2fc9712b63d7eb2dd6ca6460de Mon Sep 17 00:00:00 2001
From: LaoLittle <93422095+LaoLittle@users.noreply.github.com>
Date: Mon, 31 Jan 2022 16:34:35 +0800
Subject: [PATCH] feat: enhancement (#13)
- add commenting drift bottle feature
- add a composite command for querying and deleting items in the sea
- add an option for disabling certain message types
- add a reply when commands invocation is throttled
Signed-off-by: Samarium <28302241+Samarium150@users.noreply.github.com>
Co-authored-by: Samarium <28302241+Samarium150@users.noreply.github.com>
---
build.gradle.kts | 4 +-
.../driftbottle/MiraiConsoleDriftBottle.kt | 37 +++++---
.../plugin/driftbottle/command/Comment.kt | 75 +++++++++++++++
.../plugin/driftbottle/command/JumpInto.kt | 19 ++--
.../plugin/driftbottle/command/Pickup.kt | 55 ++++++-----
.../driftbottle/command/SeaOperation.kt | 78 +++++++++++++++
.../plugin/driftbottle/command/ThrowAway.kt | 43 +++++----
.../driftbottle/config/AdvancedConfig.kt | 63 +++++++++++-
.../driftbottle/config/CommandConfig.kt | 15 ++-
.../driftbottle/config/GeneralConfig.kt | 7 +-
.../plugin/driftbottle/config/ReplyConfig.kt | 15 ++-
.../plugin/driftbottle/data/CommentData.kt | 66 +++++++++++++
.../mirai/plugin/driftbottle/data/Item.kt | 90 ++++++++++--------
.../plugin/driftbottle/util/ContentCensor.kt | 8 +-
.../util/CustomForwardMsgDisplay.kt | 40 ++++++++
.../mirai/plugin/driftbottle/util/General.kt | 95 ++++++++++++++++++-
.../mirai/plugin/driftbottle/util/Throttle.kt | 16 ++++
17 files changed, 598 insertions(+), 128 deletions(-)
create mode 100644 src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Comment.kt
create mode 100644 src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/SeaOperation.kt
create mode 100644 src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/CommentData.kt
create mode 100644 src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/CustomForwardMsgDisplay.kt
diff --git a/build.gradle.kts b/build.gradle.kts
index bf66cff..beae4ab 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -10,11 +10,11 @@ plugins {
}
group = "io.github.samarium150"
-version = "1.5.0"
+version = "1.6.0"
repositories {
mavenLocal()
- maven("https://maven.aliyun.com/repository/public")
+ maven("https://maven.aliyun.com/repository/central")
mavenCentral()
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/MiraiConsoleDriftBottle.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/MiraiConsoleDriftBottle.kt
index 177d744..1a014af 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/MiraiConsoleDriftBottle.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/MiraiConsoleDriftBottle.kt
@@ -16,15 +16,12 @@
*/
package io.github.samarium150.mirai.plugin.driftbottle
-import io.github.samarium150.mirai.plugin.driftbottle.command.JumpInto
-import io.github.samarium150.mirai.plugin.driftbottle.command.Pickup
-import io.github.samarium150.mirai.plugin.driftbottle.command.ThrowAway
-import io.github.samarium150.mirai.plugin.driftbottle.config.CommandConfig
-import io.github.samarium150.mirai.plugin.driftbottle.config.ContentCensorConfig
-import io.github.samarium150.mirai.plugin.driftbottle.config.GeneralConfig
-import io.github.samarium150.mirai.plugin.driftbottle.config.ReplyConfig
+import io.github.samarium150.mirai.plugin.driftbottle.command.*
+import io.github.samarium150.mirai.plugin.driftbottle.config.*
+import io.github.samarium150.mirai.plugin.driftbottle.data.CommentData
import io.github.samarium150.mirai.plugin.driftbottle.data.ContentCensorToken
import io.github.samarium150.mirai.plugin.driftbottle.data.Sea
+import io.github.samarium150.mirai.plugin.driftbottle.util.alsoSave
import io.ktor.client.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
@@ -37,7 +34,7 @@ object MiraiConsoleDriftBottle : KotlinPlugin(
JvmPluginDescription(
id = "io.github.samarium150.mirai.plugin.mirai-console-drift-bottle",
name = "Drift Bottle",
- version = "1.5.0",
+ version = "1.6.0",
) {
author("Samarium150")
info("简单的漂流瓶插件")
@@ -46,19 +43,33 @@ object MiraiConsoleDriftBottle : KotlinPlugin(
lateinit var client: HttpClient
- override fun onEnable() {
- // 重载数据
- GeneralConfig.reload()
- ReplyConfig.reload()
- CommandConfig.reload()
+ private fun init() {
+ // 重载只读配置
+ AdvancedConfig.alsoSave()
+ GeneralConfig.alsoSave()
+ ReplyConfig.alsoSave()
+ CommandConfig.alsoSave()
+
+ // 重载配置
ContentCensorConfig.reload()
+
+ // 重载数据
ContentCensorToken.reload()
+ CommentData.reload()
Sea.reload()
// 注册命令
JumpInto.register()
Pickup.register()
ThrowAway.register()
+ SeaOperation.register()
+ if (GeneralConfig.incrementalBottle)
+ Comment.register()
+ }
+
+ override fun onEnable() {
+ // 初始化插件
+ init()
// 初始化 HTTP 客户端
if (GeneralConfig.enableContentCensor)
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Comment.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Comment.kt
new file mode 100644
index 0000000..e8a1a1a
--- /dev/null
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Comment.kt
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+package io.github.samarium150.mirai.plugin.driftbottle.command
+
+import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle
+import io.github.samarium150.mirai.plugin.driftbottle.config.CommandConfig
+import io.github.samarium150.mirai.plugin.driftbottle.data.CommentData
+import io.github.samarium150.mirai.plugin.driftbottle.util.indexOfBottle
+import io.github.samarium150.mirai.plugin.driftbottle.util.isNotOutOfRange
+import io.github.samarium150.mirai.plugin.driftbottle.util.randomDelay
+import net.mamoe.mirai.console.command.CommandSenderOnMessage
+import net.mamoe.mirai.console.command.SimpleCommand
+import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
+import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.contact.nameCardOrNick
+import net.mamoe.mirai.message.data.PlainText
+import net.mamoe.mirai.message.data.SingleMessage
+
+/**
+ * @author LaoLittle
+ */
+object Comment : SimpleCommand(
+ MiraiConsoleDriftBottle,
+ primaryName = "comment",
+ secondaryNames = CommandConfig.comment,
+ description = "评论漂流瓶"
+) {
+ private val comments by CommentData.Companion::comments
+
+ @ExperimentalCommandDescriptors
+ @ConsoleExperimentalApi
+ override val prefixOptional: Boolean = true
+
+ override val usage: String
+ get() = "评论 内容 漂流瓶序号"
+
+ @Suppress("unused")
+ @Handler
+ suspend fun CommandSenderOnMessage<*>.handle(
+ comment: SingleMessage,
+ index: Int? = indexOfBottle[fromEvent.subject.id]?.takeIf { it.isNotEmpty() }?.peek()?.plus(1)
+
+ ) {
+ if (comment !is PlainText) {
+ sendMessage("评论只能包含纯文本!")
+ return
+ }
+ val commentStr = comment.content
+ val realIndex = index?.minus(1)
+ if (isNotOutOfRange(realIndex)) {
+ val nick = fromEvent.sender.nameCardOrNick
+ val id = fromEvent.sender.id
+ comments[realIndex]?.add(CommentData(id, nick, commentStr)) ?: comments.put(
+ realIndex,
+ mutableListOf(CommentData(id, nick, commentStr))
+ )
+ randomDelay()
+ sendMessage("已评论漂流瓶 $index") // 或许可由用户自行配置
+ }
+ }
+}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/JumpInto.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/JumpInto.kt
index 3bac469..9e33409 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/JumpInto.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/JumpInto.kt
@@ -48,10 +48,13 @@ object JumpInto : SimpleCommand(
@Handler
suspend fun CommandSender.handle() {
val sender = user
- if (sender == null) randomDelay().also {
+ if (sender == null)
sendMessage(ReplyConfig.jumpInto.replace("%num", Sea.contents.size.toString()))
- } else {
- if (!lock(sender.id)) return
+ else {
+ if (!lock(sender.id)) {
+ sendMessage(ReplyConfig.inCooldown)
+ return
+ }
val subject = subject
val owner = Owner(
sender.id,
@@ -64,12 +67,12 @@ object JumpInto : SimpleCommand(
) else null
val body = Item(Item.Type.BODY, owner, source)
Sea.contents.add(body)
- randomDelay().also {
- sendMessage(ReplyConfig.jumpInto.replace("%num", Sea.contents.size.toString())).also {
- delay(GeneralConfig.perUse * 1000L)
- unlock(sender.id)
- }
+ runCatching {
+ randomDelay()
+ sendMessage(ReplyConfig.jumpInto.replace("%num", (Sea.contents.size - 1).toString()))
+ delay(GeneralConfig.perUse * 1000L)
}
+ unlock(sender.id)
}
}
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Pickup.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Pickup.kt
index df672c9..370ba27 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Pickup.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/Pickup.kt
@@ -22,15 +22,13 @@ import io.github.samarium150.mirai.plugin.driftbottle.config.GeneralConfig
import io.github.samarium150.mirai.plugin.driftbottle.config.ReplyConfig
import io.github.samarium150.mirai.plugin.driftbottle.data.Item
import io.github.samarium150.mirai.plugin.driftbottle.data.Sea
-import io.github.samarium150.mirai.plugin.driftbottle.util.disableAt
-import io.github.samarium150.mirai.plugin.driftbottle.util.lock
-import io.github.samarium150.mirai.plugin.driftbottle.util.randomDelay
-import io.github.samarium150.mirai.plugin.driftbottle.util.unlock
+import io.github.samarium150.mirai.plugin.driftbottle.util.*
import kotlinx.coroutines.delay
import net.mamoe.mirai.console.command.CommandSenderOnMessage
import net.mamoe.mirai.console.command.SimpleCommand
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.message.data.MessageChain
import java.util.*
object Pickup : SimpleCommand(
@@ -45,28 +43,41 @@ object Pickup : SimpleCommand(
@Suppress("unused")
@Handler
- suspend fun CommandSenderOnMessage<*>.handle() {
- val sender = fromEvent.sender
- val subject = fromEvent.subject
- if (!lock(sender.id)) return
- if (Sea.contents.size == 0) {
- randomDelay().also {
- sendMessage(ReplyConfig.noItem)
+ suspend fun CommandSenderOnMessage<*>.handle(index: Int = Random().nextInt(Sea.contents.size) + 1) {
+ val realIndex = index - 1
+ if (isNotOutOfRange(realIndex)) {
+ val sender = fromEvent.sender
+ val subject = fromEvent.subject
+ if (!lock(sender.id)) {
+ sendMessage(ReplyConfig.inCooldown)
+ return
+ }
+ if (Sea.contents.size == 0) {
+ randomDelay()
unlock(sender.id)
+ sendMessage(ReplyConfig.noItem)
+ return
}
- return
- }
- val index = Random().nextInt(Sea.contents.size)
- val item = Sea.contents[index]
- if ((item.type == Item.Type.BOTTLE && !GeneralConfig.incrementalBottle)
- || (item.type == Item.Type.BODY && !GeneralConfig.incrementalBody)
- )
- Sea.contents.removeAt(index)
- randomDelay().also {
- sendMessage(disableAt(item.toMessageChain(subject), subject)).also {
+ val item = Sea.contents[realIndex]
+ if ((item.type == Item.Type.BOTTLE && !GeneralConfig.incrementalBottle)
+ || (item.type == Item.Type.BODY && !GeneralConfig.incrementalBody)
+ ) {
+ Sea.contents.removeAt(realIndex)
+ rearrangeComments(realIndex)
+ } else {
+ indexOfBottle[subject.id]?.remove(realIndex)
+ indexOfBottle[subject.id]?.push(realIndex) ?: indexOfBottle.put(
+ subject.id,
+ Stack().put(realIndex)
+ )
+ }
+ runCatching {
+ randomDelay()
+ val message = item.toMessage(subject, realIndex)
+ sendMessage(if (message is MessageChain) disableAt(message, subject) else message)
delay(GeneralConfig.perUse * 1000L)
- unlock(sender.id)
}
+ unlock(sender.id)
}
}
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/SeaOperation.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/SeaOperation.kt
new file mode 100644
index 0000000..6cc42e2
--- /dev/null
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/SeaOperation.kt
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+package io.github.samarium150.mirai.plugin.driftbottle.command
+
+import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle
+import io.github.samarium150.mirai.plugin.driftbottle.config.CommandConfig
+import io.github.samarium150.mirai.plugin.driftbottle.data.Sea
+import io.github.samarium150.mirai.plugin.driftbottle.util.*
+import net.mamoe.mirai.console.command.CommandSender
+import net.mamoe.mirai.console.command.CompositeCommand
+
+/**
+ * @author LaoLittle
+ */
+object SeaOperation : CompositeCommand(
+ MiraiConsoleDriftBottle,
+ primaryName = "sea",
+ secondaryNames = CommandConfig.seaOperation,
+ description = "漂流瓶操作复合指令"
+) {
+ @Suppress("unused")
+ @SubCommand("del", "rm")
+ suspend fun CommandSender.remove(
+ index: Int? = subject?.let { sub ->
+ indexOfBottle[sub.id]?.takeIf { it.isNotEmpty() }?.pop()?.plus(1)
+ }
+ ) {
+ val realIndex = index?.minus(1)
+ if (isNotOutOfRange(realIndex)) {
+ val result = runCatching {
+ Sea.contents.removeAt(realIndex)
+ rearrangeComments(realIndex)
+ }.onFailure { e ->
+ if (e !is IndexOutOfBoundsException) MiraiConsoleDriftBottle.logger.error(e)
+ }
+ randomDelay()
+ sendMessage(if (result.isSuccess) "已删除漂流瓶$index" else "删除漂流瓶$index 失败")
+ }
+ }
+
+ @Suppress("unused")
+ @SubCommand("query", "get")
+ suspend fun CommandSender.query(
+ index: Int? = subject?.let { sub ->
+ indexOfBottle[sub.id]?.takeIf { it.isNotEmpty() }?.peek()?.plus(1)
+ }
+ ) {
+ val realIndex = index?.minus(1)
+ if (isNotOutOfRange(realIndex)) {
+ val result = runCatching {
+ val item = Sea.contents[realIndex]
+ """
+ 漂流瓶序号: $index
+ ${item.source?.let { "漂流瓶发送群: ${it.name}(${it.id})" } ?: "此漂流瓶是私聊发送"}
+ 漂流瓶发送人: ${item.owner.name}(${item.owner.id})
+ 漂流瓶发送时间: ${item.timestamp.timestampToString()}
+ """.trimIndent()
+ }.onFailure { e ->
+ if (e !is IndexOutOfBoundsException) MiraiConsoleDriftBottle.logger.error(e)
+ }
+ sendMessage(result.getOrNull() ?: "无法找到漂流瓶$index")
+ }
+ }
+}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/ThrowAway.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/ThrowAway.kt
index 056023b..d8a16d5 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/ThrowAway.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/command/ThrowAway.kt
@@ -52,24 +52,31 @@ object ThrowAway : SimpleCommand(
suspend fun CommandSenderOnMessage<*>.handle(vararg messages: Message = arrayOf()) {
val sender = fromEvent.sender
val subject = fromEvent.subject
- if (!lock(sender.id)) return
+ if (!lock(sender.id)) {
+ sendMessage(ReplyConfig.inCooldown)
+ return
+ }
val chain = if (messages.isNotEmpty()) messageChainOf(*messages)
else {
- randomDelay().also {
- sendMessage(ReplyConfig.waitForNextMessage)
- }
+ randomDelay()
+ sendMessage(ReplyConfig.waitForNextMessage)
runCatching {
fromEvent.nextMessage(30_000)
}.onFailure {
- sendMessage(ReplyConfig.timeoutMessage)
- }.getOrNull() ?: run {
unlock(sender.id)
- return@handle
+ sendMessage(ReplyConfig.timeout)
+ }.getOrNull() ?: return
+ }
+ forbidMessageKeys.forEach {
+ if (chain.contains(it)) {
+ unlock(sender.id)
+ sendMessage(ReplyConfig.bannedMessageType)
+ return
}
}
if (GeneralConfig.enableContentCensor) runCatching {
if (!ContentCensor.determine(chain)) {
- sendMessage(ReplyConfig.invalidMessage)
+ sendMessage(ReplyConfig.invalid)
return
}
}.onFailure {
@@ -94,18 +101,16 @@ object ThrowAway : SimpleCommand(
Sea.contents.add(bottle)
val parts = ReplyConfig.throwAway.split("%content")
runCatching {
- randomDelay().also {
- if (parts.size == 1) sendMessage(parts[0])
- else
- sendMessage(buildMessageChain {
- +PlainText(parts[0])
- +disableAt(chain, subject)
- +PlainText(parts[1])
- })
- }
- }.also {
+ randomDelay()
+ if (parts.size == 1) sendMessage(parts[0])
+ else
+ sendMessage(buildMessageChain {
+ +PlainText(parts[0])
+ +disableAt(chain, subject)
+ +PlainText(parts[1])
+ })
delay(GeneralConfig.perUse * 1000L)
- unlock(sender.id)
}
+ unlock(sender.id)
}
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/AdvancedConfig.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/AdvancedConfig.kt
index 09f499e..3c0a18f 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/AdvancedConfig.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/AdvancedConfig.kt
@@ -1,11 +1,70 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
package io.github.samarium150.mirai.plugin.driftbottle.config
-import net.mamoe.mirai.console.data.AutoSavePluginConfig
+import kotlinx.serialization.Serializable
+import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault
+import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.value
+import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.message.data.MessageContent
+import net.mamoe.mirai.message.data.MessageKey
-object AdvancedConfig : AutoSavePluginConfig("Advanced") {
+object AdvancedConfig : ReadOnlyPluginConfig("Advanced") {
@ValueDescription("At显示为纯文本")
val disableDirectAt by value(false)
+
+ @ConsoleExperimentalApi
+ @ValueDescription(
+ """
+ 漂流瓶消息类型控制
+ 可在此配置以下类型:
+ Image: 图片, LightApp: 小程序, Audio: 语音, FlashImage: 闪照
+ MarketFace: 商城表情, Dice: 骰子, ForwardMessage: 合并转发消息
+ FileMessage: 文件消息 (貌似漂流瓶无法存放文件,但还是先放着)
+ """
+ )
+ val saveMessageTypes by value(MessageType.values().associateWith { true }).withDefault { true }
+
+ @Serializable
+ enum class MessageType {
+ Image,
+ LightApp,
+ Audio,
+ FlashImage,
+ MarketFace,
+ Dice,
+ ForwardMessage,
+ FileMessage,
+ ;
+
+ fun toMessageKey(): MessageKey {
+ return when (this) {
+ Image -> net.mamoe.mirai.message.data.Image
+ LightApp -> net.mamoe.mirai.message.data.LightApp
+ Audio -> net.mamoe.mirai.message.data.Audio
+ FlashImage -> net.mamoe.mirai.message.data.FlashImage
+ MarketFace -> net.mamoe.mirai.message.data.MarketFace
+ Dice -> net.mamoe.mirai.message.data.Dice
+ ForwardMessage -> net.mamoe.mirai.message.data.ForwardMessage
+ FileMessage -> net.mamoe.mirai.message.data.FileMessage
+ }
+ }
+ }
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/CommandConfig.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/CommandConfig.kt
index 50e60ec..ed63b05 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/CommandConfig.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/CommandConfig.kt
@@ -16,19 +16,24 @@
*/
package io.github.samarium150.mirai.plugin.driftbottle.config
-import net.mamoe.mirai.console.data.AutoSavePluginConfig
+import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.value
-object CommandConfig : AutoSavePluginConfig("Command") {
+object CommandConfig : ReadOnlyPluginConfig("Command") {
@ValueDescription("jump-into命令的别名")
- val jumpInto: Array by value(arrayOf("跳海", "跳进海里"))
+ val jumpInto by value(arrayOf("跳海", "跳进海里"))
@ValueDescription("pickup命令的别名")
- val pickup: Array by value(arrayOf("捡漂流瓶"))
+ val pickup by value(arrayOf("捡漂流瓶"))
@ValueDescription("throw-away命令的别名")
- val throwAway: Array by value(arrayOf("丢漂流瓶"))
+ val throwAway by value(arrayOf("丢漂流瓶"))
+ @ValueDescription("comment命令的别名")
+ val comment by value(arrayOf("评论"))
+
+ @ValueDescription("sea-operation命令的别名")
+ val seaOperation by value(arrayOf("海", "s"))
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/GeneralConfig.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/GeneralConfig.kt
index 9c911e9..a7a643a 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/GeneralConfig.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/GeneralConfig.kt
@@ -16,11 +16,11 @@
*/
package io.github.samarium150.mirai.plugin.driftbottle.config
-import net.mamoe.mirai.console.data.AutoSavePluginConfig
+import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.value
-object GeneralConfig : AutoSavePluginConfig("General") {
+object GeneralConfig : ReadOnlyPluginConfig("General") {
@ValueDescription("捡起命令不减少漂流瓶总数")
val incrementalBottle by value(true)
@@ -39,4 +39,7 @@ object GeneralConfig : AutoSavePluginConfig("General") {
@ValueDescription("随机延迟回复的时间区间 (单位: 毫秒)")
val randomDelayInterval: Pair by value(Pair(1000L, 1500L))
+
+ @ValueDescription("使用转发消息展示漂流瓶")
+ val displayInForward by value(false)
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/ReplyConfig.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/ReplyConfig.kt
index dea998e..e350ced 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/ReplyConfig.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/config/ReplyConfig.kt
@@ -16,17 +16,17 @@
*/
package io.github.samarium150.mirai.plugin.driftbottle.config
-import net.mamoe.mirai.console.data.AutoSavePluginConfig
+import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.value
-object ReplyConfig : AutoSavePluginConfig("Reply") {
+object ReplyConfig : ReadOnlyPluginConfig("Reply") {
@ValueDescription("海里没有物品时的回复")
val noItem: String by value("海里暂时没有物品哦~")
@ValueDescription("捡起漂流瓶的回复")
- val pickupBottle: String by value("你在海边捡到了一个来自【%source】的漂流瓶,打开瓶子,里面有一张纸条,写着:\n")
+ val pickupBottle: String by value("序号: %index\n你在海边捡到了一个来自【%source】的漂流瓶,打开瓶子,里面有一张纸条,写着:\n")
@ValueDescription("捡起尸体的回复")
val pickupBody: String by value("海面飘来了【%who】的浮尸……\n他于【%time】")
@@ -53,9 +53,14 @@ object ReplyConfig : AutoSavePluginConfig("Reply") {
val waitForNextMessage: String by value("请把想说的话写在纸条上发送出来吧~")
@ValueDescription("等待漂流瓶内容超时的回复")
- val timeoutMessage: String by value("是不是没有还没有想到要写什么呢?那待会再找我也行哦")
+ val timeout: String by value("是不是没有还没有想到要写什么呢?那待会再找我也行哦")
@ValueDescription("漂流瓶内容不合规的回复")
- val invalidMessage: String by value("不要往瓶子里塞奇怪的东西哦~")
+ val invalid: String by value("不要往瓶子里塞奇怪的东西哦~")
+ @ValueDescription("漂流瓶使用速度过快的回复")
+ val inCooldown: String by value("好快啊,能不能慢一点")
+
+ @ValueDescription("漂流瓶消息类型被禁用的回复")
+ val bannedMessageType: String by value("不要往瓶子里塞这种类型的消息哦~")
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/CommentData.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/CommentData.kt
new file mode 100644
index 0000000..7c730d3
--- /dev/null
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/CommentData.kt
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+package io.github.samarium150.mirai.plugin.driftbottle.data
+
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.serialization.Serializable
+import net.mamoe.mirai.console.data.AutoSavePluginData
+import net.mamoe.mirai.console.data.value
+import java.util.*
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+
+/**
+ * @author LaoLittle
+ */
+@Serializable
+data class CommentData(
+ val senderId: Long,
+ val senderName: String,
+ val content: String,
+) {
+ @Suppress("unused")
+ val timestamp: Long = Date().time
+
+ companion object : AutoSavePluginData("Comment") {
+ val comments by value(mutableMapOf>())
+ }
+}
+
+private val mutex = Mutex()
+
+var isLocked = false
+ private set
+
+@OptIn(ExperimentalContracts::class)
+suspend fun useLock(owner: Any? = null, action: () -> T): T {
+ contract {
+ callsInPlace(action, InvocationKind.EXACTLY_ONCE)
+ }
+
+ mutex.lock(owner)
+ isLocked = true
+ try {
+ return action()
+ } finally {
+ isLocked = false
+ mutex.unlock(owner)
+ }
+}
+
+val comments by CommentData.Companion::comments
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/Item.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/Item.kt
index 69d8a0f..09b50a7 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/Item.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/data/Item.kt
@@ -16,24 +16,17 @@
*/
package io.github.samarium150.mirai.plugin.driftbottle.data
-import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle
import io.github.samarium150.mirai.plugin.driftbottle.config.GeneralConfig
import io.github.samarium150.mirai.plugin.driftbottle.config.ReplyConfig
-import io.github.samarium150.mirai.plugin.driftbottle.util.CacheType
-import io.github.samarium150.mirai.plugin.driftbottle.util.cacheFolderByType
-import io.github.samarium150.mirai.plugin.driftbottle.util.saveFrom
+import io.github.samarium150.mirai.plugin.driftbottle.data.Item.Type.BODY
+import io.github.samarium150.mirai.plugin.driftbottle.data.Item.Type.BOTTLE
+import io.github.samarium150.mirai.plugin.driftbottle.util.*
import kotlinx.serialization.Serializable
import net.mamoe.mirai.contact.Contact
-import net.mamoe.mirai.message.data.Image
+import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.Image.Key.queryUrl
-import net.mamoe.mirai.message.data.MessageChain
-import net.mamoe.mirai.message.data.PlainText
-import net.mamoe.mirai.message.data.buildMessageChain
import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage
-import java.io.FileNotFoundException
import java.net.URL
-import java.time.ZoneId
-import java.time.format.DateTimeFormatter
import java.util.*
@Serializable
@@ -45,10 +38,10 @@ class Item {
}
val type: Type
- private val owner: Owner
- private val source: Source?
+ val owner: Owner
+ val source: Source?
private var content: String? = null
- private val timestamp = Date().time
+ val timestamp = Date().time
constructor(type: Type, owner: Owner, source: Source?) {
this.type = type
@@ -63,15 +56,10 @@ class Item {
this.content = content
}
- suspend fun toMessageChain(contact: Contact): MessageChain {
- return buildMessageChain {
+ suspend fun toMessage(contact: Contact, index: Int): Message {
+ val messageChain = buildMessageChain {
when (type) {
- Type.BOTTLE -> {
- var from = "$owner"
- if (source != null)
- from = "${source}的" + from
- else
- from += "悄悄留下"
+ BOTTLE -> {
var chainJson = content ?: throw NoSuchElementException("未知错误")
if (GeneralConfig.cacheImage)
Image.IMAGE_ID_REGEX.findAll(chainJson).forEach {
@@ -81,20 +69,34 @@ class Item {
val image = file.uploadAsImage(contact)
if (imageId != image.imageId)
chainJson = chainJson.replace(imageId, image.imageId)
- }.onFailure { e ->
- if (e is FileNotFoundException) runCatching {
- val image = Image.fromId(imageId)
- file.saveFrom(image.queryUrl())
- }.onFailure {
- MiraiConsoleDriftBottle.logger.error(e)
- } else
- MiraiConsoleDriftBottle.logger.error(e)
+ }.onFailure {
+ val image = Image(imageId)
+ file.saveFrom(image.queryUrl())
}
}
- add(ReplyConfig.pickupBottle.replace("%source", from))
- add(MessageChain.deserializeFromJsonString(chainJson))
+ if (!GeneralConfig.displayInForward) {
+ var from = owner.name
+ if (source != null)
+ from = "${source}的$from\n"
+ else
+ from += "悄悄留下"
+ var comments = ""
+ CommentData.comments[index]?.let {
+ if (it.isNotEmpty()) comments += "\n此漂流瓶的评论为"
+ it.forEach { each ->
+ comments += "\n${each.senderName}: ${each.content}"
+ }
+ }
+ add(
+ ReplyConfig.pickupBottle
+ .replace("%source", from)
+ .replace("%index", (index + 1).toString())
+ )
+ add(MessageChain.deserializeFromJsonString(chainJson))
+ add(comments) // 本来想让用户自定义评论位置的,但是...摆了
+ } else add(MessageChain.deserializeFromJsonString(chainJson))
}
- Type.BODY -> {
+ BODY -> {
val avatarStream = URL(owner.avatarUrl).openStream()
val img = avatarStream.use { it.uploadAsImage(contact) }
add(img)
@@ -102,13 +104,7 @@ class Item {
PlainText(
ReplyConfig.pickupBody
.replace("%who", owner.name)
- .replace(
- "%time",
- Date(timestamp)
- .toInstant()
- .atZone(ZoneId.of("Asia/Shanghai"))
- .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
- )
+ .replace("%time", timestamp.timestampToString())
)
)
val where = if (source != null)
@@ -118,5 +114,19 @@ class Item {
}
}
}
+ return if (!GeneralConfig.displayInForward || messageChain.any {
+ when (it) {
+ is Audio, is FlashImage -> true
+ else -> false
+ }
+ }) messageChain
+ else buildForwardMessage(contact, CustomForwardMsgDisplay(index + 1, this)) {
+ add(owner.id, owner.name, messageChain, timestamp.seconds)
+ CommentData.comments[index]?.let {
+ it.forEach { each ->
+ add(each.senderId, each.senderName, PlainText(each.content), each.timestamp.seconds)
+ }
+ }
+ }
}
}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/ContentCensor.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/ContentCensor.kt
index 8c01cb8..ae504d5 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/ContentCensor.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/ContentCensor.kt
@@ -72,9 +72,7 @@ object ContentCensor {
val response: ResponseBody = when (message) {
is PlainText -> client.submitForm(
url = "${URLS.TEXT_CENSOR.url}?access_token=${ContentCensorToken.accessToken}",
- formParameters = Parameters.build {
- append("text", message.content)
- }
+ formParameters = parametersOf("text", message.content)
)
is Image -> {
val buffer = withContext(Dispatchers.IO) {
@@ -87,9 +85,7 @@ object ContentCensor {
val base64 = Base64.getEncoder().encodeToString(output.toByteArray())
client.submitForm(
url = "${URLS.IMAGE_CENSOR.url}?access_token=${ContentCensorToken.accessToken}",
- formParameters = Parameters.build {
- append("image", base64)
- }
+ formParameters = parametersOf("image", base64)
)
}
else -> continue
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/CustomForwardMsgDisplay.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/CustomForwardMsgDisplay.kt
new file mode 100644
index 0000000..3ebaa0c
--- /dev/null
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/CustomForwardMsgDisplay.kt
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+package io.github.samarium150.mirai.plugin.driftbottle.util
+
+import io.github.samarium150.mirai.plugin.driftbottle.data.Item
+import net.mamoe.mirai.message.data.ForwardMessage.DisplayStrategy
+import net.mamoe.mirai.message.data.RawForwardMessage
+
+/**
+ * @author LaoLittle
+ */
+class CustomForwardMsgDisplay(
+ private val index: Int,
+ private val item: Item
+) : DisplayStrategy {
+ override fun generateBrief(forward: RawForwardMessage): String = "[漂流瓶]"
+
+ override fun generateSummary(forward: RawForwardMessage): String = "漂流瓶序号: $index"
+
+ override fun generatePreview(forward: RawForwardMessage): List {
+ val subject = if (item.source == null) "此漂流瓶由私聊发送" else "此漂流瓶来自群: ${item.source}"
+ val sender = "发送人是: ${item.owner.name}"
+ val message = "点击打开漂流瓶"
+ return listOf(subject, sender, message)
+ }
+}
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/General.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/General.kt
index d01071f..c3c8a7c 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/General.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/General.kt
@@ -1,21 +1,48 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
package io.github.samarium150.mirai.plugin.driftbottle.util
import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle
+import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle.reload
+import io.github.samarium150.mirai.plugin.driftbottle.MiraiConsoleDriftBottle.save
import io.github.samarium150.mirai.plugin.driftbottle.config.AdvancedConfig
import io.github.samarium150.mirai.plugin.driftbottle.config.GeneralConfig
+import io.github.samarium150.mirai.plugin.driftbottle.data.Sea
+import io.github.samarium150.mirai.plugin.driftbottle.data.comments
+import io.github.samarium150.mirai.plugin.driftbottle.data.useLock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import net.mamoe.mirai.console.command.CommandSender
+import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
+import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.message.data.At
-import net.mamoe.mirai.message.data.MessageChain
-import net.mamoe.mirai.message.data.PlainText
-import net.mamoe.mirai.message.data.toMessageChain
+import net.mamoe.mirai.message.data.*
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.net.URL
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.util.*
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
internal enum class CacheType {
IMAGE
@@ -61,3 +88,63 @@ internal fun disableAt(messageChain: MessageChain, subject: Contact): MessageCha
chain.toMessageChain()
} else messageChain
}
+
+internal fun Stack.put(item: E): Stack {
+ addElement(item)
+ return this
+}
+
+@OptIn(ConsoleExperimentalApi::class)
+internal val forbidMessageKeys by lazy {
+ mutableListOf>().apply {
+ AdvancedConfig.saveMessageTypes.forEach { (type, bool) ->
+ if (!bool) add(type.toMessageKey())
+ }
+ }.toTypedArray()
+}
+
+internal fun ReadOnlyPluginConfig.alsoSave() {
+ reload()
+ save()
+}
+
+@OptIn(ExperimentalContracts::class)
+internal suspend fun CommandSender.isNotOutOfRange(index: Int?): Boolean {
+ contract {
+ returns(true) implies (index != null)
+ }
+ return when (index) {
+ null -> {
+ subject?.sendMessage("请尝试输入序号") ?: MiraiConsoleDriftBottle.logger.error("控制台使用请输入序号")
+ false
+ }
+ !in 0 until Sea.contents.size -> {
+ sendMessage("数字超出范围!")
+ false
+ }
+ else -> true
+ }
+}
+
+internal val indexOfBottle = mutableMapOf>()
+
+internal fun Long.timestampToString(): String {
+ return Date(this)
+ .toInstant()
+ .atZone(ZoneId.of("Asia/Shanghai"))
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
+}
+
+internal suspend fun rearrangeComments(from: Int) {
+ MiraiConsoleDriftBottle.launch {
+ useLock {
+ comments.remove(from)
+ comments.filter { (t, _) -> t > from }.forEach { (t, _) ->
+ comments[t - 1] = comments.getValue(t)
+ comments.remove(t)
+ }
+ }
+ }
+}
+
+internal val Long.seconds get() = (this / 1000).toInt()
diff --git a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/Throttle.kt b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/Throttle.kt
index 29b4193..f2eeb66 100644
--- a/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/Throttle.kt
+++ b/src/main/kotlin/io/github/samarium150/mirai/plugin/driftbottle/util/Throttle.kt
@@ -1,3 +1,19 @@
+/**
+ * Copyright (c) 2020-2021 Samarium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
package io.github.samarium150.mirai.plugin.driftbottle.util
import kotlinx.coroutines.sync.Mutex