A Mood-based Spotify Music Recommendation Web App
Music Valet is a simple web application integrated with Spotify to provide music recommendations based on the user's current mood or activity of their choice.
The recommendations are personalized and tailored to their preferred artists and genre.
Visually, the app also creates an ambience by changing themes based on the current weather, temperatures or time of day.
Technology, Language & Libraries
Authentication and Authorization
To use the app, users must have an existing account with Spotify or register as a new user. For the authentication, I used the Spotify Web API's Authorization Code Flow. What this does is it grabs a code from the Spotify Accounts Service and exchanges it for an access token and refresh token. This access token is then stored in the browser cookies and this is what we use whenever we make requests to the Web API.
The first time a user logs in, the app will request for authorization with the following scopes:
Once a user successfully logs in, the user will be able to see the display name and profile picture in the landing page of the app.
The user can choose to log out from the app at any time by accessing the logout button from the profile dropdown. Since Spotify doesn't have an API for log out, I am forcing a request to https://www.spotify.com/logout/.
Current Track Playing & Audio Features
If a user is currently listening to a track, it will be displayed at the very top and the user will be able to click pause/resume playback. The album, artist, duration is displayed, as well as some of its audio features such as danceability, energy, liveness and valence.
Spotify Web API does not provide a way to trigger when a track is done playing. Or when the user "seeks" the playback from outside the Music Valet app. This makes it difficult to include a progress bar and hold the accuracy of the play progress of the track.
One way that I thought of implementing a progress bar, is to constantly make a request to get what's currently playing. But it seems excessive to make this call every second, just to check the state of the playback.
Basic Web Player
The app allows users to play/pause the recommended tracks from within the app.
The Spotify Web API does not provide a way to get a list of devices. It only provides an endpoint for active devices. This means that if the user is currently not connected to any device, i.e. if there's been a period of inactivity, then the app won't be able to play a track from any of the user's devices.
As a workaround, if the app detects that there are no active devices, then it will simply launch the web player.
Time, Location and Weather-based UI
In the landing page, the user will also be provided a daily weather summary. In addition to creating an ambient mood through music, I also wanted to capture the mood visually through the app's UI.
I translated the current temperature (in degree Celsius, because I'm Canadian) into colours in the hue spectrum. Since blue is usually perceived as cold and red as hot, I then decided to use their corresponding hue values (240 and 0/360), converted it to it's hex values and used this as the theme colour of the app.
I chose to use a smaller range of 240 to 360 rather than 0 to 240. This gives me a colour spectrum of blue, pink and red; rather than red, yellow, green and blue. I think the former would give me a better visual perception of how hot or cold it is.
For my temperature range, I decided to use -30C as the coldest and 30C as the hottest. Since I live in Canada and have also lived in the Philippines before, I have experienced both ends of that spectrum now.
With these ranges, I came up with the following equation:
hue = 180 + (2 * (temp + 60))
Activities are divided into 4 categories: morning, afternoon, evening and weekend. Each time-based category would have a list of activities that commonly occur during that time of day. These activities then correspond to a genre of music and a rate of energy or danceability.
For example, in the evening, we could choose the "bed time" activity which would commonly correspond to music that is ambient, gentle and soothing with a low energy and valence rate, and almost zero danceability rate. We wouldn't want to be going to bed with music that is hardcore with high energy levels and amplified drum beatings.
* This is a proof-of-concept (POC) project, so the activity-to-genre data used in the app is limited and might not be accurate for all users.
Project Planning & Timeline
When I started to work on this project, I decided to give myself a timeline of one week to create an app with limited scope and features. I mostly wanted to see what I can do with the Spotify APIs. I came up with the following requirements:
- Be able to login using a Spotify user account
- Be able to get user's top artists and tracks
- Prompt the user to choose an activity or get their current mood
- Show the track title, album, artist, duration, and some audio features
- Be able to control playback of the tracks
- Show what track is currently playing
- Have a dynamic UI theme colour
For backend, I used Node.js to do the authentication and all server to server communications. For front end, I used Handlebars to easily render and update the templates.
I used the following APIs:
Spotify Web API
- Personalization API
- Player API
- Track API
- Dark Sky API
Majority of the challenges that I encountered in this project relates to the limited features of the Spotify Web API. As I've mentioned above, the API does not provide a way to get a list of the user's available devices. Hence, if there is currently no active device, then the MusicValet app won't be able to trigger the playback on the user's device; instead, it will open up the web player.
Overall, I think I was able to achieve my goal of creating a simple yet functional web app using the Spotify Web API. I've got a list of improvements and features that I'd like to implement on a future phase, hopefully when Spotify updates their API and add more functionalities.
If you have any requests, suggestions or would like to file a bug, please open up a ticket for this project by sending an email at: