mirror of
https://github.com/yattee/yattee.git
synced 2025-11-16 06:58:43 +00:00
Add nil safety checks for stream resolution handling
Added comprehensive nil checks for stream resolution values across PlayerBackend, QualityProfile, and PlayerQueue to prevent crashes when streams have missing resolution metadata. Also added backend nil checks in PlayerQueue.
This commit is contained in:
@@ -154,9 +154,14 @@ extension PlayerBackend {
|
||||
let nonHLSStreams = streams.filter {
|
||||
let isHLS = $0.kind == .hls
|
||||
// Check if the stream's resolution is within the maximum allowed resolution
|
||||
let isWithinResolution = $0.resolution.map { $0 <= maxResolution.value } ?? false
|
||||
// Safety: Ensure resolution exists before comparing
|
||||
guard let streamResolution = $0.resolution else {
|
||||
logger.info("Stream ID: \($0.id) has nil resolution, skipping")
|
||||
return false
|
||||
}
|
||||
let isWithinResolution = streamResolution <= maxResolution.value
|
||||
|
||||
logger.info("Stream ID: \($0.id) - Kind: \(String(describing: $0.kind)) - Resolution: \(String(describing: $0.resolution)) - Bitrate: \($0.bitrate ?? 0)")
|
||||
logger.info("Stream ID: \($0.id) - Kind: \(String(describing: $0.kind)) - Resolution: \(String(describing: streamResolution)) - Bitrate: \($0.bitrate ?? 0)")
|
||||
logger.info("Is HLS: \(isHLS), Is within resolution: \(isWithinResolution)")
|
||||
|
||||
logger.info("video url: \($0.videoAsset?.url.absoluteString ?? "nil"), audio url: \($0.audioAsset?.url.absoluteString ?? "nil")")
|
||||
@@ -191,8 +196,13 @@ extension PlayerBackend {
|
||||
}
|
||||
|
||||
let filteredStreams = adjustedStreams.filter { stream in
|
||||
// Safety check: Ensure stream has a resolution
|
||||
guard let streamResolution = stream.resolution else {
|
||||
logger.info("Filtered stream ID: \(stream.id) has nil resolution, excluding")
|
||||
return false
|
||||
}
|
||||
// Check if the stream's resolution is within the maximum allowed resolution
|
||||
let isWithinResolution = stream.resolution <= maxResolution.value
|
||||
let isWithinResolution = streamResolution <= maxResolution.value
|
||||
logger.info("Filtered stream ID: \(stream.id) - Is within max resolution: \(isWithinResolution)")
|
||||
return isWithinResolution
|
||||
}
|
||||
@@ -200,7 +210,15 @@ extension PlayerBackend {
|
||||
logger.info("Filtered streams count after adjustments: \(filteredStreams.count)")
|
||||
|
||||
let bestStream = filteredStreams.max { lhs, rhs in
|
||||
if lhs.resolution == rhs.resolution {
|
||||
// Safety check: Ensure both streams have resolutions
|
||||
guard let lhsResolution = lhs.resolution, let rhsResolution = rhs.resolution else {
|
||||
logger.info("One or both streams missing resolution - LHS: \(lhs.id), RHS: \(rhs.id)")
|
||||
// If lhs has no resolution, it's "less than" rhs (prefer rhs)
|
||||
// If rhs has no resolution, it's "less than" lhs (prefer lhs)
|
||||
return lhs.resolution == nil
|
||||
}
|
||||
|
||||
if lhsResolution == rhsResolution {
|
||||
guard let lhsFormat = QualityProfile.Format(rawValue: lhs.format.rawValue),
|
||||
let rhsFormat = QualityProfile.Format(rawValue: rhs.format.rawValue)
|
||||
else {
|
||||
@@ -216,9 +234,9 @@ extension PlayerBackend {
|
||||
return lhsFormatIndex > rhsFormatIndex
|
||||
}
|
||||
|
||||
logger.info("Comparing resolutions for streams \(lhs.id) and \(rhs.id) - LHS Resolution: \(String(describing: lhs.resolution)), RHS Resolution: \(String(describing: rhs.resolution))")
|
||||
logger.info("Comparing resolutions for streams \(lhs.id) and \(rhs.id) - LHS Resolution: \(String(describing: lhsResolution)), RHS Resolution: \(String(describing: rhsResolution))")
|
||||
|
||||
return lhs.resolution < rhs.resolution
|
||||
return lhsResolution < rhsResolution
|
||||
}
|
||||
|
||||
logger.info("Best stream selected: \(String(describing: bestStream?.id)) with resolution: \(String(describing: bestStream?.resolution)) and format: \(String(describing: bestStream?.format))")
|
||||
|
||||
@@ -52,7 +52,7 @@ extension PlayerModel {
|
||||
func playItem(_ item: PlayerQueueItem, at time: CMTime? = nil) {
|
||||
advancing = false
|
||||
|
||||
if !playingInPictureInPicture, !currentItem.isNil {
|
||||
if !playingInPictureInPicture, !currentItem.isNil, backend != nil {
|
||||
backend.closeItem()
|
||||
}
|
||||
|
||||
@@ -125,6 +125,12 @@ extension PlayerModel {
|
||||
}
|
||||
|
||||
var streamByQualityProfile: Stream? {
|
||||
// Safety check: Ensure backend is available
|
||||
guard backend != nil else {
|
||||
logger.error("Backend is nil when trying to select stream by quality profile")
|
||||
return nil
|
||||
}
|
||||
|
||||
let profile = qualityProfile ?? .defaultProfile
|
||||
|
||||
// First attempt: Filter by both `canPlay` and `isPreferred`
|
||||
@@ -229,7 +235,9 @@ extension PlayerModel {
|
||||
self.removeQueueItems()
|
||||
}
|
||||
|
||||
backend.closeItem()
|
||||
if backend != nil {
|
||||
backend.closeItem()
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult func enqueueVideo(
|
||||
|
||||
@@ -76,8 +76,13 @@ struct QualityProfile: Hashable, Identifiable, Defaults.Serializable {
|
||||
return true
|
||||
}
|
||||
|
||||
// Safety check: Ensure stream has a resolution
|
||||
guard let streamResolution = stream.resolution else {
|
||||
return false
|
||||
}
|
||||
|
||||
let defaultResolution = Stream.Resolution.custom(height: 720, refreshRate: 30)
|
||||
let resolutionMatch = resolution.value ?? defaultResolution >= stream.resolution
|
||||
let resolutionMatch = resolution.value ?? defaultResolution >= streamResolution
|
||||
|
||||
if resolutionMatch, formats.contains(.stream), stream.kind == .stream {
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user