Skip to content

Instantly share code, notes, and snippets.

@AgeOfMarcus
Last active March 20, 2022 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AgeOfMarcus/635c824688ed525ab181409a1a17997c to your computer and use it in GitHub Desktop.
Save AgeOfMarcus/635c824688ed525ab181409a1a17997c to your computer and use it in GitHub Desktop.
Python script using the spotipy library to merge multiple child playlists' tracks into one parent playlist without duplicates.
'''
Name : spotify_playlist_combine.py
Author : Marcus Weinberger
About : This program takes multiple "child" playlists and combines their tracks
(without duplicates). Then, tracks from playlists marked for removal are
removed from the list. The parent playlist is emptied, and all tracks added.
You might need to run it a couple times because it throws errors and idk why,
but run it twice and usually it will have done all it needs to.
'''
import spotipy
from spotipy.oauth2 import SpotifyOAuth
from dotenv import load_dotenv
import os
load_dotenv() # save your environment variables in the same directory as this script in a .env file
# Make sure your application has the redirect_uri configured the same.
# It doesn't need to be reachable. https://127.0.0.1/callback works fine.
auth_manager = SpotifyOAuth(
client_id=os.getenv('SPOTIFY_CLIENT_ID'),
client_secret=os.getenv('SPOTIFY_CLIENT_SECRET'),
scope='playlist-modify-public',
redirect_uri='https://127.0.0.1/callback'
)
sp = spotipy.Spotify(auth_manager=auth_manager)
####### EDIT THESE VARIABLES #######
PL_PARENT = '5PHoZ0ogEayVPilp2cq4p7' # dxm
PL_CHILDS = [
'5xSG6BCHFbRoj64Y7fM56n', # vyv
'0pSMHk2yCLedHzDHnzZoc8', # flp
'0atxFIMASi6z1YiYv6PrWb', # cnd
'5Hur608iMkjucDQqZS6YAa', # he
'6lvfbcgQ0O4BOcVSipH0Dr', # snm
'2laqXV38PevvZ5oCPPV7dx', # dav
]
PL_REMOVE = [
'0dPPa4MSRuj1rP06oipf5e', # k
'4jZILf6GxjxBFK3Ju9xvHX', # non
]
####### END CONFIGURATION #######
# get tracks in parent playlist
PARENT_TRACKS = set()
PL_TRACKS = sp.playlist(PL_PARENT)['tracks']
while True:
for track in PL_TRACKS['items']:
song_id = track['track']['id']
if song_id: PARENT_TRACKS.add(song_id)
if PL_TRACKS['next']:
PL_TRACKS = sp.next(PL_TRACKS)
else:
break
PARENT_TRACKS = list(PARENT_TRACKS)
# get tracks from children to add
tracks = set()
for PL in PL_CHILDS:
playlist = sp.playlist(PL)['tracks']
while True:
for track in playlist['items']:
song_id = track['track']['id']
if song_id and not song_id in PARENT_TRACKS:
tracks.add(song_id)
print('Added:', track['track']['name'])
if playlist['next']:
playlist = sp.next(playlist)
else:
break
tracks = list(tracks)
# get tracks scheduled for removal
remove = set()
for PL in PL_REMOVE:
playlist = sp.playlist(PL)['tracks']
while True:
for track in playlist['items']:
song_id = track['track']['id']
if song_id and not song_id in remove:
remove.add(song_id)
print('Removing:', track['track']['name'])
if playlist['next']:
playlist = sp.next(playlist)
else:
break
remove = list(remove)
# merging shit
NEW_PARENT_TRACKS = set()
for id in [*PARENT_TRACKS, *tracks]:
if not id in remove and not id in NEW_PARENT_TRACKS:
NEW_PARENT_TRACKS.add(id)
NEW_PARENT_TRACKS = list(NEW_PARENT_TRACKS)
# queued for removal
TO_REMOVE = [x for x in PARENT_TRACKS if not x in NEW_PARENT_TRACKS]
# queued for addition
TO_ADD = [x for x in NEW_PARENT_TRACKS if not x in PARENT_TRACKS]
# make changes
print('Removing old songs...')
removed = 0
while not removed == len(TO_REMOVE):
newtracks = TO_REMOVE[removed:removed+99]
sp.playlist_remove_all_occurrences_of_items(PL_PARENT, newtracks)
removed += 99
print('Syncing to parent playlist...')
added = 0
while not added == len(TO_ADD):
newtracks = TO_ADD[added:added+99] # max 100 songs at a time
sp.playlist_add_items(PL_PARENT, newtracks)
added += 99
print('Done!')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment