-- Set “Sort Artists” for iTunes Selection, by Jacob Rus, 20 March 2007
--
-- This script will pop up a dialog for each artist represented
-- among the selected tracks in iTunes, asking what to put in the
-- “Sort Artists” field for all selected songs by that artist.
--
-- Note: this script breaks if the the current iTunes view is sorted by
-- artist, or by ‘album by artist’ or ‘album by year’, because the order
-- of the selection then changes as the tracks gain a ‘sort artist’
-- attribute. Also, it may bog down a bit if very large numbers of
-- tracks are selected.
--
-- Suggestion: create a new smart playlist called “Not Sorted” which
-- matches tracks where “Sort Artist” is "". Make sure that this
-- smart playlist is *NOT* set to “Live Updating”, as this will
-- cause the same problem as sorting by Artist. Sort this by Album,
-- and then select up to a few dozen albums, and run this script.


-- set this to true if you want the script to ignore any artists all
-- of whose tracks already have a “Sort Artist” attribute
property check_for_existing_sort_artist : false



tell application "iTunes"
activate
-- set track_list to (tracks in selection)
set artist_list to {}
repeat with track_ in (selection)
set artist_ to (artist of track_)

-- if we are not checking for already sorted artists, then we
-- should make sure `no_sort_artist` is true, so every artist
-- will be included in the list
if check_for_existing_sort_artist then
set no_sort_artist to (sort artist of track_ is "")
else
set no_sort_artist to true
end if

if (artist_list does not contain artist_) and no_sort_artist then
set artist_list to artist_list & artist_
end if
end repeat

-- pop up a dialog box for every unique artist, and then add the
-- “Sort Artist” attribute to all tracks for that artist when the
-- user confirms.
repeat with artist_ in artist_list
set dialog_prompt to "Type the desired value for “Sort Artist”, for the artist:" & return & return & artist_
set default_text to my put_last_name_first(artist_)
set b2 to "Use “Artist” for “Sort Artist”"
set b3 to "Set “Sort Artist”"

set the_result to display dialog dialog_prompt with icon 1 ¬
default answer default_text ¬
buttons {"Cancel", b2, b3} default button b3
set button_pressed to button returned of the_result
set text_typed to text returned of the_result
if button_pressed is b3 then
-- use typed text
my set_sort_artist_on_selection(artist_, text_typed)
else if button_pressed is b2 then
-- use artist
my set_sort_artist_on_selection(artist_, artist_)
end if
end repeat

-- we're finished; better let the user know
display dialog "All Done" with icon 1 buttons {"OK"} default button 1
end tell


-- Subroutines:

-- changes every song in the selection by 'artist_' to have sort artist 'sort_artist'
on set_sort_artist_on_selection(artist_, sort_artist)
tell application "iTunes"
set artist_ to artist_ as Unicode text
repeat with track_ in selection
if (artist_ = artist of track_) then
set (sort artist of track_) to sort_artist
end if
end repeat
end tell
end set_sort_artist_on_selection


-- Turn "First Middle Last" into "Last, First Middle". Note, this function
-- does not get every name perfect. That's what the text box is for. ;)
on put_last_name_first(artist_name)

-- handle the case where multiple artists are involved. Put last name
-- first on the first artist, and then just leave everyone else's name
-- alone.
repeat with conj_ in {" & ", " and "}
if (artist_name contains conj_) then
set parts_ to split of artist_name by conj_
set (item 1 of parts_) to put_last_name_first(item 1 of parts_)
return (join of parts_ by (conj_ as string))
end if
end repeat

set name_list to split of artist_name by " "

if (length of name_list) ≤ 1 then
return artist_name
else
return (item -1 of name_list) & ", " & ¬
(join of ({items 1 thru -2 of name_list}) by " ")
end if
end put_last_name_first

-- split the string into a list by some separator
to split of aString by sep
local aList, delims
tell AppleScript
set delims to text item delimiters
set text item delimiters to sep
set aList to text items of aString
set text item delimiters to delims
end tell
return aList
end split

-- join a list into a string with some separator
to join of aList by sep
local aString, delims
tell AppleScript
set delims to text item delimiters
set text item delimiters to sep
set aString to aList as string
set text item delimiters to delims
end tell
return aString
end join