Compare commits
5 Commits
0800ebeb70
...
apiBase
| Author | SHA1 | Date | |
|---|---|---|---|
| 0685701355 | |||
| 2b6825b7e3 | |||
| 0bfe341afe | |||
| 4419482152 | |||
| e1a0fe68e8 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.env
|
||||
package-lock.json
|
||||
@@ -8,3 +8,9 @@ Ce projet a pour objectif de réaliser des actions via l'API de Spotify afin de
|
||||
- Contrôler le lecteur de musique
|
||||
- Visualiser les canvas d'éléments de Spotify
|
||||
- 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/api.proto
Normal file
31
src/protobuf/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;
|
||||
}
|
||||
568
src/protobuf/api_pb.js
Normal file
568
src/protobuf/api_pb.js
Normal file
@@ -0,0 +1,568 @@
|
||||
// source: src/protobuf/api.proto
|
||||
/**
|
||||
* @fileoverview
|
||||
* @enhanceable
|
||||
* @suppress {missingRequire} reports error on implicit type usages.
|
||||
* @suppress {messageConventions} JS Compiler reports an error if a variable or
|
||||
* field starts with 'MSG_' and isn't a translatable message.
|
||||
* @public
|
||||
*/
|
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
var jspb = require('google-protobuf');
|
||||
var goog = jspb;
|
||||
var global =
|
||||
(typeof globalThis !== 'undefined' && globalThis) ||
|
||||
(typeof window !== 'undefined' && window) ||
|
||||
(typeof global !== 'undefined' && global) ||
|
||||
(typeof self !== 'undefined' && self) ||
|
||||
(function () { return this; }).call(null) ||
|
||||
Function('return this')();
|
||||
|
||||
goog.exportSymbol('proto.com.spotify.api.GetUserTokenRequest', null, global);
|
||||
goog.exportSymbol('proto.com.spotify.api.GetUserTokenResponse', null, global);
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.com.spotify.api.GetUserTokenRequest, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.displayName = 'proto.com.spotify.api.GetUserTokenRequest';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.com.spotify.api.GetUserTokenResponse, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.displayName = 'proto.com.spotify.api.GetUserTokenResponse';
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.com.spotify.api.GetUserTokenRequest.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.com.spotify.api.GetUserTokenRequest} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
clientId: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
grantType: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
code: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
redirectUri: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
codeVerifier: jspb.Message.getFieldWithDefault(msg, 5, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.com.spotify.api.GetUserTokenRequest;
|
||||
return proto.com.spotify.api.GetUserTokenRequest.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.com.spotify.api.GetUserTokenRequest} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setClientId(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setGrantType(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setCode(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setRedirectUri(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setCodeVerifier(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.com.spotify.api.GetUserTokenRequest.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.com.spotify.api.GetUserTokenRequest} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getClientId();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getGrantType();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getCode();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getRedirectUri();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getCodeVerifier();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string client_id = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.getClientId = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.setClientId = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string grant_type = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.getGrantType = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.setGrantType = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string code = 3;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.getCode = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.setCode = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string redirect_uri = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.getRedirectUri = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.setRedirectUri = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string code_verifier = 5;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.getCodeVerifier = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenRequest} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenRequest.prototype.setCodeVerifier = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.com.spotify.api.GetUserTokenResponse.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.com.spotify.api.GetUserTokenResponse} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
accessToken: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
tokenType: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
expiresIn: jspb.Message.getFieldWithDefault(msg, 3, 0),
|
||||
refreshToken: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
scope: jspb.Message.getFieldWithDefault(msg, 5, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.com.spotify.api.GetUserTokenResponse;
|
||||
return proto.com.spotify.api.GetUserTokenResponse.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.com.spotify.api.GetUserTokenResponse} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setAccessToken(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setTokenType(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {number} */ (reader.readInt32());
|
||||
msg.setExpiresIn(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setRefreshToken(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setScope(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.com.spotify.api.GetUserTokenResponse.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.com.spotify.api.GetUserTokenResponse} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getAccessToken();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getTokenType();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getExpiresIn();
|
||||
if (f !== 0) {
|
||||
writer.writeInt32(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getRefreshToken();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getScope();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string access_token = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.getAccessToken = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.setAccessToken = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string token_type = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.getTokenType = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.setTokenType = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional int32 expires_in = 3;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.getExpiresIn = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.setExpiresIn = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string refresh_token = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.getRefreshToken = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.setRefreshToken = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string scope = 5;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.getScope = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.com.spotify.api.GetUserTokenResponse} returns this
|
||||
*/
|
||||
proto.com.spotify.api.GetUserTokenResponse.prototype.setScope = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.com.spotify.api);
|
||||
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