diff --git a/DarockBili Watch App/Extension/CodeExt.swift b/DarockBili Watch App/Extension/CodeExt.swift index 6a2e8ad3a..bf47115f8 100644 --- a/DarockBili Watch App/Extension/CodeExt.swift +++ b/DarockBili Watch App/Extension/CodeExt.swift @@ -211,6 +211,59 @@ func biliWbiSign(paramEncoded: String, completion: @escaping (String?) -> Void) } } +// AV & BV ID Convert Logic +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 +} + postfix operator ++ postfix operator -- prefix operator ++ diff --git a/DarockBili Watch App/Video/VideoCommentsView.swift b/DarockBili Watch App/Video/VideoCommentsView.swift index d4f685727..321aab315 100644 --- a/DarockBili Watch App/Video/VideoCommentsView.swift +++ b/DarockBili Watch App/Video/VideoCommentsView.swift @@ -56,7 +56,7 @@ struct VideoCommentsView: View { @AppStorage("DedeUserID__ckMd5") var dedeUserID__ckMd5 = "" @AppStorage("SESSDATA") var sessdata = "" @AppStorage("bili_jct") var biliJct = "" - @State var avid = -1 + @State var avid: UInt64 = 0 @State var comments = [[String: String]]() @State var sepTexts = [[String]]() @State var emojiUrls = [[String]]() @@ -231,74 +231,68 @@ struct VideoCommentsView: View { } func ContinueLoadComment() { - DarockKit.Network.shared.requestString("https://api.darock.top/bili/toav/\(oid)") { respStr, isSuccess in + avid = bv2av(bvid: oid) + debugPrint(avid) + let headers: HTTPHeaders = [ + "cookie": "SESSDATA=\(sessdata);" + ] + DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/v2/reply?type=1&oid=\(avid)&sort=1&ps=20&pn=\(nowPage)", headers: headers) { respJson, isSuccess in if isSuccess { - avid = Int(respStr)! - debugPrint(avid) - let headers: HTTPHeaders = [ - "cookie": "SESSDATA=\(sessdata);" - ] - DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/v2/reply?type=1&oid=\(avid)&sort=1&ps=20&pn=\(nowPage)", headers: headers) { respJson, isSuccess in - if isSuccess { - debugPrint(respJson) - let replies = respJson["data"]["replies"] - var calNum = 0 - for reply in replies { - isSenderDetailsPresented.append(false) - commentOffsets.append(20) - let repliesInComment = reply.1["replies"] - commentReplies.append([]) - for sigReply in repliesInComment { - commentReplies[calNum].append(["Text": sigReply.1["content"]["message"].string ?? "[加载失败]", "Sender": sigReply.1["member"]["uname"].string ?? "[加载失败]", "SenderPic": sigReply.1["member"]["avatar"].string ?? "E", "SenderID": sigReply.1["member"]["mid"].string ?? "E", "IP": sigReply.1["reply_control"]["location"].string ?? "", "UserAction": String(sigReply.1["action"].int ?? 0), "Rpid": String(sigReply.1["rpid"].int ?? -1), "Like": String(sigReply.1["like"].int ?? -1)]) - } - let text = reply.1["content"]["message"].string ?? "[加载失败]" - comments.append(["Text": text, "Sender": reply.1["member"]["uname"].string ?? "[加载失败]", "SenderPic": reply.1["member"]["avatar"].string ?? "E", "SenderID": reply.1["member"]["mid"].string ?? "E", "IP": reply.1["reply_control"]["location"].string ?? "", "UserAction": String(reply.1["action"].int ?? 0), "Rpid": String(reply.1["rpid"].int ?? -1), "Like": String(reply.1["like"].int ?? -1)]) -// sepTexts.append([]) -// isEmoted.append(false) -// // 文本中包含表情 -// if text.range(of: "\\[(.*?)\\]", options: .regularExpression) != nil { -// let regex = try! NSRegularExpression(pattern: "\\[(.*?)\\]") -// debugPrint("Contains") -// // 分割文本,同时去除表情 -// let tmpSpdText = regex.stringByReplacingMatches(in: text, range: NSRange(text.startIndex..