1+ ############################
2+ # MADE BY: OMKAR PATEL #
3+ ############################
4+
5+ import os
6+ import time
7+ import random
8+ import string
9+ import spotipy
10+ import webbrowser
11+ import spotipy .util as util
12+ from colorama import Fore as fore
13+ from twilio .rest import Client
14+
15+
16+ ###########################################
17+ # CONFIG VALUES -> README.md for setup #
18+ ###########################################
19+
20+ try :
21+ from utils .user_secrets import username , clientID , clientSecret , redirectURI , banner , account_sid , auth_token , acc_number
22+ except :
23+ print ("Error: utils/user_secrets.py NOT found\n View https://github.com/omkarxpatel/Spotify-Playlist-Generator#getting-started" )
24+
25+ ###########################
26+ # CHECKLIST FUNCTIONS #
27+ ###########################
28+
29+ not_completed = "❌"
30+ completed = "✅"
31+ working = "⏳"
32+
33+ topbot = "--------------------------------------------"
34+ step1 = f"| { not_completed } | Extracting songs | |"
35+ step2 = f"| { not_completed } | Extracting song-ids | |"
36+ step3 = f"| { not_completed } | Generating songs | |"
37+ step4 = f"| { not_completed } | Adding songs | |"
38+ step5 = f"| { not_completed } | Playlist finished | |"
39+
40+
41+ def checklist_helper (task ):
42+ task = int (task )
43+ taskTime = round (time .time ()- task ,2 )
44+ spacing = " " * (6 - len (str (taskTime )))
45+
46+ return ([taskTime , spacing ])
47+
48+
49+ def checklist (step , working_bool = None , task = None ):
50+ clear (0 )
51+ global step1 ,step2 ,step3 ,step4 ,step5
52+
53+ value = completed
54+ if working_bool == True :
55+ value = working
56+
57+ if step == 1 :
58+ if task :
59+ val = checklist_helper (task )
60+ step1 = f"| { value } | Extracting songs | ({ val [0 ]} s){ val [1 ]} |"
61+
62+ elif step == 2 :
63+ if task :
64+ val = checklist_helper (task )
65+ step2 = f"| { value } | Extracting song-ids | ({ val [0 ]} s){ val [1 ]} |"
66+
67+ elif step == 3 :
68+ if task :
69+ val = checklist_helper (task )
70+ step3 = f"| { value } | Generating songs | ({ val [0 ]} s){ val [1 ]} |"
71+
72+ elif step == 4 :
73+ if task :
74+ val = checklist_helper (task )
75+ step4 = f"| { value } | Adding songs | ({ val [0 ]} s){ val [1 ]} |"
76+
77+ elif step == 5 :
78+ if task :
79+ val = checklist_helper (task )
80+ step5 = f"| { value } | Playlist finished | ({ val [0 ]} s){ val [1 ]} |"
81+
82+
83+ print (topbot ); print (step1 ); print (step2 ); print (step3 ); print (step4 ); print (step5 ); print (topbot )
84+
85+ ########################
86+ # HELPER FUNCTIONS #
87+ ########################
88+
89+ def roundPlaylistLen (val ):
90+ return (val + (20 - val % 20 ))/ 4
91+
92+ def isvalid (option , min , max ):
93+ return min <= option <= max
94+
95+ def raiseError (error ):
96+ print (f"{ fore .RED } Error: { fore .RESET } { error } " )
97+
98+ def clear (val ):
99+ if val != 0 :
100+ time .sleep (val )
101+ os .system ("clear" )
102+
103+ ###################
104+ # PLAY A SONG #
105+ ###################
106+
107+ def playSong (spotifyObject , searchQuery ):
108+ searchResults = spotifyObject .search (searchQuery ,1 ,0 ,"track" )
109+ track = searchResults ["tracks" ]["items" ][0 ]
110+
111+ openSong = input ("Would you like to open this song in your browser [yes/no]: " ).lower ()
112+ song = searchResults ["tracks" ]["items" ][0 ]["external_urls" ]["spotify" ]
113+
114+ if openSong in ["y" ,"yes" ]:
115+ try :
116+ webbrowser .open (song )
117+ except :
118+ raiseError (f"Could not open: { song } " )
119+
120+ print (f"{ fore .GREEN } ✅ Playing { track ['name' ]} - { track ['artists' ][0 ]['name' ]} { fore .RESET } " )
121+
122+ scope = "user-modify-playback-state"
123+ token = util .prompt_for_user_token (username , scope , client_id = clientID , client_secret = clientSecret , redirect_uri = redirectURI )
124+
125+ sp = spotipy .Spotify (auth = token )
126+ sp .start_playback (uris = [song ])
127+
128+ ##############################
129+ # GET A RECOMMENDED SONG #
130+ ##############################
131+
132+ def recommendSong (spotifyObject , song1 , song2 , song3 ):
133+
134+ results_1 = spotifyObject .search (q = song1 , type = "track" )
135+ song_1_id = results_1 ["tracks" ]["items" ][0 ]["id" ]
136+
137+ results_2 = spotifyObject .search (q = song2 , type = "track" )
138+ song_2_id = results_2 ["tracks" ]["items" ][0 ]["id" ]
139+
140+ results_3 = spotifyObject .search (q = song3 , type = "track" )
141+ song_3_id = results_3 ["tracks" ]["items" ][0 ]["id" ]
142+
143+
144+ recommendations = spotifyObject .recommendations (seed_tracks = [song_1_id , song_2_id , song_3_id ])
145+ recommended_song = recommendations ["tracks" ][0 ]["name" ]
146+ recommended_song_id = recommendations ["tracks" ][0 ]["id" ]
147+ recommended_song_url = recommendations ["tracks" ][0 ]["external_urls" ]["spotify" ]
148+
149+ track = spotifyObject .track (recommended_song_id )
150+ artist = track ["artists" ][0 ]["name" ]
151+
152+ print (f"\n Recommended song: { recommended_song } - { artist } " )
153+ play = input ("Would you like to play this song [yes/no]: " ).lower ()
154+
155+ if play in ["y" ,"yes" ]:
156+
157+ print (f"{ fore .GREEN } ✅ Playing { recommended_song } - { artist } { fore .RESET } " )
158+
159+ scope = "user-modify-playback-state"
160+ token = util .prompt_for_user_token (username , scope , client_id = clientID , client_secret = clientSecret , redirect_uri = redirectURI )
161+
162+ sp = spotipy .Spotify (auth = token )
163+ sp .start_playback (uris = [recommended_song_url ])
164+
165+ #########################
166+ # GENERATE PLAYLIST #
167+ #########################
168+
169+ def generate_similar_playlist (spotifyObject , playlist_url ):
170+ tasktime = time .time ()
171+
172+ checklist (0 , task = tasktime )
173+ checklist (1 , True )
174+ onetime = time .time ()
175+
176+ playlist_id = playlist_url .split ("/" )[- 1 ]
177+ playlist = spotifyObject .playlist (playlist_id )
178+
179+ song_names = []
180+ tracks = playlist ['tracks' ]
181+
182+ for z in range (len (tracks ['items' ])):
183+ item = tracks ['items' ][z ]
184+ song_names .append (item ['track' ]['name' ])
185+
186+ checklist (1 , True , task = tasktime )
187+
188+ checklist (1 , task = onetime )
189+ checklist (2 , True )
190+ twotime = time .time ()
191+
192+ song_ids = []
193+ total_songs = []
194+
195+ for z in range (len (song_names )):
196+ item = song_names [z ]
197+ result = spotifyObject .search (q = item , type = "track" )
198+ song_id = result ["tracks" ]["items" ][0 ]["id" ]
199+
200+ song_ids .append (song_id )
201+ checklist (2 , True , task = twotime )
202+
203+
204+ checklist (2 , task = twotime )
205+ checklist (3 , True )
206+ threetime = time .time ()
207+
208+ for _ in range (int (roundPlaylistLen (len (song_ids ))/ 4 )):
209+ recommendations = spotifyObject .recommendations (limit = 20 , seed_tracks = random .sample (song_ids , 5 ))
210+
211+ for y in range (len (recommendations ["tracks" ])):
212+ song = recommendations ["tracks" ][y ]["name" ]
213+ song_uri = recommendations ["tracks" ][y ]["uri" ]
214+
215+ value = f"{ song } :{ song_uri } "
216+ total_songs .append (value )
217+ checklist (3 , True , task = threetime )
218+
219+ scope = 'playlist-modify-public playlist-modify-private'
220+ token = util .prompt_for_user_token (username , scope , client_id = clientID , client_secret = clientSecret , redirect_uri = redirectURI )
221+ sp = spotipy .Spotify (auth = token )
222+
223+ generated_name = '' .join (random .choices (string .ascii_letters , k = 10 ))
224+ gen_playlist = sp .user_playlist_create (username , name = generated_name )
225+ gen_playlist_id = gen_playlist ['id' ]
226+
227+ checklist (3 , task = threetime )
228+ checklist (4 , True )
229+ fourtime = time .time ()
230+
231+ for item in total_songs :
232+ item = item .split (":" )
233+
234+ sp .user_playlist_add_tracks (username , gen_playlist_id , [item [- 1 ]])
235+ checklist (4 , True , task = fourtime )
236+
237+
238+ checklist (4 , task = fourtime )
239+ checklist (5 , True )
240+
241+ time .sleep (1 )
242+ checklist (5 , task = tasktime )
243+
244+
245+ print (f"Generated playlist: { generated_name } " )
246+ print (f"Playlist URL: { gen_playlist ['external_urls' ]['spotify' ]} " )
247+
248+ client = Client (account_sid , auth_token )
249+
250+ message = client .messages .create (
251+ to = acc_number ,
252+ from_ = "+19295773793" ,
253+ body = f"Your generated playlist is: { gen_playlist ['external_urls' ]['spotify' ]} " )
254+ print (f"Message SID: { message .sid } " )
255+
256+ ####################
257+ # MAIN STARTER #
258+ ####################
259+
260+ def main ():
261+ spotifyObject = spotipy .Spotify (auth = spotipy .SpotifyOAuth (clientID ,clientSecret ,redirectURI ).get_access_token ()["access_token" ])
262+ user = spotifyObject .current_user ()
263+ clear (0 )
264+
265+ while True :
266+ print (banner .format (user ["display_name" ]))
267+
268+ while True :
269+ choice = input ("Enter a choice: " )
270+
271+
272+ try :
273+ choice = int (choice )
274+ except :
275+ raiseError (f"\" { choice } \" is not an integer" )
276+ clear (5 )
277+
278+ if isvalid (choice , 0 , 4 ):
279+ clear (0 ); break
280+
281+ if choice == 0 :
282+ clear (0 ); exit ()
283+
284+ elif choice == 1 :
285+ searchQuery = input ("Enter Song Name: " )
286+ playSong (spotifyObject , searchQuery )
287+
288+ elif choice == 2 :
289+ values = []
290+ for x in range (3 ):
291+ value = input (f"Enter song { x + 1 } : " )
292+ values .append (value )
293+
294+ recommendSong (spotifyObject , values [0 ],values [1 ],values [2 ])
295+
296+ elif choice == 3 :
297+ playlistUrl = input ("Enter playlist url: " )
298+ generate_similar_playlist (spotifyObject , playlistUrl )
299+
300+ # DEBUG COMMAND
301+ elif choice == 10 :
302+ scope = 'playlist-modify-public playlist-modify-private'
303+ token = util .prompt_for_user_token (username , scope , client_id = clientID , client_secret = clientSecret , redirect_uri = redirectURI )
304+ sp = spotipy .Spotify (auth = token )
305+
306+ generated_name = '' .join (random .choices (string .ascii_letters , k = 10 ))
307+
308+ gen_playlist = sp .user_playlist_create (username , name = generated_name )
309+ gen_playlist_id = gen_playlist ['id' ]
310+
311+ song = input ("Enter song name: " )
312+ results = sp .search (q = song , type = 'track' )
313+
314+ song_uri = results ["tracks" ]["items" ][0 ]["uri" ]
315+
316+ sp .user_playlist_add_tracks (username , gen_playlist_id , [song_uri ])
317+
318+ print (f"Generated playlist - { generated_name } " )
319+
320+
321+
322+ repeat = input ("\n Would you like to try again [yes/no]: " ).lower ()
323+ if repeat in ["y" ,"yes" ]:
324+ clear (3 )
325+
326+ else :
327+ exit ()
328+
329+ main ()
0 commit comments