Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do you get output from Javascript into Java using ScriptEngine

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.

like image 603
Paul Taylor Avatar asked Nov 01 '22 16:11

Paul Taylor


1 Answers

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
like image 93
regulus6633 Avatar answered Nov 09 '22 11:11

regulus6633