feat(*): subsonic client with avfoundation playback and apple music ui
This commit is contained in:
commit
e5bb559d7f
93 files changed
+7517
No files matched your search
@@ -0,0 +1,88 @@
|
||||
import Domain
|
||||
import Foundation
|
||||
|
||||
public struct QueueItem: Identifiable, Hashable, Codable, Sendable {
|
||||
public let id: UUID
|
||||
public let track: Track
|
||||
|
||||
public init(id: UUID = UUID(), track: Track) {
|
||||
self.id = id
|
||||
self.track = track
|
||||
}
|
||||
}
|
||||
|
||||
public enum RepeatMode: String, Codable, Sendable, CaseIterable {
|
||||
case off, all, one
|
||||
}
|
||||
|
||||
public enum PlaybackCommand: Codable, Sendable {
|
||||
case play
|
||||
case pause
|
||||
case togglePlayPause
|
||||
case seek(to: TimeInterval)
|
||||
case next
|
||||
case previous
|
||||
case setQueue(tracks: [Track], startIndex: Int, shuffled: Bool)
|
||||
case insertNext([Track])
|
||||
case insertLast([Track])
|
||||
case jump(to: QueueItem.ID)
|
||||
case move(item: QueueItem.ID, after: QueueItem.ID?)
|
||||
case remove(QueueItem.ID)
|
||||
case clearUpcoming
|
||||
case setShuffle(Bool)
|
||||
case setRepeat(RepeatMode)
|
||||
}
|
||||
|
||||
public struct PlaybackAnchor: Hashable, Sendable {
|
||||
public var position: TimeInterval
|
||||
public var instant: ContinuousClock.Instant
|
||||
public var rate: Double
|
||||
|
||||
public init(position: TimeInterval, instant: ContinuousClock.Instant, rate: Double) {
|
||||
self.position = position
|
||||
self.instant = instant
|
||||
self.rate = rate
|
||||
}
|
||||
|
||||
public func position(at now: ContinuousClock.Instant) -> TimeInterval {
|
||||
let elapsed = now - instant
|
||||
let seconds = Double(elapsed.components.seconds) + Double(elapsed.components.attoseconds) / 1e18
|
||||
return position + seconds * rate
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlaybackStatus: String, Sendable {
|
||||
case stopped, paused, playing
|
||||
}
|
||||
|
||||
public struct PlaybackState: Hashable, Sendable {
|
||||
public var history: [QueueItem] = []
|
||||
public var current: QueueItem?
|
||||
public var upcoming: [QueueItem] = []
|
||||
public var status: PlaybackStatus = .stopped
|
||||
public var anchor = PlaybackAnchor(position: 0, instant: .now, rate: 0)
|
||||
public var isShuffled = false
|
||||
public var repeatMode: RepeatMode = .off
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public enum OutputEvent: Sendable {
|
||||
case finished(QueueItem.ID)
|
||||
case failed(QueueItem.ID)
|
||||
case anchor(QueueItem.ID, position: TimeInterval, rate: Double)
|
||||
}
|
||||
|
||||
public protocol OutputEngine: Sendable {
|
||||
var events: AsyncStream<OutputEvent> { get }
|
||||
func load(_ item: QueueItem, at position: TimeInterval) async
|
||||
func prepare(_ item: QueueItem?) async
|
||||
func play() async
|
||||
func pause() async
|
||||
func seek(to position: TimeInterval) async
|
||||
func stop() async
|
||||
}
|
||||
|
||||
public extension OutputEngine {
|
||||
func prepare(_: QueueItem?) async {}
|
||||
}
|
||||
Reference in new issue
Block a user