Support anonymous connect to ws server

This commit is contained in:
2026-09-01 01:13:40 +08:00
parent 559581d33f
commit f5aa7400a8
8 files changed
+56 -42

No files matched your search

@@ -7,16 +7,15 @@
package cn.rtast.bldm.client package cn.rtast.bldm.client
import cn.rtast.bldm.client.util.fromJson import cn.rtast.bldm.client.util.fromJson
import cn.rtast.bldm.client.util.parseBuvidAndUid
import cn.rtast.bldm.client.util.sendPacket import cn.rtast.bldm.client.util.sendPacket
import cn.rtast.bldm.codec.event.DanmuEventDispatcher import cn.rtast.bldm.codec.event.DanmuEventDispatcher
import cn.rtast.bldm.codec.protocol.codec.PacketDecoder import cn.rtast.bldm.codec.protocol.codec.PacketDecoder
import cn.rtast.bldm.codec.protocol.codec.PacketEncoder import cn.rtast.bldm.codec.protocol.codec.PacketEncoder
import cn.rtast.bldm.codec.util.parseBuvidAndUid
import cn.rtast.bldm.codec.util.signWbi import cn.rtast.bldm.codec.util.signWbi
import cn.rtast.bldm.dto.BldmConstant import cn.rtast.bldm.dto.*
import cn.rtast.bldm.dto.DMServerConf import io.ktor.client.*
import cn.rtast.bldm.dto.RealRoomId import io.ktor.client.plugins.*
import cn.rtast.bldm.dto.UserNavData
import io.ktor.client.plugins.websocket.* import io.ktor.client.plugins.websocket.*
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.client.statement.* import io.ktor.client.statement.*
@@ -31,6 +30,16 @@ public class BldmClient internal constructor(
) : DanmuEventDispatcher(), AutoCloseable { ) : DanmuEventDispatcher(), AutoCloseable {
private companion object { private companion object {
private val HEARTBEAT_INTERVAL = 30.seconds private val HEARTBEAT_INTERVAL = 30.seconds
private const val USER_AGENT =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36"
}
private val httpClient = HttpClient {
install(WebSockets)
defaultRequest {
header(HttpHeaders.UserAgent, USER_AGENT)
}
} }
private val packetEncoder = PacketEncoder() private val packetEncoder = PacketEncoder()
@@ -39,8 +48,12 @@ public class BldmClient internal constructor(
private var connectionJob: Job? = null private var connectionJob: Job? = null
private var session: DefaultClientWebSocketSession? = null private var session: DefaultClientWebSocketSession? = null
private suspend fun getBuvidFromApi(): String =
httpClient.get(BldmConstant.BUVID_URL)
.bodyAsText().fromJson<Buvid>()
.data.buvid
private suspend fun internalConnect() { private suspend fun internalConnect() {
val parsedCookie = parseBuvidAndUid(cookie ?: "")
val realRoomId = httpClient.get(BldmConstant.REAL_ROOM_ID_URL + "?id=$roomId") val realRoomId = httpClient.get(BldmConstant.REAL_ROOM_ID_URL + "?id=$roomId")
.bodyAsText().fromJson<RealRoomId>() .bodyAsText().fromJson<RealRoomId>()
val navData = httpClient.get(BldmConstant.USER_NAV_URL) val navData = httpClient.get(BldmConstant.USER_NAV_URL)
@@ -49,14 +62,13 @@ public class BldmClient internal constructor(
val serverConf = httpClient.get(BldmConstant.DM_SERVER_CONF_URL + "?$wbi") { val serverConf = httpClient.get(BldmConstant.DM_SERVER_CONF_URL + "?$wbi") {
cookie?.let { header(HttpHeaders.Cookie, it) } cookie?.let { header(HttpHeaders.Cookie, it) }
}.bodyAsText().fromJson<DMServerConf>().data }.bodyAsText().fromJson<DMServerConf>().data
val parsedCookie = parseBuvidAndUid(cookie ?: "")
val buvid = if (cookie == null) getBuvidFromApi() else parsedCookie.first!!
val uid = if (cookie == null) 0 else parsedCookie.second!!
httpClient.webSocket(serverConf.hostList.first().tlsWsAddress) { httpClient.webSocket(serverConf.hostList.first().tlsWsAddress) {
session = this session = this
val authPacket = packetEncoder.authPacket( val authPacket = packetEncoder.authPacket(
parsedCookie.second ?: 0, uid, realRoomId.data.roomId, buvid, serverConf.token
realRoomId.data.roomId,
parsedCookie.first ?: "",
serverConf.token
) )
sendPacket(authPacket) sendPacket(authPacket)
val heartbeatJob = launch { val heartbeatJob = launch {
@@ -1,25 +0,0 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/8/30
*/
package cn.rtast.bldm.client
import io.ktor.client.*
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.plugins.websocket.*
import io.ktor.client.request.header
import io.ktor.http.HttpHeaders
internal val httpClient = HttpClient {
install(WebSockets)
defaultRequest {
header(HttpHeaders.UserAgent, USER_AGENT)
}
}
internal const val USER_AGENT =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36"
@@ -5,7 +5,7 @@
*/ */
package cn.rtast.bldm.codec.util package cn.rtast.bldm.client.util
/** /**
* get buvid and uid from a cookie * get buvid and uid from a cookie
@@ -9,14 +9,12 @@ package test
import cn.rtast.bldm.client.BLDMClient import cn.rtast.bldm.client.BLDMClient
import cn.rtast.bldm.codec.event.DanmuEvent import cn.rtast.bldm.codec.event.DanmuEvent
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.io.buffered import kotlinx.io.buffered
import kotlinx.io.files.Path import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem import kotlinx.io.files.SystemFileSystem
import kotlinx.io.readString import kotlinx.io.readString
import kotlin.test.Test import kotlin.test.Test
import kotlin.time.Duration.Companion.seconds
class TestClient { class TestClient {
@@ -25,7 +23,7 @@ class TestClient {
@Test @Test
fun `test bldm client`() = runTest { fun `test bldm client`() = runTest {
val client = BLDMClient(7777, cookie) val client = BLDMClient(55, null)
client.on<DanmuEvent.HeartbeatEvent> { println("Heartbeat") } client.on<DanmuEvent.HeartbeatEvent> { println("Heartbeat") }
client.on<DanmuEvent.AuthReplyEvent> { println("AuthReply") } client.on<DanmuEvent.AuthReplyEvent> { println("AuthReply") }
client.on<DanmuEvent.MessageEvent> { println(it.content) } client.on<DanmuEvent.MessageEvent> { println(it.content) }
@@ -10,6 +10,7 @@ package cn.rtast.bldm.dto
public object BldmConstant { public object BldmConstant {
public const val REAL_ROOM_ID_URL: String = "https://api.live.bilibili.com/room/v1/Room/room_init" public const val REAL_ROOM_ID_URL: String = "https://api.live.bilibili.com/room/v1/Room/room_init"
public const val USER_NAV_URL: String = "https://api.bilibili.com/x/web-interface/nav" public const val USER_NAV_URL: String = "https://api.bilibili.com/x/web-interface/nav"
public const val BUVID_URL: String = "https://api.bilibili.com/x/web-frontend/getbuvid"
public const val DM_SERVER_CONF_URL: String = public const val DM_SERVER_CONF_URL: String =
"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo" "https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo"
} }
@@ -0,0 +1,16 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/8/31
*/
package cn.rtast.bldm.dto
import kotlinx.serialization.Serializable
@Serializable
public data class Buvid(val data: BuvidData) {
@Serializable
public data class BuvidData(val buvid: String)
}
+13 -1
View File
@@ -20,12 +20,24 @@ subprojects {
publishing { publishing {
repositories { repositories {
maven("https://repo.maven.rtast.cn/snapshots") { maven("https://repo.maven.rtast.cn/releases") {
name = "RTAST-PKG"
credentials { credentials {
username = "RTAkland" username = "RTAkland"
password = System.getenv("PUBLISH_TOKEN") password = System.getenv("PUBLISH_TOKEN")
} }
} }
maven("https://repo.rtast.cn/packages") {
name = "RTAST-GIT"
credentials(HttpHeaderCredentials::class) {
name = "Authorization"
value = "Bearer ${System.getenv("PUBLISH_TOKEN")}"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
} }
} }
} }
+1 -1
View File
@@ -2,4 +2,4 @@ kotlin.code.style=official
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError
kotlin.native.ignoreDisabledTargets=true kotlin.native.ignoreDisabledTargets=true
libVersion=0.1.0 libVersion=0.1.1