yattee/Model/Stream.swift

160 lines
4.2 KiB
Swift
Raw Normal View History

2021-06-14 18:05:02 +00:00
import AVFoundation
2021-09-25 08:18:22 +00:00
import Defaults
2021-06-14 18:05:02 +00:00
import Foundation
// swiftlint:disable:next final_class
2021-10-16 22:48:58 +00:00
class Stream: Equatable, Hashable, Identifiable {
2021-09-25 08:18:22 +00:00
enum Resolution: String, CaseIterable, Comparable, Defaults.Serializable {
2022-03-27 18:59:22 +00:00
case hd2160p
case hd1440p60
case hd1440p
case hd1080p60
case hd1080p
case hd720p60
case hd720p
case sd480p
case sd360p
case sd240p
case sd144p
case unknown
2021-10-16 22:48:58 +00:00
var name: String {
"\(height)p\(refreshRate != -1 ? ", \(refreshRate) fps" : "")"
}
2021-07-22 12:43:13 +00:00
var height: Int {
2021-10-16 22:48:58 +00:00
if self == .unknown {
return -1
}
let resolutionPart = rawValue.components(separatedBy: "p").first!
return Int(resolutionPart.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())!
}
var refreshRate: Int {
if self == .unknown {
return -1
}
let refreshRatePart = rawValue.components(separatedBy: "p")[1]
return Int(refreshRatePart.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) ?? -1
2021-07-22 12:43:13 +00:00
}
2021-10-16 22:48:58 +00:00
static func from(resolution: String) -> Resolution {
allCases.first { "\($0)".contains(resolution) } ?? .unknown
2021-07-22 12:43:13 +00:00
}
static func < (lhs: Resolution, rhs: Resolution) -> Bool {
lhs.height < rhs.height
}
}
enum Kind: String, Comparable {
2021-10-16 22:48:58 +00:00
case stream, adaptive, hls
2021-07-22 12:43:13 +00:00
private var sortOrder: Int {
switch self {
2021-10-16 22:48:58 +00:00
case .hls:
2021-07-22 12:43:13 +00:00
return 0
2021-10-16 22:48:58 +00:00
case .stream:
2021-07-22 12:43:13 +00:00
return 1
2021-10-16 22:48:58 +00:00
case .adaptive:
return 2
2021-07-22 12:43:13 +00:00
}
}
static func < (lhs: Kind, rhs: Kind) -> Bool {
lhs.sortOrder < rhs.sortOrder
}
}
2021-10-16 22:48:58 +00:00
let id = UUID()
var instance: Instance!
var audioAsset: AVURLAsset!
var videoAsset: AVURLAsset!
var hlsURL: URL!
2021-06-14 18:05:02 +00:00
2021-10-16 22:48:58 +00:00
var resolution: Resolution!
var kind: Kind!
2021-06-14 18:05:02 +00:00
2021-10-16 22:48:58 +00:00
var encoding: String!
2022-02-16 20:23:11 +00:00
var videoFormat: String!
2021-06-14 18:05:02 +00:00
2021-10-16 22:48:58 +00:00
init(
instance: Instance? = nil,
audioAsset: AVURLAsset? = nil,
videoAsset: AVURLAsset? = nil,
hlsURL: URL? = nil,
resolution: Resolution? = nil,
kind: Kind = .hls,
2022-02-16 20:23:11 +00:00
encoding: String? = nil,
videoFormat: String? = nil
2021-10-16 22:48:58 +00:00
) {
self.instance = instance
2021-06-14 18:05:02 +00:00
self.audioAsset = audioAsset
self.videoAsset = videoAsset
2021-10-16 22:48:58 +00:00
self.hlsURL = hlsURL
2021-06-14 18:05:02 +00:00
self.resolution = resolution
2021-07-22 12:43:13 +00:00
self.kind = kind
2021-06-14 18:05:02 +00:00
self.encoding = encoding
2022-02-16 20:23:11 +00:00
self.videoFormat = videoFormat
2021-06-14 18:05:02 +00:00
}
2021-10-16 22:48:58 +00:00
var quality: String {
2022-02-16 20:23:11 +00:00
if resolution == .hd2160p {
return "4K (2160p)"
}
return kind == .hls ? "adaptive (HLS)" : "\(resolution.name)\(kind == .stream ? " (\(kind.rawValue))" : "")"
}
var format: String {
let lowercasedFormat = (videoFormat ?? "unknown").lowercased()
if lowercasedFormat.contains("webm") {
return "WEBM"
} else if lowercasedFormat.contains("avc1") {
return "avc1"
} else if lowercasedFormat.contains("av01") {
return "AV1"
} else if lowercasedFormat.contains("mpeg_4") || lowercasedFormat.contains("mp4") {
return "MP4"
} else {
return lowercasedFormat
}
2021-10-16 22:48:58 +00:00
}
2021-06-14 18:05:02 +00:00
var description: String {
2022-02-16 20:23:11 +00:00
let formatString = format == "unknown" ? "" : " (\(format))"
return "\(quality)\(formatString) - \(instance?.description ?? "")"
2021-06-14 18:05:02 +00:00
}
2021-06-15 16:35:21 +00:00
var assets: [AVURLAsset] {
[audioAsset, videoAsset]
}
2021-10-16 22:48:58 +00:00
var videoAssetContainsAudio: Bool {
assets.dropFirst().allSatisfy { $0.url == assets.first!.url }
2021-07-22 12:43:13 +00:00
}
2021-10-16 22:48:58 +00:00
var singleAssetURL: URL? {
if kind == .hls {
return hlsURL
} else if videoAssetContainsAudio {
return videoAsset.url
}
return nil
}
2021-06-14 18:05:02 +00:00
static func == (lhs: Stream, rhs: Stream) -> Bool {
2021-10-16 22:48:58 +00:00
lhs.id == rhs.id
2021-07-22 12:43:13 +00:00
}
func hash(into hasher: inout Hasher) {
2021-10-16 22:48:58 +00:00
hasher.combine(videoAsset?.url)
hasher.combine(audioAsset?.url)
hasher.combine(hlsURL)
}
2021-06-14 18:05:02 +00:00
}