0

I have looked at several posts here about issues very close to this one including one that is exactly the same but no one gave an answer so I am going to give it a go. I am very new to Python. My current homework is to connect to Spotify using their API. According to the documentation on authorization code flow in Spotify. the response to the authorization request should provide two items: code and state.

After I send my request

def authenticate_user():
auth_code = requests.get(ENPOINT_USER_AUTH, {
    'client_id': CLIENT_ID,
    'response_type': 'code',
    'redirect_uri': 'https://www.example.com/',
    'scope': 'playlist-modify-private'
})

print(f'Auth code: {auth_code}')

I get a Auth code: <Response [200]>. The response however does not include a code or state. What comes with the response though, is a URL that I can copy-paste into the browser which will redirect me to a callabck URL with the code in it.

My issue here is, I want to save that code into a variable in my Python code. This copy-pasting into a browser can't be the way to do this.

My other problem is that I really don't know what a callback server/redirect is and how to use or set it up to extract this information, or how do achieve this in my python code.

Basically a lot of beginer' questions I apologize. But it's been hours of research and reading and I really would like some input.

This is what the redirect URL looks like after pasting the URL I get in the response.

https://www.example.com/?code=AQAqA0eYYk......JLVUomOR0ziDTcIupZoU

I hope this is clear and I am making sense.

Thank you in advance.

Oh, and I know about Spotipy and that it's supposed to simplify things but I am not interested. I want to learn to use the Spotify aPI.

To make it short and clear: how can I obtain this "code" from their response URL and save it into a variable in my python code programmatically?

EDIT:

Let's say that I want to keep a main.py for the logic and a service.py for the for the localhost services.

Once I have authenticated the user and I get the URL that redirects, how can I feed this URL to my service to get the final URL. I want to be able to send requests from my main.py to the service and get the data in the response rather than keeping everything on the service side.

kenpino
  • 63
  • 7

2 Answers2

1

I will demo two versions (full and simple) for get playlist API call.

Full Version

This code is v1 using Flask and requests_oauthlib.

The redirect URL should be match with your Developer Dashboard configuration in here.

Developer Dashboard

https://developer.spotify.com/dashboard

Save as full_code.py file name.

from flask import Flask, request, redirect
from requests_oauthlib import OAuth2Session
from requests.auth import HTTPBasicAuth
import os
import requests
import json

app = Flask(__name__)

AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
PORT = 3000 # replace <your redirect port>
REDIRECT_URI = 'http://localhost:{}/callback'.format(PORT) # my configuration is 'http://localhost:3000/callback' in dashboard
CLIENT_ID = '<your client id>'
CLIENT_SECRET = '<your client secret>'
# You can add your required scopes
SCOPE = [
    'user-read-currently-playing',
    'playlist-modify-private'
]
@app.route("/login")
def login():
    spotify = OAuth2Session(client_id = CLIENT_ID, scope=SCOPE, redirect_uri=REDIRECT_URI)
    authorization_url, state = spotify.authorization_url(AUTH_URL)
    return redirect(authorization_url)

@app.route("/callback", methods=['GET'])
def callback():
    code = request.args.get('code')
    response = requests.post(TOKEN_URL,
        auth = HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        data = {
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': REDIRECT_URI
        })
    # Save Access Token to environment variable
    os.environ['ACCESS_TOKEN'] = response.json()['access_token']
    headers = {
        # Get Access Token from environment variable
        'Authorization': "Bearer {}".format(os.environ['ACCESS_TOKEN'])
    }

    # get playlist API call with <your playlist id>
    url = 'https://api.spotify.com/v1/playlists/{}'.format('37i9dQZF1DX0tnKPLNG9Ld')
    response = requests.get(url, headers=headers)
    results = response.json()
    songs = []
    for item in results['tracks']['items']:
        if (item is not None and item['track']['artists'][0] is not None):
            # display format <artists name : song title>
            songs.append(item['track']['artists'][0]['name']  + " : " + item['track']['name'])
    return json.dumps(songs)

if __name__ == '__main__':
    app.run(port = PORT,debug = True)

Run it

python full_code.py

Then open URL by browser

http://localhost:3000/login

Result enter image description here

Simple Version

Using spotipy

Save as simple_code.py file name.

import spotipy
from spotipy.oauth2 import SpotifyOAuth

PORT = 3000 # replace <your redirect port>
REDIRECT_URI = 'http://localhost:{}/callback'.format(PORT) # my configuration is 'http://localhost:3000/callback' in dashboard
CLIENT_ID = '<your client id>'
CLIENT_SECRET = '<your client secret>'
PLAYLIST_ID = '37i9dQZF1DX0tnKPLNG9Ld' # <your playlist id>

sp = spotipy.Spotify(
    auth_manager = SpotifyOAuth(
        client_id = CLIENT_ID,
        client_secret = CLIENT_SECRET,
        redirect_uri = REDIRECT_URI,
        # You can add your required scopes
        scope=['user-read-currently-playing','playlist-modify-private']))

def Get_Playlist(playlist_id):
    # get playlist API call
    results = sp.playlist(playlist_id)
    for item in results['tracks']['items']:
        if (item is not None and item['track']['artists'][0] is not None):
            # artists name : song title
            print(item['track']['artists'][0]['name']  + "\t" + " : " + item['track']['name'])

Get_Playlist(PLAYLIST_ID)

Run it

python simple_code.py

Result

enter image description here

Bench Vue
  • 5,257
  • 2
  • 10
  • 14
  • Thanks a lot for your reply - it works great :) - now i need some time to understand why it works and how, lots of new stuff for me here :) – kenpino Aug 30 '23 at 08:47
  • 1
    Good to hear to success my demo versions, let me know the specific part to understand in my code. – Bench Vue Aug 30 '23 at 08:59
  • Thank you :) - is there a way to keep the logic and the service separate? I want to manipulate the data on a main.py for example and make requests to the service. I edited my post with more info about this, – kenpino Aug 30 '23 at 09:34
  • 1
    No way without using browser for `authorization code` grant flow in [here](https://stackoverflow.com/questions/48821666/is-it-possible-to-get-authorization-code-in-oauth-2-0-without-web-browser-in-jav) – Bench Vue Aug 30 '23 at 09:44
  • Allright then :) ty so much for taking the time! Super helpfull – kenpino Aug 30 '23 at 09:47
  • 1
    No problem, your accept and vote me will make me happy. – Bench Vue Aug 30 '23 at 09:48
  • :) done - one last thing - what can i do if i scrapped https://www.billboard.com/charts/hot-100/ for a list of songs and I want to pass this data somehow to the service to build a playlist with these items? is there a way to link the python file where i scrapped this data to the service? – kenpino Aug 30 '23 at 10:08
  • Thanks for your accepting. I will try web scrapping when I return home but I am not sure, it is easy or hard. – Bench Vue Aug 30 '23 at 10:20
  • Can you try this in [here](https://stackoverflow.com/questions/73356641/how-to-scrape-billboard-using-find-all)? – Bench Vue Aug 30 '23 at 10:23
  • oh don't wory about web scrapping! that part I've actually done :) - i end up with a simple list of songs. what needs to happen now is a search, create the playlsit, and add the tracks. would something like this work: create new endpoint at service that accepts a song as a paramter, and have the service redirect us to the search endpoint of the spotify api? – kenpino Aug 30 '23 at 14:52
  • I don't fully understand your question. I just picked up search song and add into exist my playlist. This answer [to add a song](https://stackoverflow.com/questions/75419872/spotify-api-getting-404-as-a-response-trying-to-find-current-song/75424917#75424917), other case you needs to new question with real example. It will be help to get answer from stack overflow guys.(include me) – Bench Vue Aug 30 '23 at 15:07
  • you're right, that a whole new question, ty :) – kenpino Aug 30 '23 at 15:51
-1

The response however does not include a code or state

It probably does include those, but you're not printing it the right way to actually see them.

You're printing the whole response, and <Response [200]> is just the default way response objects appear when you print them.

Try this instead, which will print the individual data elements contained in the response:

print(auth_code.json())
John Gordon
  • 29,573
  • 7
  • 33
  • 58
  • TY for answering. I am not even lookinga the print part. I know that displays only the response state. I am looking though into every single element that come withing the response while I am debuging. – kenpino Aug 28 '23 at 23:44