I had the idea to write a little AppleScript to show the user’s top-rated artists (sum of song ratings/# of songs with rating of 1/2 star or more).
The problem I have here is that I don’t know of a good way to return a list with all artists. I also don’t know of a way to return all songs by a specific artist. If I figure these two things out, I’ll have enough information to be able to gather the ratings of the songs, and thus provide a rating for each artist. I know that all the songs are listed in the XML file, (“~/Music/iTunes/iTunes Music Library.xml”) along with the artist and rating, but is there an easy way to list songs by artist, rather than retrieve the artist for each track? If so, how would this be done in AppleScript?
On second thought, all the folders contained in “~/Music/iTunes/iTunes Media/Music/” have the artist names. How could I get the folder names as strings contained within a list? Also, the files inside the folders have the track and disc numbers preceding the names of the tracks; how could I work around this? Parsing out numbers and hyphens would work for most songs, but many people, myself included, have songs with numbers in the titles.
set the_artist to "Chicago"
tell application "iTunes"
set the_tracks to (name of every track of playlist "Library" whose artist is the_artist)
end tell
--set the_artist to "Chicago"
tell application "iTunes"
set the_artists to (artist of every track of playlist "Library")
--set the_tracks to (name of every track of playlist "Library" whose artist is the_artist)
end tell
Edited: wait I need to think about this because it lists the same artist.
Thanks! You just solved half of my problem, but I still need a way to get a list of all artists. Really appreciate it, that helped a lot.
EDIT: You’re amazing, thank you so much!
EDIT 2: You’re right, it does repeat artists. Not a problem, I can eliminate duplicates.
EDIT 3: Using the code mentioned in the thread here, it works well in conjunction.
I haven’t looked at the code and it’s probably faster, but here’s a basic way:
--set the_artist to "Chicago"
tell application "iTunes"
set the_artists to (artist of every track of playlist "Library")
set artist_list to {}
repeat with this_artist in the_artists
if this_artist is not in artist_list then
set end of artist_list to (contents of this_artist)
end if
end repeat
--set the_tracks to (name of every track of playlist "Library" whose artist is the_artist)
end tell
artist_list
Alright, so after a little under an hour, here’s what I’ve got. It currently gets the average ratings of all iTunes contents, because I haven’t found a good way to export the data yet. Maybe I’ll go with a log file or something. Anyway, it computes the ratings and gives back a number that falls between 0 and 5.
to addr2(l)
set okAddresses to {}
repeat with i from 1 to count l
set x to (l's item i)
if x is not in okAddresses then set end of okAddresses to x
end repeat
okAddresses
end addr2
set list_ to {}
set avg_rating to 0
tell application "iTunes"
set the_artists to (artist of every track of playlist "Library")
end tell
set the_artists to addr2(the_artists)
repeat with i from 1 to (count the_artists)
tell application "iTunes"
set y to (name of every track of playlist "Library" whose artist is item i of the_artists)
repeat with i from 1 to (count y)
set rate to item i of y
set rate to rating of track rate
if rate > 0 then
set end of list_ to rate as number
end if
end repeat
repeat with i from 1 to (count list_)
set avg_rating to avg_rating + (item i of list_)
end repeat
set avg_rating to avg_rating / (count list_) / 20
end tell
end repeat
So all unrated items are omitted, that took like 2 seconds once I started thinking. Any ideas about how to output the data? Also any suggestions about cleaning up redundant code? Tidbit: my average iTunes rating is 3.95499.
New development, I’m having trouble with the line to output the artist name. I took out the additional parts of the script to make it easier to identify the issue.
to addr2(l)
set okAddresses to {}
repeat with i from 1 to count l
set x to (l's item i)
if x is not in okAddresses then set end of okAddresses to x
end repeat
okAddresses
end addr2
set list_ to {}
set avg_rating to 0
tell application "iTunes"
set the_artists to (artist of every track of playlist "Library")
end tell
set the_artists to addr2(the_artists)
repeat with i from 1 to (count the_artists)
tell application "iTunes"
set y to (name of every track of playlist "Library" whose artist is item i of the_artists)
repeat with i from 1 to (count y)
set rate to item i of y
set rate to rating of track rate
if rate > 0 then
set end of list_ to rate as number
end if
end repeat
repeat with i from 1 to (count list_)
set avg_rating to avg_rating + (item i of list_)
end repeat
set avg_rating to avg_rating / (count list_) / 20
set a to (item i of the_artists)
end tell
end repeat
Hi. I took some liberties with this, mostly because I was being persnickety about variable names. I also see that you don’t appear to be recording the artist rating anywhere in iTunes, itself; I saved that info in the show property.
tell application "iTunes" to repeat with thisArtist in my removeDupes((playlist "Library"'s tracks whose rating ≥ 10)'s artist)
tell (playlist "Library"'s tracks whose artist is thisArtist) to set show to (my average(its rating))
end repeat
to removeDupes(ArtistList)
set traversalPast to {}
repeat with listItem in ArtistList
tell listItem's contents to if it is not in traversalPast then set traversalPast's end to it
end repeat
traversalPast
end removeDupes
to average(ratingList)
set sum to 0
repeat with aNum in ratingList
set sum to sum + aNum
end repeat
sum / (count ratingList) / 20
end average
This is a much cleaner version, although when calculating the averages, your version counts unrated songs as having a score of 0, thus skewing the results. Other than that, it seemed to work pretty well. Also, the way you’ve written it, there’s no real way to isolate the average rating.
Hmmm. I made a typo on line 1; “≥ 10” should either be “≥ 11” or “> 10,” to filter out the half-starred items. If you want to filter unrated songs, line 2 could be:
tell (playlist "Library"'s tracks whose artist is thisArtist and rating is not "") to set show to my average(its rating)
Be aware that any previously averaged tracks that are now excluded by that filter will need to be set back to nothing, as their value will not be updated. I’m not sure what you mean by isolating the rating, as I thought the whole intent of this was to assign a common artist rating.