And here is a slightly improved version of the script that also shows the app icon when the file is an app. This requires the latest BTT alpha 4.717 though - with previous versions the icons would be huge.
async function retrieveJSON() {
let folder = "/Applications";
let tags = ["Red", "Green"];
// Join tags to form the search query, each tag must be checked separately with an OR condition
let tagQuery = tags.map(tag => `kMDItemUserTags == '${tag}'`).join(" || ");
// Construct the shell script with the folder and tags
let script = `mdfind -onlyin ${folder} "${tagQuery}"`;
let filePaths = await runShellScript({
script: script,
});
// Split the file paths by new line
let fileArray = filePaths.split("\n").filter(Boolean); // filter(Boolean) removes any empty lines
// Create an array of objects with filePath and fileName
let files = fileArray.map((filePath) => {
let fileName = filePath.split("/").pop(); // Extract the file name from the path
return { filePath, fileName };
});
let menuItems = [];
// Function to retrieve the icon path by reading the Info.plist
async function getAppIconPath(filePath) {
// Construct the path to the Info.plist file
let plistPath = `${filePath}/Contents/Info.plist`;
// Run a shell script to retrieve the CFBundleIconFile from the Info.plist
let iconName = await runShellScript({
script: `defaults read "${plistPath}" CFBundleIconFile || echo "AppIcon"`,
});
// Add the .icns extension if not present
iconName = iconName.trim();
if (!iconName.endsWith(".icns")) {
iconName += ".icns";
}
// Return the full path to the .icns file
return `${filePath}/Contents/Resources/${iconName}`;
}
// Create the context menu items that trigger a shell script to open the file
for (let file of files) {
let iconPath = await getAppIconPath(file.filePath); // Get the correct icon path from Info.plist
let item = {
title: file.fileName,
action: `js::(async () => {runShellScript({script: 'open "${file.filePath}"'})})()`,
icon: `path::${iconPath}::width@@30`
};
menuItems.push(item);
}
return JSON.stringify(menuItems);
}
Instead of a context menu, you can also use this script with the "Choose From List" action: