Skip to content
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 4bc2bcee8262d21be8c54f8457ebc47ab451586e @TooTallNate committed
Showing with 167 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +46 −0 README.md
  3. +87 −0 lib/node-applescript.js
  4. +20 −0 samples/execString.js
  5. +3 −0 samples/locationCurrentTrack.applescript
  6. +10 −0 samples/locationCurrentTrack.js
1 .gitignore
@@ -0,0 +1 @@
+.DS_Store
46 README.md
@@ -0,0 +1,46 @@
+node-applescript
+================
+
+A high-level way to execute AppleScript code through NodeJS, and retrieve
+the result as a native JavaScript object (when possible). In reality, this
+module is just a simple wrapper around the Apple `osascript` command.
+
+### Why?
+AppleScripts are the only way to communicate and interact with certain
+external OS X processes, for example [iTunes](http://www.itunes.com).
+
+Requirements
+------------
+
+ * Mac (or Hackintosh) running [OS X](http://www.apple.com/macosx) (tested with Snow Leopard)
+ * [NodeJS](http://nodejs.org) (v0.1.100 or newer)
+
+Usage
+-----
+
+The `node-applescript` module provides `execString` and `execFile` functions
+to easily execute AppleScript commands and buffer the output into a calback.
+
+--------------------------------------------------------
+
+ var applescript = require("node-applescript");
+
+ // Very basic AppleScript command. Returns the song name of each
+ // currently selected track in iTunes as an 'Array' of 'String's.
+ var script = 'tell application "iTunes" to get name of selection';
+
+ applescript.execString(script, function(err, rtn) {
+ if (err) {
+ // Something went wrong!
+ }
+ if (Array.isArray(rtn)) {
+ rtn.forEach(function(songName) {
+ console.log(songName);
+ });
+ }
+ });
+
+--------------------------------------------------------
+
+`execFile` works the exact same way, except you pass the _path_ of the AppleScript
+(`*.applescript`) file as the first argument instead of the command itself.
87 lib/node-applescript.js
@@ -0,0 +1,87 @@
+
+var spawn = require("child_process").spawn;
+
+// Path to 'osascript'. By default search PATH.
+exports.osascript = "osascript";
+
+// Execute a *.applescript file.
+exports.execFile = function execFile(file, args, callback) {
+ if (!Array.isArray(args)) {
+ callback = args;
+ args = [];
+ }
+ return runApplescript(file, args, callback);
+}
+
+// Execute a String as AppleScript.
+exports.execString = function execString(str, callback) {
+ return runApplescript(str, callback);
+}
+
+
+
+function runApplescript(strOrPath, args, callback) {
+ var needsE = false;
+ if (!Array.isArray(args)) {
+ callback = args;
+ args = [];
+ needsE = true;
+ }
+
+ // args get added in reverse order with 'unshift'
+ args.unshift(strOrPath);
+ if (needsE) {
+ args.unshift("-e"); // If 'execString' was called
+ }
+ args.unshift("-ss"); // To output machine-readable text.
+
+ var interpreter = spawn(exports.osascript, args);
+
+ var stdout = "";
+ interpreter.stdout.on('data', function (data) {
+ stdout += data;
+ });
+
+ var stderr = "";
+ interpreter.stderr.on('data', function (data) {
+ stderr += data;
+ });
+
+ interpreter.on('exit', function (code) {
+ var result = processOutput(stdout);
+ callback(code, result, stderr);
+ });
+
+}
+
+function processOutput(stdout) {
+ // Output usually unnecessarily contains a \n
+ // at the end, so let's remove it.
+ if (stdout[stdout.length-1] == '\n') {
+ stdout = stdout.substring(0, stdout.length-1);
+ }
+
+ // 'osascript' returns "Array"s that have {}
+ // instead of []. We must replace them before
+ // we can run them through JSON.parse
+ var leftBracket = stdout.indexOf("{");
+ var rightBracket = stdout.lastIndexOf("}");
+ if (leftBracket >= 0 && rightBracket > 0) {
+ stdout = '[' + stdout.substring(leftBracket+1, rightBracket) + ']';
+ }
+
+ // the 'alias' type represents a path on the
+ // filesystem, in a weird format. Let's fix it.
+ if (stdout.indexOf('alias "') != -1) {
+ stdout = stdout.replace(/alias "/g, '"/Volumes/').replace(/:/g, "/");
+ }
+
+ // Finally try running the result through JSON.parse
+ try {
+ stdout = JSON.parse(stdout);
+ } catch(e) {
+ //console.error(e);
+ }
+
+ return stdout;
+}
20 samples/execString.js
@@ -0,0 +1,20 @@
+var applescript = require("../lib/node-applescript");
+
+// Very basic AppleScript command. Returns the song name of each
+// currently selected track in iTunes as an 'Array' of 'String's.
+var script = 'tell application "iTunes" to get name of selection';
+
+applescript.execString(script, function(rtnCode, stdout, stderr) {
+ if (rtnCode) {
+ // Something went wrong!
+ }
+
+ if (Array.isArray(stdout)) {
+ console.log("Currently selected tracks:");
+ stdout.forEach(function(songName) {
+ console.log("\t" + songName);
+ });
+ } else {
+ console.log("No tracks are selected...")
+ }
+});
3 samples/locationCurrentTrack.applescript
@@ -0,0 +1,3 @@
+tell application "iTunes"
+ return location of current track
+end tell
10 samples/locationCurrentTrack.js
@@ -0,0 +1,10 @@
+var applescript = require("../lib/node-applescript");
+
+var file = require("path").join(__dirname, "locationCurrentTrack.applescript");
+
+applescript.execFile(file, function(rtnCode, stdout, stderr) {
+ if (rtnCode) {
+ // Something went wrong!
+ }
+ console.log("The currently playing track is located at:\n\t"+stdout);
+});

0 comments on commit 4bc2bce

Please sign in to comment.
Something went wrong with that request. Please try again.