From 2ca9272972d82f56037b5c5c73f55878741712ca Mon Sep 17 00:00:00 2001 From: Kataick <24969684+Kataick@users.noreply.github.com> Date: Sat, 23 Nov 2024 14:12:24 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs(message):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=A7=81=E4=BF=A1=E6=B6=88=E6=81=AF=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/message/private_msg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/message/private_msg.md b/docs/message/private_msg.md index ae4e11e..c81cbab 100644 --- a/docs/message/private_msg.md +++ b/docs/message/private_msg.md @@ -738,7 +738,7 @@ curl -G 'https://api.vc.bilibili.com/session_svr/v1/session_svr/session_detail' | ----------------- | ---- | ---------------- | ------ | ------------------------------------------------------ | | talker_id | num | 聊天对象的id | 必要 | `session_type` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | | session_type | num | 聊天对象的类型 | 必要 | 1:用户
2:粉丝团 | -| size | num | 返回消息数量 | 非必要 | 默认为 20,最大为 200 | +| size | num | 返回消息数量 | 必要 | 默认为 0,最大为 200 | | begin_seqno | num | 开始的序列号 | 非必要 | 提供本参数时返回以本序列号开始(不包括本序列号)的消息 | | end_seqno | num | 结束的序列号 | 非必要 | 提供本参数时返回以本序列号结束(不包括本序列号)的消息 | | sender_device_id | num | 发送者设备 | 非必要 | 默认为 `1` | From b65aaf93127d738a123d041a45910dd3afae6993 Mon Sep 17 00:00:00 2001 From: Kataick <24969684+Kataick@users.noreply.github.com> Date: Mon, 14 Apr 2025 22:39:24 +0800 Subject: [PATCH 2/8] =?UTF-8?q?@Kataick=20docs(message):=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=8F=91=E9=80=81=E7=A7=81=E4=BF=A1=E6=96=87=E6=A1=A3?= =?UTF-8?q?(wbi)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/message/private_msg.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/message/private_msg.md b/docs/message/private_msg.md index ae4e11e..610ce01 100644 --- a/docs/message/private_msg.md +++ b/docs/message/private_msg.md @@ -1253,10 +1253,22 @@ curl 'https://api.vc.bilibili.com/session_svr/v1/session_svr/update_ack' \ 认证方式:Cookie(SESSDATA) +鉴权方式:[Wbi 签名](../misc/sign/wbi.md) + **仅支持发送 `msg[msg_type]` 为 `1`、`2` 或 `5` 的私信** 调用该接口同时会将该会话设置为已读 +**URL参数:** + +| 参数名 | 类型 | 内容 | 必要性 | 备注 | +| --- | --- | --- | --- | --- | +| w_sender_uid | num | 发送者mid | 必要 | 必须为自己的 mid | +| w_receiver_id | num | 接收者id | 必要 | `w_receiver_id` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | +| w_dev_id | str | 设备id | 必要 | 实质上即 UUID(版本 4),**生成方式见下** | +| w_rid | str | Wbi 签名 | 必要 | 参见 [Wbi 签名](../misc/sign/wbi.md) | +| wts | str | UNIX 秒级时间戳 | 必要 | 参见 [Wbi 签名](../misc/sign/wbi.md) | + **正文参数(application/x-www-form-urlencoded):** | 参数名 | 类型 | 内容 | 必要性 | 备注 | From 52f0d2b3799807d95851da3f30610ac1ee7f9f88 Mon Sep 17 00:00:00 2001 From: Kataick <24969684+Kataick@users.noreply.github.com> Date: Mon, 14 Apr 2025 23:44:43 +0800 Subject: [PATCH 3/8] update --- docs/message/private_msg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/message/private_msg.md b/docs/message/private_msg.md index c81cbab..37bffaa 100644 --- a/docs/message/private_msg.md +++ b/docs/message/private_msg.md @@ -738,7 +738,7 @@ curl -G 'https://api.vc.bilibili.com/session_svr/v1/session_svr/session_detail' | ----------------- | ---- | ---------------- | ------ | ------------------------------------------------------ | | talker_id | num | 聊天对象的id | 必要 | `session_type` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | | session_type | num | 聊天对象的类型 | 必要 | 1:用户
2:粉丝团 | -| size | num | 返回消息数量 | 必要 | 默认为 0,最大为 200 | +| size | num | 返回消息数量 | 非必要 | 默认为 0,最大为 200
本参数不存在时,只返回系统提示 | | begin_seqno | num | 开始的序列号 | 非必要 | 提供本参数时返回以本序列号开始(不包括本序列号)的消息 | | end_seqno | num | 结束的序列号 | 非必要 | 提供本参数时返回以本序列号结束(不包括本序列号)的消息 | | sender_device_id | num | 发送者设备 | 非必要 | 默认为 `1` | From 0f804d9752776fe1e847069d618bddbb0e53fbc0 Mon Sep 17 00:00:00 2001 From: Kataick <24969684+Kataick@users.noreply.github.com> Date: Mon, 14 Apr 2025 23:46:02 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E9=97=B4=E9=9A=94=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/message/private_msg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/message/private_msg.md b/docs/message/private_msg.md index 37bffaa..57bf156 100644 --- a/docs/message/private_msg.md +++ b/docs/message/private_msg.md @@ -738,7 +738,7 @@ curl -G 'https://api.vc.bilibili.com/session_svr/v1/session_svr/session_detail' | ----------------- | ---- | ---------------- | ------ | ------------------------------------------------------ | | talker_id | num | 聊天对象的id | 必要 | `session_type` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | | session_type | num | 聊天对象的类型 | 必要 | 1:用户
2:粉丝团 | -| size | num | 返回消息数量 | 非必要 | 默认为 0,最大为 200
本参数不存在时,只返回系统提示 | +| size | num | 返回消息数量 | 非必要 | 默认为 0,最大为 200
本参数不存在时,只返回系统提示 | | begin_seqno | num | 开始的序列号 | 非必要 | 提供本参数时返回以本序列号开始(不包括本序列号)的消息 | | end_seqno | num | 结束的序列号 | 非必要 | 提供本参数时返回以本序列号结束(不包括本序列号)的消息 | | sender_device_id | num | 发送者设备 | 非必要 | 默认为 `1` | From 0a3c04ae2d3bc3db7261f2a74660289633ab7a3a Mon Sep 17 00:00:00 2001 From: SessionHu <102411014+SessionHu@users.noreply.github.com> Date: Tue, 15 Apr 2025 00:13:44 +0800 Subject: [PATCH 5/8] fix(wallet/info.md): typo --- docs/wallet/info.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/wallet/info.md b/docs/wallet/info.md index e15fafe..24f02c3 100644 --- a/docs/wallet/info.md +++ b/docs/wallet/info.md @@ -38,13 +38,13 @@ | mid | num | 用户 mid | | | totalBp | num | 总计 B 币 | | | defaultBp | num | 默认 B 币? | | -| isoBp | num | iOS B 币? | | +| iosBp | num | iOS B 币? | | | couponBalance | num | 优惠券余额 | | | availableBp | num | 可用 B 币 | | | unavailableBp | num | 不可用 B 币 | | | unavailableReason | str | 不可用原因 | | | tip | str | 请XXXXX | 请投币?? | -| needShowClassBalance | num | 需要显示类平衡?? | 1 | +| needShowClassBalance | num | 需要显示类余额?? | 1 | **示例:** From ad1d2dd96dc3285e0ed3941796fb2ed2ed237536 Mon Sep 17 00:00:00 2001 From: SessionHu <102411014+SessionHu@users.noreply.github.com> Date: Thu, 17 Apr 2025 00:00:34 +0800 Subject: [PATCH 6/8] feat(misc/sign/wbi.md): haskell demo --- docs/misc/sign/wbi.md | 128 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/docs/misc/sign/wbi.md b/docs/misc/sign/wbi.md index 86311d3..003e798 100644 --- a/docs/misc/sign/wbi.md +++ b/docs/misc/sign/wbi.md @@ -121,7 +121,7 @@ ## Demo -含 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)、[Kotlin](#Kotlin)、[Swift](#Swift)、[C++](#CPlusPlus)、[Rust](#Rust) 语言编写的 Demo 。 +含 [Python](#python)、[JavaScript](#javascript)、[Golang](#golang)、[C#](#csharp)、[Java](#java)、[Kotlin](#kotlin)、[Swift](#swift)、[C++](#cplusplus)、[Rust](#rust)、[Haskell](#haskell) 语言编写的 Demo 。 ### Python @@ -1341,3 +1341,129 @@ int main() { ```text avid=1755630705&cid=1574294582&fnval=4048&fnver=0&fourk=1&qn=32&wts=1717922933&w_rid=43571b838a1611fa121189083cfc1784 ``` + +### Haskell + +无第三方依赖: `base`, `Cabal-syntax`, `bytestring`, `containers`
+注: 此处使用自写的 URI 编码模块, 实际可用别的第三方库替代 + +`Main.hs`: +```hs +module Main (wbi, main) where + +import Data.ByteString.Char8 (pack) +import qualified Data.Map.Strict as Map +import Distribution.Utils.MD5 (md5, showMD5) +import URIEncoder (encodeURIComponent) + +mixinKeyEncTab :: [Int] +mixinKeyEncTab = [ + 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 + ] + +getMixinKey :: String -> String -> String +getMixinKey imgKey subKey = + let s = imgKey ++ subKey + in map (\i -> s !! (mixinKeyEncTab !! i)) [0..31] + +join :: [String] -> String -> String +join arr ins = concatMap (++ ins) (init arr) ++ last arr + +wbi :: String -> String -> Integer -> Map.Map String String -> String +wbi imgKey subKey wts params = + let orig = join (map (\(k, v) -> encodeURIComponent k ++ "=" ++ encodeURIComponent v) (Map.toList $ Map.insert "wts" (show wts) params)) "&" + in orig ++ "&w_rid=" ++ showMD5 (md5 $ pack $ orig ++ getMixinKey imgKey subKey) + +main :: IO () +main = -- hard encode for test + let params = Map.fromList [("foo", "114") + ,("bar", "514") + ,("hello", "世 界") + ] + wts = 1702204169 + imgKey = "7cd084941338484aae1ad9425b84077c" + subKey = "4932caff0ff746eab6f01bf08b70ac45" + in putStrLn $ wbi imgKey subKey wts params +``` + +`URIEncoder.hs`: +```hs +module URIEncoder (encodeURIComponent) where + +import Data.Char (ord, chr, intToDigit) +import Data.Bits (shiftL, shiftR, (.&.)) +import Data.List (isInfixOf) + +-- ES 19.2.6.4 encodeURIComponent ( uriComponent ) +encodeURIComponent :: String -> String +encodeURIComponent input = case encode input "" of + Right result -> result + Left err -> error err + +-- ES 19.2.6.5 Encode ( string, extraUnescaped ) +encode :: String -> String -> Either String String +encode string extraUnescaped = loop 0 string + where + alwaysUnescaped = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "-.!~*'()" + unescapedSet = alwaysUnescaped ++ extraUnescaped + + loop k str + | k >= length str = Right [] + | otherwise = case codePointAt str k of + (Nothing, _) -> Left "Unpaired surrogate" + (Just (cp, _), newK) -> + if [str !! k] `isInfixOf` unescapedSet + then (str !! k :) <$> loop (k + 1) str + else do + bytes <- utf8Encode cp + let escaped = concatMap percentEncode bytes + rest <- loop newK str + Right (escaped ++ rest) + +codePointAt :: String -> Int -> (Maybe (Int, Int), Int) +codePointAt s k + | k >= length s = (Nothing, k) + | otherwise = + let c1 = ord (s !! k) + in if 0xD800 <= c1 && c1 <= 0xDBFF && k+1 < length s + then let c2 = ord (s !! (k+1)) + in if 0xDC00 <= c2 && c2 <= 0xDFFF + then ( Just (0x10000 + ((c1 - 0xD800) `shiftL` 10) + (c2 - 0xDC00), 2) + , k + 2 ) + else (Just (c1, 1), k + 1) + else (Just (c1, 1), k + 1) + +utf8Encode :: Int -> Either String [Int] +utf8Encode cp + | cp < 0 = Left "Invalid code point" + | cp <= 0x007F = Right [cp] + | cp <= 0x07FF = Right + [ 0xC0 + (cp `shiftR` 6) + , 0x80 + (cp .&. 0x3F) ] + | cp <= 0xFFFF = Right + [ 0xE0 + (cp `shiftR` 12) + , 0x80 + ((cp `shiftR` 6) .&. 0x3F) + , 0x80 + (cp .&. 0x3F) ] + | cp <= 0x10FFFF = Right + [ 0xF0 + (cp `shiftR` 18) + , 0x80 + ((cp `shiftR` 12) .&. 0x3F) + , 0x80 + ((cp `shiftR` 6) .&. 0x3F) + , 0x80 + (cp .&. 0x3F) ] + | otherwise = Left "Code point out of range" + +percentEncode :: Int -> String +percentEncode byte = '%' : toHex byte + where + toHex n = [hexDigit (n `div` 16), hexDigit (n `mod` 16)] + hexDigit x + | x < 10 = intToDigit x + | otherwise = chr (x - 10 + ord 'A') +``` + +输出: +```text +bar=514&foo=114&hello=%E4%B8%96%20%E7%95%8C&wts=1702204169&w_rid=89f9002a49e1d13c07a28054a1cc2614 +``` From 526b0374c0ba58c7a1266762f464f5a5579b02ce Mon Sep 17 00:00:00 2001 From: SessionHu <102411014+SessionHu@users.noreply.github.com> Date: Thu, 17 Apr 2025 01:08:47 +0800 Subject: [PATCH 7/8] feat(misc/sign/wbi.md): update haskell demo data --- docs/misc/sign/wbi.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/misc/sign/wbi.md b/docs/misc/sign/wbi.md index 003e798..23eae00 100644 --- a/docs/misc/sign/wbi.md +++ b/docs/misc/sign/wbi.md @@ -1355,6 +1355,7 @@ import Data.ByteString.Char8 (pack) import qualified Data.Map.Strict as Map import Distribution.Utils.MD5 (md5, showMD5) import URIEncoder (encodeURIComponent) +import Data.Time.Clock.System (getSystemTime, systemSeconds) mixinKeyEncTab :: [Int] mixinKeyEncTab = [ @@ -1378,15 +1379,18 @@ wbi imgKey subKey wts params = in orig ++ "&w_rid=" ++ showMD5 (md5 $ pack $ orig ++ getMixinKey imgKey subKey) main :: IO () -main = -- hard encode for test - let params = Map.fromList [("foo", "114") +main = do -- hard encode for test + let params1 = Map.fromList [("aid", "2")] + params2 = Map.fromList [("foo", "114") ,("bar", "514") ,("hello", "世 界") ] - wts = 1702204169 imgKey = "7cd084941338484aae1ad9425b84077c" subKey = "4932caff0ff746eab6f01bf08b70ac45" - in putStrLn $ wbi imgKey subKey wts params + wts1 <- getSystemTime + putStrLn $ wbi imgKey subKey (toInteger $ systemSeconds wts1) params1 + wts2 <- getSystemTime + putStrLn $ wbi imgKey subKey (toInteger $ systemSeconds wts2) params2 ``` `URIEncoder.hs`: @@ -1465,5 +1469,6 @@ percentEncode byte = '%' : toHex byte 输出: ```text -bar=514&foo=114&hello=%E4%B8%96%20%E7%95%8C&wts=1702204169&w_rid=89f9002a49e1d13c07a28054a1cc2614 +aid=2&wts=1744823207&w_rid=a3cd246bd42c066932752b24694eaf0d +bar=514&foo=114&hello=%E4%B8%96%20%E7%95%8C&wts=1744823207&w_rid=93acf59d85f74453e40cea00056c3daf ``` From 5c303a22e48ad1d9e3e534e46a60fcb244605631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E5=8F=B6=E6=A2=A6=E6=98=A5?= <65224318+wuziqian211@users.noreply.github.com> Date: Thu, 17 Apr 2025 21:25:52 +0800 Subject: [PATCH 8/8] Update private_msg.md --- docs/message/private_msg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/message/private_msg.md b/docs/message/private_msg.md index 36b5fd2..edc113f 100644 --- a/docs/message/private_msg.md +++ b/docs/message/private_msg.md @@ -1264,7 +1264,7 @@ curl 'https://api.vc.bilibili.com/session_svr/v1/session_svr/update_ack' \ | 参数名 | 类型 | 内容 | 必要性 | 备注 | | --- | --- | --- | --- | --- | | w_sender_uid | num | 发送者mid | 必要 | 必须为自己的 mid | -| w_receiver_id | num | 接收者id | 必要 | `w_receiver_id` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | +| w_receiver_id | num | 接收者id | 必要 | 请求参数 `msg[receiver_type]` 为 `1` 时表示用户 mid,为 `2` 时表示粉丝团 id | | w_dev_id | str | 设备id | 必要 | 实质上即 UUID(版本 4),**生成方式见下** | | w_rid | str | Wbi 签名 | 必要 | 参见 [Wbi 签名](../misc/sign/wbi.md) | | wts | str | UNIX 秒级时间戳 | 必要 | 参见 [Wbi 签名](../misc/sign/wbi.md) |