You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
43 lines
1.6 KiB
43 lines
1.6 KiB
import Foundation
|
|
|
|
public enum HLSManifestGenerator: Sendable {
|
|
public struct TimeRange: Equatable, Sendable {
|
|
public var start: Double
|
|
public var duration: Double
|
|
}
|
|
|
|
public static func manifest(trackId: Int64, duration: Double, segmentDuration: Double, token: String? = nil) -> String {
|
|
let count = segmentCount(duration: duration, segmentDuration: segmentDuration)
|
|
let targetDuration = Int(segmentDuration.rounded(.up))
|
|
|
|
var lines: [String] = [
|
|
"#EXTM3U",
|
|
"#EXT-X-VERSION:3",
|
|
"#EXT-X-TARGETDURATION:\(targetDuration)",
|
|
"#EXT-X-MEDIA-SEQUENCE:0",
|
|
]
|
|
|
|
let tokenQuery = token.map { "?token=\($0)" } ?? ""
|
|
for i in 0..<count {
|
|
let range = segmentTimeRange(index: i, trackDuration: duration, segmentDuration: segmentDuration)
|
|
lines.append(String(format: "#EXTINF:%.3f,", range.duration))
|
|
lines.append("segments/\(i).mp3\(tokenQuery)")
|
|
}
|
|
|
|
lines.append("#EXT-X-ENDLIST")
|
|
lines.append("")
|
|
return lines.joined(separator: "\n")
|
|
}
|
|
|
|
public static func segmentCount(duration: Double, segmentDuration: Double) -> Int {
|
|
guard duration > 0, segmentDuration > 0 else { return 0 }
|
|
return Int((duration / segmentDuration).rounded(.up))
|
|
}
|
|
|
|
public static func segmentTimeRange(index: Int, trackDuration: Double, segmentDuration: Double) -> TimeRange {
|
|
let start = Double(index) * segmentDuration
|
|
let remaining = trackDuration - start
|
|
let duration = min(segmentDuration, remaining)
|
|
return TimeRange(start: start, duration: duration)
|
|
}
|
|
}
|
|
|