From c2e1ec91b5f20b1ab367e540b93480202f78f990 Mon Sep 17 00:00:00 2001 From: RTAkland Date: Tue, 15 Oct 2024 15:40:33 +0800 Subject: [PATCH] feat: support parse youtube video --- src/main/kotlin/cn/rtast/fancybot/Const.kt | 3 +- src/main/kotlin/cn/rtast/fancybot/FancyBot.kt | 1 + .../parse/YoutubeVideoParseCommand.kt | 84 +++++++++++++++++++ .../kotlin/cn/rtast/fancybot/entity/Config.kt | 1 + .../entity/yt/YoutubeVideoResponse.kt | 42 ++++++++++ .../rtast/fancybot/util/file/ConfigManager.kt | 1 + src/main/resources/config.json | 3 +- 7 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/cn/rtast/fancybot/commands/parse/YoutubeVideoParseCommand.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/yt/YoutubeVideoResponse.kt diff --git a/src/main/kotlin/cn/rtast/fancybot/Const.kt b/src/main/kotlin/cn/rtast/fancybot/Const.kt index 2994bbc..9749233 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -83,7 +83,8 @@ val DEFAULT_CONFIG = Config( cloudflareR2PublicUrl = "https://114514.com", apiSpaceKey = "114514", apiRtastKey = "114514", - azureAppClientId = "114514" + azureAppClientId = "114514", + youtubeDataApiKey = "114514" ) val configManager = ConfigManager() diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 6324188..6733514 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -69,6 +69,7 @@ class FancyBot : OneBotListener { BiliVideoParseCommand.parse(this, message) BiliUserParseCommand.parse(this, message) DouyinVideoParseCommand.parse(message) + YoutubeVideoParseCommand.parse(message) if (message.rawMessage.toList().any { it in arrayListOf('*', '-', '/', '+', '=') }) { val calculateResult = CalculateCommand.parse(message.rawMessage) diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/parse/YoutubeVideoParseCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/parse/YoutubeVideoParseCommand.kt new file mode 100644 index 0000000..f837e65 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/commands/parse/YoutubeVideoParseCommand.kt @@ -0,0 +1,84 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/15 + */ + + +package cn.rtast.fancybot.commands.parse + +import cn.rtast.fancybot.configManager +import cn.rtast.fancybot.entity.yt.YoutubeVideoResponse +import cn.rtast.fancybot.util.Http +import cn.rtast.fancybot.util.misc.toBufferedImage +import cn.rtast.fancybot.util.misc.toByteArray +import cn.rtast.fancybot.util.misc.toURL +import cn.rtast.fancybot.util.str.encodeToBase64 +import cn.rtast.fancybot.util.str.proxy +import cn.rtast.rob.entity.GroupMessage +import cn.rtast.rob.util.ob.MessageChain +import java.awt.Color +import java.awt.Font +import java.awt.RenderingHints +import java.awt.image.BufferedImage + +object YoutubeVideoParseCommand { + private const val YOUTUBE_API_URL = "https://proxy.rtast.cn/https/www.googleapis.com/youtube/v3/videos" + private const val IMAGE_WIDTH = 800 + private const val IMAGE_HEIGHT = 450 + private val dataApiKey = configManager.youtubeDataApiKey + private val youtubeVideoIdRegex = + Regex("(?:https?://)?(?:www\\.)?(?:youtube\\.com/(?:watch\\?v=|embed/|v/|.+\\?v=)|youtu\\.be/)([\\w\\-]{11})") + + private fun createVideoCard(videoInfo: YoutubeVideoResponse): String { + val image = BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB) + val g2d = image.createGraphics() + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON) + g2d.color = Color(48, 48, 48) + g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT) + g2d.color = Color(255, 255, 255) + g2d.font = Font("Serif", Font.BOLD, 24) + val title = videoInfo.items.first().snippet.title + g2d.drawString(title, 20, 40) + g2d.font = Font("Serif", Font.PLAIN, 18) + val channelTitle = videoInfo.items.first().snippet.channelTitle + g2d.drawString(channelTitle, 20, 70) + val thumbnailImage = videoInfo.items.first().snippet.thumbnails.maxRes.url + .proxy.toURL().readBytes().toBufferedImage() + val scaledWidth = 300 + val scaledHeight = (thumbnailImage.height * (scaledWidth / thumbnailImage.width.toDouble())).toInt() + g2d.drawImage(thumbnailImage, 20, 100, scaledWidth, scaledHeight, null) + g2d.color = Color(200, 200, 200) + g2d.font = Font("Serif", Font.PLAIN, 16) + g2d.drawString("观看次数: ${videoInfo.items.first().statistics.viewCount}", 340, 120) + g2d.drawString("点赞次数: ${videoInfo.items.first().statistics.likeCount}", 340, 150) + g2d.drawString("收藏次数: ${videoInfo.items.first().statistics.favoriteCount}", 340, 180) + g2d.drawString("评论数: ${videoInfo.items.first().statistics.commentCount}", 340, 210) + g2d.dispose() + return image.toByteArray().encodeToBase64() + } + + private fun getVideoInfo(videoId: String): YoutubeVideoResponse { + val response = Http.get( + YOUTUBE_API_URL, + mapOf( + "id" to videoId, + "key" to dataApiKey, + "part" to "snippet,statistics" + ) + ) + return response + } + + suspend fun parse(message: GroupMessage) { + val matchResult = youtubeVideoIdRegex.find(message.rawMessage) + if (matchResult != null) { + val videoId = matchResult.groupValues[1] + val videoInfo = this.getVideoInfo(videoId) + val image = createVideoCard(videoInfo) + val msg = MessageChain.Builder().addImage(image, true).build() + message.reply(msg) + } + } +} \ 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 d444f6c..b33879a 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt @@ -48,4 +48,5 @@ data class Config( val apiSpaceKey: String, val apiRtastKey: String, val azureAppClientId: String, + val youtubeDataApiKey: String, ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/yt/YoutubeVideoResponse.kt b/src/main/kotlin/cn/rtast/fancybot/entity/yt/YoutubeVideoResponse.kt new file mode 100644 index 0000000..8ef8de9 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/yt/YoutubeVideoResponse.kt @@ -0,0 +1,42 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/15 + */ + + +package cn.rtast.fancybot.entity.yt + +import com.google.gson.annotations.SerializedName + + +data class YoutubeVideoResponse( + val items: List +) { + data class Item( + val snippet: Snippet, + val statistics: Statistics + ) + + data class Snippet( + val title: String, + val thumbnails: Thumbnails, + val channelTitle: String, + ) + + data class Thumbnails( + @SerializedName("maxres") + val maxRes: MaxRes + ) + + data class MaxRes( + val url: String, + ) + + data class Statistics( + val viewCount: String, + val likeCount: String, + val favoriteCount: String, + val commentCount: 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 2d70e22..406d69b 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt @@ -48,4 +48,5 @@ class ConfigManager : JsonFileHandler("config.json") { val apiSpaceKey = config.apiSpaceKey val apiRtastKey = config.apiRtastKey val azureAppClientId = config.azureAppClientId + val youtubeDataApiKey = config.youtubeDataApiKey } \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json index 6809cd8..7a40fa2 100644 --- a/src/main/resources/config.json +++ b/src/main/resources/config.json @@ -39,5 +39,6 @@ "cloudflareR2PublicUrl": "https://114514.com", "apiSpaceKey": "114514", "apiRtastKey": "114514", - "azureAppClientId": "114514" + "azureAppClientId": "114514", + "youtubeDataApiKey": "114514" } \ No newline at end of file