Skip to content

Commit aef4d8e

Browse files
committed
misc: 独立wbiSign代码,修改缓存判断
1 parent f4a851d commit aef4d8e

File tree

3 files changed

+145
-129
lines changed

3 files changed

+145
-129
lines changed

BilibiliLive.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
492AD7112C001C7B007221C8 /* BVideoPlayPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492AD7102C001C7B007221C8 /* BVideoPlayPlugin.swift */; };
3131
492AD7132C001CA7007221C8 /* String+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492AD7122C001CA7007221C8 /* String+Error.swift */; };
3232
493307FD2BF230DB003622ED /* LivePlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493307FC2BF230DB003622ED /* LivePlayerViewModel.swift */; };
33+
4933B8912CFC1B070056B04D /* WebRequest+WbiSign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4933B8902CFC1B070056B04D /* WebRequest+WbiSign.swift */; };
3334
49389D6228AFEA2900B9DAFD /* VideoDanmuProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49389D6128AFEA2900B9DAFD /* VideoDanmuProvider.swift */; };
3435
49389D8928B0A1B700B9DAFD /* UIViewController+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49389D8828B0A1B700B9DAFD /* UIViewController+Ext.swift */; };
3536
49389D8C28B0A84500B9DAFD /* PersonalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49389D8B28B0A84500B9DAFD /* PersonalViewController.swift */; };
@@ -179,6 +180,7 @@
179180
492AD7102C001C7B007221C8 /* BVideoPlayPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BVideoPlayPlugin.swift; sourceTree = "<group>"; };
180181
492AD7122C001CA7007221C8 /* String+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Error.swift"; sourceTree = "<group>"; };
181182
493307FC2BF230DB003622ED /* LivePlayerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LivePlayerViewModel.swift; sourceTree = "<group>"; };
183+
4933B8902CFC1B070056B04D /* WebRequest+WbiSign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebRequest+WbiSign.swift"; sourceTree = "<group>"; };
182184
49389D6128AFEA2900B9DAFD /* VideoDanmuProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDanmuProvider.swift; sourceTree = "<group>"; };
183185
49389D8828B0A1B700B9DAFD /* UIViewController+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Ext.swift"; sourceTree = "<group>"; };
184186
49389D8B28B0A84500B9DAFD /* PersonalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalViewController.swift; sourceTree = "<group>"; };
@@ -632,6 +634,7 @@
632634
0A41EE1A2A63102B0066444C /* dm.pb.swift */,
633635
0A41EE1B2A63102B0066444C /* dmView.pb.swift */,
634636
49D39F27263AD40000F14497 /* WebRequest.swift */,
637+
4933B8902CFC1B070056B04D /* WebRequest+WbiSign.swift */,
635638
F9D382B326359EF90070508F /* ApiRequest.swift */,
636639
F927ED8F2610A5E900EAB8E3 /* CookieManager.swift */,
637640
4921389F2CD5CA6000891D56 /* SponsorBlockRequest.swift */,
@@ -975,6 +978,7 @@
975978
49A441CD293F6DFD0007606C /* FollowUpsViewController.swift in Sources */,
976979
AEA6AB1928FFF3DD007CE72E /* Settings.swift in Sources */,
977980
498CF2962B63AABE0009793E /* block_splitter.c in Sources */,
981+
4933B8912CFC1B070056B04D /* WebRequest+WbiSign.swift in Sources */,
978982
494741C6290177BB005D6885 /* UpSpaceViewController.swift in Sources */,
979983
496E5A552C01CDBB0062951B /* DebugPlugin.swift in Sources */,
980984
49DA01A0296C466C00EEAE15 /* AVInfoPanelCollectionViewThumbnailCell+Hook.swift in Sources */,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//
2+
// WebRequest+WbiSign.swift
3+
// BilibiliLive
4+
//
5+
// Created by yicheng on 1/12/2024.
6+
//
7+
8+
import Alamofire
9+
import CommonCrypto
10+
import SwiftyJSON
11+
12+
extension WebRequest {
13+
static func addWbiSign(method: HTTPMethod = .get,
14+
url: URLConvertible,
15+
parameters: Parameters = [:],
16+
onComplete: @escaping (String?) -> Void)
17+
{
18+
do {
19+
let urlObj = try url.asURL()
20+
if urlObj.absoluteString.contains("/wbi/") == true, method == .get {
21+
var request = URLRequest(url: urlObj)
22+
request.method = .get
23+
request = try URLEncoding.queryString.encode(request, with: parameters)
24+
if let query = request.url?.query(percentEncoded: true) {
25+
biliWbiSign(param: query) { res in
26+
if let res {
27+
let urlString = urlObj.absoluteString + "?" + res
28+
onComplete(urlString)
29+
return
30+
} else {
31+
onComplete(nil)
32+
}
33+
}
34+
return
35+
}
36+
}
37+
onComplete(nil)
38+
} catch {
39+
onComplete(nil)
40+
}
41+
}
42+
43+
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md#Swift
44+
private static func biliWbiSign(param: String, completion: @escaping (String?) -> Void) {
45+
func getMixinKey(orig: String) -> String {
46+
return String(mixinKeyEncTab.map { orig[orig.index(orig.startIndex, offsetBy: $0)] }.prefix(32))
47+
}
48+
49+
func encWbi(params: [String: Any], imgKey: String, subKey: String) -> [String: Any] {
50+
var params = params
51+
let mixinKey = getMixinKey(orig: imgKey + subKey)
52+
let currTime = round(Date().timeIntervalSince1970)
53+
params["wts"] = currTime
54+
params = params.sorted { $0.key < $1.key }.reduce(into: [:]) { $0[$1.key] = $1.value }
55+
params = params.mapValues { String(describing: $0).filter { !"!'()*".contains($0) } }
56+
let query = params.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
57+
let wbiSign = calculateMD5(string: query + mixinKey)
58+
params["w_rid"] = wbiSign
59+
return params
60+
}
61+
62+
func getWbiKeys(completion: @escaping (Result<(imgKey: String, subKey: String), Error>) -> Void) {
63+
class Cache {
64+
var imgKey: String?
65+
var subKey: String?
66+
var lastUpdate: Date?
67+
68+
static let shared = Cache()
69+
}
70+
71+
if let imgKey = Cache.shared.imgKey,
72+
let subKey = Cache.shared.subKey,
73+
let lastUpdate = Cache.shared.lastUpdate,
74+
Date().timeIntervalSince(lastUpdate) < 60 * 60 * 12,
75+
Calendar.current.isDate(Date(), inSameDayAs: lastUpdate)
76+
{
77+
completion(.success((imgKey, subKey)))
78+
return
79+
}
80+
81+
let headers: HTTPHeaders = [
82+
"User-Agent": Keys.userAgent,
83+
"Referer": Keys.referer,
84+
]
85+
86+
AF.request("https://api.bilibili.com/x/web-interface/nav", headers: headers).responseData { response in
87+
switch response.result {
88+
case let .success(value):
89+
let json = JSON(value)
90+
let imgURL = json["data"]["wbi_img"]["img_url"].string ?? ""
91+
let subURL = json["data"]["wbi_img"]["sub_url"].string ?? ""
92+
let imgKey = imgURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
93+
let subKey = subURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
94+
Cache.shared.imgKey = imgKey
95+
Cache.shared.subKey = subKey
96+
Cache.shared.lastUpdate = Date()
97+
completion(.success((imgKey, subKey)))
98+
case let .failure(error):
99+
completion(.failure(error))
100+
}
101+
}
102+
}
103+
104+
func calculateMD5(string: String) -> String {
105+
let data = Data(string.utf8)
106+
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
107+
_ = data.withUnsafeBytes {
108+
CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
109+
}
110+
return digest.map { String(format: "%02hhx", $0) }.joined()
111+
}
112+
113+
let mixinKeyEncTab = [
114+
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
115+
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
116+
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
117+
36, 20, 34, 44, 52,
118+
]
119+
120+
getWbiKeys { result in
121+
switch result {
122+
case let .success(keys):
123+
let spdParam = param.components(separatedBy: "&")
124+
var spdDicParam = [String: String]()
125+
spdParam.forEach { pair in
126+
let components = pair.components(separatedBy: "=")
127+
if components.count == 2 {
128+
spdDicParam[components[0]] = components[1]
129+
}
130+
}
131+
132+
let signedParams = encWbi(params: spdDicParam, imgKey: keys.imgKey, subKey: keys.subKey)
133+
let query = signedParams.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
134+
completion(query)
135+
case let .failure(error):
136+
print("Error getting keys: \(error)")
137+
completion(nil)
138+
}
139+
}
140+
}
141+
}

BilibiliLive/Request/WebRequest.swift

-129
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77

88
import Alamofire
9-
import CommonCrypto
109
import Foundation
1110
import SwiftProtobuf
1211
import SwiftyJSON
@@ -113,36 +112,6 @@ enum WebRequest {
113112
}
114113
}
115114

116-
private static func addWbiSign(method: HTTPMethod = .get,
117-
url: URLConvertible,
118-
parameters: Parameters = [:],
119-
onComplete: @escaping (String?) -> Void)
120-
{
121-
do {
122-
let urlObj = try url.asURL()
123-
if urlObj.absoluteString.contains("/wbi/") == true, method == .get {
124-
var request = URLRequest(url: urlObj)
125-
request.method = .get
126-
request = try URLEncoding.queryString.encode(request, with: parameters)
127-
if let query = request.url?.query(percentEncoded: true) {
128-
biliWbiSign(param: query) { res in
129-
if let res {
130-
let urlString = urlObj.absoluteString + "?" + res
131-
onComplete(urlString)
132-
return
133-
} else {
134-
onComplete(nil)
135-
}
136-
}
137-
return
138-
}
139-
}
140-
onComplete(nil)
141-
} catch {
142-
onComplete(nil)
143-
}
144-
}
145-
146115
static func requestJSON(method: HTTPMethod = .get,
147116
url: URLConvertible,
148117
parameters: Parameters = [:],
@@ -550,104 +519,6 @@ extension WebRequest {
550519
}
551520
}
552521

553-
// MARK: - Wbi
554-
555-
extension WebRequest {
556-
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md#Swift
557-
static func biliWbiSign(param: String, completion: @escaping (String?) -> Void) {
558-
func getMixinKey(orig: String) -> String {
559-
return String(mixinKeyEncTab.map { orig[orig.index(orig.startIndex, offsetBy: $0)] }.prefix(32))
560-
}
561-
562-
func encWbi(params: [String: Any], imgKey: String, subKey: String) -> [String: Any] {
563-
var params = params
564-
let mixinKey = getMixinKey(orig: imgKey + subKey)
565-
let currTime = round(Date().timeIntervalSince1970)
566-
params["wts"] = currTime
567-
params = params.sorted { $0.key < $1.key }.reduce(into: [:]) { $0[$1.key] = $1.value }
568-
params = params.mapValues { String(describing: $0).filter { !"!'()*".contains($0) } }
569-
let query = params.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
570-
let wbiSign = calculateMD5(string: query + mixinKey)
571-
params["w_rid"] = wbiSign
572-
return params
573-
}
574-
575-
func getWbiKeys(completion: @escaping (Result<(imgKey: String, subKey: String), Error>) -> Void) {
576-
class Cache {
577-
var imgKey: String?
578-
var subKey: String?
579-
var lastUpdate: Date?
580-
581-
static let shared = Cache()
582-
}
583-
584-
if let imgKey = Cache.shared.imgKey, let subKey = Cache.shared.subKey, let lastUpdate = Cache.shared.lastUpdate, Date().timeIntervalSince(lastUpdate) < 60 * 60 * 12 {
585-
completion(.success((imgKey, subKey)))
586-
return
587-
}
588-
589-
let headers: HTTPHeaders = [
590-
"User-Agent": Keys.userAgent,
591-
"Referer": Keys.referer,
592-
]
593-
594-
AF.request("https://api.bilibili.com/x/web-interface/nav", headers: headers).responseData { response in
595-
switch response.result {
596-
case let .success(value):
597-
let json = JSON(value)
598-
let imgURL = json["data"]["wbi_img"]["img_url"].string ?? ""
599-
let subURL = json["data"]["wbi_img"]["sub_url"].string ?? ""
600-
let imgKey = imgURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
601-
let subKey = subURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
602-
Cache.shared.imgKey = imgKey
603-
Cache.shared.subKey = subKey
604-
Cache.shared.lastUpdate = Date()
605-
completion(.success((imgKey, subKey)))
606-
case let .failure(error):
607-
completion(.failure(error))
608-
}
609-
}
610-
}
611-
612-
func calculateMD5(string: String) -> String {
613-
let data = Data(string.utf8)
614-
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
615-
_ = data.withUnsafeBytes {
616-
CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
617-
}
618-
return digest.map { String(format: "%02hhx", $0) }.joined()
619-
}
620-
621-
let mixinKeyEncTab = [
622-
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
623-
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
624-
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
625-
36, 20, 34, 44, 52,
626-
]
627-
628-
getWbiKeys { result in
629-
switch result {
630-
case let .success(keys):
631-
let spdParam = param.components(separatedBy: "&")
632-
var spdDicParam = [String: String]()
633-
spdParam.forEach { pair in
634-
let components = pair.components(separatedBy: "=")
635-
if components.count == 2 {
636-
spdDicParam[components[0]] = components[1]
637-
}
638-
}
639-
640-
let signedParams = encWbi(params: spdDicParam, imgKey: keys.imgKey, subKey: keys.subKey)
641-
let query = signedParams.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
642-
completion(query)
643-
case let .failure(error):
644-
print("Error getting keys: \(error)")
645-
completion(nil)
646-
}
647-
}
648-
}
649-
}
650-
651522
struct HistoryData: DisplayData, Codable {
652523
struct HistoryPage: Codable, Hashable {
653524
let cid: Int

0 commit comments

Comments
 (0)