From 78487514ce24160827ee7e4a7a3ae6f55a2c4c4b Mon Sep 17 00:00:00 2001 From: RTAkland Date: Sat, 14 Sep 2024 22:00:18 +0800 Subject: [PATCH] feat: add view count on bv parse card --- src/main/kotlin/cn/rtast/fancybot/FancyBot.kt | 2 +- .../fancybot/commands/parse/BVParseCommand.kt | 58 +++++++++++--- .../cn/rtast/fancybot/entity/bili/ShortUrl.kt | 16 ++++ .../entity/bili/{BVID.kt => VideoStat.kt} | 3 +- .../rtast/fancybot/entity/bili/ViewCount.kt | 16 ++++ .../kotlin/cn/rtast/fancybot/util/Http.kt | 78 ++++++++----------- 6 files changed, 115 insertions(+), 58 deletions(-) create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/bili/ShortUrl.kt rename src/main/kotlin/cn/rtast/fancybot/entity/bili/{BVID.kt => VideoStat.kt} (92%) create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/bili/ViewCount.kt diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 3f98a1a..4209606 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -83,7 +83,7 @@ class FancyBot : OBMessage { } BVParseCommand.getShortUrlBVID(shortUrl) } else { - message.rawMessage.split("/")[4] + message.rawMessage.split("?").first().split("/").filter { it.isNotEmpty() && it.isNotBlank() }.last() } BVParseCommand.parse(this, bvid, message) } diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt index 09a158c..6ecc8f1 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt @@ -7,8 +7,10 @@ package cn.rtast.fancybot.commands.parse -import cn.rtast.fancybot.entity.bili.BVID +import cn.rtast.fancybot.entity.bili.ShortUrl import cn.rtast.fancybot.entity.bili.UserStat +import cn.rtast.fancybot.entity.bili.VideoStat +import cn.rtast.fancybot.entity.bili.ViewCount import cn.rtast.fancybot.util.Http import cn.rtast.fancybot.util.Resources import cn.rtast.fancybot.util.drawCustomImage @@ -30,8 +32,10 @@ import javax.imageio.ImageIO object BVParseCommand { - private const val CID_URL = "https://api.bilibili.com/x/web-interface/view" + private const val VIDEO_STAT_URL = "https://api.bilibili.com/x/web-interface/view" private const val USER_STAT_URL = "https://api.bilibili.com/x/relation/stat" + private const val SHORT_URL_API_URL = "https://api.bilibili.com/x/share/click" + private const val VIEW_COUNT_URL = "https://api.bilibili.com/x/player/online/total" private const val CANVAS_WIDTH = 1000 private const val CANVAS_HEIGHT = 600 private val titleFont = Font("Serif", Font.ITALIC, 40) @@ -46,12 +50,32 @@ object BVParseCommand { private val tempOkHttpClient = OkHttpClient() - fun getShortUrlBVID(shortUrl: String): String { - val request = Request.Builder().url(shortUrl.split(" ").last()).build() - val redirectedUrl = tempOkHttpClient.newCall(request).execute() - redirectedUrl.use { - return it.request.url.toString().split("/")[4].split("?").first() - } + private fun generateShortUrl(bvid: String, oid: Long): String { + val result = Http.post( + SHORT_URL_API_URL, mapOf( + "buvid" to bvid, + "build" to 6114514, + "platform" to "unix", + "share_channel" to "COPY", + "share_mode" to 2, + "share_id" to "main.ugc-video-detail.0.0.pv", + "oid" to oid + ) + ) + return result.data.content.split(" ").last() + } + + private fun getViewCount(bvid: String, cid: Long): String { + return Http.get( + VIEW_COUNT_URL, mapOf( + "bvid" to bvid, + "cid" to cid + ) + ).data.total + } + + private fun getVideoStat(bvid: String): VideoStat { + return Http.get(VIDEO_STAT_URL, mapOf("bvid" to bvid)) } private fun createResponseImage( @@ -66,6 +90,7 @@ object BVParseCommand { like: String, favorite: String, fans: Int, + viewCount: String, ): String { val coverImage = ImageIO.read(URI(picUrl).toURL()) val faceImage = ImageIO.read(URI(authorFace).toURL()) @@ -104,6 +129,8 @@ object BVParseCommand { // draw fans count g2d.font = numberFont g2d.drawString(fans.formatNumber() + "粉丝", 120, 520) + // draw viewing count + g2d.drawString("${viewCount}人正在观看", 40, 460) // draw author face g2d.drawCustomImage(faceImage, 40, 480, 60.0, 60.0, true) // draw cover image @@ -112,8 +139,18 @@ object BVParseCommand { return canvas.toByteArray().encodeToBase64() } + fun getShortUrlBVID(shortUrl: String): String { + val request = Request.Builder().url(shortUrl.split(" ").last()).build() + val redirectedUrl = tempOkHttpClient.newCall(request).execute() + redirectedUrl.use { + return it.request.url.toString().split("/")[4].split("?").first() + } + } + suspend fun parse(listener: OBMessage, bvid: String, message: GroupMessage) { - val videoInfo = Http.get(CID_URL, mapOf("bvid" to bvid)) + val videoInfo = this.getVideoStat(bvid) + val viewCount = this.getViewCount(bvid, videoInfo.data.cid) + val shortUrl = this.generateShortUrl(bvid, videoInfo.data.aid) val fans = Http.get(USER_STAT_URL, mapOf("vmid" to videoInfo.data.owner.mid)).data.follower val authorFace = videoInfo.data.owner.face val title = videoInfo.data.title @@ -128,11 +165,12 @@ object BVParseCommand { val image = this.createResponseImage( title, author, authorFace, coverPicUrl, reply, view, coin, - share, like, favorite, fans + share, like, favorite, fans, viewCount ) val msg = MessageChain.Builder() .addReply(message.messageId) .addImage(image, true) + .addText(shortUrl) .build() listener.sendGroupMessage(message.groupId, msg) } diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/bili/ShortUrl.kt b/src/main/kotlin/cn/rtast/fancybot/entity/bili/ShortUrl.kt new file mode 100644 index 0000000..d853f24 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/bili/ShortUrl.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/14 + */ + + +package cn.rtast.fancybot.entity.bili + +data class ShortUrl( + val data: Data +) { + data class Data( + val content: String + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/bili/BVID.kt b/src/main/kotlin/cn/rtast/fancybot/entity/bili/VideoStat.kt similarity index 92% rename from src/main/kotlin/cn/rtast/fancybot/entity/bili/BVID.kt rename to src/main/kotlin/cn/rtast/fancybot/entity/bili/VideoStat.kt index 79ea234..1acc1fc 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/bili/BVID.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/bili/VideoStat.kt @@ -7,10 +7,11 @@ package cn.rtast.fancybot.entity.bili -data class BVID( +data class VideoStat( val data: Data ) { data class Data( + val aid: Long, val pic: String, val title: String, val owner: Owner, diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/bili/ViewCount.kt b/src/main/kotlin/cn/rtast/fancybot/entity/bili/ViewCount.kt new file mode 100644 index 0000000..c426915 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/bili/ViewCount.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/14 + */ + + +package cn.rtast.fancybot.entity.bili + +data class ViewCount( + val data: Data +) { + data class Data( + val total: String + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/Http.kt b/src/main/kotlin/cn/rtast/fancybot/util/Http.kt index 376a84d..30250c4 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/Http.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/Http.kt @@ -100,7 +100,7 @@ object Http { @JvmOverloads inline fun post( url: String, - formBody: Map? = null, + formBody: Map? = null, headers: Map? = null, params: Map? = null ): T { @@ -108,7 +108,7 @@ object Http { val paramsUrl = buildParams(url, params) formBody?.let { it.forEach { (key, value) -> - body.add(key, value) + body.add(key, value.toString()) } } val request = Request.Builder() @@ -146,48 +146,34 @@ object Http { return this.executeRequest(headerRequest.build()) } - inline fun getAsync( - url: String, - params: Map? = null, - headers: Map? = null, - noinline callback: (T?) -> Unit - ) { - val paramsUrl = buildParams(url, params) - val request = Request.Builder() - .url(paramsUrl) - .get() - - executeRequestAsync(request, headers) { response -> - try { - callback(response.fromJson()) - } catch (e: Exception) { - e.printStackTrace() - callback(null) - } - } - } - - inline fun postAsync( - url: String, - jsonBody: String, - headers: Map? = null, - params: Map? = null, - noinline callback: (T?) -> Unit - ) { - val body = jsonBody.toRequestBody(jsonMediaType) - val paramsUrl = buildParams(url, params) - val request = Request.Builder() - .post(body) - .url(paramsUrl) - this.addHeaders(request, jsonHeader) - - executeRequestAsync(request, headers) { response -> - try { - callback(response.fromJson()) - } catch (e: Exception) { - e.printStackTrace() - callback(null) - } - } - } +// @JvmOverloads +// fun post( +// url: String, +// form: Map, +// headers: Map? = null, +// params: Map? = null +// ): String { +// val formBody = FormBody.Builder() +// form.forEach { +// formBody.add(it.key, it.value.toString()) +// } +// val paramsUrl = buildParams(url, params) +// val request = Request.Builder() +// .post(formBody.build()) +// .url(paramsUrl) +// this.addHeaders(request, jsonHeader) +// val headerRequest = addHeaders(request, headers) +// return this.executeRequest(headerRequest.build()) +// } +// +// @JvmOverloads +// inline fun post( +// url: String, +// form: Map, +// headers: Map? = null, +// params: Map? = null +// ): T { +// val result = post(url, form, headers, params) +// return result.fromJson() +// } }