Applescript. Get properties of all instances - applescript

I have many instances of VLC open. I want to check the playing status of every instance like:
tell application "VLC"
if playing = true then return
end tell
But it checks only one instance of VLC. How can I check all instances?

This is a workaround answer based on your comment "I want to prevent a scheduled applescript to execute if a VLC instance is playing." and the other information that has been presented in other comments and answer posted prior to this one. Also, by execute, I'm assuming you mean execute any additional code in the script that started on schedule.
Also note, this may not be perfect however its being presented to give it a try.
On my system, when an occurrence of VLC is open and without content loaded, after the initial percent of CPU usage spikes it quickly settles to 0% and with content loaded but not playing it's less than 5% and typically less than 3%. If it's playing it's typically always greater than 5%.
This of course may vary on your system, so you'll need to monitor over a period of time polling CPU usage to see how it fluctuates on your system to see what the sweet spot is.
The following example AppleScript code when placed at the beginning of the code in the scheduled AppleScript, prior to code in your script to trigger whatever with VLC, will abort processing the rest of the script if the percent of CPU usage of other instances of VLC is equal to or greater than 5%.
set |VLC%CPU| to paragraphs of text of ¬
(do shell script "ps -Ac -o %cpu -o command | grep [V]LC ; exit 0")
repeat with thisItem in |VLC%CPU|
if first word of thisItem as integer ≥ 5 then return
end repeat

Another method could be to rename the instances by making copies of the application, and giving them new names such as VLC1, VLC2. You can do this by going to the applications folder and copying the VLC Application. Then paste it within the same folder to create the app "VLC copy". Then rename each copy you create. The copies will now show in the applescript dictionaries.
You can now use a tell block for each instance to check if it's playing. You just need to make sure that you open the correct instance numbers for the number you have playing. E.g. don't open "VLC1" and "VLC3" if you only have 2 instances, or close a lower instance number. By having the if c is equal to statement it won't open that instance of the application by executing the tell block.
If you have all instances open you could remove the loop and the if statements and just check if they're playing or not.
on getCount()
tell application "System Events"
set p to processes whose name contains "VLC"
set theCount to count of p
return theCount
end tell
end getCount
set appCount to my getCount()
if appCount is greater than 0 then
repeat with c from 1 to appCount
if c is equal to 1 then
tell application "VLC1"
if playing is true then
log ("playing 1")
end if
end tell
end if
if c is equal to 2 then
tell application "VLC2"
if playing is true then
log ("playing 2")
end if
end tell
end if
end repeat
end if

So far the half solution I do is:
tell application "System Events"
if (name of application processes whose frontmost is true) = {"VLC"} then return
end tell
So I check is it frontmost. Usually if I run a movie it is frontmost. I would prefer the "is playing" variation but... ok, what can I do.

I think I'm understanding the nature of your query more now. I was previously a little confused about what your objective was, but now I'm gathering it's simply to determine whether any VLC instance is playing or not. Is that correct ?
But that you do not need to know what is playing or in which window it's playing ?
And am I correct in saying that you only need to discover that a single instance out of many is playing, in which case this is sufficient to prevent some other AppleScript from executing ? Or, put another way, that other AppleScript will execute if and only if no instance of VLC is playing ?
I believe that's achievable. Although we can't use the playing property of the VLC application object, we can use properties/attributes of VLC processes/windows to determine whether or not each instance of VLC is playing.
tell application "System Events"
set _W to a reference to window 1 of (every process whose name is "VLC")
set _title to the value of attribute "AXTitle" of _W
end tell
That is literally all you need, as the AXTitle attribute returns very predictable data depending on the state of VLC:
▸ If VLC is playing and NOT fullscreen: _title evaluates to a non-empty string (specifically, it contains the name of the video file or the path to the internet stream).
▸ If VLC is NOT playing: _title evaluates to "VLC media player".
▸ If VLC is playing and IS fullscreen: _title evaluates to an empty string ("").
Therefore:
If _title = "VLC media player", then VLC is not playing; otherwise, VLC is playing.
Utilising this fact, in order for your other AppleScript to be allowed to execute, we want every _title value representing each instance of VLC to be equal to "VLC media player". If there is even one value in _title that is anything other than that, then the assertion fails and the script can terminate, or do whatever it needs to do to prevent the execution of some other script.
I chose to simply count the number of attributes returned with the name "AXTitle" and a value other than "VLC media player". The number returned is equal to the number of VLC instances currently playing:
tell application "System Events" to count ¬
(the attributes of window 1 of ¬
(every process whose name is "VLC") whose ¬
name is "AXTitle" and ¬
value is not "VLC media player")
if result is not 0 then return

Related

How to launch an application after a specific Disc was mounted using Automator

I'm new to Automator.
There are many examples for simple actions.
But I couldn't find examples or documentation for launching some applications after a specific disk was mounted.
It will be very useful at work.
Has someone done this?
Ok, you want the Automator way, you get it :-D
Create a new Automator action of type Folder Action
Choose the Volumes folder of your System as input, I think you'll have to use Go to folder and type /Volumes
As first action choose Execute Applescript
Use the following script and define the first two variables to match your needs:
on run {input, parameters}
-- define the volume name and the application to start
set triggeringVolumeName to "YOUR_VOLUME_NAME"
set applicationToStart to application "Microsoft Word"
-- walk through all newly mounted volumes
repeat with aMountedVolumeAlias in input
-- get the volume name from the given alias
tell application "System Events" to set mountedVolumeName to name of aMountedVolumeAlias
-- compare the volume name with the defined trigger name
if mountedVolumeName is triggeringVolumeName then
-- launch the target application
launch applicationToStart
-- all is done stop checking
exit repeat
end if
end repeat
return input
end run
The trick is to watch for changes inside the default mount point of your system (/Volumes). Everytime something is added to the folder, the AppleScript will be executed and aliases of the newly added items (aka the new volumes) will be inside the input parameter given to the script.
We walk through the list of all item aliases and get the real name of the alias, compare it with our trigger name and in case of a match we start the application.
Have fun with Automator, Michael / Hamburg
Elaborating on ShooTerKo's answer I've written the following script that continues the Workflow if the triggeringVolumeName is found. That way the actual launch (or any other Workflow action) can be moved outside the Applescript:
Create a new Automator action of type Folder Action
Choose the Volumes folder of your system as input by clicking Other... in the Choose folder dropdown, pressing Cmd+Shift+G and typing /Volumes
As first action choose Execute Applescript
Use the following script and change YOUR_VOLUME_NAME to match your needs:
on run {input, parameters}
-- define the volume name and the application to start
set triggeringVolumeName to "YOUR_VOLUME_NAME"
-- walk through all newly mounted volumes
repeat with aMountedVolumeAlias in input
-- get the volume name from the given alias
tell application "System Events" to set mountedVolumeName to name of aMountedVolumeAlias
-- compare the volume name with the defined trigger name
if mountedVolumeName is triggeringVolumeName then
-- continue workflow
return input
end if
end repeat
-- if repeat finished without match, cancel workflow
error number -128
end run
Add other actions to the Workflow, e.g. Ask for Confirmation, Copy Finder Items or Launch Application

Show a message on screen if a specific folder is empty Applescripts

I have a system which move files across the network to my MAC computer (CSV File), that file is necessary for me to feed a local system, but sometimes people forget sending it or producing it, so I need to show an error message in my computer that says "Careful, there is not a file in your folder"
A POP UP would be good to have, this script should run every 2 seconds, it should show a button to close the message.
Any ideas on how to do this using applescripts? anyone have example code?
Something such as this might be what you are looking for:
set POSIXpath to "/path/of/file"
set POSIXfile to POSIXpath & "file.csv"
set theAlias to POSIX file POSIXfile
tell application "Finder"
repeat
--The next line is optional
if exists process "Application of CSV file" then
if not (exists theAlias) then
--display alert
display alert "Warning: the file does not exist"
end if
end if
delay 5
end repeat
end tell
The optional line I included can be made to check for the process of whatever application you are using the file with. So for example:
if exists process "Numbers" then
This checks first to see if the application "Numbers" was currently running. If you choose not to check the application process remove that line and one end if statement.

Ensure one instance of an applescript is running

There is an screensaver that will launch scripts in OS X - which is great, but the problem I am having is that it launches multiple copies of the script. Is there a simple way to ensure that only one copy of this script is running at a time?
John Gruber wrote a post on something very similar to this a while back. Long story short, you would just wrap the entire thing in a block similar to the following:
tell application "System Events"
count (every process whose name is "BBEdit")
end tell
replacing "BBEdit" with your app name, and then launch only if the count is 0.

applescript: is it possible to make a running script using system events block additional user input?

System Events has the virtue of being very flexible, intuitive and universal (i.e. it works whether the application has scripting support or not) but it feels wrong to make important scripts that aren't fat-finger-proof. Is there any way to block user input either all or part of the time a script is running? How would it be done in the script below?
tell application "System Events"
keystroke "Please! "
delay 1
keystroke "I need your help. "
delay 1
keystroke "My kludgy nature annoys my maker. "
delay 1
keystroke "I must learn how to work without interference!"
delay 1
end tell
An experienced applescript guy --StefanK at the macscripter forum-- told me this was impossible.

Applescript timeout when screen is locked

I am getting an AppleEvent timed out error when my Applescript is running and the screensaver turns on and locks the screen. The applescript completes the current operation and when trying to do the next Finder operation it does not proceed but waits and times out.
I cannot increase the time-out time limit since I will not unlock the screen at all. Is there a way to ignore waiting for the screen unlock or some other solution to this?
Thanks in advance.
The best answer I have received (from macscripter.net) is to use shell commands instead of Finder commands to avoid this timeout.
I don't know how you could bypass the locked screen so your code keeps working, however you might use an if statement such that when the screen saver is running then your code isn't executed. That would at least prevent the timeout error. For example suppose you wanted to run a repeat loop 10 times for some reason, and you wanted not to run some code when the screen saver is running... you could do this.
set i to 0
repeat
set screenSaverEngineIsRunning to false
tell application "System Events"
if (exists process "ScreenSaverEngine") then set screenSaverEngineIsRunning to true
end tell
if not screenSaverEngineIsRunning then
set i to i + 1
-- do some code here
end if
delay 1
if i is 10 then exit repeat
end repeat
http://www.macupdate.com/app/mac/10387/sleepwatcher
I just did a test using Python + Appscript to do my scripting rather than Applescript and it continued to run without trouble on my system when either the user was suspended (i.e. going to the login window but with the user still logged in) or if the screen save was running. It was a simple script but presumably demonstrates what you needed to do.
Appscript comes with ASTranslate which translates Applescript calls into the equivalent Python + Appscript call. It doesn't handle variables but typically you can do a little cutting and pasting to figure out how to convert your script. It really goes quick and Python is a vastly superior language to script in than Applescript.
#!/usr/bin/python
import sys, os
from appscript import *
import time
def gettodos():
cs = app(u'iCal').calendars.get()
for c in cs:
print c.name()
tds = c.todos()
for t in tds:
print " ", t.summary()
def test():
for i in range(1,1000):
print
print "Run # " + str(i)
print
gettodos()
time.sleep(10)
if __name__ == '__main__':
test()
# change to 0 for success, 1 for (partial) failure
sys.exit(0)
I cannot reproduce your problem. I tried the following script and it worked fine even when the screensaver was running.
delay 10
tell application "Finder"
name of startup disk
end tell
delay 5
tell application "Finder"
contents of startup disk
end tell
The problem must depend on the specific commands your script is executing. What are they?

Resources