jellyflood/Shared/Objects/MediaPlayerManager/MediaPlayerItem/MediaPlayerItem.swift

103 lines
3.2 KiB
Swift

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
//
import JellyfinAPI
import SwiftUI
// TODO: get preview image for current manager seconds?
// - would make scrubbing image possibly ready before scrubbing
// TODO: fix leaks
// - made from publishers of observers not being cancelled
@MainActor
class MediaPlayerItem: ViewModel, MediaPlayerObserver {
typealias ThumbnailProvider = () async -> UIImage?
@Published
var selectedAudioStreamIndex: Int? = nil {
didSet {
if let proxy = manager?.proxy as? any VideoMediaPlayerProxy {
proxy.setAudioStream(.init(index: selectedAudioStreamIndex))
}
}
}
@Published
var selectedSubtitleStreamIndex: Int? = nil {
didSet {
if let proxy = manager?.proxy as? any VideoMediaPlayerProxy {
proxy.setSubtitleStream(.init(index: selectedSubtitleStreamIndex))
}
}
}
weak var manager: MediaPlayerManager? {
didSet {
for var o in observers {
o.manager = manager
}
}
}
var observers: [any MediaPlayerObserver] = []
let baseItem: BaseItemDto
let mediaSource: MediaSourceInfo
let playSessionID: String
let previewImageProvider: (any PreviewImageProvider)?
let thumbnailProvider: ThumbnailProvider?
let url: URL
let audioStreams: [MediaStream]
let subtitleStreams: [MediaStream]
let videoStreams: [MediaStream]
let requestedBitrate: PlaybackBitrate
// MARK: init
init(
baseItem: BaseItemDto,
mediaSource: MediaSourceInfo,
playSessionID: String,
url: URL,
requestedBitrate: PlaybackBitrate = .max,
previewImageProvider: (any PreviewImageProvider)? = nil,
thumbnailProvider: ThumbnailProvider? = nil
) {
self.baseItem = baseItem
self.mediaSource = mediaSource
self.playSessionID = playSessionID
self.requestedBitrate = requestedBitrate
self.previewImageProvider = previewImageProvider
self.thumbnailProvider = thumbnailProvider
self.url = url
let adjustedMediaStreams = mediaSource.mediaStreams?.adjustedTrackIndexes(
for: mediaSource.transcodingURL == nil ? .directPlay : .transcode,
selectedAudioStreamIndex: mediaSource.defaultAudioStreamIndex ?? 0
)
let audioStreams = adjustedMediaStreams?.filter { $0.type == .audio } ?? []
let subtitleStreams = adjustedMediaStreams?.filter { $0.type == .subtitle } ?? []
let videoStreams = adjustedMediaStreams?.filter { $0.type == .video } ?? []
self.audioStreams = audioStreams
self.subtitleStreams = subtitleStreams
self.videoStreams = videoStreams
super.init()
selectedAudioStreamIndex = mediaSource.defaultAudioStreamIndex ?? -1
selectedSubtitleStreamIndex = mediaSource.defaultSubtitleStreamIndex ?? -1
observers.append(MediaProgressObserver(item: self))
}
}