def get_album_tracks(albumUrl: str, output_format: str = None) -> List[SongObj]: """ `str` `albumUrl` : Spotify Url of the album whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the given album """ spotifyClient = SpotifyClient() albumTracks = [] trackResponse = spotifyClient.album_tracks(albumUrl) # while loop acts like do-while while True: for track in trackResponse["items"]: song = songobj_from_spotify_url( "https://open.spotify.com/track/" + track["id"], output_format ) if song is not None and song.get_youtube_link() is not None: albumTracks.append(song) # check if more tracks are to be passed if trackResponse["next"]: trackResponse = spotifyClient.album_tracks( albumUrl, offset=len(albumTracks) ) else: break return albumTracks
def get_playlist_tracks(playlistUrl: str) -> List[SongObj]: ''' `str` `playlistUrl` : Spotify Url of the album whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the given playlist ''' spotifyClient = SpotifyClient() playlistTracks = [] playlistResponse = spotifyClient.playlist_tracks(playlistUrl) # while loop to mimic do-while while True: for songEntry in playlistResponse['items']: if songEntry['track'] is None or songEntry['track']['id'] is None: continue song = SongObj.from_url('https://open.spotify.com/track/' + songEntry['track']['id']) if song.get_youtube_link() is not None: playlistTracks.append(song) # check if more tracks are to be passed if playlistResponse['next']: playlistResponse = spotifyClient.playlist_tracks( playlistUrl, offset=playlistResponse['offset'] + playlistResponse['limit']) else: break return playlistTracks
def get_album_tracks(albumUrl: str) -> List[SongObj]: ''' `str` `albumUrl` : Spotify Url of the album whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the given album ''' spotifyClient = SpotifyClient() albumTracks = [] trackResponse = spotifyClient.album_tracks(albumUrl) # while loop acts like do-while while True: for track in trackResponse['items']: song = SongObj.from_url('https://open.spotify.com/track/' + track['id']) if song.get_youtube_link() is not None: albumTracks.append(song) # check if more tracks are to be passed if trackResponse['next']: trackResponse = spotifyClient.album_tracks(albumUrl, offset=len(albumTracks)) else: break return albumTracks
def search_for_song(query: str) -> SongObj: ''' `str` `query` : what you'd type into spotify's search box Queries Spotify for a song and returns the best match ''' # get a spotify client spotifyClient = SpotifyClient() # get possible matches from spotify result = spotifyClient.search(query, type='track') # return first result link or if no matches are found, raise and Exception if len(result['tracks']['items']) == 0: raise Exception('No song matches found on Spotify') else: for songResult in result['tracks']['items']: songUrl = 'http://open.spotify.com/track/' + songResult['id'] song = SongObj.from_url(songUrl) if song.get_youtube_link() is not None: return song raise Exception('Could not match any of the results on YouTube')
def get_saved_tracks(output_format: str = None) -> List[SongObj]: """ returns a `list<songObj>` containing Url's of each track in the user's saved tracks """ spotifyClient = SpotifyClient() savedTracks = [] savedTracksResponse = spotifyClient.current_user_saved_tracks() while True: for songEntry in savedTracksResponse["items"]: if songEntry["track"] is None or songEntry["track"]["id"] is None: continue song = songobj_from_spotify_url( "https://open.spotify.com/track/" + songEntry["track"]["id"], output_format, ) if song is not None and song.get_youtube_link() is not None: savedTracks.append(song) # check if more tracks are to be passed if savedTracksResponse["next"]: savedTracksResponse = spotifyClient.current_user_saved_tracks( offset=savedTracksResponse["offset"] + savedTracksResponse["limit"] ) else: break return savedTracks
def console_entry_point(): ''' This is where all the console processing magic happens. Its super simple, rudimentary even but, it's dead simple & it works. ''' arguments = parse_arguments() SpotifyClient.init(client_id='4fe3fecfe5334023a1472516cc99d805', client_secret='0f02b7c483c04257984695007a4a8d5c') if arguments.path: if not os.path.isdir(arguments.path): sys.exit("The output directory doesn't exist.") print(f"Will download to: {os.path.abspath(arguments.path)}") os.chdir(arguments.path) with DownloadManager() as downloader: for request in arguments.url: if 'open.spotify.com' in request and 'track' in request: print('Fetching Song...') song = SongObj.from_url(request) if song.get_youtube_link() is not None: downloader.download_single_song(song) else: print( 'Skipping %s (%s) as no match could be found on youtube' % (song.get_song_name(), request)) elif 'open.spotify.com' in request and 'album' in request: print('Fetching Album...') songObjList = get_album_tracks(request) downloader.download_multiple_songs(songObjList) elif 'open.spotify.com' in request and 'playlist' in request: print('Fetching Playlist...') songObjList = get_playlist_tracks(request) downloader.download_multiple_songs(songObjList) elif 'open.spotify.com' in request and 'artist' in request: print('Fetching artist...') artistObjList = get_artist_tracks(request) downloader.download_multiple_songs(artistObjList) elif request.endswith('.spotdlTrackingFile'): print('Preparing to resume download...') downloader.resume_download_from_tracking_file(request) else: print('Searching for song "%s"...' % request) try: song = search_for_song(request) downloader.download_single_song(song) except Exception as e: print(e)
def console_entry_point(): """ This is where all the console processing magic happens. Its super simple, rudimentary even but, it's dead simple & it works. """ arguments = parse_arguments() args_dict = vars(arguments) if (ffmpeg.has_correct_version(arguments.ignore_ffmpeg_version, arguments.ffmpeg or "ffmpeg") is False): sys.exit(1) for request in arguments.query: if "saved" == request and not arguments.userAuth: arguments.userAuth = True print( "Detected 'saved' in command line, but no --user-auth flag. Enabling Anyways." ) print("Please Log In...") SpotifyClient.init( client_id="5f573c9620494bae87890c0f08a60293", client_secret="212476d9b0f3472eaa762d90b19b0ba8", user_auth=arguments.userAuth, ) if arguments.path: if not os.path.isdir(arguments.path): sys.exit("The output directory doesn't exist.") print(f"Will download to: {os.path.abspath(arguments.path)}") os.chdir(arguments.path) with DownloadManager(args_dict) as downloader: if not arguments.debug_termination: def gracefulExit(signal, frame): downloader.displayManager.close() sys.exit(0) signal.signal(signal.SIGINT, gracefulExit) signal.signal(signal.SIGTERM, gracefulExit) songObjList = [] for request in arguments.query: if request.endswith(".spotdlTrackingFile"): print("Preparing to resume download...") downloader.resume_download_from_tracking_file(request) else: songObjList.extend( songGatherer.from_query(request, arguments.format)) # linefeed to visually separate output for each query print() if len(songObjList) > 0: downloader.download_multiple_songs(songObjList)
def from_url(spotifyURL: str): if not ("open.spotify.com" in spotifyURL and "track" in spotifyURL): raise Exception("passed URL is not that of a track: %s" % spotifyURL) # query spotify for song, artist, album details spotifyClient = SpotifyClient() rawTrackMeta = spotifyClient.track(spotifyURL) primaryArtistId = rawTrackMeta["artists"][0]["id"] rawArtistMeta = spotifyClient.artist(primaryArtistId) albumId = rawTrackMeta["album"]["id"] rawAlbumMeta = spotifyClient.album(albumId) return rawTrackMeta, rawArtistMeta, rawAlbumMeta
def console_entry_point(): ''' This is where all the console processing magic happens. Its super simple, rudimentary even but, it's dead simple & it works. ''' arguments = parse_arguments() if ffmpeg.has_correct_version(arguments.ignore_ffmpeg_version, arguments.ffmpeg or "ffmpeg") is False: sys.exit(1) SpotifyClient.init(client_id='5f573c9620494bae87890c0f08a60293', client_secret='212476d9b0f3472eaa762d90b19b0ba8') if arguments.path: if not os.path.isdir(arguments.path): sys.exit("The output directory doesn't exist.") print(f"Will download to: {os.path.abspath(arguments.path)}") os.chdir(arguments.path) with DownloadManager(arguments.ffmpeg) as downloader: if not arguments.debug_termination: def gracefulExit(signal, frame): downloader.displayManager.close() sys.exit(0) signal.signal(signal.SIGINT, gracefulExit) signal.signal(signal.SIGTERM, gracefulExit) for request in arguments.url: if os.path.isfile(request): print('Processing file ...') try: with open(request) as input: for line in input.readlines(): process_request(downloader, line) except Exception as e: print(e) else: process_request(downloader, request)
def from_url(cls, spotifyURL: str): # check if URL is a playlist, user, artist or album, if yes raise an Exception, # else procede if not ('open.spotify.com' in spotifyURL and 'track' in spotifyURL): raise Exception('passed URL is not that of a track: %s' % spotifyURL) # query spotify for song, artist, album details spotifyClient = SpotifyClient() rawTrackMeta = spotifyClient.track(spotifyURL) primaryArtistId = rawTrackMeta['artists'][0]['id'] rawArtistMeta = spotifyClient.artist(primaryArtistId) albumId = rawTrackMeta['album']['id'] rawAlbumMeta = spotifyClient.album(albumId) # get best match from the given provider songName = rawTrackMeta['name'] albumName = rawTrackMeta['album']['name'] duration = round(rawTrackMeta['duration_ms'] / 1000, ndigits=3) contributingArtists = [] for artist in rawTrackMeta['artists']: contributingArtists.append(artist['name']) youtubeLink = SongObj.searchProvider(songName, contributingArtists, albumName, duration) # try to get lyrics from Genius try: lyrics = get_song_lyrics(songName, contributingArtists) except (AttributeError, IndexError): lyrics = "" return cls(rawTrackMeta, rawAlbumMeta, rawArtistMeta, youtubeLink, lyrics)
def get_artist_tracks(artistUrl: str) -> List[SongObj]: ''' `str` `albumUrl` : Spotify Url of the artist whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the artist profile ''' spotifyClient = SpotifyClient() artistTracks = [] offset = 0 artistResponse = spotifyClient.artist_albums(artistUrl) # while loop acts like do-while while True: for album in artistResponse['items']: # get albums and singles if not (album['album_group'] == 'appears_on' and album['album_type'] in ['album', 'compilation']): artistTracks.extend(get_album_tracks(album['id'])) # get features from other artists albums elif album['album_group'] == 'appears_on' and album[ 'album_type'] == 'album': trackResponse = spotifyClient.album_tracks(album['uri']) albumTracks = [] # while loop acts like do-while while True: for track in trackResponse['items']: for artist in track['artists']: if artist['id'] == artistResponse['href'].split( '/')[-2]: song = SongObj.from_url( 'https://open.spotify.com/track/' + track['id']) if song.get_youtube_link() is not None: albumTracks.append(song) # check if more tracks are to be passed if trackResponse['next']: trackResponse = spotifyClient.album_tracks( album['uri'], offset=len(albumTracks)) else: break artistTracks.extend(albumTracks) offset += len(artistResponse['items']) # check if more albums are to be passed if artistResponse['next']: artistResponse = spotifyClient.artist_albums(artistUrl, offset=offset) else: break return artistTracks
def from_search_term(query: str, output_format: str = None) -> List[SongObj]: """ `str` `query` : what you'd type into Spotify's search box Queries Spotify for a song and returns the best match """ # get a spotify client spotifyClient = SpotifyClient() tracks = [] # get possible matches from spotify result = spotifyClient.search(query, type="track") # return first result link or if no matches are found, raise and Exception if len(result["tracks"]["items"]) == 0: raise Exception("No song matches found on Spotify") else: songUrl = "http://open.spotify.com/track/" + result["tracks"]["items"][0]["id"] song = songobj_from_spotify_url(songUrl, output_format) tracks.append(song) return tracks
def get_playlist_tracks(playlistUrl: str, output_format: str = None) -> List[SongObj]: """ `str` `playlistUrl` : Spotify Url of the album whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the given playlist """ spotifyClient = SpotifyClient() playlistTracks = [] playlistResponse = spotifyClient.playlist_tracks(playlistUrl) # while loop to mimic do-while while True: for songEntry in playlistResponse["items"]: if songEntry["track"] is None or songEntry["track"]["id"] is None: continue song = songobj_from_spotify_url( "https://open.spotify.com/track/" + songEntry["track"]["id"], output_format, ) if song is not None and song.get_youtube_link() is not None: playlistTracks.append(song) # check if more tracks are to be passed if playlistResponse["next"]: playlistResponse = spotifyClient.playlist_tracks( playlistUrl, offset=playlistResponse["offset"] + playlistResponse["limit"], ) else: break return playlistTracks
def console_entry_point(): ''' This is where all the console processing magic happens. Its super simple, rudimentary even but, it's dead simple & it works. ''' arguments = parse_arguments() if ffmpeg.has_correct_version(arguments.ignore_ffmpeg_version) is False: sys.exit(1) SpotifyClient.init(client_id='5f573c9620494bae87890c0f08a60293', client_secret='212476d9b0f3472eaa762d90b19b0ba8') if arguments.path: if not os.path.isdir(arguments.path): sys.exit("The output directory doesn't exist.") print(f"Will download to: {os.path.abspath(arguments.path)}") os.chdir(arguments.path) with DownloadManager() as downloader: for request in arguments.url: if 'open.spotify.com' in request and 'track' in request: print('Fetching Song...') song = SongObj.from_url(request) if song.get_youtube_link() is not None: downloader.download_single_song(song) else: print( 'Skipping %s (%s) as no match could be found on youtube' % (song.get_song_name(), request)) elif 'open.spotify.com' in request and 'album' in request: print('Fetching Album...') songObjList = get_album_tracks(request) downloader.download_multiple_songs(songObjList) elif 'open.spotify.com' in request and 'playlist' in request: print('Fetching Playlist...') songObjList = get_playlist_tracks(request) downloader.download_multiple_songs(songObjList) elif 'open.spotify.com' in request and 'artist' in request: print('Fetching artist...') artistObjList = get_artist_tracks(request) downloader.download_multiple_songs(artistObjList) elif request.endswith('.spotdlTrackingFile'): print('Preparing to resume download...') downloader.resume_download_from_tracking_file(request) else: print('Searching for song "%s"...' % request) try: song = search_for_song(request) downloader.download_single_song(song) except Exception as e: print(e)
def init_spotdl(loc: str) -> None: os.chdir(loc.strip("\\").strip("/")) SpotifyClient.init(user_auth=False, **get_client_secrets())
def new_initialize(client_id, client_secret): """This function allows calling `initialize()` multiple times""" try: return SpotifyClient() except: return ORIGINAL_INITIALIZE(client_id, client_secret)
def get_artist_tracks(artistUrl: str, output_format: str = None) -> List[SongObj]: """ `str` `albumUrl` : Spotify Url of the artist whose tracks are to be retrieved returns a `list<songObj>` containing Url's of each track in the artist profile """ spotifyClient = SpotifyClient() albums = [] albumTracks: Dict[str, SongObj] = {} offset = 0 artistResponse = spotifyClient.artist_albums(artistUrl) # loop until we get all tracks from all albums/playlists while True: for album in artistResponse["items"]: # return an iterable containing the string's alphanumeric characters alphaNumericFilter = filter(str.isalnum, album["name"].lower()) # join all characters into one string albumName = "".join(alphaNumericFilter) # check if we've already downloaded album with this name if not (albumName in albums) and not ( # exclude compilation playlists album["album_group"] == "appears_on" and album["album_type"] in ["compilation"] ): trackResponse = spotifyClient.album_tracks(album["uri"]) # loop until we get all tracks from playlist while True: for track in trackResponse["items"]: # return an iterable containing the string's alphanumeric characters alphaNumericFilter = filter(str.isalnum, track["name"].lower()) # join all characters into one string trackName = "".join(alphaNumericFilter) # check if we've alredy downloaded this track if albumTracks.get(trackName) is None: for artist in track["artists"]: # get artist id from url # https://api.spotify.com/v1/artists/1fZAAHNWdSM5gqbi9o5iEA/albums # split string # ['https:', '', 'api.spotify.com', # 'v1', 'artists', '1fZAAHNWdSM5gqbi9o5iEA', 'albums'] # get second element from the end # '1fZAAHNWdSM5gqbi9o5iEA' artistId = artistResponse["href"].split("/")[-2] # ignore tracks that are not from our artist by checking # the id if artist["id"] == artistId: song = songobj_from_spotify_url( "https://open.spotify.com/track/" + track["id"], output_format, ) if ( song is not None and song.get_youtube_link() is not None ): albumTracks[trackName] = song # check if more tracks are to be passed if trackResponse["next"]: trackResponse = spotifyClient.album_tracks( album["uri"], offset=len(albumTracks) ) else: break albums.append(albumName) offset += len(artistResponse["items"]) # check if more albums are to be passed if artistResponse["next"]: artistResponse = spotifyClient.artist_albums(artistUrl, offset=offset) else: break return list(albumTracks.values())