feat: segment playback slider with resolved YouTube chapters
This commit is contained in:
@@ -167,6 +167,70 @@ struct YouTubeResolverChecks {
|
||||
try require(try decode(emptyHeaders).video.headers.isEmpty, "absent headers serialize to an empty block")
|
||||
}
|
||||
|
||||
static func chapters() throws {
|
||||
var object = try fixture(combinedJSON)
|
||||
try require(try decode(object).chapters.isEmpty, "absent chapters remain playable")
|
||||
for payload in [NSNull(), [], true, 17, "chapters", [:],
|
||||
[NSNull(), 17, "row", [:], ["start_time": 0],
|
||||
["start_time": "0", "end_time": 2], ["start_time": 0, "end_time": false]]] as [Any] {
|
||||
object["chapters"] = payload
|
||||
let video = try decode(object)
|
||||
try require(video.chapters.isEmpty && video.video.url == "https://media.example/combined",
|
||||
"null, empty and malformed optional chapters never prevent playback")
|
||||
}
|
||||
object["chapters"] = [
|
||||
NSNull(),
|
||||
["start_time": 0, "end_time": 2.25, "title": "Opening"],
|
||||
["start_time": 2.25, "end_time": 8.75],
|
||||
["start_time": 8.75, "end_time": 12, "title": ["malformed"]],
|
||||
["start_time": 2.25, "end_time": 8.75, "title": NSNull()]
|
||||
] as [Any]
|
||||
let decoded = try decode(object)
|
||||
try require(decoded.chapters.count == 4 && decoded.chapters[0].title == "Opening"
|
||||
&& decoded.chapters[0].end == 2.25 && decoded.chapters[1].start == 2.25,
|
||||
"fractional chapters and titles survive malformed sibling rows")
|
||||
try require(decoded.chapters.dropFirst().allSatisfy { $0.title == nil },
|
||||
"missing, null and malformed optional titles do not discard chapters")
|
||||
try require(decoded.chapterBoundaries(duration: 12) == [2.25, 8.75],
|
||||
"chapter edges are sorted, deduplicated and strictly interior")
|
||||
|
||||
object["duration"] = 0
|
||||
object["chapters"] = [["start_time": 0, "end_time": 2.25],
|
||||
["start_time": 2.25, "end_time": 20.5]]
|
||||
let unknownDuration = try decode(object)
|
||||
try require(unknownDuration.chapterBoundaries(duration: 20.5) == [2.25],
|
||||
"actual playback duration, not extractor duration, validates chapters")
|
||||
for duration in [0, -1, Double.nan, .infinity, -.infinity] {
|
||||
try require(unknownDuration.chapterBoundaries(duration: duration).isEmpty,
|
||||
"unknown and invalid playback durations never produce boundaries")
|
||||
}
|
||||
|
||||
let video = YouTubeVideo(title: "Chapters",
|
||||
video: .init(url: "https://media.example/combined", headers: ""), audio: nil,
|
||||
duration: 0, isLive: false, webpageURL: page, height: nil, availableHeights: [],
|
||||
chapters: [
|
||||
.init(start: 8.75, end: 12, title: nil),
|
||||
.init(start: 0, end: 2.25, title: nil),
|
||||
.init(start: 2.25, end: 8.75, title: nil),
|
||||
.init(start: 2.25, end: 8.75, title: nil),
|
||||
.init(start: -1, end: 4, title: nil),
|
||||
.init(start: 3, end: 13, title: nil),
|
||||
.init(start: 6, end: 6, title: nil),
|
||||
.init(start: 7, end: 5, title: nil),
|
||||
.init(start: .nan, end: 4, title: nil),
|
||||
.init(start: .infinity, end: 4, title: nil),
|
||||
.init(start: -.infinity, end: 4, title: nil),
|
||||
.init(start: 3, end: .nan, title: nil),
|
||||
.init(start: 3, end: .infinity, title: nil),
|
||||
.init(start: 3, end: -.infinity, title: nil)
|
||||
])
|
||||
try require(video.chapterBoundaries(duration: 12) == [2.25, 8.75],
|
||||
"invalid, zero-length, reversed and over-range rows contribute neither edge")
|
||||
object["chapters"] = "malformed optional data"
|
||||
object["url"] = 17
|
||||
try reject("chapter tolerance must not weaken required stream validation") { _ = try decode(object) }
|
||||
}
|
||||
|
||||
static func qualities() throws {
|
||||
func video(_ height: Int, audio: Bool = false, range: String = "SDR", transport: String = "https") -> [String: Any] {
|
||||
["height": height, "vcodec": "h264", "acodec": audio ? "aac" : "none",
|
||||
@@ -609,6 +673,7 @@ struct YouTubeResolverChecks {
|
||||
try FileManager.default.createSymbolicLink(at: runtime, withDestinationURL: URL(fileURLWithPath: "/usr/bin/true"))
|
||||
try videoURLs()
|
||||
try metadata()
|
||||
try chapters()
|
||||
try malformedMetadata()
|
||||
try qualities()
|
||||
try bundledHelpers(root: root)
|
||||
|
||||
Reference in New Issue
Block a user