I have an endless loop AppleScript application started at login. But there is a problem: I can not quit it unless im using SIGKILL. Is there any way to add some quit handler to it? Or there is better approach to make background process in AppleScript then "repeat - delay - end repeat"?
It doesn't sound like you're using an on idle handler, that's what you want to do.
on run
-- prep code goes here
end run
on idle
-- your code here
display dialog "TEST" giving up after 4
return 10
end idle
The above code will repeat itself every 10 seconds (based on the return value of 10, change as needed). The only other thing to keep in mind is this script needs to be saved as "Stay Open".
Hope this helps
Related
I have an AppleScript application in which I have a background task running in an infinite loop.
repeat while true
-- do some tasks
delay 0.5
end repeat
When I export and run the application, I am not able to quit it normally, instead I have to use the force quit. How am I able to fix this?
Instead of the infinite loop implement the on idle handler. It allows to consider the quit command.
on idle
-- do some tasks
return 1
end idle
However there is a restriction. The minimum interval is one second.
Forgive me if this turns out to be a dumb question, I've been writing cocoa apps for a long time but have only recently started to make them scriptable.
Scripting with this particular app is working well. But if the script has a loop like this...
tell application "myApplication"
repeat
set someProperty of someObject to someValue
delay 0.5
end repeat
end tell
(this is actually a script to cycle the colour of a connected bulb, so it does want to be an infinite loop.)
... no problem when everything's running on Mavericks. But on Yosemite, if the user interacts with myApplication's UI then things stop working. The script continues running (without things happening in myApplication) for a while before the script stops with a timeout (-1712)
The 'setter' for someProperty in the someObject class returns void and I've confirmed with messages to the console that it returns correctly every time it's called.
Is this behaviour expected? Is there something obvious I'm doing wrong?
I am wondering how to stop another function from a background function.
In addition, I have to drain NSAutoreleasePool, but I don't know how to do it.
I think this app sometimes freeze if I don't release pool.
property i : 0
property myLabel : missing value
on myStartButtonHandler_(sender)
my performSelectorInBackground_withObject_("start", missing value) -- This code prevents "Stop" Button from freezing.
end myStartButtonHandler_
on myStopButtonHandler_(sender)
-- I want to stop start() function and drain AutoreleasePool!
-- I don't want to use "quit me" because I want to stop only start() function.
end myStopButtonHandler_
on start()
repeat
set i to i + 1
myLabel's setIntegerValue_(i)
delay 1
end repeat
end start
You can download source code from here --> https://dl.dropboxusercontent.com/u/97497395/test2.zip
For your information, I am using Xcode 4.6.3.
EDIT
My script has delay 300 command, so I can't stop the function with checking the value of the variable. Sorry.
EDIT
I conceived of an idea to stop the function while delay commands.
on start()
repeat 5 times
if i = 1 then
error -128
else
delay 60
end repeat
end start
on myStopButtonHandler_(sender)
set i to 1
end myStopButtonHandler_
I can stop the function in 60 seconds, but I can't stop it as soon as I push the stop button. So, I am still waiting for your answer.
An easy way to stop the function is to have a variable. Check the value of the variable. If the variable is true for example then you can exit your repeat loop and drain the autorelease pool. I'm running to work now so no time to write code. Good luck.
EDIT: If you use an NSTimer to fire your handler, as opposed to a repeat loop, then you can invalidate the timer to stop it from running the handler. I use this to invalidate a timer because you should always check that the timer is valid before invalidating it... it will crash if you invalidate a non-valid timer.
-(void)deleteMyTimer {
if ([myTimer isValid]) {
[myTimer invalidate]
myTimer = nil;
}
}
I'm trying to write an Applescript that will make an outgoing Skype call at times scheduled by received invites from other parties.
I think I'm fine with the script to Skype's API to make the call, however I'm struggling with iCal with either method of
A) getting the script to run in the background and getting the time of all new events, or
B) getting the event alert to run a one-off script.
The issue with option B) is that although you can set events from within iCal so that the alert runs a script, I need to trigger this from events that have been received.
A typical example would be:
All scripts and iCal running on the Host
At 10am a User schedules an event (via google cal on portable device) for 3pm** and invites the the Host.
At 3pm the script on the Host uses Skype API to make a call to the User.
** this could just as equally be on a date in the future and the requirements still hold.
Many thanks for any advice!
Since iCal doesn't have any notifications (some applications do like iChat) you'll have to run a "stay open" applescript application. Something like this will do it for your "B" scenario. NOTE: you will have to add the path to your applescript file (the one that makes your Skype call) in the "applescriptPath" variable.
When launched it will get a listing of all the calendar events you have in iCal. It will then run itself every 5 minutes. When it runs it will check the current events against the list of events it originally made. If there are new events then your applescript will be added as an alarm to the new events. This way it keeps track of the current events between runs and only finds the new ones.
So this script should be a good starting point for you. Remember to save it as a stay-open applescript application. You probably will want to modify it. For example I have it checking every calendar for new events but you may have one particular calendar you want to target. Good luck.
property storedUIDs : {} -- we use this to check for new events, if an event is not in this list then it is new
global applescriptPath
on run
set applescriptPath to (path to desktop as text) & "myAlarm.scpt" -- the path to the applescript which is run as the alarm
end run
on idle
set newEvents to {}
tell application "iCal"
set theCals to calendars
set allUIDs to {}
repeat with aCal in theCals
tell aCal
set theseEvents to events
repeat with anEvent in theseEvents
set thisUID to uid of anEvent
set end of allUIDs to thisUID
if thisUID is not in storedUIDs then
set end of newEvents to contents of anEvent
end if
end repeat
end tell
end repeat
set storedUIDs to allUIDs
if (count of newEvents) is less than 5 then -- this will prevent the first run of the script from adding the alarm to every event
repeat with aNewEvent in newEvents
-- do something with this new events like add an alarm to run an applescript
set theAlarm to make new open file alarm at end of open file alarms of aNewEvent with properties {trigger interval:0, filepath:POSIX path of applescriptPath}
end repeat
end if
end tell
return (5 * 60) -- run every 5 minutes
end idle
on quit
set storedUIDs to {}
continue quit
end quit
I am writing a small applescript which retrieves all "unread" messages in the viewer and loops them.
I have two goals to complete:
I need to get the subject of each message and perform a regular expression to see if it's suitable for step 2 (ex: get emails with subject {.*})
I need to open each message on a separate window and after 4 seconds, I need to close that window and proceed with the next message
Do you know how to do these?
Thanks in advance.
The following applescript works for me, but I'm not sure how to do the regex matching. You can use the unix 'grep' function with applescript's 'do shell script' command, but I'm no expert in how to use grep properly. I'll leave that for someone else to answer.
on run
tell application "Mail"
set myInbox to mailbox "INBOX" of account 1
set myMessages to every message of myInbox
repeat with theMessage in myMessages
if read status of theMessage is false then
if my subjectIsInteresting(subject of theMessage) then
open theMessage
delay 4
close window 1
end if
end if
end repeat
end tell
end run
on subjectIsInteresting(subject)
-- do some regex magic here
return true -- for now
end subjectIsInteresting
For regexes -- If you're running the script on your own machine, or can distribute it bundled, you could use Satimage's Smile extension (http://www.satimage.fr/software/en/downloads/index.html) which adds regexes to Applescript.
I know you already have your answer but have you looked into Automator? For most standard scripts such as this, it can be less painful if you aren't too familiar with AppleScript. It's not very 'programmy' but it's quick and you'll spend less time debugging.