93 lines
3.0 KiB
Swift
93 lines
3.0 KiB
Swift
import Foundation
|
|
|
|
/// 直播相关模型 - 对应 Android 版 LiveChannel*.java / Epginfo.java
|
|
|
|
/// 直播频道分组
|
|
struct LiveChannelGroup: Codable, Identifiable, Hashable {
|
|
/// 以分组名作为稳定标识,便于 SwiftUI 列表 diff。
|
|
var id: String { groupName }
|
|
/// 分组名称(如“央视”“卫视”)。
|
|
var groupName: String = ""
|
|
/// 分组在列表中的顺序索引。
|
|
var groupIndex: Int = 0
|
|
/// 分组下频道列表。
|
|
var channels: [LiveChannelItem] = []
|
|
/// 是否为加密分组(当前实现仅保留字段,未启用密码校验)。
|
|
var isPassword: Bool = false
|
|
|
|
init(groupName: String = "", groupIndex: Int = 0) {
|
|
self.groupName = groupName
|
|
self.groupIndex = groupIndex
|
|
}
|
|
}
|
|
|
|
/// 直播频道
|
|
struct LiveChannelItem: Codable, Identifiable, Hashable {
|
|
/// 频道标识由名称+索引组成,规避同名频道冲突。
|
|
var id: String { "\(channelName)_\(channelIndex)" }
|
|
/// 频道名。
|
|
var channelName: String = ""
|
|
/// 频道在分组内的顺序索引。
|
|
var channelIndex: Int = 0
|
|
/// 多线路播放地址。
|
|
var channelUrls: [String] = []
|
|
/// 当前选中的线路索引。
|
|
var sourceIndex: Int = 0
|
|
/// 可用线路总数。
|
|
var sourceNum: Int { channelUrls.count }
|
|
/// 台标地址(预留)。
|
|
var logo: String = ""
|
|
|
|
init(channelName: String = "", channelIndex: Int = 0) {
|
|
self.channelName = channelName
|
|
self.channelIndex = channelIndex
|
|
}
|
|
|
|
/// 当前线路对应的播放地址。
|
|
/// 当索引越界时兜底返回第一条线路,避免直接播放失败。
|
|
var currentUrl: String? {
|
|
guard sourceIndex >= 0, sourceIndex < channelUrls.count else { return channelUrls.first }
|
|
return channelUrls[sourceIndex]
|
|
}
|
|
|
|
/// 轮换到下一条线路。
|
|
mutating func nextSource() {
|
|
if channelUrls.count > 0 {
|
|
sourceIndex = (sourceIndex + 1) % channelUrls.count
|
|
}
|
|
}
|
|
}
|
|
|
|
/// EPG 节目信息
|
|
struct Epginfo: Codable, Identifiable, Hashable {
|
|
var id: String { "\(title)_\(startTime)" }
|
|
var title: String = ""
|
|
var startTime: String = ""
|
|
var endTime: String = ""
|
|
var index: Int = 0
|
|
|
|
/// 根据 `HH:mm` 时间段判断节目是否正在播出。
|
|
var isLive: Bool {
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "HH:mm"
|
|
guard let start = formatter.date(from: startTime),
|
|
let end = formatter.date(from: endTime) else { return false }
|
|
|
|
let now = formatter.date(from: formatter.string(from: Date()))!
|
|
return now >= start && now < end
|
|
}
|
|
}
|
|
|
|
/// EPG 日期分组
|
|
struct LiveEpgDate: Codable, Identifiable, Hashable {
|
|
var id: String { datePresent }
|
|
/// 供 UI 展示的日期文案。
|
|
var datePresent: String = ""
|
|
/// 供接口查询的原始日期值。
|
|
var date: String = ""
|
|
/// 在日期列表中的位置索引。
|
|
var index: Int = 0
|
|
/// 是否被当前 UI 选中。
|
|
var isSelected: Bool = false
|
|
}
|