I'm trying to create a Python program to create Spotify playlists according to the user's "mood"; that is, the user chooses a specific mood and the program returns a playlist where the song's (taken from the user's saved tracks) features indicate that they match said mood. However, I'm running into the issue that the playlist is made up of the same song repeated 30 times, instead of 30 different songs. I'm fairly new to Python and programming in general, so maybe this isn't a very difficult problem, but I'm trying to see the issue and I am unable to.
Here is the route in my main code that refers to this issue (my full program has more routes, which all work fine so far). All other moods will be defined by other routes, but following the same logic. Any extra code that may be necessary in order to understand the issue better, I'll provide.
#app.route("/playlist_mood_angry")
def mood_playlist_angry():
# define mood and create empty track list
selected_mood = "Angry"
tracks_uris = [] # we need all the tracks uri to add to the future playlist
if 'auth_header' in session:
auth_header = session['auth_header']
# get user profile and saved tracks
user_profile_data = spotify.get_users_profile(auth_header)
user_id = user_profile_data["id"]
saved_tracks_data = spotify.get_user_saved_tracks(auth_header)
playlist_name = 'CSMoodlet: Angry'
playlist_description = "A playlist for when you're just pissed off and want a soundtrack to go with it. Automatically curated by CSMoodlet."
# go through saved tracks dictionary, get the tracks and for each one check if features average matches selected mood
for item in saved_tracks_data["items"]:
track = item["track"]
features = sp.audio_features(track['id'])
acousticness = features[0]['acousticness']
danceability = features[0]['danceability']
energy = features[0]['energy']
speechiness = features[0]['speechiness']
valence = features[0]['valence']
track_mood = spotify.define_mood(acousticness, danceability, energy, speechiness, valence)
# if the track's mood is "angry", if the list is not 30 tracks long yet, append it to the list
if track_mood == "Angry": #if track's mood is not Angry, it will go back to the for loop to check the next one (THIS DOESN'T WORK)
while len(tracks_uris) < 30:
track_uri = "spotify:track:{}".format(track['id'])
tracks_uris.append(track_uri)
# once it has gone through all saved tracks, create the playlist and add the tracks
new_playlist = spotify.create_playlist(auth_header, user_id, playlist_name, playlist_description)
new_playlist_id = new_playlist['id']
added_playlist = spotify.add_tracks_to_playlist(auth_header, new_playlist_id, tracks_uris)
playlist = spotify.get_playlist(auth_header, new_playlist_id)
tracks_data = []
for item in playlist["items"]:
track_data = item["track"]
tracks_data.append(track_data)
return render_template("created_playlist.html", selected_mood = selected_mood, playlist_tracks=tracks_data)
Any help would be deeply appreciated. Apologies if anything is badly explained, I am new to Stackoverflow and English is not my first language.
Found the error!
For anyone having issues with the same problem, I found that it was actually very simple. just substitute the while loop by an if loop, when checking the length of the playlist is less than 30.
Related
Beginner here. I am working on a Reddit API (PRAW) project in which I am attempting to aggregate data from multiple subreddits.
In order to achieve this now, I am writing a line for each subreddit in which I want to query and it works, but I would really like to write a piece of code that takes in a list of subreddit names and performs the call for each item in the list instead of me having to add lines of code.
The list of subreddits would eventually be user-defined and read in from a google sheet or similar entry point.
My code now
#Authenticate for Reddit
r = praw.Reddit(client_id='id',
client_secret='secret',
user_agent='agent')
#call new posts from multiple subreddits with no limit
posts = [] #empty container for df
toyota = r.subreddit('Toyota').new(limit=None)
tundra = r.subreddit('ToyotaTundra').new(limit=None)
tacoma = r.subreddit('ToyotaTacoma').new(limit=None)
prius = r.subreddit('Prius').new(limit=None)
runner= r.subreddit('4Runner').new(limit=None)
highlander = r.subreddit('ToyotaHighlander').new(limit=None)
#compile into list
lists = list(itertools.chain(toyota,tundra,tacoma,prius,runner,highlander))
Maybe you are looking for a simple input loop:
x = int(input()) #user inputs how many submissions he plans to do
posts = []
for y in range (0,x):
a = input()
subposts = r.subreddit(a).new(limit=None)
posts.append(subposts)
You may deal with the data the way you prefer, but the general idea is that you can put the info you get from each subreddit everytime the loop runs.
I'd like to retrieve the follower count of my Spotify playlist using Python. I've been searching https://developer.spotify.com/documentation/web-api/reference-beta/#category-playlists but haven't found a way to do so yet. However, I found a working code on how to retrieve the track IDs of a playlist, how could I tweak it to get the followers instead?
def getTrackIDs(user, playlist_id):
ids = []
playlist = sp.user_playlist(user, playlist_id)
for item in playlist['tracks']['items']:
track = item['track']
ids.append(track['id'])
return ids
ids = getTrackIDs('User', 'Playlist_Id')
print(len(ids))
print(ids)
Take a look at the playlist object that should be returned by getting a playlist.
https://developer.spotify.com/documentation/web-api/reference/object-model/#playlist-object-full.
It has the followers property which is a followers object which is located here
https://developer.spotify.com/documentation/web-api/reference/object-model/#followers-object.
The followers object contains the total property, which should be what you are looking for.
Although I cannot run your code, I imagine the result should look like the following. Let me know if this works for you (I can't run the code).
def getPlaylistFollowerCount(user, playlist_id):
playlist = sp.user_playlist(user, playlist_id)
return playlist['followers']['total']
On the Soundcloud API guide (https://developers.soundcloud.com/docs/api/guide#pagination)
the example given for reading more than 100 piece of data is as follows:
# get first 100 tracks
tracks = client.get('/tracks', order='created_at', limit=page_size)
for track in tracks:
print track.title
# start paging through results, 100 at a time
tracks = client.get('/tracks', order='created_at', limit=page_size,
linked_partitioning=1)
for track in tracks:
print track.title
I'm pretty certain this is wrong as I found that 'tracks.collection' needs referencing rather than just 'tracks'. Based on the GitHub python soundcloud API wiki it should look more like this:
tracks = client.get('/tracks', order='created_at',limit=10,linked_partitioning=1)
while tracks.collection != None:
for track in tracks.collection:
print(track.playback_count)
tracks = tracks.GetNextPartition()
Where I have removed the indent from the last line (I think there is an error on the wiki it is within the for loop which makes no sense to me). This works for the first loop. However, this doesn't work for successive pages because the "GetNextPartition()" function is not found. I've tried the last line as:
tracks = tracks.collection.GetNextPartition()
...but no success.
Maybe I'm getting versions mixed up? But I'm trying to run this with Python 3.4 after downloading the version from here: https://github.com/soundcloud/soundcloud-python
Any help much appreciated!
For anyone that cares, I found this solution on the SoundCloud developer forum. It is slightly modified from the original case (searching for tracks) to list my own followers. The trick is to call the client.get function repeatedly, passing the previously returned "users.next_href" as the request that points to the next page of results. Hooray!
pgsize=200
c=1
me = client.get('/me')
#first call to get a page of followers
users = client.get('/users/%d/followers' % me.id, limit=pgsize, order='id',
linked_partitioning=1)
for user in users.collection:
print(c,user.username)
c=c+1
#linked_partitioning means .next_href exists
while users.next_href != None:
#pass the contents of users.next_href that contains 'cursor=' to
#locate next page of results
users = client.get(users.next_href, limit=pgsize, order='id',
linked_partitioning=1)
for user in users.collection:
print(c,user.username)
c=c+1
I am using soundcloud api through python SDK.
When I get the tracks data through 'Search',
the track attribute 'playback_count' seems to be
smaller than the actual count seen on the web.
How can I avoid this problem and get the actual playback_count??
(ex.
this track's playback_count gives me 2700,
but its actually 15k when displayed on the web
https://soundcloud.com/drumandbassarena/ltj-bukem-soundcrash-mix-march-2016
)
note: this problem does not occur for comments or likes.
following is my code
##Search##
tracks = client.get('/tracks', q=querytext, created_at={'from':startdate},duration={'from':startdur},limit=200)
outputlist = []
trackinfo = {}
resultnum = 0
for t in tracks:
trackinfo = {}
resultnum += 1
trackinfo["id"] = resultnum
trackinfo["title"] =t.title
trackinfo["username"]= t.user["username"]
trackinfo["created_at"]= t.created_at[:-5]
trackinfo["genre"] = t.genre
trackinfo["plays"] = t.playback_count
trackinfo["comments"] = t.comment_count
trackinfo["likes"] =t.likes_count
trackinfo["url"] = t.permalink_url
outputlist.append(trackinfo)
There is an issue with the playback count being incorrect when reported via the API.
I have encountered this when getting data via the /me endpoint for activity and likes to mention a couple.
The first image shows the information returned when accessing the sound returned for the currently playing track in the soundcloud widget
Information returned via the api for the me/activities endpoint
Looking at the SoundCloud website, they actually call a second version of the API to populate the track list on the user page. It's similar to the documented version, but not quite the same.
If you issue a request to https://api-v2.soundcloud.com/stream/users/[userid]?limit=20&client_id=[clientid] then you'll get back a JSON object showing the same numbers you see on the web.
Since this is an undocumented version, I'm sure it'll change the next time they update their website.
Consider the following:
I'm making a secret santa script for my family for next year using python, and although I have figured out how to draw names (see code below), I need to execute it just once. I'm planning to use the flask framework to create a page counts down the days until the draw (which I've figured out as well), but how do i make it so it does the draw, just once, and not everytime somebody logs on to that page? Get what I mean?
Anyway, I'll show you my code here:
# imports & initial Flask set up above
def do_matchup(names, draw, matches=None):
if matches is None:
matches = []
while names:
member = names.pop()
recipient = choice(draw)
if recipient != member:
matches.append("%s=%s" % (member, recipient))
draw.remove(recipient)
else:
names.append(member)
return matches
#app.route("/")
def index():
now = dt.datetime.now()
draw_date = dt.datetime.strptime('10/1/2013', '%m/%d/%Y')
days = draw_date - now
family = ["member1", "member2", "member3", "member4", "member5", "Me"]
hat_names = [name for name in family]
matchup = do_matchup(family, hat_names)
return render_template("base.html", now=now,
draw_date=draw_date,
days=days,
matchup=matchup)
The template is a basic html page that says {% if now < draw_date %} "There are x-amount of days until the draw", {% else %} "Show the draw results".
Every time the page is loaded, it does a new draw. How do I make it so it just does the draw once and not give every family member different results?
You need to have a separate way of running the shuffle - e.g. by visiting a particular page. That code should also save the shuffle to the database. Another way is to check if there is already a shuffle for the current year, and only to generate and save it if not.
Fundamentally, the answer is to save your shuffle in e.g. a database.
If you are not using a database and just need this small amount of saved results, you could just pickle the matchup to a file. Then in your index you just check if the file exists and if so, read the file and return that matchup. Otherwise you generate a new matchup, save it, and return results.