Applescript (.scpt) being if Tor Browser is running? - applescript

Running: OSX 10.11.3
So I have the script below. It is a naive hack to build an html link string based on the selected text and current url of a Firefox window. It's fragile but works ok.
However if I have Tor Browser running in addition to Firefox and open the script in Script Editor, I see that the code has been changed to reference Tor Browser:
tell application "TorBrowser" to activate
Yikes! I know Tor Browser is based on Firefox – but it seems to have its own process ID (confirmed in Activity Monitor). Even if it didn't why and how is the code being changed? I've tested this numerous times:
Without Tor Browser running: code doesn't change
Based on its "modified date" it is not being changed after I close it in Script Editor. (i.e. save it at 11:10, leave the window open until 11:12)
Duplicate script. Launch one copy with Tor Browser running: script is changed. Quit Tor Browser and launch second copy: script is not changed. There is no prompt to save the changed file when closing it.
Does anyone know what is going on? This seems very bizarre. Is there a workaround?
tell application "Firefox" to activate
delay 0.3
tell application "System Events"
tell process "Firefox"
keystroke "c" using command down
delay 0.1
end tell
set theHeadline to the clipboard
delay 1
tell process "Firefox"
keystroke "l" using command down
delay 0.1
keystroke "c" using command down
delay 0.1
set theUrl to the clipboard
end tell
set tagStart to "<a href ="
set tagMiddle to "><b><u>"
set tagEnd to "</u></b></a>"
set tag to tagStart & "\"" & theUrl & "\"" & tagMiddle & theHeadline & tagEnd
set the clipboard to tag
end tell

From the info.plist files, the CFBundleExecutable of these applications is "firefox", and the CFBundleSignature is "MOZB", maybe this causes this issue.
To avoid this, use the bundle identifier of the application in your script:
tell application id "org.mozilla.firefox" to activate
-- the bundle identifier of the "Tor Browser" application is "org.mozilla.tor browser"
Since the name of the processes is the same, use this:
tell application "System Events"
tell (first process whose its bundle identifier is "org.mozilla.firefox")
keystroke "c" using command down
delay 0.1
end tell
end tell

First I would recommend a couple of simple changes to your script. When you're working with system events, there is no need to use tell process within the system events block.
tell application "Firefox" to activate
delay 0.3
tell application "System Events"
keystroke "c" using command down
delay .1
set theHeadline to the clipboard
keystroke "l" using command down
delay 0.1
keystroke "c" using command down
delay 0.1
set theUrl to the clipboard
end tell
set tagStart to "<a href ="
set tagMiddle to "><b><u>"
set tagEnd to "</u></b></a>"
set tag to tagStart & "\"" & theUrl & "\"" & tagMiddle & theHeadline & tagEnd
set the clipboard to tag
end tell
Back to your original question, your compiler (Script Editor) is trying to correct your mistake. It assumes that your are meaning Tor since it sees that running. You and I know you really mean FireFox, but it assumes you've made a mistake. The good news is once you compile it and save it as an app, this shouldn't be an issue. Just make sure when you compile and save that you don't have Tor running and I believe you should be fine.
Btw... You'll see similar behavior if you were to change FireFox to to FoxFire or something else. It will usually prompt you to select the application, then you'd have to navigate to FireFox.
please forgive formatting, writing this on my phone

Related

AppleScript running Atom text-editor every time script is run instead of when if statement is true

I'm new to AppleScript and I'm trying to make a simple AppleScript that will pop-up a dialog asking for user input and based on the input it will open one application or another. To do this I've used:
tell application "atom"
activate
end tell
One of the applications is stored on an external hard drive called Tardis. The problem with my code below is that it automatically opens Atom every time I run the script AND the dialog window at the same time. I only want it to open Atom when the input a is given. Thanks for the help! Code is below:
on run {input, parameters}
set inputText to text returned of (display dialog "Options: p - a - j" default answer "")
set p to "p"
set a to "a"
set j to "j"
if (inputText = p) then
tell application "Terminal"
if it is running then
do script "cd Python_Workspace; source ~/tensorflow/bin/activate"
end if
activate
end tell
tell application "Finder" to open POSIX file "/Volumes/Tardis/EXTRA Applications/Sublime Text.app"
end if
if (inputText = a) then
tell application "Atom"
activate
end tell
tell application "Terminal"
if it is running then
do script ""
end if
activate
end tell
end if
if (inputText = j) then
tell application "Terminal"
if it is running then
do script "cd /Java_Workspace"
end if
activate
end tell
tell application "IntelliJ IDEA CE"
activate
end tell
end if
return input
end run
So some applications that support Applescript do - or did, require the application to launch to compile the Applescript at all (if I remember correctly these are applications that support Applescript poorly, which I'm betting is Atom).
This may not be exactly what's happening, especially since if you are launching a compiled Applescript, but maybe you are running a .applescript (text) file.
What I would do, instead of tell application "Atom" to activate (a one line version of what you have), instead: activate application "Atom".
If that does work for you, activate vs tell here's what's going on:
Applescript notices you're talking about Atom. It needs a dictionary to translate your typing into... events.
Applecript can't find the dictionary, so it launches the application, hoping that it can get more information from it when it launches
Atom launches, Applescript realizes that every application supports activate.
Where activate application you're not trying to do anything Atom specific... just activate an app. No dictionary lookup required.
(It's also worth noting that I've been doing this a very long time. I could actually be quoting you information that's a decade or more out of date, or "new" in 10.4 - not 10.14, but 10.4)

Dynamic Slideshow using Applescript

I have a folder of images that gets updated from a camera taking pictures periodically throughout the day. I'm trying to write some applescript that will create a slideshow from a folder of images but also update as more are added without having to rerun the script. I started out trying to do quick look but couldn't get that working. Any ideas on how best to tackle this?
UPDATE
this is what I have hacked together so far:
tell application "Finder" to set the_folder to get folder (choose folder)
tell application "Finder" to open the_folder
tell application "System Events"
tell process "Finder"
key code 124
keystroke "a" using command down
keystroke " " using option down
end tell
end tell
I don't believe this works if I add photos behind the scenes though.
This is what I came up with and it works perfectly for what I need.
tell application "Finder" to set the_folder to get folder (choose folder)
tell application "Finder" to open the_folder
tell application "System Events"
tell process "Finder"
key code 124
keystroke "a" using command down
keystroke " " using option down
end tell
end tell
repeat while true
delay 60
tell application "System Events"
tell process "Finder"
keystroke "a" using command down
end tell
end tell
end repeat
A few caveats... since it is using quick look, you can't really do anything on the computer while this is running since it can't have any other app activate while it is running (quick look closes when this happens). Also the repeat section is required to get quick look to pickup the new additions to the directory without losing focus. Pretty nasty stuff, but I couldn't really find another easy way to do it!

How can I use AppleScript to address dialog box in Ableton Live?

I have a collection of Ableton Live files (extension ".als") that I need to cycle through while playing a show. I'd like to dedicate a keyboard shortcut to launch each one, and had intended to use AppleScript for this.
The issue is that each file gets changed as I go through the process of playing the associated song, so that when I press the keyboard shortcut to launch the .als associated with the next song in my set, Ableton opens the "Save changes before closing?" dialog box (at which point what I want to do is select "Don't Save").
Simply pressing command + D at this point will do the trick, but I'd really like to automate this keypress. I can't seem to figure out how to get applescript to do this. I'm an applescript noob, and clicking the "Open Dictionary" option in AS seems to show that Ableton is not officially a scriptable app.
Any thoughts on this? Here's an example of an AppleScript I've been trying. This starts the process of opening the next .als in my set list, but won't click the "Don't Save" button.
tell application "Finder"
activate
open document file "Song 1.als" of folder "Desktop" of folder "User" of folder "Users" of startup disk
end tell
tell application "System Events"
keystroke "d" using command down
end tell
Interesting!
Finally came across tips that made it work:
Add both the Script Editor and Ableton Live to the Accessibility API:
System Preferences > Security & Privacy > Privacy...
Ignore application responses to continue the script during dialog.
LiveLoader.scpt:
-- open file
ignoring application responses -- don't wait for user input
tell application "Ableton Live 9 Suite" to open "Users:username:Desktop:LiveSet Project:LiveSet.als"
end ignoring
-- use delay if needed
-- delay 0.5
-- skip saving file
tell application "System Events"
set frontmost of process "Live" to true
key code 123 -- left
key code 123 -- left
keystroke return -- enter
end tell
Note:
Consider possible security impact.
Perhaps simply disable apps in Privacy List after use. (Could be scripted ;)
Can now also send mouse clicks, for more creativeness. :)
I know this is old. but in the interest of helping others who might find themselves here... heres what i have done.
use a program call Qlab. the free version will be fine.
make an applescript Cue. go to the 'trigger' tab. select midi trigger. hit the midi key you would like to assign the command too. this cue will now launch when it receives this midi note - even when running in the background.
go to the 'script' tab. copy and paste the script below.
you can make the relevant adjustments for each song. Basically each key will close all current ableton files without saving - as requested. and then launch a specific live set. which ever one you have assigned. in this case, the song 'Less Than Nothing'
the code...
tell application "System Events"
set frontmost of process "Live" to true
keystroke "q" using command down
tell application "System Events" to keystroke (ASCII character 28) --left arrow
tell application "System Events" to keystroke (ASCII character 28) --left arrow
keystroke return
end tell
delay 2.0
do shell script "open '/Users/CamMac/Desktop/Less Than Nothing 2 .als' "

Applescript keystroke not behaving as expected

I'm experimenting with Applescript for the first time, and am trying to build a script to setup my default layout of applications for developing at work. This involves placing applications across multiple Mission Control spaces. My problem at hand is simply moving about the spaces. I found in many posts similar to this that such action could be achieved with
tell application "System Events"
tell process "Finder"
keystroke "1" using control down
end tell
end tell
if the appropriate key binding was in place. I made the Preferences change so I could use control+1 to move to the first MC space. However, running the script doesn't do anything. This is the event log output:
tell application "System Events"
keystroke "1" using control down
end tell
No errors that I can see, but again: new to Applescript. I've tried many variations of this command including wrapping control down in curly braces and wrapping the call to "System Events" inside a call to "Finder" like this
tell application "Finder"
tell application "System Events"
keystroke "1" using control down
end tell
end tell
but the output is exactly the same with no shift in view. I think I'm missing something here...
According to this question's responses, I tried adding in a delay to make sure I wasn't stepping on my own feet with running the script with CMD-r but nothing happens. I hear the sound effect when you try to click out of an important focus window (if that makes any sense), it's a short beep. Am I talking to the applications improperly?
EDIT
Ok I got something working, but I'm a little confused why this is the case.
tell application "Finder"
activate
delay 0.2
tell application "System Events" to keystroke "a" using control down
end tell
This accomplishes what I need, but I have to change the key binding to a letter. I can replicate the error tone by pressing control+1 when Applescript Editor is active. I guess there's a shortcut for AE that uses the key combo. But why is that running when Finder is supposed to be active?
To answer your question, in your working code the difference is that you activate the Finder before you issue the keystroke command. Keystroke commands are always sent to the frontmost application so you must always make sure to activate an application first as you have done.
If control-1 didn't work then I suspect either some Finder command uses that combo or some other application uses that in a global context meaning it intercepts that command no matter which application is frontmost. Otherwise it should work for you.
Finally, I would remove your system events line of code from the Finder tell block of code. There's no reason the tell the Finder to tell system events to perform a command. Just put that line on its own after the "end tell" line.
Good luck.
I've just been working with this - I don't want to activate finder before triggering what should be a global shortcut. Keystroke was not working, however I tried key code and that indeed works:
on run {}
tell application "System Events"
key code {18} using {command down}
end tell
return "success"
end run
There is a list of key codes at this question: https://apple.stackexchange.com/questions/36943/how-do-i-automate-a-key-press-in-applescript
This should work:
tell application "Finder"
activate
end tell
delay 0.2
tell application "System Events"
key code 18 using {control down}
end tell
I found this tool to be a good alternative that does not have that issue.
Installation is as simple as:
brew install socsieng/tap/sendkeys
Usage:
sendkeys send --initial-delay 0 --delay 0.001 --characters 'Hello'
https://github.com/socsieng/sendkeys

How to check in AppleScript if an app is running, without launching it - via osascript utility

Consider the following AppleScript:
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
if safRunning then
tell application "Safari"
-- Stuff I only want executed if Safari is running goes here.
end tell
return "Running"
else
return "Not running"
end if
The problem: when I run this via the osascript command line utility, if Safari is not running, it gets launched and the script reports "Running". This is not the behaviour I desire or would expect. Note that it works as desired/expected when run within AppleScript Editor.
Is this an osascript bug / known issue? Or is it somehow intended behaviour for reasons I'm missing? Can anyone get it to work as desired? (BTW I'm running OSX 10.7.5; I can't see how to get osascript to report a version number).
If you comment out the tell / end tell lines, it behaves as I'd expect: if Safari is not running, it doesn't launch it, and prints "Not running". So it seems to me like the tell is what's causing Safari to be launched, but it doesn't need to be actually executed, just present in the script...? For a while I wondered if maybe this was just how tell is supposed to work, but since it doesn't work like this in AppleScript Editor, I guess not...
In fact, here's another, madder, version with similar behaviour:
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
return safRunning
if false then
tell application "Safari"
end tell
end if
This still always launches Safari, even though tell is inside an if false block after the return statement! (But again, this is fine in AppleScript Editor.)
BTW, this behaviour isn't limited to Safari, but it also isn't universal:
Affected apps include: Safari, TextEdit, iPhoto, AppleScript Editor, iTerm, ...
Non-affected apps include: Google Chrome, iTunes, Preview, Mail, Terminal, Address Book, Echofon, ...
So, does anyone have any ideas about how I might fix or route around this? Is it an osascript bug? Or am I missing something about AppleScript's semantics?
For context: I'm trying to write a script (to be embedded/called from some python) which queries open browsers for the URLs of any tabs they have open; I've got it all working fine except that it always launches Safari, whether it's open or not. I've boiled down that undesirable behaviour to the simple test case shown above. I'm not aware of any way to run this script from python without using osascript, other than appscript, which I don't want to use because it's no longer developed/supported/recommended.
Many thanks for all inputs / insights!
I suspect the reason you are getting this is because each time you call the script from the command line with osascript the script is being compiled.
The act of compiling on a tell application will afaik make the app launch.
Calling the script from the command line with osascript from a pre-compiled file i.e .scpt does not cause this behaviour because the is no compiling to be done.
But calling it from a plain text (.txt,.sh ) file will so the app will launch.
If you do not want to use a .scpt file and want to use a plain text file then you could try the trick of putting a run script command in the applescript.
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
if safRunning then
run script "tell application \"Safari\"
open location \"http://google.com\"
end tell"
return "Running"
else
return "Not running"
end if
The script in the run script is only compiled when needed. You will need to escape any characters like quotes as in my example.
It will be easier if you write the script in a normal applescript document first and compiled it to check for errors.
Then copy it to the plain text file.
UPDATE **
The method I used above was from a old script I had used to solved this issue a while before I answered here.
The answer works and is not trying to be elegant. ;-)
I actually like user1804762 method below. As it does work but feel the Answer is not clear enough so I will give an example on using it.
set appName to "Safari"
if application appName is running then
tell application id (id of application appName)
open location "http://google.com"
end tell
return "Running"
else
return "Not running"
end if
This script can be run from the command line with osascript
example:
osascript /Users/USERNAME/Desktop/foo.scpt
Notice that the script is saved as a compiled script. This will work ok and you can also save and use it as a plain text script.
i.e.
osascript /Users/USERNAME/Desktop/foo.applescript
Some Info:
"Enhanced Application Object Model":
tell application "iTunes"
if it is running then
pause
end if
end tell
You can also do it that way:
if application "iTunes" is running then
tell application "iTunes" to quit
end if
You can also do this:
get name of application "iTunes"
get version of application "iTunes"
And to complete the journey:
get id of application "TextEdit" --> "com.apple.TextEdit"
tell application id "com.apple.TextEdit"
make new document
end tell
That was the "Enhanced Application Object Model". If an app still launches (for example, the first time you compile & execute the script) I assume it is because AS has to get some info from the app which it did not found in the dictionary (or something like that...?).
OK, I know this question is really old, but I stumbled on it looking for a different issue and had to pipe in considering how complicated some of these responses are.
The simple code to achieve what you want(ed) is:
tell application "System Events"
if application process "Safari" exists then
-- do stuff you want to do only if Safari exists
end if
end tell
On older systems, the syntax used to be:
tell application "System Events"
if exists of application process "Safari" is true then
-- do stuff you want to do only if Safari exists
end if
end tell
One of these should definitely work for you, intrepid searcher of Applescript solutions for action only when an app is running.
Oh! Bonus tip: And if you're not sure what the application process name is exactly (it is usually but not always the app name), before coding your final script run…
tell application "System Events"
get every application process
end tell
And find your app process name in the results.
Here's a screen grab of running that command. (Note the zillions of Google Chrome Helper instances. Thanks Google!)
HTH!
tell application "Finder"
set applicationsnames to get the name of every process whose visible is true
end tell
set appName to "Safari"
if applicationsnames does not contain appName then
say (appName & " is not running")
--add here what you want to happen
end if
return applicationsnames
This is returning {"Finder", "JavaAppLauncher", "firefox", "Microsoft Word", "iTunes", "AppleScript Editor"} for me
Hope this helps
All the previously made answers suffer from the same issue, though:
They look for the app by its name. However, the user may rename the app, and then the script will believe the app does not run, when in fact it does.
To properly check for a running app, it should be found by its bundle ID, which the user cannot change.
The bundle ID can be inquired with this command, for instance, when the app is already running:
tell application "System Events"
get bundle identifier of application process "Safari"
end tell
Or like this for any installed app:
get id of application "Safari"
To check whether an app with a particular bundle ID is running, use this code:
tell application "System Events"
set ids to bundle identifier of every application process
if ids contains "com.apple.safari" then
return "Running"
else
return "Not running"
end if
end tell
Furthermore, here's an example to check if an app is running, then quit it, then relaunch it, ensuring that the very same app is relaunched that was running before, and not some other copy that may also exist:
set bundleID to "com.apple.safari"
set apps to runningApps(bundleID)
set appCount to length of apps
if appCount is not 0 then
quit application id bundleID
repeat while length of runningApps(bundleID) = appCount
-- wait for the app to quit
end repeat
open first item of apps
end if
on runningApps(bundleID)
-- The try block is to catch the rare case of having more than one
-- copy of an app running at the same time. Unfortunately, in that
-- case this code will not run as expected, because we don't get the
-- correct list of multiple items back then. But at least the script
-- will not crash from it but handle it gracefully.
tell application "System Events"
try
return application file of (every application process whose bundle identifier = bundleID)
end try
end tell
return {}
end runningApps
I had the same problem as described here trying to set up an AppleScript (triggered by a BetterTouchTool gesture) that plays/pauses VLC or iTunes, but only iTunes if VLC is not running (due to my workflow) and, naturally, only VLC while it's running. (I use the automatic pause/play trigger for iTunes in VLC's settings, for launch and quit of the app.)
VLC was always launched on the first use of the BetterTouchTool-trigger after every relaunch of BTT as the dictionary-cache is deleted at that point and the AppleScript handler has to launch every scripted application if a tell is aimed at it in order to call its dictionary.
I didn't find anything that avoided this anywhere; there were some attempts, but none worked for me as the dictionary-call by the script handler is nothing we can influence. I came up with this dirty workaround:
Create a separate AppleScript file only containing the line that includes the tell for VLC
Save it at some place where it won't annoy you
Replace the line containing the tell in the original AppleScript with a line that runs that script
This will lead to the first compilation of the script not calling the application (VLC, in my case) directly, only the script, which means that the application will not need to launch.
VLC will need to launch once that separate file is called, but, well, if you call that file in order to tell VLC something, you will have VLC already opened (or will want it open) anyway.
The AppleScript I call through my BetterTouchTool-trigger (a specific tap on the trackpad, in my case) looks like this:
if application "iTunes" is running and not application "VLC" is running then
tell application "iTunes" to playpause
end if
if application "VLC" is running then
run script "/Users/jannis/bin/PlayVLC.scpt"
end if
The separate AppleScript file ("PLayVLC.scpt, saved in a folder called "bin" in my user folder which I created manually ages ago for such purposes) is just this:
tell application "VLC" to play
If you open that script manually, it will of course also launch VLC. But that hopefully won't be necessary often, or ever.
I actually have no idea if this creates any deeper problems I don't know of as I'm not a pro coder; if so, please notify me. I hope this helps anyone!

Resources