Skip to content

Instantly share code, notes, and snippets.

@jefftriplett
Last active October 24, 2020 02:49
Show Gist options
  • Save jefftriplett/7168ab8a57a1ffcdc118d7ae60fec2d0 to your computer and use it in GitHub Desktop.
Save jefftriplett/7168ab8a57a1ffcdc118d7ae60fec2d0 to your computer and use it in GitHub Desktop.
Dump your Spotify playlists to YAML or Markdown using Python.
"""
Formatting based on:
https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Albums/Album_article_style_guide
YAML formatting inspired by:
https://github.com/katydecorah/katydecorah.github.io/blob/master/_data/playlists.yml
Method inspired from:
- https://github.com/plamere/spotipy/blob/master/examples/user_playlists_contents.py
- https://github.com/jacobian/rdio-takeout-importer/blob/master/r2s.py#L68
Getting started:
$ pip install click envparse spotipy pyyaml unicode-slugify
Create a .env file with:
SPOTIFY_CLIENT_ID="CHANGE-THIS"
SPOTIFY_CLIENT_SECRET="CHANGE-THIS"
SPOTIFY_REDIRECT_URI="http://127.0.0.1/''
SPOTIFY_USERNAME="CHANGE-THIS"
If you plan to export to Yaml:
$ mkdir -p playlists
Run the script:
$ python spotify_playlist_export.py your-user-name --all --verbose
"""
import click
import os
import slugify
import spotipy
import spotipy.util
import yaml
from envparse import Env
env = Env(
SPOTIFY_CLIENT_ID=str,
SPOTIFY_CLIENT_SECRET=str,
SPOTIFY_REDIRECT_URI=dict(cast=str, default=''),
SPOTIFY_TOKEN=dict(cast=str, default=''),
SPOTIFY_USERNAME=dict(cast=str, default=''),
)
def connect_to_spotify(username):
SPOTIFY_TOKEN = env.str('SPOTIFY_TOKEN')
if len(SPOTIFY_TOKEN):
return spotipy.Spotify(auth=SPOTIFY_TOKEN)
else:
token = spotipy.util.prompt_for_user_token(
username or env.str('SPOTIFY_USERNAME'),
scope='playlist-read-private playlist-read-collaborative',
client_id=env.str('SPOTIFY_CLIENT_ID'),
client_secret=env.str('SPOTIFY_CLIENT_SECRET'),
redirect_uri=env.str('SPOTIFY_REDIRECT_URI'))
return spotipy.Spotify(auth=token)
def show_tracks(results):
tracks = results['items']
for result in tracks:
track = result['track']
click.echo('- ["{name}"]({href}) ({artist})'.format(
artist=track['artists'][0]['name'],
name=track['name'],
href=track['external_urls']['spotify'] if 'spotify' in track['external_urls'] else '',
))
def show_tracks_in_yaml(results):
track_results = []
for result in results['items']:
track = result['track']
track_results.append({
'track': track['name'],
'album': track['album']['name'],
'artist': track['artists'][0]['name'],
'spotify': track['external_urls']['spotify'] if 'spotify' in track['external_urls'] else '',
'spotify_id': track['id'],
})
return track_results
@click.command()
@click.argument('username')
@click.option('--playlist', default='')
@click.option('-a', '--all', 'use_all', is_flag=True)
@click.option('-s', '--save', is_flag=True)
@click.option('-v', '--verbose', is_flag=True)
@click.option('-y', '--yaml', 'use_yaml', is_flag=True)
def main(username, playlist, use_all, save, verbose, use_yaml):
if len(playlist):
playlist_names = playlist.split(',')
else:
playlist_names = []
spotify = connect_to_spotify(username)
playlists = spotify.user_playlists(username)
if use_yaml:
playlists_data = []
for playlist in playlists['items']:
if not(use_all) and \
len(playlist_names) and \
playlist['name'] not in playlist_names:
if verbose:
click.echo('skipping: {0}'.format(playlist['name']))
continue
playlist_data = {
'playlist': playlist['name'],
'cover': playlist['images'][0]['url'],
'hidden': not playlist['public'],
'spotify': playlist['external_urls']['spotify'],
'spotify_id': playlist['id'],
'tracks': []
}
# from pprint import pprint
# pprint(playlist)
owner = playlist['owner']['id']
results = spotify.user_playlist(owner, playlist['id'], fields='tracks,next')
tracks = results['tracks']
playlist_data['tracks'] = show_tracks_in_yaml(tracks)
while tracks['next']:
tracks = spotify.next(tracks)
playlist_data['tracks'] += show_tracks_in_yaml(tracks)
if save:
filename = '{0}.yml'.format(slugify.slugify(playlist['name']))
if verbose:
click.echo('writing playlist: {0}'.format(filename))
with open(os.path.join('playlists', filename), 'w') as f:
f.write(
yaml.dump(
playlist_data,
default_flow_style=False,
allow_unicode=True
)
)
else:
filename = '{0}.yml'.format(slugify.slugify(playlist['name']))
click.echo('# {0}'.format(filename))
click.echo(
yaml.dump(
playlist_data,
default_flow_style=False,
allow_unicode=True
)
)
playlists_data.append(playlist_data)
else:
for playlist in playlists['items']:
if len(playlist_names) and playlist['name'] not in playlist_names:
if verbose:
click.echo('skipping: {0}'.format(playlist['name']))
continue
click.echo("# {0}".format(playlist['name']))
click.echo()
owner = playlist['owner']['id']
results = spotify.user_playlist(owner, playlist['id'], fields='tracks,next')
tracks = results['tracks']
show_tracks(tracks)
while tracks['next']:
tracks = spotify.next(tracks)
show_tracks(tracks)
click.echo()
click.echo('---')
click.echo()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment