fix: retain Zoko opening and ending metadata through playback
This commit is contained in:
@@ -974,9 +974,16 @@ final class PlayerModel: ObservableObject {
|
||||
skipOffer = nil
|
||||
}
|
||||
let parts = source?.url.absoluteString.split(separator: ":") ?? []
|
||||
let episode = parts.count == 3 && parts[0] == "miruro" ? Int(parts[2]) : nil
|
||||
let generation = metadataLifecycle.replace(identity: source?.url.absoluteString, episode: episode)
|
||||
guard let source, let episode else { return }
|
||||
let episode = parts.count == 3 && (parts[0] == "miruro" || parts[0] == "anilist") ? Int(parts[2]) : nil
|
||||
let providerIntervals: [ProviderInterval]
|
||||
if case .resolved(let resolved, _) = source, parts.first == "anilist" {
|
||||
providerIntervals = resolved.intervals
|
||||
} else {
|
||||
providerIntervals = []
|
||||
}
|
||||
let generation = metadataLifecycle.replace(identity: source?.url.absoluteString, episode: episode,
|
||||
providerIntervals: providerIntervals)
|
||||
guard let source, let episode, parts[0] == "miruro" else { return }
|
||||
let identity = source.url.absoluteString
|
||||
let mediaID = String(parts[1])
|
||||
let resolver = miruroMetadataResolver
|
||||
@@ -2142,14 +2149,20 @@ final class PlayerModel: ObservableObject {
|
||||
private struct MetadataLifecycle {
|
||||
private(set) var identity: String?
|
||||
private(set) var metadata: MiruroMetadata?
|
||||
private var providerIntervals: [MiruroInterval] = []
|
||||
private var episode: Int?
|
||||
private var generation: UInt64 = 0
|
||||
|
||||
mutating func replace(identity: String?, episode: Int?) -> UInt64 {
|
||||
mutating func replace(identity: String?, episode: Int?, providerIntervals: [ProviderInterval] = []) -> UInt64 {
|
||||
generation &+= 1
|
||||
self.identity = identity
|
||||
self.episode = episode
|
||||
metadata = nil
|
||||
self.providerIntervals = episode.map { episode in
|
||||
providerIntervals.map {
|
||||
MiruroInterval(kind: $0.kind == .intro ? .intro : .outro, start: $0.start, end: $0.end, episode: episode)
|
||||
}
|
||||
} ?? []
|
||||
return generation
|
||||
}
|
||||
|
||||
@@ -2160,8 +2173,14 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
|
||||
func visibleIntervals(duration: Double) -> [MiruroInterval] {
|
||||
guard let episode, let metadata else { return [] }
|
||||
return metadata.visibleIntervals(episode: episode, duration: duration)
|
||||
guard let episode else { return [] }
|
||||
if !providerIntervals.isEmpty {
|
||||
guard duration.isFinite, duration > 0 else { return [] }
|
||||
return providerIntervals.filter {
|
||||
$0.start.isFinite && $0.end.isFinite && $0.start >= 0 && $0.end > $0.start && $0.end <= duration
|
||||
}
|
||||
}
|
||||
return metadata?.visibleIntervals(episode: episode, duration: duration) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2208,6 +2227,32 @@ final class PlayerModel: ObservableObject {
|
||||
precondition(!lifecycle.accept(metadata, identity: a, generation: second), "YouTube rejects earlier metadata")
|
||||
_ = lifecycle.replace(identity: nil, episode: nil)
|
||||
precondition(lifecycle.metadata == nil, "Close clears metadata")
|
||||
let providerRows: [ProviderInterval] = [
|
||||
.init(kind: .intro, start: 0.25, end: 1.75),
|
||||
.init(kind: .outro, start: 90.5, end: 100),
|
||||
.init(kind: .intro, start: -1, end: 1),
|
||||
.init(kind: .outro, start: 10, end: 10),
|
||||
.init(kind: .intro, start: .nan, end: 3),
|
||||
.init(kind: .outro, start: 2, end: .infinity),
|
||||
]
|
||||
let providerGeneration = lifecycle.replace(identity: "anilist:1:1", episode: 1, providerIntervals: providerRows)
|
||||
let expected = [
|
||||
MiruroInterval(kind: .intro, start: 0.25, end: 1.75, episode: 1),
|
||||
MiruroInterval(kind: .outro, start: 90.5, end: 100, episode: 1),
|
||||
]
|
||||
for duration in [0.0, -1, .nan, .infinity] {
|
||||
precondition(lifecycle.visibleIntervals(duration: duration).isEmpty, "Unknown/nonfinite provider duration hides bands")
|
||||
}
|
||||
precondition(lifecycle.visibleIntervals(duration: 100) == expected, "Provider fractions and exact-duration end survive mapping")
|
||||
precondition(lifecycle.visibleIntervals(duration: 95) == [expected[0]], "Provider ranges outside actual duration are rejected, not clipped")
|
||||
precondition(lifecycle.visibleIntervals(duration: 100) == expected, "Provider raw rows survive duration changes")
|
||||
_ = lifecycle.replace(identity: "anilist:1:2", episode: 2)
|
||||
precondition(lifecycle.visibleIntervals(duration: 100).isEmpty, "Missing provider timing clears preceding episode")
|
||||
_ = lifecycle.replace(identity: "anilist:1:1", episode: 1)
|
||||
precondition(!lifecycle.accept(metadata, identity: "anilist:1:1", generation: providerGeneration),
|
||||
"Provider replacement retains same-identity generation protection")
|
||||
_ = lifecycle.replace(identity: nil, episode: nil)
|
||||
precondition(lifecycle.visibleIntervals(duration: 100).isEmpty, "Close clears provider bands")
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user