Category: Hazel


Hazel’s 15th 16th Anniversary

September 6th, 2022 — 9:05am

It’s been 16 years ago today since Hazel’s first release. Why celebrate the 16th anniversary? Because I thought it was actually 15 years but got the dates wrong. So, to mark the 16th anniversary (or a belated 15th, if you prefer), Hazel is 30% off. That applies to all license types (single, family, and upgrade). Just go to the store. Sale ends at 3am EDT.

Chances are if you are reading this, then you already own a copy so share the news with friends and family. Just don’t tell Zach in Accounting. He knows what he did.

While odd bits have changed since the 10th anniversary, things remain mostly the same. After all these years, still not in the App Store. No plans to shift to a subscription model. I’ve resisted many of the “innovations” in software sales and distribution in recent years. I could probably write another post why but in short, I haven’t found any need to change something that works.

Can’t say whether I’ll still be here doing this for Hazel’s 20th anniversary but I hope you’ll forgive me if I forget again and end up being a year or two late.

1 comment » | Business, Hazel, Noodlesoft

Codesigning & Notarization Woes

January 25th, 2021 — 1:34pm

As mentioned in my last post, I had various issues with codesigning and notarization during Hazel 5’s launch. Now before I get into it, remember during all this that Hazel is codesigned and notarized with no warnings or errors. In my release build process, I do a codesign —verify as well as spctl to make sure everything is hunky-dory before submitting to Apple for notarization.

The biggest problem at launch was some users getting an “Unidentified developer” alert when opening the dmg. I had various users send in logs, but it was only when someone found a log message pertaining to the rpath for one of the binaries in the bundle that I was able to identify the problem. Strangely enough, that person didn’t receive the “Unidentified developer” error alert.

Turns out, I had mistakenly added a binary to the top level bundle (it was originally in a framework). The binary had an rpath which escaped the framework bundle as it depended on a sibling framework. This worked fine when the binary was in the framework bundle but when it was at the top level of the main app bundle, it escaped the app bundle itself. Not sure how the binary got added to the Copy Files phase there but it was an easy fix to remove.

Another issue was that the installer wasn’t triggering for some people. For the installer to trigger, Hazel needs to detect that it is running from a disk image. Further investigation turned up that Hazel was being translocated. If you don’t know what translocation is, I suggest reading this article: https://lapcatsoftware.com/articles/app-translocation.html

When translocated, the binary is no longer on the disk image, instead it is copied to a temp location on disk. Hazel is unaware of this and as a result, doesn’t run the installer. Why was Hazel being translocated? I’m still not sure. It’s my understanding that if an app and its containing dmg is signed and notarized, it shouldn’t be translocated. As a workaround, I ended up using the private SecTranslocate.h APIs to detect the translocation and compensate appropriately.

Possibly related to the above, there was also an issue with the embedded helper app not running. Logs from users showed that the quarantine flag was still set on the helper and that was preventing it from being run. When the user copies an app, like say from a disk image to /Applications, the quarantine flag should be cleared for the app and everything inside but for some reason it was not clearing it for the embedded binaries. Note that unlike when a user launches an app from Finder where they will be asked to run the app, a login item helper will fail to launch without any prompt. As a short term workaround, on first run, I had Hazel recursively remove its quarantine flag before it attempted to run the helper.

Even with the workarounds, something didn’t sit right with me. I suspected there was something wrong with my bundle that was causing these issues. I ended up filing a DTS incident to get some feedback from Apple. The DTS engineer was able to reproduce the issue on a VM and dig up a log message indicating that it could not clear the quarantine flag on the Autoupdate helper app in the Sparkle framework. For those that don’t know, Sparkle is a very commonly used framework for apps to update themselves. The Autoupdate helper runs when your app is terminated so that it can install and run the new version.

This all lead to an investigation into where should Autoupdate, or executable binaries in general, be put in a framework. Now, I had looked into this once before . Sparkle originally put Autoupdate in Resources which is incorrect and can cause subtle issues. The solution I came up with back then was to put any executables alongside the framework binary, which would be in Versions/A with a symbolic link at the top level of the framework bundle. This seemed to work at the time. It got through codesigning and notarization checks without issue and ran fine after that.

But it seems that the problem is more subtle than that as whatever code that clears quarantine flags on embedded bundles didn’t like that. I was pointed to this article which suggests I put the program in Contents/Helpers. Despite the insistence that this was the way to do it, it flat out did not work. An important thing to note is that framework bundles do not have a Contents directory. Putting a Contents directory, either in Versions/A or at the top level will make codesign barf, complaining about an invalid bundle format. My guess is that when codesign sees a Contents directory, it considers the bundle to be another (non-framework) type of bundle. After wasting a good bit of time on this, I went with what I thought made more sense, putting it in a Helpers directory (sans Contents). If you have an Xcode “Copy Files” phase copy to Resources for a framework, for instance, it doesn’t put it in Contents/Resources, but in Resources so it made some sense to do it this way.

Sure enough, that worked. Of course, after fixing it, someone pointed out how some of the system frameworks use the Helper directory. I guess I should’ve checked there first. At least I have some confirmation that I was on the right track. Note that you should put the Helper directory under Versions/A. You can symlink to the top level but that’s optional. I did it mainly to give myself a more consistent path to access it in the very unlikely event that I end up shipping different versions of the framework.

Overall, this experience has been very frustrating. There is little to no documentation on all the various things that can go wrong in your bundle that will cause things to fail, and when it does fail, the logging is very inconsistent. Lastly, none of the tools or processes in place (codesign, spctl, notarization) catch these cases. These are all issues related to the static structure of the app bundle so it seems like they should be detectable. Having a tool that developers can run on their bundles before submitting them would be very helpful as the current ones are far from complete in that regard.

After all this, I’m still not sure if the translocation problem is still there or not. I’m not about to remove a workaround just to have it fail for users just so I can get some feedback so that question will remain unanswered for the time being. The lack of definitive and correct information during this whole ordeal is a bit disturbing and makes me think that there’s no one that actually knows for sure how things really work.

For those at Fruit Company, I’ve filed FBAs FB8981011 and FB8981016.

Comment » | Hazel, Software, Tools, Xcode

Hazel 5 Launch Postmortem

December 20th, 2020 — 4:57pm

As promised, I thought I’d write about my launch. While not disastrous, it had its share of bumps. I had hoped that I had learned something from the Hazel 4 launch four years ago. One of the issues was server capacity. This year, I deployed an extra server. It was an asymmetrical setup, with my main setup handling the website and doling out free upgrades to recent purchasers, while the second server handled the store. Unfortunately, it wasn’t enough. The store still got swamped. Given how busy I was handling requests and trying to troubleshoot other issues, I didn’t have time to test and deploy yet another server, plus they would all be hitting the same database so it was unclear if it would help much. Given that this type of load tends to subside within the day, I rode it out.

One thing I could have done to help alleviate this was to spread out sending messages to the mailing list. Before sending anything to the list, traffic was quite manageable. Once the list got blasted, so did my site. I’m not sure if my email campaign provider supports it, but sending messages in chunks or just slowing down the sending rate would have probably minimized the problems.

Then there were packaging issues. Hazel is codesigned and notarized yet on some people’s systems, it would reject Hazel, either wholesale or in parts. This is worth a whole post on its own so expect one later. Suffice it to say, I did fix some of the issues and came up with workarounds for the others.

And finally, there were actual issues with the software.

First was a bug with trial mode expiring soon after install. I had Hazel reset the trial period for people coming from a previous version but it contained a bug which I did not catch. I did have a beta period but the version used then accepted Hazel 4 licenses, which meant that trial mode was not tested.

The other major bug was black backgrounds appearing in some views on 10.13. I take total responsibility for this as I did not test for 10.13. I did have a 10.13 partition on a drive I keep with various macOS versions, but it got nuked by an early Big Sur beta install which went awry. I tried reinstalling but my installer was corrupt. Add to that that Apple doesn’t allow you to download old installers and you can see how this fell by the wayside as other issues came up. It is ultimately my fault and my apologies to those running 10.13. As for the issue, it seems that 10.13 has problems with certain named/system colors when the app is linked against 11.0. Solution was to do special-case code for 10.13 using non-named colors.

There were plenty of other bugs but those were the most apparent and the ones I had to address quickly.

And with all of the above issues, I had to deal with thousands of people reporting them. Especially in the first few days, it was a frantic balancing act of being responsive to users while trying to carve out time to investigate the issues they were reporting. Logic would dictate stopping the bleeding first (i.e. investigate and address the problems) but it’s hard to ignore the huge number of messages piling up. Some would say that having all that attention would be a good problem to have, but when it was happening, it sure didn’t feel like it.

Lessons to be learned:

  • Try and slow down or space out announcements. Having everyone find out at once is asking for trouble. One idea I toyed with before launch but didn’t implement was to have a preview for those on the mailing list. Have a separate store that was available early where they could purchase an upgrade before the release to the public at large. That might have helped with the initial crush.
  • When running a beta test, be mindful of the holes in your testing, including differences between the beta and final product and missing demographics in your pool of beta testers.
  • Keep your priorities straight. Not everything needs to be handled immediately. It’s ok to ignore stuff.
  • Accept that no matter how much you prepare, you are never fully ready for what comes next.

Oddly, I found that the press was noticeably absent. It seems that even though the Mac market keeps growing, there are fewer and fewer outlets reporting and reviewing Mac products. Hazel has enough of a following that it didn’t matter as much but it feels as if things have regressed on that front, which is a bit sad.

Next time, I’ll be talking about my journey into the nightmare world of code signing and notarization. Fun times to be had by all. Until then…

2 comments » | Hazel, Noodlesoft, Software, System Administration

Hazel 5

December 9th, 2020 — 11:40am

I’m almost a month late with this announcement but Hazel 5 is out! I’ve been quite busy since the launch but after releasing 5.0.3 (yes, there have already been three patches) I feel like I have a little breathing room to post even if I’m bit exhausted.

I won’t give a full rundown of what’s new but you can get more details here.

The most obvious thing you’ll probably notice is that Hazel is no longer a preference pane, instead shipping in an app form factor. Why? The main reason is Apple. If you missed my post on this topic, in short, Apple screwed over preference panes in Catalina. The result is a buggy mess and I’ve seen almost no improvement on that front since then. It seemed clear to me that preference panes were a developmental dead end.

I had already been planning on releasing a version 5 so I was prepared to make some major changes. Problem was, I had to make sure I released 5.0 around when Apple’s next OS (now known as Big Sur) would arrive. Why? Because any Big Sur compatibility work put into Hazel 4 would most likely not be usable in version 5. Partly because of the major changes between the two but mostly because many of the issues that affect preference panes since Catalina aren’t a problem for apps. I could either do double the work or cut my losses and do a big push for version 5 in the time available. The downside is that the conversion to an app displaced other features I had planned. Some of these will make it into point releases but the bigger ones may have to wait until 6.0. 

It is nice to be able to have things in an app. There are fewer limitations but at the same time, it changes expectations. One of the major reasons why I had Hazel as a preference pane was that people expected preference panes to be for configuring services that run in the background. Since releasing as an app, I’ve had numerous people ask me to provide a way to hide the dock icon. People have the notion that they need to keep the app running for Hazel to run its rules, not realizing there’s a helper doing all that separately and that they can quit the app at any time. I did add in a little tip that pops up if you activate Hazel after a few minutes of inactivity (which would imply, to me, that they were keeping it running longer than needed) but I may need to be a bit more forceful in educating users.

Besides all the interface improvements, I’ve also added support for tables and lists. This expands the possibilities with text matching, hopefully allowing users to consolidate their rules. This took a good deal of back and forth in the design until I finally settled on what’s there now. There’s a chance these features will change in the future, especially with how list items work, but I’ll try and make sure it is done in a way to preserve compatibility with old rules. That’s always been a concern for me: making sure any changes I make to the rule schema/interface are done in a way such that old rules are expressible in the new paradigm. Except in the rare case where I drop a function entirely, I strive to make sure everything carries over.

One focus this time around was making the install process a bit nicer. Hazel 5 ships as an app on a disk image. The preferred way to install is to run it right off the disk image. Hazel will detect this case and offer to install into Applications (or a folder of your choosing) and relaunch. Or if you prefer, you can drag Hazel to a folder and run it there, in which case, the installer doesn’t kick in. The latter should reassure users that the app is self-contained and doesn’t install stuff in unexpected places. I’ve always felt that when you are first presented with an app, a double-click should run it, ready to do work. This includes any steps needed to get to that point, like installation. That was something that worked very well when Hazel was a preference pane and I wanted that same experience as an app. Having the user drag the app to Applications, navigate to it and then launch it seems like too many steps and I felt I could do better. If you want to do this with your own app, there are frameworks you can use.

Another thing I’ve added is the “Full Disk Access Guide”. For some operations, such as managing your Trash, Hazel requires full disk access. Unfortunately, Apple dropped the ball on this, providing little to no guidance or APIs to detect these cases and having no UI to help the user do it, thus leaving it to individual developers to cook up their own schemes. Previously, I pointed the user to a webpage which outlined the steps of navigating to the correct pane in System Preferences, unlocking it and then dragging the app into the list. For Hazel 5, I now bring up the correct pane in System Preferences and show a window/overlay which attaches itself to System Preferences, showing each step with arrows for guidance. Screenshot included below. And if it looks familiar to you, yes, I stole it from SuperDuper, with permission from its developer Dave Nanian (thanks Dave!).

Pricing is always a tricky issue. It’s always hard coming up with the right balance of something users will pay while also making sure your business is sustainable. But let’s address the elephant in room, or maybe the lack of said elephant. Subscriptions. I never really considered them for two reasons (a) I’m not particularly fond of them and neither are a good number of users and (b) I don’t need them. I’ve been fortunate in being able to keep doing this while charging a price that is fair to me and my users. Could I make more money? Sure, but if you’ve followed this blog for any period of time, you should realize that’s not my main goal.

That all said, I did end up raising prices as a lot of work went into this release. While users have been pretty supportive of the price changes, I can’t please everyone. In my defense, I’ll point out that I’ve been pretty good with providing significant amounts of functionality for free in between major releases (don’t believe me? Check out my release notes). Additionally, my major releases are pretty far apart (about every 4 years). Not that I’m doing that on purpose and I can’t guarantee the next one will happen at the same interval. It just happens to be how I do development. Major release sees major shift in architecture, paradigm or functionality. Minor releases flesh that out until I feel like that has run its course. Rinse, repeat.

And on that note, I hope to get one more release out before the end of the year. With luck, this will include a bonus feature which should make tables even more useful. Also, I’ll try and write up a post-mortem for the launch as it didn’t go quite so smoothly and I’m sure there are lessons to be learned there. And before I forget, thanks to you for your support. It’s been a long journey and it feels great reaching this milestone.

Comment » | Hazel, Noodlesoft, Software

Preference Panes and Catalina

August 28th, 2019 — 1:09pm

Apple announced numerous changes in Catalina in WWDC but there’s one that they failed to mention. System Preferences has had a major change: preference panes now load in a separate process. Apple ones get their own while all the third party ones get stuck in a process called “legacyLoader (System Preferences)”.

It’s becoming more common nowadays to split up programs into separate processes to isolate them from each other, usually done in the name of stability and security. The upshot of this to me is that all display and events happen via IPC between my pane and System Preferences. If done right, this should all be seamless and I shouldn’t notice a thing:

Window2

Of course, it’s never that simple.

First off, dark mode is broken. You can test this out by creating a blank preference pane in Xcode and loading that. For you Apple folks, that’s FB7076716. Interesting side note: problem doesn’t manifest itself if SIP is disabled.

The other problem is that magenta. What is that? Apparently, it’s a security feature. Any windows besides the main preference window will have their transparent areas colored magenta. I’ve been trying to pin down the rules as to when this occurs but it’s been slow going and also the screenshot above contradicts what I’ve been told. Note that my software is notarized so it’s not like this is only applying to unknown software.

To top this all off: none of this has been announced or documented. I’ve only found out about this through backchannels and then later, via a “conversation” via Feedback Assistant (FB6758586). It’s a big change and requires some major overhauls on my part. Aside from leaving things as they are, my options are to either rework my whole UI to avoid using any extra windows or convert my preference pane to an app. The latter is a long term goal but neither of those are realistic for doing over the summer between WWDC and Catalina’s launch. And mind you, that’s assuming they actually announced and documented this stuff up front (which they didn’t). How Hazel is going to look on Catalina is very much up in the air right now.

Maybe this will help other people writing pref panes as info on this is nowhere to be found (if I’m wrong on this, please send a link my way as I dying for any clarification on this). I don’t know how much of this Apple will fix as a good part of it is meant as a feature but one can hope that it will somehow sort itself out in the end.

Comment » | Hazel, OS X, Software, User Interface

AEftermath

January 29th, 2019 — 1:30pm

Now that the dust has mostly settled, I thought I’d follow up on my previous post concerning Mojave and its new privacy protections.

When Mojave was first released, there were complaints about Hazel not working. In these cases, Hazel was in the privacy list, but not checked. Users claimed to have not seen any sort of prompt. It’s hard to say if the prompt was just missed somehow or if there was a bug where the prompt was not showing up.

Months later, the issues stopped (or at least people stopped reporting them). I can’t say whether some sort of bug was fixed or if people are just now more familiar with how all the new privacy protections work. I’m leaning towards a bug of some sort as the reports have stopped altogether; I’d expect the occasional report of confusion if it was just a knowledge thing.

Regarding unit tests, it seems that changing my unit tests to run within an app, and adding the appropriate usage strings to the test app, was enough to get them to run. There is an issue of including Appkit in unit tests that are testing Appkit-independent functionality, possibly in resulting in subtle false positives in some tests. I suspect those cases will be very rare and, frankly, I’m just glad I can actually run my tests on Mojave now.

One issue that remains is filesystem level protections. With Mojave, certain directories (which I believe still aren’t documented) are protected, not by permissions, but a separate system tied in with SIP. The problem with this is lack of transparency both to us devs as well as users. I’ve had users waste a bunch of time trying to fix the issue by tweaking permissions and ACLs, not realizing that there is another system in place that is invisible to them. Very few users were able to suss out that they needed to add Hazel to the “Full Disk Access” list (instructions on how to do that can be found here).

Overall, it’s confusing since there’s little to no indication in the OS. Finder can view these folders fine whereas other Apple apps (like Terminal) can’t. The red badge on the folder icon looks the same as one for a folder protected by UNIX permissions.

At least, there seems to be one way as a dev to be able to make sense of things. Accessing protected directories (for instance, by using access() ) will fail with an EPERM error. This differs from accessing a directory protected by UNIX permissions. In those cases, you will get an EACCESS error. While that’s great for differentiating between the two cases what’s unclear to me is if there are other situations, outside of Mojave privacy protections, that would give me an EPERM error. Nonetheless, in the latest release, I’ve tried to detect this in Hazel and put up an alert. It’s a fairly uncommon case so I suspect most users will not run into this.

By now, most of the kinks have been worked out but it would be nice if Apple were to document this stuff. The path getting to this point was far more rocky than it should have been.

Comment » | Hazel, OS X, Programming

Hazel and the AEpocalypse

September 4th, 2018 — 1:13pm

This morning I released a beta of Hazel with a good deal of trepidation. If you’ve been following the dev blogosphere, you should know that the AEpocalpyse is coming. For those not in the know, Mojave introduces privacy protections for access to AppleEvents, prompting the user whenever an app tries to send AppleEvents to another app.

Here’s some reading to get you up to speed:

Felix Schwarz: macOS Mojave gets new APIs around AppleEvent sandboxing – but AEpocalypse still looms
Daniel Jalkut: Apple Events Usage Description
Dave Nanian: macOS Mojave: Opening New Vistas in Security for Mac Users
Paulo Andrade: Apple Events And The State Of macOS Automation

The result of all this is that we have a not-very-well-thought-out and buggy feature which was added late in the beta with no documentation. The last part makes it particularly hard as we have no way of knowing if the current behavior is a bug or by design, nor whether there will be any more changes or fixes before Mojave ships.

As it stands right now, I am faced with the following problems:

  • I cannot run a number of my automated tests.
    My tests test functionality that uses AppleEvents or the tests use AppleScripts themselves to verify test results. Adding the usage description keys to the Info.plists of the xctest bundles does not work. Also, it’s unclear which app the keys should be added to as it’s not documented whether a helper app, or its enclosing app needs to include them. On top of that, I don’t own the running app in this case so changing those keys will break the code signature. If anyone has a workaround for this, I’m all ears.
  • If the user is away when the prompt comes up, the request can time out and it will silently default to denying authorization thereafter.

    As pointed out by Dave Nanian in his post above, users may never see the prompt to provide access and later find that key functions are not working. To fix it requires using the commandline (provided the user knows what’s going on). Update: This is fixed in beta 10.
  • In some cases, users may be prompted twice for the same feature within Hazel.
    For example, when using the “Import into Photos” action, users will be prompted in the UI as Hazel needs to fetch the list of Photos albums via the MediaLibrary API. Then to do the import itself, Hazel has to use AppleEvents, which brings up another prompt. Guarding AppleEvents is a bit orthogonal to the other access restrictions as it is focusing on an access mechanism and not the information being accessed, resulting in redundancies like this.
  • Running user scripts is problematic
    Since Hazel allows users to run their own scripts, I may end up having to specify usage strings for everything, in the off-chance a user’s script accesses that area of the OS.
  • AEDeterminePermissionToAutomateTarget doesn’t work very well
    Felix’s post outlines this function. It has a critical bug making it near useless for me. On top of that, it requires the app you want to access to be running to determine permissions which leads to a less than ideal user experience.

In short, unless Apple fixes this soon, or even better, rolls it back to be released later, things are going to be a bit bumpy in Mojave. As a user, you may be surprised how often AppleEvents come up in the apps that you use.

The Hazel beta is out (forum login required) so if you are on Mojave (or even if you’re not; I need to make sure I didn’t break things on previous OS versions), give it a try. Reports from the field will help greatly. My options may be limited given the scant documentation and tools provided by Apple but hopefully something can be done.

Update (Sept 13): Beta 11 is out. It fixes a couple of issues I’ve found:

  • It doesn’t seem to prompt anymore when using the MediaLibrary API so the “double-prompting” issue is no longer a concern. I was wrong on this. I thought I had reset permissions when doing the test but trying it again, it seems I didn’t. So, the double-prompt is still a thing.
  • If the user denies access, the app now appears in the SysPrefs Privacy settings, unchecked. This is huge as the user can now enable access without having to resort to tccutil

tccutil itself is still broken in that it does not work when specifying a bundle identifier. Makes it such that if you want to reset permissions, you have to do it for all apps, not just for the one you care about. This results in you getting re-prompted all over again. The fix to the Privacy settings above does alleviate much of the need for this but this still indicates a lack of thoroughness when implementing this new system.

Comment » | Hazel, OS X, Programming

Getting Info From iTunes

May 19th, 2017 — 12:35pm

Things have settled down with my 4.1 release so I thought I’d tend to my neglected blog.

Today, I’m going to talk about getting info about your iTunes library, playlists and albums.

Now, the obvious way to do this would be through AppleScript/AppleEvents. The problem with this approach is that it requires iTunes to be running for it to work. To actually change stuff in your iTunes library, you will have to use AppleScript but for the purposes of this article, we are just looking at ways to get information about it.

The old way to do this was to parse the iTunes Library.xml file (located in ~/Music/iTunes). This file contains a dump of everything you need. Unfortunately, recent versions of iTunes do not generate this automatically; you have to enable it in its preferences (it’s in the “Advanced” tab).

Now, the notion of having to parse an XML file does sound painful but luckily it’s actually a property list so you can load it that way and access everything as NSArrays, NSDictionaries, NSStrings, etc.

With OS X 10.9 (yes, I know it’s macOS now but back then it was still OS X), Apple introduced the MediaLibrary API (ML). This provided a way of not just accessing the iTunes library, but the libraries of all of Apple’s other media apps (Photos, GarageBand, even Final Cut). No parsing involved but it is a fully asynchronous API so expect to deal with a lot of callbacks.

The last one (I don’t know exactly when it was released but it was the last one I discovered) is iTunesLibrary (ITLib) and it’s a bit easy to miss because, from what I can tell, it is not a part of the OS, but iTunes itself. You can find the framework under /Library/Frameworks (not /System/Library/Frameworks). It provides similar functionality to the MediaLibrary framework, but specific to iTunes.

With so many options, which do you use? For the most part, they return the same information though it depends on the version of iTunes. With some versions, one API may return some special playlist that the others don’t. Also, ML is asynchronous while the others are synchronous. I don’t see that as a big deal either way as you can convert one into the other with a tiny bit of work.

The big differentiating factor is performance. Here are the results for getting a list of playlists for my library:

XML: 1.664939s
ML: 18.792855s
ITLib: 0.844415

I don’t think my library is the biggest in the world but it is significant (about 2000 albums). As you can see, ML is pretty damn slow with ITLib being much, much, much faster. What is surprising to me is how much faster parsing the XML file is than ML. It is possible, though, that I’m holding it wrong.

So, ITLib is my recommended API for this. It’s what Hazel uses starting with 4.1 (previously, it was parsing the XML when it was available and falling back to ML). That said, there is one wrinkle.

The persistent IDs of entities in iTunes are hex strings. In the XML file, they are zero padded. In ML, though it returns strings, they are not zero padded (rdar://26624642 for you Apple folks watching from home). To add even more confusion to the mix, they are NSNumbers in ITLib.

If you are using any of these APIs in isolation then it’s probably not a big deal, but if you want to later manipulate that entity using AppleScript (like importing files into a playlist), you will need to provide the zero-padded hex string. Something to keep in mind.

Comment » | Cocoa, Hazel, OS X, Programming, Software

Ten Years

September 6th, 2016 — 7:00am

Today marks the 10th anniversary of Hazel. On September 6, 2006, Hazel 1.0 was released and after all this time, it’s still going strong. I’ve already shared my thoughts on why I took this journey and how I managed to stay on this road so I won’t rehash that here. What started as a product developed in my bedroom is, well, still a product developed in my bedroom, but now I can say it’s a successful one.

Hazel back then was a much more basic product. You can check out the release notes page, which documents everything back to the beginning. It’s interesting to see what features were added later, many of which are probably considered essential now.

As for the future, who knows? While the list of big features I want to implement is much shorter now, there are still a bunch of smaller things I want to put in. I can’t say whether I’ll still be doing this in another ten years but I have no intention of quitting now.

And with today being the anniversary, I need to celebrate in some way so, from today until 3am (EDT) tomorrow (Sept. 7), I am offering Hazel at its original price from 10 years ago. That’s $16 (50% off). The family pack and upgrade didn’t exist back then but they’re 50% off as well. No special code or link. Just go to the store and buy. If you don’t have a copy yet, here’s your chance.

2 comments » | Business, Hazel, Noodlesoft, Software

Cleaning Out Turd Files

May 17th, 2016 — 12:37pm

A little pet peeve of mine are the turd files that Emacs leaves behind all over the place.

For those that don’t use Emacs, when you edit files with it, it will keep a backup of the original file in a file with the same name, except with a tilde (~) at the end. The problem is that you have to manually clear them out. When you are jumping around in Terminal editing config files left and right, trying to get something working, you tend to forget where those files are. And yes, you can turn that off, but I like having the backups and yes, you can specify that it store its backup files in a common place but it makes it harder to recover files should I need to check the backup version, especially when I’m editing a bunch of files with the same name (index.php anyone?).

Since Hazel before version 4 only operated on actual folders/directories in the filesystem, it couldn’t really handle cases like this where the files are strewn all over the place. Now with Smart Folder support, you can create one to match all the turd files and have Hazel clean them up for you. Here’s a Smart Folder and Hazel rule you can use yourself:

Turd Cleanup

One important bit about the Smart Folder conditions is that I use “Filename” and not the more readily available “Name” or “File extension” attributes as the ~ is tacked onto the end regardless of whether there is an extension or not.

And of course, no reason to limit it to Emacs turds. Go ahead and edit the Smart Folder to include whatever other poops you have on your system.

Comment » | Hazel, Software, System Administration

Back to top