I would like to run this AppleScript handler in parallel two times (so I want two calls of tillSideBySideWindows("right") to run asynchronously and not after each other), is there a way to do it?
on tillSideBySideWindows(direction)
tell application "System Events"
set allVisibleProcessNames to name of processes whose visible is true
repeat with processName in allVisibleProcessNames
set windowsOfCurrentApp to every window of application process processName
repeat with currentWindow in windowsOfCurrentApp
set currentWindowsSize to size of currentWindow
set currentWindowsWidth to item 1 of currentWindowsSize
set currentWindowsPosition to position of currentWindow
set currentWindowsLeftPos to item 1 of currentWindowsPosition
if currentWindowsLeftPos = 0 then
if direction = "right" then
set currentWindowsWidth to currentWindowsWidth + 30
else
set currentWindowsWidth to currentWindowsWidth - 30
end if
set currentWindowsHeight to item 2 of currentWindowsSize
set winName to name of currentWindow
set size of window winName of application process processName to {currentWindowsWidth, currentWindowsHeight}
end if
if (currentWindowsLeftPos + currentWindowsWidth) = 1680 then
set currentWindowsHeight to item 2 of currentWindowsSize
if direction = "right" then
set currentWindowsLeftPos to currentWindowsLeftPos + 30
set currentWindowsWidth to currentWindowsWidth - 30
else
set currentWindowsLeftPos to currentWindowsLeftPos - 30
set currentWindowsWidth to currentWindowsWidth + 30
end if
set winName to name of currentWindow
set position of window winName of application process processName to {currentWindowsLeftPos, 0}
set size of window winName of application process processName to {currentWindowsWidth, currentWindowsHeight}
get currentWindowsWidth
end if
end repeat
end repeat
end tell
end tillSideBySideWindows
tillSideBySideWindows("right")
Related
Hoping someone can help with this – I'm running macOS Monterey on an Apple M1 Pro laptop. My AppleScript to send out batch text messages, stored on an Excel file, delivered through the Messages app is now not working – it worked fine on my old laptop operating under Catalina.
The problem appears to be in delivering the phone number ("targetBuddyPhone") into the proper location in the Messages app. Instead, the text message ("targetMessage") is being dropped into the recipient location in the app. Does anyone have any ideas on possible solutions?
Thanks in advance.
on run {input, parameters}
set phoneCol to "B"
set messageCol to "C"
set startRow to 1
set counter to "D"
set xlsFilePath to (path to desktop as text) & "texttest.xlsx"
tell application "Microsoft Excel" to open file xlsFilePath
tell application "Microsoft Excel"
set endRow to value of cell (counter & startRow) as number
end tell
repeat with thisRow from startRow to endRow
tell application "Microsoft Excel"
set targetBuddyPhone to string value of cell (phoneCol & thisRow) as string
set targetMessage to value of cell (messageCol & thisRow) as string
end tell
activate application "Messages"
tell application "System Events" to tell process "Messages"
key code 45 using command down -- press Command + N to start a new window
keystroke targetBuddyPhone -- input the phone number
key code 36 -- press Enter to focus on the message area
delay 3
keystroke targetMessage -- type some message
key code 36 -- press Enter to send
end tell
delay 6
end repeat
return input
end run
Since GUI scripting is always tightly tied to the version of the application, I recommend getting rid of it once and for all and using the following more durable solution:
on run {input, parameters}
set phoneCol to "B"
set messageCol to "C"
set startRow to 1
set counter to "D"
set xlsFilePath to (path to desktop as text) & "texttest.xlsx"
tell application "Microsoft Excel"
open file xlsFilePath
set endRow to value of cell (counter & startRow) as number
end tell
tell application "Messages"
activate
set SMSService to service named "SMS" -- YOU NEED THIS SERVICE
end tell
repeat with thisRow from startRow to endRow
tell application "Microsoft Excel"
set targetBuddyPhone to string value of cell (phoneCol & thisRow) as string
set targetMessage to value of cell (messageCol & thisRow) as string
end tell
tell application "Messages"
set theBuddy to buddy targetBuddyPhone of SMSService
send targetMessage to theBuddy
end tell
end repeat
return input
end run
I figured out the solution. To my GUI-based approach, I inserted delays into the script, which solved the problems.
on run {input, parameters}
set phoneCol to "B"
set messageCol to "C"
set startRow to 1
set counter to "D"
set xlsFilePath to (path to desktop as text) & "texttest.xlsx"
tell application "Microsoft Excel" to open file xlsFilePath
tell application "Microsoft Excel"
set endRow to value of cell (counter & startRow) as number
end tell
repeat with thisRow from startRow to endRow
tell application "Microsoft Excel"
set targetBuddyPhone to string value of cell (phoneCol & thisRow) as string
set targetMessage to value of cell (messageCol & thisRow) as string
end tell
activate application "Messages"
tell application "System Events" to tell process "Messages"
key code 45 using command down -- press Command + N to start a new window
delay 3
keystroke targetBuddyPhone -- input the phone number
delay 3
key code 36
delay 3
key code 36 -- press Enter to focus on the message area
delay 3
keystroke targetMessage -- type some message
delay 3
key code 36 -- press Enter to send
end tell
delay 6
end repeat
return input
end run
To Robert's solution, I changed one line (set SMSService to ...) and this script now works properly.
on run {input, parameters}
set phoneCol to "B"
set messageCol to "C"
set startRow to 1
set counter to "D"
set xlsFilePath to (path to desktop as text) & "texttest.xlsx"
tell application "Microsoft Excel"
open file xlsFilePath
set endRow to value of cell (counter & startRow) as number
end tell
tell application "Messages"
activate
set SMSService to 1st account whose service type = SMS -- YOU NEED THIS SERVICE
end tell
repeat with thisRow from startRow to endRow
tell application "Microsoft Excel"
set targetBuddyPhone to string value of cell (phoneCol & thisRow) as string
set targetMessage to value of cell (messageCol & thisRow) as string
end tell
tell application "Messages"
set theBuddy to participant targetBuddyPhone of SMSService
send targetMessage to theBuddy
end tell
end repeat
return input
end run
I'm a beginner working on a script that counts windows in locations on screen. So far it works fairly well, although one flaw is it counts windows that are minimized.
Here is the working code currently:
tell application "System Events"
set winCount1 to 0
set winCount2 to 0
set winCount3 to 0
set winCount4 to 0
set theProcesses to application processes
repeat with theProcess from 1 to count theProcesses
if visible of process theProcess is true then
tell process theProcess
repeat with x from 1 to (count windows)
if ((description of window x is not "dialog") then
set Pos to position of window x
if item 1 of Pos is less than -960 then
set winCount1 to winCount1 + 1
else if item 1 of Pos is less than 0 then
set winCount2 to winCount2 + 1
else if item 1 of Pos is less than 960 then
set winCount3 to winCount3 + 1
else
set winCount4 to winCount4 + 1
end if
end if
end repeat
end tell
end if
end repeat
set countList to {winCount1, winCount2, winCount3, winCount4}
return countList
end tell
Now to try to solve this issue, I tried adding a new condition:
if ((description of window x) is not "dialog") and window x is not miniaturized then
But this returns the error stated in the title. So I tried:
set props to get properties of window x
if props contains miniaturized then
This returns the same error.
I also tried:
set props to get properties of class of window x
if props contains miniaturized then
Same error.
It can't be that difficult to avoid windows without the miniaturized property before testing for it, but I'm not having luck finding a solution. Any ideas?
Get the value of attribute "AXMinimized" of the window, like this:
set winCount1 to 0
set winCount2 to 0
set winCount3 to 0
set winCount4 to 0
tell application "System Events"
repeat with theProcess in (application processes whose visible is true)
tell theProcess
repeat with thisWin in windows
if (description of thisWin is not "dialog") and not (value of attribute "AXMinimized" of thisWin) then
set Pos to position of thisWin
if item 1 of Pos is less than -960 then
set winCount1 to winCount1 + 1
else if item 1 of Pos is less than 0 then
set winCount2 to winCount2 + 1
else if item 1 of Pos is less than 960 then
set winCount3 to winCount3 + 1
else
set winCount4 to winCount4 + 1
end if
end if
end repeat
end tell
end repeat
end tell
return {winCount1, winCount2, winCount3, winCount4}
So for an infinite monkey theorem test i need applescript to input random numbers (0-6) into TextEdit.
I have a working code which doesn't slow down the cpu or anything, but i can't terminate it after running it once without terminating TextEdit.
So my question is:
How can i improve this code so it allows me to terminate it without any concerns.
delay 2
repeat
delay 0.2
tell application "System Events"
if (item 1 of (get name of processes whose frontmost is true)) is "TextEdit" then
set r to (random number from 0 to 1)
if (r = 0) then
keystroke "0"
else if (r = 1) then
keystroke "1"
end if
end if
end tell
end repeat
It will take a long time to create a large sample with a .2 delay and keystrokes.
Try something like this:
set csvOutputPath to (POSIX path of (path to desktop as text)) & "test.txt"
set fileRef to (open for access csvOutputPath)
close access csvOutputPath
set numberList to {}
set counter to 0
repeat
set end of numberList to (random number from 0 to 1)
set counter to counter + 1
if (counter mod 10000) = 0 then
write (numberList as text) to csvOutputPath starting at eof
set numberList to {}
end if
end repeat
I know virtually nothing about AppleScript and could do with some help.
While running, my broadcast playout system (MegaSeg) writes details of the track currently playing to a textfile called "NowPlaying" which contains solely the following contents, each on its own line and without square brackets:
Title: [title]
Artist: [artist]
Album: [album]
Time: [time in some format or other]
I want to pass this to my broadcast streamer LadioCast, which can be addressed via AppleScript, so that it sends info on what is playing to the streaming server.
MegaSeg doesn't support Applescript calls like 'tell application "MegaSeg"... set trackName to name of current track' so I can't do it that way. I have no idea about how to do this.
If we imagine that I was able to grab that info, this is what I would do with it:
set lastName to ""
set lastArtist to ""
set lastAlbum to ""
repeat
** insert missing file reading section here
** in the following, "title", "artist" and "album" are from the text file **
set trackName to title
set trackArtist to artist
set trackAlbum to album
** end of missing section
if trackName is not lastName and trackArtist is not lastArtist and trackAlbum is not lastAlbum then
set lastName to trackName
set lastArtist to trackArtist
set lastAlbum to trackAlbum
tell application "LadioCast"
set metadata song to trackName & " – " & trackArtist & " – " & trackAlbum
end tell
end if
delay 15
end repeat
Thanks in advance.
--Richard E
===
I tried the suggestions from #DigiMonk and they were very helpful, but not all of them worked. First, the file is in a specific location and not on the desktop; second, I could not get 'trim_line' to work at all - I got "script does not understand trim_line message". However the text in the file seems to be already trimmed.
The script below nearly works; when run from the Applescript Editor it does seem to get the Title, Artist and Album into the variables. However when I try running it from LadioCast I get an EOF -39 error. More importantly, as soon as I run this, MegaSeg stops updating the file, forever. I am presumably locking the file to read from it and stopping MegaSeg writing to it. How do I avoid this?
set lastName to ""
set lastArtist to ""
set lastAlbum to ""
set lastTime to ""
set trackName to ""
set trackArtist to ""
set trackAlbum to ""
set sourcePath to ""
repeat
set sourcePath to open for access file "Library:MegaSeg User Data:Logs:Logs for MegaSeg System (4):NowPlaying"
set thisText to read sourcePath as text
close access file "Library:MegaSeg User Data:Logs:Logs for MegaSeg System (4):NowPlaying"
set the paragraphList to every paragraph of thisText
repeat with i from 1 to number of items in paragraphList
set thisItem to item i of paragraphList
if thisItem starts with "Title:" then
set x to the offset of "Title:" in thisItem
set trackName to (text (x + 6) thru -1 of thisItem)
else if thisItem starts with "Artist:" then
set x to the offset of "Artist:" in thisItem
set trackArtist to (text (x + 7) thru -1 of thisItem)
else if thisItem starts with "Album:" then
set x to the offset of "Album:" in thisItem
set trackAlbum to (text (x + 6) thru -1 of thisItem)
end if
end repeat
if trackName is not lastName and trackArtist is not lastArtist and trackAlbum is not lastAlbum then
set lastName to trackName
set lastArtist to trackArtist
set lastAlbum to trackAlbum
tell application "LadioCast"
set metadata song to trackName & " – " & trackArtist & " – " & trackAlbum
end tell
end if
delay 15
end repeat
May be this helps: (feed sourcePath with the path to your NowPlaying.txt file)
set sourcePath to (path to desktop) & "NowPlaying.txt" as text
set thisText to my readFile(sourcePath)
set the paragraphList to every paragraph of thisText
set lastName to ""
set lastArtist to ""
set lastAlbum to ""
set lastTime to ""
repeat with i from 1 to number of items in paragraphList
set thisItem to item i of paragraphList
--log thisItem
if thisItem starts with "Title:" then
set x to the offset of "Title:" in thisItem
set y to (text (x + 6) thru -1 of thisItem)
set lastName to my trim_line(y, " ", 2)
else if thisItem starts with "Artist:" then
set x to the offset of "Artist:" in thisItem
set y to (text (x + 7) thru -1 of thisItem)
set lastArtist to my trim_line(y, " ", 2)
else if thisItem starts with "Album:" then
set x to the offset of "Album:" in thisItem
set y to (text (x + 6) thru -1 of thisItem)
set lastAlbum to my trim_line(y, " ", 2)
else if thisItem starts with "Time:" then
set x to the offset of "Time:" in thisItem
set y to (text (x + 5) thru -1 of thisItem)
set lastTime to my trim_line(y, " ", 2)
end if
end repeat
log "lastName = '" & lastName & "'"
log "lastArtist = '" & lastArtist & "'"
log "lastAlbum = '" & lastAlbum & "'"
on readFile(thisFile)
set thisFile to thisFile as text
if thisFile is "" then return ""
try
set fi to open for access file the thisFile
set myData to read fi as text
close access file the thisFile
return myData
on error
try
close access file the thisFile
return ""
end try
end try
end readFile
on trim_line(this_text, trim_chars, trim_indicator)
-- 0 = beginning, 1 = end, 2 = both
set x to the length of the trim_chars
-- TRIM BEGINNING
if the trim_indicator is in {0, 2} then
repeat while this_text begins with the trim_chars
try
set this_text to characters (x + 1) thru -1 of this_text as string
on error
-- the text contains nothing but the trim characters
return ""
end try
end repeat
end if
-- TRIM ENDING
if the trim_indicator is in {1, 2} then
repeat while this_text ends with the trim_chars
try
set this_text to characters 1 thru -(x + 1) of this_text as string
on error
-- the text contains nothing but the trim characters
return ""
end try
end repeat
end if
return this_text
end trim_line
Having trouble figuring out this loop - I want the below function to repeat ONLY if myText changes (i.e. the album the individual is listening to changes) - I have been able to make it loop a certain number of times or repeat in the event the track changes, but I want it to repeat in the event the album changes.
tell application "iTunes"
repeat if myText changes
if player state is playing then
set albumName to (get album of current track)
set myText to text 1 thru 10 of albumName
end if
end repeat
end tell
open location "http://bandsite.com/shows/" & myText
When the code works without the repeat command it looks like this:
tell application "iTunes"
if player state is playing then
set albumName to (get album of current track)
set myText to text 1 thru 10 of albumName
end if
end tell
open location "http://bandsite.com/shows/" & myText
I need the whole function to repeat in the event myText changes
Save this as a stay open application:
property myList : {}
on run
set albumA to my playCheck()
if albumA ≠ false then
set end of myList to albumA
else
quit -- Quit on the next idle.
return 1 -- Please send the next idle as soon as possible.
end if
end run
on idle
set albumA to my playCheck()
if albumA ≠ false then
set end of myList to albumA
if (item -1 of myList) ≠ (item -2 of myList) then
open location "http://bandsite.com/shows/" & (text 1 thru 10 of albumA)
end if
end if
return 3
end idle
on playCheck()
tell application "iTunes"
if player state is playing then return (get album of current track)
return false
end tell
end playCheck
temptext = mytext
do
if temptext != myText
tell application "iTunes"
if player state is playing then
set albumName to (get album of current track)
set myText to text 1 thru 10 of albumName
end if
end tell
temptext = myText
end if
while temptext==text
Try this
Hope this is what you want...