Search code examples
applescriptitunesrepeatshuffle

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).


Solution

  • 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