├── AccessSpotify.png ├── LICENSE ├── README.md ├── SamplePlaylist.txt ├── SpotifyAppAccess.jpg └── textToSpotify.py /AccessSpotify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxyodedara5/TextToSpotify/185f2817e353e169590fef70fa7c49e43a1c6783/AccessSpotify.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 maxyodedara5 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextToSpotify 2 | 3 | Program for creating a Spotify playlist from a text file 4 | 5 | Why ? : Some of the playlists on internet are usually listed out in text format, instead of searching each song manually and creating a playlist. We can use this Program for creating the spotify playlist programmatically 6 | 7 | ## CodeInPlace Final Project 8 | 9 | This project was a submission for CodeInPlace Course a 5-week introductory online Python programming course based on material from the first half of Stanford’s introductory programming course, CS106A. 10 | 11 | The project is also displayed at [CodeInPlace's Public Showcase for projects](https://codeinplace.stanford.edu/2021/showcase/1240) 12 | 13 | For more info about Code in Place you can take a look [here](https://codeinplace.stanford.edu/) 14 | 15 | ## Dependencies 16 | 17 | Following libraries need to be installed 18 | * spotipy 19 | * requests 20 | 21 | ## Dependencies 22 | To get started, install spotipy and create an app on https://developers.spotify.com/. 23 | Add your new ID, SECRETa and redirect URL to textToSpotify.py 24 | 25 | ## Working logic 26 | 27 | Approach : 28 | 29 | * Read file name from user 30 | * Read file and create list of song names and artists 31 | * Get authentication token for Spotify Web API 32 | * Create a header with authentication token for all requests 33 | * Create a playlist in Spotify after taking playlist name and description from user 34 | * Use the list from text file and get IDs/URIs for each song in list if available 35 | * Create a URI string from the list of URIs for the song 36 | * Create a playlist by adding tracks from the file from the URI string 37 | * Provide the created playlist URL to User 38 | 39 | ### Example 40 | 41 | When we run the program, User will be prompted to enter the name of text file 42 | 43 | [SamplePlaylist.txt ](https://raw.githubusercontent.com/maxyodedara5/TextToSpotify/master/SamplePlaylist.txt) 44 | 45 | When filename is provided, a browser window should popup and ask you for authentication which in turn will provide an access token to be used for further requests 46 | 47 | If you haven't logged in to Spotify it will ask User to login and provide access to the application/program for updating playlist 48 | 49 | ![Access Image ](AccessSpotify.png) 50 | 51 | ![Access Image ](SpotifyAppAccess.jpg) 52 | 53 | Then we provide Playlist name and description which will be reflected in Spotify 54 | While making the example I set 55 | * Playlist name : textToSpotify 56 | * Playlist description : Songs we listen on repeat some of my favourites 57 | 58 | After giving the playlist details, program will Search on Spotify for the listed tracks and if found will list them out in your terminal and then add them to your playlist 59 | 60 | Created playlist link [textToSpotify ](https://open.spotify.com/playlist/3jsD7ExjSnCFBlJtSBPLBR) 61 | 62 | Once done will print out a link for your playlist, the playlist should be present in your Spotify account to listen anytime 63 | 64 | ## License 65 | 66 | This project is licensed under the [MIT License](LICENSE). 67 | 68 | ## To do items 69 | 70 | * Update working to have command line args 71 | * Create a standalone python project 72 | * Speed improvements 73 | -------------------------------------------------------------------------------- /SamplePlaylist.txt: -------------------------------------------------------------------------------- 1 | Unknown (To You) Jacob Banks 2 | Hey Soul sister Train 3 | Coldhearted Bryce Fox 4 | AWAY NOIXES 5 | Out of my head John Newman 6 | Being Special Sophia Kennedy 7 | idfc blackbear 8 | Way down we go KALEO 9 | Ghost Au/Ra 10 | Willow Tree Rival -------------------------------------------------------------------------------- /SpotifyAppAccess.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxyodedara5/TextToSpotify/185f2817e353e169590fef70fa7c49e43a1c6783/SpotifyAppAccess.jpg -------------------------------------------------------------------------------- /textToSpotify.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import sys 3 | import spotipy.util as util 4 | import requests 5 | import json 6 | 7 | ''' 8 | TextToSpotify 9 | 10 | Approach : 11 | Read file name from user 12 | Read file and create list of song names and artists 13 | Get authentication token for Spotify Web API 14 | Create a header with authentication token for all requests 15 | Create a playlist in Spotify after taking playlist name and description from user 16 | Use the list from text file and get IDs/URIs for each song in list if available 17 | Create a URI string from the list of URIs for the song 18 | Create a playlist by adding tracks from the file from the URI string 19 | Provide the created playlist URL to User 20 | ''' 21 | 22 | #Gets filename from user 23 | #If user provides text file without .txt extension 24 | #.txt extension is added to the filename 25 | def getFileName(): 26 | filename = input('Enter the text filename (.txt) which contains list of songs: ') 27 | if not(filename.endswith(".txt")): 28 | filename = filename + ".txt" 29 | return filename 30 | 31 | 32 | ''' 33 | #Get track names from the text file 34 | #Format for the text file: File should contains list of all songs on different lines 35 | #PlaylistTextFile.txt sample file with 10 songs provided for reference 36 | #If file is not found then program will stop running and prompt user to try again 37 | ''' 38 | def getTracksfromFile(): 39 | filename = getFileName() 40 | file = pathlib.Path(filename) 41 | tracks = [] 42 | if file.exists (): 43 | with open(filename) as f: 44 | for line in f: 45 | line = line.strip() 46 | tracks.append(line) 47 | return tracks 48 | else: 49 | sys.exit(filename + " file not found, try keeping the file in same directory") 50 | 51 | 52 | ''' 53 | Get access token which will be used for further requests 54 | Access token function will open up the browser and ask the User to 55 | provide access to thier spotify account so that playlists can be added 56 | ''' 57 | def getAccessToken(): 58 | redirect_uri = 'YOUR_REDIRECT_URL_GOES_HERE' 59 | scope = 'user-read-private user-read-email playlist-read-collaborative playlist-modify-public playlist-modify-private' 60 | SPOTIPY_CLIENT_ID = 'YOUR_SPOTIFY_CLIENT_ID_GOES_HERE' 61 | SPOTIPY_CLIENT_SECRET = 'YOUR_SPOTIFY_CLIENT_SECRET_GOES_HERE' 62 | token = util.prompt_for_user_token(scope=scope, 63 | client_id=SPOTIPY_CLIENT_ID, 64 | client_secret=SPOTIPY_CLIENT_SECRET, 65 | redirect_uri=redirect_uri) 66 | 67 | return token 68 | 69 | 70 | ''' 71 | Get header 72 | Access token will be passed so that web api requests are authorized 73 | ''' 74 | def getHeader(access_token): 75 | headers = { 76 | 'Accept': 'application/json', 77 | 'Content-Type': 'application/json', 78 | 'Authorization': 'Bearer {token}'.format(token=access_token), 79 | } 80 | return headers 81 | 82 | ''' 83 | get User ID 84 | Headers passed which have access token so all requests are authorized 85 | We need user ID to create a playlist for that user 86 | ''' 87 | def getUserID(headers): 88 | response = requests.get('https://api.spotify.com/v1/me', headers=headers) 89 | if (response.status_code != 201 and response.status_code != 200): 90 | print("Error with getting User ID") 91 | print("Status code for getting User ID response" + str(response.status_code)) 92 | print(response.text) 93 | sys.exit() 94 | user_profile = response.json() 95 | user_id = user_profile['id'] 96 | #print('User ID' + str(user_id)) 97 | return user_id 98 | 99 | 100 | ''' 101 | Get playlist name from User 102 | User Enters the playlist name which will be used 103 | If nothing is entered default text will be used TextToPlaylist 104 | ''' 105 | def getPlaylistName(): 106 | playListName = input("Enter the name for playlist: ") 107 | if playListName == "": 108 | print("Setting the name of playlist as default, TextToPlaylist") 109 | playListName = "TextToPlaylist" 110 | return playListName 111 | 112 | 113 | ''' 114 | Get playlist description name from User 115 | User Enters the playlist description which will be used 116 | If nothing is entered default description will be used 117 | ''' 118 | def playlistDescription(): 119 | playlist_description = input("Enter description for playlist: ") 120 | if playlist_description == "": 121 | print("Setting the description of playlist as default") 122 | playlist_description = "Playlist created from list of Text provided" 123 | return playlist_description 124 | 125 | ''' 126 | Create playlist 127 | Pass user ID to playlist is created for authenticated user 128 | Returns a playlist ID of created playlist so tracks can be added to 129 | that playlist 130 | ''' 131 | def createPlaylist(user_id, headers): 132 | playlist_name = getPlaylistName() 133 | playlist_description = playlistDescription() 134 | 135 | data = { 136 | "name": playlist_name, 137 | "description": playlist_description 138 | } 139 | 140 | data = json.dumps(data) 141 | 142 | response = requests.post('https://api.spotify.com/v1/users/' + user_id + '/playlists', headers=headers, data=data) 143 | 144 | if response.status_code != 201 and response.status_code != 200: 145 | print("Error with creation of playlist") 146 | print("Status code for playlist creation response" + str(response.status_code)) 147 | print(response.text) 148 | sys.exit() 149 | 150 | playlist_json = response.json() 151 | playlist_id = playlist_json['id'] 152 | return playlist_id 153 | 154 | 155 | ''' 156 | Get track URIs 157 | Search spotify API for all the URIs of tracks and create a list to provide 158 | for creation of playlist 159 | ''' 160 | #Create id list from the list of tracks 161 | def GetURIs(tracks, header): 162 | 163 | SEARCH_BASE_URL = 'https://api.spotify.com/v1/search?' 164 | track_URIs = [] 165 | 166 | print("Tracks being added to playlist") 167 | for track_title in tracks: 168 | if track_title == "": 169 | continue 170 | id_request_url = SEARCH_BASE_URL + 'q=' + track_title + '&type=' + 'track' 171 | id_request = requests.get(id_request_url, headers=header) 172 | json_id = id_request.json() 173 | items = json_id['tracks']['items'] 174 | 175 | if len(items) > 0: 176 | track = items[0] 177 | print(track['name']) 178 | track_URIs.append(track['uri']) 179 | 180 | #print(track_URIs) 181 | return track_URIs 182 | 183 | 184 | ''' 185 | Get URI String 186 | Reformat the URI List so that its comma separated string which 187 | can be passed through for playlist creation function 188 | ''' 189 | def GetURIString(trackURIs): 190 | track_URIs = trackURIs 191 | track_string_for_query = "" 192 | 193 | for uri in track_URIs: 194 | track_string_for_query += uri + "," 195 | 196 | track_string_for_query = track_string_for_query[:-1] 197 | return track_string_for_query 198 | 199 | 200 | ''' 201 | Add tracks to playlist 202 | Playlist ID and track URIs are passed along with headers 203 | Track URIs are list of all URIs of tracks which need to be added 204 | ''' 205 | def addTracksToPlaylist( playlist_id, trackURIString, headers): 206 | response = requests.get('https://api.spotify.com/v1/playlists/' + playlist_id, headers=headers) 207 | playlist_json = response.json() 208 | playlist_id = playlist_json['id'] 209 | #playlist_name = playlist_json['name'] 210 | 211 | params = ( 212 | ('uris', trackURIString ), 213 | ) 214 | response = requests.post('https://api.spotify.com/v1/playlists/'+ str(playlist_id) + '/tracks', headers=headers, params=params) 215 | if response.status_code != 201 and response.status_code != 200: 216 | print("Error with addition of tracks for playlist") 217 | print("Status code for addition of tracks response" + str(response.status_code)) 218 | print(response.text) 219 | sys.exit() 220 | return response.status_code 221 | 222 | 223 | def main(): 224 | tracks = getTracksfromFile() 225 | access_token = getAccessToken() 226 | header = getHeader(access_token) 227 | user_id = getUserID(header) 228 | playlist_id = createPlaylist(user_id, header) 229 | trackURIs = GetURIs(tracks, header) 230 | trackURIString = GetURIString(trackURIs) 231 | status = addTracksToPlaylist( playlist_id, trackURIString, header) 232 | 233 | if (status == 201): 234 | print("Playlist has been created") 235 | playlist_url = 'https://open.spotify.com/playlist/' + playlist_id 236 | print("You can access your playlist at: " + playlist_url) 237 | else: 238 | print("There was an error with addition of tracks in playlist") 239 | 240 | if __name__ == '__main__': 241 | main() 242 | --------------------------------------------------------------------------------