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!!
Related
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.
The following script will open a track in iTunes
use application "iTunes"
property trackURL : "itmss://itunes.apple.com/us/album/brahms-violin-concerto-in-d-major-op-77-iii-allegro/145533236?i=145533044&uo=4"
open location trackURL
Now, asking "iTunes" to play it does not work because the track is highlighted but not properly selected, i.e., it requires a manual mouse click to select it and play it.
How can I select the highlighted track? Or how could I ask "iTunes" to play the song?! Alternatively, is there a way to add a music to my library from an URL directly?
Disclaimer: I don't have the Apple Music subscription, so the UI on my end may not be exactly the same as yours. However, if I click the "Play" button, I get the little advertisement asking me to sign up for the service, which I assume would just play the music if you had the service. So, these are the steps I've been able to follow to get that box to pop up:
The first, and most convenient from AppleScript, thing to try is just to hit the space bar to start the music playing. This actually works great if I've selected the item manually by clicking on it. However, after open location, it doesn't work, and this appears to be because even though the row is highlighted in the viewer, the actual keyboard focus seems to be on the page itself (the iTunes Store and Apple Music appear to have their entire UI presented as web pages rendered by WebKit). You can verify this by tapping the up and down arrow keys on the keyboard; the page scrolls up and down instead of you switching to adjacent tracks.
My opinion is that this is actually a bug in iTunes; I'd consider the true solution to the problem to be to report this to Apple via the bug reporter. Using open location really should set the keyboard focus to the track you navigated to.
With that said, we can work around it in the short term by simulating a click on the "Play" button. Note that you'll probably need to add your app in System Preferences > Security and Privacy > Accessibility. Note also that this is incredibly fragile, and if Apple ever changes anything in the layout of the web pages they're serving, this whole thing will break. Finally, please note that this code is extremely ugly; the whole thing gives me hives just by looking at it, but it's the only thing I was able to get to work. Side effects of reading this code may include nausea, headaches, and suicidal thoughts. Do not read this code immediately after eating. Consult your doctor before reading this code if you have a history of depression or obsessive-compulsive disorder.
property trackURL : "itmss://itunes.apple.com/us/album/brahms-violin-concerto-in-d-major-op-77-iii-allegro/145533236?i=145533044&uo=4"
property trackTitle : "III. Allegro giocoso, ma non troppo vivace"
tell application "iTunes"
activate
open location trackURL
delay 1 -- give the page a second to load
end tell
tell application "System Events"
tell process "iTunes"
set theRows to the rows of table 1 of UI element 1 of scroll area 1 of group 1 of group 1 of front window
-- "repeat with eachRow in theRows" isn't working. I don't know why. Freaking AppleScript
repeat with i from 1 to the number of theRows
set eachRow to item i of theRows
if exists group 2 of UI element 2 of eachRow then
if value of static text 1 of group 1 of group 2 of UI element 2 of eachRow is trackTitle then
tell group 1 of UI element 2 of eachRow to click
end if
end if
end repeat
end tell
end tell
If Apple ever fixes the bug, of course, we should be able to just:
tell application "iTunes"
activate
open location trackURL
delay 1 -- give the page a second to load
end tell
tell application "System Events" to keystroke space
I am looking for a script that will place the cursor in the text field in the Messages App. I have looked for a keyboard shortcut to do this but cannot find one. Can anyone provide a script, or a similar one I can modify.
NB I am not a programmer or very familiar with AppleScript, but have been able to modify scripts that are close to my needs.
I need this as I am trying to make the messages app controllable using the built in dictation feature in Mac OS. I need a script I can assign to a voice command to place the cursor in the text field so that I can then dictate a message.
Many thanks.
If you are using dictation commands, in any application all you need to do is say the command “Show Numbers” and you will see this:
Then you would just say the command “Twenty” which will place your cursor right where you want it… in this case it would be the text field
Also speaking the command “Show Comands” Will open up this window listing tons of dictation commands.
The following was tested and works under OS X 10.8.5 and Messages 7.0.1 and may need to be adjusted for other versions of OS X/macOS/Messages:
tell application "Messages"
activate
tell application "System Events"
set focused of text area 1 of scroll area 4 of splitter group 1 of window 1 of application process "Messages" to true
end tell
end tell
Note: This is coded with the assumption that Messages is already open with an open window. Additional coding will be necessary, in the form of try and or delay and or on error statements as needed and appropriate otherwise.
Here's an example of how I'd code it otherwise, which handles whether or not Messages is open, has its window showing, etc.
on setFocusToTextArea()
tell application "System Events"
if (count of windows of application process "Messages") is equal to 0 then
click UI element "Messages" of list 1 of application process "Dock"
delay 0.25
end if
try
set focused of text area 1 of scroll area 4 of splitter group 1 of window 1 of application process "Messages" to true
end try
end tell
end setFocusToTextArea
tell application "Messages"
if running then
my setFocusToTextArea()
else
activate
delay 2
my setFocusToTextArea()
end if
activate
end tell
Note: If Messages is closed when this script is run, the delay 2 command gives time for Messages to open before the other code runs. The value of the delay command can be adjusted as appropriate for the speed of your system.
The scenario I have is that the new windows opens, and the script executes inside it. I am looking for a way how to come back to the previous active window and did try these 2 ways:
1. Executing keyboard shortcut
tell application "System Events" to keystroke "§" using command down
Note: Unpleasant experience since the slight flashback as a result of window swap.
2. Giving lastWindow personal ID and later bringing it to the front
set lastWindow to id of window 1
...
set index of window id lastWindow to 1
Note: When the lastWindow is changed it becomes visible but inactive state, and requires an additional click on page to make it truly active
I did also try to change visible false of the newly created window, but it results in making it minimized and slowing the speed of background script execution.
Question. So is there a way to create new window and swap back to the last one while in a most "silent" way?
In reference to:
Note: When the lastWindow is changed it becomes visible but inactive state, and requires an additional click on page to make it truly active
The following example AppleScript code will raise the previous front most window to the top having full focus and be active. No additional click necessary.
tell application "Safari"
activate
set thePreviousFrontWindowID to id of front window
make new document with properties {URL:"https://www.google.com"}
delay 4 -- # The delay command is here as a placeholder for whatever you're doing in the new window.
set index of window id thePreviousFrontWindowID to 1
end tell
tell application "System Events" to perform action "AXRaise" of front window of application process "Safari"
It's the last line in this example AppleScript code that you need to get the window all the way to the top fully focused and active.
In reference to:
Question. So is there a way to create new window and swap back to the last one while in a most "silent" way?
Since windows don't make any sound when, for example, running the example AppleScript code above it couldn't be any more "silent" however, as far as minimizing visual distractions, that's so subjective that it almost should not have been asked. The fact is, there is always going to be some level of visual distraction as one moves though the windows of an app, manually or programmatically.
The only suggestion I have is, maybe set the bounds of the new window to that of the previous front window. Then when whatever is happening in the new and current front window is done and you bring the previous front window forward, you will see the entire window and none of the new window that's now behind it.
tell application "Safari"
activate
set thePreviousFrontWindowID to id of front window
set thePreviousFrontWindowBounds to bounds of front window
make new document with properties {URL:"https://www.google.com"}
set bounds of front window to thePreviousFrontWindowBounds
delay 4 -- # The delay command is here as a placeholder for whatever you're doing in the new window.
set index of window id thePreviousFrontWindowID to 1
end tell
tell application "System Events" to perform action "AXRaise" of front window of application process "Safari"
These are just examples to show how to get farther along then you were.
I am currently using applescript to setup various parameters of the desktops at my university. So far my script successfully changes the desktop background and the dock size.
The problem at hand is when I run the script, majority of the time, the icons on the desktop never change.
Here is the script I wrote to alter the desktop icon's size and grid spacing:
tell application "System Events"
set finderPrefsFile to property list file "~/Library/Preferences/com.apple.Finder.plist"
tell finderPrefsFile
tell property list item "DesktopViewSettings"
tell property list item "IconViewSettings"
set value of property list item "gridSpacing" to "100"
set value of property list item "iconSize" to "32"
set value of property list item "arrangeBy" to "none"
end tell
end tell
end tell
end tell
#Restart Finder for changes to take effect.
do shell script "killall Finder"
How should I go about altering the script to make it work all the time (I would like to eventually share this script with some of my classmates).
P.s.
Here is the full script
I didn't get your script work reliable. I played around with timeouts but didn't get the Finder to refresh using the new settings.
But I found to set some view options directly using vanilla AppleScript:
tell application "Finder"
activate
set iconViewOptions to desktop's window's icon view options
tell iconViewOptions
set arrangement to not arranged
set icon size to 32
set shows item info to false
set shows icon preview to false
end tell
quit
end tell
delay 1
tell application "Finder" to activate
The AppleScript quit-handler works more reliable then do shell script "killall Finder", maybe the killall is too hard...
The delay 1 does the magic to give the Finder the time to breath before get up again and using it the Script works each time...
But one thing is AFAIK not possible in Finder scripting: Setting the grid space :-/
Greetings, Michael / Hamburg