Jump to content

Recent Files Workflow with built in objects


Recommended Posts

Inspired by some of @Floating.Point's recents posts, I wanted to set out and a make a recent files workflow that doesn't rely on the universal action as certain apps don't seem to provide accurate results. My main Digital Audio Workstation, Pro Tools is one. 

 

I built something kind of simple and something slightly less simple, but wondering if there is a better way to do this.......

 

version 1:

 

image.png.61474edf809e12f6a63954de3025af85.png

 

I just have the file filter's "limit and sort" tab set to 3 days and when i type "*" i get those results on all files.

 

---

the slightly more complicated version of this is choosing the file type first with a list filter.... 

image.thumb.png.c6010e1f1665827663ba9326ba5bf83f.png

 

image.thumb.png.b463c772c0ee541162fdc5adf5dacd7f.png

 

 

 

 

the arguments in the list filter are the file utis that then get stored in the json object:

 

{
  "alfredworkflow" : {
    "config" : {
      "types" : "{query}",}
	}
}

 

and the file filter is setup the same as the first example.

 

Another version of this can be built with an automation task where it identifies the frontmost app, -- matches the uti (probably with a conditional utility) -- and then the rest of the workflow is the same.

 

these methods always give me the results I'm looking for (and with alfred's built in objects -- but i'm wondering if there is a better way. I would love not the have to type the "*" every time. Is there a smarter more efficient way. I tried prepopulating the keyword of the file filter with a variable but couldn't get that to work. 

 

 

Edited by sepulchra
Link to comment
Posted (edited)

well i think i may have overcomplicated this all together. 

 

1. I see i can pepopulate the wildcard in the hotkey.

2. if i want to narrow down to a specific file type i can just type the extension after the wildcard ..... ie ..... "*taskpaper"  or "*wav" 

 

that approach kind of eliminates the need for my list filter uti based system.

 

Edited by sepulchra
Link to comment
  • sepulchra changed the title to Recent Files Workflow with built in objects

@Floating.Point I tried to building something that might get at what you are looking for. It does not use that API but wonder if this gets close:

image.thumb.png.e7017e2b4e13a4507ddce599873f1775.png

 

right now i just have one app in the conditional (you could have as many as you want) -- but if it matches taskpaper -- it then goes to the json object that sets file uti for the file type in the file filter

 

image.thumb.png.ebda0f95f7c7286d8fa10c6bf3fc05af.png

 

I have the limit and sort set to 30 days but that can be reduced. I still can't figured out how to set the search field to prepoluate with an "*" 

 

Maybe someone with more programming experience can make this work more efficiently? maybe a script filter can do all of these things?

 

 

 

 

Link to comment

Ah okay, so if I'm not mistaken, this would require that you manually add each filetype to be parsed by each app. For example if I have: .mov .mp4 .mkv .aiff. .mp3 .etc all associated with IINA media player, this workflow would need to be told explicitly that those filetypes should be opened with that app. What I'm getting it is a way to make that step dynamic, so it will do a kind of reverse lookup: identify the app, and then automatically determine which filetypes are associated with it, and those files should be returned by Alfred.

Link to comment

well I should have thought of that -- i thought you could just have it populated there without a variable -- but this makes sense. and to respond to your earlier note.

 

 

I suspect it could be done dynamically but I don't have the programming experience. But you are right -- in my setup when the app is matched in the conditional it then outputs the correct uti -- which i manually had to input. If there is a way to do it dynamically with a script filter that would be very cool. If that "identify front most app" could output the associated uti, then that could also work, but it does not have that as an option. Maybe this thread can pique @vitor's interest. 

Link to comment

The Launch Services pages says you can use them to:

  • Identify the preferred app for opening a document or URL
  • Register information about the kinds of document files and URLs an app can open

But not, crucially, identify the documents and apps an application is configured to open. That’s the thing that needs to be ascertained, and it may not be possible without hacky methods or parsing specific plists (something that could work but is prone to breakages from Apple). You can see what an app says it can open (though it may not be associated with it) by parsing its Info.plist. Something like, in /usr/bin/osascript (JavaScript):

 

function documentTypes(infoPlist) {
  const plistJSON = Application("System Events").propertyListFiles.byName(infoPlist).contents.value()
  const getEntries = (parentKey, childKey) => plistJSON[parentKey]?.flatMap(item => item[childKey] || []) || []

  return {
    Extensions: getEntries("CFBundleDocumentTypes", "CFBundleTypeExtensions"),
    ItemContentTypes: getEntries("CFBundleDocumentTypes", "LSItemContentTypes"),
    MIMETypes: getEntries("CFBundleDocumentTypes", "CFBundleTypeMIMETypes"),
    URLSchemes: getEntries("CFBundleURLTypes", "CFBundleURLSchemes"),
    UTTypeIdentifiers: getEntries("UTImportedTypeDeclarations", "UTTypeIdentifier")
  }
}

documentTypes("/Applications/Safari.app/Contents/Info.plist")

 

The last line is how you call it, in the example using Safari. Here’s the result for that:

 

{
  "Extensions":["css", "pdf", "webarchive", "webbookmark", "webhistory", "webloc", "download", "safariextz", "gif", "html", "htm", "shtml", "jhtml", "js", "jpg", "jpeg", "jp2", "txt", "text", "png", "tiff", "tif", "url", "ico", "xhtml", "xht", "xhtm", "xht", "xml", "xbl", "xsl", "xslt", "svg", "avif", "webp", "heic", "jxl"],
  "ItemContentTypes":[],
  "MIMETypes":["text/css", "application/pdf", "application/x-webarchive", "application/x-safari-extension", "image/gif", "text/html", "application/x-javascript", "image/jpeg", "image/jp2", "text/plain", "image/png", "image/tiff", "image/x-icon", "application/xhtml+xml", "application/xml", "text/xml", "image/svg+xml", "image/avif", "image/webp", "image/heic", "image/jxl"],
  "URLSchemes":["http", "https", "file", "x-safari-https", "prefs", "x-webkit-app-launch"],
  "UTTypeIdentifiers":[]
}

 

QuickTime Player:

 

{
  "Extensions":[],
  "ItemContentTypes":["com.apple.quicktimeplayerx-composition", "com.apple.quicktimeplayerx-composition-bundle", "public.avchd-content", "public.avchd-collection", "public.audiovisual-content", "public.audio", "public.mpeg-4-audio", "com.apple.protected-mpeg-4-audio", "public.mp3", "public.ulaw-audio", "public.au-audio", "public.aifc-audio", "public.aiff-audio", "com.apple.coreaudio-format", "org.3gpp.adaptive-multi-rate-audio", "com.digidesign.sd2-audio", "com.microsoft.waveform-audio", "public.movie", "com.apple.quicktime-movie", "public.mpeg", "public.mpeg-2-video", "public.mpeg-4", "com.apple.protected-mpeg-4-video", "public.dv-movie", "public.avi", "public.flc-animation", "public.3gpp", "public.3gpp2", "com.apple.photos.apple-adjustment-envelope", "com.apple.photos.slow-motion-video-sidecar", "public.camera-raw-image", "public.jpeg", "public.png", "public.tiff", "public.heif", "public.folder", "com.apple.mediaextension-content", "com.apple.avurlasset-content"],
  "MIMETypes":[],
  "URLSchemes":[],
  "UTTypeIdentifiers":["public.sdp", "public.avchd-content", "public.avchd-mpeg-2-transport-stream", "com.apple.photos.apple-adjustment-envelope", "com.apple.photos.slow-motion-video-sidecar"]
}

 

Preview:

 

{
  "Extensions":[],
  "ItemContentTypes":["public.folder", "com.apple.application-bundle", "com.apple.package", "com.adobe.pdf", "com.apple.pdf-printer-settings", "com.apple.localized-pdf-bundle", "public.ofd", "com.adobe.illustrator.ai-image", "public.jpeg", "com.apple.rjpeg", "public.png", "public.tiff", "public.camera-raw-image", "public.heif", "public.heifs", "public.avif", "public.heic", "public.heics", "public.avci", "public.avcs", "public.pbm", "public.pvr", "org.khronos.astc", "org.khronos.ktx", "com.google.webp", "org.webmproject.webp", "com.microsoft.dds", "public.xbitmap-image", "com.ilm.openexr-image", "com.microsoft.bmp", "com.compuserve.gif", "com.microsoft.ico", "com.truevision.tga-image", "com.sgi.sgi-image", "com.adobe.photoshop-image", "com.apple.macpaint-image", "com.kodak.flashpix-image", "public.fax", "com.apple.icns", "public.jpeg-2000", "public.radiance", "public.mpo-image", "com.apple.pict", "public.3d-content", "com.pixar.universal-scene-description", "com.pixar.universal-scene-description-mobile"],
  "MIMETypes":[],
  "URLSchemes":[],
  "UTTypeIdentifiers":[]
}

 

As you can see, apps don’t necessarily register everything. The first three are bound to be the most useful.

 

To explore the entire Info.plist for an app and poke around, do:

 

/usr/bin/plutil -convert json '/Applications/Safari.app/Contents/Info.plist' -o -

 

 

Edited by vitor
Updated code
Link to comment

Ugh, I got so close to hacking together something that would return only those UTIs that will actually open in an app by default.

I thought this was it – until I discovered some apps dont seem to work… and for now at least, im gonna give up on this one.

It all started with this (LLM assisted):

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep -B 6 -A 2 -i "role.*com.apple.quicktimeplayerx"

 

And I got this far with it:

  • Cache the resulting UTI's for each app in one big JSON file
  • The workflow will check the cache first and if it finds an entry it will skip the lookup and just output the results.
  • If there's no results it will perform the lookup and add entry to the JSON
  • Added the ability to force the cache to update

  • then I discovered it didn't actually work for all apps. 
    I troubleshot for a few more hours…
    then I had to let this one go. Got very close though, and I learned how to store results in a JSON and later retrieve them, so not wasted time.
Link to comment

You do much more than that. When I’m “needed” at a thread you’ve been participating in, I can be confident the scope and goals of the matter have been fleshed out and that a reasonable attempt has been made (which further defines the scope and highlights pitfalls). It allows me to go right to thinking of the solution (or why there isn’t one) instead of the loop of asking for more details → wait → get response…

 

But far from me to discourage you from learning more coding! You are clearly keen to understand and aren’t afraid to experiment, which is a great combo.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...