Meanwhile, on my end...

The past month has gone by in a blur, but until I am able to fully catch up I decided to put some useful tidbits out there, since macOS is still my preferred platform and I have a lot of personal backlog to go through–so best to space it out and get started right away:

Getting EXIF information from HEIC files

One of the things I have been putting off is rebuilding my photo processing and archiving pipeline to deal with HEIC files. I’ve long been using jhead to extract EXIF metadata and rename files accordingly as a first step, but jhead (and plenty of other similar CLI tools) are showing their age, so I decided to see what I could do with native macOS.

Another thing I’ve been putting off is writing more JavaScript (which I still despise as a language but cannot ignore), so I looked at JavaScript for Automation as a way to get going quickly.

As usual, the best resources for this kind of niche are third-parties rather than terse and unfriendly Apple docs, and there’s a great cookbook that walks you through the basics–it only took me half an hour (and some cursing) to build a little CLI tool to dump metadata from anything that supports EXIF in macOS:

#!/usr/bin/env osascript -l JavaScript

ObjC.import("Cocoa");

function run(argv) {
    if(argv[0]) {
        var url = $.NSURL.fileURLWithPath(argv[0]),
            source = $.CGImageSourceCreateWithURL(url, null),
            metadataRef = $.CGImageSourceCopyPropertiesAtIndex(source, 0, null),
            err = $.NSError;
        if(metadataRef) {
            var dic = $.NSDictionary.dictionaryWithDictionary(metadataRef);
            /* Alternatively, you can have some fun with this: 
            var allKeys = ObjC.unwrap(dic.allKeys);
            var keys = allKeys.map((x => ObjC.unwrap(x)));
            var values = keys.map((x => ObjC.unwrap(dic.objectForKey(x))));
            console.log([keys, values]);
            */
            var json = $.NSJSONSerialization.dataWithJSONObjectOptionsError(
                    dic.objectForKey('{Exif}'), // yeah, magic.
                    $.NSJSONReadingMutableContainers, err),
                buffer = $.NSString.alloc.initWithDataEncoding(json, 
                    $.NSUTF8StringEncoding);
            console.log(ObjC.unwrap(buffer));
        }
    }
}

There is a little bit of magic involved here–you need to know how the Objective-C bridge name mangling works, but I’ve had plenty of experience with the Python bridge, so it all boils down to a bit of experience and educated trial and error.

But it works fine for HEIC, DNG and CRW (Canon RAW), and I’ll be rewriting my Automator workflows to incorporate it as time permits.

Personal E-Mail and Domains

It’s now been well over six months since I changed my personal e-mail workflow to MsgFiler, and it’s been working great for me: I can zip through most of my e-mail and re-file it with a few keystrokes, and I sorely miss this kind of thing when I’m on Windows. Overall, it’s probably the only third-party Mac app I have running 100% of the time.

When I have time to use it, that is. I am woefully behind on personal mail, so much so that I only caught up with Cloudflare‘s DNS registrar e-mails recently, and began the long and arduous process of clicking through Network Solutions’ hilariously bad back-office to migrate my domains to Cloudflare.

The experience is fraught with glitches, largely because Network Solutions appears to have re-locked this domain after sending me the transfer code, even though it shows up as unlocked on their back-office.

So I’m currently dead-locked between Cloudflare support and Network Solutions, which makes me dread the inevitable moment when I try to call them to get this fixed…

Assuming all of it eventually works on NetSol’s side, the only real drawback so far seems to be that Cloudflare only allows for yearly renewals, which is just plain weird, really. I really don’t want to deal with renewals annually and would gladly pay a little extra to renew domains for 3-5 years.

Ghosts, in Various Forms

Every now and then I benchmark other blog engines, and this week I had the occasion to set up Ghost on Azure App Service using this nice ARM template to help a customer put together a test web site.

It’s pretty nice as far as the authoring experience goes (it feels a lot like Medium, but without a good iOS app1) and it might be useful if I need to quickly set up an event blog, but the lack of search, proper tables, and (shockingly) an easy way to insert relative links to other posts turns it from a pretty nice to an ultimately pointless experience for me.

I’m also planning to tweak my infrastructure a bit, since I suspect uwsgi has been breaking the site now and then due to a memory corruption bug and really want to move to aiohttp and traefik to match the rest of the stuff I build.

Serendipitously, I’ve also been editing Pixels Camp posts on Medium, and expect to spend three days at the event having some fun (for a change)…


  1. Phantom doesn’t count, since it was recently removed from the App Store and seems to be dead, besides apparently lacking rich editing capabilities. ↩︎

See Also: