5

With this simple piece of applescript I can list the names of all songs within iTunes

tell application "iTunes"
    set mainLibrary to library playlist 1
    repeat with nexttrack in (get every track of mainLibrary)
        try
            name of nexttrack
        end try
    end repeat
end tell

I then run it as Java 7 code using ScriptEngine, however it is only obvious how to get the result of the script which in this case is the name of the last track only.

    StringBuilder script =new StringBuilder();
    script.append("tell application \"iTunes\"\n");
    script.append("set mainLibrary to library playlist 1\n");
    script.append("repeat with nexttrack in (get every track of mainLibrary)\n");
    script.append("try\n");
    script.append("name of nexttrack\n");
    script.append("end try\n");
    script.append("end repeat\n");
    script.append("end tell\n");
    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine engine = mgr.getEngineByName("AppleScript");
    System.out.println(engine.eval(script.toString()));

How do can I capture the name of all tracks , i.e all output from the script. I assume I have to redirect standard out to a Reader, but cannot see how to do it.

Update:

I found this article 

http://www.informit.com/articles/article.aspx?p=696621&seqNum=6

But updating by code to

StringBuilder script =new StringBuilder();
script.append("tell application \"iTunes\"\n");
script.append("set mainLibrary to library playlist 1\n");
script.append("repeat with nexttrack in (get every track of mainLibrary)\n");
script.append("try\n");
script.append("name of nexttrack\n");
script.append("end try\n");
script.append("end repeat\n");
script.append("end tell\n");
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("AppleScript");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
StringWriter swError = new StringWriter();
PrintWriter pwError = new PrintWriter(swError);
engine.getContext().setWriter(pw);
engine.getContext().setErrorWriter(pwError);

System.out.println(engine.eval(script.toString()));
System.out.println("************* engine:"+sw.getBuffer());
System.out.println("************* engine error:"+swError.getBuffer());

Just outputs

See You on the Other Side (short)
************* engine:
************* engine error:

So you can clearly see the script works as the eval shows the name of the last track , but I'm getting nothing back from the redirected writers. Wondering does this actually work for applescript ?

Update 2 I wrote a test in Javascript and found setting the writers DID WORK for that so Im thinking that either

  1. There is something broken in script engine for Applescript ( Im using a recent build 1.7.0_40-ea-b29) of the early access version of Java 7 on OSX)
  2. My Applescript is wrong, i.e rather than just name of nexttrack I should be doing something like echo name of nexttrack to actually make it go to to stdout.

I'd like to think (2) was the problem, but I canot find any reference to outputting text in Applescript, echo is not a valid command and the print command does actually try to print to a printer rather than print to stdout as it would in Java or C.

Update 3 So I couldn't get this working, and now wondering if Applescript only ever writes the return value. I found an example of using stdout ( or so i thought) but I think that was just a naming convention, and in fact all it does is continually append data to a variable, and eventually return that.

So I did it get something working by using the following script stored in a file, and then used in Java with engine.eval(new java.io.FileReader("filename")

tell application "iTunes"
    set output to ""
    set mainLibrary to library playlist 1
    repeat with nexttrack in (get every track of mainLibrary)
        if (class of nexttrack is file track) then
            try
                set trackname to name of nexttrack
                set loc to location of nexttrack
                set locpath to POSIX path of loc
                set persistid to persistent ID of nexttrack
                set nextline to trackname & "::" & locpath & "::" & persistid
                set output to output & "\n" & nextline
            end try
        end if
    end repeat
    copy output to stdout
end tell

but this doesnt actually resolve the original question, and the one problem with it is that if there is any error then I wont get anything back, whereas if it failed halfway through reading my iTuneslibrary and I was using stdout I would at least get half the data back.

Paul Taylor
  • 13,411
  • 42
  • 184
  • 351

1 Answers1

2

To answer you original question, you get back whatever you "return" at the end of the script. If you do not have a specific "return" statement then by default you get back the result from the last action (which in your case is the last iteration of the repeat loop). Therefore if you need more than the last action returned you must create the return value in your script and then return it at the end.

but this doesnt actually resolve the original question, and the one problem with it is that if there is any error then I wont get anything back, whereas if it failed halfway through reading my iTuneslibrary and I was using stdout I would at least get half the data back. This is incorrect. The try block around your code will make applescript ignore the errors and continue, so anything you collect that doesn't error will still get returned.

Note that you have some errors in your latest applescript code. Especially this line makes no sense as applescript doesn't know what stdout is. So your comment is incorrect.

copy output to stdout

Here's what you need to do. As mentioned, you use "return" to return something. So I cleaned up your code. This will put each line of the repeat loop on a separate line of the output variable, which you return at the end of your code, which you can then parse once you bring it into your javascript code. Try this...

tell application "iTunes"
    set output to ""
    set mainLibrary to library playlist 1
    repeat with nexttrack in (get every track of mainLibrary)
        if (class of nexttrack is file track) then
            try
                set trackname to name of nexttrack
                set loc to location of nexttrack
                set locpath to POSIX path of loc
                set persistid to (persistent ID of nexttrack) as text
                set nextline to trackname & "::" & locpath & "::" & persistid & return
                set output to output & nextline
            end try
        end if
    end repeat
end tell
return output
regulus6633
  • 18,848
  • 5
  • 41
  • 49
  • Thankyou I understand your answer. But what I don't understand is whether applescript can be used to write output to stdout as it runs, or whether it can never write to stdout except writing the last value/ return statement as the script finishes. This is importnat in my case as an iTunes lib may contain 50,000 songs and hence output would have to hold 50,000 song locations and names. – Paul Taylor Aug 12 '13 at 15:04
  • No, you cannot write to stdout as the script is progressing. You can only write once at the end of the script as explained. However, you can write to a file line-by-line in the repeat loop and then read that file from your javascript code after the applescript has completed... if that's needed. – regulus6633 Aug 12 '13 at 15:08
  • Its actually from java code, thats a shame I was hoping I could avoid the creation of temporary files, seems realy wierd the manual for osascript seems to imply output is written when discussing -e option – Paul Taylor Aug 12 '13 at 15:18
  • regulus6633 I hesitate to mark your answer correct as I'm still not entirely convinced that applescript only sends output to stdout at the end of the script – Paul Taylor Aug 13 '13 at 15:38