DEV Community

Simon Pfeiffer for Codesphere Inc.

Posted on • Edited on

7 4

Voice Automating Spotify w/ React and Codesphere

Written by Lior David

Earlier this week, we spoke about the relationship between coding productivity and listening to music. If you're a developer, you know how many different tabs and applications you might have open at once. That's why today we're going to create a simple web app to voice control Spotify.

You can check out the demo, deployed on Codesphere, here:

https://18922-3000.codesphere.com/


Project Overview

To do this we're going to use React, the Spotify Web API, the react-speech-recognition library, and Codesphere.

The flow will look like so:

Alt Text

This GIF obviously doesn't include sound, but upon saying "pause music", your Spotify will pause, and upon saying "play music", the song will start playing again.

Spotify's Web API includes tons of different features, so you can automate your app to do pretty much anything you can do in the actual Spotify app.


Setting up Spotify Web API

To get started with the Spotify Web API, go to this page and sign in with your Spotify account:

https://developer.spotify.com/dashboard/

You will then see a menu to create a new app in your Spotify developer dashboard:

Alt Text

Once you create your app, press the edit settings button and add localhost:3000 to your redirect URI. This is the link that Spotify will send the user to after they successfully sign in. If you are deploying this app in the cloud, make sure to change your redirect URI to the domain of your app.

Alt Text

Finally, note the clientID in your dashboard, we are going to need this for later.


Creating our Spotify Player

We are going to handle authentication by storing an authentication token that we pull from the API. The user can begin the authentication process by pressing a sign-in button and being redirected to a Spotify login.

Once there is a valid token, we then are going to pull the currently playing song and display the title, artist, and album cover. Finally, we are going to add buttons that can play and pause the current song.

import './App.css';
import {useEffect, useState} from 'react'
function App() {
const authEndpoint = "https://accounts.spotify.com/authorize/?"
const clientId = "" // Find ClientID on Spotify Dashboard
const redirectUri = "https://18922-3000.codesphere.com/" // Where to go after sign in
const scopes = [
'user-read-currently-playing',
'user-read-playback-state',
'user-modify-playback-state',
]
let [token, setToken] = useState() // Authorization Token
let [currSong, setCurrSong] = useState()
useEffect(() => {
// Get the token information from the URI
const hash = window.location.hash
.substring(1)
.split("&")
.reduce(function(initial, item) {
if (item) {
var parts = item.split("=");
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = "";
let _token = hash.access_token
if(_token) {
setToken(_token)
getCurrentSong(_token)
}
}, [])
const getCurrentSong = (tok) => {
fetch("https://api.spotify.com/v1/me/player", {
method: 'GET',
headers: {
Authorization: "Bearer " + tok
}
})
.then((response) => response.json()).then(data => {
setCurrSong({
item: data.item,
is_playing: data.is_playing,
progress_ms: data.progress_ms,
});
})
}
const pauseSong = () => {
fetch("https://api.spotify.com/v1/me/player/pause", {
method: 'PUT',
headers: {
Authorization: "Bearer " + token
}
})
}
const playSong = () => {
fetch("https://api.spotify.com/v1/me/player/play", {
method: 'PUT',
headers: {
Authorization: "Bearer " + token
}
})
}
return (
<div className="App">
<header className="App-header">
{!token && (
<a
className="btn btn--loginApp-link"
href={`${authEndpoint}client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes.join("%20")}&response_type=token&show_dialog=true`}
>
<button>Login to Spotify</button>
</a>
)}
{token && (<>
{currSong && <>
<img src = {currSong.item.album.images[0].url} alt = "Album Cover"/>
<h2>{currSong.item.name}</h2>
<p>{currSong.item.artists[0].name}</p>
<div>
<button onClick = {playSong}>Play</button>
<button onClick = {pauseSong}>Pause</button>
</div>
</>}
</>
)}
</header>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

And we are going to style these components like so:

.App {
text-align: center;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
padding-top: 50px;
}
h2 {
margin-bottom: 0;
margin-top: 5px;
}
button {
display:inline-block;
padding:0.35em 1.2em;
border:0.1em solid #FFFFFF;
background-color: transparent;
margin:0 0.3em 0.3em 0;
border-radius:0.12em;
color:#FFFFFF;
font-size: 20px;
transition: all 0.2s;
}
button:hover {
color:#000000;
background-color:#FFFFFF;
}
img {
width: 35vh;
height: 35vh;
margin: 0;
padding: 0;
}
view raw App.css hosted with ❤ by GitHub

With this code, we can play and pause our Spotify from the web. That's cool I guess, but not really helpful. Now here comes the fun part.


Setting up Voice Recognition

We are first going to install the react-speech-recognition library with:

npm i react-speech-recognition

We then are going to amend our code as follows:

import './App.css';
import {useEffect, useState} from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
function App() {
const authEndpoint = "https://accounts.spotify.com/authorize/?"
const clientId = "" // Find ClientID on Spotify Dashboard
const redirectUri = "https://18922-3000.codesphere.com/" // Where to go after sign in
const scopes = [
'user-read-currently-playing',
'user-read-playback-state',
'user-modify-playback-state',
]
let [token, setToken] = useState() // Authorization Token
let [currSong, setCurrSong] = useState()
useEffect(() => {
const hash = window.location.hash
.substring(1)
.split("&")
.reduce(function(initial, item) {
if (item) {
var parts = item.split("=");
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = "";
let _token = hash.access_token
if(_token) {
setToken(_token)
getCurrentSong(_token)
SpeechRecognition.startListening({continuous: true})
}
}, [])
const getCurrentSong = (tok) => {
fetch("https://api.spotify.com/v1/me/player", {
method: 'GET',
headers: {
Authorization: "Bearer " + tok
}
})
.then((response) => response.json()).then(data => {
setCurrSong({
item: data.item,
is_playing: data.is_playing,
progress_ms: data.progress_ms,
});
})
}
const pauseSong = () => {
fetch("https://api.spotify.com/v1/me/player/pause", {
method: 'PUT',
headers: {
Authorization: "Bearer " + token
}
})
}
const playSong = () => {
fetch("https://api.spotify.com/v1/me/player/play", {
method: 'PUT',
headers: {
Authorization: "Bearer " + token
}
})
}
const commands = [
{
command: ['play music', 'resume music'],
callback: () => playSong(),
isFuzzyMatch: true,
},
{
command: ['pause music', 'stop music'],
callback: () => pauseSong(),
isFuzzyMatch: true,
},
]
const {
transcript,
listening,
} = useSpeechRecognition({commands})
return (
<div className="App">
<header className="App-header">
{!token && (
<a
className="btn btn--loginApp-link"
href={`${authEndpoint}client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes.join("%20")}&response_type=token&show_dialog=true`}
>
<button>Login to Spotify</button>
</a>
)}
{token && (<>
{listening && <p>Listening for Commands</p>}
<p>{transcript}</p>
{currSong && <>
<img src = {currSong.item.album.images[0].url} alt = "Album Cover"/>
<h2>{currSong.item.name}</h2>
<p>{currSong.item.artists[0].name}</p>
<div>
<button onClick = {playSong}>Play</button>
<button onClick = {pauseSong}>Pause</button>
</div>
</>}
</>
)}
</header>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

And there you have it! We can now voice control our Spotify!


Next Steps

Playing and Pausing songs is only the tip of the iceberg of the Spotify Web API. If you want, you can use the API to create a functioning Spotify clone.

In addition, if you link up more voice commands, you can create a fully automated Spotify app. While this is nice for those of us who are lazy, this also has the potential to make life much easier for music listeners with visual impairments.

So code away!

Brought to you by your good friends at Codesphere, the next-generation cloud provider.

Top comments (0)