applescript screen-shot automator buggy when exported as .app - applescript

so, I am making an app that takes screenshots at a regular interval for a customizable amount of time. I'm having a hard time with it because when I run the app in the applescript editor, everything is fine - but when I export it to an .app, things are buggy, and if the user clicks on the app icon, it will trigger the "repeat" code, and if the user tries to quit, it behaves erratically.
I read in other posts that on idle could work, but I don't know how to end an idle handler after a specified amount of time.
Anybody knows the solution to my conundrum? Thank you!
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set chosenDurationSeconds to chosenDuration * 60
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
set repeatNumber to chosenDurationSeconds / chosenFrequencySeconds
display dialog "Great! I'll take " & repeatNumber & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
repeat repeatNumber times
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture \"" & FolderPath & "Screen Shot" & theCurrentDate & ".png\""
do shell script shellCommand
delay chosenFrequencySeconds
end repeat
end run

Here's how you would write your code with an "on idle" handler (I didn't test it). Remember to save this as a "stay open application". Notice that you tell the on idle handler to repeat in seconds in the last line of the handler. Notice also that we quit the app at the calculated date rather than repeating a number of times. You could essentially make a counter to count the loops of the idle handler but the date method is easier. Finally notice we have global variables. This makes the variables initiated in the on run handler available to the on idle handler.
Good luck.
global quitTime, chosenFrequencySeconds, FolderPath
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set quitTime to (current date) + chosenDuration * minutes
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
display dialog "Great! I'll take " & repeatNumber & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
end run
on idle
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture " & quoted form of (FolderPath & "Screen Shot" & (theCurrentDate as text) & ".png")
do shell script shellCommand
if theCurrentDate is greater than or equal to quitTime then tell me to quit
return chosenFrequencySeconds
end idle

Maybe you should try to implement a reopen handler. I have done so with regulus's code, and it worked for me, if the applet is installed in the dock, then it starts the first, time, if it is clicked later on, you'll get a message that it is already running. The reopen handler probably have some superfluos code, like testing for if the app is running, and activating it, since the reopen handler should only be triggered when the app is already running. But I'll leave that for you, at least it doesn't execute the run handler now. :)
global quitTime, chosenFrequencySeconds, FolderPath
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set quitTime to (current date) + chosenDuration * minutes
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
display dialog "Great! I'll take " & chosenFrequency & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
end run
on idle
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture " & quoted form of (FolderPath & "Screen Shot" & (theCurrentDate as text) & ".png")
do shell script shellCommand
if theCurrentDate is greater than or equal to quitTime then tell me to quit
return chosenFrequencySeconds
end idle
on reopen
if running of me then
tell me
activate
display alert "Already running"
end tell
end if
end reopen

Related

Making a dialog that bugs me in Applescript

I know this question is kinda messy. I don't know how to make it more specific. I want to make an applescript that asks me every hour what I've been doing for the past hour.
The issue I'm having is that I want it to pop up, make a sound, and wait for my response. If I do a normal dialog, and I'm busy, it will go behind the other windows on my mac. I thought maybe having a persistent banner notification would be great, but applescript doesn't allow for much control over banners.
I want something to float over all windows so that I can see that the applescript has been waiting for a response from me until I fill out the dialog.
What you're looking for is a global floating window, similar to what LittleSnitch does. You can do that, but not with pure AppleScript. You'd have to write a Cocoa app.
Adding an activate command just before a display dialog command in your AppleScripts, will ensure the pop-up dialog window will become frontmost and visible no matter what other apps and documents are currently opened (until another app or document gets activated, thus bringing that item to the front).
This following AppleScript may be of some use to you.
Save this following AppleScript code as a "stay open application" in Script Editor.app.
When running your new AppleScript applet, it will remain running (because it has an idle handler) until you press "Cancel" in any of the dialog pop-ups or choosing to quit the app in the Dock.
This code also logs everything it receives in the dialog pop-ups, to file for you.
property myComputerActivitiesLog : (path to desktop as text) & "My_Computer_Activities.log"
property theDialog : missing value
property theDate : missing value
property insertTime : missing value
property logContent : missing value
on idle
set theDate to (current date)
set insertTime to " ------ " & theDate & " ------ "
beep 5
say "It's time to log your activities"
activate
try
set theDialog to display dialog ¬
"Itemize my activities." default answer ¬
"Itemize my activities for yhe past hour." & linefeed & linefeed ¬
buttons {"Cancel", "OK"} default button 2 cancel button 1 ¬
with title "Account For My Activities" with icon 1
end try
if theDialog = missing value then
quit me
else
set logContent to insertTime & linefeed & (text returned of theDialog) & linefeed
do shell script "echo " & quoted form of logContent & ¬
" >> " & quoted form of POSIX path of myComputerActivitiesLog
set theDialog to missing value
return 3600 -- in seconds
end if
end idle
on quit -- Executed when the script quits
-- Additional code to perform (if any) goes here
continue quit -- allows the script to quit
end quit

How to make application written using AppleScript to open the dialog each time the icon is clicked?

I'm writing an applescript application that would say time every 5 mins. This will be in an infinite loop. My requirement is, although it is running 24x7 since start, next time when I click application icon, it should show the dialog to get user input via one of the 3 buttons.
I have 3 buttons.
Pause Notifications
Notifications ON
Notification OFF
When the code is in infinite loop, and I click the application icon, the dialog prompt doesn't come up to get the user input via above 3 buttons. How to fix that?
global isSoundEnabled, isNotifEnabled
on run
set isSoundEnabled to true
set isNotifEnabled to true
set theDialogText to "The curent date and time is " & (current date) & "."
display dialog theDialogText buttons {"Pause", "Notif ON", "Notif OFF"} default button "Notif ON" cancel button "Pause" with icon caution
if result = {button returned:"Notif ON"} then
set isSoundEnabled to true
set isNotifEnabled to true
loop()
else if result = {button returned:"Notif OFF"} then
set isSoundEnabled to false
set isNotifEnabled to false
end if
end run
on loop()
repeat while true
set min to getMin()
get min as integer
#if (min mod 5) = 0 then
if (min / 5) > 1 then
set timee to getTimeInHoursAndMinutes()
if isNotifEnabled then
display notification timee
end if
if isSoundEnabled then
say timee
end if
#delay 60
#if isSoundEnabled is not
end if
#exit repeat
end repeat
end loop
I haven't added getTimeInHoursAndMinutes() and getMin() implementation on purpose as it doesn't much value.
The application user interface (menus, etc) will be blocked if you don’t give the system time to process events, so you want to avoid long repeat loops. The standard dialogs are modal, so you also normally can't do other things while they are being shown.
Repeatedly showing the standard dialogs can also be intrusive, since the current application will switch if activating the application (to show the dialog), or the Dock icon will start bouncing if you don't. Some AppleScriptObjc could be used for other types of notifications, but for this example I stayed with the standard dialogs.
I did cheat a little in the following script by using some AppleScriptObjC for the speech synthesizer, since it can speak in the background (while a dialog is shown). I've also avoided using notifications, since those need to be allowed in the System Preferences.
The bottom line is that when saving an app as stay open, the idle and reopen handlers can be used - the idle handler is repeatedly called after the run handler finishes (it uses a timer), and the reopen handler is called when the app is double-clicked (or the Dock icon clicked), so you can avoid locking up the UI. For example:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "AppKit" -- for the speech synthesizer
use scripting additions
global isSoundEnabled, isNotifEnabled, defaultButton
on run -- initial setup
set isSoundEnabled to true
set isNotifEnabled to true
set defaultButton to "Notif OFF" -- the default is set opposite the current setting
getSettings()
end run
to getSettings()
set theDialogText to "The curent date and time is " & (current date) & "."
tell me to activate
set theButton to button returned of (display dialog theDialogText buttons {"Quit", "Notif ON", "Notif OFF"} default button defaultButton with icon caution giving up after 10)
if theButton is "Notif ON" then
set isSoundEnabled to true
set isNotifEnabled to true
set defaultButton to "Notif OFF"
else if theButton is "Notif OFF" then
set isSoundEnabled to false
set isNotifEnabled to false
set defaultButton to "Notif ON"
end if
end getSettings
on reopen -- application double-clicked or dock icon clicked
getSettings()
end reopen
on idle -- after the run handler completes, is called repeatedly
set giveup to 5 -- dialog will self-dismiss, although timing will be a little off if manually dismissed
set theTime to time string of (current date)
if isSoundEnabled then -- AppleScriptObjC is used to speak in the background
(current application's NSSpeechSynthesizer's alloc's initWithVoice:(missing value))'s startSpeakingString:theTime
end if
if isNotifEnabled then
tell me to activate
display dialog "The current time is " & theTime with title "Current time" buttons {"OK"} giving up after 5
end if
return 300 - giveup -- the number of seconds for next idle run (less the dialog giveup time)
end idle

AppleScript does not work in app save window

I have an AppleScript that works perfectly in finder. It creates a folder named with the days date and has a shortcut key connected to it.
But it does not work when in another app, in the save window. Can you please help.
Here is the code I have.
tell application "Finder"
try
if exists Finder window 1 then
set thisPath to (the target of the front window) as alias
else
set thisPath to (path to desktop)
end if
on error
return
end try
end tell
set x to my the_perfect_datestring()
if x is not "-ERROR" then
set fullPath to thisPath & x as text
tell application "Finder"
try
--activate
if not (exists fullPath) then
set y to make new folder at thisPath with properties {name:x}
end if
activate
end try
end tell
end if
on the_perfect_datestring()
try
set cd to (the current date)
set the_year to year of (cd) as number
set the_month to month of (cd) as number
set the_day to day of (cd) as number
if the_month < 10 then set the_month to "0" & the_month
if the_day < 10 then set the_day to "0" & the_day
return ((the_year & "-" & the_month & "-" & the_day) as string)
on error
return "-ERROR"
end try
You cannot access the settings in a Save dialog box with the Finder AppleScript terminology.
The only way with AppleScript is System Events and GUI scripting. The script syntax depends strongly on the particular UI.
To work with save dialogs in other applications, you would need to change your workflow a bit. The save dialog works with text (the file/folder name), so you can create a text service to paste in the desired string.
To create a service, start up the Automator application and select the Service (Quick Action) document - the workflow will have settings that determine what kind of input it will accept, for example:
Workflow receives current text in any application
Next, check the Output replaces selected text box - this will replace selected text with the output of your workflow.
Drag a Run AppleScript action into the workflow, and completely replace the default contents with a new Run handler and your date string handler, for example:
on run {input, parameters}
set x to the_perfect_datestring()
if x is not "-ERROR" then return x
end run
on the_perfect_datestring()
try
# do your filename stuff
tell (current date) as «class isot» as string
return text 1 thru 10
end tell -- or whatever
on error
return "-ERROR"
end try
end the_perfect_datestring
After you save the workflow, the service should be available any time you select some text (in the right-click context menu).
An equivalent to your original workflow with the Finder would then be to create a new folder, and use the service on the highlighted “untitled folder” name to change it.

AppleScript Prompt User for Clicks

For my studies I use a lot the screencapture feature as a terminal command. Recently I started to use AppleScript to automate some of those screen captures. But now I would like to push the thing a bit further.
Is it possible to use a command such as "display dialog", but to query 2 clicks, of which the coordinates would be assigned to the screencapture command so that it takes the picture of the screen?
I was thinking of something like this:
set click1 to "0,0"
set click2 to "0,0"
display dialog "Click where the screen area to grab begins" & click1
display dialog "Click where the screen area to grab begins" & click2
do shell script "screencapture -R click1,click2 /Users/user/Desktop/name_of_the_file.png"
Applescript does not have any mechanism for capturing mouse clicks, or even getting the position. You can get the mouse position using a call to the framework.
But, you will have to resort to a cocoa app solution to capture screen clicks.
One idea is you could use an applescript flow that gives you 2 seconds to place the first mouse position, then it can beep to tell you it has captured it, and then you have two more seconds to place the pointer in the second position before it captures it.
Something like this:
use framework "Foundation"
use scripting additions
display dialog "Place your mouse pointer in the first position within 2 seconds, then after the beep, place it in the second position within 2 seconds."
delay 2
set theList to current application's NSEvent's mouseLocation()
set xCoord1 to theList's x
set yCoord1 to theList's y
beep
delay 2
set theList to current application's NSEvent's mouseLocation()
set xCoord2 to theList's x
set yCoord2 to theList's y
beep
display dialog (((xCoord1 as string) & ", " & yCoord1 as string) & return & xCoord2 as string) & ", " & yCoord2 as string

"giving up after" command not fully working in Mavericks

I encountered a mysterious bug with AppleScript and OSX 10.9.1.
This code works inside AppleScript Editor, but when I save it as an application, "giving up after" doesn't work. It works in my other computer with 10.6.8 (Snow Leopard) though. Does anyone know what's the issue? Thanks!
global fullTime
global chosenTime
set pickFromList to {1, 2}
choose from list the pickFromList with prompt "Next message will dissapear after 1 + x seconds. Choose x!"
set chosenTime to result as text
add1sec()
display dialog "Click OK and the next dialog box will appear in " & fullTime & " seconds"
delay fullTime
display dialog "Works! But now this should dissapear after " & fullTime & " seconds" giving up after fullTime
on add1sec()
set fullTime to chosenTime + 1
end add1sec
I would write it like this:
set pickFromList to {1, 2}
set chosenTime to (choose from list the pickFromList with prompt "Next message will dissapear after 1 + x seconds. Choose x!") as number
set fullTime to add1sec(chosenTime)
display dialog "Click OK and the next dialog box will appear in " & fullTime & " seconds"
delay fullTime
tell application "SystemUIServer" to display dialog "Works! But now this should dissapear after " & fullTime & " seconds" giving up after fullTime
on add1sec(startTime)
return startTime + 1
end add1sec
Hmm, this actually did solve the "giving up after" -problem, but it also created another one. Now that this is used:
tell application "SystemUIServer" to display dialog "Works! But now this should disappear after " & fullTime & " seconds" giving up after fullTime
First of all, the dialog box is not "connected" to the running application anymore, so that I can't make it active by clicking the application icon in dock. Second, if "giving up after" is longer than 2 minutes the default timeout occurs.
Updating to OSX 10.9.2 fixed this issue.

Resources