mirror of
https://github.com/SocialSisterYi/bilibili-API-collect.git
synced 2024-12-26 04:20:07 +08:00
为avid-bvid转换和Wbi签名添加Swift实现 (#890)
* Update bvid_desc.md * Update wbi.md
This commit is contained in:
parent
56bfa77a70
commit
27308c22c8
@ -192,6 +192,65 @@ print(bv2av("BV1L9Uoa9EUx"))
|
||||
|
||||
参考 <https://github.com/Colerar/abv/blob/main/src/lib.rs>
|
||||
|
||||
### Swift
|
||||
|
||||
```swift
|
||||
fileprivate let XOR_CODE: UInt64 = 23442827791579
|
||||
fileprivate let MASK_CODE: UInt64 = 2251799813685247
|
||||
fileprivate let MAX_AID: UInt64 = 1 << 51
|
||||
|
||||
fileprivate let data: [UInt8] = [70, 99, 119, 65, 80, 78, 75, 84, 77, 117, 103, 51, 71, 86, 53, 76, 106, 55, 69, 74, 110, 72, 112, 87, 115, 120, 52, 116, 98, 56, 104, 97, 89, 101, 118, 105, 113, 66, 122, 54, 114, 107, 67, 121, 49, 50, 109, 85, 83, 68, 81, 88, 57, 82, 100, 111, 90, 102]
|
||||
|
||||
fileprivate let BASE: UInt64 = 58
|
||||
fileprivate let BV_LEN: Int = 12
|
||||
fileprivate let PREFIX: String = "BV1"
|
||||
|
||||
func av2bv(avid: UInt64) -> String {
|
||||
var bytes: [UInt8] = [66, 86, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48]
|
||||
var bvIdx = BV_LEN - 1
|
||||
var tmp = (MAX_AID | avid) ^ XOR_CODE
|
||||
|
||||
while tmp != 0 {
|
||||
bytes[bvIdx] = data[Int(tmp % BASE)]
|
||||
tmp /= BASE
|
||||
bvIdx -= 1
|
||||
}
|
||||
|
||||
bytes.swapAt(3, 9)
|
||||
bytes.swapAt(4, 7)
|
||||
|
||||
return String(decoding: bytes, as: UTF8.self)
|
||||
}
|
||||
|
||||
func bv2av(bvid: String) -> UInt64 {
|
||||
let fixedBvid: String
|
||||
if bvid.hasPrefix("BV") {
|
||||
fixedBvid = bvid
|
||||
} else {
|
||||
fixedBvid = "BV" + bvid
|
||||
}
|
||||
var bvidArray = Array(fixedBvid.utf8)
|
||||
|
||||
bvidArray.swapAt(3, 9)
|
||||
bvidArray.swapAt(4, 7)
|
||||
|
||||
let trimmedBvid = String(decoding: bvidArray[3...], as: UTF8.self)
|
||||
|
||||
var tmp: UInt64 = 0
|
||||
|
||||
for char in trimmedBvid {
|
||||
if let idx = data.firstIndex(of: char.utf8.first!) {
|
||||
tmp = tmp * BASE + UInt64(idx)
|
||||
}
|
||||
}
|
||||
|
||||
return (tmp & MASK_CODE) ^ XOR_CODE
|
||||
}
|
||||
|
||||
print(av2bv(avid: 111298867365120))
|
||||
print(bv2av(bvid: "BV1L9Uoa9EUx"))
|
||||
```
|
||||
|
||||
## 老版算法存档
|
||||
|
||||
算法参考自[【揭秘】av号转bv号的过程](https://www.bilibili.com/video/BV1N741127Tj)
|
||||
|
@ -115,7 +115,7 @@
|
||||
|
||||
## Wbi签名算法实现Demo
|
||||
|
||||
该 Demo 提供 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)和[Java](#Java) 语言
|
||||
该 Demo 提供 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)和[Swift](#Swift) 语言
|
||||
|
||||
### Python
|
||||
|
||||
@ -816,3 +816,87 @@ async fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Swift
|
||||
|
||||
需要 [Alamofire](https://github.com/Alamofire/Alamofire) 和 [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON) 库
|
||||
|
||||
```swift
|
||||
import Foundation
|
||||
import CommonCrypto
|
||||
import Alamofire
|
||||
import SwiftyJSON
|
||||
|
||||
func biliWbiSign(param: String, completion: @escaping (String?) -> Void) {
|
||||
func getMixinKey(orig: String) -> String {
|
||||
return String(mixinKeyEncTab.map { orig[orig.index(orig.startIndex, offsetBy: $0)] }.prefix(32))
|
||||
}
|
||||
|
||||
func encWbi(params: [String: Any], imgKey: String, subKey: String) -> [String: Any] {
|
||||
var params = params
|
||||
let mixinKey = getMixinKey(orig: imgKey + subKey)
|
||||
let currTime = round(Date().timeIntervalSince1970)
|
||||
params["wts"] = currTime
|
||||
params = params.sorted { $0.key < $1.key }.reduce(into: [:]) { $0[$1.key] = $1.value }
|
||||
params = params.mapValues { String(describing: $0).filter { !"!'()*".contains($0) } }
|
||||
let query = params.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
|
||||
let wbiSign = calculateMD5(string: query + mixinKey)
|
||||
params["w_rid"] = wbiSign
|
||||
return params
|
||||
}
|
||||
|
||||
func getWbiKeys(completion: @escaping (Result<(imgKey: String, subKey: String), Error>) -> Void) {
|
||||
AF.request("https://api.bilibili.com/x/web-interface/nav").responseJSON { response in
|
||||
switch response.result {
|
||||
case .success(let value):
|
||||
let json = JSON(value)
|
||||
let imgURL = json["data"]["wbi_img"]["img_url"].string ?? ""
|
||||
let subURL = json["data"]["wbi_img"]["sub_url"].string ?? ""
|
||||
let imgKey = imgURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
|
||||
let subKey = subURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
|
||||
completion(.success((imgKey, subKey)))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calculateMD5(string: String) -> String {
|
||||
let data = Data(string.utf8)
|
||||
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
|
||||
_ = data.withUnsafeBytes {
|
||||
CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
|
||||
}
|
||||
return digest.map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
|
||||
let 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
|
||||
]
|
||||
|
||||
getWbiKeys { result in
|
||||
switch result {
|
||||
case .success(let keys):
|
||||
let spdParam = param.components(separatedBy: "&")
|
||||
var spdDicParam = [String: String]()
|
||||
spdParam.forEach { pair in
|
||||
let components = pair.components(separatedBy: "=")
|
||||
if components.count == 2 {
|
||||
spdDicParam[components[0]] = components[1]
|
||||
}
|
||||
}
|
||||
|
||||
let signedParams = encWbi(params: spdDicParam, imgKey: keys.imgKey, subKey: keys.subKey)
|
||||
let query = signedParams.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
|
||||
completion(query)
|
||||
case .failure(let error):
|
||||
print("Error getting keys: \(error)")
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user