Skip to content

Commit

Permalink
First working version for public Deezer playlist migration
Browse files Browse the repository at this point in the history
  • Loading branch information
SebRil committed Nov 30, 2024
1 parent e9efd3c commit 975cb65
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 75 deletions.
16 changes: 8 additions & 8 deletions DeezerHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,32 +56,32 @@ def get_playlists_from_user(self, user_id=None):

def get_playlist_as_dir(self, input_playlists, output_dict):
print("Setting playlist dict 2")
max = 75
max = 100000
current = 0
for playlist in input_playlists:
print(playlist)
track_list = []
# L'API renvoie uniquement 25 morceaux par 25 morceaux, donc on les parcourt en incrémentant à chaque fois l'index de départ de 25
print("Deezer - Getting playlist tracks...")
for i in range(ceil(playlist.nb_tracks/25)):
try:
print("Getting playlist tracks...")
playlists_tracks = playlist.get_tracks(index=i*25)
except:
print("API error?")
print("Deezer - API error?")
return output_dict
for track in playlists_tracks:
print("ajout de: " + track.title)
#print("ajout de: " + track.title)
track_list.append([track.title, track.artist.name, track.album.title])
print("Ajouté!")
#print("Ajouté!")
current += 1
if current >= max:
print("Reaching too many songs in a variable, stopping here")
print("Deezer - Reaching too many songs in a variable, stopping here")
break
if current >= max:
break
print("Adding playlist to dict")
#print("Adding playlist to dict")
output_dict[playlist.title] = track_list
print("Returning playlist dict")
print("Deezer - Returning playlist dict")
return output_dict

def get_loved_tracks_as_dir(self, private_user):
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Launch the "testUI.py" file to run the main UI.
- Go to https://developer.spotify.com/dashboard
- Create an app:
- Provide an app name & description
- Set the redirect URI to http://localhost
- Set the redirect URI to http://localhost:8888
- Tick the usage of the Web API
- Go to the app's settings
- Copy the Client ID and the Client Secret into a notepad (or anywhere, just don't save it!)
Expand Down
37 changes: 24 additions & 13 deletions SpotifyHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,31 +113,31 @@ def find_track(self, track_name, track_artist=None, track_album=None):
result_tracks_list.append(current_track_data)
# Si le résultat courant correspond exactement au morceau cherché, on ne renvoie que celui-là ; sinon on continue de parcourir en ajoutant les morceaux aux résultat potentiels
if current_track_data[1] == track_name and current_track_data[2] == track_artist and current_track_data[3] == track_album:
result_tracks_list = [current_track_data]
result_tracks_list = current_track_data
result = result_tracks_list
exact_track_found = True
print('INFO : Morceau exact trouvé')
break
# Si aucun résultat exact n'a été trouvé, on renvoie la liste des résultats potentiels
# Si aucun résultat exact n'a été trouvé, on renvoie le premier résultat
if not exact_track_found :
print('AVERTISSEMENT : le morceau exact n\'a pas été trouvé')
result = result_tracks_list
result = result_tracks_list[0]
return result

def create_playlist(self, playlist_name, playlist_description):
playlist_already_exists, playlist_id = self.find_playlist_by_name(playlist_name)
if not playlist_already_exists:
created_playlist = self.sp.user_playlist_create(self.user_id, playlist_name, False, False, playlist_description)
playlist_id = created_playlist['id']
print("Playlist id = " + playlist_id)
print("Created playlist id = " + playlist_id)
return playlist_id

def find_playlist_by_name(self, playlist_name):
user_playlists = self.sp.user_playlists(self.user_id)
for playlist in user_playlists['items']:
print("Playlist courante : " + playlist['name'])
#print("Playlist courante : " + playlist['name'])
if playlist_name == playlist['name']:
print('Une playlist existe déjà avec ce nom')
#print('Une playlist existe déjà avec ce nom')
return True, playlist['id']
return False, None

Expand All @@ -148,13 +148,22 @@ def add_tracks_to_playlist(self, playlist_id, tracks_list):
API_limit = 99
nb_tracks = len(tracks_list)
nb_packets = ceil(nb_tracks / API_limit)
print(nb_tracks)
print(nb_packets)
last_packet_length = nb_tracks % API_limit
j = 0
for i in range(nb_packets - 1):
self.sp.playlist_add_items(playlist_id, tracks_list[j:(j + API_limit)])
j += API_limit
if last_packet_length > 0:
self.sp.playlist_add_items(playlist_id, tracks_list[j:(j + last_packet_length)])
print(last_packet_length)
j = 0
#TODO: harmoniser; si on ne sélectionne qu'un morceau j'ai dû ajouter ce if dégueulasse
if nb_tracks == 1:
print(playlist_id)
print(tracks_list[0])
self.sp.playlist_add_items(playlist_id, tracks_list[0])
else:
for i in range(nb_packets - 1):
self.sp.playlist_add_items(playlist_id, tracks_list[j:(j + API_limit)])
j += API_limit
if last_packet_length > 0:
self.sp.playlist_add_items(playlist_id, tracks_list[j:(j + last_packet_length)])

# Récupère les playlists
def get_playlists(self):
Expand All @@ -171,4 +180,6 @@ def get_playlists(self):
def get_playlist_tracks(self,playlist_id):
tracks = self.sp.playlist(playlist_id,additional_types=('track'))
print('##########################')
print(tracks['items'])
#print(tracks)
print(tracks['tracks']['items'])
return tracks['tracks']['items']
192 changes: 139 additions & 53 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
# - User ID (public playlists)
# - User application (private playlists)

def reset_session(caller):
print("Reset cache initiated by " + caller)
st.session_state.search_songs = False
st.session_state.sptfy_matches = []
st.session_state.playlist_created_success = ''

# Left menu
# Deezer elements
global deezer_handler
deezer_handler=None
st.sidebar.text('Deezer')
deezer_element_choice = st.sidebar.selectbox(
'What element would you like to retrieve from Deezer?',
Expand All @@ -23,19 +31,67 @@
dzr_playlist_id = st.sidebar.text_input("Playlist ID", default_value)
elif deezer_element_choice == 'A user\'s public playlists':
dzr_user_id = st.sidebar.text_input("Deezer user ID", default_value)
st.write("This feature has not been implemented! 🥵")
elif deezer_element_choice == 'All playlists from a user':
dzr_app_id = st.sidebar.text_input("Application ID", "")
dzr_app_secret = st.sidebar.text_input("Application Secret", "")
dzr_access_token = st.sidebar.text_input("Redirect URI", "")
dzr_app_id = st.sidebar.text_input("Deezer Application ID", "")
dzr_app_secret = st.sidebar.text_input("Deezer Application Secret", "")
dzr_access_token = st.sidebar.text_input("Deezer Application Redirect URI", "")
st.write("This feature has not been implemented! 🥵")

# Spotify elements
#global sptfy_handler
#sptfy_handler=None
st.sidebar.text('Spotify')
spfy_app_id = st.sidebar.text_input("Application ID", "")
spfy_app_secret = st.sidebar.text_input("Application Secret", "")
spfy_access_token = st.sidebar.text_input("Redirect URI", "")
spfy_app_id = st.sidebar.text_input("Spotify Application ID", "",on_change=reset_session, args=('sptf_app_id',))
spfy_app_secret = st.sidebar.text_input("Spotify Application Secret", "",on_change=reset_session, args=('sptf_app_id',))
spfy_access_token = st.sidebar.text_input("Spotify Application Redirect URI", "",on_change=reset_session, args=('sptf_app_id',))

# Initiate session variables
if 'search_songs' not in st.session_state:
st.session_state.search_songs = False

# Methods
def get_spotify_handler():
if spfy_app_id != '' and spfy_app_secret != '' and spfy_access_token != '':
try:
spotify_handler = sh.SpotifyHandler(spfy_app_id,spfy_app_secret,spfy_access_token)
st.sidebar.write("Successfully connected to Spotify! 😊")
except Exception as e:
st.sidebar.write("Couldn't connect to this Spotify App 🫣")
spotify_handler = None
else:
spotify_handler = None
return spotify_handler

def search_sptfy_songs(dzr_songs, sptfy_handler):
results=[]
for index,dzr_song in dzr_songs.iterrows():
matching_track = sptfy_handler.find_track(track_name=dzr_song['Title'],track_artist=dzr_song['Artist'],track_album=dzr_song['Album'])
print(matching_track)
if matching_track is not None:
results.append(matching_track)
return results

def create_sptfy_playlist(sptfy_playlist_name, sptfy_playlist_desc, sptfy_matches,sptfy_handler):
# Create the new playlist
sptfy_playlist_id = sptfy_handler.create_playlist(sptfy_playlist_name,sptfy_playlist_desc)
if sptfy_playlist_id is not None:
# Keep only URI to add to the playlist
tracks_uri = [elem[0] for elem in sptfy_matches]
print(tracks_uri)
# Add tracks to the playlist
try:
sptfy_handler.add_tracks_to_playlist(sptfy_playlist_id,tracks_uri)
st.session_state.playlist_created_success = 'OK'
except:
st.session_state.playlist_created_success = 'TracksKO'
else:
st.session_state.playlist_created_success = 'PlaylistKO'
st.write('A playlist already exists with this name 🫣')

def button_search_songs_clicked():
st.session_state.search_songs = True

def handle_deezer_input_playlist(playlist_id):
try:
deezer_handler = dh.DeezerHandler()
Expand All @@ -46,44 +102,94 @@ def handle_deezer_input_playlist(playlist_id):
playlist = None

if playlist is not None:
select_all = st.checkbox('Select all')
tracks = {}
tracks = deezer_handler.get_playlist_as_dir([playlist],tracks)
print(tracks)
#df = pd.DataFrame([tracks[0]], columns=["Title", "Author", "Album"])
df = pd.DataFrame.from_dict(tracks)#, columns=["Title", "Author", "Album"])
#df_spotify = pd.DataFrame([["Test1", "Test1", "Test1"],["Test2", "Test2", "Test2"]],columns=["Title", "Author", "Album"])
#edited_df = st.data_editor(df)
edited_df = st.table(df)
#col1, col2 = st.columns(2)
#col1.data_editor(df)
#col2.data_editor(df_spotify)
#tabs
#tab1, tab2 = st.tabs(["Data", "Chart"])
#with tab1:
# st.table(df)
list_for_df = ((elem + [select_all]) for elem in tracks[playlist.title])
dzr_df = pd.DataFrame(list_for_df, columns=["Title", "Artist", "Album","Select"])
dzr_track_array = st.data_editor(
dzr_df,
column_config={
"Select": st.column_config.CheckboxColumn(
"Select",
help="Migrate this song",
default=False,
)
},
disabled=["Title","Artist","Album"],
hide_index=True,
on_change=reset_session,
args=('Deezer table',)
)
selected_rows = dzr_track_array[dzr_track_array.Select]

# Search for matching songs in Spotify
sptfy_matches = None
st.button('Search songs in Spotify', on_click=button_search_songs_clicked)
if st.session_state.search_songs:
print("Searching Spotify songs")
sptfy_handler = get_spotify_handler()
if sptfy_handler is None:
st.write('Please connect to your Spotify API application to search for songs 🫣')
else:
if len(selected_rows) == 0:
st.write('Please select some songs to migrate 🫣')
else:
if st.session_state.sptfy_matches:
print('Retrieving matching songs from cache')
sptfy_matches = st.session_state.sptfy_matches
else:
print('Searching for songs in Spotify')
sptfy_matches = search_sptfy_songs(selected_rows, sptfy_handler)
print(sptfy_matches)
if sptfy_matches is not None:
st.session_state.sptfy_matches = sptfy_matches
# Display recap
st.title('Spotify search results')
st.write('The following tracks will be added to the new playlist:')
sptfy_df = pd.DataFrame.from_records(sptfy_matches, columns=["Id","Title", "Artist", "Album"])
sptfy_track_array = st.data_editor(
sptfy_df,
disabled=["Id","Title","Artist","Album"],
column_order=("Title", "Artist", "Album")
)

# Add inputs for the new playlist
sptfy_playlist_name = st.text_input("Target Spotify Playlist Name",playlist.title)
sptfy_playlist_desc= st.text_input("Target Spotify Playlist Description",'')
if st.button('Create the playlist!', on_click=create_sptfy_playlist, args=(sptfy_playlist_name, sptfy_playlist_desc, sptfy_matches, sptfy_handler)):
if st.session_state.playlist_created_success == 'OK':
st.write('The playlist has been created! 🥳')
elif st.session_state.playlist_created_success == 'TracksKO':
st.write('Something went wrong when adding the tracks to the new playlist 🫣')
elif st.session_state.playlist_created_success == 'PlaylistKO':
st.write('The playlist could not be created (maybe this name is already taken?) 🫣')
else:
st.write('The corresponding songs in Spotify were not found 🫣')

def handle_deezer_input_user(dzr_user_id):
try:
deezer_handler = dh.DeezerHandler()
st.sidebar.write("The user is", deezer_handler.get_user_name(dzr_user_id))
st.write("The user is", deezer_handler.get_user_name(dzr_user_id))
except Exception as e:
st.sidebar.write("Wrong user ID 🫣")
dzr_user_id = None

if dzr_user_id is not None:
deezer_playlists = deezer_handler.get_playlists_from_user(dzr_user_id)
st.write("This feature has not been implemented! 🥵")
#if dzr_user_id is not None:
# deezer_playlists = deezer_handler.get_playlists_from_user(dzr_user_id)

selected_playlists = st.multiselect(
"Select playlists you want to migrate",
list(deezer_playlists.keys()),
[])
# selected_playlists = st.multiselect(
# "Select playlists you want to migrate",
# list(deezer_playlists.keys()),
# [])

for playlist in selected_playlists:
st.title('Migrate playlist %s' % playlist)
df = pd.DataFrame(deezer_playlists[playlist], columns=["Title", "Author", "Album"])
df_spotify = pd.DataFrame([["Test1", "Test1", "Test1"],["Test2", "Test2", "Test2"]],columns=["Title", "Author", "Album"])
# for playlist in selected_playlists:
# st.title('Migrate playlist %s' % playlist)
# df = pd.DataFrame(deezer_playlists[playlist], columns=["Title", "Author", "Album"])
# df_spotify = pd.DataFrame([["Test1", "Test1", "Test1"],["Test2", "Test2", "Test2"]],columns=["Title", "Author", "Album"])
#edited_df = st.data_editor(df)
edited_df = st.table(df)
# edited_df = st.table(df)
#col1, col2 = st.columns(2)
#col1.data_editor(df)
#col2.data_editor(df_spotify)
Expand All @@ -97,25 +203,5 @@ def handle_deezer_input_app(app_id, app_secret, app_token):

if dzr_playlist_id != '' and dzr_playlist_id != default_value:
handle_deezer_input_playlist(dzr_playlist_id)
if dzr_user_id != '' and dzr_user_id != default_value:
handle_deezer_input_user(dzr_user_id)

if spfy_app_id != '' and spfy_app_secret != '' and spfy_access_token != '':
try:
spotify_handler = sh.SpotifyHandler(spfy_app_id,spfy_app_secret,spfy_access_token)
st.sidebar.write("Successfully connected to Spotify! 😊")
except Exception as e:
st.sidebar.write("Couldn't connect to this Spotify App 🫣")
spotify_handler = None

if spotify_handler is not None:
spotify_playlists = spotify_handler.get_playlists()

selected_playlists = st.multiselect(
"Select playlists you want to browse",
list(spotify_playlists.keys()),
[])

for selected_playlist in selected_playlists :
print('Getting tracks from playlist ' + selected_playlist + ' id (' + spotify_playlists[selected_playlist]['id'] + ')')
spotify_handler.get_playlist_tracks(spotify_playlists[selected_playlist]['id'])
#if dzr_user_id != '' and dzr_user_id != default_value:
# handle_deezer_input_user(dzr_user_id)

0 comments on commit 975cb65

Please sign in to comment.