0

I am trying to separate out my .applescript files into different ones to tidy things up.

I have a JS AppleScript file called Test.applescript that tries to run the JS AppleScript file Group Tracks Dependency.applescript and what I want to do is pass in a parameter into the dependency script and get a return value out of it. (It creates an array of arrays of iTunes tracks).

Test.applescript

(function() {
    var app = Application('iTunes');
    app.includeStandardAdditions = true;

    app.doShellScript('Group Tracks Dependency.applescript');

    return "Done";
})();

// For quick logging
function log(obj) {
    this.console.log(obj);
}

Group Tracks Dependency.applescript

(function(selection) {

    return getGroupsOfTracks(selection);

    function getGroupsOfTracks(originalTracksArray) {
        if (originalTracksArray == null || originalTracksArray.length == 0) 
            return null;

        var tracks = originalTracksArray.slice();
        var groups = [];
        while (true) {
            var group = [];
            group.push(tracks[0]);
            tracks = tracks.slice(1);

            while (true) {
                if (!tracks[0]) break;
                if (tracks[0].album() != group[0].album())
                    break;
                if (tracks[0].artist() != group[0].artist())
                    break;
                if (tracks[0].discNumber() != group[0].discNumber())
                    break;
                group.push(tracks[0]);
                tracks = tracks.slice(1);
            }

            groups.push(group);
            if (!tracks[0]) break;
        }

        return groups;
    }
})();

When I try to run the Test script I get this error (line 5 is the app.doShellScript line):

Error on line 5: Error: A privilege violation occurred.

Is there any way to get around this? I should also note that I want other people to be able to download these scripts and run them on their own iTunes libraries in the future (currently it's not user-friendly though).

If there's no way to get around this then would importing another JS AppleScript file work?

Dylanthepiguy
  • 1,621
  • 18
  • 47

3 Answers3

2

I think you may be fighting a battle that you can’t win using .doShellScript.

The Apple way is to use a Script Library as defined on https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-11.html#//apple_ref/doc/uid/TP40014508-CH110-SW1

Unfortunately a script library has constraints where you can only pass simple variables.

Another way is to use require, which can be defined with code like https://github.com/dtinth/JXA-Cookbook/wiki/Importing-Scripts

JakeCigar
  • 603
  • 6
  • 12
0

I'm not sure what you are trying to accomplish, but this works for me using Script Editor 2.8.1 (183.1) on OSX 10.11.4:

  1. Create a main JXA Script file
  2. Create a JXA Script Library file

BOTH of these MUST be saved as compiled script files (.scpt)

It is INCORRECT that "Unfortunately a script library has constraints where you can only pass simple variables."

You can call any of the functions in the Script Library file from any JXA script.

In your MAIN script file, which I will call "Get iTunes Group Selection.scpt":

var app = Application('iTunes');
app.includeStandardAdditions = true;

var myLib = Library("My JXA Lib")

var selectionArr = app.selection()   // ### Change as needed ###
var groupArr = myLib.getGroupsOfTracks(selectionArr)
groupArr

~~~~~~~~~~~~~~~~~~~~~

And then in a separate script file, saved as: ~/Library/Script Libraries/My JXA Lib.scpt

function getGroupsOfTracks(originalTracksArray) {
        if (originalTracksArray == null || originalTracksArray.length == 0) 
            return null;

        var tracks = originalTracksArray.slice();
        var groups = [];
        while (true) {
            var group = [];
            group.push(tracks[0]);
            tracks = tracks.slice(1);

            while (true) {
                if (!tracks[0]) break;
                if (tracks[0].album() != group[0].album())
                    break;
                if (tracks[0].artist() != group[0].artist())
                    break;
                if (tracks[0].discNumber() != group[0].discNumber())
                    break;
                group.push(tracks[0]);
                tracks = tracks.slice(1);
            }

            groups.push(group);
            if (!tracks[0]) break;
        }

        return groups;
 }
JMichaelTX
  • 1,659
  • 14
  • 19
  • I found that I can not pass/return a RegEx or a function to a Library. Not sure what else I can’t pass/return. But, with require, it all runs together. – JakeCigar May 13 '16 at 06:10
  • The problem with this is that I want to be able to distribute the scripts easily, which can't be done unless I put the scripts inside a script bundle. But then git won't show the changes becauese .scpt files aren't text files. I believe I can solve this problem by writing a build script... – Dylanthepiguy May 14 '16 at 00:49
0

Well, it's been a few years...

I ran into errors with JXA and doShellScript when I tried to run with Application("Finder"). These errors went away when I instead ran the script from Application.currentApplication(). So for my script, I used const finder = Application("Finder") for Finder specific stuff, then const app = Application.currentApplication() for running the script.

For example:

//test1.scpt
function run() {    
    const app = Application.currentApplication()
    app.includeStandardAdditions = true
    app.doShellScript("osascript ~/Desktop/test2.scpt")
}
//test2.scpt
function run() {
    const app = Application.currentApplication()
    app.includeStandardAdditions = true
    
    app.displayDialog("foo")
    app.doShellScript("osascript -e 'display dialog \"bar\"'")
}

As expected, running test1.scpt gives me two dialogs: foo and `bar.

n8henrie
  • 2,737
  • 3
  • 29
  • 45