No internet connection
  1. Home
  2. How to

Hide Empty Folder Tracks

By mikkeljm @mikkeljm
    2022-11-11 19:56:18.037Z2022-11-12 10:41:12.924Z

    I would like to select all Folder tracks and only all folder tracks in the session that are empty, and make them inactive and hide them?
    I dont wanna hide any other empty tracks such as VCAs or empty audio tracks, only empty folder tracks.

    Scheps Tracks selector can of course select all my folder tracks, but not all the Empty folder tracks. Wich would be a great future update. :-)

    • 29 replies

    There are 29 replies. Estimated reading time: 37 minutes

    1. samuel henriques @samuel_henriques
        2022-11-12 17:05:10.704Z

        Hello @mikkeljm,
        Try this,
        It will do as you ask the first parent folders, folders inside folders wont work with this code.
        Let me know if this is it.

        function clickAllGroupSymbol() {
            sf.ui.proTools.groupsEnsureGroupListIsVisible();
            sf.ui.proTools.mainWindow.groupListView.children.whoseRole.is("AXColumn").first
                .children.whoseRole.is("AXRow").first
                .children.whoseRole.is("AXCell").first
                .buttons.first.elementClick();
        
            sf.ui.proTools.trackDeselectAll();
        };
        
        function openAllFolderTracks() {
            sf.ui.proTools.invalidate()
        
            const selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders;
        
            clickAllGroupSymbol();
        
            sf.ui.proTools.invalidate();
        
        
            // Select original Track Selection
            if (selectedTrackHeaders.length > 0) {
                selectedTrackHeaders[0].trackSelect()
                selectedTrackHeaders[0].trackScrollToView()
                sf.ui.proTools.trackSelectByName({ names: selectedTrackHeaders.map(tr => tr.normalizedTrackName) })
            };
        };
        
        
        
        
        /**
         * @param {AxPtTrackHeader} track
         */
        function getTrackDepth(track) {
            return Math.floor((track.titleButton.frame.x - track.frame.x) / 15);
        }
        
        /**
         * @author Christian Scheuer - https://forum.soundflow.org/-1784/how-to-select-specific-type-of-tracks-inside-a-folder
         */
        function getTrackFolderStructure() {
            var root = { children: [] };
            var stack = [];
            stack[0] = root;
            var flatList = sf.ui.proTools.visibleTrackHeaders.map(t => ({ track: t, depth: getTrackDepth(t) }));
            for (var i = 0; i < flatList.length; i++) {
                var flatItem = flatList[i];
                var node = {
                    name: flatItem.track.normalizedTrackName,
                    type: flatItem.track.title.value.match(/ - (.*)$/)[1].trim().replace(/track$/i, '').trim().toLowerCase(),
                    track: flatItem.track,
                    children: []
                };
                stack[flatItem.depth] = node;
                stack[flatItem.depth - 1].children.push(node);
            }
            return root;
        };
        
        function main(callback) {
        
            const isTrackListVisible = sf.ui.proTools.getMenuItem("View", "Other Displays", "Track List").isMenuChecked
            const selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders;
        
            try {
                //Open All folders
                clickAllGroupSymbol();
        
                callback();
        
            } catch (err) {
                throw err
            } finally {
        
                sf.ui.proTools.invalidate();
                // Select original Track Selection
                if (selectedTrackHeaders.length > 0) {
                    selectedTrackHeaders[0].trackSelect()
                    selectedTrackHeaders[0].trackScrollToView()
                    sf.ui.proTools.trackSelectByName({ names: selectedTrackHeaders.map(tr => tr.normalizedTrackName) })
                };
        
                //Close track list if originaly closed
                if (!isTrackListVisible) sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Track List"], targetValue: "Disable" })
            };
        };
        
        
        function hideAndMakeInactiveEmptyFolders() {
        
            sf.ui.proTools.mainWindow.invalidate();
        
            const root = getTrackFolderStructure();
        
            const emptyFolders = root.children.filter(track =>
                track.type.endsWith("folder") &&
                track.children.length === 0
            ).map(folder => folder.name)
        
            sf.ui.proTools.trackSelectByName({ names: emptyFolders });
            sf.ui.proTools.trackHideAndMakeInactiveSelected();
        };
        
        
        main(hideAndMakeInactiveEmptyFolders);
        
        1. Nathan Salefski @nathansalefski
            2023-08-28 15:12:41.604Z

            Hi Samuel, I was wondering how I could rewrite this to detect empty folders regardless of how deeply nested they are within other folders. Currently just trying to log their names. I assume it has something to do with function getTrackDepth(track) {} maybe @chrscheuer can shed some light as well:

            /**
             * @param {AxPtTrackHeader} track
             */
            function getTrackDepth(track) {
                return Math.floor((track.titleButton.frame.x - track.frame.x) / 15);
            }
            
            /**
             * @author Christian Scheuer - https://forum.soundflow.org/-1784/how-to-select-specific-type-of-tracks-inside-a-folder
             */
            function getTrackFolderStructure() {
                var root = { children: [] };
                var stack = [];
                stack[0] = root;
                var flatList = sf.ui.proTools.visibleTrackHeaders.map(t => ({ track: t, depth: getTrackDepth(t) }));
                for (var i = 0; i < flatList.length; i++) {
                    var flatItem = flatList[i];
                    var node = {
                        name: flatItem.track.normalizedTrackName,
                        type: flatItem.track.title.value.match(/ - (.*)$/)[1].trim().replace(/track$/i, '').trim().toLowerCase(),
                        track: flatItem.track,
                        children: []
                    };
                    stack[flatItem.depth] = node;
                    stack[flatItem.depth - 1].children.push(node);
                }
                return root;
            };
            
            const root = getTrackFolderStructure();
            
            const emptyFolders = root.children.filter(track =>
                track.type.endsWith("folder") &&
                track.children.length === 0
            ).map(folder => folder.name)
            
            log(emptyFolders)
            
            1. samuel henriques @samuel_henriques
                2023-09-02 08:47:55.719Z

                Hello Nathan,
                chatGPT to the help.

                function findEmptyFolder(obj) {
                    const result = [];
                
                    function traverse(node) {
                        if (node.children && node.type && node.type.endsWith("folder") && Array.isArray(node.children) && node.children.length === 0) {
                            result.push(node);
                        }
                        if (node.children && Array.isArray(node.children)) {
                            for (const child of node.children) {
                                traverse(child);
                            }
                        }
                    }
                
                    traverse(obj);
                    return result;
                };
                
                
                const emptyFolderNames = findEmptyFolder(root).map(el => el.name);
                log(emptyFolderNames);
                

                This will take the root object and return the empty folder names.

                1. Nathan Salefski @nathansalefski
                    2023-09-02 15:56:30.300Z2023-09-02 16:02:36.908Z

                    Wow this is AMAZING! This will be a huge help! THANKS! Here's it all pieced together for anyone looking

                    /**
                     * @author Christian Scheuer - https://forum.soundflow.org/-1784/how-to-select-specific-type-of-tracks-inside-a-folder
                     */
                    // Get Track Depth 
                    function getTrackDepth(track) {
                        return Math.floor((track.titleButton.frame.x - track.frame.x) / 15);
                    }
                    
                    // Get Folder Structure
                    function getTrackFolderStructure() {
                        var root = { children: [] };
                        var stack = [];
                        stack[0] = root;
                        var flatList = sf.ui.proTools.visibleTrackHeaders.map(t => ({ track: t, depth: getTrackDepth(t) }));
                        for (var i = 0; i < flatList.length; i++) {
                            var flatItem = flatList[i];
                            var node = {
                                name: flatItem.track.normalizedTrackName,
                                type: flatItem.track.title.value.match(/ - (.*)$/)[1].trim().replace(/track$/i, '').trim().toLowerCase(),
                                track: flatItem.track,
                                children: []
                            };
                            stack[flatItem.depth] = node;
                            stack[flatItem.depth - 1].children.push(node);
                        }
                        return root;
                    };
                    
                    const root = getTrackFolderStructure();
                    
                    /**
                     * Samuel Henriques - https://forum.soundflow.org/-8814#post-5
                     */
                    // Works Regardless of Folder Structure
                    function findEmptyFolder(obj) {
                        const result = [];
                    
                        function traverse(node) {
                            if (node.children && node.type && node.type.endsWith("folder") && Array.isArray(node.children) && node.children.length === 0) {
                                result.push(node);
                            }
                            if (node.children && Array.isArray(node.children)) {
                                for (const child of node.children) {
                                    traverse(child);
                                }
                            }
                        }
                    
                        traverse(obj);
                        return result;
                    };
                    
                    const emptyFolderNames = findEmptyFolder(root).map(el => el.name);
                    
                    log(emptyFolderNames);
                    
                    1. Nathan Salefski @nathansalefski
                        2023-09-02 16:08:39.545Z

                        Interestingly, when I try to sf.ui.proTools.trackSelectByName({names: emptyFolderNames}); it will not select Empty folders nested deeper than one level deep. Any clue as to why? Ideally I'd be able to select and delete all empty folders in the session no matter where they are. Here's a quick screen recording https://we.tl/t-ZRDqtzIOMp

                        1. Nathan Salefski @nathansalefski
                            2023-09-02 16:17:00.855Z

                            It seems to just be this, which funnily enough, Kitch and I already solved How to use looseMatch in Popup Menu #post-21

                            1. In reply tonathansalefski:
                              samuel henriques @samuel_henriques
                                2023-09-02 16:22:07.206Z

                                I'm not having this problem, try to invalidate before the script so pro tools will get the most updated track list and order,

                                sf.ui.proTools.invalidate();
                                
                                1. Nathan Salefski @nathansalefski
                                    2023-09-02 16:24:57.745Z

                                    Can you see if you have a problem with your track list view at its minimum size

                                    1. samuel henriques @samuel_henriques
                                        2023-09-02 16:26:29.144Z

                                        works all the way to micro

                                        1. Nathan Salefski @nathansalefski
                                            2023-09-02 16:27:43.646Z

                                            Ah I meant this

                                            1. samuel henriques @samuel_henriques
                                                2023-09-02 16:30:04.571Z

                                                Ahh yes, this way it will become unstable, not selecting the correct ones

                                                1. samuel henriques @samuel_henriques
                                                    2023-09-02 16:34:52.828Z

                                                    weird. if track list is closed the problem goes away.

                                                    1. samuel henriques @samuel_henriques
                                                        2023-09-02 16:36:29.678Z

                                                        actually no. It's still unstable

                                                        1. Nathan Salefski @nathansalefski
                                                            2023-09-02 16:42:08.761Z

                                                            @Kitch and I ran into this problem lol Hide Empty Folder Tracks #post-8

                                                            1. samuel henriques @samuel_henriques
                                                                2023-09-02 16:43:09.491Z

                                                                yes, i see it now

                                                                1. Nathan Salefski @nathansalefski
                                                                    2023-09-02 16:50:14.832Z

                                                                    This seems to be working:

                                                                    // Mouse Drag Funtion
                                                                    function mouseDrag(startPos, endPos) {
                                                                        const timeToWaitBeforeDropping = 250;
                                                                    
                                                                        sf.mouse.down({ position: startPos, });
                                                                    
                                                                        sf.mouse.drag({ position: endPos });
                                                                    
                                                                        sf.wait({ intervalMs: timeToWaitBeforeDropping });
                                                                    
                                                                        sf.mouse.up({ position: endPos });
                                                                    };
                                                                    
                                                                    /**
                                                                     * @authors Kitch Membery & Nathan Salefksi - https://forum.soundflow.org/-10790#post-28
                                                                     */
                                                                    
                                                                    function resizeTrackListView(editWindow, editWindowTrackListFrame, size) {
                                                                        const editWindowMenuItem = sf.ui.proTools.getMenuItem('Window', 'Edit');
                                                                    
                                                                        if (!(editWindowMenuItem.isMenuChecked)) {
                                                                            sf.ui.proTools.menuClick({ menuPath: ['Window', 'Edit',] },
                                                                                `Could Not Show Edit Window`
                                                                            );
                                                                    
                                                                            sf.wait({ intervalMs: 100 });
                                                                    
                                                                            sf.ui.proTools.mainWindow.invalidate();
                                                                        }
                                                                    
                                                                        const trackListMenuItem = sf.ui.proTools.getMenuItem('View', 'Other Displays', 'Track List');
                                                                    
                                                                        if (!(trackListMenuItem.isMenuChecked)) {
                                                                            sf.ui.proTools.menuClick({ menuPath: ['View', 'Other Displays', 'Track List'], },
                                                                                `Could Not Show Track List`
                                                                            );
                                                                    
                                                                            sf.wait({ intervalMs: 100 });
                                                                    
                                                                            sf.ui.proTools.mainWindow.invalidate();
                                                                        }
                                                                    
                                                                        const trackListResizePoint = {
                                                                            x: editWindow.frame.x + editWindowTrackListFrame.w + 21,
                                                                            y: editWindow.frame.y + (editWindow.frame.h / 2),
                                                                        };
                                                                    
                                                                        const startDrag = trackListResizePoint;
                                                                    
                                                                        let endDrag = {}
                                                                    
                                                                        if (size === 'Increase') {
                                                                            endDrag = {
                                                                                x: trackListResizePoint.x + 150,
                                                                                y: trackListResizePoint.y
                                                                            };
                                                                    
                                                                            mouseDrag(startDrag, endDrag);
                                                                    
                                                                        } else if (size === 'Decrease') {
                                                                            endDrag = {
                                                                                x: trackListResizePoint.x - 150,
                                                                                y: trackListResizePoint.y
                                                                            };
                                                                    
                                                                            mouseDrag(startDrag, endDrag);
                                                                        }
                                                                    }
                                                                    
                                                                    /**
                                                                     * @author Christian Scheuer - https://forum.soundflow.org/-1784/how-to-select-specific-type-of-tracks-inside-a-folder
                                                                     */
                                                                    
                                                                    function getTrackDepth(track) {
                                                                        return Math.floor((track.titleButton.frame.x - track.frame.x) / 15);
                                                                    }
                                                                    
                                                                    function getTrackFolderStructure() {
                                                                        var root = { children: [] };
                                                                        var stack = [];
                                                                        stack[0] = root;
                                                                        var flatList = sf.ui.proTools.visibleTrackHeaders.map(t => ({ track: t, depth: getTrackDepth(t) }));
                                                                        for (var i = 0; i < flatList.length; i++) {
                                                                            var flatItem = flatList[i];
                                                                            var node = {
                                                                                name: flatItem.track.normalizedTrackName,
                                                                                type: flatItem.track.title.value.match(/ - (.*)$/)[1].trim().replace(/track$/i, '').trim().toLowerCase(),
                                                                                track: flatItem.track,
                                                                                children: []
                                                                            };
                                                                            stack[flatItem.depth] = node;
                                                                            stack[flatItem.depth - 1].children.push(node);
                                                                        }
                                                                        return root;
                                                                    };
                                                                    
                                                                    /**
                                                                     * Samuel Henriques - https://forum.soundflow.org/-8814#post-5
                                                                     */
                                                                    
                                                                    function findEmptyFolder(obj) {
                                                                        const result = [];
                                                                    
                                                                        function traverse(node) {
                                                                            if (node.children && node.type && node.type.endsWith("folder") && Array.isArray(node.children) && node.children.length === 0) {
                                                                                result.push(node);
                                                                            }
                                                                            if (node.children && Array.isArray(node.children)) {
                                                                                for (const child of node.children) {
                                                                                    traverse(child);
                                                                                }
                                                                            }
                                                                        }
                                                                    
                                                                        traverse(obj);
                                                                        return result;
                                                                    };
                                                                    
                                                                    function main() {
                                                                    
                                                                        sf.ui.proTools.appActivateMainWindow();
                                                                        sf.ui.proTools.mainWindow.invalidate();
                                                                    
                                                                        const root = getTrackFolderStructure();
                                                                    
                                                                        const emptyFolderNames = findEmptyFolder(root).map(el => el.name);
                                                                    
                                                                        const editWindow = sf.ui.proTools.windows.whoseTitle.startsWith('Edit: ').first;
                                                                    
                                                                        let editWindowTrackListFrame = editWindow.tables.whoseTitle.is('Track List').first.frame;
                                                                    
                                                                        if (editWindowTrackListFrame.w >= 85 && editWindowTrackListFrame.w <= 250) {
                                                                            resizeTrackListView(editWindow, editWindowTrackListFrame, 'Increase');
                                                                    
                                                                            sf.ui.proTools.trackSelectByName({ names: emptyFolderNames });
                                                                    
                                                                            editWindowTrackListFrame = editWindow.tables.whoseTitle.is('Track List').first.frame;
                                                                    
                                                                            resizeTrackListView(editWindow, editWindowTrackListFrame, 'Decrease');
                                                                        } else {
                                                                    
                                                                            sf.ui.proTools.trackSelectByName({ names: emptyFolderNames });
                                                                    
                                                                        }
                                                                    }
                                                                    
                                                                    main();
                                                                    
                                                                    1. samuel henriques @samuel_henriques
                                                                        2023-09-02 16:56:18.149Z

                                                                        :) thats cool

                                                                        1. Nathan Salefski @nathansalefski
                                                                            2023-09-02 16:57:01.180Z

                                                                            Teamwork makes the dream work

                                                                            1. Ben Rubin @Ben_Rubin
                                                                                2025-04-16 18:27:33.794Z2025-04-16 18:57:50.641Z

                                                                                Jumping on an old thread here, how can I modify this script to ignore tracks with certain names, @samuel_henriques ? So it will still see the folder as "empty" even if it has certain tracks with specific names?

                                                                                thanks!

                                                  • M
                                                    In reply tomikkeljm:
                                                    mikkeljm @mikkeljm
                                                      2022-11-15 08:31:20.972Z

                                                      Thanks Samuel.

                                                      This did the trick. I love it. Big help.

                                                      1. In reply tomikkeljm:
                                                        Chris Shaw @Chris_Shaw2025-04-16 21:15:39.386Z2025-04-17 00:33:38.298Z

                                                        @samuel_henriques,

                                                        With SF 5.10.3 the code for this becomes much simpler.
                                                        The PT SDK can now return parentFolder for tracks.
                                                        Using this we can get all folder track names, check if it is a parent of any other track and if not, hide/deactivate or delete it.
                                                        If a folder is hidden / deleted then the function calls itself again (a recursive function) until the number of tracks in the session hasn't changed.
                                                        This will delete or deactivate and hide all empty folders and(!) subfolders:

                                                        sf.ui.proTools.appActivateMainWindow();
                                                        
                                                        const getTracks = () => sf.app.proTools.tracks.invalidate().allItems;
                                                        
                                                        function deleteFolder(trackName) {
                                                            sf.app.proTools.selectTracksByName({
                                                                trackNames: [trackName]
                                                            })
                                                            sf.ui.proTools.menuClick({
                                                                menuPath: ["Track", "Delete"]
                                                            })
                                                        }
                                                        
                                                        function deactivateFolder(trackName) {
                                                            sf.app.proTools.setTrackInactiveState({
                                                                trackNames: [trackName],
                                                                enabled: true
                                                            })
                                                        }
                                                        
                                                        function hideFolderTrack(trackName) {
                                                            sf.app.proTools.setTrackHiddenState({
                                                                trackNames: [trackName],
                                                                enabled: true
                                                            })
                                                        }
                                                        
                                                        let deletedOrHiddenFolders = []
                                                        
                                                        let pass = 1
                                                        function hideAndDeactivateEmptyFolderTracks() {
                                                            const uid = "hideDeactivateEmptyFolders" + Date.now();
                                                        
                                                            let tracksInSession = getTracks();
                                                            let inactiveTracksInSession = tracksInSession.filter(t => t.isInactive)
                                                        
                                                            const folderTracks = tracksInSession.filter(t => t.type.endsWith("Folder")).filter(t => !t.isInactive);
                                                            let folderTrackNames = folderTracks.map(f => f.name);
                                                        
                                                            folderTrackNames.forEach((folderName, index) => {
                                                        
                                                                sf.interaction.notify({
                                                                    uid,
                                                                    title: "Hide and deactivate empty folder tracks",
                                                                    message: `${folderName}:Checking for sub-tracks. Pass ${pass}`,
                                                                    progress: (index + 1) / folderTrackNames.length,
                                                                    keepAliveMs: 500
                                                        
                                                                })
                                                                // if (getTracks().find(t => t.name == folderName).isInactive) return
                                                        
                                                                function getSubTracks(folderName) {
                                                        
                                                                    const tracksInFolder = getTracks().filter(t => t.parentFolderName == folderName);
                                                                    const tracksInFolderNames = tracksInFolder.map(t => t.name);
                                                                    let activeSubTrackCount = 0
                                                                    tracksInFolder.forEach(t => {
                                                                        if (!t.isInactive) { activeSubTrackCount++; }
                                                                    })
                                                                    if (activeSubTrackCount == 0) {
                                                                        hideFolderTrack(folderName);
                                                                        deactivateFolder(folderName);
                                                                        deletedOrHiddenFolders.push(folderName)
                                                                        return
                                                                    }
                                                                    if (tracksInFolderNames.length == 1) {
                                                        
                                                                        const subTrack = getTracks().find(t => t.name == tracksInFolderNames[0])
                                                                        // if (subTrack.isInactive) getSubTracks(subTrack.name);
                                                                        if (subTrack.isInactive ) return;
                                                                        if (subTrack.type.endsWith("Folder") && !subTrack.isInactive) {
                                                                            getSubTracks(subTrack.name)
                                                                        }
                                                                        if (subTrack.type.endsWith("Folder") && subTrack.isInactive) {
                                                                            hideFolderTrack(folderName);
                                                                            deactivateFolder(folderName);
                                                                            deletedOrHiddenFolders.push(folderName)
                                                                            return
                                                                        }
                                                                    }
                                                                    if (tracksInFolderNames.length == 0) {
                                                                        hideFolderTrack(folderName);
                                                                        deactivateFolder(folderName);
                                                                        deletedOrHiddenFolders.push(folderName)
                                                                    }
                                                                }
                                                                getSubTracks(folderName)
                                                        
                                                                // Compare number of inactive tracks in session after deactivating
                                                                // If different run again
                                                            })
                                                            const updatedInactiveTracksCount = getTracks().filter(t => t.isInactive).length
                                                            if (updatedInactiveTracksCount != inactiveTracksInSession.length) {
                                                                pass++
                                                                hideAndDeactivateEmptyFolderTracks();
                                                            }
                                                            // 
                                                            const tracksHiddenAndDeactivatedCount = getTracks().filter(t => t.isInactive).length - inactiveTracksInSession.length
                                                        
                                                            sf.interaction.notify({
                                                                title: "Hide Empty Folders",
                                                                message: `${tracksHiddenAndDeactivatedCount} folders Hidden and made inactive`
                                                            })
                                                        }
                                                        
                                                        function deleteEmptyFolders() {
                                                            let tracksInSession = getTracks();
                                                        
                                                            const folderTracks = tracksInSession.filter(t => t.type.endsWith("Folder"));
                                                            const folderTrackNames = folderTracks.map(f => f.name);
                                                        
                                                            folderTrackNames.forEach(folderName => {
                                                                const tracksInFolder = tracksInSession.filter(t => t.parentFolderName == folderName).map(t => t.name);
                                                        
                                                                if (tracksInFolder.length == 0) {
                                                                    deleteFolder(folderName);
                                                                    deletedOrHiddenFolders.push(folderName)
                                                                }
                                                            })
                                                            // Compare number of tracks in session after deletion
                                                            // If different run again
                                                            if (tracksInSession.length != getTracks().length) deleteEmptyFolders()
                                                        
                                                            sf.interaction.notify({
                                                                title: "Delete Empty Folders",
                                                                message: `${deletedOrHiddenFolders.length} folders deleted`
                                                            })
                                                        }
                                                        
                                                        function main() {
                                                            const deleteOrHide = sf.interaction.displayDialog({
                                                                prompt: "Delete or deactivate/hide all empty folders?",
                                                                buttons: ["Cancel", "Delete", "Hide"],
                                                                defaultButton: "Hide"
                                                            }).button
                                                        
                                                            deleteOrHide == "Delete" ? deleteEmptyFolders() : hideAndDeactivateEmptyFolderTracks()
                                                        }
                                                        
                                                        main()
                                                        
                                                        1. Updated:
                                                          I misread the original post.
                                                          I've updated the code above to give the option to either make empty folders inactive and hidden or delete them.

                                                          1. Ben Rubin @Ben_Rubin
                                                              2025-04-17 00:07:33.560Z

                                                              Thanks, @Chris_Shaw. Wondering if you would be able to answer my question above when you get a moment?

                                                              thanks much
                                                              ben

                                                              1. Not sure I understand the request.
                                                                I'm interpreting that as "If the script encounters a folder with a certain name then do not deactivate and hide."
                                                                I'm not sure what you mean by

                                                                So it will still see the folder as "empty" even if it has certain tracks with specific names

                                                                1. Ben Rubin @Ben_Rubin
                                                                    2025-04-17 00:25:01.014Z

                                                                    So in my template, I have a bunch of Instrument Busses which are folder tracks and I move all the tracks I intake into the proper folder, Drums, Vocals etc. But often I don't use them all if that instrument is not being used. So if for example there's no Drums, I don't need the Drums folder. But there's always three aux tracks already in there, ie "Kick SansAmp" "Kick Snare Krush" and "Drums Buss Slam." So I'd like the script to ignore these tracks and still basically recognize the Drums folder as "empty" for this purpose so I can hide or delete it. Does that make sense?

                                                                    1. That's WAYY more complicated than simply adjusting the above script unfortunately

                                                                2. In reply toChris_Shaw:

                                                                  Updated again:
                                                                  Hiding folder tracks needed more recursion.
                                                                  Updated the code above

                                                                  1. Ben Rubin @Ben_Rubin
                                                                      2025-04-17 14:53:28.370Z

                                                                      this script is great, btw. i know you're super busy, but hoping you're up for the challenge at some point!

                                                                      1. Ben Rubin @Ben_Rubin
                                                                          2025-04-17 18:58:36.448Z

                                                                          ChatGPT to the rescue! For anyone coming across this thread who is looking to do what I want to do, here is a script that can ignore tracks in folders with specific names.

                                                                          sf.ui.proTools.appActivateMainWindow();
                                                                          
                                                                          const getTracks = () => sf.app.proTools.tracks.invalidate().allItems;
                                                                          
                                                                          function deleteFolders(trackNames) {
                                                                              sf.app.proTools.selectTracksByName({ trackNames });
                                                                          
                                                                              sf.ui.proTools.menuClick({
                                                                                  menuPath: ["Track", "Delete"]
                                                                              });
                                                                          
                                                                              try {
                                                                                  sf.ui.proTools.confirmationButtonDialog.elementWaitFor({
                                                                                      waitType: "Appear",
                                                                                      timeout: 500
                                                                                  });
                                                                                  sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("Delete").first.elementClick();
                                                                              } catch (e) {}
                                                                          }
                                                                          
                                                                          function deactivateFolders(trackNames) {
                                                                              sf.app.proTools.setTrackInactiveState({
                                                                                  trackNames,
                                                                                  enabled: true
                                                                              });
                                                                          }
                                                                          
                                                                          function hideFolderTracks(trackNames) {
                                                                              sf.app.proTools.setTrackHiddenState({
                                                                                  trackNames,
                                                                                  enabled: true
                                                                              });
                                                                          }
                                                                          
                                                                          let deletedOrHiddenFolders = [];
                                                                          let pass = 1;
                                                                          
                                                                          const IGNORED_TRACK_NAMES = [
                                                                              "KICK SANSAMP",
                                                                              "KICK SNARE KRUSH",
                                                                              "DRUMS BUSS SLAM"
                                                                          ];
                                                                          
                                                                          function hideAndDeactivateEmptyFolderTracks() {
                                                                              const uid = "hideDeactivateEmptyFolders" + Date.now();
                                                                          
                                                                              let tracksInSession = getTracks();
                                                                              let inactiveTracksInSession = tracksInSession.filter(t => t.isInactive);
                                                                              const folderTracks = tracksInSession.filter(t => t.type.endsWith("Folder"));
                                                                              let folderTrackNames = folderTracks.map(f => f.name);
                                                                          
                                                                              let foldersToProcess = [];
                                                                          
                                                                              folderTrackNames.forEach((folderName, index) => {
                                                                                  sf.interaction.notify({
                                                                                      uid,
                                                                                      title: "Hide and deactivate empty folder tracks",
                                                                                      message: `${folderName}:Checking for sub-tracks. Pass ${pass}`,
                                                                                      progress: (index + 1) / folderTrackNames.length,
                                                                                      keepAliveMs: 500
                                                                                  });
                                                                          
                                                                                  function getSubTracks(folderName) {
                                                                                      const tracksInFolder = getTracks().filter(t => t.parentFolderName == folderName);
                                                                                      const tracksInFolderNames = tracksInFolder.map(t => t.name);
                                                                                      let activeSubTrackCount = 0;
                                                                          
                                                                                      tracksInFolder.forEach(t => {
                                                                                          const isIgnored = IGNORED_TRACK_NAMES.includes(t.name.toUpperCase());
                                                                                          if (!t.isInactive && !isIgnored) {
                                                                                              activeSubTrackCount++;
                                                                                          }
                                                                                      });
                                                                          
                                                                                      const onlyIgnoredOrInactive = tracksInFolder.every(t =>
                                                                                          IGNORED_TRACK_NAMES.includes(t.name.toUpperCase()) || t.isInactive
                                                                                      );
                                                                          
                                                                                      const folderTrack = getTracks().find(t => t.name === folderName && t.type.endsWith("Folder"));
                                                                          
                                                                                      if ((activeSubTrackCount === 0 || onlyIgnoredOrInactive) && folderTrack) {
                                                                                          foldersToProcess.push(folderName);
                                                                                          return;
                                                                                      }
                                                                          
                                                                                      if (tracksInFolderNames.length === 1) {
                                                                                          const subTrack = getTracks().find(t => t.name === tracksInFolderNames[0]);
                                                                                          const isIgnored = IGNORED_TRACK_NAMES.includes(subTrack.name.toUpperCase());
                                                                          
                                                                                          if (subTrack.isInactive && isIgnored && folderTrack) {
                                                                                              foldersToProcess.push(folderName);
                                                                                              return;
                                                                                          }
                                                                          
                                                                                          if (subTrack.type.endsWith("Folder")) {
                                                                                              getSubTracks(subTrack.name);
                                                                                          }
                                                                                      }
                                                                          
                                                                                      if (tracksInFolderNames.length === 0 && folderTrack) {
                                                                                          foldersToProcess.push(folderName);
                                                                                      }
                                                                          
                                                                                      tracksInFolder.forEach(subTrack => {
                                                                                          if (subTrack.type.endsWith("Folder")) {
                                                                                              getSubTracks(subTrack.name);
                                                                                          }
                                                                                      });
                                                                                  }
                                                                          
                                                                                  getSubTracks(folderName);
                                                                              });
                                                                          
                                                                              if (foldersToProcess.length > 0) {
                                                                                  hideFolderTracks(foldersToProcess);
                                                                                  deactivateFolders(foldersToProcess);
                                                                                  deletedOrHiddenFolders.push(...foldersToProcess);
                                                                              }
                                                                          
                                                                              const updatedInactiveFolders = getTracks().filter(t => t.type.endsWith("Folder") && t.isInactive).length;
                                                                              const previousInactiveFolders = inactiveTracksInSession.filter(t => t.type.endsWith("Folder")).length;
                                                                          
                                                                              if (updatedInactiveFolders != previousInactiveFolders) {
                                                                                  pass++;
                                                                                  hideAndDeactivateEmptyFolderTracks();
                                                                              }
                                                                          
                                                                              sf.interaction.notify({
                                                                                  title: "Hide Empty Folders",
                                                                                  message: `${foldersToProcess.length} folders Hidden and made inactive`
                                                                              });
                                                                          }
                                                                          
                                                                          function deleteEmptyFolders() {
                                                                              let tracksInSession = getTracks();
                                                                              const folderTracks = tracksInSession.filter(t => t.type.endsWith("Folder"));
                                                                              const folderTrackNames = folderTracks.map(f => f.name);
                                                                          
                                                                              let foldersToDelete = [];
                                                                          
                                                                              folderTrackNames.forEach(folderName => {
                                                                                  const tracksInFolder = tracksInSession.filter(t => t.parentFolderName == folderName);
                                                                          
                                                                                  const onlyIgnoredOrInactive = tracksInFolder.every(t =>
                                                                                      IGNORED_TRACK_NAMES.includes(t.name.toUpperCase()) || t.isInactive
                                                                                  );
                                                                          
                                                                                  if (tracksInFolder.length === 0 || onlyIgnoredOrInactive) {
                                                                                      foldersToDelete.push(folderName);
                                                                                  }
                                                                              });
                                                                          
                                                                              if (foldersToDelete.length > 0) {
                                                                                  deleteFolders(foldersToDelete);
                                                                                  deletedOrHiddenFolders.push(...foldersToDelete);
                                                                              }
                                                                          
                                                                              if (tracksInSession.length != getTracks().length) deleteEmptyFolders();
                                                                          
                                                                              sf.interaction.notify({
                                                                                  title: "Delete Empty Folders",
                                                                                  message: `${deletedOrHiddenFolders.length} folders deleted`
                                                                              });
                                                                          }
                                                                          
                                                                          function main() {
                                                                              const deleteOrHide = sf.interaction.displayDialog({
                                                                                  prompt: "Delete or deactivate/hide all empty folders?",
                                                                                  buttons: ["Cancel", "Delete", "Hide"],
                                                                                  defaultButton: "Hide"
                                                                              }).button;
                                                                          
                                                                              deleteOrHide == "Delete" ? deleteEmptyFolders() : hideAndDeactivateEmptyFolderTracks();
                                                                          }
                                                                          
                                                                          main();
                                                                          

                                                                          Just change the string in const IGNORED_TRACK_NAMES
                                                                          to your folder names and you are good to go. works with active or inactive folders.