diff --git a/src/main/kotlin/cn/rtast/fancybot/Const.kt b/src/main/kotlin/cn/rtast/fancybot/Const.kt index 8aecba1..021e37e 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -61,7 +61,8 @@ val DEFAULT_CONFIG = Config( admins = listOf(3458671395L), enableAntiRevoke = true, llamaUrl = "http://127.0.0.1", - llamaModel = "llama3.1" + llamaModel = "llama3.1", + qqMusicApiUrl = "http://127.0.0.1:3200" ) val configManager = ConfigManager() @@ -101,5 +102,6 @@ val commands = listOf( NiuziBankCommand(), WithdrawCommand(), BankTransferCommand(), CreateBankAccountCommand(), BankBalanceCommand(), DepositCommand(), - DMSearchCommand(), LlamaCommand() + DMSearchCommand(), LlamaCommand(), + QQMusicCommand() ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/lookup/MusicCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/MusicCommand.kt index 8650a8c..4b9caea 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/lookup/MusicCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/MusicCommand.kt @@ -11,12 +11,20 @@ import cn.rtast.fancybot.configManager import cn.rtast.fancybot.entity.music.Search import cn.rtast.fancybot.entity.music.SearchedResult import cn.rtast.fancybot.entity.music.SongUrl +import cn.rtast.fancybot.entity.music.qq.CoverImage +import cn.rtast.fancybot.entity.music.qq.QMSearchResult +import cn.rtast.fancybot.entity.music.qq.QQMSearch import cn.rtast.fancybot.util.Http +import cn.rtast.fancybot.util.str.encodeToBase64 +import cn.rtast.fancybot.util.str.formatToMinutes import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.enums.MusicShareType import cn.rtast.rob.util.BaseCommand import cn.rtast.rob.util.ob.MessageChain +import cn.rtast.rob.util.ob.NodeMessageChain import cn.rtast.rob.util.ob.OneBotListener +import java.io.FileNotFoundException +import java.net.URI import java.time.Instant class MusicCommand : BaseCommand() { @@ -121,7 +129,7 @@ class MusicCommand : BaseCommand() { } val keyword = args.joinToString(" ") - val result = searchSong(keyword).result.songs.asSequence().first().id + val result = searchSong(keyword).result.songs.first().id val msg = MessageChain.Builder() .addMusicShare(MusicShareType.Netease, result.toString()) .build() @@ -151,4 +159,94 @@ class MusicPlayUrlCommand : BaseCommand() { .build() listener.sendGroupMessage(message.groupId, msg) } +} + +class QQMusicCommand : BaseCommand() { + override val commandNames = listOf("qm", "/qqm", "qqm", "/qm", "q点歌") + + private val qqMusicApiUrl = configManager.qqMusicApiUrl + + private val recordMap = mutableMapOf>() + + override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List) { + if (args.isEmpty()) { + message.reply("发送`/qm <关键词>`即可搜索qq音乐的音乐哦") + return + } + this.recordMap.forEach { (key, results) -> + val validResults = results.filter { result -> + Instant.now().epochSecond - result.timestamp <= 30 + } + if (validResults.isEmpty()) { + recordMap.remove(key) + } else { + recordMap[key] = validResults + } + } + val method = args.first() + when (method) { + "p" -> { + try { + val index = args.last().toInt() + val result = recordMap[message.sender.userId]!![index] + val msg = MessageChain.Builder() + .addMusicShare(MusicShareType.QQ, result.id.toString()) + .build() + listener.sendGroupMessage(message.groupId, msg) + } catch (_: Exception) { + message.reply("回复错误已清除本次搜索结果") + } + recordMap.remove(message.sender.userId) + } + + else -> { + try { + val keyword = args.joinToString(" ") + val response = Http.get( + "$qqMusicApiUrl/getSearchByKey", + mapOf("key" to keyword) + ).response.data.song.list + val tempResultList = mutableListOf() + response.forEach { + val coverUrl = Http.get( + "$qqMusicApiUrl/getImageUrl", + mapOf("id" to it.albumMid) + ) + val tempSearchResult = QMSearchResult( + it.songId, it.songName, it.singer.joinToString(", ") { join -> join.name }, + it.interval, it.songMid, Instant.now().epochSecond, coverUrl.response.data.imageUrl + ) + tempResultList.add(tempSearchResult) + } + recordMap[message.sender.userId] = tempResultList + val nodeMsg = NodeMessageChain.Builder() + val headerMsg = MessageChain.Builder() + .addText("发送 `qm p <序号>`即可返回对应的歌曲") + .addNewLine() + .addText("你有30秒的时间进行操作") + .build() + nodeMsg.addMessageChain(headerMsg, message.sender.userId) + tempResultList.forEachIndexed { index, it -> + try { + val imageBase64 = URI(it.albumUrl).toURL().readBytes().encodeToBase64() + val msg = MessageChain.Builder() + .addImage(imageBase64, true) + .addText("序号: $index") + .addNewLine() + .addText("歌曲名: ${it.name}") + .addNewLine() + .addText("歌手: ${it.singers}") + .addNewLine() + .addText("时长: ${it.interval.formatToMinutes()}") + .build() + nodeMsg.addMessageChain(msg, message.sender.userId) + } catch (_: FileNotFoundException) { + } + } + message.reply(nodeMsg.build()) + } catch (_: Exception) { + } + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt index 887e8e4..8ce8b8f 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt @@ -32,4 +32,5 @@ data class Config( val enableAntiRevoke: Boolean, val llamaUrl: String, val llamaModel: String, + val qqMusicApiUrl: String ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/CoverImage.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/CoverImage.kt new file mode 100644 index 0000000..e68fbe1 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/CoverImage.kt @@ -0,0 +1,20 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/25 + */ + + +package cn.rtast.fancybot.entity.music.qq + +data class CoverImage( + val response: Response +) { + data class Response( + val data: Data + ) + + data class Data( + val imageUrl: String + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QMSearchResult.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QMSearchResult.kt new file mode 100644 index 0000000..e67ea19 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QMSearchResult.kt @@ -0,0 +1,18 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/25 + */ + + +package cn.rtast.fancybot.entity.music.qq + +data class QMSearchResult( + val id: Long, + val name: String, + val singers: String, + val interval: Int, + val mid: String, + val timestamp: Long, + val albumUrl: String +) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QQMSearch.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QQMSearch.kt new file mode 100644 index 0000000..9b08bee --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/qq/QQMSearch.kt @@ -0,0 +1,43 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/25 + */ + + +package cn.rtast.fancybot.entity.music.qq + +import com.google.gson.annotations.SerializedName + +data class QQMSearch( + val response: Response, +) { + data class Response( + val data: Data + ) + + data class Data( + val song: Songs + ) + + data class Songs( + val list: List + ) + + data class Song( + @SerializedName("albummid") + val albumMid: String, + val interval: Int, + @SerializedName("songmid") + val songMid: String, + @SerializedName("songid") + val songId: Long, + @SerializedName("songname") + val songName: String, + val singer: List, + ) + + data class Singer( + val name: String + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt index 1f19a87..a2c3b94 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt @@ -32,4 +32,5 @@ class ConfigManager : JsonFileHandler("config.json") { val enableAntiRevoke get() = this.read().enableAntiRevoke val llamaUrl get() = this.read().llamaUrl val llamaModel get() = this.read().llamaModel + val qqMusicApiUrl get() = this.read().qqMusicApiUrl } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/str/StringFormatter.kt b/src/main/kotlin/cn/rtast/fancybot/util/str/StringFormatter.kt index 2a9e7ee..91b15aa 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/str/StringFormatter.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/str/StringFormatter.kt @@ -40,3 +40,9 @@ fun Int.formatNumberEnglish(): String { else -> this.toString() } } + +fun Int.formatToMinutes(): String { + val minutes = this / 60 + val remainingSeconds = this % 60 + return "$minutes:${if (remainingSeconds < 10) "0" else ""}$remainingSeconds" +} \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json index c5c984f..1aa0ad3 100644 --- a/src/main/resources/config.json +++ b/src/main/resources/config.json @@ -24,5 +24,6 @@ ], "enableAntiRevoke": true, "llamaUrl": "http://127.0.0.1", - "llamaModel": "llama3.1" + "llamaModel": "llama3.1", + "qqMusicApiUrl": "http://127.0.0.1:3200" } \ No newline at end of file