예제 #1
0
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
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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')
예제 #5
0
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
예제 #6
0
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)
예제 #7
0
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
예제 #9
0
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)
예제 #10
0
    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)
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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
예제 #14
0
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)
예제 #15
0
def init_spotdl(loc: str) -> None:
    os.chdir(loc.strip("\\").strip("/"))
    SpotifyClient.init(user_auth=False, **get_client_secrets())
예제 #16
0
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)
예제 #17
0
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())