spotipy-dev / spotipy

A light weight Python library for the Spotify Web API
http://spotipy.readthedocs.org
MIT License
5.03k stars 957 forks source link

Is it possible to create a playlist of every song an artist ID has and appears on (including appears on section)? #702

Closed greeneryAO closed 3 years ago

greeneryAO commented 3 years ago

Several apps that claim to do this, like for example alfred spotify mini player that says creates complete collection misses many songs, mostly the appears on sections, which it cannot penetrate, but that is where artists frequently appear on remixes etc.

searching in spotify and sorting by songs is messy too, and often includes junk and songs not by that artist as it runs out of songs by the artist.

Is there a way to run a script that will return a list of all songs if I put in the artist name (ID?), regardless of dupes, just a total list, this would be helpful for grass cutting for updates every few weeks or so, as the big apps that update new releases are annoying and sporadic. I want to do it when I want to do it.

Would it be easy or hard, as you can probably tell I'm not a coder but have some money left on freelancer I'd rather spend than try to claw back.

I think this is the relevant section.

playlist_add_items(playlist_id, items, position=None) Adds tracks/episodes to a playlist

Parameters: playlist_id - the id of the playlist items - a list of track/episode URIs, URLs or IDs position - the position to add the tracks

thanks.

kenmacf commented 3 years ago

I've done something like this, assuming authentication is in place:

spotify_post = spotipy.Spotify(auth=token)

album_track_ids = []
albums = session.spotify_artist_albums(artist_id)
for album in albums:
    if 'US' not in album['available_markets']:
        continue
    for track in session.spotify_album_tracks(album['id']):
        track_artists = [x['uri'] for x in track['artists']]
        if 'spotify:artist:' + artist_id in track_artists:
            album_track_ids.append(track['id'])

playlist_title = 'New Playlist {:%Y-%m-%d %H:%M}'.format(datetime.datetime.today())
new_playlist = spotify_post.user_playlist_create(spotify_userid, playlist_title, public=False)
if spotify_post.playlist_add_items(new_playlist['id'], album_track_ids):
    print(new_playlist['id'])
greeneryAO commented 3 years ago

thanks very much, I don't know what to make of the code but I'm glad I have it and I have saved it, and it's possible. I will try and learn it on my own, worst case I pay somebody on freelancer who understands python and spotipy

My guy who has helped me before just quit working there, don't want to bug him again, but somebody else could figure it out what I have to put in and where.

I have several python scripts that use authorization and spotipy and work well so I think that's good.

greeneryAO commented 3 years ago

I've done something like this, assuming authentication is in place:

spotify_post = spotipy.Spotify(auth=token)

album_track_ids = []
albums = session.spotify_artist_albums(artist_id)
for album in albums:
    if 'US' not in album['available_markets']:
        continue
    for track in session.spotify_album_tracks(album['id']):
        track_artists = [x['uri'] for x in track['artists']]
        if 'spotify:artist:' + artist_id in track_artists:
            album_track_ids.append(track['id'])

playlist_title = 'New Playlist {:%Y-%m-%d %H:%M}'.format(datetime.datetime.today())
new_playlist = spotify_post.user_playlist_create(spotify_userid, playlist_title, public=False)
if spotify_post.playlist_add_items(new_playlist['id'], album_track_ids):
    print(new_playlist['id'])

well I looked at it, sorry for not understanding a thing about python but where do you put the artist ID to run the script and generate the playlist?.

I assume I have to add the credentials and the redirect and that on top of the script like is required for spotipy and like is on all my other scripts, but on those scripts there would always be somewhere he would tell me to insert information.

if you could explain I would appreciate, if not , it's cool, I appreciate you even sharing.

Peter-Schorn commented 3 years ago

You must define a variable called artist_id with the artist id.

greeneryAO commented 3 years ago

would this work?

from pprint import pprint
import spotipy
from spotipy.oauth2 import SpotifyOAuth
from anybar import AnyBar
import threading
# START Custom Credentials
SPOTIPY_CLIENT_ID = 'my private'
SPOTIPY_CLIENT_SECRET = 'my private'
SPOTIFY_USERNAME = 'my private'
# The cache file absolute path
SPOTIFY_CACHE = 'my private'
artist_id = 'I put in here???'

# END Custom Credentials

SPOTIPY_REDIRECT_URI = 'http://127.0.0.1:9090'

sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope, client_id=SPOTIPY_CLIENT_ID,
                                               username=SPOTIFY_USERNAME,
                                               client_secret=SPOTIPY_CLIENT_SECRET, redirect_uri=SPOTIPY_REDIRECT_URI, cache_path=SPOTIFY_CACHE))
album_track_ids = []
albums = session.spotify_artist_albums(artist_id)
for album in albums:
    if 'US' not in album['available_markets']:
        continue
    for track in session.spotify_album_tracks(album['id']):
        track_artists = [x['uri'] for x in track['artists']]
        if 'spotify:artist:' + artist_id in track_artists:
            album_track_ids.append(track['id'])

playlist_title = 'New Playlist {:%Y-%m-%d %H:%M}'.format(datetime.datetime.today())
new_playlist = spotify_post.user_playlist_create(spotify_userid, playlist_title, public=False)
if spotify_post.playlist_add_items(new_playlist['id'], album_track_ids):
    print(new_playlist['id'])
stephanebruckert commented 3 years ago

@greeneryAO why don't you just run it to know if it would work? it's not that hard, just google how to run a python script and start from there

greeneryAO commented 3 years ago

I know how to run them, just not to fix them, tried it, error message was

Traceback (most recent call last): File "spotify playlist maker.py", line 23, in albums = session.spotify_artist_albums(artist_id) NameError: name 'session' is not defined

greeneryAO commented 3 years ago

If I change it around, either the token is not defined, or the session is not defined, or the scope is note defined, must have did something wrong.

stephanebruckert commented 3 years ago

Yeah session is not defined, as the error message says. @kenmacf's code aims to show the logic but as mentioned it's not including the authentication part. So you will have to adapt it a little.

Since you don't need to add songs to any user playlist, you won't need user authentication, which will be easy for you.

My suggestion is you follow these steps:

  1. Have a look at the Quick Start / Without user authentication example on the README
  2. Run it. If it works, you've already fixed the "session" problem and you can work on the fun stuff 👍
  3. You can now adapt that code to search for artist albums. Instead of sp.search(), you can do sp.artist_albums
  4. Print the result to see what you get
  5. Once you got the albums, get the album tracks with sp.album_tracks

Good luck, and remember to always start from something that works

greeneryAO commented 3 years ago

thanks, I'll give it a try, what about this code, I found it just in the newest changes to spotipy, maybe it's the same thing.

artist_discography.py

import argparse
import logging

from spotipy.oauth2 import SpotifyClientCredentials
import spotipy
logger = logging.getLogger('examples.artist_discography')
logging.basicConfig(level='INFO')
def get_args():
    parser = argparse.ArgumentParser(description='Shows albums and tracks for '
                                     'given artist')
    parser.add_argument('-a', '--artist', required=True,
                        help='Name of Artist')
    return parser.parse_args()
def get_artist(name):
    results = sp.search(q='artist:' + name, type='artist')
    items = results['artists']['items']
    if len(items) > 0:
        return items[0]

I ran it and it said it succeeded but nothing happened

stephanebruckert commented 3 years ago

https://github.com/plamere/spotipy/blob/master/examples/artist_discography.py

You skipped the main() function therefore nothing ran. Just run the full thing. Starting with examples is a very good approach

greeneryAO commented 3 years ago

ran it by itself and error was

spotipy.oauth2.SpotifyOauthError: No client_id. Pass it or set a SPOTIPY_CLIENT_ID environment variable.

ran it with credentials and same error?

#Shows the list of all songs sung by the artist or the band
import argparse
import logging

from spotipy.oauth2 import SpotifyClientCredentials
import spotipy

# START Custom Credentials
SPOTIPY_CLIENT_ID = ''
SPOTIPY_CLIENT_SECRET = ''
SPOTIFY_USERNAME = ''
# The cache file absolute path
SPOTIFY_CACHE = ''

# END Custom Credentials

logger = logging.getLogger('examples.artist_discography')
logging.basicConfig(level='INFO')

def get_args():
    parser = argparse.ArgumentParser(description='Shows albums and tracks for '
                                     'given artist')
    parser.add_argument('-a', '--artist', required=True,
                        help='Name of Artist')
    return parser.parse_args()

def get_artist(name):
    results = sp.search(q='artist:' + name, type='artist')
    items = results['artists']['items']
    if len(items) > 0:
        return items[0]
    else:
        return None

def show_album_tracks(album):
    tracks = []
    results = sp.album_tracks(album['id'])
    tracks.extend(results['items'])
    while results['next']:
        results = sp.next(results)
        tracks.extend(results['items'])
    for i, track in enumerate(tracks):
        logger.info('%s. %s', i+1, track['name'])

def show_artist_albums(artist):
    albums = []
    results = sp.artist_albums(artist['id'], album_type='album')
    albums.extend(results['items'])
    while results['next']:
        results = sp.next(results)
        albums.extend(results['items'])
    logger.info('Total albums: %s', len(albums))
    unique = set()  # skip duplicate albums
    for album in albums:
        name = album['name'].lower()
        if name not in unique:
            logger.info('ALBUM: %s', name)
            unique.add(name)
            show_album_tracks(album)

def show_artist(artist):
    logger.info('====%s====', artist['name'])
    logger.info('Popularity: %s', artist['popularity'])
    if len(artist['genres']) > 0:
        logger.info('Genres: %s', ','.join(artist['genres']))

def main():
    args = get_args()
    artist = get_artist(args.artist)
    show_artist(artist)
    show_artist_albums(artist)

if __name__ == '__main__':
    client_credentials_manager = SpotifyClientCredentials()
    sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
    main()
stephanebruckert commented 3 years ago

No you didn't pass the credentials. See the difference between your code:

    client_credentials_manager = SpotifyClientCredentials()
    sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

and the code in the README:

sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id="YOUR_APP_CLIENT_ID",
                                                           client_secret="YOUR_APP_CLIENT_SECRET"))
greeneryAO commented 3 years ago
    client_credentials_manager = SpotifyClientCredentials()
    sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

is in the example, I'll try to make the credentials like the readme

greeneryAO commented 3 years ago

Tried a bunch of things, putting in my app credentials authorized or not, wouldn't work, same errors.

spotipy.oauth2.SpotifyOauthError: No client_id. Pass it or set a SPOTIPY_CLIENT_ID environment variable.

I know I seem like a dolt to people who know python but not going to start learning python and spotipy for this last script I need for my spotify setup, I guess I'll take both scripts to market and get the dummy version handed to me and see if either can do what I imagined.

thanks anyway.