Creating a list from text

Hi,

I am very new to apple script. I'm familiar with awk and bash so i managed to extract song, artist and album from the iTunes xml file in the followin format:

song1,artist1,album1
song2.artist1,album1
...
songN,artistN,albumN

How can I make a list of this text output so that each line is an item containing three items. Like if I create directly in applescript:

set myList to {{"song1","artist1","album1"},{"song2","artist1","album1"},...,{"songN","artist N,"albumN"}}

Any help would be appreciated.
Thanks.
Indy

powerbook-g4, Mac OS X (10.4)

Posted on Jul 24, 2009 10:43 AM

Reply
13 replies

Jul 24, 2009 11:10 AM in response to freeindy

This is relatively easy using AppleScript's text item delimiters to break up a string/text object:

set theSourceText to "song1,artist1,album1
song2,artist1,album1" -- or however you extract it from your library.

set myList to {} -- start with an empty list
set oldTIDs to AppleScript's text item delimiters -- store the current TID
set my text item delimiters to "," -- set the TID to comma
repeat with eachTrack in (paragraphs of theSourceText) -- iterate through the source
copy (text items of eachTrack) to end of myList
end repeat
set AppleScript's text item delimiters to oldTIDs -- restore the TIDs
return myList

--> {{"song1", "artist1", "album1"}, {"song2", "artist1", "album1"}}


This works because when you ask for 'text items' of a string, AppleScript uses the current 'text item delimiters' to work out how to break the string into components. It's important, though, to restore the original settings when you're done, or unexpected things can happen.

Note also, that iTunes is pretty scriptable, and this data is available directly, without having to awk the library XML file:

set myList to {}
tell application "iTunes"
repeat with eachTrack in (get every track)
tell eachTrack to copy {name, artist, album} to end of myList
end repeat
end tell

Jul 24, 2009 11:53 AM in response to Camelot

Camelot,

Thanks for your reply.

I know the 'tell' block with scripting Itunes directly to get the information. I tried it, even yours again, but here my problem:

I have 1077 songs and it takes tremendous time on my powerbook G4 to retrieve all the information. Several minutes in fact. This puts my cpu at 100% making it very hot during the process.

Doing the same procedure in awk, it took about 5 secs. So, there is a efficiency while using scripting language awk or processing bash information.

But trying your code, now repeat block is taking tremendous time as well. So, I'm in square one. It's taking too much time and contributing too much lot global warming.

However, I very new applescript so maybe there is something I'm not aware of.

Regards,
Indy

Jul 24, 2009 12:02 PM in response to freeindy

I'm surprised it takes that long to extract the data from iTunes directly, but I understand your concern.

If the text manipulation code is still slower than you'd like, then consider changing the awk script to output the data in the format you require, e.g. literally have it write:

{ {"song1", "artist1", "artist2"}, {"song2", "artist1", "album1"} }

with all the brackets, quotes, commas, etc. You can then run this through AppleScript's run script command that will effectively turn it into an AppleScript list:

set awkOutput to do shell script "whatever" -- your awk script
run script awkOutput

Jul 24, 2009 3:04 PM in response to freeindy

Maybe you might also try the following script, which is very much like the one that Camelot suggested. On my computer, it took about one minute to make a list of 1127 triplets.

tell application "iTunes"
set myList to {}
set myListRef to a reference to myList
tell playlist "Music" of source "Library"
repeat with k from 1 to number of tracks
copy {name, artist, album} of file track k to the end of myListRef
end repeat
end tell
myList
end tell

The script uses the information about large lists given on page 91 of the AppleScript Language Guide.

Jul 24, 2009 5:25 PM in response to freeindy

It looks like the main culprits are the repeat statement and getting multiple properties from the tracks. Since getting a single property from the tracks seems to be fairly speedy, I tried using separate lists for each property - on my machine, this wound up being 20 times faster (!!). I don't know how much it will improve the times on your G4, but you might give it a try:

<pre style="
font-family: Monaco, 'Courier New', Courier, monospace;
font-size: 10px;
font-weight: normal;
margin: 0px;
padding: 5px;
border: 1px solid #000000;
width: 720px;
color: #000000;
background-color: #FFEE80;
overflow: auto;"
title="this text can be pasted into the Script Editor">
set myList to {}
set myListRef to a reference to myList
tell application "iTunes"
set theNames to (get name of every track)
set theArtists to (get artist of every track)
set theAlbums to (get album of every track)
end tell

repeat with X from 1 to (count theNames)
set the end of myListRef to {item X of theNames, item X of theArtists, item X of theAlbums}
end repeat
</pre>

Jul 24, 2009 6:20 PM in response to Pierre L.

If speed is your primary goal, this seems to be the fastest pure-AppleScript solution I've come up with:

tell application "iTunes"
set trackData to (get {name, artist, album} of every track)
end tell
set outputList to {}
repeat with i from 1 to (count item 1 of trackData)
copy {item i of item 1 of trackData, item i of item 2 of trackData, item i of item 3 of trackData} to end of outputList
end repeat


This works by asking iTunes just for the data you're after (rather than getting all the track data and manually extracting the data you want). The downside is that this generates three lists, one for each of name, artist and album, hence the second block that refactors the lists into the desired format.

OMM this takes about 5 seconds to process a 1740-track library, compared to 14-15 seconds for the previous incarnations.

Jul 24, 2009 7:34 PM in response to Camelot

And to go even further, you can put the track information into a script property. Using all of the techniques posted so far, processing 4200 tracks on my machine takes about a second (actually, formatting the Script Editor's result takes longer than getting the list).

<pre style="
font-family: Monaco, 'Courier New', Courier, monospace;
font-size: 10px;
font-weight: normal;
margin: 0px;
padding: 5px;
border: 1px solid #000000;
width: 720px;
color: #000000;
background-color: #FFEE80;
overflow: auto;"
title="this text can be pasted into the Script Editor">
script GetStuff
property Stuff : {}
tell application "iTunes" to set Stuff to (get {name, artist, album} of every track)
end script
run GetStuff

set myList to {}
set myListRef to a reference to myList
repeat with X from 1 to (count item 1 of GetStuff's Stuff)
copy {item X of item 1 of GetStuff's Stuff, item X of item 2 of GetStuff's Stuff, item X of item 3 of GetStuff's Stuff} to the end of myListRef
end repeat
myList
</pre>

Jul 24, 2009 9:04 PM in response to red_menace

It looks like the main culprits are the repeat statement and getting multiple properties from the tracks


Actually, that doesn't seem to be the problem. OMM, both:

set trackData to {name, artist, album} of every track


and:

set theNames to name of every track
set theArtists to artist of every track
set theAlbums to album of every track


Take almost exactly the same amount of time (0.93 seconds vs. 0.92 seconds).

What seems to make the difference is using the reference to the list vs. manipulating the list directly. I always forget that one. OMM:

set the end of myList to {item X of theNames, item X of theArtists, item X of theAlbums}


takes 5.09 seconds, vs.:

set the end of myListRef to {item X of theNames, item X of theArtists, item X of theAlbums}


which takes 2.78 seconds. I really wish Apple would fix that one 🙂

Message was edited by: Camelot

Jul 24, 2009 9:36 PM in response to Camelot

I was referring to your original iTunes script where you were getting the properties by repeating through each track item, but yes, it would be nice to get rid of some of those performance issues. I think that is what makes AppleScript so frustrating at times - from your original example script to one that uses references and script objects, I'm getting speeds of over 250 times faster.

Jul 25, 2009 1:19 AM in response to red_menace

Speed is not my primarily goal but waiting a few minutes is a frustration. Considering every time you start up my application, you might need to go for a coffee.

Anyway Wow,
This really was an improvement. Much faster than I expected. However, I'm getting an error (from log):

*tell current application*
* set last insertion point of myList to {"Song1", "Artist", "Album"}*
* "Can’t make myList into type reference."*

Why is that?

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Creating a list from text

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.