feat: add qq music api search

This commit is contained in:
2024-09-25 23:04:49 +08:00
parent ecd50ffea6
commit 1c89d54636
9 files changed
+194 -4

No files matched your search

+4 -2
View File
@@ -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()
)
@@ -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<Long, List<QMSearchResult>>()
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
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<QQMSearch>(
"$qqMusicApiUrl/getSearchByKey",
mapOf("key" to keyword)
).response.data.song.list
val tempResultList = mutableListOf<QMSearchResult>()
response.forEach {
val coverUrl = Http.get<CoverImage>(
"$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) {
}
}
}
}
}
@@ -32,4 +32,5 @@ data class Config(
val enableAntiRevoke: Boolean,
val llamaUrl: String,
val llamaModel: String,
val qqMusicApiUrl: String
)
@@ -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
)
}
@@ -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
)
@@ -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<Song>
)
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<Singer>,
)
data class Singer(
val name: String
)
}
@@ -32,4 +32,5 @@ class ConfigManager : JsonFileHandler<Config>("config.json") {
val enableAntiRevoke get() = this.read<Config>().enableAntiRevoke
val llamaUrl get() = this.read<Config>().llamaUrl
val llamaModel get() = this.read<Config>().llamaModel
val qqMusicApiUrl get() = this.read<Config>().qqMusicApiUrl
}
@@ -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"
}
+2 -1
View File
@@ -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"
}