My AppleScript used to work to take multiple screenshots of a specified area in Safari. Now I get an error message: Safari got an error. No file specified.
What is wrong?
I open Safari in the full screen mode, then it automatically takes a new screenshot of this area every second. I would greatly appreciate some help!
repeat
tell application "Safari"
do shell script "date=$(date '+%Y%m%dT%H%M%S'); screencapture -x -R210,347,700,610~/Desktop/screen_${date}.png"
say "Click!"
end tell
delay 1
end repeat
In a shell script line parameters are separated by spaces so between the screen dimensions and the file path there must be a space character.
And do shell script and say don't belong to Safari.
repeat
do shell script "date=$(date '+%Y%m%dT%H%M%S'); screencapture -x -R210,347,700,610 ~/Desktop/screen_${date}.png"
say "Click!
delay 1
end repeat
Related
I have a massive spreadsheet with a titanic number of rows/columns (e.g. ~250 columns, many thousands of rows) that I'm trying to convert into PDFs by looping through each row with AppleScript, copying that row's ~250 variables to TextEdit set to Rich Text (for bold formatting etc), and then using System Events to save the txt as a PDF. Here's a summary of the code:
on run
set initialRow to 1
tell application "System Events"
tell application process "TextEdit"
set frontmost to true
end tell
end tell
repeat
tell application "Microsoft Excel"
-- CLEAR MY ~250 VARIABLES FROM PREVIOUS ROW'S VALUES TO MAKE SURE NOTHING IS CARRIED OVER BY MISTAKE
-- THEN SET MY ~250 VARIABLES TO THE NEXT ROW'S VALUES
if exampleValue is "" then exit repeat
end tell
tell application "TextEdit"
set the text of the front document to ""
-- THEN SET FIRST PARAGRAPH TO MY FIRST VARIABLE PLUS A LINE BREAK SO THEN THERE'S A NEW PARAGRAPH FOR THE NEXT VARIABLE, ETC
-- THEN GO THROUGH ALL OF MY VARIABLES TO IMPORT THE IMPORTANT ONES INTO TEXTEDIT, SET SOME FORMATTING, ETC.
end tell
delay 1
tell application "System Events"
click menu item "Export as PDF…" of menu 1 of menu bar item "File" of menu bar 1 of application process "TextEdit"
delay 1
keystroke exampleValue -- SYSTEM EVENTS TYPES THE NAME OF THE PDF
delay 1
key code 36
delay 1
end tell
set myRow to (myRow + 1)
end repeat
end run
This all runs great, no bugs (seemingly!), no issues at all in small doses. The problem, however, is that something happens as the script runs where it seems to be tying up more and more memory somewhere; everything is fine for the first hundred or so rows, but at some point my Mac stops running anything at all, i.e. whether I let the script run until it starts producing super random errors (I could collect them if helpful, but it's like a random different error each time so not much help there) or even if I let the script run for a while and then stop it before it errors out - it will let me stop the script but then I can't actually quit out of Script Editor or TextEdit or Excel, my keyboard stops working, I can't Force Quit anything, can't Reset the computer, etc. It's just a complete meltdown of the machine unlike anything I've encountered, and the only way to get back to work is to force a hard boot with the power button.
I've never had this problem with my other scripts, but I also don't usually use System Events, so my hunch is that it's something to do with that. Do I need to be 'resetting' System Events somehow, or clearing out the memory for some reason, or...? Thanks for the help!!
Figured it out! After trying the script one more time with Activity Monitor running, I discovered that each time it iterates through, 3 new processes were popping up - Core Sync, Dropbox Finder Extension, and SnailSVNLite - and then never going away! So if I ran through the script 500 times, I'd end up with 1500 new processes running, which was almost certainly what was wrecking me though I have no idea why telling System Events anything was doing that. I looked around online, and it turns out those are all Finder Extensions that had been turned on at some point long ago, so just needed to go to System Preferences > Extensions > Added Extensions and then uncheck those 3 extensions - and then problem solved!!
I have an apple script like this
#!/bin/zsh
tell application "iTerm"
activate
select first window
# Create new tab
tell current window
create tab with default profile
end tell
# Split pane
tell current session of current window
split vertically with default profile
split vertically with default profile
split vertically with default profile
end tell
# Exec commands
tell first session of current tab of current window
write text "aws-vault exec my-role -d 12h --no-session"
write text "start him"
end tell
tell second session of current tab of current window
write text "start her"
end tell
tell third session of current tab of current window
write text "start you"
end tell
tell fourth session of current tab of current window
write text "start me"
end tell
end tell
the problem is the script doesn't wait for me to fill in the mfa information from aws command. I've also tried aws-command; start him but that just exits and doesn't execute start him at all. Anyone run into this before?
I don't think this is really possible, because Apple Script has no way of knowing that the aws command requires mfa information and if you are done typing that information.
But there are 2 very hacky ways in which you could achieve this:
Using delay
This option is probably very unreliable, but it may do the job.
You can use the delay command to make AppleScript wait X seconds until it runs write text "start him". Lets say it takes you around 10 seconds to type out the mfa information, then you would use delay 10. Below is how the code would look like.
# more code above...
tell first session of current tab of current window
write text "aws-vault exec my-role -d 12h --no-session"
delay 10 # <-- change this value to your liking
write text "start him"
end tell
# more code below...
Using display dialog
I personally feel this may be the most reliable option for you. What you can do is have a dialog box open and once you have typed out the mfa information, click "Ok" so that the script resumes. So you'd have something like this:
# more code above...
tell first session of current tab of current window
write text "aws-vault exec my-role -d 12h --no-session"
display dialog "Click Ok once you are done "
write text "start him"
end tell
# more code below...
Just a small warning: I haven't tested the above code as I do not own a macOS computer.
I have written an AppleScript to automate my work setup and just need the final touch. I copy something to clipboard in my script; I need to edit the text I copied to leave only the last line (preferably without opening an actual text editor application, as this would clutter my workspace) and just paste that line in the Google Chrome browser.
In the last step of my script so far I do something causing message text to be output to Terminal. Then I get the text visible in Terminal to be copied to the clipboard as follows:
tell application "Terminal"
tell front window
set the clipboard to contents of selected tab as text
end tell
end tell
Now I can for example paste it, and it's something like
...
[I 15:03:31.259 LabApp] Serving notebooks from local directory: /workspace
[I 15:03:31.259 LabApp] The Jupyter Notebook is running at:
[I 15:03:31.259 LabApp] http://1fw5c518af9:1932/?token=5e6d97b348fsy734gd
[I 15:03:31.259 LabApp] or http://88.0.0.1:1932/?token=5e6d97b348fsy734gd
[I 23:56:47.798 LabApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 23:56:47.803 LabApp]
To access the notebook, open this file in a browser:
file:///root/.local/share/jupyter/runtime-open.html
Or copy and paste one of these URLs:
http://1fw5c518af9:1932/?token=5e6d97b348fsy734gd
or http://88.0.0.1:1932/?token=5e6d97b348fsy734gd
This always ends with text of the format or *URL*, e.g. in the above example it would be or http://88.0.0.1:1932/?token=5e6d97b348fsy734gd. This is separated from the line above by a line delimiter plus some trailing white-space before "or".
What I need to do is grab that URL, start a Google Chrome browser and paste it in there.
For opening Google Chrome, it should be simple enough, the following code (from this tut) takes you to Instagram:
tell application "Google Chrome" to activate
tell application "System Events"
key code 37 using command down
delay 0.5
keystroke "https://www.instagram.com/instagram"
delay 1
key code 36
delay 1
end tell
and literally all I need is something which edits what's on the clipboard to just the *URL* (in the case of the above example, just http://88.0.0.1:1932/?token=5e6d97b348fsy734gd). After that I can paste it from the clipboard (where Instagram is typed in, in the tutorial).
After trying the lovely answer by #user3439894 below I found the situation is a bit more complicated:
there are an unpredictable number of blank lines "" after the final
link.
I'm also wondering whether there may be white-space at the end
as well
I already know the form of http://88.0.0.1 (it's always consistently this) so is there a way of maybe searching for that and then just grabbing it with the rest of the link that follows? (it would be great to be able to delimit the end by either " " or new-line)
Edit 2:
In case http://88.0.0.1... occurs multiple times, we would like to select just one of these URLs - they are probably generally the same, but selecting the last would be safest.
What I need to do is grab that URL, start a Google Chrome browser and paste it in there.
&
This always ends with text of the format or *URL*, e.g. in the above
example it would be or http://88.0.0.1:1932/?token=5e6d97b348fsy734gd. This is separated
from the line above by a line delimiter plus some trailing white-space
before "or".
&
In case http://88.0.0.1... occurs multiple times, we would like to
select just one of these URLs - they are probably generally the
same, but selecting the last would be safest.
If what you are trying to do is get the last URL that starts with http://88 from the contents of the selected tab of the front window in Terminal, then here is a way to do it without using the clipboard, and open it in Google Chrome, and also do it without having to use UI Scripting.
In other words, no need to alter the text on the clipboard or keystroke the URL as you can just tell Google Chrome what to use for the URL.
Example AppleScript code:
tell application "Terminal" to ¬
set theTextFromTerminal to ¬
the contents of ¬
the selected tab of ¬
the front window ¬
as text
set theURL to ¬
the last paragraph of ¬
(do shell script ¬
"grep -o 'http://88.*$' <<< " & ¬
theTextFromTerminal's quoted form & ¬
"; exit 0")
if theURL is "" then return
if theURL does not start with ¬
"http://88." then return
tell application "Google Chrome"
activate
delay 1
if exists front window then
make new tab at ¬
end of front window ¬
with properties {URL:theURL}
else
set URL of ¬
the active tab of ¬
(make new window) to theURL
end if
end tell
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.
I am working with Selenium on macOS to automate sending images using WhatsApp web in Google Chrome. The task involves uploading the image, and for that a system(Finder) prompt comes up to select the file. It's done in Windows using AutoIt.
I tried looking up how to automate this task in macOS, and I believe AppleScript can be used for it. Since I have no experience in GUI scripting, any help would be appreciated.
Thanks.
I was able to find the answer on another post on Stack Overflow. I have added the answer for anyone who comes across the same problem.
tell application "System Events"
keystroke "G" using {command down, shift down}
delay 1
keystroke "/path/to/file"
delay 1
keystroke return
delay 1
keystroke return
delay 1
end tell
I don't advocate GUI scripting any more than the burning down of the Amazon, but it seems to be necessary for this task, and I wanted to provide you with an example of a GUI script that tries its best to minimise the unpleasantness of the user experience, and aim for fewer weak points in the code where GUI scripts are most likely to falter.
If you know the path to your file—which I assume you do in these sorts of situations, as your script keystrokes the filepath—then you might find the following technique saves a few steps, and feels a bit more graceful in how it gets executed:
set filepath to "/path/to/image.jpg"
-- Copy file object to clipboard
set the clipboard to filepath as «class furl»
-- Make sure Chrome is in focus and the
-- active tab is a WhatsApp tab
tell application id "com.google.Chrome"
activate
if the URL of the active tab in the front window ¬
does not contain "web.whatsapp.com" then return
end tell
-- Paste the clipboard contents
-- and hit return (send)
tell application id "com.apple.SystemEvents"
tell (process 1 where it is frontmost) to tell ¬
menu bar 1 to tell menu bar item "Edit" to tell ¬
menu 1 to tell menu item "Paste" to set Paste to it
if (click Paste) = Paste then keystroke return
end tell
The if (click Paste) = Paste check should negate the need for a delay, as it explicitly forces AppleScript to evaluate the click command before going on to issue a keystroke. However, I can't test this under all possible conditions, and if there are other factors, like CPU usage, or process freezes, that are likely to give the script a chance to jump ahead, then just insert a small delay after then and move keystroke return down onto its own line.
If you wish to remove the file object from the clipboard afterwards, then simply add as the final line set the clipboard to (and just leave it blank after the word "to", which will clear the clipboard's contents). Of course, this won't affect any clipboard history data you might have if you use a clipboard managing app, only the system clipboard's current item.
I've been working on an application in Automator that changes the desktop background to the album art of the current song playing in iTunes.
You can download my first version here.
The most annoying issue I have found is that when there is a full screen app open on the same display being updated, whenever the song changes the background flickers between the current song and the previous.
This is my current code (Updated from version 1.0 above):
You may need to scroll within the code to see all of it.
tell application "System Events"
set fileName to (((path to desktop) as text) & ".iTunesArt2-1.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
set fileName to (((path to desktop) as text) & ".iTunesArt2-2.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
end tell
I got the actual code that saves the artwork to a file from here.
The desktop will not update unless you give it a new file name to update, therefore I have duplicated the process with "iTunesArt2-1" and "iTunesArt2-1".
The first 2 in '2-1' or '2-2' simply means the second desktop, as I have two different applications to change each desktop, and use my 2nd desktop for testing.
The entire application is set to loop for 1000 years, using three separate Loop functions in Automator (720 minutes, 730 times & 1000 times).
When first trying to debug this issue, the process was duplicated into four separate scripts, one for saving the image, then setting as background, and two more scripts to repeat the process with a new file name.
Here's an example of my debugging:
I remove the opening period from ".iTunesArt##.jpg" so that I can see the files on my desktop.
I play a Coldplay song and run the application in Automator to set the background.
"iTunesArt2-1.jpg" and "iTunesArt2-2.jpg" are shown on my desktop with the correct album art.
I stop the application, and play a Paramore song.
I run the first script of the application (Saves the album art).
"iTunesArt2-1.jpg" is updated to the Paramore artwork.
I run the second script of the application (Sets background image).
Note, this script should be setting the background to the Paramore image.
The background remains set to the Coldplay image.
At first I think this is only because the background image was already set to "iTunesArt2-1.jpg", and therefore the system will not try to update it again, not knowing the data in the file has been changed.
So I run the next script which should force the background to update:
I run the third script in the application.
"iTunesArt2-2.jpg" is updated to the Paramore artwork.
I run the forth script in the application.
The desktop background is updated to the Paramore artwork.
So, we can confirm that scripts 3 & 4 worked correctly.
According to the code, when the application loops back to scripts 1 & 2, the desktop background should remain as the Paramore artwork.
BUT...
I run the first script in the application.
"iTunesArt2-1.jpg" remains the Paramore artwork (as it should).
I run the second script in the application.
This script should update the desktop background from ""iTunesArt2-2.jpg" (Paramore) to "iTunesArt2-1.jpg" (Paramore).
The desktop background changes to the Coldplay artwork.
Now that makes zero sense at all.
This will happen every time I loop through the scripts.
Script 4 will change the desktop to Paramore and script 2 will change it back to Coldplay.
Remember this issue only happens when there is a full screen app open on the same display being updated. ie. A full screen app open on my primary display doesn't matter.
I have found sometimes that sliding over to the full screen app and 'activating' it will stop the flickering, and the background will be set correctly.
There surely is nothing 'wrong' with my code is there? If not, I need a way to get around this issue.
Specifically, is there a way of 'activating' every full screen app in the background without moving to those spaces?
I would love anyone who wants it to have this program, but it needs to be able to run under all circumstances.
Any help would be greatly appreciated.
Found a work around which creates a random file name each time, meaning the desktop can't get confused as to which image it is supposed to display.
screenNum refers to which screen the desktop is being set to.
set randID to screenNum
set randLoop to 0
repeat while randLoop is not 9
set randNum to (random number from 0 to 9) as text
set randID to randID & randNum
set randLoop to randLoop + 1
end repeat
Then included randID in the file name upon its creation.
Have not noticed any flickering using this method.
Note: This solves my problem, but does not answer my initial question of how one can activate a full screen app in the background.