Localized menu bar item strings in iTunes - macos

The following code will disable shuffle mode in iTunes:
tell application "System Events"
tell process "iTunes"
click menu item "Off" of menu 1 of menu item "Shuffle" of menu 1 of menu bar item "Controls" of menu bar 1
end tell
end tell
However it only works if the system language is English.
I would prefer not to use indices, so I tried using localized string of on "Off", "Shuffle" and "Controls", but it doesn't seem to work.
Test code:
tell application "iTunes" to get localized string of "Shuffle"
Is there another way of getting the localized string or at least avoid having to hardcode the menu bar item indices?

You need to know the key's name because iTunes don't use the english menu's title as the key name.
To know the key name (the "Localizable.strings" file in the iTunes bundle is a plist format):
Open the TextWrangler application, drag the
"/Applications/iTunes.app/Contents/Resources/English.lproj/Localizable.strings"
file and drop it on the icon of the TextWrangler application.
Search "string>Shuffle<" in the document to get the key
name.
set iTunesPath to "/Applications/iTunes.app" as POSIX file as alias
set contr to localized string "8d2vvyy7c7" in bundle iTunesPath
set shuf to localized string "atmqaez8y8" in bundle iTunesPath
set off to localized string "ve0frz64yk" in bundle iTunesPath
activate application "iTunes"
tell application "System Events"
tell process "iTunes"
click menu item off of menu 1 of menu item shuf of menu 1 of menu bar item contr of menu bar 1
end tell
end tell

I opened the Accessibility Inspector in Xcode's Development Tools to see what objects I could find enumerating through UI elements
First I ran this to get a good idea, which returns the name I need to start, menu bar 1
tell application "System Events to tell process "iTunes"
UI elements
end tell
After this you can get a list of elements to work with, once you run tell menu bar 1 to display its UI elements.
{menu bar item "Apple" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "iTunes" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "File" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "Edit" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "View" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "Controls" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "Store" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "Window" of menu bar 1 of application process "iTunes" of application "System Events", menu bar item "Help" of menu bar 1 of application process "iTunes" of application "System Events"}
I'm thinking next you could do use what is returned here to iterate through and find the item, store this in a variable and make it less dependent on name, since the index won't change based on the language and this can be verified in Accessibility Inspector which will show object references.
I tried something along these lines:
tell menu bar 1
set a to UI Elements
return item 6 of a
end tell
Output:
menu bar item "Controls" of menu bar 1 of application process "iTunes" of application "System Events"
All right, going further you will want to find the specific menu item and value. Which values are being affected by the language changes too.
tell application "System Events" to tell process "iTunes"
tell menu bar 1
set a to UI elements
set b to item 6 of a
set c to UI elements of b
-- c = {menu "Controls" of menu bar item "Controls" of menu bar 1 of application process "iTunes" of application "System Events"}
tell menu "Controls"
set d to item 16 of UI elements
tell menu "Shuffle" of d
--click menu item 1 (On)
--click menu item 2 (Off)
end tell
end tell
end tell
end tell

Related

Applescript Click item in system menu bar after opening it

I can open the bluetooth dropdown menu item with this code but I don't know how to actually click on any of the items in the menu.
tell application "System Events" to tell process "ControlCenter"
click menu bar item "Bluetooth" of menu bar 1
end tell
What would be a command to click on something in the open bluetooth menu?
This following AppleScript code should accomplish what you are trying to achieve. Just replace the "Mac Pro" part of the code with the name of the item you want to click.
tell application "System Events" to tell process "ControlCenter"
click menu bar item "Bluetooth" of menu bar 1
repeat until exists of checkbox 1 of scroll area 1 of window 1
delay 0.1
end repeat
click checkbox "Mac Pro" of scroll area 1 of window 1
key code 53 -- Press escape key
end tell
This following AppleScript code will return the names of the checkboxes so you can easily know your options to use in the first code.
tell application "System Events" to tell process "ControlCenter"
click menu bar item "Bluetooth" of menu bar 1
repeat until exists of checkbox 1 of scroll area 1 of window 1
delay 0.1
end repeat
set checkBoxNames to name of checkboxes of scroll area 1 of window 1
end tell

Applescript clicking unknown menu item?

I'm using the LG OnScreen Control app to switch between different monitor layouts which have no names in the menu item as it uses pictures. I want to write an applescript that clicks either the first one or the 9th one, my favourite selections. =)
How can I click them? I only managed to select them with the below code
ignoring application responses
tell application "System Events" to tell process "OnScreen Control"
click menu bar item 1 of menu bar 2
end tell
end ignoring
delay 0.1
do shell script "killall System\\ Events"
tell application "System Events" to tell process "OnScreen Control"
tell menu bar item 1 of menu bar 2
click menu item "Screen Split" of menu 1
end tell
end tell
UPDATE1: Ah silly me, I figured I can use "key code 125" several times to click the down arrow and "key code 76" to hit enter.
ignoring application responses
tell application "System Events" to tell process "OnScreen Control"
click menu bar item 1 of menu bar 2
end tell
end ignoring
delay 0.1
do shell script "killall System\\ Events"
tell application "System Events" to tell process "OnScreen Control"
tell menu bar item 1 of menu bar 2
click menu item "Screen Split" of menu 1
key code 125
key code 125
key code 125
key code 125
key code 125
key code 125
key code 125
key code 125
key code 76
end tell
end tell
Wondering though if there is a better and quicker way to execute this? Addressing the sub-items directly despite not having a name?
UDPATE2 with solution thanks to #user3439894
ignoring application responses
tell application "System Events" to tell process "OnScreen Control"
click menu bar item 1 of menu bar 2
end tell
end ignoring
delay 0.1
do shell script "killall System\\ Events"
tell application "System Events" to tell process "OnScreen Control"
tell menu bar item 1 of menu bar 2
click menu item "Screen Split" of menu 1
click menu item 9 of menu 1 of menu item "Screen Split" of menu 1
end tell
end tell
After:
click menu item "Screen Split" of menu 1
Use:
click menu item 9 of menu 1 of menu item "Screen Split" of menu 1
Getting rid of all the key code commands

Applescript to click menu item of status bar app

I have an app called Fenêtre, when looking process name using top command it gives the name Fene?~Btre H.
I would like to click the item called 'a.py' under its menubar item as shown in figure.
My attempt:
attempt 1
tell application "System Events" to tell process "Fenêtre"
tell menu bar item 1 of menu bar 1
click
click menu item "Show all" of menu 1
end tell
end tell
Error:
$ osascript a.applescript
a.applescript:121:157: execution error: System Events got an error: Can’t get menu item "Show all" of menu 1 of menu bar item 1 of menu bar 1 of process "Fenêtre". (-1728)
Note that, when I run only first and last line of attemp1 it runs good, when I add middle lines it fails to run.
attempt 2
ignoring application responses
tell application "System Events" to tell process "Fenêtre"
click menu bar item 1 of menu bar 2
end tell
end ignoring
do shell script "killall System\\ Events"
delay 0.1
tell application "System Events" to tell process "Fenêtre"
tell menu bar item 1 of menu bar 2
click menu item "a.py" of menu 1
-- click menu item 1 of menu 1 -- another try
end tell
end tell
Updates (Still get errors)
tell application "System Events" to tell process "Fenêtre"
get entire contents of menu bar 2
end tell
This gives:
{menu bar item 1 of menu bar 2 of application process "Fenêtre" of application "System Events"}
References:
Applescript: on clicking Menu Bar item via gui script
applescript click menu bar option
https://superuser.com/questions/587815/can-applescript-osascript-be-used-to-click-menu-extra-menu-items
Applescript to show Apple menu bar items
Is AppleScript UI Scripting very slow in general, or is it my script, or something else?
Clicking an applications menu bar item with AppleScript
Thanks a lot.
Use a bundle identifier instead of the app name:
tell application "System Events"
tell (first application process whose bundle identifier is "BUNDLE_IDENTIFIER_HERE")
tell menu bar item 1 of menu bar 1
click
click menu item "Show all" of menu 1
end tell
end tell
end tell

Applescript: on clicking Menu Bar item via gui script

I'm trying to make an applescript for an application called F.lux that clicks the menu item "Disable for an Hour" as indicated in the screenshot below:
The element path is indicated in the screenshot below:
Here is my code thus far:
tell application "System Events"
tell process "Flux"
click (menu bar item 1 of menu bar 2)
click menu item "Disable for an hour" of menu 1 of menu bar item 1 of
menu bar 2
end tell
end tell
Everything compiles fine, however I keep getting the error message below when I attempt to run the script:
error "System Events got an error: Can’t get menu 1 of menu bar item 1 of menu bar 2 of process "Flux". Invalid index." number -1719 from menu 1 of menu bar item 1 of menu bar 2 of process "Flux"
Can someone pinpoint where I'm going wrong with this?
This worked for me, but there is a delay of about 5 seconds after the first click command.
tell application "System Events" to tell process "Flux"
tell menu bar item 1 of menu bar 2
click
click menu item "Disable for an hour" of menu 1
end tell
end tell
One workaround is to use ignoring application responses and terminate System Events after the click command:
ignoring application responses
tell application "System Events" to tell process "Flux"
click menu bar item 1 of menu bar 2
end tell
end ignoring
do shell script "killall System\\ Events"
delay 0.1
tell application "System Events" to tell process "Flux"
tell menu bar item 1 of menu bar 2
click menu item "Disable for an hour" of menu 1
end tell
end tell

How to set iTunes 11 in shuffle or repeat mode via applescript

According to http://dougscripts.com/ setting shuffle and repeat modes via applescript is broken in iTunes 11.
According to this stackoverflow answer shuffle is now a playlist independent setting.
Thus, I tried to set the shuffle value via the UI, either by the LCD-ish display of iTunes or via the menu bar. All I could get was "unknown UI index" errors when trying to click the shuffle button/menu item, either in the LCD area or the menu bar. (I'm new to applescript).
If some of you could come up with a way to toggle shuffle mode on iTunes 11, that would be great. Also I'd prefer a solution based on the menu bar rather than the LCD display since the shuffle button is not always visible in the latter.
Ideally, I'd prefer a semantic-based solution over a UI-based solution but I'm not sure if it's possible (iTunes 11 applescript library seems to be outdate since it mention a "shuffle" property for "playlists" items).
For the new Music app, this works. If you're using iTunes still, change "Music" to "iTunes".
Repeat can be set to one or off or all.
tell application "Music"
set song repeat to off
end
Shuffle can be set to true or false.
tell application "Music"
set shuffle enabled to true
end
You can find more details at Dougscripts.
I liked John Sauer's approach so much I wrote myself some getters/setters for these properties using his approach. It's works well because you do not have to activate iTunes before using them. Anyway, I thought I'd post them in case they're of help to anyone. You will get or set their values using the "types" (modeled after the menu item names) as follows:
Repeat types are "Off", "All", or "One".
Shuffle types are "Off", "By Songs", "By Albums", or "By Groupings"
on getRepeatType() -- the return value is a string: Off/All/One
tell application "System Events"
tell process "iTunes"
set menuItems to menu items of menu bar 1's menu bar item "Controls"'s menu 1's menu item "Repeat"'s menu 1
set currentChoice to "unknown"
repeat with anItem in menuItems
try
set theResult to value of attribute "AXMenuItemMarkChar" of anItem
if theResult is not "" then
set currentChoice to name of anItem
exit repeat
end if
end try
end repeat
end tell
end tell
return currentChoice
end getRepeatType
on setRepeatType(repeatType) -- repeatType is a string: Off/All/One
set currentValue to my getRepeatType()
ignoring case
if currentValue is not repeatType then
tell application "System Events" to tell process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Repeat"'s menu 1
if repeatType is "all" then
perform action "AXPress" of menu item "All"
else if repeatType is "one" then
perform action "AXPress" of menu item "One"
else
perform action "AXPress" of menu item "Off"
end if
end tell
end if
end ignoring
end setRepeatType
on getShuffleType() -- the return value is a string: Off/By Songs/By Albums/By Groupings
tell application "System Events"
tell process "iTunes"
set menuItems to menu items of menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1
set onOffItemName to name of item 1 of menuItems
end tell
end tell
-- is shuffle off
ignoring case
if onOffItemName contains " on " then return "Off"
end ignoring
-- shuffle is on so find how we are shuffling
set currentChoice to "Unknown"
tell application "System Events"
tell process "iTunes"
repeat with i from 2 to count of menuItems
set anItem to item i of menuItems
try
set theResult to value of attribute "AXMenuItemMarkChar" of anItem
if theResult is not "" then
set currentChoice to name of anItem
exit repeat
end if
end try
end repeat
end tell
end tell
return currentChoice
end getShuffleType
on setShuffleType(shuffleType) -- shuffleType is a string: Off/By Songs/By Albums/By Groupings
set currentValue to my getShuffleType()
script subs
on toggleShuffleOnOff()
tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1 whose name ends with "Shuffle")
end toggleShuffleOnOff
on pressBySongs()
tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1 whose name ends with "Songs")
end pressBySongs
on pressByAlbums()
tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1 whose name ends with "Albums")
end pressByAlbums
on pressByGroupings()
tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1 whose name ends with "Groupings")
end pressByGroupings
end script
ignoring case
if shuffleType contains "off" then -- we have to make sure it's off
if currentValue does not contain "off" then subs's toggleShuffleOnOff()
else
-- make sure it's on
if currentValue contains "off" then subs's toggleShuffleOnOff()
-- select the shuffle menu item for the type
if shuffleType contains "song" and currentValue does not contain "song" then
subs's pressBySongs()
else if shuffleType contains "album" and currentValue does not contain "album" then
subs's pressByAlbums()
else if shuffleType contains "group" and currentValue does not contain "group" then
subs's pressByGroupings()
end if
end if
end ignoring
end setShuffleType
I was optimistic when I saw the AppleScript property current playlist of the iTunes application, but it doesn't work well. It's able to get and set the current playlist's name, but it can do neither for the properties shuffle or song repeat. It errors when trying to set either property, and it always returns 'false' for shuffle and 'off' for song repeat.
I think your only option is UI Scripting. Here's how to toggle shuffle through the menu bar:
tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Shuffle"'s menu 1 whose name ends with "Shuffle")
And here's how to set repeat:
tell application "System Events" to tell process "iTunes"'s menu bar 1's menu bar item "Controls"'s menu 1's menu item "Repeat"'s menu 1
perform action "AXPress" of menu item "Off"
perform action "AXPress" of menu item "All"
perform action "AXPress" of menu item "One"
end tell
For iTunes 12, this works
tell application "System Events"
tell process "iTunes" to if exists then
click menu item "Albums" of menu "Shuffle" of menu item "Shuffle" of menu "Controls" of menu bar 1
end if
end tell
Change Albums to Songs, Groupings, On and Off accordingly.
Here is another approach:
activate application "iTunes"
tell application "System Events"
tell process "iTunes"
click menu item 1 of menu 1 of menu item "Shuffle" of menu 1 of menu bar item "Controls" of menu bar 1
end tell
end tell
It looks like many of these scripts are broken in the newest iTunes. Here are two the work:
tell application "System Events" to tell UI element "iTunes" of list 1 of process "Dock"
if not (exists) then return
perform action "AXShowMenu"
click menu item "Shuffle" of menu 1
end tell
That one toggles shuffle via the Dock. You can watch the Dock menu animate when you use it.
This one toggles shuffle via the menu, invisibly:
tell application "System Events"
tell application process "iTunes"
tell menu 1 of menu item "Shuffle" of menu "Controls" of menu bar 1
if (value of attribute "AXMenuItemMarkChar" of item 1 of menu items as string) = "✓" then
click menu item 2
else
click menu item 1
end if
end tell
end tell
end tell
Both of these will work even with iTunes is in the background.
Spent some time deconstructing all the obfuscated solutions in this post (which appear to not work anymore), here's a more readable and customizable approach that works with iTunes 12.1:
tell application "System Events"
set itunesMenuBar to process "iTunes"'s first menu bar
set controlsMenu to itunesMenuBar's menu bar item "Controls"'s first menu
set shuffleMenu to controlsMenu's menu item "Shuffle"'s first menu
set shuffleOnMenuItem to shuffleMenu's menu item "On"
set shuffleSongsMenuItem to shuffleMenu's menu item "Songs"
tell process "iTunes"
click shuffleOnMenuItem
click shuffleSongsMenuItem
end tell
end tell
This will turn shuffle on and set it to shuffle songs instead of albums, and it should be pretty obvious how to change it to do other things.

Resources