Files
ios/MusicBridgeRemote/MusicBridgeRemote.swift
T

69 lines
3.1 KiB
Swift
Raw Normal View History

import ExtensionFoundation
import NowPlaying
import Observation
import Foundation
@main
struct MusicBridgeRemote: RemoteMediaSessionExtension {
var configuration: RemoteMediaSessionExtensionConfiguration<Self> {
RemoteMediaSessionExtensionConfiguration(extension: self)
}
func session(_ attributes: SystemPlayerAttributes) async throws -> PCMediaSession {
_ = try SystemPlayerCredentials.load(attributes.id)
return PCMediaSession(attributes)
}
}
@MainActor @Observable
final class PCMediaSession: RemoteMediaSessionRepresentable {
let id: String
var attributes: SystemPlayerAttributes
private let transport = SystemPlayerTransport()
init(_ attributes: SystemPlayerAttributes) { id = attributes.id; self.attributes = attributes }
func update(_ attributes: SystemPlayerAttributes) { self.attributes = attributes }
var content: (any MediaContentRepresentable)? {
guard attributes.hasSession else { return nil }
let artwork = attributes.artworkID.map { artworkID in
Artwork(id: artworkID) { _ in
let saved = try SystemPlayerCredentials.load(self.id)
let client = BridgeClient(saved, timeout: 5)
defer { client.close() }
return try ArtworkRepresentation(data: await client.artwork(artworkID))
}
}
return MusicContent(id: attributes.source + "/" + attributes.title + "/" + attributes.artist,
songTitle: attributes.title.isEmpty ? "Без названия" : attributes.title,
artistName: attributes.artist, albumName: "", type: .audio,
duration: attributes.duration > 0 ? .finite(attributes.duration) : nil, artwork: artwork)
}
var playbackSnapshot: MediaPlaybackSnapshot? {
MediaPlaybackSnapshot(state: attributes.playing ? .playing(rate: Float(attributes.rate)) : .paused,
elapsedTime: attributes.position, timestamp: attributes.timestamp)
}
var commands: [MediaCommand] {
[
.play { try await self.send(.play) }.enabled(attributes.capabilities.play),
.pause { try await self.send(.pause) }.enabled(attributes.capabilities.pause),
.next { try await self.send(.next) }.enabled(attributes.capabilities.next),
.previous { try await self.send(.previous) }.enabled(attributes.capabilities.previous),
.seekToPosition { try await self.send(.seek, value: $0) }.enabled(attributes.capabilities.seek)
]
}
var devices: [MediaDevice] {
let capabilities: [MediaDevice.Capability] = attributes.volume.map { volume in
[.absoluteVolume(Float(volume)) { try await self.send(.volume, value: Double($0)) }]
} ?? []
return [MediaDevice(id: id, name: "MusicBridge · ПК", type: .speaker, capabilities: capabilities)]
}
private func send(_ action: SystemPlayerAction, value: Double? = nil) async throws {
let state = try await transport.send(action, value: value, sessionID: id)
attributes = SystemPlayerAttributes(id: id, state: state)
}
}