Mac Create an agent to watch program launches

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
Hello,

I want to create an agent that would launch a certain script when iTunes is launched. Obviously, with the traditional set of properties such as KeepAlive and RunAtLoad it will resume endlessly as soon as the default 10-sec interval elapses which is not the desired behaviour as I need it running the script at iTunes' launch time and only once per launch session. I'm not a programmer, so my knowledge is not first-hand, but I'm aware of the notions of file descriptors, ports and files opened by a Mac application. In Activity Monitor I see those but I don't know which of them could be useful. If it's a path than I'd experiment with it by setting either WatchPaths, PathState or QueueDirectories but I don't even have a clue what paths and ports are indicative of the launched process or if it's some other properties of Launchd.plist.

My job is as follows:

XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.smartsolutions.addtracks</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/osascript</string>
        <string>/Users/me/Documents/Run Targeted iTunes Script.scpt</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/me/Documents/MyLaunchd_Logs/Addtracks-out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/me/Documents/MyLaunchd_Logs/Addtracks-err.log</string>
</dict>
</plist>
NOTE. "Run targeted iTunes script.scpt" is the script that targets (runs) another AppleScript script.
 
Last edited:

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
Something would need to watch for launches, so take a look at adding an observer for NSWorkspace's NSWorkspaceDidLaunchApplicationNotification notification to whatever you are using for your agent app.
As I said I'm not a programmer, I don't write apps nor am I familiar with programming languages such as Obj-C and others. I just wrote a simple XML plist and want to know how to make it watch iTunes launches.
 

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
A launchd.plist doesn't watch for application launches, the daemon/agent it manages is what would do that. You didn't mention what you are using, so I just suggested that approach.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
I gave an account quite explicitly in my first post and even posted the plist itself. I was seeking for more detailed and clear recommendations, not "something could be done about this or that". I failed to understand what did you mean by "the daemon/agent it manages is what would do that" and why launchd.plist doesn't watch. Since it operates in my home directory it should kick into action as soon as I log into my account. What other kinds of demons and agents are you talking of?
 
Last edited:

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
Launchd can be set to run jobs in a few situations, such as on a schedule or filesystem changes or mounts, but it isn't a general purpose scripting tool - it just loads and maintains services, which are the daemons and agents that you are launching with a launchd.plist. It doesn't sound like you need to use launchd at all, just a login application to watch for workspace notifications.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
The problem is it either runs continually or doesn't at all with every approach. I need it to run after iTunes is launched but only once. The script that's the bare bones of the workflow is a simple AppleScript script that looks for certain tracks and adds them if those satisfy my search criteria. Even if it was a login item then how would I tell it to run only ONCE? It has the "if running of application "iTunes" then [the rest of the script]" clause, so it will be running as long as iTunes is running with or without launchd. That's the problem.
 
Last edited:

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
The following script, saved as a stay-open application, sets up an observer for application launches and will run the doStuff handler each time iTunes is launched - just replace the contents of the handler with your current workflow (minus any statements that check if iTunes is running). After the app is running to your liking, it can be set to be an agent (no menu or dock icon) by adding the LSUIElement key to the application Info.plist.

AppleScript:
use scripting additions
use framework "Foundation"

property NSWorkspace : a reference to current application's NSWorkspace
property launchNotification : a reference to current application's NSWorkspaceDidLaunchApplicationNotification
property workspaceNotificationCenter : missing value

on run
   tell NSWorkspace's sharedWorkspace's notificationCenter -- add observer for app launches
      set workspaceNotificationCenter to it
      its addObserver:(me) selector:"appLaunchNotification:" |name|:launchNotification object:(missing value)
   end tell
end run

on appLaunchNotification:aNotification -- an application was launched
   # aNotification's userInfo contains the application that was launched
   set applicationInfo to NSWorkspaceApplicationKey of aNotification's userInfo
   if (localizedName of applicationInfo) as text is "iTunes" then doStuff()
end appLaunchNotification:

on doStuff() -- replace with workflow to run
   beep
   activate me
   display dialog "Doing iTunes Stuff..." giving up after 3
end doStuff

on quit
   workspaceNotificationCenter's removeObserver:me
   continue quit
end quit
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
The following script, saved as a stay-open application, sets up an observer for application launches and will run the doStuff handler each time iTunes is launched - just replace the contents of the handler with your current workflow (minus any statements that check if iTunes is running). After the app is running to your liking, it can be set to be an agent (no menu or dock icon) by adding the LSUIElement key to the application Info.plist.

AppleScript:
use scripting additions
use framework "Foundation"

property NSWorkspace : a reference to current application's NSWorkspace
property launchNotification : a reference to current application's NSWorkspaceDidLaunchApplicationNotification
property workspaceNotificationCenter : missing value

on run
   tell NSWorkspace's sharedWorkspace's notificationCenter -- add observer for app launches
      set workspaceNotificationCenter to it
      its addObserver:(me) selector:"appLaunchNotification:" |name|:launchNotification object:(missing value)
   end tell
end run

on appLaunchNotification:aNotification -- an application was launched
   # aNotification's userInfo contains the application that was launched
   set applicationInfo to NSWorkspaceApplicationKey of aNotification's userInfo
   if (localizedName of applicationInfo) as text is "iTunes" then doStuff()
end appLaunchNotification:

on doStuff() -- replace with workflow to run
   beep
   activate me
   display dialog "Doing iTunes Stuff..." giving up after 3
end doStuff

on quit
   workspaceNotificationCenter's removeObserver:me
   continue quit
end quit
Thank you, very much. What's the compatibility? I see it's AppleScript-ObjC.
 

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
It uses some AppleScriptObjC for the workspace notifications, but it is still AppleScript. I don't know what is in your script, but you should be able to put it in (or call it from) the doStuff handler with minimal (if any) changes. Note that the handler is only called when iTunes is launched, so you won't need to check if it is running.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
Hello,
I get compilation errors in 10.7 about the colon before the "(me)" reference and, possibly, the one-line syntax of putting the properties (sic! - meant to say "variables") inside the run handler.
 
Last edited:

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
Properties cannot be declared in a handler, they need to be declared in their containing script object.

The interleaved method syntax was introduced in OS X 10.9 Mavericks, so if you are using something older than that you will need to use the older underscore style, for example

Code:
addObserver_selector_name_object_(me, "appLaunchNotification:", launchNotification, missing value)
and

Code:
workspaceNotificationCenter's removeObserver_(me)
There may be more differences that I can't remember, since I haven't run anything that old in quite a while.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
I corrected the syntax and it compiled, however, running the script stumbled over the error -1700 "Can’t make notificationCenter of sharedWorkspace of NSWorkspace into type reference." I'm talking about your explicit run handler.

If it's MountainLion's and higher Notification Center then it doesn't belong to Lion.
 

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
I think you are talking about a different Notification Center - the NSNotificationCenter class has been in the Cocoa API since 10.0. If you are actually trying to build the application in Lion, you will probably need to use Xcode or maybe the Script Editor's Cocoa-AppleScript template, since being able to use AppleScriptObjC anywhere was a feature introduced in Yosemite (AppleScript's use statement didn't exist back then).
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
If you are actually trying to build the application in Lion, you will probably need to use Xcode.
I don't need to build an application. I just want to use it as a standalone AppleScript script or applet as you suggested previously. It throws the aforementioned coercion error when I try to execute your script.
 

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
An applet is an application. If you are looking at building my posted script on a ten-year-old system (or pre-Yosemite), you will probably need to use Xcode (it has an AppleScript app template) - I don't have a system that old to test with. In the future you might mention the system you are developing for.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
1 of all, as of 16th post in this thread you know the system version I'm talking about. 2, your code doesn't run without errors from Script Editor on this system. I want to know why and how to make it run.
And to build an app around AppleScript you don't need Xcode, it's as simple as saving the current script file as an app in Script Editor.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
For not knowing what to do and asking for help, you sure come across as quite ungrateful for the help you do receive.
I did make myself abundantly clear, no denying of that. But I do know what I came for and it's certainly not preaching to me from random entitled Internet guys. And if your sole purpose wasn't to contribute with smth of an utilitarian value then you're better off jogging on.
 
Last edited:
  • Haha
Reactions: TiggrToo

Wowfunhappy

macrumors 6502
Mar 12, 2019
292
243
I will say more generally—if there's any developers out there looking for a weekend project, a "generic" solution (like a preference pane app) for running scripts when a specific application launches would be super useful.

It's a problem I've run into as well, and a somewhat major limitation of macOS's scripting capabilities. Services, Applescripts, etc are a very powerful tool for extending macOS's built-in capabilities, but there's no way to "trigger" a script based on certain events, like an application launching. It's a bit frustrating.

I used to use EventScripts, but I found it a bit buggy, and also lacking some really basic triggers like the ability to run a script when a specific application launches. You can set up a script to run when any new application launches, but not when a specific (arbitrary) application is launched, which is a pretty basic need.
 
Last edited:

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
I will say more generally—if there's any developers out there looking for a weekend project, a "generic" solution (like a preference pane app) for running scripts when a specific application launches would be super useful.

It's a problem I've run into as well, and a somewhat major limitation of macOS's scripting capabilities. Services, Applescripts, etc are a very powerful tool for extending macOS's built-in capabilities, but there's no way to "trigger" a script based on certain events, like an application launching. It's a bit frustrating.

I used to use EventScripts, but I found it a bit buggy, and also lacking some really basic triggers—like the ability to run a script when a specific application launches. You can set up a script to run when any new application launches, but not when a specific application is launched, which is a pretty basic need.
I use EventScripts too, and since it's incompatible with 10.9 and 10.7 I decided to emulate the behaviour by summoning all the knowledge I posses to this moment, hence this topic. I use EventScripts now in Mojave [I got fed up with High Sierra's annoyances, terrible performance and design] to watch iTunes launches and run a specific AppleScript script, and it triggers events, the last update was 3 days ago.
I know the basics of launchd but it's hard to imagine that there're no cues sent by a process as it's being launched. It has to be some kind of a watcher, observer, and that's what I thought agents can do because they watch in background.

eventscripts.jpeg
event-scripts.gif
 

Wowfunhappy

macrumors 6502
Mar 12, 2019
292
243
know the basics of launchd but it's hard to imagine that there're no cues sent by a process as it's being launched.
There are cues sure, but I'm really quite sure there isn't anything you can use as a launchd trigger, unless it's some completely undocumented functionality. This isn't what launchd was designed for.

Have you attempted the trick of trying to download EventScripts from the App Store's "Purchased" page in an older OS, to see if it offers a download of the last compatible version? EventScripts dates back to 2012, so I'd be very surprised if there wasn't a version that works on 10.9, if not 10.7.

Edit: Just tested it myself, can confirm EventScripts works on 10.9 at least.
Screen Shot 2020-07-15 at 8.06.43 PM.png
 
Last edited:

Red Menace

macrumors 6502
May 29, 2011
440
78
Fruita, Colorado, USA
There was the DoSomethingWhen preference pane, but I don't know how compatible it is these days and the author's website has since gone away. It registered for some workspace notifications like any other Cocoa (or AppleScriptObjC) app can do, which can tell you what application launched.
 

Wowfunhappy

macrumors 6502
Mar 12, 2019
292
243
There was the DoSomethingWhen preference pane, but I don't know how compatible it is these days and the author's website has since gone away. It registered for some workspace notifications like any other Cocoa (or AppleScriptObjC) app can do, which can tell you what application launched.
Oh hey, what do you know, this works great on 10.9 at least! (Sorry, this thread appears to have become the people-on-very-old-OS's club!) Thank you so much!

Someone would need to try it, but I'd be surprised if this didn't work through Mojave—these types of simple preference panes tend to be forwards-compatible in my experience. It appears to be 32 bit though, so Mojave would be the end of the road. Shame it wasn't open sourced.
 

maverick28

macrumors 6502
Original poster
Mar 14, 2014
385
249
There are cues sure, but I'm really quite sure there isn't anything you can use as a launchd trigger, unless it's some completely undocumented functionality. This isn't what launchd was designed for.

Have you attempted the trick of trying to download EventScripts from the App Store's "Purchased" page in an older OS, to see if it offers a download of the last compatible version? EventScripts dates back to 2012, so I'd be very surprised if there wasn't a version that works on 10.9, if not 10.7.

Edit: Just tested it myself, can confirm EventScripts works on 10.9 at least. View attachment 934235
See, you purchased it when it was compatible with Mavericks, and I did that when I used High Sierra, i.e. this year, and as of this day High Sierra is the minimum (not even Sierra). So, no, it's not possible.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.