yattee/Model/Player/PlayerSponsorBlock.swift
Arkadiusz Fal bf46c36eca Don't skip segments that start before 4 seconds
To minimize buffering
2022-10-27 18:03:57 +02:00

86 lines
2.5 KiB
Swift

import CoreMedia
import Defaults
import Foundation
extension PlayerModel {
func handleSegments(at time: CMTime) {
if let segment = lastSkipped {
if time > .secondsInDefaultTimescale(segment.end + 10) {
resetLastSegment()
}
}
guard let firstSegment = sponsorBlock.segments.first(where: { $0.timeInSegment(time) }) else {
return
}
// find last segment in case they are 2 sec or less after each other
// to avoid multiple skips in a row
var nextSegments = [firstSegment]
while let segment = sponsorBlock.segments.first(where: {
$0.timeInSegment(.secondsInDefaultTimescale(nextSegments.last!.end + 2))
}) {
nextSegments.append(segment)
}
if let segmentToSkip = nextSegments.last(where: { $0.endTime <= playerItemDuration ?? .zero }),
self.shouldSkip(segmentToSkip, at: time)
{
skip(segmentToSkip, at: time)
}
}
private func skip(_ segment: Segment, at time: CMTime) {
guard segment.endTime.seconds <= playerItemDuration?.seconds ?? .infinity else {
logger.error(
"segment end time is: \(segment.end) when player item duration is: \(playerItemDuration?.seconds ?? .infinity)"
)
return
}
backend.seek(to: segment.endTime)
DispatchQueue.main.async { [weak self] in
self?.lastSkipped = segment
self?.segmentRestorationTime = time
}
logger.info("SponsorBlock skipping to: \(segment.end)")
}
private func shouldSkip(_ segment: Segment, at time: CMTime) -> Bool {
guard isPlaying,
!restoredSegments.contains(segment),
Defaults[.sponsorBlockCategories].contains(segment.category),
segment.start > 4
else {
return false
}
return time.seconds - segment.start < 2 && segment.end - time.seconds > 2
}
func restoreLastSkippedSegment() {
guard let segment = lastSkipped,
let time = segmentRestorationTime
else {
return
}
restoredSegments.append(segment)
backend.seek(to: time)
resetLastSegment()
}
private func resetLastSegment() {
DispatchQueue.main.async { [weak self] in
self?.lastSkipped = nil
self?.segmentRestorationTime = nil
}
}
func resetSegments() {
resetLastSegment()
restoredSegments = []
}
}