Implement artwork download and cache
This commit is contained in:
@@ -1,6 +1,38 @@
|
||||
import Foundation
|
||||
import VelodyDomain
|
||||
|
||||
public struct RemoteArtworkDTO: Codable, Hashable, Sendable {
|
||||
public var artworkId: String
|
||||
public var sha256: String
|
||||
public var mimeType: String
|
||||
public var width: Int?
|
||||
public var height: Int?
|
||||
|
||||
public init(
|
||||
artworkId: String,
|
||||
sha256: String,
|
||||
mimeType: String,
|
||||
width: Int? = nil,
|
||||
height: Int? = nil
|
||||
) {
|
||||
self.artworkId = artworkId
|
||||
self.sha256 = sha256
|
||||
self.mimeType = mimeType
|
||||
self.width = width
|
||||
self.height = height
|
||||
}
|
||||
|
||||
public var remoteArtwork: RemoteArtwork {
|
||||
RemoteArtwork(
|
||||
artworkId: artworkId,
|
||||
sha256: sha256,
|
||||
mimeType: mimeType,
|
||||
width: width,
|
||||
height: height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public struct RemoteTrackDTO: Codable, Hashable, Sendable {
|
||||
public var trackId: String
|
||||
public var title: String
|
||||
@@ -10,6 +42,7 @@ public struct RemoteTrackDTO: Codable, Hashable, Sendable {
|
||||
public var assetId: String
|
||||
public var createdAt: String
|
||||
public var updatedAt: String
|
||||
public var artwork: RemoteArtworkDTO?
|
||||
|
||||
public init(
|
||||
trackId: String,
|
||||
@@ -19,7 +52,8 @@ public struct RemoteTrackDTO: Codable, Hashable, Sendable {
|
||||
sha256: String,
|
||||
assetId: String,
|
||||
createdAt: String,
|
||||
updatedAt: String
|
||||
updatedAt: String,
|
||||
artwork: RemoteArtworkDTO? = nil
|
||||
) {
|
||||
self.trackId = trackId
|
||||
self.title = title
|
||||
@@ -29,6 +63,7 @@ public struct RemoteTrackDTO: Codable, Hashable, Sendable {
|
||||
self.assetId = assetId
|
||||
self.createdAt = createdAt
|
||||
self.updatedAt = updatedAt
|
||||
self.artwork = artwork
|
||||
}
|
||||
|
||||
public var remoteTrack: RemoteTrack {
|
||||
@@ -40,7 +75,8 @@ public struct RemoteTrackDTO: Codable, Hashable, Sendable {
|
||||
sha256: sha256,
|
||||
assetId: assetId,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt
|
||||
updatedAt: updatedAt,
|
||||
artwork: artwork?.remoteArtwork
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,11 @@ public protocol VelodyAPIClient: Sendable {
|
||||
deviceId: String
|
||||
) async throws -> Data
|
||||
|
||||
func downloadArtwork(
|
||||
artworkId: String,
|
||||
deviceId: String
|
||||
) async throws -> Data
|
||||
|
||||
func prepareUpload(
|
||||
_ payload: UploadPrepareRequest
|
||||
) async throws -> UploadPrepareResponse
|
||||
@@ -145,6 +150,23 @@ public struct URLSessionVelodyAPIClient: VelodyAPIClient {
|
||||
return try await executeData(request)
|
||||
}
|
||||
|
||||
public func downloadArtwork(
|
||||
artworkId: String,
|
||||
deviceId: String
|
||||
) async throws -> Data {
|
||||
let request = try buildRequest(
|
||||
method: "GET",
|
||||
pathComponents: ["api", "v1", "artwork", artworkId, "download"],
|
||||
queryItems: [
|
||||
URLQueryItem(name: "deviceId", value: deviceId),
|
||||
],
|
||||
bodyData: nil,
|
||||
acceptType: "image/*"
|
||||
)
|
||||
|
||||
return try await executeData(request)
|
||||
}
|
||||
|
||||
public func prepareUpload(
|
||||
_ payload: UploadPrepareRequest
|
||||
) async throws -> UploadPrepareResponse {
|
||||
@@ -450,6 +472,18 @@ public struct StubVelodyAPIClient: VelodyAPIClient {
|
||||
])
|
||||
}
|
||||
|
||||
public func downloadArtwork(
|
||||
artworkId: String,
|
||||
deviceId: String
|
||||
) async throws -> Data {
|
||||
_ = artworkId
|
||||
_ = deviceId
|
||||
|
||||
return Data([
|
||||
0x89, 0x50, 0x4E, 0x47,
|
||||
])
|
||||
}
|
||||
|
||||
public func prepareUpload(
|
||||
_ payload: UploadPrepareRequest
|
||||
) async throws -> UploadPrepareResponse {
|
||||
|
||||
+28
-2
@@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import XCTest
|
||||
import VelodyDomain
|
||||
@testable import VelodyNetworking
|
||||
|
||||
final class RemoteLibraryDTOTests: XCTestCase {
|
||||
@@ -12,7 +13,14 @@ final class RemoteLibraryDTOTests: XCTestCase {
|
||||
sha256: String(repeating: "a", count: 64),
|
||||
assetId: "asset-456",
|
||||
createdAt: "2026-05-29T08:00:00.000Z",
|
||||
updatedAt: "2026-05-29T08:05:00.000Z"
|
||||
updatedAt: "2026-05-29T08:05:00.000Z",
|
||||
artwork: RemoteArtworkDTO(
|
||||
artworkId: "artwork-789",
|
||||
sha256: String(repeating: "b", count: 64),
|
||||
mimeType: "image/png",
|
||||
width: 512,
|
||||
height: 512
|
||||
)
|
||||
)
|
||||
|
||||
let track = dto.remoteTrack
|
||||
@@ -23,6 +31,16 @@ final class RemoteLibraryDTOTests: XCTestCase {
|
||||
XCTAssertEqual(track.durationSeconds, 245)
|
||||
XCTAssertEqual(track.sha256, String(repeating: "a", count: 64))
|
||||
XCTAssertEqual(track.assetId, "asset-456")
|
||||
XCTAssertEqual(
|
||||
track.artwork,
|
||||
RemoteArtwork(
|
||||
artworkId: "artwork-789",
|
||||
sha256: String(repeating: "b", count: 64),
|
||||
mimeType: "image/png",
|
||||
width: 512,
|
||||
height: 512
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testRemoteLibraryResponseDTODecodesFromAPIResponse() throws {
|
||||
@@ -38,7 +56,14 @@ final class RemoteLibraryDTOTests: XCTestCase {
|
||||
"sha256": "\(String(repeating: "a", count: 64))",
|
||||
"assetId": "asset-456",
|
||||
"createdAt": "2026-05-29T08:00:00.000Z",
|
||||
"updatedAt": "2026-05-29T08:05:00.000Z"
|
||||
"updatedAt": "2026-05-29T08:05:00.000Z",
|
||||
"artwork": {
|
||||
"artworkId": "artwork-789",
|
||||
"sha256": "\(String(repeating: "b", count: 64))",
|
||||
"mimeType": "image/png",
|
||||
"width": 512,
|
||||
"height": 512
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -50,5 +75,6 @@ final class RemoteLibraryDTOTests: XCTestCase {
|
||||
XCTAssertEqual(decoded.tracks.count, 1)
|
||||
XCTAssertEqual(decoded.tracks.first?.trackId, "track-123")
|
||||
XCTAssertEqual(decoded.tracks.first?.durationSeconds, 245)
|
||||
XCTAssertEqual(decoded.tracks.first?.artwork?.artworkId, "artwork-789")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user