Files
duooomi-ios-sdk/Sources/DuooomiBleSDK/Services/AniConverter.swift
km2023 1a7bbdc625 feat: 重写 SDK 支持 iOS 12.2,移除 async/await 和 Combine
- 所有公开 API 改为 completion handler (Result<T, Error>)
- 状态通知改为 DuooomiBleSDKDelegate 协议
- 移除 Sendable、@MainActor、AsyncStream、CheckedContinuation
- 网络请求改为 URLSession.dataTask 回调
- BLE 通信改为 delegate + 闭包模式
- deployment target 降至 iOS 12.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:59:39 +08:00

104 lines
3.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
struct AniConverterError: LocalizedError {
let message: String
var errorDescription: String? { message }
}
/// / ANI
final class AniConverter {
private let config: DuooomiBleConfig
private var endpoint: URL {
URL(string: "\(config.apiHost)/api/auth/loomart/file/convert-to-ani")!
}
private let session: URLSession = {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 120
cfg.timeoutIntervalForResource = 180
cfg.waitsForConnectivity = true
return URLSession(configuration: cfg)
}()
init(config: DuooomiBleConfig) {
self.config = config
}
/// ANI ani CDN URL
func convert(fileUrl: String, completion: @escaping (Result<String, Error>) -> Void) {
performConvert(fileUrl: fileUrl) { result in
switch result {
case .success:
completion(result)
case .failure(let error):
// Retry once on connection lost
if (error as NSError).code == NSURLErrorNetworkConnectionLost {
self.performConvert(fileUrl: fileUrl, completion: completion)
} else {
completion(.failure(error))
}
}
}
}
private func performConvert(fileUrl: String, completion: @escaping (Result<String, Error>) -> Void) {
var request = URLRequest(url: endpoint)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "content-type")
request.setValue(config.apiKey, forHTTPHeaderField: "x-api-key")
request.timeoutInterval = 120
let body: [String: Any] = [
"videoUrl": fileUrl,
"width": config.aniWidth,
"height": config.aniHeight,
"fps": config.aniFps,
]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: body)
} catch {
completion(.failure(error))
return
}
session.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
if let http = response as? HTTPURLResponse, !(200..<300).contains(http.statusCode) {
completion(.failure(AniConverterError(message: "HTTP \(http.statusCode)")))
return
}
guard let data = data,
let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
completion(.failure(AniConverterError(message: "Invalid JSON response")))
return
}
guard (json["success"] as? Bool) == true,
let outer = json["data"] as? [String: Any] else {
completion(.failure(AniConverterError(message: "ANI API reported failure")))
return
}
if (outer["status"] as? Bool) != true {
let msg = (outer["msg"] as? String) ?? "ANI conversion failed"
completion(.failure(AniConverterError(message: msg)))
return
}
guard let aniUrl = outer["data"] as? String, !aniUrl.isEmpty else {
completion(.failure(AniConverterError(message: "Missing ani url in response")))
return
}
completion(.success(aniUrl))
}.resume()
}
}