Skip to content

Instantly share code, notes, and snippets.

@cbilson
Last active February 18, 2018 19:47
Show Gist options
  • Save cbilson/fb81ba6834ba084a803f5f817b22d5c6 to your computer and use it in GitHub Desktop.
Save cbilson/fb81ba6834ba084a803f5f817b22d5c6 to your computer and use it in GitHub Desktop.
get a user's spotify playlists
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Clef</title>
</head>
<body id="home">
<h1>Logged in as {{user.display_name}}</h1>
<h3>Playlists</h3>
<ul>
{% for item in user.playlists %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<footer>
Also online: {{other_users}}
</footer>
</body>
</html>
import base64, json, logging, os, requests, sys, threading, webbrowser
from urllib.parse import urlencode, unquote
from flask import Flask, render_template, request, session, redirect
from datetime import datetime
from logging import StreamHandler
from logging.handlers import RotatingFileHandler
app = Flask(__name__)
app.logger.setLevel(logging.DEBUG)
app.config.update(
SESSION_COOKIE_NAME = 'clef_1_session')
if (os.getenv('DEBUG')):
stdoutLogger = StreamHandler(sys.stdout)
stdoutLogger.setLevel(logging.DEBUG)
app.logger.addHandler(stdoutLogger)
app.config.update(
DEBUG = True,
# just for running locally
SECRET_KEY='P/5K82pTf0Gmx/DGvS/5s6S+XCy7133NUSm5kOAxKCH1xoK9oI/sDrmUJy1wsFfZcvVlu6QtEGuxyvlMP98YcQ==')
else:
fileHandler = RotatingFileHandler('app.log', maxBytes=10*1024*1024, backupCount=100)
fileHandler.setLevel(logging.DEBUG)
app.logger.addHandler(fileHandler)
app.config.update(
SECRET_KEY = os.getenv('SECRET_KEY'),
SESSION_COOKIE_SECURE = True)
if not app.config['SECRET_KEY']:
raise Exception('Please specify a SECRET_KEY or DEBUG environment variable.')
CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
if not CLIENT_ID:
raise Exception('SPOTIFY_CLIENT_ID environment variable not set.')
CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")
if not CLIENT_SECRET:
raise Exception('SPOTIFY_CLIENT_SECRET environment variable not set.')
ENCODED_AUTHENTICATION = base64.b64encode(bytes(CLIENT_ID + ':' + CLIENT_SECRET, 'utf-8')).decode('ascii')
scope = "playlist-read-private user-library-read user-read-email user-read-playback-state user-modify-playback-state user-read-currently-playing user-read-recently-played"
class User:
def __init__(self, token_json, me_json, playlists_json):
self.access_token = token_json['access_token']
self.scope = token_json['scope']
self.expires_in = token_json['expires_in']
self.refresh_token = token_json['refresh_token']
self.id = me_json['id']
self.display_name = me_json['display_name']
self.email = me_json['email']
self.playlists = [item['name'] for item in playlists_json['items']]
# this would be in our database eventually
users = {}
pending_authentications = {}
@app.route('/')
def index():
if 'user_id' in session and session['user_id'] in users:
app.logger.debug('All users: %s' % ', '.join(users.keys()))
user = users[session['user_id']]
other_users = ', '.join([u for u in list(users.keys()) if u != user.id][:10])
return render_template('logged-in.html', user=user, other_users=other_users)
session.clear()
state = base64.b64encode(os.urandom(64)).decode('ascii')
app.logger.info('Redirecting to authorize, state = %s', state)
pending_authentications[state] = datetime.utcnow()
params = urlencode({'client_id': CLIENT_ID,
'response_type': 'code',
'redirect_uri': request.url_root + 'authorized',
'state': state,
'scope': scope})
authorize_url = 'https://accounts.spotify.com/authorize/?' + params
return redirect(authorize_url)
@app.route('/authorized')
def authorized():
if 'error' in request.args:
error = request.args.get('error')
app.logger.error('Error response from authorize: %s', error)
return render_template('auth-error.html', error=error)
auth_code = request.args.get('code')
state = unquote(request.args.get('state'))
app.logger.info('authorized state: %s', state)
if state not in pending_authentications:
app.logger.error("state doesn't match: state: %s" % state)
app.logger.error("pending_authentications: %s" % ', '.join(pending_authentications.keys()))
return render_template('auth-error.html', error="Hmm...this doesn't look like an authorization requested by Clef.")
pending_authentications.pop(state)
headers = {'Authorization': 'Basic ' + ENCODED_AUTHENTICATION}
data = {'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': request.url_root + 'authorized'}
app.logger.info('Requesting token.')
resp = requests.post('https://accounts.spotify.com/api/token', headers=headers, data=data)
token_json = resp.json()
if resp.status_code != 200:
app.logger.error('Failed to get token: ' + str(token_json))
error = 'Failed to get token.'
if 'error_description' in token_json: error = token_json['error_description']
return render_template('auth-error.html', error=error)
headers['Authorization'] = 'Bearer ' + token_json['access_token']
app.logger.info('Requesting user information')
resp = requests.get('https://api.spotify.com/v1/me', headers=headers)
if resp.status_code != 200:
app.logger.error('me resp code not OK, Response: ' + (resp))
return render_template('auth-error.html', error="Failed to get your profile.")
# TODO: This would be stored in a database
user_json = resp.json()
app.logger.debug('User info: %s', json.dumps(user_json))
app.logger.info('Requesting user playlists')
resp = requests.get('https://api.spotify.com/v1/me/playlists', headers=headers)
playlists_json = resp.json()
app.logger.debug('User playlists: %s', json.dumps(playlists_json))
user = User(token_json, user_json, playlists_json)
users[user.id] = user
session['user_id'] = user.id
return redirect('/')
if __name__ == '__main__':
#threading.Timer(1.25, lambda: webbrowser.open('http://localhost:5000/')).start()
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment