diff --git a/build.gradle.kts b/build.gradle.kts index 8117ea5..42968f2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "top.colter" -version = "3.2.6" +version = "3.2.7" repositories { mavenLocal() @@ -43,7 +43,7 @@ dependencies { } implementation("com.google.zxing:javase:3.5.0") - compileOnly("xyz.cssxsh.mirai:mirai-skia-plugin:1.2.1") + compileOnly("xyz.cssxsh.mirai:mirai-skia-plugin:1.3.1") testImplementation(kotlin("test", "1.7.0")) testImplementation("org.jetbrains.skiko:skiko-awt-runtime-windows-x64:0.7.27") diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliBiliDynamic.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliBiliDynamic.kt index 365bcf3..66c11d6 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliBiliDynamic.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliBiliDynamic.kt @@ -24,7 +24,7 @@ object BiliBiliDynamic : KotlinPlugin( JvmPluginDescription( id = "top.colter.bilibili-dynamic-mirai-plugin", name = "BiliBili Dynamic", - version = "3.2.6", + version = "3.2.7", ) { author("Colter") dependsOn("xyz.cssxsh.mirai.plugin.mirai-skia-plugin", ">= 1.1.0") diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliConfig.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliConfig.kt index 7702630..6d2e9fe 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliConfig.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/BiliConfig.kt @@ -1,7 +1,7 @@ package top.colter.mirai.plugin.bilibili import kotlinx.serialization.Serializable -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 import org.jetbrains.skia.paragraph.Alignment @@ -9,13 +9,13 @@ import top.colter.mirai.plugin.bilibili.service.TriggerMode import top.colter.mirai.plugin.bilibili.utils.CacheType -object BiliConfig: AutoSavePluginConfig("BiliConfig") { +object BiliConfig: ReadOnlyPluginConfig("BiliConfig") { - @ValueDescription("具体的配置文件描述请前往下方链接查看") - val help: String by value("https://github.com/Colter23/bilibili-dynamic-mirai-plugin#BiliConfig.yml") + //@ValueDescription("具体的配置文件描述请前往下方链接查看") + //val help: String by value("https://github.com/Colter23/bilibili-dynamic-mirai-plugin#BiliConfig.yml") @ValueDescription("管理员") - var admin: Long by value(0L) + val admin: Long by value(0L) @ValueDescription( """ diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/Api.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/Api.kt index 1166fa8..27bfd6e 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/Api.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/Api.kt @@ -1,8 +1,8 @@ package top.colter.mirai.plugin.bilibili.api // Login -const val LOGIN_URL = "http://passport.bilibili.com/qrcode/getLoginUrl" -const val LOGIN_INFO = "http://passport.bilibili.com/qrcode/getLoginInfo" +const val LOGIN_QRCODE = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate" +const val LOGIN_INFO = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll" // Dynamic const val NEW_DYNAMIC = "https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all" @@ -26,6 +26,7 @@ const val SEARCH = "https://api.bilibili.com/x/web-interface/search/type" // Space const val USER_INFO = "https://api.bilibili.com/x/space/acc/info" +const val USER_INFO_WBI = "https://api.bilibili.com/x/space/wbi/acc/info" const val USER_ID = "https://api.bilibili.com/x/web-interface/nav" const val SPACE_SEARCH = "https://api.bilibili.com/x/space/arc/search" diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/General.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/General.kt index 0665fd8..1084414 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/General.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/General.kt @@ -9,6 +9,7 @@ import top.colter.mirai.plugin.bilibili.data.ShortLinkData import top.colter.mirai.plugin.bilibili.utils.actionNotify import top.colter.mirai.plugin.bilibili.utils.bodyParameter import top.colter.mirai.plugin.bilibili.utils.decode +import top.colter.mirai.plugin.bilibili.utils.md5 fun twemoji(code: String) = "$TWEMOJI/$code.png" @@ -31,6 +32,21 @@ internal suspend inline fun BiliClient.getData( res.data.decode() } } +internal suspend inline fun BiliClient.getDataWithWbi( + url: String, + crossinline block: HttpRequestBuilder.() -> Unit = {} +): T? { + val builder = HttpRequestBuilder() + builder.block() + val params = builder.url.parameters.build().formUrlEncode() + val wts = System.currentTimeMillis() / 1000 + val wrid = "$params&wts=$wts${getVerifyString()}".md5() + return getData(url) { + block() + parameter("w_rid", wrid) + parameter("wts", wts) + } +} suspend fun BiliClient.redirect(url: String): String? { return useHttpClient { @@ -71,4 +87,26 @@ suspend fun BiliClient.toShortLink(oid: String, shareId: String, shareOrigin: St }.body().decode().data?.decode()?.link } }catch (e: Exception) { null } +} + +fun getVerifyString(): String { + // https://api.bilibili.com/x/web-interface/nav + //val imgUrl = "https://i0.hdslb.com/bfs/wbi/829e9923f2d9407c8932e9e492a345ff.png" + //val subUrl = "https://i0.hdslb.com/bfs/wbi/349e075a9ac443dfb7679db4f73c379f.png" + //val r = splitUrl(imgUrl) + splitUrl(subUrl) + //val r = "829e9923f2d9407c8932e9e492a345ff349e075a9ac443dfb7679db4f73c379f" + //val array = intArrayOf(46,47,18,2,53,8,23,32,15,50,10,31,58,3,45,35,27,43,5,49,33,9,42,19,29,28,14,39,12,38,41,13,37,48,7,16,24,55,40,61,26,17,0,1,60,51,30,4,22,25,54,21,56,59,6,63,57,62,11,36,20,34,44,52) + //return buildString { + // array.forEach { t -> + // if (t < r.length) { + // append(r[t]) + // } + // } + //}.slice(IntRange(0, 31)) + + return "df39df43c6df3e3e349742c2547a45a0" +} + +fun splitUrl(url: String): String { + return url.removeSuffix("/").split("/").last().split(".").first() } \ No newline at end of file diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/User.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/User.kt index d54041b..6217a0b 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/User.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/api/User.kt @@ -7,20 +7,15 @@ import top.colter.mirai.plugin.bilibili.data.* import top.colter.mirai.plugin.bilibili.utils.bodyParameter import top.colter.mirai.plugin.bilibili.utils.decode -suspend fun BiliClient.getLoginUrl(): LoginResult = get(LOGIN_URL) -suspend fun BiliClient.loginInfo(oauthKey: String): LoginResult { - //return useHttpClient { - // it.post(LOGIN_INFO) { - // bodyParameter("oauthKey", oauthKey) - // }.body().decode() - //} - return post(LOGIN_INFO) { - bodyParameter("oauthKey", oauthKey) +suspend fun BiliClient.getLoginQrcode(): LoginQrcode? = getData(LOGIN_QRCODE) +suspend fun BiliClient.loginInfo(qrcodeKey: String): LoginData? { + return getData(LOGIN_INFO) { + parameter("qrcode_key", qrcodeKey) } } suspend fun BiliClient.userInfo(uid: Long): BiliUser? { - return getData(USER_INFO) { + return getDataWithWbi(USER_INFO_WBI) { parameter("mid", uid) } } diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/command/DynamicCommand.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/command/DynamicCommand.kt index e7767fa..0c17b31 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/command/DynamicCommand.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/command/DynamicCommand.kt @@ -24,6 +24,7 @@ import top.colter.mirai.plugin.bilibili.data.DynamicDetail import top.colter.mirai.plugin.bilibili.data.LiveDetail import top.colter.mirai.plugin.bilibili.service.* import top.colter.mirai.plugin.bilibili.utils.* +import xyz.cssxsh.mirai.skia.MiraiSkiaPlugin.reload object DynamicCommand : CompositeCommand( owner = BiliBiliDynamic, @@ -41,6 +42,12 @@ object DynamicCommand : CompositeCommand( loadResourceBytes("image/HELP.png").toExternalResource().toAutoCloseable().sendAsImageTo(Contact()) } + @SubCommand("reload", "重载") + suspend fun CommandSender.reload() { + BiliConfig.reload() + sendMessage("配置重载成功") + } + @SubCommand("color", "颜色") suspend fun CommandSender.color(user: String, color: String) { matchUser(user) { @@ -177,8 +184,9 @@ object DynamicCommand : CompositeCommand( @SubCommand("templateList", "tl", "模板列表") suspend fun CommandSenderOnMessage<*>.templateList(type: String = "d") { - subject?.sendMessage("少女祈祷中...") + val ms = subject?.sendMessage("加载中...") TemplateService.listTemplate(type, Contact()) + ms?.recall() } @SubCommand("template", "t", "模板") @@ -260,7 +268,7 @@ object DynamicCommand : CompositeCommand( } catch (e: Exception) { null } - if (detail != null) subject.sendMessage("少女祈祷中...") else subject.sendMessage("未找到动态") + if (detail != null) subject.sendMessage("加载中...") else subject.sendMessage("未找到动态") detail?.let { d -> BiliBiliDynamic.dynamicChannel.send(DynamicDetail(d, subject.delegate)) } } @@ -268,7 +276,7 @@ object DynamicCommand : CompositeCommand( suspend fun CommandSenderOnMessage<*>.live() { val subject = Contact() val detail = biliClient.getLive(1, 1) - if (detail != null) subject.sendMessage("少女祈祷中...") else subject.sendMessage("当前没有人在直播") + if (detail != null) subject.sendMessage("加载中...") else subject.sendMessage("当前没有人在直播") detail?.let { d -> BiliBiliDynamic.liveChannel.send(LiveDetail(d.rooms.first(), subject.delegate)) } } @@ -279,7 +287,7 @@ object DynamicCommand : CompositeCommand( list?.forEach { di -> BiliBiliDynamic.dynamicChannel.send(DynamicDetail(di, Contact().delegate)) } - if (!list.isNullOrEmpty()) "少女祈祷中..." else "未找到动态" + if (!list.isNullOrEmpty()) "加载中..." else "未找到动态" }?.let { sendMessage(it) } } diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Login.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Login.kt new file mode 100644 index 0000000..3452d83 --- /dev/null +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Login.kt @@ -0,0 +1,26 @@ +package top.colter.mirai.plugin.bilibili.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class LoginData( + @SerialName("code") + val code: Int? = null, + @SerialName("message") + val message: String? = null, + @SerialName("refresh_token") + val refreshToken: String? = null, + @SerialName("timestamp") + val timestamp: Long? = null, + @SerialName("url") + val url: String? = null, +) + +@Serializable +data class LoginQrcode( + @SerialName("url") + val url: String, + @SerialName("qrcode_key") + val qrcodeKey: String? = null +) \ No newline at end of file diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Result.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Result.kt index f216bf0..3bb888f 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Result.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/data/Result.kt @@ -16,28 +16,6 @@ data class BiliResult( val data: JsonElement? = null ) -@Serializable -data class LoginResult( - @SerialName("code") - val code: Int? = null, - @SerialName("message") - val message: String? = null, - @SerialName("ts") - val ts: Int? = null, - @SerialName("status") - val status: Boolean? = null, - @SerialName("data") - val data: JsonElement? = null -) - -@Serializable -data class LoginData( - @SerialName("url") - val url: String, - @SerialName("oauthKey") - val oauthKey: String? = null -) - @Serializable data class PgcResult( @SerialName("code") diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/old/DataMigration.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/old/DataMigration.kt index 14d7e7e..8d65819 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/old/DataMigration.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/old/DataMigration.kt @@ -100,7 +100,7 @@ fun migrationConfig() { if (!BiliPluginConfig.migrated) { BiliBiliDynamic.logger.info("开始转移旧版配置...") - BiliConfig.admin = BiliPluginConfig.admin.toLong() + //BiliConfig.admin = BiliPluginConfig.admin.toLong() BiliConfig.accountConfig.cookie = BiliPluginConfig.cookie BiliConfig.accountConfig.autoFollow = BiliPluginConfig.autoFollow BiliConfig.accountConfig.followGroup = BiliPluginConfig.followGroup diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/DynamicService.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/DynamicService.kt index 4dd80d9..51ac0f3 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/DynamicService.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/DynamicService.kt @@ -119,17 +119,18 @@ object DynamicService { }else false } if (c == 0) appendLine("无") + //appendLine() + //appendLine("番剧: ") + //val cc = bangumi.count { (ssid, sub) -> + // if (subject in sub.contacts) { + // appendLine("${sub.title}@ss$ssid") + // true + // }else false + //} + //if (cc == 0) appendLine("无") appendLine() - appendLine("番剧: ") - val cc = bangumi.count { (ssid, sub) -> - if (subject in sub.contacts) { - appendLine("${sub.title}@ss$ssid") - true - }else false - } - if (cc == 0) appendLine("无") - appendLine() - append("共 ${c + cc} 个订阅") + //append("共 ${c + cc} 个订阅") + append("共 ${c} 个订阅") } } diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/LoginService.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/LoginService.kt index 2534fee..c70776e 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/LoginService.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/service/LoginService.kt @@ -9,17 +9,15 @@ import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource import top.colter.mirai.plugin.bilibili.BiliBiliDynamic import top.colter.mirai.plugin.bilibili.BiliBiliDynamic.save import top.colter.mirai.plugin.bilibili.BiliConfig -import top.colter.mirai.plugin.bilibili.api.getLoginUrl +import top.colter.mirai.plugin.bilibili.api.getLoginQrcode import top.colter.mirai.plugin.bilibili.api.loginInfo -import top.colter.mirai.plugin.bilibili.data.LoginData import top.colter.mirai.plugin.bilibili.draw.loginQrCode import top.colter.mirai.plugin.bilibili.initTagid -import top.colter.mirai.plugin.bilibili.utils.decode import java.net.URI object LoginService { suspend fun login(contact: Contact) { - val loginData = client.getLoginUrl().data!!.decode() + val loginData = client.getLoginQrcode()!! val image = loginQrCode(loginData.url) val qrMsg = image.encodeToData()!!.bytes.toExternalResource().toAutoCloseable().sendAsImageTo(contact) @@ -28,10 +26,9 @@ object LoginService { withTimeout(180000) { while (isActive) { delay(3000) - val loginInfo = client.loginInfo(loginData.oauthKey!!) - if (loginInfo.status == true) { - val url = loginInfo.data!!.decode().url - val querys = URI(url).query.split("&") + val loginInfo = client.loginInfo(loginData.qrcodeKey!!)!! + if (loginInfo.code == 0) { + val querys = URI(loginInfo.url!!).query.split("&") val cookie = buildString { querys.forEach { if (it.contains("SESSDATA") || it.contains("bili_jct")) diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/tasker/ListenerTasker.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/tasker/ListenerTasker.kt index fbfe3f0..6fd9a75 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/tasker/ListenerTasker.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/tasker/ListenerTasker.kt @@ -42,6 +42,7 @@ object ListenerTasker : BiliTasker() { TriggerMode.Never -> f = false } if (f) { + val ms = subject.sendMessage("加载中...") val msg = message.filter { it !is At && it !is Image }.toMessageChain().content.trim() val type = matchingRegular(msg) val img = type?.drawGeneral() ?: return@subscribeAlways @@ -50,6 +51,7 @@ object ListenerTasker : BiliTasker() { + imgMsg if (returnLink) + PlainText(type.getLink()) }) + ms.recall() } } } diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/General.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/General.kt index 496476c..ecbf7f7 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/General.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/General.kt @@ -24,6 +24,7 @@ import top.colter.mirai.plugin.bilibili.data.DynamicItem import top.colter.mirai.plugin.bilibili.data.DynamicType.* import java.nio.file.Path import java.nio.file.attribute.FileTime +import java.security.MessageDigest import java.time.Duration import java.time.Instant import java.time.LocalDateTime @@ -38,7 +39,7 @@ internal val logger by lazy { try { BiliBiliDynamic.logger } catch (_: Throwable) { - MiraiLogger.Factory.create(BiliClient::class) + MiraiLogger.Factory.create(BiliBiliDynamic::class) } } @@ -459,3 +460,8 @@ inline fun matchUser(user: String, matchSuccess: (uid: Long) -> String?): String } } } + +fun String.md5(): String { + val md = MessageDigest.getInstance("MD5") + return md.digest(toByteArray()).joinToString("") { "%02x".format(it) } +} \ No newline at end of file diff --git a/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/JsonUtils.kt b/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/JsonUtils.kt index 3ccf678..1e75c21 100644 --- a/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/JsonUtils.kt +++ b/src/main/kotlin/top/colter/mirai/plugin/bilibili/utils/JsonUtils.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.decodeFromJsonElement import top.colter.mirai.plugin.bilibili.BiliBiliDynamic -import top.colter.mirai.plugin.bilibili.utils.translate.MD5 +import kotlin.io.path.appendText import kotlin.io.path.createDirectories import kotlin.io.path.notExists import kotlin.io.path.writeText @@ -23,17 +23,22 @@ inline fun JsonElement.decode(): T { return try { json.decodeFromJsonElement(this) }catch (e: SerializationException) { - val time = System.currentTimeMillis().formatTime("yyyy-MM-dd") - val md5 = MD5.md5(e.message) + val time = (System.currentTimeMillis() / 1000).formatTime("yyyy-MM-dd") + + val md5 = e.message?.md5() val fileName = "$time-$md5.json" BiliBiliDynamic.dataFolderPath.resolve("exception").apply { if (notExists()) createDirectories() }.resolve(fileName).apply { - if (notExists()) writeText(json.encodeToString(JsonElement.serializer(), this@decode)) + if (notExists()) { + writeText(e.stackTraceToString()) + appendText("\n\n\n") + appendText(json.encodeToString(JsonElement.serializer(), this@decode)) + } } - BiliBiliDynamic.logger.error("json解析失败,请把 /data/exception/ 目录下的 $fileName 文件反馈给开发者") + BiliBiliDynamic.logger.error("json解析失败,请把 /data/exception/ 目录下的 $fileName 文件反馈给开发者\n${e.message}") throw e } }