diff options
Diffstat (limited to 'MusicConverter/helpers/MusicKITApi.swift')
-rw-r--r-- | MusicConverter/helpers/MusicKITApi.swift | 148 |
1 files changed, 144 insertions, 4 deletions
diff --git a/MusicConverter/helpers/MusicKITApi.swift b/MusicConverter/helpers/MusicKITApi.swift index 0b394a3..e47241a 100644 --- a/MusicConverter/helpers/MusicKITApi.swift +++ b/MusicConverter/helpers/MusicKITApi.swift @@ -72,7 +72,7 @@ class AppleMusicApi: ObservableObject { do { let decodedData = try JSONDecoder().decode(musicData<StoreFront>.self, from: data!) - self.storeFront = decodedData.data.first + self.storeFront = decodedData.data!.first guard self.storeFront != nil else { completion(.failure(MusicKitError.NoStoreFront)) return @@ -80,6 +80,7 @@ class AppleMusicApi: ObservableObject { completion(.success(self.storeFront!.id)) } catch { print("data: \(String(decoding: data!, as: UTF8.self))") + print("error decoding: \(error)") completion(.failure(error)) return } @@ -112,9 +113,10 @@ class AppleMusicApi: ObservableObject { do { let decodedData = try JSONDecoder().decode(musicData<Song>.self, from: data!) - completion(.success(decodedData.data)) + completion(.success(decodedData.data!)) } catch { print("data: \(String(decoding: data!, as: UTF8.self))") + print("error song: \(error)") completion(.failure(error)) return } @@ -207,6 +209,8 @@ class AppleMusicApi: ObservableObject { } pos += 1; self.fetchForIsrc(isrc: isrc!, completion: callback) + } else { + completion(nil) } } } @@ -226,8 +230,144 @@ class AppleMusicApi: ObservableObject { self.fetchForIsrc(isrc: isrc!, completion: callback) } + public func createPlaylistAPI(name: String, tracks: [LibraryPlaylistRequestTrack]? = nil, description: String? = nil, completion: @escaping (Result<[LibraryPlaylist], Error>) -> Void) { + let request = LibraryPlaylistCreationRequest(name: name, tracks: tracks, description: description) + createPlaylistAPI(creationRequest: request, completion: completion) + } + + public func createPlaylistAPI(creationRequest: LibraryPlaylistCreationRequest, completion: @escaping (Result<[LibraryPlaylist], Error>) -> Void) { + + + guard let url = URL(string: "https://api.music.apple.com/v1/me/library/playlists") else { + completion(.failure(MusicKitError.InvalidUrl)) + return + } + var playlistRequest = self.buildRequest(url: url) + playlistRequest.httpMethod = "POST" + playlistRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") + do { + playlistRequest.httpBody = try JSONEncoder().encode(creationRequest) + let str = String(data: playlistRequest.httpBody!, encoding: .utf8) + print("request: \(str!)") + } catch { + completion(.failure(error)) + return + } + + URLSession.shared.dataTask(with: playlistRequest) { (data, response, error) in + guard error == nil else { + completion(.failure(error!)) + return + } + + do { + let decodedData = try JSONDecoder().decode(musicData<LibraryPlaylist>.self, from: data!) + if decodedData.hasError { + decodedData.printErrors() + completion(.failure(decodedData.errors!.first!)) + return + } + completion(.success(decodedData.data!)) + } catch { + print("error playlistCreationRequest: \(error)") + print("json response: \(String(data: data!, encoding: .utf8) ?? "error")") + completion(.failure(error)) + return + } + //completion(.success()) + } + .resume() + } + + // TODO: https://developer.apple.com/documentation/applemusicapi/responseroot struct musicData<T: Decodable>: Decodable { - var data: [T] + var data: [T]? + var errors: [ResposeError]? + + var hasError: Bool { + return errors != nil && errors?.count ?? 0 > 0 + } + + func printErrors() { + for error in errors ?? [] { + print("error: \(error)") + } + } + + public struct ResposeError: Codable, Error { + var code: String + var detail: String? + var id: String + // var source + var status: String + var title: String + } + } + + public struct LibraryPlaylistCreationRequest: Codable { + var attributes: Attributes + var relationships: Relationships? + + init(name: String, tracks: [LibraryPlaylistRequestTrack]? = nil, description: String? = nil) { + self.attributes = Attributes(name: name, description: description) + + if let tracks = tracks { + self.relationships = Relationships(tracks: Relationships.TracksData(data: tracks)) + } + } + + public struct Attributes: Codable { + var name: String + var description: String? + } + + public struct Relationships: Codable { + var tracks: TracksData + + public struct TracksData: Codable { + var data: [LibraryPlaylistRequestTrack] + } + } + } + + public struct LibraryPlaylistRequestTrack: Codable, Identifiable { + var id: String + var type: TrackType = .songs + + public enum TrackType: String, Codable { + case songs = "songs" + case music_videos = "music-videos" + case library_songs = "library-songs" + case library_music_videos = "library-music-videos" + } + } + + public struct LibraryPlaylist: Decodable { + var attributes: Attributes? + //var relationships: Relationships? + var type: String + var id: String + + /*var id: String? { + attributes?.playParams?.id + }*/ + + var name: String? { + attributes?.name + } + + public struct Attributes: Decodable { + var artwork: Song.Attributes.Artwork? + //var description: String? + var name: String + var playParams: Song.Attributes.PlayParameters? + var canEdit: Bool + } + + // TODO + public struct Relationships: Decodable { + + } } public struct StoreFront: Decodable { @@ -289,7 +429,7 @@ class AppleMusicApi: ObservableObject { var genreNames: [String] var isrc: String var name: String - var playParams: PlayParameters + var playParams: PlayParameters? // var previews: [Preview] (required) var releaseDate: String /// (Required) The number of the song in the album’s track list. |