Am trying to make a program that finds the current song playing and then to put it an one of my playlists. But am getting a 404 response when a trying to obtain the current playing song.
This is how I am getting my access token:
def get_token():
auth_str = client_id + ":" + client_secret
auth_bytes = auth_str.encode("utf-8")
auth_base64 = str(base64.b64encode(auth_bytes), "utf-8")
url = "https://accounts.spotify.com/api/token"
headers = {
"Authorization": "Basic " + auth_base64,
"Content-Type": "application/x-www-form-urlencoded"
}
data = {"grant_type": "client_credentials"}
result = post(url, headers=headers, data=data)
json_result = json.loads(result.content)
token = json_result["access_token"]
return token
This is how I am creating the headers:
def get_headers(token):
return {"Authorization": "Bearer " + token}
This is how I am trying to get the current playing song uri:
def get_current_track_and_post_in_playlist(token):
headers = get_headers(token)
result = get('https://api.spotify.com/v1/me/player/currently-playing', headers=headers)
playlist_id = "0p4d0akcszc87kcf0pym6qws1"
print(result)
json_result = json.loads(result.content)["item"]["uri"]
print(json_result)
playlist_put = post(f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks?uris={json_result}', headers=headers)
When am printing the result in get_current_track_and_post_in_playlist function i get a <Response [404]>. Can someone help me resolve this problem?
A reasons is required a user authentication for those two REST APIs.
Get Currently Playing Track
https://api.spotify.com/v1/me/player/currently-playing
Add Items to Playlist
https://api.spotify.com/v1/playlists/{playlist_id}/tracks
It needs to get token by Authorization Code Flow
So I will demo by local server with Flask
This overall steps
# Step 1
I play a song by browser. it will add into my playlist
# Step 2
Running local redirect server with this code with add-song.py file name.
You needs to config the Redirect URIs of your application in your dashboard.
https://developer.spotify.com/dashboard/applications
from flask import Flask, request, redirect
from requests_oauthlib import OAuth2Session
from requests.auth import HTTPBasicAuth
import requests
import json
app = Flask(__name__)
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
REDIRECT_URI = 'http://localhost:3000/callback' # your redirect URI
CLIENT_ID = "<your client ID>"
CLIENT_SECRET = "<your client Secret>"
SCOPE = [
"user-read-playback-state",
"app-remote-control",
"user-modify-playback-state",
"playlist-read-private",
"playlist-read-collaborative",
"user-read-currently-playing",
"user-read-playback-position",
"user-library-modify",
"playlist-modify-private",
"playlist-modify-public",
"user-read-recently-played",
"user-read-private",
"user-library-read"
]
def get_headers(token):
return {"Authorization": "Bearer " + token}
#app.route("/login")
def login():
spotify = OAuth2Session(CLIENT_ID, scope=SCOPE, redirect_uri=REDIRECT_URI)
authorization_url, state = spotify.authorization_url(AUTH_URL)
return redirect(authorization_url)
# your redirect URI's path
#app.route("/callback", methods=['GET'])
def callback():
code = request.args.get('code')
res = requests.post(TOKEN_URL,
auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
data={
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI
})
access_token = res.json()['access_token']
listObj = []
listObj.append(res.json())
# get current playing
headers = get_headers(access_token)
result1 = requests.get(url='https://api.spotify.com/v1/me/player/currently-playing', headers=headers)
current_song = result1.json()
listObj.append(current_song)
# Add new song into playlist with current playing song
playlist="<your playlist ID>"
url = "https://api.spotify.com/v1/playlists/{0}/tracks".format(playlist)
# current_song['item']['uri'] = 'spotify:track:xxxxxxxxxxxxxxxx'
params = {'uris': current_song['item']['uri']}
result2 = requests.post(url,
params=params,
headers={'Content-Type':'application/json',
'Authorization': 'Bearer {0}'.format(access_token)})
added_song = result2.json()
listObj.append(added_song)
return listObj
if __name__ == '__main__':
app.run(port=3000,debug=True) # your redirect URI's port
$ python add-song.py
#3 Login by Browser
http://localhost:3000/login
login your Spotify credential
Before add Song
After added Song
In the browser, will display current play song information and added song's snapshot_id.
The key is playing song's track URI needs to set a parameter of add playlist.
current_song['item']['uri']
#Step 4~6
It is running by inside code.
I hope to this demo your are looking for solution.
Related
I'm working on a simple python script to help me retrieve email in office365 user mailbox based on the following parameters, sentdatetime, sender or from address and subject.
As of current, am able to get the access token using msal, however the email api call does not work. I get an error 401. From graph explorer the query works however in the script it's not working.
My app registration is assigned application permission for mail, i selected everything under mail permissions. see below permissions
Below is my script so far, what am i doing wrong.
import msal
import json
import requests
def get_access_token():
tenantID = '9a13fbbcb90fa2'
authority = 'https://login.microsoftonline.com/' + tenantID
clientID = 'xxx'
clientSecret = 'yyy'
scope = ['https://outlook.office365.com/.default']
app = msal.ConfidentialClientApplication(clientID, authority=authority, client_credential = clientSecret)
access_token = app.acquire_token_for_client(scopes=scope)
return access_token
# token block
access_token = get_access_token()
token = access_token['access_token']
# Set the parameters for the email search
date_sent = "2023-01-22T21:13:24Z"
mail_subject = "Test Mail"
sender = "bernardberbell#gmail.com"
mailuser = "bernardmwanza#bernardcomms.onmicrosoft.com"
# Construct the URL for the Microsoft Graph API
url = "https://graph.microsoft.com/v1.0/users/{}/mailFolders/Inbox/Messages?$select=id,sentDateTime,subject,from&$filter=contains(subject, '{}') and from/emailAddress/address eq '{}' and SentDateTime gt '{}'".format(mailuser, mail_subject, sender, date_sent)
# Set the headers for the API call
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# Send the API request and get the response
response = requests.get(url, headers=headers)
print(response)
# # Parse the response as JSON
# data = json.loads(response.text)
# print(data)
Below is the error
Your scope is wrong for the Graph API this
scope = ['https://outlook.office365.com/.default']
Will give you a token that has an audience of outlook.office365.com which is okay for IMAP4 but not for the Graph which requires the audience to be https://graph.microsoft.com
so your scope for the graph should be
scope = ['https://graph.microsoft.com/.default']
You can check your token use jwt.io and verify it.
import requests
import base64
# Request an access token
def request_access_token():
AUTH_URL = 'https://accounts.spotify.com/api/token'
# POST
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
'client_id': "<client ID>",
'client_secret': "<client Secret>",
})
# convert the response to JSON
auth_response_data = auth_response.json()
# save the access token
print(auth_response_data)
access_token = auth_response_data['access_token']
return access_token
# Check if the access token is valid
def check_access_token_validity(access_token):
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get("https://api.spotify.com/v1/me", headers=headers)
print(response)
if response.status_code == 200:
return True
else:
return False
# Run the code
access_token = request_access_token()
if access_token:
if check_access_token_validity(access_token):
print("Access token is valid.")
else:
print("Access token is not valid.")
else:
print("Could not request access token.")
I get a "access_token" but it doesn't work. It gives Error 401. I also got the same issue in javascript. I tried everything and I dont know what is wrong. Here's the output:
output
Which shows that I did recieve a token. But when I try to check it's validity, it is [Invalid 401]. I have also rotated my client secret and same issue. Both Client ID and Client Secret are correct.
As mentioned in the docs, your access token request is different
Try this
import requests
import base64
client_id = 'CLIENT_ID';
client_secret = 'CLIENT_SECRET';
response = requests.post(
'https://accounts.spotify.com/api/token',
data={'grant_type':'client_credentials'},
headers={'Authorization': 'Basic ' + base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode())},
)
I'm new to both python and APIs. lol. But google isn't helping. I have the below simple authentication request and am getting a KeyError: 'token' from the line, authorization = {"Authorization": "Bearer " + token['token']}
I appreciate any guidance you can provide!
#!/usr/bin/python3
import requests
import argparse
import math
import os
import json
export_format_map = {
"csv": "zip",
"json": "json",
"kml": "kml"
}
def download_logs(args):
"""
NOTE: Requires user credentials
Downloads log files from user-specified host in user-specified file format.
"""
rest_api = "https://address.here/api/1.0"
# Step 1. Login and get token to authenticate requests
print(f"Logging into {rest_api}...")
# Get username and password from environment variables
username = os.environ.get('USERNAME')
password = os.environ.get('PASSWORD')
# Put the credentials into a dictionary object
credentials = {"email": username, "password": password}
r = requests.post(f"{rest_api}/authentication/login", json=credentials)
# Build the JWT compliant authorization dictionary
token = json.loads(r.text)
authorization = {"Authorization": "Bearer " + token['token']}
# Step 2. Gather a list of contacts filtered to be within the min/max timestamps
def get_agents(params):
"""Sends GET request to API with provided parameters; Returns response."""
response = requests.get(
url=f"{rest_api}/agent",
params=params,
headers=authorization
).json()
return response
#code continues.....
I have also tried setting up the token request like this with the same error:
TOKEN = requests.post(
url=f"{rest_api}/authentication/login",
data={
"email": input("\nusername/email: "),
"password": getpass.getpass(),
}
).json()
authorization = {"Authorization": "Bearer " + TOKEN['token']}
I am trying to do the authorization code flow using Spotify's API to ultimately add songs to a playlist. I am building this from scratch, and not using any libraries such as Spotipy.
I am able to successfully hit the authorize endpoint, but I am having some issues with the token endpoint. Here is the code I have so far:
# URLS
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
BASE_URL = 'https://api.spotify.com/v1/'
# Make a request to the /authorize endpoint to get an authorization code
auth_code = requests.get(AUTH_URL, {
'client_id': CLIENT_ID,
'response_type': 'code',
'redirect_uri': 'https://open.spotify.com/collection/playlists',
'scope': 'playlist-modify-private',
})
print(auth_code)
auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode('ascii'))
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic %s' % auth_header.decode('ascii')
}
payload = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': 'https://open.spotify.com/collection/playlists',
#'client_id': CLIENT_ID,
#'client_secret': CLIENT_SECRET,
}
# Make a request to the /token endpoint to get an access token
access_token_request = requests.post(url=TOKEN_URL, data=payload, headers=headers)
# convert the response to JSON
access_token_response_data = access_token_request.json()
print(access_token_response_data)
# save the access token
access_token = access_token_response_data['access_token']
When I run my script, I get this output in Terminal:
{'error': 'invalid_grant', 'error_description': 'Invalid authorization code'}
Traceback (most recent call last):
File "auth.py", line 48, in <module>
access_token = access_token_response_data['access_token']
KeyError: 'access_token'```
Can anyone explain to me what I might be doing wrong here?
By now, you probably have figure out what the problem was, but I am answering for future readers as well.
When you encode the auth_header, you should encode it to bytes not ascii. The str.encode() does this by default, so you can call it without arguments. Your code changes to this:
auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode()).
Now you must have a working example.
The code below worked for me to create a playlist and add a song.
The prerequisite is that you have a client_id and client_secret.
Run the code below and browse to your base URL (in my case, that was localhost), then you will see an authorize hyperlink that forwards you to the spotify authorization page.
Note that the redirect_url needs to be whitelisted in the spotify developer dashboard.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import requests
import uvicorn
# client_id = "YOUR_CLIENT_ID"
# client_secret = "YOUR_CLIENT_SECRET"
# redirect_uri = "YOUR_REDIRECT_URI" # e.g. http://localhost:8000/callback/ --> you will have to whitelist this url in the spotify developer dashboard
app = FastAPI()
def get_access_token(auth_code: str):
response = requests.post(
"https://accounts.spotify.com/api/token",
data={
"grant_type": "authorization_code",
"code": auth_code,
"redirect_uri": redirect_uri,
},
auth=(client_id, client_secret),
)
access_token = response.json()["access_token"]
return {"Authorization": "Bearer " + access_token}
#app.get("/")
async def auth():
scope = ["playlist-modify-private", "playlist-modify-public"]
auth_url = f"https://accounts.spotify.com/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={' '.join(scope)}"
return HTMLResponse(content=f'Authorize')
#app.get("/callback")
async def callback(code):
headers = get_access_token(code)
response = requests.get("https://api.spotify.com/v1/me", headers=headers)
user_id = response.json()["id"]
name = "Name of your playlist"
description = "Description of your playlist"
params = {
"name": name,
"description": description,
"public": True,
}
url = f"https://api.spotify.com/v1/users/{user_id}/playlists"
response = requests.post(url=url, headers=headers, json=params)
playlist_id = response.json()["id"]
track_uri = "spotify:track:319eU2WvplIHzjvogpnNc6"
response = requests.post(
f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks",
headers=headers,
json={"uris": [track_uri]},
)
if response.status_code == 201:
return {"message": "Track added successfully!"}
else:
return {"error": response.json()}
if __name__ == "__main__":
uvicorn.run(app, debug=True)
You're missing the CLIENT_ID and CLIENT_SECRET set within the code if I'm not mistaken.
This means Spotify will return invalid access token, which results in you not being able to continue.
You can also use Spotipy library for Python to make things easier.
https://spotipy.readthedocs.io/en/2.16.1/
I found a piece of code on Azure documentation that allows getting credentials without MFA. But I'm wondering if is possible to use it to connect to PowerBI API.
The piece of code that I'm using is:
import adal
import requests
from msrestazure.azure_active_directory import AADTokenCredentials
def authenticate_client_key():
authority_host_uri = 'https://login.microsoftonline.com'
tenant = 'tenant'
authority_uri = authority_host_uri + '/' + tenant
resource_uri = 'https://management.core.windows.net/'
client_id = 'clientid'
client_secret = 'client-secret'
context = adal.AuthenticationContext(authority_uri, api_version=None)
mgmt_token = context.acquire_token_with_client_credentials(resource_uri, client_id, client_secret)
credentials = AADTokenCredentials(mgmt_token, client_id)
return credentials
source: https://azure.microsoft.com/en-us/resources/samples/data-lake-analytics-python-auth-options/
According to the code written on PowerShell, the aim is to insert the access_token into the header of the following POST request
POST https://api.powerbi.com/v1.0/myorg/groups/me/datasets/{dataset_id}/refreshes
Source:https://powerbi.microsoft.com/en-us/blog/announcing-data-refresh-apis-in-the-power-bi-service/
I have tried to use the credentials into the POST request, but seems is not working.
I have tried
url = 'https://api.powerbi.com/v1.0/myorg/groups/me/datasets/datasetid/refreshes'
requests.post(url,data=mgmt_token)
Is it possible to merge this two codes?
Regards,
You can use the pypowerbi package to refresh Power BI datasets or you can check how to do it yourself by inspecting the code. https://github.com/cmberryau/pypowerbi
pip install pypowerbi
import adal
from pypowerbi.client import PowerBIClient
# you might need to change these, but i doubt it
authority_url = 'https://login.windows.net/common'
resource_url = 'https://analysis.windows.net/powerbi/api'
api_url = 'https://api.powerbi.com'
# change these to your credentials
client_id = '00000000-0000-0000-0000-000000000000'
username = 'someone#somecompany.com'
password = 'averygoodpassword'
# first you need to authenticate using adal
context = adal.AuthenticationContext(authority=authority_url,
validate_authority=True,
api_version=None)
# get your authentication token
token = context.acquire_token_with_username_password(resource=resource_url,
client_id=client_id,
username=username,
password=password)
# create your powerbi api client
client = PowerBIClient(api_url, token)
# Refresh the desired dataset (dataset and group IDs can be taken from the browser URL)
client.datasets.refresh_dataset(dataset_id='data-set-id-goes-here',
notify_option='MailOnCompletion',
group_id='group-id-goes-here')
Your code for acquiring an access token looks ok, but to use it with Power BI REST API, you must change resource_uri to be https://analysis.windows.net/powerbi/api.
When making a request to Power BI REST API, you must add Authorization header with value Bearer {accessToken}, where {accessToken} is the token acquired. I can't write in python, but you should do something like this:
headers = {'Authorization': 'Bearer ' + accessToken, 'Content-Type': 'application/json'}
url = 'https://api.powerbi.com/v1.0/myorg/groups/me/datasets/datasetid/refreshes'
requests.post(url, headers=headers)
(of course, you need to replace datasetid with actual value in url).
For example, here is how it can be done in C#:
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
string resourceUri = "https://analysis.windows.net/powerbi/api";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
string powerBIApiUrl = $"https://api.powerbi.com/v1.0/myorg/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/refreshes";
AuthenticationContext authContext = new AuthenticationContext(authorityUri, new TokenCache());
var authenticationResult = await authContext.AcquireTokenAsync(resourceUri, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto));
var accessToken = authenticationResult.AccessToken;
var request = WebRequest.Create(powerBIApiUrl) as HttpWebRequest;
request.KeepAlive = true;
request.Method = "POST";
request.ContentLength = 0;
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
using (Stream writer = request.GetRequestStream())
{
var response = (HttpWebResponse)request.GetResponse();
}