Skip to main content
John Hawkinson
Inspiring
November 23, 2011
Question

Remotely triggering an action in InDesign?

  • November 23, 2011
  • 2 replies
  • 3281 views

I see a lot of ways to solve this problem and I can't seem to decide which solution is least bad. Advice please.

I have an environment where InDesign deals with linked images on a remote AFP fileserver, and I would like a script to trigger and run in InDesign when a photo is added to a directory on that fileserver. The model in which I am thinking about this in is the afterAttributeChanged event, which gets fired on a Link if the link status changes to LinkStatus.LINK_OUT_OF_DATE. Of course this model doens't work if the photo is not linked. (In this case, the newly added photo will be replacing an existing FPO photo, but it cannot overwrite the FPO photo, it needs to have a different name. So using the afterAttributeChanged event is not feasible).

My environment is all Macs running CS5. Preferred scripting language is JavaScript.

For OS technical reasons, detection of the files newly added to the fileserver really has to run as a process on the fileserver to be reliable. (Detection is implemented as a kqueue in perl, but that's not really important). So the simplest implementation would be a simple TCP server on the fileserver that accepts a connection from each InDesign client with the Socket API, and then a thread or listener that woke up whenever there was data on the socket to read. (Let's say a new file is added once/hour and I would like InDesign to notice the file within five seconds.)

Unfortunately, InDesign's socket API does not support this, and there's no support for select()/poll() on an existing connection to learn when there is data to read, nor is there support for non-blocking IO. So that's right out.

Approach I: It looks like the Socket API does support non-blocking checks for incoming connections with Socket.poll(), which is really more like a combination of select(2) or poll(2) and accept(2) and not really just plain poll(2). So I could have the InDesign script create a socket to listen on for notifications of file updates, then connect to the server on a secondary connection, tell the server its port number, and then call Socket.poll() on the socket from an idle handler. This means I am polling the TCP socket the idle event handler, which seems bad but not that bad. It's abusing the Socket API because it doesn't support a reasonable approach. And there's no support for INADDR_ANY, so I need to guess at a free TCP port to listen on, but I guess I can iterate so it's not a big deal.

Approach II: Instead of doing all of that, I could write a small helper program to run on each machine that connects to the server and waits for data. When it receives that data, then it could send a message to InDesign telling it the filename. This seems like it would work, but would be kind of cumbersome (more programs, an extra process, etc.).  Also, then, how should the process signal InDesign?

Approach II(a): Signal InDesign with AppleScript. My process could just run osascript -e 'tell app "Adobe InDesign CS5" to do script "newPhoto.jsx"'. That seems like it could work, but also there might be annoying problems if message happens to come in while the user is in a modal dialog box.

Approach II(b): Use Bridgetalk. I'm not sure how I would do this -- I don't see a library that I would link my helper program against, so I suppose I would have to  have InDesign direct something like Adobe Bridge to talk to my helper program and hope that Bridge's scripting has a richer set of primitives for asynchronous IO.

Approach III: Use Adobe Bridge's HttpConnection.async=true object, and use asynchronous IO in Bridge to implement my helper process, and then have it send messages to InDesign via BridgeTalk.

I don't really like any of these solutions. I feel like Approach II(a) might be better since it doesn't abuse InDesign's idle loop (how fragile is that?), but maye Approach I is cleaner and more maintainable? I have no deal idea on II(b) or III, but it feels like adding a dependency on Adobe Bridge is may be unwise.

Has anyone implemented this sort of thing? Signalling InDesign to perform a task from another process on the same machine, or via a remote machine, with any success? What does your implementation experience tell you?

Thanks!

This topic has been closed for replies.

2 replies

John Hawkinson
Inspiring
November 26, 2011

Nobody? Harbs?

I guess I'll start with II(a), helper daemon on each client (probably in perl) that sends an AppleScript message to ID, and we'll see how it goes. Seems easiest to implement...

Harbs.
Legend
November 27, 2011

A pretty good alternative to any of the above is to write a CS Extension to poll the file server using Actionscript.

You'll need to create the extension launch automatically on app launch off the screen.

To make it more robust, you can create a second extension that checks that the first is running and relaunches it if it fails. (The two extensions can both check on each other...)

John Hawkinson
Inspiring
November 28, 2011

I'm sure you know that I do need to bone up on my CSXS/ActionScript, so perhaps this is a good chance, but why is this a good alternative? What does AS3 bring to the picture? Does it have richer socket APIs?

I guess there is the XMLSocket API...it looks like it has events that fire when data is received...

I'm not sure that this is much better than a perl script that does the same thing and triggers InDesign. I guess...platform-independent?

What are the things that cause CSXS extensions to need relaunching?

Somehow I think of CSXS as being useful when you want to have a panel that looks like an ID panel. But I guess there's a lot more than that...

SuperMacGuy
Known Participant
November 23, 2011

I've been using watched folders via Applescript for a long time now. I've had really good success with it, with the caveat that it's never a completely error-free experience. There's the occasional server-unmounting or application crash. But my apps process 1000s of ID files every week, so I think it's pretty high volume and high probably of an error just because of volume we do.

I've used a couple different methods to watch the folders. Lately I've been going with "do shell script "ls -tr " & quoted form of (POSIX path of (watchedFolder as string))"

This was a lot more reliable than Finder tells for getting/updating folder contents. Then I can filter for file extension if needed. If you are only adding files to the folder, you'd have to keep a list of file names and compare against that each time the script scans.

My apps are Applescript-ObjectiveC based now. So I am using the cocoa event timer to run the process every 30 seconds [set myTimer to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(10, me, "doAutoLoop:", missing value, true)]. The apps have a UI with a start/stop button. They also use some straight ObjectiveC for server/volume re-mounting if the volume isn't found. I like this kind of approach, with a UI, so if the user can control the work that happens. If a user needs to run the automated app, they run it. Or if they can't be interrupted, then they stop it. I'd be worried about how this entire process runs if a user is doing something completely different (or in the modal dialog as you mention).

I've never considered trying to run the notification process on the server, mainly since I'm not in IT nor would consider windows programming. But, there is the possibility that you could use InDesign server to handle your process more reliably. ??

John Hawkinson
Inspiring
November 23, 2011

SuperMacGuy: Thanks for the thoughts. I'd really rather the discussion not head towards how to monitor the files outside of InDesign -- I have a solution for that that works pretty well (kqueue), but we can talk about it another thread if you like. I'm very happy with my solution.

For me, the question is triggering InDesign. Do you do that from your script? It sounds like you really doing batch processing, which is not my application here. To the extent that you have anything analagous, I guess your entire batch workflow is written in AppleScript so your easy answer is the equivalent of II(a), though you don't need to run "osascript."

If a user needs to run the automated app, they run it. Or if they can't be interrupted, then they stop it. I'd be worried about how this entire process runs if a user is doing something completely different (or in the modal dialog as you mention). [...]

But, there is the possibility that you could use InDesign server to handle your process more reliably.

In short, no. The use case here involves the production editor actively working on a document in InDesign while the photo editor is preparing final photos to replace the FPO placeholders. The script in InDesign is short and sweet, and it's also not the end of the world if it doesn't happen automatically or gets deferred. It's really quite analagous to updating links.

InDesign server would not work because the layouts are actively open and being worked on in ID Desktop. It is also too expensive -- paying around $15k  for this little bit of added functionality doesn't make financial sense.

I've never considered trying to run the notification process on the server, mainly since I'm not in IT nor would consider windows programming.

Err, this is probably a better question for your other thread, but how did we get to Windows programming? I guess you must be running a Windows fileserver? I guess my solutions wouldn't work for you then.