Peter-Schorn/SpotifyAPI

Get Track API Object Info

Closed this issue · 3 comments

Hi Peter, ty for making this library!!

More of a 'how to' than an issue....:

I'm trying to object info from a get track -> artist, album, etc. see:
https://developer.spotify.com/documentation/web-api/reference/#object-trackobject

Using:
`

    let spotify = SpotifyAPI(
        authorizationManager: AuthorizationCodeFlowManager(
            clientId: SpotifyClientID, clientSecret: SpotifyClientSecret
        )
    )
    
    let authorizationURL = spotify.authorizationManager.makeAuthorizationURL(
        redirectURI: URL(string: SpotifyRedirectURL)!,
        showDialog: false,
        scopes: [
            .playlistModifyPrivate,
            .userModifyPlaybackState,
            .playlistReadCollaborative,
            .userReadPlaybackPosition,
            .appRemoteControl
        ]
    )!
            
    Spotify().authorize()

    let testURI = "spotify:track:14g6foD6sxO1qgkDKuPgWv" as SpotifyURIConvertible
                    
    let track = spotify.track(testURI)

    print("spotify: Track: ", track)

`

I get track as :

spotify: Track: AnyPublisher

What is the approach to get the object info from the Track API endpoint?

TY!

You seem to have some major misconceptions about this library. First of all, why are you calling Spotify().authorize() without retaining the instance that it returns? Also, you never opened the authorization URL that you created using AuthorizationCodeFlowManager.makeAuthorizationURL(redirectURI:showDialog:state:scopes:) in the browser; that doesn't make any sense.

As specified in the README (please read it again very carefully), authorizing with the Spotify web API is a two-step process. First, you create and open the authorization URL, which displays a permissions dialog asking the user to login to their Spotify account. After the user logs in and clicks "agree" (or "cancel"), Spotify redirects to the redirect URI that you specify with query parameters appended to it. Pass this URL to requestAccessAndRefreshTokens(redirectURIWithQuery:state:) in order to request the access and refresh tokens, which completes the authorization process.

Furthermore, this library uses apple's Combine framework in order to handle asynchronous events. Notice that SpotifyAPI.track(_:market:) returns a publisher. You must subscribe to this publisher in order to receive the track. A full tutorial of how the Combine framework works is outside the scope of this discussion, although I am willing to answer some questions. Here are some resources for you:

https://www.swiftbysundell.com/basics/combine/ (a simple introduction)
https://developer.apple.com/documentation/combine/receiving-and-handling-events-with-combine
https://heckj.github.io/swiftui-notes/#coreconcepts-subscribers (a comprehensive overview)

See also this example iOS app and this example command-line app.

Below is the full code for authorizing your app and then retrieving a track. In order to run it, you must register the following redirect URI in the dashboard:

http://localhost:8080

Run this code inside a command-line program. You can't use a playground because playgrounds don't support reading from standard input.

import Foundation
import SpotifyWebAPI
import Combine
import Cocoa

let dispatchGroup = DispatchGroup()
var cancellables: Set<AnyCancellable> = []

let spotify = SpotifyAPI(
    authorizationManager: AuthorizationCodeFlowManager(
        clientId: "your client id",
        clientSecret: "your client secret"
    )
)

let authorizationURL = spotify.authorizationManager.makeAuthorizationURL(
    redirectURI: URL(string: "http://localhost:8080")!,
    showDialog: false,
    scopes: [
        .playlistModifyPrivate,
        .userModifyPlaybackState,
        .playlistReadCollaborative,
        .userReadPlaybackPosition,
        .appRemoteControl
    ]
)!

NSWorkspace.shared.open(authorizationURL)

print(
    """
    after you log in to your Spotify account and are redirected, \
    paste the URL that you were redirected to here:
    """
)

guard let redirectURIWithQueryString = readLine()?
        .trimmingCharacters(in: .whitespacesAndNewlines) else {
    fatalError("couldn't read from standard input")
}

guard let redirectURIWithQuery = URL(
    string: redirectURIWithQueryString
) else {
    fatalError("couldn't convert to URL: '\(redirectURIWithQueryString)'")
}

dispatchGroup.enter()
spotify.authorizationManager.requestAccessAndRefreshTokens(
    redirectURIWithQuery: redirectURIWithQuery
)
.sink(receiveCompletion: { completion in
    switch completion {
        case .finished:
            print("successfully authorized")
        case .failure(let error):
            if let authError = error as? SpotifyAuthorizationError, authError.accessWasDenied {
                fatalError("The user denied the authorization request")
            }
            else {
                fatalError("couldn't authorize application: \(error)")
            }
    }
    dispatchGroup.leave()
})
.store(in: &cancellables)
dispatchGroup.wait()

// MARK: At this point, your application is authorized and you can
// MARK: begin making requests to the Spotify web API.

// you don't need to explicitly cast `String` to `SpotifyURIConvertible`
let testURI = "spotify:track:14g6foD6sxO1qgkDKuPgWv"

dispatchGroup.enter()
spotify.track(testURI)
    .sink(
        receiveCompletion: { completion in
            print("completion: \(completion)")
            dispatchGroup.leave()
        },
        receiveValue: { track in
            print("received track: \(track)")
        }
    )
    .store(in: &cancellables)
dispatchGroup.wait()

Ty for the quick and detailed reply. I will get more educated on Combine, but the code sample you provided explains the use case - appreciate it.

I am closing this issue for now. Open a new issue if you have more questions.