I was tired of loosing / forgetting awesome songs due to Spotify's daily modification of their playlists, so I decided to create plvc.
Plvc was created with two goals in mind:
-
Tracking changes to your playlists:
- Adding / removing songs
- Spotify removing songs due to licensing issues
-
Tracking new / old playlists added to your personal library
There are three components to plvc:
- Spotify API
- Git repos
- Github PR API
To keep things simple, I decided to use git's version control capabilities to keep track of changes to my Spotify playlists.
For each playlist in a Spotify account, plvc creates a {playlist_uid}_{playlist_normalized_name}.txt
file with the following format:
{playlist_uid} - {playlist_name} by {playlist_owner}
{track_uid} - {track_name} by {track_artists}
{track_uid} - {track_name} by {track_artists}
{track_uid} - {track_name} by {track_artists}
...
In addition to creating playlist text files, plvc requires an additional git repository to store / track changes to the generated files. This repository will contain the history of track / playlist changes, making it easy to see how your music changed over time.
For example, let's assume we have these two repos:
plvc.git - repo containing the version control logic
history.git - repo containing playlist text files and history
When running plvc, the following steps will occur:
- Pull the latest master from origin in our
history.git
repo - Create a temporary branch from master. Branch name will be the current timestamp e.g
Aug-28-2020-12-23-05
- Using the Spotify API, generate a playlist text file containing all the track metadata
- Create a commit containing the newly generated playlist text files, and push to origin
- Using the Github API, create a PR from our temporary branch to our base branch (
master
) - If no conflicts are found, automatically merge and close the PR.
- Profit
To use plvc, a few ENV variables are needed:
PLAYLIST_REPO_DIR - Absolute path to the repository containg the playlist text files (`history.git` in the example)
PLAYLIST_REPO_REMOTE_URL - Origin remote url for our playlist history repository
SPOTIFY_CLIENT_ID - Spotify client ID
SPOTIFY_CLIENT_SECRET - Spotify client secret
SPOTIFY_REDIRECT_URI - Spotify redirect URI
SPOTIFY_USERNAME - Spotify username
GITHUB_ACCESS_TOKEN - Github access token with repo permissions
GITHUB_PLAYLIST_REPO_ID - Repository name for the playlist history in Github
SENTRY_DSN - DSN to report to Sentry. Not needed, but I use it for my own personal reporting in my server
These variables can be stored in an .env
file within the plvc directory, or loaded in your execution environment.
To start plvc:
# Skip if you don't need a virtualenv
pyhton3 -m venv venv
source venv/bin/activate
pip3 install -r plvc/requirements.txt
python3 plvc
In order to view a user's public and private playlists, plvc needs to use Spotify's Authorization Code Flow. This auth flow requires the account owner to accept a prompt giving plvc permission to access their personal information.
This auth flow should work fine if you are running plvc in an environment with a graphical user interface (e.g. your personal laptop, a server with a windowing system, etc...)
If you are running plvc on a server, you will need to obtain your Spotify access token and refresh token somehow and store it in a token-info.json
at the root of your plvc directory.
To obtain a valid token-info.json
file to be used server side, I recommend:
- Running plvc in an environment that has a GUI and a browser
- Copying the
token-info.json
generated by plvc to your server - Run plvc server-side and ensure that the auth process is working correctly
If you know of other ways of obtaining a valid Spotify access token and refresh token, then simply create a token-info.json
file in the root of your plvc directory and plug in the values.
The token-info.json
file should look like this:
{
"access_token": "YOURACCESSTOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "playlist-read-collaborative playlist-read-private user-library-read",
"expires_at": 1598642585,
"refresh_token": "YOURREFRESHTOKEN"
}
Since we are pushing / pulling from a remote origin, make sure that the user excuting plvc has read / write permissions to the playlist history repository.
Make sure that the Github access token you are using with plvc has the following permissions:
In my personal setup, I'm running plvc as a systemd service with a 1 hour trigger.
Here are my config files:
plvc.service:
[Unit]
Description=plvc
Wants=plvc.timer
[Service]
Type=simple
WorkingDirectory=/path/to/plvc
ExecStart=/path/to/plvc/venv/bin/python .
[Install]
WantedBy=multi-user.target
plvc.timer:
[Unit]
Description=Run plvc every hour
Requires=plvc.service
[Timer]
Unit=plvc.service
OnUnitInactiveSec=60m
AccuracySec=1s
[Install]
WantedBy=timers.target
For error reporting, I use Sentry to send email notifications whenever an exception is raised.