From 5a13a8e6a6db153660abd6bf49375d1a4ead724f Mon Sep 17 00:00:00 2001 From: William Date: Tue, 30 Jun 2026 12:12:06 +0600 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E4=B8=8D=E5=8C=B9=E9=85=8D=E7=9A=84=E6=A0=B9=E6=9C=AC=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0=EF=BC=8C=E6=94=B9=E7=94=A8=E6=89=8B=E5=8A=A8=E6=8B=BC?= =?UTF-8?q?=E6=8E=A5=20URL=20=E6=9B=BF=E4=BB=A3=20URLComponents=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8A=A0=E8=BD=BD=E9=87=8D=E8=AF=95=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VODManager/Services/VODClient.swift | 25 +++++--- .../VODManager/Services/VODSignature.swift | 6 +- .../VODManager/Views/VideoListView.swift | 57 +++++++++++-------- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/apps/macos/VODManager/Sources/VODManager/Services/VODClient.swift b/apps/macos/VODManager/Sources/VODManager/Services/VODClient.swift index 746968d..885b20a 100644 --- a/apps/macos/VODManager/Sources/VODManager/Services/VODClient.swift +++ b/apps/macos/VODManager/Sources/VODManager/Services/VODClient.swift @@ -66,15 +66,12 @@ actor VODClient { params["Signature"] = signature let host = endpoint() - var components = URLComponents() - components.scheme = "https" - components.host = host - components.path = "/" - components.queryItems = params.sorted(by: { $0.key < $1.key }).map { - URLQueryItem(name: $0.key, value: $0.value) - } + let query = params.sorted(by: { $0.key < $1.key }) + .map { "\(VODSignature.percentEncodePublic($0.key))=\(VODSignature.percentEncodePublic($0.value))" } + .joined(separator: "&") + let urlString = "https://\(host)/?\(query)" - guard let url = components.url else { + guard let url = URL(string: urlString) else { throw VODClientError.invalidResponse } return url @@ -93,7 +90,17 @@ actor VODClient { } let decoder = JSONDecoder() - return try decoder.decode(T.self, from: data) + do { + return try decoder.decode(T.self, from: data) + } catch { + if action == "GetPlayInfo" { + print("[VODClient] GetPlayInfo 解码失败: \(error)") + if let raw = String(data: data, encoding: .utf8) { + print("[VODClient] GetPlayInfo 原始响应: \(raw)") + } + } + throw error + } } func searchMedia( diff --git a/apps/macos/VODManager/Sources/VODManager/Services/VODSignature.swift b/apps/macos/VODManager/Sources/VODManager/Services/VODSignature.swift index b2436b8..5a6c771 100644 --- a/apps/macos/VODManager/Sources/VODManager/Services/VODSignature.swift +++ b/apps/macos/VODManager/Sources/VODManager/Services/VODSignature.swift @@ -26,8 +26,6 @@ struct VODSignature { let stringToSign = "\(method)&%2F&\(percentEncode(canonicalQuery))" - print("[VODSignature] stringToSign: \(stringToSign)") - guard let keyData = "\(accessKeySecret)&".data(using: .utf8) else { throw VODSignatureError.invalidKey } @@ -41,6 +39,10 @@ struct VODSignature { return signatureData.base64EncodedString() } + static func percentEncodePublic(_ value: String) -> String { + percentEncode(value) + } + private static func percentEncode(_ value: String) -> String { let allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~" var result = "" diff --git a/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift b/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift index f3db59e..5f2efad 100644 --- a/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift +++ b/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift @@ -243,31 +243,42 @@ struct VideoListView: View { private func refreshFromAPI() async { isLoading = true errorMessage = nil - loadingStatus = "正在加载视频列表..." - var collected: [VideoItem] = [] - var page = 1 - let size = 100 - var total = 0 - do { - while true { - loadingStatus = "正在加载视频列表... (第 \(page) 页)" - let response = try await VODClient.shared.searchMedia( - pageNo: page, - pageSize: size - ) - let videos = response.videos - collected.append(contentsOf: videos) - total = response.Total ?? 0 - if collected.count >= total || videos.isEmpty { - break + let maxRetries = 3 + for attempt in 1...maxRetries { + loadingStatus = attempt == 1 ? "正在加载视频列表..." : "重试中... (第 \(attempt)/\(maxRetries) 次)" + var collected: [VideoItem] = [] + var page = 1 + let size = 100 + var total = 0 + do { + while true { + loadingStatus = "正在加载视频列表... (第 \(page) 页)" + let response = try await VODClient.shared.searchMedia( + pageNo: page, + pageSize: size + ) + let videos = response.videos + collected.append(contentsOf: videos) + total = response.Total ?? 0 + if collected.count >= total || videos.isEmpty { + break + } + page += 1 + try? await Task.sleep(for: .milliseconds(200)) + } + allVideos = collected + applyFilter() + loadingStatus = "" + isLoading = false + return + } catch { + if attempt < maxRetries { + let delay = UInt64(attempt) * 1_000_000_000 + try? await Task.sleep(nanoseconds: delay) + } else { + errorMessage = "加载失败(已重试 \(maxRetries) 次):\(error.localizedDescription)" } - page += 1 } - allVideos = collected - applyFilter() - loadingStatus = "" - } catch { - errorMessage = "加载失败:\(error.localizedDescription)" } isLoading = false }