applescriptitunes-app

Why does the "Click row ndx . . ." statement have no effect in this Applescript?


The "on switchDir" routine is intended to locate each element of the path passed as "directory" and click on it so the directory path is dived through to reach the desired final output directory.

When activating the desired row with the mouse. as normal, it must be double-clicked to select it!

This is the code of "on switchDir" alone:

on switchDir(directory, appName, selectDefault, createIt)
    local compname, bootvolume
    set compname to get computer name of (system info)
    set bootvolume to get boot volume of (system info)
    if directory is equal to "~" then set directory to system attribute ("HOME")
    if directory starts with "~/" then set directory to (system attribute ("HOME")) & text 2 through -1 of (get directory)
    if not checkPathExists(directory) then
        if createIt then
            do shell script ("mkdir -p " & (POSIX path of directory))
        else
            return false
        end if
    end if
    if directory begins with "/" then
        set directory to bootvolume & (get directory)
    end if
    tell application "System Events" to tell (process "iTunes"'s front window)
        delay 1
        click pop up button 1 of group 1 -- selects the drop-down box above the directory listing
        set max to the count of menu items of menu 1 of pop up button 1 of group 1 -- number of items in the drop-down menu
        set ndx to 1
        repeat while ndx ≤ max
            if the title of group 1's pop up button 1's menu 1's menu item ndx as string is equal to compname then -- found the absolute top-level directory
                click group 1's pop up button 1's menu 1's menu item ndx - so choose it and go to next part of navigation
                exit repeat
            else -- keep looking
                set ndx to (get ndx) + 1
            end if
        end repeat
        if ndx > max then error "Never found " & compname
        set thePath to every item of my splitString(directory, "/") -- thePath equals every individual folder in the path's name in order
        repeat with dir in thePath
            set max to the (count of rows in outline 1 of scroll area 1 of splitter group 1 of group 1) -- max equals the number of rows in the "directory contents" list box
            log max
            set ndx to 2 -- row 1 is just the colum titles
            repeat while ndx ≤ max
                log the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string
                log the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string is equal to dir as string
                if the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string is equal to dir as string then -- this is the row we want!
                    log "found " & dir & " at row " & ndx as string
                    select row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 -- included to make sure the reference in the "click" statement is correct
                    click row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 -- supposed to "click" the desired folder name to choose it and dive deeper, BUT IT DOESN'T ACTUALLY DO THAT!
                    exit repeat -- apparently never executed because the loop keeps going past finding the desired directory's name and crashes at the first blank row!
                else
                    set ndx to (get ndx) + 1
                end if
                if ndx > max then error "Never found " & dir
             end repeat
        end repeat
    end tell
    error "success"
    return true
end switchDir

The error occurs in "on switchDir", the rest of the code is only included so that the code will execute under "Script Editor". Both the "Click row ndx . . . ." statement and the "exit repeat" statement after it are apparently never being executed as the loop continues to run past the logging of "found ". . . . and consequently crashes on the first blank row in the list box. The found (with the quotes) can be used as a search term to find the code.

The complete, runnable application code follows:

on splitString(theString, theDelimiter)
    set oldDelimiters to AppleScript's text item delimiters
    set AppleScript's text item delimiters to theDelimiter
    set theArray to every text item of theString
    set AppleScript's text item delimiters to oldDelimiters
    return theArray
end splitString

on checkPathExists(thePath)
    if thePath is equal to "~" then set thePath to system attribute ("HOME")
    if thePath starts with "~/" then set thePath to (system attribute ("HOME")) & text 2 through -1 of (get thePath)
    try
        POSIX file thePath as alias
        return true
    on error
        return false
    end try
end checkPathExists

on switchDir(directory, appName, selectDefault, createIt)
    local compname, bootvolume
    set compname to get computer name of (system info)
    set bootvolume to get boot volume of (system info)
    if directory is equal to "~" then set directory to system attribute ("HOME")
    if directory starts with "~/" then set directory to (system attribute ("HOME")) & text 2 through -1 of (get directory)
    if not checkPathExists(directory) then
        if createIt then
            do shell script ("mkdir -p " & (POSIX path of directory))
        else
            return false
        end if
    end if
    if directory begins with "/" then
        set directory to bootvolume & (get directory)
    end if
    tell application "System Events" to tell (process "iTunes"'s front window)
        delay 1
        click pop up button 1 of group 1 -- selects the drop-down box above the directory listing
        set max to the count of menu items of menu 1 of pop up button 1 of group 1 -- number of items in the drop-down menu
        set ndx to 1
        repeat while ndx ≤ max
            if the title of group 1's pop up button 1's menu 1's menu item ndx as string is equal to compname then -- found the absolute top-level directory
                click group 1's pop up button 1's menu 1's menu item ndx - so choose it and go to next part of navigation
                exit repeat
            else -- keep looking
                set ndx to (get ndx) + 1
            end if
        end repeat
        if ndx > max then error "Never found " & compname
        set thePath to every item of my splitString(directory, "/") -- thePath equals every individual folder in the path's name in order
        repeat with dir in thePath
            set max to the (count of rows in outline 1 of scroll area 1 of splitter group 1 of group 1) -- max equals the number of rows in the "directory contents" list box
            log max
            set ndx to 2 -- row 1 is just the colum titles
            repeat while ndx ≤ max
                log the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string
                log the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string is equal to dir as string
                if the value of text field 1 of UI element 1 of row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 as string is equal to dir as string then -- this is the row we want!
                    log "found " & dir & " at row " & ndx as string
                    select row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 -- included to make sure the reference in the "click" statement is correct
                    click row ndx of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1 -- supposed to "click" the desired folder name to choose it and dive deeper, BUT IT DOESN'T ACTUALLY DO THAT!
                    exit repeat -- apparently never executed because the loop keeps going past finding the desired directory's name and crashes at the first blank row!
                else
                    set ndx to (get ndx) + 1
                end if
                if ndx > max then error "Never found " & dir
             end repeat
        end repeat
    end tell
    error "success"
    return true
end switchDir

set directory to "/Users/bryandunphy/Music"
try
    tell application "iTunes" to quit
end try
tell application "System Events"
    key down option
    tell application "iTunes" to activate
    key up option
    repeat until process "iTunes" exists
        delay 0.5
    end repeat
    click process "iTunes"'s window 1's button 2
    my switchDir(directory, "iTunes", false, true)
    delay 2
    set libraryName to value of text field "Save As:" of window "New iTunes Library" of process "iTunes"
    delay 2
    click process "iTunes"'s window "New iTunes Library"'s button "Save"
end tell
return libraryName

Any idea of the cause of the error and / or how to fix it would be greatly appreciated.


Solution

  • I have refactored your onSwitchDir function to make it work on my machine, and to make it more readable.

    I also added a ton of logging to help troubleshoot, feel free to delete.

    on switchDir(directory, appName, selectDefault, createIt)
    
        local compname, bootvolume
        set sysInfo to (system info) -- cache value to reduce processing time
        set compname to get computer name of sysInfo
        log "compname: " & compname
        set bootvolume to get boot volume of sysInfo
        log "bootvolume: " & bootvolume
        if directory is equal to "~" then set directory to system attribute ("HOME")
        if directory starts with "~/" then set directory to (system attribute ("HOME")) & text 2 through -1 of (get directory)
    
        if not checkPathExists(directory) then
            if createIt then
                do shell script ("mkdir -p " & (POSIX path of directory))
            else
                return false
            end if
        end if
    
        if directory begins with "/" then
            set directory to bootvolume & (get directory)
        end if
    
        tell application "System Events" to tell (process "iTunes"'s front window)
    
            -- ensure view is set to expanded view
            try
                click pop up button 1 of group 1
            on error
                key code 81 using {command down} -- expand view
                delay 2 -- esnure it finishes expanding before continuing
            end try
    
            -- name the item, making the code more readable
            set dropDownMenuBtn to menu 1 of pop up button 1 of group 1
    
            click dropDownMenuBtn -- selects the drop-down box above the directory listing
    
            -- Set drop-down menu to go to system's root folder
            -- Variation of solution from http://stackoverflow.com/questions/13415994/how-to-get-the-number-of-items-in-a-pop-up-menu-without-opening-it-using-applesc
            tell pop up button 1 of group 1
                if value of it is not equal to compname then
                    set menuItemTitles to name of menu items of menu 1
                    --check if the menu item exists
                    if compname is in menuItemTitles then
                        --menu item exists; click on it
                        click menu item compname of menu 1
                        log "yay! found it! setting menu to item " & compname
                    else
                        --the menu item to select doesn't exist; hide the menu
                        log "bummer! " & compname & " doesn't exist"
                        key code 53
                    end if
                else
                    log "yay! menu already set to " & compname
                end if
            end tell
    
            -- Make iTunes dialog navigate to root folder
            set thePath to every item of my splitString(directory, "/") -- thePath equals every individual folder in the path's name in order
            log "thePath: " & thePath
    
            set isFound to false -- so we can exit the repeat loop when needed
    
            repeat with dir in thePath
    
                if isFound is false then
    
                    -- set reference to UI element for readability
                    set theOutline to outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of group 1
    
                    set max to the (count of rows in theOutline) -- max equals the number of rows in the "directory contents" list box
                    log "max for " & dir & ": " & max
    
                    set ndx to 2 -- row 1 is just the column titles
    
                    repeat while ndx ≤ max
    
                        -- set reference to item for readability
                        set theRow to row ndx of theOutline
    
                        -- set reference to item for readability                    
                        set theElement to text field 1 of UI element 1 of theRow
    
                        -- if we have found the appropriate item
                        if the value of theElement is equal to dir as string then
    
                            -- set focus so we can use keyboard commands on it
                            set value of attribute "AXFocused" of theOutline to true
    
                            -- select the item in the list
                            select theRow
    
                            -- set boolean so we can avoid re-running the repeat loop
                            set isFound to true
    
                            -- exit inner repeat
                            exit repeat
    
                        else
    
                            set ndx to (get ndx) + 1
    
                        end if
    
                        if ndx > max then error "Never found " & dir
    
                    end repeat
    
                else
    
                    -- exit outer repeat
                    exit repeat
    
                end if
    
            end repeat
    
            -- CMD-o to open the selected directory
            keystroke "o" using {command down}
    
        end tell
    
    end switchDir
    
    set directory to "/Users/username/Music"
    
    try
        tell application "iTunes" to quit
    end try
    
    tell application "System Events"
        key down option
        tell application "iTunes" to activate
        key up option
        repeat until process "iTunes" exists
            delay 0.5
        end repeat
        click process "iTunes"'s window 1's button 2
        my switchDir(directory, "iTunes", false, true)
        delay 0.5
        set libraryName to value of text field "Save As:" of window "New iTunes Library" of process "iTunes"
        delay 0.5
        click process "iTunes"'s window "New iTunes Library"'s button "Save"
    end tell
    return libraryName
    

    Noteworthy changes:

    Note the outcome of this script is an iTunes warning that it can't create a new library at the requested location. I believe this is because I only have a snippet of your entire script. I imagine you have the other end of the code, which would resolve the issue. If so, you should be able to incorporate these changes into your project without much effort.