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,56 @@
|
||||
import Foundation
|
||||
|
||||
public actor SilentEngine: OutputEngine {
|
||||
public nonisolated let events: AsyncStream<OutputEvent>
|
||||
private let continuation: AsyncStream<OutputEvent>.Continuation
|
||||
private var item: QueueItem?
|
||||
private var position: TimeInterval = 0
|
||||
private var startedAt: ContinuousClock.Instant?
|
||||
private var timer: Task<Void, Never>?
|
||||
|
||||
public init() {
|
||||
(events, continuation) = AsyncStream<OutputEvent>.makeStream()
|
||||
}
|
||||
|
||||
public func load(_ item: QueueItem, at position: TimeInterval) {
|
||||
timer?.cancel()
|
||||
self.item = item
|
||||
self.position = position
|
||||
startedAt = nil
|
||||
}
|
||||
|
||||
public func play() {
|
||||
guard let item, startedAt == nil else { return }
|
||||
startedAt = .now
|
||||
let remaining = max(item.track.duration - position, 0)
|
||||
timer = Task { [continuation] in
|
||||
try? await Task.sleep(for: .seconds(remaining))
|
||||
guard !Task.isCancelled else { return }
|
||||
continuation.yield(.finished(item.id))
|
||||
}
|
||||
}
|
||||
|
||||
public func pause() {
|
||||
timer?.cancel()
|
||||
if let startedAt {
|
||||
let elapsed = ContinuousClock.now - startedAt
|
||||
position += Double(elapsed.components.seconds) + Double(elapsed.components.attoseconds) / 1e18
|
||||
}
|
||||
startedAt = nil
|
||||
}
|
||||
|
||||
public func seek(to position: TimeInterval) {
|
||||
let wasPlaying = startedAt != nil
|
||||
pause()
|
||||
self.position = position
|
||||
if wasPlaying {
|
||||
play()
|
||||
}
|
||||
}
|
||||
|
||||
public func stop() {
|
||||
timer?.cancel()
|
||||
item = nil
|
||||
startedAt = nil
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user