first commit
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - 灵活类型解码器
|
||||
|
||||
/// 兼容 JSON 中数值字段可能是字符串 "0" 或整数 0 的情况
|
||||
/// Android Gson 自动处理此差异,Swift 需要手动兼容
|
||||
struct FlexibleInt: Codable, Hashable {
|
||||
let value: Int
|
||||
|
||||
init(_ value: Int) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if let intVal = try? container.decode(Int.self) {
|
||||
self.value = intVal
|
||||
} else if let stringVal = try? container.decode(String.self),
|
||||
let intVal = Int(stringVal) {
|
||||
self.value = intVal
|
||||
} else {
|
||||
self.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// 兼容 ext 字段可能是字符串或对象
|
||||
struct FlexibleExt: Codable, Hashable {
|
||||
let stringValue: String?
|
||||
let dictValue: [String: AnyCodableValue]?
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if let str = try? container.decode(String.self) {
|
||||
self.stringValue = str
|
||||
self.dictValue = nil
|
||||
} else if let dict = try? container.decode([String: AnyCodableValue].self) {
|
||||
self.stringValue = nil
|
||||
self.dictValue = dict
|
||||
} else {
|
||||
self.stringValue = nil
|
||||
self.dictValue = nil
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
if let str = stringValue {
|
||||
try container.encode(str)
|
||||
} else if let dict = dictValue {
|
||||
try container.encode(dict)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 通用的 JSON 值类型,用于处理混合类型的字典
|
||||
enum AnyCodableValue: Codable, Hashable {
|
||||
case string(String)
|
||||
case int(Int)
|
||||
case double(Double)
|
||||
case bool(Bool)
|
||||
case dict([String: AnyCodableValue])
|
||||
case array([AnyCodableValue])
|
||||
case null
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if let str = try? container.decode(String.self) {
|
||||
self = .string(str)
|
||||
} else if let int = try? container.decode(Int.self) {
|
||||
self = .int(int)
|
||||
} else if let double = try? container.decode(Double.self) {
|
||||
self = .double(double)
|
||||
} else if let bool = try? container.decode(Bool.self) {
|
||||
self = .bool(bool)
|
||||
} else if let dict = try? container.decode([String: AnyCodableValue].self) {
|
||||
self = .dict(dict)
|
||||
} else if let array = try? container.decode([AnyCodableValue].self) {
|
||||
self = .array(array)
|
||||
} else {
|
||||
self = .null
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
switch self {
|
||||
case .string(let s): try container.encode(s)
|
||||
case .int(let i): try container.encode(i)
|
||||
case .double(let d): try container.encode(d)
|
||||
case .bool(let b): try container.encode(b)
|
||||
case .dict(let d): try container.encode(d)
|
||||
case .array(let a): try container.encode(a)
|
||||
case .null: try container.encodeNil()
|
||||
}
|
||||
}
|
||||
|
||||
/// 将可能的任意类型转换为字符串(如果原本是字典或数组,则转为 JSON 字符串)
|
||||
var stringValue: String? {
|
||||
switch self {
|
||||
case .string(let s): return s
|
||||
case .int(let i): return String(i)
|
||||
case .double(let d): return String(d)
|
||||
case .bool(let b): return b ? "true" : "false"
|
||||
case .null: return nil
|
||||
case .dict, .array:
|
||||
if let data = try? JSONEncoder().encode(self),
|
||||
let str = String(data: data, encoding: .utf8) {
|
||||
return str
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 解析接口配置
|
||||
|
||||
/// 解析接口配置 - 对应 Android 版 ParseBean.java
|
||||
struct ParseBean: Codable, Identifiable, Hashable {
|
||||
var id: String { name }
|
||||
var name: String = ""
|
||||
var url: String = ""
|
||||
var type: Int = 0 // 0:嗅探 1:解析
|
||||
var ext: [String: String]? = nil
|
||||
|
||||
init(name: String = "", url: String = "", type: Int = 0) {
|
||||
self.name = name
|
||||
self.url = url
|
||||
self.type = type
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - API 配置顶层结构
|
||||
|
||||
/// API 配置顶层结构 - 对应 JSON 配置文件格式
|
||||
struct AppConfigData: Codable {
|
||||
var spider: String?
|
||||
var wallpaper: String?
|
||||
var sites: [SiteConfig]?
|
||||
var parses: [ParseConfig]?
|
||||
var lives: [LiveConfig]?
|
||||
var doh: [DoHConfig]?
|
||||
var rules: [RuleConfig]?
|
||||
var hosts: [String]?
|
||||
var flags: [String]?
|
||||
var ads: [String]?
|
||||
|
||||
struct SiteConfig: Codable {
|
||||
var key: String?
|
||||
var name: String?
|
||||
var api: String?
|
||||
var searchable: FlexibleInt?
|
||||
var filterable: FlexibleInt?
|
||||
var quickSearch: FlexibleInt?
|
||||
var playerType: FlexibleInt?
|
||||
var type: FlexibleInt?
|
||||
var ext: AnyCodableValue?
|
||||
var jar: String?
|
||||
var style: AnyCodableValue?
|
||||
var playUrl: String?
|
||||
var categories: [String]?
|
||||
var click: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case key, name, api, searchable, filterable, quickSearch
|
||||
case playerType, type, ext, jar, style, playUrl, categories, click
|
||||
// type_flag 也可能出现
|
||||
}
|
||||
}
|
||||
|
||||
struct ParseConfig: Codable {
|
||||
var name: String?
|
||||
var url: String?
|
||||
var type: FlexibleInt?
|
||||
var ext: FlexibleExt?
|
||||
}
|
||||
|
||||
struct LiveConfig: Codable {
|
||||
var name: String?
|
||||
var url: String?
|
||||
var type: FlexibleInt?
|
||||
var ua: String?
|
||||
var epg: String?
|
||||
var logo: String?
|
||||
var pass: AnyCodableValue? // Android 配置中存在
|
||||
var playerType: FlexibleInt?
|
||||
var channels: [LiveChannelConfig]?
|
||||
|
||||
struct LiveChannelConfig: Codable {
|
||||
var name: String?
|
||||
var urls: [String]?
|
||||
var group: String?
|
||||
var logo: String?
|
||||
}
|
||||
}
|
||||
|
||||
struct DoHConfig: Codable {
|
||||
var name: String?
|
||||
var url: String?
|
||||
}
|
||||
|
||||
struct RuleConfig: Codable {
|
||||
var name: String?
|
||||
var host: String?
|
||||
var hosts: [String]?
|
||||
var rule: [String]?
|
||||
var regex: [String]?
|
||||
var filter: [String]?
|
||||
var script: [String]?
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user