80 lines
2.1 KiB
Swift
80 lines
2.1 KiB
Swift
import Foundation
|
|
|
|
public struct ResourceRequest: Hashable, Sendable {
|
|
public var url: URL
|
|
public var headers: [String: String]
|
|
public var expiresAt: Date?
|
|
|
|
public init(url: URL, headers: [String: String] = [:], expiresAt: Date? = nil) {
|
|
self.url = url
|
|
self.headers = headers
|
|
self.expiresAt = expiresAt
|
|
}
|
|
}
|
|
|
|
public struct StreamRequest: Hashable, Sendable {
|
|
public var resource: ResourceRequest
|
|
public var format: AudioFormat?
|
|
|
|
public init(resource: ResourceRequest, format: AudioFormat?) {
|
|
self.resource = resource
|
|
self.format = format
|
|
}
|
|
}
|
|
|
|
public struct Cursor: Hashable, Codable, Sendable {
|
|
public let raw: String
|
|
|
|
public init(_ raw: String) {
|
|
self.raw = raw
|
|
}
|
|
}
|
|
|
|
public struct Annotation: Hashable, Codable, Sendable {
|
|
public var favoritedAt: Date?
|
|
public var playCount: Int
|
|
public var lastPlayedAt: Date?
|
|
|
|
public init(favoritedAt: Date? = nil, playCount: Int = 0, lastPlayedAt: Date? = nil) {
|
|
self.favoritedAt = favoritedAt
|
|
self.playCount = playCount
|
|
self.lastPlayedAt = lastPlayedAt
|
|
}
|
|
}
|
|
|
|
public enum Entity: Sendable {
|
|
case artist(Artist)
|
|
case album(Album)
|
|
case track(Track)
|
|
case playlist(Playlist, entries: [PlaylistEntry])
|
|
case station(RadioStation)
|
|
}
|
|
|
|
public enum Change: Sendable {
|
|
case upsert(Entity)
|
|
case remove(EntityKind, EntityID)
|
|
case annotate(EntityID, Annotation)
|
|
case checkpoint(Cursor)
|
|
}
|
|
|
|
public enum SourceError: Error {
|
|
case cannotCalculateChanges
|
|
case notFound
|
|
}
|
|
|
|
public protocol LibrarySource: Sendable {
|
|
var id: SourceID { get }
|
|
var name: String { get }
|
|
func changes(since cursor: Cursor?) -> AsyncThrowingStream<Change, Error>
|
|
func stream(for track: EntityID) async throws -> StreamRequest
|
|
func artwork(_ id: EntityID, pixelSize: Int) async throws -> ResourceRequest
|
|
}
|
|
|
|
public protocol Starring: LibrarySource {
|
|
func setFavorite(_ isFavorite: Bool, for id: EntityID, kind: EntityKind) async throws
|
|
}
|
|
|
|
public protocol Scrobbling: LibrarySource {
|
|
func scrobble(_ track: EntityID, at date: Date, submission: Bool) async throws
|
|
}
|