Hi,
Here's a module I programmed for controlling volume and basic Spotify playback functions with Flic Twist, in case someone else has any use for it. To use it, you'll have to register for a Spotify developer account and create a new app from their dashboard, in order to get access tokens etc.
@flichub @Emil: Is it possible to somehow get this added to the existing public Spotify "provider"? Seems a bit tedious/difficult for users without any programming experience to go down this particular rabbit hole.
// main.js
const flicapp = require('flicapp');
const http = require('http');
const datastore = require('datastore');
datastore.get('clientID', (err, key) => {
const clientID = key // store this first: (datastore.put('clientID', 'YOUR CLIENT ID')
datastore.get('clientSecret', (err, key) => {
const clientSecret = key // store this first: (datastore.put('clientSecret', 'YOUR CLIENT SECRET')
function percent(volume, decimalPlaces = 0) {
const percentage = (volume * 100).toFixed(decimalPlaces);
return `${percentage}`;
}
function spotifyStatus() {
datastore.get('accessToken', (err, key) => {
const accessToken = key
if (key !== null) {
const options = {
url: 'https://api.spotify.com/v1/me/player',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
};
const req = http.makeRequest(options, (error, result) => {
if (result.statusCode == 401) {
refreshToken();
}
if (result.statusCode == 204) {
var status = "No active sessions."
console.log(status);
}
if (result.statusCode == 200) {
var jresp = JSON.parse(result.content);
var status = jresp["is_playing"];
if (status === true) {
spotifyPause();
}
if (status === false) {
spotifyPlay();
}
}
})
}
})
};
function spotifyPlay() {
datastore.get('accessToken', (err, key) => {
const accessToken = key
if (key !== null) {
const options = {
url: 'https://api.spotify.com/v1/me/player/play',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
};
const req = http.makeRequest(options, (error, result) => {
if (result.statusCode == 401) {
refreshToken();
}
})
}
})
};
function spotifyPause() {
datastore.get('accessToken', (err, key) => {
const accessToken = key
if (key !== null) {
const options = {
url: 'https://api.spotify.com/v1/me/player/pause',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
};
const req = http.makeRequest(options, (error, result) => {
if (result.statusCode == 401) {
refreshToken();
}
})
}
})
};
function spotifyNext() {
datastore.get('accessToken', (err, key) => {
const accessToken = key
if (key !== null) {
const options = {
url: 'https://api.spotify.com/v1/me/player/next',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
};
const req = http.makeRequest(options, (error, result) => {
if (result.statusCode == 401) {
refreshToken();
}
})
}
})
};
function spotifyVolume(volume) {
datastore.get('accessToken', (err, key) => {
const accessToken = key
if (key !== null) {
const options = {
url: 'https://api.spotify.com/v1/me/player/volume?volume_percent=' + volume,
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
};
const req = http.makeRequest(options, (error, result) => {
if (result.statusCode == 401) {
refreshToken();
}
if (result.statusCode == 404) {
console.log("No active sessions.")
}
})
}
})
};
function refreshToken() {
datastore.get('refreshToken', (err, key) => {
const refreshToken = key
if (key !== null) {
const options = {
url: 'https://accounts.spotify.com/api/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
content: "refresh_token=" + refreshToken + "&scope=user-read-playback-state%2C+user-modify-playback-state%2C+user-follow-read%2C+user-library-read%2C+streaming%2C+user-read-playback-position%2C+user-top-read%2C+user-read-currently-playing%2C+&client_id=" + clientID + "&client_secret=" + clientSecret + "&grant_type=refresh_token"
};
const req = http.makeRequest(options, (error, result) => {
if (!error && result.statusCode === 200) {
var jresp = JSON.parse(result.content);
datastore.put('accessToken', jresp["access_token"])
spotifyStatus();
}
})
}
})
};
flicapp.on("actionMessage", function(message) {
if (message == 'playtoggle') {
spotifyStatus();
}
});
flicapp.on("actionMessage", function(message) {
if (message == 'next') {
spotifyNext();
}
});
flicapp.on("virtualDeviceUpdate", function(metaData, values) {
if (values.volume && metaData.virtualDeviceId == "spotify") {
var volume = percent(values.volume)
spotifyVolume(volume);
flicapp.virtualDeviceUpdateState("Speaker", "spotify", {
volume: values.volume
});
}
});
}); // clientID var
}); // clientSecret var
As you probably can see, I'm not exactly a Javascript wizard, but it works
Enjoy.
Andreas