init: init proj
This commit is contained in:
121
DDYSClient/Services/APIClient.swift
Normal file
121
DDYSClient/Services/APIClient.swift
Normal file
@@ -0,0 +1,121 @@
|
||||
import Foundation
|
||||
|
||||
enum APIError: LocalizedError {
|
||||
case invalidURL
|
||||
case networkError(Error)
|
||||
case invalidResponse(Int)
|
||||
case decodingError(Error)
|
||||
case noData
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL: return "无效的 URL"
|
||||
case .networkError(let error): return "网络错误: \(error.localizedDescription)"
|
||||
case .invalidResponse(let code): return "服务器错误: \(code)"
|
||||
case .decodingError(let error): return "解析错误: \(error.localizedDescription)"
|
||||
case .noData: return "无数据"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actor APIClient {
|
||||
static let shared = APIClient()
|
||||
|
||||
private let baseURL = "https://ddys.io"
|
||||
private let session: URLSession
|
||||
|
||||
private init() {
|
||||
let config = URLSessionConfiguration.default
|
||||
config.httpAdditionalHeaders = [
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
||||
"Referer": "https://ddys.io/",
|
||||
]
|
||||
config.httpCookieStorage = .shared
|
||||
self.session = URLSession(configuration: config)
|
||||
}
|
||||
|
||||
// MARK: - HTML 页面请求
|
||||
|
||||
func fetchHTML(path: String) async throws -> String {
|
||||
guard let url = URL(string: baseURL + path) else {
|
||||
throw APIError.invalidURL
|
||||
}
|
||||
let (data, response) = try await session.data(from: url)
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
throw APIError.noData
|
||||
}
|
||||
guard (200...299).contains(httpResponse.statusCode) else {
|
||||
throw APIError.invalidResponse(httpResponse.statusCode)
|
||||
}
|
||||
guard let html = String(data: data, encoding: .utf8) else {
|
||||
throw APIError.noData
|
||||
}
|
||||
return html
|
||||
}
|
||||
|
||||
// MARK: - 首页
|
||||
|
||||
func fetchHomePage() async throws -> String {
|
||||
try await fetchHTML(path: "/")
|
||||
}
|
||||
|
||||
// MARK: - 分类列表
|
||||
|
||||
func fetchCategoryPage(category: ContentCategory, page: Int = 1, filter: FilterState = FilterState()) async throws -> String {
|
||||
var path = filter.buildPath(base: category.pathPrefix)
|
||||
if page > 1 {
|
||||
path += "/page/\(page)"
|
||||
}
|
||||
return try await fetchHTML(path: path)
|
||||
}
|
||||
|
||||
// MARK: - 详情页
|
||||
|
||||
func fetchDetailPage(path: String) async throws -> String {
|
||||
try await fetchHTML(path: path)
|
||||
}
|
||||
|
||||
// MARK: - 搜索
|
||||
|
||||
func fetchSearchPage(query: String, page: Int = 1) async throws -> String {
|
||||
let encoded = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? query
|
||||
var path = "/search?q=\(encoded)&type=all"
|
||||
if page > 1 {
|
||||
path += "&page=\(page)"
|
||||
}
|
||||
return try await fetchHTML(path: path)
|
||||
}
|
||||
|
||||
// MARK: - JSON API
|
||||
|
||||
func fetchHotMovies() async throws -> [HotMovieItem] {
|
||||
guard let url = URL(string: baseURL + "/api/hot-movies") else {
|
||||
throw APIError.invalidURL
|
||||
}
|
||||
let (data, response) = try await session.data(from: url)
|
||||
guard let httpResponse = response as? HTTPURLResponse,
|
||||
(200...299).contains(httpResponse.statusCode) else {
|
||||
throw APIError.invalidResponse((response as? HTTPURLResponse)?.statusCode ?? 0)
|
||||
}
|
||||
let result = try JSONDecoder().decode(HotMoviesResponse.self, from: data)
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - API Response Models
|
||||
|
||||
struct HotMoviesResponse: Codable {
|
||||
let success: Bool
|
||||
let data: [HotMovieItem]
|
||||
}
|
||||
|
||||
struct HotMovieItem: Codable, Identifiable {
|
||||
let id: Int?
|
||||
let title: String
|
||||
let slug: String
|
||||
let poster: String?
|
||||
|
||||
var itemId: String { slug }
|
||||
}
|
||||
Reference in New Issue
Block a user