Compare commits
3 Commits
main
...
0bfe341afe
| Author | SHA1 | Date | |
|---|---|---|---|
| 0bfe341afe | |||
| 4419482152 | |||
| e1a0fe68e8 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
package-lock.json
|
||||||
@@ -7,4 +7,10 @@ Ce projet a pour objectif de réaliser des actions via l'API de Spotify afin de
|
|||||||
- Récupérer des informations sur les musiques, playlists et podcasts
|
- Récupérer des informations sur les musiques, playlists et podcasts
|
||||||
- Contrôler le lecteur de musique
|
- Contrôler le lecteur de musique
|
||||||
- Visualiser les canvas d'éléments de Spotify
|
- Visualiser les canvas d'éléments de Spotify
|
||||||
- Récupérer des informations supplémentaires non-affichées dans l'application
|
- Récupérer des informations supplémentaires non-affichées dans l'application
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
|
Afin d'utiliser ce module, il est nécessaire de créer un fichier `.env` à la racine du projet contenant les variables d'environnement suivantes :
|
||||||
|
|
||||||
|
`SPOTIFY_CLIENT_ID='<your-spotify-client-id>'`
|
||||||
13
main.js
Normal file
13
main.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const SpotifyController = require('./src/spotify.js')
|
||||||
|
|
||||||
|
var spotifyController = new SpotifyController().then(initializingSuccess, printError)
|
||||||
|
|
||||||
|
// SpotifyController initialized
|
||||||
|
function initializingSuccess(result) {
|
||||||
|
console.log(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the error to the console
|
||||||
|
function printError(error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
1249
package-lock.json
generated
Normal file
1249
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "spotifycontroller",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Get all the spotify data with NodeJS!",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://factory.vbprojects.fr/thinkode/SpotifyController.git"
|
||||||
|
},
|
||||||
|
"author": "V. Boulanger",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.4.0",
|
||||||
|
"base64url": "^3.0.1",
|
||||||
|
"crypto": "^1.0.1",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"opn": "^6.0.0",
|
||||||
|
"randomstring": "^1.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/configuration.js
Normal file
16
src/configuration.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const SpotifyEndpoints = {
|
||||||
|
GET_USER_TOKEN_ENDPOINT: "https://accounts.spotify.com/api/token",
|
||||||
|
GET_USER_PROFILE_ENDPOINT: 'https://api.spotify.com/v1/me'
|
||||||
|
}
|
||||||
|
|
||||||
|
const AuthorizationScopes = [
|
||||||
|
'user-read-private',
|
||||||
|
'user-read-email',
|
||||||
|
'user-top-read',
|
||||||
|
'user-read-currently-playing'
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SpotifyEndpoints,
|
||||||
|
AuthorizationScopes
|
||||||
|
};
|
||||||
31
src/protobuf/pb/api.proto
Normal file
31
src/protobuf/pb/api.proto
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package com.spotify.api;
|
||||||
|
|
||||||
|
// Request used to get a new token for the current user
|
||||||
|
message GetUserTokenRequest {
|
||||||
|
// The client id
|
||||||
|
string client_id = 1;
|
||||||
|
// The grant type
|
||||||
|
string grant_type = 2;
|
||||||
|
// The code returned by the authorization server
|
||||||
|
string code = 3;
|
||||||
|
// The redirect uri
|
||||||
|
string redirect_uri = 4;
|
||||||
|
// The client secret
|
||||||
|
string code_verifier = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reponse of the GetUserTokenRequest
|
||||||
|
message GetUserTokenResponse {
|
||||||
|
// The user access token
|
||||||
|
string access_token = 1;
|
||||||
|
// The token type
|
||||||
|
string token_type = 2;
|
||||||
|
// The time in seconds before the access token expires
|
||||||
|
int32 expires_in = 3;
|
||||||
|
// The token used to refresh the user token
|
||||||
|
string refresh_token = 4;
|
||||||
|
// A space-separated list of scopes which have been granted for this access_token
|
||||||
|
string scope = 5;
|
||||||
|
}
|
||||||
142
src/spotify.js
Normal file
142
src/spotify.js
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
const axios = require('axios')
|
||||||
|
const dotenv = require('dotenv')
|
||||||
|
const configuration = require('./configuration.js')
|
||||||
|
const randomstring = require('randomstring')
|
||||||
|
const base64url = require('base64url')
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const opn = require('opn')
|
||||||
|
const express = require('express')
|
||||||
|
|
||||||
|
class SpotifyController {
|
||||||
|
// Creates a new SpotifyController instance with the given clientId
|
||||||
|
constructor() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
dotenv.config()
|
||||||
|
// For connection management
|
||||||
|
this.clientId = process.env.SPOTIFY_CLIENT_ID
|
||||||
|
// For user token management
|
||||||
|
this.userToken = undefined
|
||||||
|
this.userTokenExpiringDate = undefined
|
||||||
|
this.refreshToken = undefined
|
||||||
|
// For canvas token management
|
||||||
|
this.canvasToken = undefined
|
||||||
|
this.canvasTokenExpiringDate = undefined
|
||||||
|
// Check client ID
|
||||||
|
if (this.clientId === undefined || this.clientId === null || this.clientId === '') {
|
||||||
|
reject('Spotify client ID not set. Please define this variable in the .env file.')
|
||||||
|
}
|
||||||
|
this.checkUserToken().then(resolve("User token got."), reject("Error requesting a user token"))
|
||||||
|
resolve("SpotifyController initialized.")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function aims to get a valid user token for the Spotify API
|
||||||
|
async checkUserToken() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.userToken === undefined) {
|
||||||
|
// Get a new token with auth
|
||||||
|
this.requestAuthentication().then(resolve("User token requested"), reject("Error requesting user token"))
|
||||||
|
} else if (this.userTokenExpiringDate < new Date()) {
|
||||||
|
// Refresh the user token
|
||||||
|
refreshUserToken().then(resolve("User token refreshed"), reject("Error refreshing user token"))
|
||||||
|
}
|
||||||
|
resolve("User token is already valid")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function aims to get a user token with authentication
|
||||||
|
async requestAuthentication() {
|
||||||
|
let clientId = this.clientId
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
//Generate a code verifier
|
||||||
|
const codeVerifier = randomstring.generate(128);
|
||||||
|
const codechallenge = base64url.fromBase64(crypto.createHash("sha256").update(codeVerifier).digest("base64"))
|
||||||
|
// Create the authentication URL
|
||||||
|
let args = new URLSearchParams({
|
||||||
|
response_type: 'code',
|
||||||
|
client_id: clientId,
|
||||||
|
scope: configuration.AuthorizationScopes.join(' '),
|
||||||
|
redirect_uri: "http://localhost:3333/callback",
|
||||||
|
code_challenge_method: 'S256',
|
||||||
|
code_challenge: codechallenge
|
||||||
|
});
|
||||||
|
// Open the authentication page
|
||||||
|
opn('https://accounts.spotify.com/authorize?' + args);
|
||||||
|
// Create an express app
|
||||||
|
let app = express()
|
||||||
|
// Catch the response
|
||||||
|
app.get('/callback', async (req, res) => {
|
||||||
|
if(req.query.code != undefined) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append("client_id", this.clientId);
|
||||||
|
params.append("grant_type", "authorization_code");
|
||||||
|
params.append("code", req.query.code);
|
||||||
|
params.append("redirect_uri", "http://localhost:3333/callback");
|
||||||
|
params.append("code_verifier", codeVerifier);
|
||||||
|
executePostRequest(configuration.SpotifyEndpoints.GET_USER_TOKEN_ENDPOINT, params, { headers: { "Content-Type": "application/x-www-form-urlencoded" } }, "json").then(result => {
|
||||||
|
console.log(result)
|
||||||
|
}, error => {
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.send("Spotify authentication failed! Please close this tab and try again.")
|
||||||
|
reject("Error when executing request: no code provided.")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
res.status(404)
|
||||||
|
res.send('404: File Not Found')
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3333, function () {
|
||||||
|
console.log('Callback server is running!')
|
||||||
|
});
|
||||||
|
resolve()
|
||||||
|
}, error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function aims to refresh the user token
|
||||||
|
async refreshUserToken() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute a GET request to the Spotify API
|
||||||
|
function executeGetRequest(url, requestObject, options, responseType){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios.get(url, requestObject.serializeBinary(), options)
|
||||||
|
.then(function(response){
|
||||||
|
if (response.statusText !== 'OK') {
|
||||||
|
reject(`Request error (${response.status}): ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
resolve(responseType.deserializeBinary(response.data).toObject());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error){
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute a POST request to the Spotify API
|
||||||
|
function executePostRequest(url, requestObject, options, responseType){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios.post(url, requestObject, options)
|
||||||
|
.then(function(response){
|
||||||
|
if (response.statusText !== 'OK') {
|
||||||
|
reject(`Request error (${response.status}): ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
resolve(response.data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error){
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SpotifyController;
|
||||||
Reference in New Issue
Block a user