Bookends Scripting with OS X Javascript Automation

A place for users to ask each other questions, make suggestions, and discuss Bookends.
Post Reply
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

Hi,

Since Yosemite, OS X can be scripted with JavaScript in addition to AppleScript. However, very little documentation exists. I was trying to translate the AppleScript examples from the User Guide into JavaScript code, but got stuck. Has anyone an idea how

Code: Select all

return «event ToySSQLS» "authors REGEX 'Johnson' "
can be expressed in JavaScript, given

Code: Select all

var bookends = Application("Bookends");
?

Thanks for any pointers...
ComplexPoint
Posts: 9
Joined: Sun Jun 26, 2016 7:19 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by ComplexPoint »

With a couple of JavaScript helper functions – evalOSA and eventCode:

Code: Select all

    // evalOSA :: String -> String -> IO String
    function evalOSA(strLang, strCode) {
      
        var oScript = ($.OSAScript || (
                ObjC.import('OSAKit'),
                $.OSAScript))
            .alloc.initWithSourceLanguage(
                strCode, $.OSALanguage.languageForName(strLang)
            ),
            error = $(),
            blnCompiled = oScript.compileAndReturnError(error),
            oDesc = blnCompiled ? (
                oScript.executeAndReturnError(error)
            ) : undefined;

        return oDesc ? (
            oDesc.stringValue.js
        ) : error.js.NSLocalizedDescription.js;
    }

    // eventCode :: String -> String
    function eventCode(strCode) {
        return 'tell application "Bookends" to «event ToyS' +
            strCode + '»';
    }
You can write JavaScript functions based on the Bookends four letter event codes:
bookendsFunctions.zip
Set of JavaScript (JXA) functions for Bookends
(6.23 KiB) Downloaded 755 times
Attachments
Remember to set Script Editor to JavaScript
Remember to set Script Editor to JavaScript
screen-shot-2016-06-27-at-004736png.png (74.75 KiB) Viewed 22884 times
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

Brilliant - thank you! I'll try it out as soon as I can...
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

It works great! I am currently experimenting with it. Unfortunately, the Script Editor is not a very good IDE and the documentation for JXA is still abysmal. Feels quite immature as a technology. But holds great promise.

Jon, if you're reading this - would you consider adding some more Apple events to make the Bookends data more accessible? I would especially be interested in being able to read and manipulate the group folder tree, in particular the following API calls:

- getId( Group Name ) -> int
- getParentId( groupId ) -> int
- getChildIds( groupId ) -> list
- setGroupName( groupId )
- getGroupName( groupId ) -> string
- createChild( groupId ) -> int (id of created child group)
- deleteGroup( groupId )

The reason is that I would like to be able to sync my Bookends library with data that I have in a different database. I work with detailed taxonomies more than with keywords, so the tree data structure is important to me.
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

Alternatively, if that is too much hassle, it would be enough for me to just be able to get the path of a single record in the group hierarchy:

getGroupPath( refId ) -> string (for example "foo/bar/baz")

This would allow me to reconstruct the hierarchy by analysing all the records and/or move the information contained in the path into the keywords.
Jon
Site Admin
Posts: 10061
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Bookends Scripting with OS X Javascript Automation

Post by Jon »

cboulanger wrote:Alternatively, if that is too much hassle, it would be enough for me to just be able to get the path of a single record in the group hierarchy:

getGroupPath( refId ) -> string (for example "foo/bar/baz")

This would allow me to reconstruct the hierarchy by analysing all the records and/or move the information contained in the path into the keywords.
Perhaps you can explain exactly what you want to send Bookends in the AppleEvent and what you want Bookends to return (with screen snaps perhaps).

Jon
Sonny Software
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

Thanks, Jon!

Here is what would be great to have, in the style of the Bookends user guide. I have changed the API from what I wrote earlier, to make it more parsimonious. I don't know much about Apple Events, so there might be things that have to be done differently.

The first two API methods would suffice to achieve what I need (read-only access to the group information):

Get the ids of the group a reference is associated with

Event id: GGID
Parameters: Reference Id
Classes: none

Example:

Code: Select all

tell application "Bookends"
    return «event ToySGGID» "1234"
  end tell
In this case, Bookends will return the ids of all groups the Reference with the given ID is in, in a Return (ASCII 13)-delimited string.

Get the name of a group with the given ID

Event id: GGNM
Parameters: Group Id
Classes: none

Example:

Code: Select all

tell application "Bookends"
    return «event ToySGGNM» "1234"
  end tell
In this case, Bookends will return the name of the group with the given ID in.

Get the ids of the parent groups of a group with the given Id

Event id: GGPT
Parameters: Group Id
Classes: none

Example:

Code: Select all

tell application "Bookends"
    return «event ToySGGPT» "345"
  end tell
In this case, Bookends will return the ids groups that are parents of the group with the given ID. For example, if you have the following tree structure:

Code: Select all

Animals (ID: 21)
|--Mammals (ID: 205)
|    |--Cats (ID:345)
|
And you would query the path for "Cats" with the Id of 345, the result would be

Code: Select all

21
205
in a Return (ASCII 13)-delimited string. If the given group is on the top (root) level, an empty string is returned.

*****

The following methods would be great to have, as they would allow write access also:

Change the name of the group with the given Id

Event id: GPNM
Parameters (required): String consisting of the unique id of the group you want to modify and the new name, separated by comma.
Classes: none

Example:

Code: Select all

tell application "Bookends"
    «event ToySGPNM» "345,Felinae"
  end tell
If an error occurs, an error message is returned.

Change the parent of the group with the given Id

Event id: GPPT
Parameters (required): String consisting of the unique id of the group you want to modify and the id of the new parent, separated by comma.
Classes: none

Example:

Code: Select all

tell application "Bookends"
    «event ToySGPPT» "345,21"
  end tell
If an error occurs, an error message is returned.


Create a new group

Event id: GPCR
Parameters (required): String consisting of the new group
Classes: none

Example:

Code: Select all

tell application "Bookends"
    «event ToySGPCR» "Golden Retriever"
  end tell
In this case, Bookends returns the ID of the new group. The group is created at the root level and can then be moved under a new parent with GPPT.

Delete a group

Event id: GPDL
Parameters (required): The unique Id of the group
Classes: none

Example:

Code: Select all

tell application "Bookends"
    «event ToySGPDL» "345"
  end tell
If an error occurs, Bookends returns an error message.

***

It would be great if you could implement some or even all of these Events. Thanks a bunch for considering this feature request.
Jon
Site Admin
Posts: 10061
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Bookends Scripting with OS X Javascript Automation

Post by Jon »

Although I understand that you would find these useful, would anyone else like to comment about the general usefulness of the proposed AppleEvents?

Jon
Sonny Software

P.S. Groups don't have id's, just names.
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

Hi Jon, just curious: if groups are not modeled as a tree of nodes having distinct ids, how do you create the tree structure?

And as I said: I'd be very happy if you just add the first two events (or others providing such information), to make the group structure readable, not just the group names.
Jon
Site Admin
Posts: 10061
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Bookends Scripting with OS X Javascript Automation

Post by Jon »

The groups are handled by a different mechanism. You want the equivalent of a group's pathname: parent1/parent2/group? Except for your unusual need, I can't think a general use for such a feature.

Jon
Sonny Software
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

HI Jon, it's your software and you set the priorities, so I won't insist. Just one point: I don't think I am the only one who sorts large bibliographic collections into a fairly complex tree of "folders/groups". A lot of work goes into this ordering and it seems generally useful (at least to me) to be able to access information about this structure in a programmatic way.

Anyways, thanks for looking into the suggestion and for taking the time to evaluate it!
Jon
Site Admin
Posts: 10061
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Bookends Scripting with OS X Javascript Automation

Post by Jon »

Actually, the things you're asking for are non-trivial and, I suspect, idiosyncratic to the way you're using Bookends. If you want to simplify your request into something atomic (like return a group's parent name) please put that together and contact me off-forum.

Jon
Sonny Software
ComplexPoint
Posts: 9
Joined: Sun Jun 26, 2016 7:19 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by ComplexPoint »

cboulanger wrote:It works great! I am currently experimenting with it. Unfortunately, the Script Editor is not a very good IDE and the documentation for JXA is still abysmal. Feels quite immature as a technology. But holds great promise.
For an IDE, I tend to use Atom (free, excellent), with the Script and JS Beautify packages, to run and format JS (.scpt files)in the Atom editor.

Let me know if there are particular issues with the JXA automation object which are still opaque.

[img]
Screen shot 2016-12-20 at 20.32.22.png
Screen shot 2016-12-20 at 20.32.22.png (16.86 KiB) Viewed 22109 times
Screen shot 2016-12-20 at 20.32.08.png
Screen shot 2016-12-20 at 20.32.08.png (10.3 KiB) Viewed 22109 times
[/img]
cboulanger
Posts: 59
Joined: Mon Jan 28, 2008 6:18 pm

Re: Bookends Scripting with OS X Javascript Automation

Post by cboulanger »

For the record:

Thank you Jon for implementing full paths for groups. I did not pursue the JXA route because the whole thing is simply to immature (I still don't understand why Apple doesn't make JavaScript a first-class citizen of the development ecosystem). I chose to use a NodeJS-AppleScript bridge instead. For example:

Code: Select all

var osascript = require('node-osascript');

var cmd = [
  'tell application "Bookends"',
  'return «event ToySRGPN» given «class PATH»: "true"',
  'end tell'
].join("\n");

osascript.execute(cmd, {},
  function(err, result, raw){
    if (err) return console.error(err);
    result= result.split("\r").join("\n");
    console.log(result);
  }
);

return;
It works very well. Thanks again!
Post Reply