Merge e24f115f42
into 0ccf12c9c7
commit
a9d7b29e42
11
README.md
11
README.md
|
@ -7,16 +7,21 @@ To run the script, [save it from here](https://raw.githubusercontent.com/caseych
|
||||||
|
|
||||||
You can run the script from the command line:
|
You can run the script from the command line:
|
||||||
|
|
||||||
python spotify-backup.py playlists.txt
|
python spotify-backup.py --file playlists.txt
|
||||||
|
|
||||||
or, to get a JSON dump, use:
|
or, to get a JSON dump, use:
|
||||||
|
|
||||||
python spotify-backup.py playlists.json --format=json
|
python spotify-backup.py --file playlists.json --format json
|
||||||
|
|
||||||
By default, it includes your playlists. To include your Liked Songs, you can use:
|
By default, it includes your playlists. To include your Liked Songs, you can use:
|
||||||
|
|
||||||
python spotify-backup.py playlists.txt --dump=liked,playlists
|
python spotify-backup.py --file liked_songs_and_playlists.txt --dump liked playlists
|
||||||
|
|
||||||
|
By default, it includes all your playlists. To include and/or exclude some, you can use:
|
||||||
|
|
||||||
|
python spotify-backup.py --file no_autogenerated_playlists.txt --exclude-playlists "Discover Weekly" "Release Radar"
|
||||||
|
|
||||||
|
python spotify-backup.py --file best_of_playlists_without_1980s.txt --include-playlists "Best of year *" --exclude-playlists "Best of year 198?"
|
||||||
|
|
||||||
If for some reason the browser-based authorization flow doesn't work, you can also [generate an OAuth token](https://developer.spotify.com/web-api/console/get-playlists/) on the developer site (with the `playlist-read-private` permission) and pass it with the `--token` option.
|
If for some reason the browser-based authorization flow doesn't work, you can also [generate an OAuth token](https://developer.spotify.com/web-api/console/get-playlists/) on the developer site (with the `playlist-read-private` permission) and pass it with the `--token` option.
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import codecs
|
import codecs
|
||||||
|
import fnmatch
|
||||||
import http.client
|
import http.client
|
||||||
import http.server
|
import http.server
|
||||||
import json
|
import json
|
||||||
|
@ -131,12 +132,16 @@ def main():
|
||||||
parser = argparse.ArgumentParser(description='Exports your Spotify playlists. By default, opens a browser window '
|
parser = argparse.ArgumentParser(description='Exports your Spotify playlists. By default, opens a browser window '
|
||||||
+ 'to authorize the Spotify Web API, but you can also manually specify'
|
+ 'to authorize the Spotify Web API, but you can also manually specify'
|
||||||
+ ' an OAuth token with the --token option.')
|
+ ' an OAuth token with the --token option.')
|
||||||
parser.add_argument('--token', metavar='OAUTH_TOKEN', help='use a Spotify OAuth token (requires the '
|
parser.add_argument('--token', metavar='OAUTH_TOKEN',
|
||||||
+ '`playlist-read-private` permission)')
|
help='use a Spotify OAuth token (requires the `playlist-read-private` permission)')
|
||||||
parser.add_argument('--dump', default='playlists', choices=['liked,playlists', 'playlists,liked', 'playlists', 'liked'],
|
parser.add_argument('--dump', default=['playlists'], nargs='+', choices=['liked', 'playlists'],
|
||||||
help='dump playlists or liked songs, or both (default: playlists)')
|
help='dump playlists or liked songs, or both (default: playlists)')
|
||||||
parser.add_argument('--format', default='txt', choices=['json', 'txt'], help='output format (default: txt)')
|
parser.add_argument('--format', default='txt', choices=['json', 'txt'], help='output format (default: txt)')
|
||||||
parser.add_argument('file', help='output filename', nargs='?')
|
parser.add_argument('--include-playlists', metavar='NAME_PATTERN', default=['*'], nargs='*',
|
||||||
|
help='playlist name(s) to be included (default: all) if dumping playlists; ? and * wildcards may be used')
|
||||||
|
parser.add_argument('--exclude-playlists', metavar='NAME_PATTERN', default=[], nargs='*',
|
||||||
|
help='playlist name(s) to be excluded (default: none) if dumping playlists; ? and * wildcards may be used')
|
||||||
|
parser.add_argument('--file', help='output filename')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# If they didn't give a filename, then just prompt them. (They probably just double-clicked.)
|
# If they didn't give a filename, then just prompt them. (They probably just double-clicked.)
|
||||||
|
@ -166,18 +171,24 @@ def main():
|
||||||
liked_albums = spotify.list('me/albums', {'limit': 50})
|
liked_albums = spotify.list('me/albums', {'limit': 50})
|
||||||
playlists += [{'name': 'Liked Songs', 'tracks': liked_tracks}]
|
playlists += [{'name': 'Liked Songs', 'tracks': liked_tracks}]
|
||||||
|
|
||||||
# List all playlists and the tracks in each playlist
|
# List all playlists and the tracks in each requested playlist
|
||||||
if 'playlists' in args.dump:
|
if 'playlists' in args.dump:
|
||||||
logging.info('Loading playlists...')
|
logging.info('Loading playlists...')
|
||||||
playlist_data = spotify.list('users/{user_id}/playlists'.format(user_id=me['id']), {'limit': 50})
|
playlist_data = spotify.list('users/{user_id}/playlists'.format(user_id=me['id']), {'limit': 50})
|
||||||
logging.info(f'Found {len(playlist_data)} playlists')
|
logging.info(f'Found {len(playlist_data)} playlists')
|
||||||
|
|
||||||
# List all tracks in each playlist
|
# List all tracks in each requested playlist
|
||||||
for playlist in playlist_data:
|
for playlist in playlist_data:
|
||||||
logging.info('Loading playlist: {name} ({tracks[total]} songs)'.format(**playlist))
|
is_included = any([fnmatch.fnmatch(playlist['name'], pattern) for pattern in args.include_playlists])
|
||||||
playlist['tracks'] = spotify.list(playlist['tracks']['href'], {'limit': 100})
|
is_excluded = any([fnmatch.fnmatch(playlist['name'], pattern) for pattern in args.exclude_playlists])
|
||||||
playlists += playlist_data
|
|
||||||
|
if is_included and not is_excluded:
|
||||||
|
logging.info('Loading playlist: {name} ({tracks[total]} songs)'.format(**playlist))
|
||||||
|
playlist['tracks'] = spotify.list(playlist['tracks']['href'], {'limit': 100})
|
||||||
|
playlists.append(playlist)
|
||||||
|
else:
|
||||||
|
logging.info('Skipped playlist: {name}'.format(**playlist))
|
||||||
|
|
||||||
# Write the file.
|
# Write the file.
|
||||||
logging.info('Writing files...')
|
logging.info('Writing files...')
|
||||||
with open(args.file, 'w', encoding='utf-8') as f:
|
with open(args.file, 'w', encoding='utf-8') as f:
|
||||||
|
|
Loading…
Reference in New Issue