Skip to content

Commit

Permalink
Merge next branch to main (#19)
Browse files Browse the repository at this point in the history
* Fix Crash Issue when Seeing User's Videos in UserDetailsView (#15)

* Update UserDetailView.swift

* Merge main workflows (#16)

* Update status-check.yml

* Update statuscheck-runner.yml

* Update CodeExt.swift

* Update UserDetailView.swift

Fixed optional unwrap issue

* Update status-check.yml

* Update status-check.yml

* Update status-check.yml

* Update status-check.yml

* Update status-check.yml

* Update status-check.yml

* Update UserDetailView.swift

* Add local wbi sign feature (#18)

* Update CodeExt.swift

Added wbi calculation logic

* Update MainView.swift

* Update PersonAccountView.swift

* Update UserDetailView.swift

Might fix the article access issue at the same time.

* Update CodeExt.swift

* Update CodeExt.swift

* Update CodeExt.swift

* Update status-check.yml

* Update status-check.yml

* Update CodeExt.swift
  • Loading branch information
WindowsMEMZ authored Dec 2, 2023
1 parent f890ddf commit 4ca62c2
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 116 deletions.
44 changes: 42 additions & 2 deletions .github/workflows/status-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,25 @@ jobs:
build:
name: Check Build
runs-on: macos-13
permissions:
checks: write
statuses: write
env:
FIN_STATUS: "error"
GH_TOKEN: ${{ github.token }}
steps:
- name: Update Check Status
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository }}/statuses/$GITHUB_SHA \
-f state='pending' \
-f target_url='https://github.com/Darock-Studio/Darock-Bili/actions/runs/${{ github.run_id }}' \
-f description='Building...' \
-f context='API Status Checker'
- name: Checkout
uses: actions/checkout@v3
with:
Expand All @@ -19,14 +37,36 @@ jobs:
- name: Set Xcode Version
run: sudo xcode-select -s /Applications/Xcode_15.0.app

- name: Get Current Time
id: current-time
run: echo "time=$(date +"%Y%m%d%H%M%S")" >> $GITHUB_OUTPUT

- name: Cache Build Caches
uses: actions/cache@v3
with:
key: check-build-cache
key: ${{ runner.os }}-check-build-cache-${{ steps.current-time.outputs.time }}
path: |
~/Library/Developer/Xcode/DerivedData
restore-keys: |
${{ runner.os }}-check-build-cache-
- name: Update Status Env
run: echo "FIN_STATUS=failure" >> $GITHUB_ENV

- name: Build DarockBili App
run: |
xcodebuild -scheme 'DarockBili Watch App' -configuration Release build CODE_SIGN_IDENTITY=""
echo "FIN_STATUS=success" >> $GITHUB_ENV
- name: Update Check Status
if: always()
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository }}/statuses/$GITHUB_SHA \
-f state='${{ env.FIN_STATUS }}' \
-f target_url='https://github.com/Darock-Studio/Darock-Bili/actions/runs/${{ github.run_id }}' \
-f context='API Status Checker'
1 change: 0 additions & 1 deletion .github/workflows/statuscheck-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,3 @@ jobs:
workflow: status-check.yml
ref: ${{ needs.get-head-sha.outputs.psha }}
inputs: '{ "psha": "${{ needs.get-head-sha.outputs.psha }}"}'

153 changes: 63 additions & 90 deletions DarockBili Watch App/Extension/CodeExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import OSLog
import SwiftUI
import Dynamic
import CryptoKit
import DarockKit
import Alamofire
import SwiftyJSON
import Foundation
import AVFoundation
import CommonCrypto
Expand Down Expand Up @@ -136,84 +138,75 @@ public func hideDigitalTime(_ b: Bool) {
app._setStatusBarTimeHidden(b, animated: true, completion: nil)
}

public class WbiSign: ObservableObject {
@State var img_key = ""
@State var sub_key = ""
func MD5Hash(_ string: String) -> String {
let data = Data(string.utf8)
var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
data.withUnsafeBytes { bytes in
_ = CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash)
}
return hash.map { String(format: "%02x", $0) }.joined()
}
static let mixinKeyEncTab: [Int] = [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]

func getMixinKey(orig: String) -> String {
let result = WbiSign.mixinKeyEncTab.reduce("") { result, index in
if index < orig.count {
let start = orig.index(orig.startIndex, offsetBy: index)
return result + String(orig[start])
} else {
return result
}
}
print("Mixin Key: \(result)")
return result
}

func filterInvalidCharacters(from value: Any) -> String {
let invalidCharacters = CharacterSet(charactersIn: "!'()*")
if let strValue = value as? String {
return strValue.components(separatedBy: invalidCharacters).joined()
} else {
return String(describing: value)
}
}

func md5(data: String) -> String {
let digest = Insecure.MD5.hash(data: data.data(using: .utf8) ?? Data())
return digest.map { String(format: "%02hhx", $0) }.joined()
func biliWbiSign(paramEncoded: 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]) -> String {
var newParams = params
let mixinKey = getMixinKey(orig: img_key + sub_key)
let currTime = Int(Date().timeIntervalSince1970)
newParams["wts"] = currTime
let sortedParams = newParams.sorted { $0.key < $1.key }
let query = sortedParams.map { "\($0.key)=\(filterInvalidCharacters(from: $0.value))" }.joined(separator: "&")
print("Query: \(query + mixinKey)")
let dataToHash = (query.urlEncoded() + mixinKey.prefix(32))
let wbiSign = (dataToHash).DDMD5Encrypt()
print("WBI Sign: \(wbiSign)")
newParams["w_rid"] = wbiSign
var paramStr = ""
for param in newParams {
paramStr += "\(param.key)=\(param.value)&"
}
paramStr.removeLast()
return paramStr
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(completionHandler: @escaping (String, String) -> Void) {
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):
if let dict = value as? [String: Any],
let data = dict["data"] as? [String: Any],
let wbiImg = data["wbi_img"] as? [String: Any],
let imgUrl = wbiImg["img_url"] as? String,
let subUrl = wbiImg["sub_url"] as? String {
let imgKey = String(imgUrl.split(separator: "/").last!.split(separator: ".").first!)
let subKey = String(subUrl.split(separator: "/").last!.split(separator: ".").first!)
print("Image Key: \(imgKey)")
print("Sub Key: \(subKey)")
completionHandler(imgKey, subKey)
}
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):
print(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 decParam = paramEncoded.base64Decoded() ?? ""
let spdParam = decParam.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)
}
}
}
Expand Down Expand Up @@ -248,24 +241,4 @@ extension Int {
}
}

postfix operator /
extension Optional {
static postfix func / (opt: Int?) -> Int {
return opt ?? 0
}
static postfix func / (opt: String?) -> String {
return opt ?? ""
}
static postfix func / (opt: Double?) -> Double {
return opt ?? 0.0
}
static postfix func / (opt: Float?) -> Float {
return opt ?? 0.0
}
static postfix func / (opt: Bool?) -> Bool {
return opt ?? false
}
}



8 changes: 4 additions & 4 deletions DarockBili Watch App/InMain/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ struct MainView: View {
let headers: HTTPHeaders = [
"cookie": "SESSDATA=\(sessdata)"
]
DarockKit.Network.shared.requestString("https://api.darock.top/bili/wbi/sign/\("ps=\(isInLowBatteryMode ? 10 : 30)".base64Encoded())") { respStr, isSuccess in
if isSuccess {
debugPrint(respStr.apiFixed())
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd?\(respStr.apiFixed())", headers: headers) { respJson, isSuccess in
biliWbiSign(paramEncoded: "ps=\(isInLowBatteryMode ? 10 : 30)".base64Encoded()) { signed in
if let signed {
debugPrint(signed)
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd?\(signed)", headers: headers) { respJson, isSuccess in
if isSuccess {
debugPrint(respJson)
let datas = respJson["data"]["item"]
Expand Down
8 changes: 4 additions & 4 deletions DarockBili Watch App/PersonalCenter/PersonAccountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ struct PersonAccountView: View {
isNetworkFixPresented = true
}
}
DarockKit.Network.shared.requestString("https://api.darock.top/bili/wbi/sign/\("mid=\(dedeUserID)".base64Encoded())") { respStr, isSuccess in
if isSuccess {
debugPrint(respStr.apiFixed())
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/acc/info?\(respStr.apiFixed())", headers: headers) { respJson, isSuccess in
biliWbiSign(paramEncoded: "mid=\(dedeUserID)".base64Encoded()) { signed in
if let signed {
debugPrint(signed)
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/acc/info?\(signed)", headers: headers) { respJson, isSuccess in
if isSuccess {
debugPrint(respJson)
userFaceUrl = respJson["data"]["face"].string ?? "E"
Expand Down
40 changes: 25 additions & 15 deletions DarockBili Watch App/PersonalCenter/UserDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ struct UserDetailView: View {
let headers: HTTPHeaders = [
"cookie": "SESSDATA=\(sessdata);"
]
DarockKit.Network.shared.requestString("https://api.darock.top/bili/wbi/sign/\("mid=\(uid)".base64Encoded())") { respStr, isSuccess in
if isSuccess {
debugPrint(respStr.apiFixed())
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/acc/info?\(respStr.apiFixed())", headers: headers) { respJson, isSuccess in
biliWbiSign(paramEncoded: "mid=\(uid)".base64Encoded()) { signed in
if let signed {
debugPrint(signed)
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/acc/info?\(signed)", headers: headers) { respJson, isSuccess in
if isSuccess {
debugPrint(respJson)
userFaceUrl = respJson["data"]["face"].string ?? "E"
Expand Down Expand Up @@ -560,19 +560,24 @@ struct UserDetailView: View {
func RefreshVideos() {
videos = [[String: String]]()
let headers: HTTPHeaders = [
"cookie": "SESSDATA=\(sessdata);"
"cookie": "SESSDATA=\(sessdata);",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15"
]
DarockKit.Network.shared.requestString("https://api.darock.top/bili/wbi/sign/\("mid=\(uid)&ps=50&pn=\(videoNowPage)".base64Encoded())") { respStr, isSuccess in
if isSuccess {
debugPrint(respStr.apiFixed())
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/arc/search?\(respStr.apiFixed())", headers: headers) { respJson, isSuccess in
biliWbiSign(paramEncoded: "mid=\(uid)&ps=50&pn=\(videoNowPage)".base64Encoded()) { signed in
if let signed {
debugPrint(signed)
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/arc/search?\(signed)", headers: headers) { respJson, isSuccess in
if isSuccess {
debugPrint(respJson)
if (respJson["code"].int ?? 0) != 0 {
tipWithText("加载失败:\(respJson["message"].string ?? "")", symbol: "xmark.circle.fill")
return
}
let vlist = respJson["data"]["list"]["vlist"]
for video in vlist {
videos.append(["Title": video.1["title"].string ?? "[加载失败]", "Length": video.1["length"].string ?? "E", "PlayCount": String(video.1["play"].int ?? -1), "PicUrl": video.1["pic"].string ?? "E", "BV": video.1["bvid"].string ?? "E", "Timestamp": String(video.1["created"].int ?? 0), "DanmakuCount": String(video.1["video_review"].int ?? -1)])
}
debugPrint(respJson["data"]["page"]["count"].int!)
debugPrint(respJson["data"]["page"]["count"].int ?? 0)
videoTotalPage = Int((respJson["data"]["page"]["count"].int ?? 0) / 50) + 1
videoCount = respJson["data"]["page"]["count"].int ?? 0
if !isVideosLoaded {
Expand All @@ -589,14 +594,19 @@ struct UserDetailView: View {
func RefreshArticles() {
articles = [[String: String]]()
let headers: HTTPHeaders = [
"cookie": "SESSDATA=\(sessdata);"
"cookie": "SESSDATA=\(sessdata);",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15"
]
DarockKit.Network.shared.requestString("https://api.darock.top/bili/wbi/sign/\("mid=\(uid)&ps=30&pn=\(articleNowPage)&sort=publish_time&platform=web".base64Encoded())") { respStr, isSuccess in
if isSuccess {
debugPrint(respStr.apiFixed())
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/article?\(respStr.apiFixed())", headers: headers) { respJson, isSuccess in
biliWbiSign(paramEncoded: "mid=\(uid)&ps=30&pn=\(articleNowPage)&sort=publish_time&platform=web".base64Encoded()) { signed in
if let signed {
debugPrint(signed)
DarockKit.Network.shared.requestJSON("https://api.bilibili.com/x/space/wbi/article?\(signed)", headers: headers) { respJson, isSuccess in
if isSuccess {
debugPrint(respJson)
if (respJson["code"].int ?? 0) != 0 {
tipWithText("加载失败:\(respJson["message"].string ?? "")", symbol: "xmark.circle.fill")
return
}
let articlesJson = respJson["data"]["articles"]
for article in articlesJson {
articles.append(["Title": article.1["title"].string ?? "[加载失败]", "Summary": article.1["summary"].string ?? "[加载失败]", "Type": article.1["categories"][0]["name"].string ?? "[加载失败]", "View": String(article.1["stats"]["view"].int ?? -1), "Like": String(article.1["stats"]["like"].int ?? -1), "Pic": article.1["image_urls"][0].string ?? "E", "CV": String(article.1["id"].int ?? 0)])
Expand Down

0 comments on commit 4ca62c2

Please sign in to comment.