Detecting Sadness Based on Your Spotify Listening History
Introducing Sad Boi Detector
I don’t think sadness or depression is a joke. On the other hand, the Sad Boi Detector certainly is. Built for Illenium, the app allows users to share a time frame of their Spotify listening history (or a playlist) and receive a sadness score in return. This was developed in good faith for a base of fans who aren’t ashamed of making their feelings known.
But what is a Sad Boi, you say?
Urban Dictionary has plenty of definitions on the term but I’ll choose “Young male who spends most of his time in the feels.” The feels being, “the wave of emotion that hits you like a truck and leaves you think fuck man why.” One could assume that an individual in the feels might be consuming music that shares a similar temperament but how do we test this?
Spotify, of course.
Every track distributed to Spotify is analyzed for a set of interesting features such as its danceability (ability to dance to it) or speechiness (inclusion of spoken word.) One of these features is Valence, which psychology defines as the “good”-ness (positive valence) or “bad”-ness (negative valence) of an event, object, or situation. Spotify’s Platform docs offer a similar defintion.
A measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), while tracks with low valence sound more negative (e.g. sad, depressed, angry).
Knowing we have this variable available, it should be fairly simple to measure an average of valence based on a collection of Spotify tracks. Sadly, the Spotify Platform does not (publicly) offer a stream of every track a user has ever consumed but they do provide the top 50 tracks a user has played over three periods of time.
- Long term: calculated from several years of data and including all new data as it becomes available
- Medium term: approximately last 6 months
- Short term: approximately last 4 weeks
We’ll leave the term choice up to the user so they can see how their mood may have changed over time.
So, in our code, we’ll need to authenticate the user on Spotify, grab the recommended time frame of tracks, obtain the audio features for all of them, and finally, calculate the average valence. Check out this article on how I handle Spotify authorization using implicit grant.
With a Spotify token handy, I like to create an axios instance of the Spotify API for easy accessing of the platform.
const spotify = axios.create({
baseURL: 'https://api.spotify.com/v1/',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}
With this instance available, we can first get the user’s top tracks based on a provided time frame. Once we receive those, we’ll need to construct the track ids into a comma separated string for use with the audio features method.
let term = 'medium-term'spotify.get(`me/top/tracks?limit=50&time_range=${term}`)
.then(response => {
let ids = response.data.items.map(item => item.id).join(",")
})
We can now use our ids
parameter to receive the audio features of all of our tracks at once by calling the appropriate method. Once we receive those, we’ll calculate the mean of just the valence feature. Looks like I cheated Math once again and used the meanBy lodash method. 😅
spotify.get(`audio-features/?ids=${ids}`)
.then(response => {
let features = response.data.audio_features
let mean = _.meanBy(features, f => 1 - feature.valence)
let score = Math.round(mean * 100)
})
Thanks to Astralwerks on bringing me into this fun concept. Go ahead and find our your own score by visiting the app. I would also suggest checking out this thread to watch the Illenium fans react to their own scores. I received a 55% for All Time by the way. Prince has a lot of Sad Boi anthems!