Title
Select/Show Tracks in Folder throwing errors
What do you expect to happen when you run the script/macro?
This has worked for a while and stopped working recently. It is supposed to select/show tracks within a folder. When I run it, I now get the error message:
TypeError: Cannot read property 'titleButton' of null
(Select/Show Tracks in Folder line 8)
Are you seeing an error?
TypeError: Cannot read property 'titleButton' of null (Select/Show Tracks in Folder line 8)
What happens when you run this script?
It seems like whenever I run it I get that error message. I have it as part of several different macros and they all give me the same error message.
How were you running this script?
I used a keyboard shortcut within the target app
How important is this issue to you?
4
Details
{ "inputExpected": "This has worked for a while and stopped working recently. It is supposed to select/show tracks within a folder. When I run it, I now get the error message:\n\n TypeError: Cannot read property 'titleButton' of null\n(Select/Show Tracks in Folder line 8) ", "inputIsError": true, "inputError": " TypeError: Cannot read property 'titleButton' of null\n(Select/Show Tracks in Folder line 8) ", "inputWhatHappens": "It seems like whenever I run it I get that error message. I have it as part of several different macros and they all give me the same error message.", "inputHowRun": { "key": "-Mpfwh4RkPLb2LPwjePT", "title": "I used a keyboard shortcut within the target app" }, "inputImportance": 4, "inputTitle": "Select/Show Tracks in Folder throwing errors" }
Source
const { folder, action, includeFolder } = event.props;
/**
* @param {AxPtTrackHeader} track
*/
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;
}
function findNearestParentFolder(root, trackName) {
var folderStack = [];
function walk(node) {
var isFolder = node.type && node.type.indexOf('folder') >= 0;
if (isFolder) {
folderStack.push(node);
}
if (node.name === trackName) {
return folderStack.slice(-1)[0];
}
for (var i = 0; i < node.children.length; i++) {
var res = walk(node.children[i]);
if (res) return res;
}
if (isFolder) {
folderStack.pop();
}
}
return walk(root);
}
/**
* @param {AxPtTrackHeader} folderTrack
* @param {boolean} includeFolder
* @return {AxPtTrackHeader[]}
*/
function getTracksInFolder(folderTrack, includeFolder) {
var root = getTrackFolderStructure();
var nearestFolder = findNearestParentFolder(root, folderTrack.normalizedTrackName);
if (!nearestFolder)
return [];
let subTracks = nearestFolder.children.map(i => i.track);
return includeFolder ? [folderTrack, ...subTracks] : subTracks;
}
function selectTracksInFolder(folderTrack, includeFolder) {
sf.ui.proTools.trackSelectByName({
names: getTracksInFolder(folderTrack, includeFolder).map(t => t.normalizedTrackName),
});
}
function getInputPathOfSelectedTrack() {
sf.ui.proTools.appActivateMainWindow();
var path = sf.ui.proTools.selectedTrack.inputPathButton.popupMenuFetchAllItems().menuItems.filter(mi => mi.element.isMenuChecked)[0].names;
sf.ui.proTools.appActivateMainWindow();
return path;
}
function main() {
if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`;
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.invalidate();
//Get folder track
let track = folder;
//Make sure current folder is open
track.folderTrackSetOpen({
targetValue: "Enable",
});
//Select all audio tracks in folder
selectTracksInFolder(track, includeFolder);
//Only show these
if (action === "ShowOnly") {
sf.ui.proTools.trackListMenu({
menuItemName: 'Show Only Selected Tracks',
});
}
}
main();
Links
User UID: 04vQUq1KmYSCMZHeEkMslw0IpRu2
Feedback Key: sffeedback:04vQUq1KmYSCMZHeEkMslw0IpRu2:-N1A_ItcgOp47Fvx8myj
- Christian Scheuer @chrscheuer2022-05-04 11:05:05.447Z
Hey Daniel,
There were some changes in PT2022.4 to how folder track titles are presented. I'll take a look.
Christian Scheuer @chrscheuer2022-05-04 11:05:28.988Z
What would be examples of the input values for the template? How would we test this?
- DDaniel Knobler @Daniel_Knobler
I have a basic folder named * that contains all of the tracks for a mix (which are organized into different folders). I use that script to select all folders within * and then I use another script to toggle them open or closed.
- In reply toDaniel_Knobler⬆:Christian Scheuer @chrscheuer2022-05-04 11:15:12.610Z
Try this:
const { folder, action, includeFolder } = event.props; /** * @param {AxPtTrackHeader} track */ function getTrackDepth(track) { if (track === null) return 0; 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.filter(t => !!t).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 findNearestParentFolder(root, trackName) { var folderStack = []; function walk(node) { var isFolder = node.type && node.type.indexOf('folder') >= 0; if (isFolder) { folderStack.push(node); } if (node.name === trackName) { return folderStack.slice(-1)[0]; } for (var i = 0; i < node.children.length; i++) { var res = walk(node.children[i]); if (res) return res; } if (isFolder) { folderStack.pop(); } } return walk(root); } /** * @param {AxPtTrackHeader} folderTrack * @param {boolean} includeFolder * @return {AxPtTrackHeader[]} */ function getTracksInFolder(folderTrack, includeFolder) { var root = getTrackFolderStructure(); var nearestFolder = findNearestParentFolder(root, folderTrack.normalizedTrackName); if (!nearestFolder) return []; let subTracks = nearestFolder.children.map(i => i.track); return includeFolder ? [folderTrack, ...subTracks] : subTracks; } function selectTracksInFolder(folderTrack, includeFolder) { sf.ui.proTools.trackSelectByName({ names: getTracksInFolder(folderTrack, includeFolder).map(t => t.normalizedTrackName), }); } function getInputPathOfSelectedTrack() { sf.ui.proTools.appActivateMainWindow(); var path = sf.ui.proTools.selectedTrack.inputPathButton.popupMenuFetchAllItems().menuItems.filter(mi => mi.element.isMenuChecked)[0].names; sf.ui.proTools.appActivateMainWindow(); return path; } function main() { if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); //Get folder track let track = folder; //Make sure current folder is open track.folderTrackSetOpen({ targetValue: "Enable", }); sf.ui.proTools.invalidate(); //Select all audio tracks in folder selectTracksInFolder(track, includeFolder); //Only show these if (action === "ShowOnly") { sf.ui.proTools.trackListMenu({ menuItemName: 'Show Only Selected Tracks', }); } } main();
- DDaniel Knobler @Daniel_Knobler
This works. Thank you!
- SIn reply toDaniel_Knobler⬆:SoundFlow Bot @soundflowbot
This issue is now tracked internally by SoundFlow as SF-581
Christian Scheuer @chrscheuer2022-05-11 10:24:14.447Z
We have this fixed now so that the original code/script you had will start working again.
The fix will be part of 5.1.5 when it comes out.
- DIn reply toDaniel_Knobler⬆:Daniel Knobler @Daniel_Knobler
Is there any way to make this script select/show ALL selected tracks? It seems like at the moment it can only do a single selected track "by using the "" option. If multiple tracks are selected when the script is run it only works on the first selected track.
Thanks!
- SIn reply toDaniel_Knobler⬆:SoundFlow Bot @soundflowbot
This issue has been marked as Done