|
|
from django.shortcuts import render, redirect from django.http import HttpResponse, HttpResponseBadRequest import math import random import requests import os import urllib from datetime import datetime
TIME_FORMAT = '%Y-%m-%d-%H-%M-%S'
def generate_random_string(length): """Generates a random string of a certain length
Args: length: the desired length of the randomized string Returns: A random string """
rand_str = "" possible_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for _ in range(length): rand_str += possible_chars[random.randint(0, len(possible_chars) - 1)] return rand_str
def token_expired(token_obtained_at, valid_for): """Returns True if token expired, False if otherwise
Args: token_obtained_at: datetime object representing the date and time when the token was obtained valid_for: the time duration for which the token is valid, in seconds """
time_elapsed = (datetime.today() - token_obtained_at).total_seconds() return time_elapsed >= valid_for
# Create your views here. def index(request): return render(request, 'spotifyvis/index.html')
def login(request):
# use a randomly generated state string to prevent cross-site request forgery attacks state_str = generate_random_string(16) request.session['state_string'] = state_str
payload = { 'client_id': os.environ['SPOTIFY_CLIENT_ID'], 'response_type': 'code', 'redirect_uri': 'http://localhost:8000/callback', 'state': state_str, 'scope': 'user-library-read', 'show_dialog': False }
params = urllib.parse.urlencode(payload) # turn the payload dict into a query string authorize_url = "https://accounts.spotify.com/authorize/?{}".format(params) return redirect(authorize_url)
def callback(request): # Attempt to retrieve the authorization code from the query string try: code = request.GET['code'] except KeyError: return HttpResponseBadRequest("<h1>Problem with login</h1>")
payload = { 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': 'http://localhost:8000/callback', 'client_id': os.environ['SPOTIFY_CLIENT_ID'], 'client_secret': os.environ['SPOTIFY_CLIENT_SECRET'], }
response = requests.post('https://accounts.spotify.com/api/token', data = payload).json() # despite its name, datetime.today() returns a datetime object, not a date object # use datetime.strptime() to get a datetime object from a string request.session['token_obtained_at'] = datetime.strftime(datetime.today(), TIME_FORMAT) request.session['access_token'] = response['access_token'] request.session['refresh_token'] = response['refresh_token'] request.session['valid_for'] = response['expires_in'] print(response)
return redirect('user_data')
def user_data(request):
token_obtained_at = datetime.strptime(request.session['token_obtained_at'], TIME_FORMAT) valid_for = int(request.session['valid_for'])
if token_expired(token_obtained_at, valid_for): req_body = { 'grant_type': 'refresh_token', 'refresh_token': request.session['refresh_token'], 'client_id': os.environ['SPOTIFY_CLIENT_ID'], 'client_secret': os.environ['SPOTIFY_CLIENT_SECRET'] } refresh_token_response = requests.post('https://accounts.spotify.com/api/token', data = req_body).json() request.session['access_token'] = refresh_token_response['access_token'] request.session['valid_for'] = refresh_token_response['expires_in']
auth_token_str = "Bearer " + request.session['access_token'] headers = { 'Authorization': auth_token_str }
user_data_response = requests.get('https://api.spotify.com/v1/me', headers = headers).json() context = { 'user_name': user_data_response['display_name'], 'id': user_data_response['id'], } return render(request, 'spotifyvis/user_data.html', context)
def get_features(track_id, token): """Returns the features of a soundtrack
Args: track_id: the id of the soundtrack, needed to query the Spotify API token: an access token for the Spotify API Returns: A dictionary with the features as its keys """
headers = { 'Authorization': token, } response = requests.get("https://api.spotify.com/v1/audio-features/{}".format(track_id), headers = headers).json() features_dict = {}
# Data that we don't need useless_keys = [ "key", "mode", "type", "liveness", "id", "uri", "track_href", "analysis_url", "time_signature", ] for key, val in response.items(): if key not in useless_keys: features_dict[key] = val
return features_dict
def update_std_dev(cur_mean, new_data_point, sample_size): """Calculates the standard deviation for a sample without storing all data points
Args: cur_mean: the current mean for N = (sample_size - 1) new_data_point: a new data point sample_size: sample size including the new data point Returns: (updated_mean, std_dev) """
# This is an implementationof Welford's method # http://jonisalonen.com/2013/deriving-welfords-method-for-computing-variance/ new_mean = ((sample_size - 1) * cur_mean + new_data_point) / sample_size std_dev = (new_data_point - new_mean) * (new_data_point - cur_mean) return new_mean, std_dev
|