Download Jigsaw for macOS

Jigsaw app icon

Like I said the other day, Jigsaw is one of those ridiculously fun (dumb?) ideas that come along and smack you upside the head one day and you can’t help but take an afternoon to build.

It’s also such a silly idea that I’d normally open source the code so other folks can tinker around with it. Unfortunately, my CloudKit syncing stack is based on a closed source framework that I can’t distribute. (Ensembles, if you’re curious. It’s basically the greatest thing ever and makes my life as a Mac/iOS developer so easy.)

Instead, Jigsaw is free to download and have fun with.

In case you missed my post about why this app even exists…

Apple already lets you sync the contents of your Desktop using iCloud. But, if you’re a visual person like me who often arranges their Desktop icons in meaningful ways, not having the positions of your files on screen also stay in sync is frustrating as I move between my laptop and desktop throughout the day.

Jigsaw solves that by syncing the positions of your Desktop icons over iCloud. Move a folder on your iMac, and a few seconds later it mirrors itself on your laptop. Here’s a demo…

Caveats

I’ve tested Jigsaw on Mojave and Catalina. I don’t know of any reason why it wouldn’t also work on Big Sur, but it’s untested for now.

I also haven’t even attempted to think about or solve any of the myriad problems that might arise from using multiple monitors.

Along those lines…

During testing this evening, I thought my sync code had gone haywire. I would move an icon on my iMac and almost immediately it would reposition itself into a random spot somewhere else rather than syncing across to my laptop.

What I finally realized was happening was this:

The position I happened to be moving that one icon on my large iMac screen was beyond the bounds of my laptop’s smaller Desktop window. The icon position was syncing correctly, however Finder on my laptop immediately moved it into a new (random) location onscreen. That new location then synced back to my iMac, which made me think my syncing was off. Turns out, iCloud sync was so fast I didn’t even notice it had round-tripped on me. (Nice work CloudKit folks!)

I mentioned in my previous Jigsaw post that I experimented with syncing the relative positions of icons instead of their absolute positions. It was as interesting solution in that it guaranteed icons would always remain on screen, but it led to odd behavior, so I took out that option.

Instead, Jigsaw’s one and only Preferences setting is to enable debug mode. When turned on, Jigsaw will sync all of your connected Mac’s screen sizes to iCloud, compute the smallest width and height among them, and then draw a red rectangle on your Desktop to show (in theory) the valid area you can safely arrange your icons within. (Again, I’ve tested this feature among my three computers – and only very briefly. YMMV.)

To support various screen sizes, I’m wondering about just ignoring icons that fall outside those bounds. But that presents its own sync challenges for another day.

Download Jigsaw

In any case, that’s Jigsaw. Probably not very practical, but it was fun to build on a rainy day. Download the app and let me know what you think.

Visually Syncing Your Mac’s Desktop

Earlier today, I had a short twitter conversation with Lauren Herda (she illustrated my first three Mac app icons).

Twitter conversation screenshot

I tweeted about symlinking my Mac’s Desktop folder into Dropbox to work around some iCloud Drive problems that had been plaguing me. It was a quick, off the cuff conversation, but for some reason it kept bouncing around in my head. A little while later when I was washing dishes, I jotted down the following note into Drafts

Screenshot of Drafts for iOS

Could we sync desktop icon positions over CloudKit??

Here’s the thing.

For me, my Mac’s Desktop is my staging ground, my active workspace, the digital representation of my mental RAM. I’ll typically have all of the files related to the task I’m currently working on stored on my Desktop. Once it’s complete, I’ll either file them away or delete them and move on to the next thing.

Having the Desktop on my iMac at home stay in-sync with my work laptop eases the transition and context switching as I move between locations. Dropbox has been doing this for years, but actually getting into the correct folder in Dropbox always has just enough friction to keep me from using it with active files the way I do my Desktop. When Apple added the option to sync your Documents and Desktop folders into iCloud Drive a number of years ago, it was a perfect fit for me…

…almost.

I’m a visual learner, and that way of thinking translates to how I work, too. That means, not only do I keep my active files on my Desktop, but I also arrange them visually in meaningful ways.

I’ll often shuffle files around into little groups to denote that they’re related to each other. Sometimes I’ll line a queue of files up on the left side of my Desktop and then move each one to the other side as I process them. My point is, in my workflow, the position of those Desktop items is a special bit of metadata that is often just as important as the contents of the files themselves.

So, it’s always seemed to me like a missed opportunity to not sync that metadata, too. And I realize that keeping the visual positions of files in sync comes with all sorts of thorny problems around different sized screens, multiple monitors, etc. But it seemed like a fun problem to think about on a rainy Saturday evening.

As you might guess, I did more than think about it.

The video above shows a macOS Mojave and Catalina virtual machine side-by-side, signed into my iCloud account. I wrote a small helper app that runs in the background and watches your Desktop for changes, which are then synced over CloudKit. The Mac on the other end, subscribes to those updates and repositions your Desktop icons accordingly.

For no particular reason other than I had to pick a name of some kind, this ridiculous little app is called Jigsaw.

When arranging your icons, Jigsaw has two modes of operation.

  1. It will sync the literal pixel coordinates of your Desktop icons from one machine to the next. This is mostly fine until you get into a scenario where one Mac has vastly more (or less) screen space than the other. In that situation, an icon can get accidentally repositioned offscreen. When that happens, the Finder steps in and moves it back onto the visible portion of your Desktop.
  2. Another way that I briefly toyed with was instead of syncing actual coordinates, I kept all of the icons synced proportionally / relative to each other and the screen. If you have an 800px by 600px monitor, with a folder at (400px, 300px) – that translates to 50% on each axis. When Jigsaw repositions the icon on your 1200px by 900px monitor, it will be placed at (600px, 450px).

I’m not sure which method is better. (Honestly, this whole idea is dumb ????) But that’s Jigsaw. Likely nothing more than an experiment but a fun, nerdy way to spend a Saturday evening.

If anyone is interested in trying it, you can download Jigsaw here.

DIY Video Hosting

I’ve been a paying customer of Vimeo since 2014 – specifically, their Pro plan.

Vimeo order receipt from 2014

(Please ignore that the above email receipt is for their Plus plan. Shortly after subscribing I realized I needed to upgrade to Pro, which supports commercial use.)

I needed a reliable way to host a bunch of screencasts and video tutorials I was producing for my software. I went with Vimeo because they’re the obvious choice in this space for two main reasons:

  1. I didn’t want my content hosted on YouTube where it would be surrounded on all sides by an infinite expanse of flaming garbage. (Don’t take that criticism too harshly – I’m a happy YouTube Premium subscriber.)
  2. Vimeo is really, really, really good at what they do. I mean, supremely top-notch when it comes to ease-of-use, controlling the end-user experience, speed, and quality.

But when my renewal email arrived in April, myself and other small developers were seeing sales slow down as the pandemic worsened.

Vimeo pricing chart

Another $240/year was a tough sell for the small amount of video content I was hosting with them, and I wondered if there might be a cheaper alternative – either another service or by hosting videos myself.

If you’re posting commercial content – like I often do – Vimeo’s terms require you to be a Pro subscriber or higher. And to be clear, I still think Vimeo at that price (at almost any price, really) is a great value. It’s cheaper than a company with four employees paying for Slack.

But at my tiny scale and thinking about cutting costs, given the amount of video content I’m actually posting each month and hosting with them, and also being a huge nerd, it didn’t make sense any longer.

So, let’s do this ourselves.

We need three things:

  1. Somewhere (cheaper than Vimeo) to serve video from.
  2. A way to play the video on our website.
  3. An easy way to convert raw video into an appropriate size and format for streaming.

So, where to actually host the video files? My requirements are somewhere reliable that won’t fall over if you get Slashdotted (ha, remember that?), can deliver quickly to visitors in any location, and won’t bankrupt you.

I have plenty of space available (and almost always enough bandwidth available) on my Linode (affiliate link – but Linode is wonderful) servers. But even my primary $20/month VPS with them was brought to its knees multiple times when traffic spiked. (Granted, I was running WordPress at the time.) And I don’t want to take the chance of my business website going down because one of my dumb blog posts on this website gets noticed.

A lifetime ago, I wrote about using S3 as a poor man’s content delivery network. That’s still an easy and reliable choice, but the cost for bandwidth doesn’t scale as a true CDN. Which is, of course, why Amazon offers CloudFront. But even then, at $0.085/GB, I’ve had multiple months in the past calendar year that would have been over $200.

Instead, let me introduce you to my secret weapon: BunnyCDN. (I get credit if you click that link. But I only use it because I completely love their service as you’ll see below.)

I switched to Bunny last October after using MaxCDN (now StackPath) since 2011 for all of my static assets. And I’ve been utterly flabbergasted at just how damn good they are. For a number of reasons:

  1. The main metric that matters: they’re really fast. I’m seeing equivalent performance as what I was used to with MaxCDN and the larger CDNs I’ve used at my day job.
  2. The two times I’ve needed to email them with a support question, a knowledgable, helpful human has replied quickly and without needing to go through dumb self-serve solutions.
  3. Bunny’s control panel where you manage your account, choose bandwidth settings, etc. is super easy to use and incredibly powerful (at least for my needs). It’s a really nice change from what I had with MaxCDN and the AWS Console (powerful as hell, but obtuse).
  4. Holeeeee crap their bandwidth is cheap.

For my static website assets (images, stylesheets, JavaScript, etc.) I use Bunny’s standard tier, which serves my content from all of their PoPs. That means visitors will connect to the server closest to them at $0.01/GB (for US and EU PoPs).

However, my video content uses their volume tier, which is distributed from 7 PoPs (instead of 41). While still being plenty fast enough, that reduces the cost further to $0.005/GB. That works out to a cool $5/TB when my traffic spikes.

I have zero understanding of how bandwidth is actually priced globally between providers or why some companies charge such a premium compared to others for the same bits over the wire. I assume you’re paying for reliability and/or speed? All I know is that I haven’t seen a blip of downtime or noticed any slowness in the nine months I’ve used BunnyCDN. I can’t explain how they can be so much less expensive. Maybe they won’t scale to “real” traffic? But for what I need, they’ve been a phenomenal choice.

(Ok, I’m done going on and on about them now. This really isn’t any sort of paid or sponsored content crap for Bunny. I’ve just been so impressed since switching, that I finally wanted to give them recognition.)

So that’s my answer to point #1 – where to host the video files.

The next thing we need is a way to show those videos inline on your website.

Gone are the days of embedded Flash video. Now, you can mostly get away with just using the native HTML5 video element.

However, if you want more control over the appearance of your video and how it behaves, take a look at Video.js. It’s a wonderful open source player from the kind folks at Brightcove that provides a similar level of control as the point and click customization options that Vimeo offers.

The last puzzle piece is getting your original videos into a web-friendly format and uploading them for distribution.

BunnyCDN offers their own online storage zones that you can simply upload to via FTP, but for historical reasons, I still store my large app downloads and videos on S3 and then have Bunny (and previously MaxCDN) pull from AWS as an origin server.

And as for the correct video format, I’m using Handbrake’s command line interface to convert my source videos files into mp4 using the Vimeo YouTube HQ 720p60 and Vimeo YouTube HQ 1080p60 presets.

But, because, hey, I’m a geek who doesn’t like doing extra work, I’ve wrapped up the whole process into a short shell script that

  1. Converts the source video to 720p
  2. Converts the source video to 1080p
  3. Uses qlmanage to output a frame of the video as a png for previewing in the HTML player before the video starts
  4. imagemagick to convert that png to a jpg
  5. Uploads all three assets to S3 with s3cmd
  6. Outputs the custom shortcode I use to embed videos in my blog posts

I just pass my video’s filename to that script, and a few minutes later I can copy and paste the output into my text editor and make it available on my website. Honestly, it’s an even faster process than using Vimeo.

Here’s the script. You’ll of course want to modify the paths to make it work with your own setup since it’s completely specific to my needs right now.

#!/bin/bash

bucket=$1

base=$(basename -- "$2")
extension="${base##*.}"
filename="${base%.*}"

p720="/Users/thall/Dropbox/Freelance/Videos/720p/$filename.mp4"
p1080="/Users/thall/Dropbox/Freelance/Videos/1080p/$filename.mp4"
png="/Users/thall/Dropbox/Freelance/Videos/jpg/$base.png"
jpg="/Users/thall/Dropbox/Freelance/Videos/jpg/$filename.jpg"

/usr/local/bin/HandBrakeCLI -Z "Vimeo YouTube HQ 720p60" -i "$2" -o $p720
/usr/local/bin/HandBrakeCLI -Z "Vimeo YouTube HQ 1080p60" -i "$2" -o $p1080

/usr/bin/qlmanage -t "$2" -s 1080 -o "/Users/thall/Dropbox/Freelance/Videos/jpg/"
/usr/local/bin/magick convert $png $jpg
rm $png

s3cmd put --acl-public --guess-mime-type $p720 "s3://$bucket/720p/$base"
s3cmd put --acl-public --guess-mime-type $p1080 "s3://$bucket/1080p/$base"
s3cmd put --acl-public --guess-mime-type $jpg "s3://$bucket/jpg/$filename.jpg"

echo "[tylervideo url=\"$base\" img=\"$filename.jpg\"]"

So that’s how I moved off Vimeo and started hosting my video content myself. On average, my bandwidth bill is about $11/month – and that includes videos, static assets, and ALSO binary downloads for all of my Mac apps. Previously, I was paying $20/month just for video hosting on top of the rest of my bandwidth.

It’s definitely a geekier solution that requires more work up front to setup, and I’m not sure I would recommend it for a “real” business, but for my needs it was a fun project and I’m happy to save $200 a year.

Process

The fifteen days since my last post are the longest I’ve gone all year between writing. My resolution at the start of this calendar year was to write 50 posts in 2020. So, I’m not quite behind yet, but I am glad that my reasons for missing two weeks eventually led to the topic of tonight’s post.

The first, and most practical reason I’ve fallen behind my writing schedule is that June and July are the busiest months for my 9 to 5 job. (Well, lately, more like my 8 to midnight job.)

To keep myself sane while dealing with my work deadlines, I’ve found myself tinkering around with an idea I’ve wanted to try building for years now. Oddly enough, it’s not yet-another-app, but a website (web service, maybe?). And it’s actually something that’s designed to be self-hosted. I haven’t yet decided if it will (eventually) be open source, or if I might solicit feedback from friends (real and online) just in case it’s more useful than I think.

But I digress.

This topic of this post is about a pattern in how I work – my process – that I only recently noticed the other day. In hindsight, it’s how I’ve always built things – how I’ve approached new projects. But for some reason, I never clued into the fact that, yes, this is how I work. These are the same steps I take with each new “thing”. And this is the step I’m currently on.

It was that realization that prompted this tweet last week.

Step 1. Build it as fast as possible.

Step 2. Wait 48 hours.

Step 3. Try again.

That’s not exactly it, but close. The longer version is…

Sometimes the idea for something new comes in a flash of inspiration. And other times (as in the current case) it meanders around in the back of my head for years – just waiting for the right moment or combination of external factors.

For this project, it’s the result of the rebirth of the indie web movement, my long time interest in self-hosting and owning the tools and data I run my business with, and Apple’s WWDC announcements about Safari and their OS’s upcoming privacy improvements.

But whatever the idea or genesis, there’s always a tipping point where that initial spark really catches fire and I have to build it now. I don’t know how to describe the feeling I get in my head (my whole body really) other than electricity-at-the-thought-of-new-possibilities. It also feels incredibly similar to when the dumb part of my brain is trying to convince the smart part of my brain that the ridiculous impulse purchase I’m considering is actually a good and rational thing to buy.

And so, full steam ahead, I try and build a proof-of-concept as fast as I can. I give no regard to code quality, architecture, performance, look and feel, anything. My only goal is to see if I can make it work in some functional way in the simplest form possible.

Writing code in this state is an ultimate high for me. It’s a pure act of creativity. Sure, I enjoy alcohol and other substances, but no feeling I’ve ever gotten from those things can compare to the literal buzz I get when my hands on the keyboard are perfectly in-sync with the instructions pouring out of my head.

And while the word may be in my job title, I hate calling myself an “engineer”. Beyond the math, there’s almost no engineering involved in how I approach the code I write. That doesn’t mean I’m not careful, thoughtful, or that I don’t make well-reasoned decisions, but I’ve always viewed my development style more like art – sculpture, specifically.

I start with a raw block of material and massage and shape it towards a final form. Sometimes, especially at the start, I may have no idea what the end goal is. But over time as I add new pieces, move and rearrange others, it takes on more definition, structure, and patterns emerge. If you look closely, you’ll see influences from prior art and other developers, too.

That’s all to say that the things I build are rarely assembled from a blueprint. They’re organic, and I’ve often found myself at odds with other peers in the industry because of that. But that’s a topic for another post.

Once the prototype is done, once I’ve proven to myself that my idea is possible, I let it sit.

For a day. For a week. In one unique instance, seven years.

During this time I focus on other things. My real work, my family, baseball (2020 season?), whatever. Anything other than the new project. And as I go about my day, my brain will naturally start to surface ideas, features, goals, must-haves, and nice-to-haves. All the little details and tentpoles that would eventually define the full scope if I choose to move forward.

If I’m on my phone or in the car, I’ll jot down (or dictate) the idea into Drafts. If I’m on my Mac, the note will go straight into Trello, which is where all of my personal projects are tracked.

It’s also the naming phase. I almost never have an idea for what to call the project when I start building it. But during this ideation downtime, coming up with a good name for the new thing seems to be a natural byproduct of listing every possible feature.

And so, once I’ve given myself enough time to sit. To think. To let all that initial, throwaway code settle and be still in my mind, I’ll revisit it with fresh eyes and attempt to place it into one of four buckets.

  1. This is crap / dumb / stupid / a nice distraction but not worth pursuing.
  2. This is great – but only for me.
  3. Other people might like this.
  4. Other people might pay for this.

In the first case, I save everything to git if I haven’t already, and move on. (I never throw away code, though.)

Number two is often very likely. I have lots of one-off projects and tools that are only useful for me.

If I think it’s useful and worth sharing, and if I’m also willing to stomach the shit-storm of asshole internet trolls who find joy in complaining about the quality of code other people publish for free, I’ll post it to GitHub. I love doing this.

But if I decide it might really be useful, typically based on feedback from friends, I’ll begin thinking about how long it might take to reach an MVP if not even a 1.0. Is there a valid business model? Is it something I feel comfortable asking strangers to pay money for in exchange for the responsibility that places on me as the developer and support person?

And if all those stars align, I’ll officially add it to my Trello development calendar, and it’ll be done just as soon as I finish the other 437 projects ahead of it.

But once the project reaches this stage, I know enough about myself to understand that I do my best planning and thinking visually. And given that the prototype was built with almost no thought to UI / UX, and that I now (hopefully) have a long backlog of features in Trello, I’ll spend whatever amount of time it takes to settle on a “final” look and/or flow that I can move forward with. (I put “final” in quotes because, ha, this stuff is never really done and will be changing forever.)

It’s just my personality and a near like writer’s block in my head, but until I’m convinced I’ve nailed down the main window (if it’s a Mac app), the first few screens (iOS app), or HTML/CSS structure (web app), I can’t write any more code. It’s impossible for me to move beyond the working prototype stage until I have a basic shell or the chrome to put my ideas into.

It doesn’t matter if the UI I settle on will eventually be completely thrown out and replaced, but it has to reach some initial threshold where my inner critic says “Ok, that’ll do for now.” Only then can I continue.

And it’s that first, final design stage I find myself in with this current project. I’ve got a working prototype churning away on a DigitalOcean VPS this very moment that I’ve been using every day this past week. And I’ve got 200+ cards in my Trello backlog. And I’m aching with excitement to stretch some development muscles I haven’t exercised in years.

I love this part.

BespokeApp

Last night my daughter was sick, so I spent a couple of hours sitting in her bed to help her fall asleep. With a bit of time on my hands, I put together this little open source project.

I really don’t know if anyone has a need for this other than me. But I’ve built this app a few times for myself in the past, so last night I finally took the initiative to make it generic and reusable – both for my future self and anyone else who might find it useful.

It’s called BespokeApp. It’s a simple iOS app that gives you a tabbed web browser with the pre-defined websites of your choosing.

Why is this helpful? Well, I have a number of websites I visit frequently that are all related.

For example, in my day-to-day business running my little software company, I often bounce between my help desk, my customer database, my website stats, and a few other 3rd party web apps like Linode and NodePing.

Separately, I have a number of web apps running locally on my iMac that I use to manage our home media sever, Docker, and some Raspberry Pi stuff.

I think of all these websites as belonging to distinct groups that are helpful when used together while I’m focused on a specific task. A common workflow I’ll run multiple times per day is…

I’ll get a push notification on my phone about a new support ticket from a customer. So, I’ll open up my bespoke, small biz app, flip to my help desk, and read their ticket. If it looks like they’re having a problem with their license or need me to send them a duplicate receipt, I can one-tap over to my backend system, lookup their order, and reply.

When I’m working on a task that requires information from various sources or multiple websites, BespokeApp just makes it fast and easy to coordinate. Sure, on my Mac (or even Mobile Safari) I could do all of this with bookmarks, but specifically on iOS, this is a pain in the butt to manage with every browser I’ve tried. None of them make switching tabs easy. Or even make accessing a group of bookmarks less than eleventy-thousand taps.

BespokeApp gives me a single app to open with a tabbed interface that lets me quickly switch between related websites.

As I said at the beginning of this post, I’ve written this same app a few different times for myself as I’ve needed different groups. But now it’s generic and reusable.

Two bespoke app icons

Everything is configured with a single property list (.plist) file. It lets you define each tab’s title, image, and the URL it loads.

You can even add multiple (related?) URLs on a single tab. The first one will be loaded by default, and you can then long-press to switch between websites within that tab itself. It’s all very meta.

Bespoke app long press action

Best of all, if you find BespokeApp helpful, you don’t need to clone a separate copy for each group (app). Instead, just duplicate the iOS target in Xcode with a new bundle ID, give it a new name, and use a different .plist. That’ll let you keep all of your bespoke apps in a single project / repo.

So that’s it. BespokeApp is a pragmatic, 152 line long, one-trick pony. I really think you’re gonna love it. (Sorry.)

A Pirate Looks (Nearly) at Forty

I first drafted this post six months ago in response to something that happened to my wife and I six months before that. But for various “reasons” I decided not to publish it.

But then, six weeks ago, Nick Heer wrote this wonderful piece connecting today’s new world of all-you-can-eat streaming music services with the piracy websites of the 2000s – specifically, the amazing communities, breadth of choice, and user experience they offered. And this post started rolling around in my head again.

A few weeks later Nick added a little color to the news that AT&T is giving HBO a free pass on data transfer because, well, AT&T owns HBO. He ended his thoughts with

I fully expect a resurgence of piracy as studios and ISPs attempt to isolate media.

And now I’m banging away on this keyboard today to say, yes, absolutely it will.

Up until last June, it had been a long, long time since we pirated any content. But that’s exactly what happened to my family last year – and is the impetus for this post.

I musically came of age my freshman year of college when the rise of Napster coincided with my first access to non-dial up internet. I’d fall down a new rabbit hole every night as friends on AIM and in the dorm would recommend an unfamiliar artist. I’d search their name and moments later be listening to their back catalog.

But by the time I got my first post-college job and a little disposable income in my pocket, the iTunes Music Store had been around for two years and I was more than happy to support my favorite artists.

And as far as music goes, I’ve been almost entirely above board and legit for the last fifteen years. But like Nick, I was also a member of Oink and discovered so much new music there.

The difference, for me at least, was that after “trying” some mp3s for “free”, if I wanted them permanently in my collection, I’d almost always pay for them via iTunes – assuming the songs were available. I can’t say why I did that other than I wanted my library to be “official”, and outside of buying CDs, the paid-for digital versions were canonical.

But movies and TV shows? What an utter shit-show the industry was back then. After our local Cupertino movie theater raised the price of a ticket north of $20, my wife and I almost entirely stopped going. That meant we watched everything at home. Sadly, though, the software, hardware, and bandwidth just wasn’t capable of supporting home media like we have now. But, a Mac mini running a combination of VLC and early builds of Plex hooked up to our HDTV meant we could solve that problem ourselves.

And for four years it worked wonderfully. But with the rise of Netflix and more capable streaming boxes, the UX of watching video legally finally got close enough to what we pirates had cobbled together ourselves years earlier to where we (and many of our friends) gave up our trusty HTPCs and went legit.

From 2012 until 2019 it all mostly worked fine. My wife and I were happy, paying customers. Sure, there was the whole Amazon Prime on iOS / tvOS debacle. And no way to find out if you didn’t remember which of the dozen streaming services carried Masha and the Bear when your three year old was melting down in the living room. And, of course, Apple kept fucking around with the the TV.app, adding more friction, up-sells, and making the whole experience pushier. But as long as your internet connection didn’t go out and you were confident you were under the residential data cap given to you by the internet company who also happens to own the streaming video platform you’re trying to watch, everything was great.

But one night last June we managed to get the kids to bed early and decided to rent a movie from iTunes. About forty-five minutes in, our youngest throws up, the oldest starts screaming because of the smell, and all hell breaks loose. Movie night over.

Amazingly, somehow, two nights later we again found ourselves with a quiet house again, ready to finish the movie we rented. But if you’ve made it this far into my story, you know exactly what happened next. We clicked play, and were informed our 48 hour rental period had expired.

For me, for us, that’s when the spell broke. For seven years we played by the rules. So I walked from the couch to my office iMac, visited an old favorite website of ill repute, and ten minutes later streamed the move in 4K to our TV.

That one evening re-opened the piracy floodgates for us, and we haven’t bought or rented another TV show or movie since. (Music, yes.)

Can I justify what we (and so many of my friends) are back to doing? Of course not. But am I OK with it? Yep. Here’s why.

The fragmentation of the streaming market into a different service for every IP holder means we’re headed back to the days of bundled cable packages. Instead of paying Comcast an exorbitant price for 200 channels to watch the five shows we care about, we’re now paying five (or more) streaming providers a smaller amount, individually, to watch the one show on each service we care about, which they use to finance production of a thousand other show we don’t want to watch. And added together we’re approaching if not exceeding what we were previously paying the single cable company.

But costs aside, the whole industry is a UX nightmare. Every service has their own awful, bespoke app. For my wife and I, we can mostly deal with that. But our parents? They simply cannot navigate so many contradictory options and ways of going about doing the same thing just because a different media conglomerate owns their three favorite shows. And good luck trying to explain the difference between HBO Now, HBO Go, and HBO Max.

Collectively, we’ve reached subscription fatigue – because of both cost and the hoops involved. Families like mine will pay for one or two services and then share passwords with or create guest accounts for other friends and family who then share their own subscriptions with us.

Some companies like HBO get it.

“It’s not that we’re unmindful of it, it just has no impact on the business,” HBO CEO Richard Plepler said. It is, in many ways, a “terrific marketing vehicle for the next generation of viewers,” he said, noting that it could potentially lead to more subscribers in the future.

Well, they used to, it now seems.

Anyway. That’s fine. It’s their content. But I view this as a market failure.

I want to pay for my content – I really do. I want to support the writers, actors, and workers making the media I enjoy. I don’t want to have to setup and maintain some wired-together, fragile pirating system. But when these media companies put onerous restrictions in place and refuse to agree upon terms that make sense to consumers – like the music industry finally did – for people with the know-how, we’re going to go back to stealing content.

And I use the word “stealing” deliberately because it absolutely is stealing. If you skim through any of the many piracy forums or subreddits, you’ll find tons of folks using twisted logic to justify that pirating content isn’t actually wrong or (worse) is somehow their right. But I have no illusions about it. When I illegally download a movie to watch one time because the studio insists I should outright purchase it for $20 instead of renting for $5, well, what I’m doing is stealing. It absolutely is and it’s wrong. But it’s also a crime that I would prefer not to commit if they would just come to the table and negotiate in good faith and try and understand what consumers want and are willing to pay for.

I’d like to make two final points.

The first is that there’s an argument to make against me which says I don’t have the right to their content just because I’m not willing to pay their price. I understand that.

But it’s not just about the cost.

Even in cases where I am willing (and happy!) to pay what they ask – and actually buy the content vs renting it – with the transition to digital / streaming, they’ve taken away my rights by denying me the ability to actually own the content I’m paying for.

As an adult, when I watch a movie, I typically just want to rent it one time unless it’s something special or a favorite. But my kids will watch the same few movies over and over and over again. So it makes perfect sense to buy their movies instead of renting them each time.

But if I buy them a movie on our Apple TV, it’s not mine. Every time they watch it the movie streams from Apple’s servers. And that means we’re dependent on a working network connection, which isn’t always guaranteed and certainly isn’t a thing on road trips. (Please don’t bring up syncing purchased videos from iTunes to iOS. Apple abandoned that workflow years ago.)

Even if I were to go old school and buy a movie through iTunes and download it to my computer, that file is encrypted. At any point Apple could revoke my ability to watch the film. Or I could lose access to my Apple ID. Or the studio could simply decide to remove the video from Apple’s platform. In any of those cases, through no fault of my own, I lose access to something I’ve paid for.

And there’s no alternative. I could buy a physical DVD or Blu-ray, but the media companies lobbied Congress two decades ago to make it illegal to backup those discs either for safe-keeping or to just make it easier to watch.

My point is: If these companies were willing to meet me in the middle, to give back the rights to the content I purchase instead of just licensing it to me, then I’d be willing to respect their rights, too.

Steve agreed with this back in 2007

Why would the big four music companies agree to let Apple and others distribute their music without using DRM systems to protect it? The simplest answer is because DRMs haven’t worked, and may never work, to halt music piracy. Though the big four music companies require that all their music sold online be protected with DRMs, these same music companies continue to sell billions of CDs a year which contain completely unprotected music. That’s right! No DRM system was ever developed for the CD, so all the music distributed on CDs can be easily uploaded to the Internet, then (illegally) downloaded and played on any computer or player.

Until then, I’ll keep paying for my music. And everything else? 🤷‍♀️

Very Simple

I’ll keep this post short because there’s really nothing more of substance I can add to this argument that many developers and pundits way smarter than myself haven’t already said.

But I suppose it’s flaring up again in the community because of the hey.com controversy, the recent developer survey Apple sent out (my less polite response from last year), and WWDC looming next week.

From my point of view this is all very simple:

The App Store opened eleven years, eleven months, and seven days ago. It is not a game. It is literally the livelihood of millions of people.

The 30% shakedown has never been justified other than “we can”.

The capricious and inconsistent review process has never been explained other than “no comment”.

With all the awfulness and urgency in the world right now; and with all the good Apple truly is doing, it feels like a waste of precious attention and resources to complain about the App Store. But, hey, that’s business.

Antitrust.

Now.

GrannySmith

Update: Take a look at Iris

Inspired by a post I wrote last year, I’ve built something new that I’m ready to share and get feedback from the community.

After upgrading to Catalina I noted

Back in April I wrote a quick post about how I was backing up the shared iCloud Photo albums that my friends and family all use to send pictures and videos of our kids back and forth. A reader emailed me today to ask if I knew where that folder had been moved to after upgrading to 10.15. So, I looked, and, sure enough, that sharedstreams folder was gone.

And with it, my ability to keep backups of thousands of photos and videos of my children that our friends and family (and their grandparents) had taken and shared with us.

Why does that matter? Scott said it best…

When I look on my Mac, I find these pictures of my kids that, to me, are absolutely priceless. In fact, I have thousands of these photos. If I were to lose a single one of these photos, it would be awful. But if I were to lose all of these photos because my hard drive died, I’d be devastated.

I never, ever want to lose these photos.

And even before the upgrade to Catalina, sure, I could backup the items themselves. But there was no way to backup the six and a half years of thousands of comments and likes that our family had posted to those albums. My family uses Apple’s shared photo albums more than Facebook or Instagram. If all that historical data was lost? We’d be devastated.

And if I can go off on an even more personal tanget for just a moment…

I’m typing this after getting my kids (finally) to sleep by myself this evening because my wife is spending the night at her grandmother’s house – my kids’ great-grandmother. Thelma, a kind and generous woman, is going to leave us in the next day or two. And my wife volunteered to take the night shift tonight so she could be there with her.

When my son was born six and a half years ago – her first great-grandchild – Thelma taught herself how to use an iPad in her 80s. She read books, the news, and was quite possibly the most active commenter and “liker” of all the photos and videos of the kids we’d share using iCloud. Whenever I posted a new picture of the kids being silly, I knew, could almost time it to the minute, when I’d get a notification back that Thelma, home alone in her big house with coffee in hand, had tapped the like button or commented with a ?? emoji.

And so now I think about not just all the photos and videos – but the 65,234 comments across 16,752 items we’ve shared. (How do I know those exact numbers? I’ll tell you in a minute.) Each one may be insignificant by itself. But combined? They represent 2,596 days of shared family history.

And when I think about losing the post she made about our newborn son in the hospital? Or the one she commented on last week? Only because there’s no way to get access to that trove of data? It breaks my heart.

Fast forward to a few weeks ago, a reader emailed me to say

Hello,

I really like reading your blog (are we still calling them that?). In particular, your posts on backups always give me better ideas on how I want to organize and save my family’s data.

Your blog, more than any other source I can find on the web, talks about backing up iOS photos and Apple’s iCloud Shared Albums. In our case, we use the Shared Albums as the exclusive place for posting photos of our 3-year-old (turning 4 on Saturday) daughter for our family and close friends. It’s a great way to share photos with family that’s completely outside of the typical social media engines.

So, while we have a backup (well, multiple backups) of the originals, my wife pointed out that we don’t have a backup of that feed and, most importantly, our and our family’s comments. We’ve chronicled the last four years of our life via the photos and comments and had our family comment with lots of stories and encouragement that have been a great way to stay connected.

I hadn’t thought about it until my wife mentioned it, but I have no backup of those photo/comment pairings. It would take one mistake by Apple (I admit not likely) or a misclick on our part to accidentally delete that album and irretrievably lose all of that content.

Are you using your Shared Albums in that manner? If so, do you have any thoughts on backing that up or exporting everything? I’ll admit I don’t really have an idea of what that backup would look like.

I’ve even thought about taking screenshots of the photos with the comments turned on (though doing that several thousand times doesn’t sound fun). I could try to automate that process, but so far I’ve not found any way to get Automator to interact with the Shared Albums and their comments, though I admit I’m a novice at it.

I hope this finds you and your family well and healthy.

Best,

Chris

So I thought about the problem again, and remembered a throw-away idea I mentioned near the end of my original blog post.

At the top level is a Core Data database. I thought I might get clever and explore that to see if I could extract out the metadata of the shared items and use it to help me write a “smart” backup script (that perhaps imports other people’s photos directly into Photos.app) instead of just taking the brute-force approach and backing up the entire album as a dumb blob, but I haven’t had enough time yet to investigate.

Enough was enough. I built it.

The app is called GrannySmith (for now) and it reaches into your Photos.app library and provides a fast, clean, native interface for browsing, sorting, filtering, and exporting all of your shared photos and videos, comments and likes. You can view a combined stream of all your shared albums, or just a single album, or even filter and see posts made by specific people.

GrannySmith screenshot

Your images can be exported directly to disk in a date-based folder structure for easy backup.

GrannySmith screenshot

And if Photos.app doesn’t have the full-resolution versions cached locally, GrannySmith will download the originals from iCloud – even your videos. You can also generate a JSON file with all of their comments and likes – neatly tied together for you to do what you want.

One more thing.

I realize that as incredibly helpful as I find archiving my photos and videos and having all of that meta data available to me in JSON format, I’m not most people. And most people don’t speak JSON.

Two months ago I released Roland – a static website generator written in Swift. Well, Roland is now embedded in GrannySmith. And that allows the app to build an actual static HTML blog out of your shared photo history.

GrannySmith website screenshot

Just like your typical WordPress website, you can browse your chronological timeline of posts – sorted by date and category. And all the original comments that friends and family posted to your shared albums are reproduced as blog comments.

GrannySmith website with comments screenshot

You can keep the exported website as an offline copy. Or you can upload it and host it yourself. There are no dependencies – no PHP, nothing. Just plain, vanilla HTML. It even comes with RSS and JSON feeds, so your geeky friends can subscribe and get updates outside of Apple’s ecosystem.

And the entire website is backed by a completely customizable template system written in PHP. So you’re free to make your exported website look and feel however you want.

It’s still very early days, but GrannySmith is coming along nicely. Here’s a four minute preview video that walks through everything – including a full website export. It’s best if you watch it in fullscreen.

Current Status and How to Download

GrannySmith works but is missing some key features I plan on adding and is also completely untested on anything earlier than 10.15.4. I’d love to know how it works for you on earlier macOS versions.

Known Bugs and Limitations

  • Most egregiously, while you can export a website of your content, you can’t currently export that JSON backup I mentioned. (Key feature, I know.) Mainly because I haven’t settled on a final data structure for it.
  • The “Dates” filter button doesn’t work yet.
  • Switching between albums is way slower than I want it to be.
  • The website templates are currently buried in ~/Application Support/. They can be customized, but this current release will overwrite them on launch to make my debugging process easier. You’ll need to live with the default theme for now.
  • I happen to like using GrannySmith as a lightweight UI to view new items that friends share with me. And since it’s pulling directly from your Photos.app database, it updates in real time, too. That said, to keep from destorying your bandwidth, the app will not automatically pull originals from iCloud when just browsing. You’ll need to choose “Download Originals” if you want those cached locally to view. Otherwise, GrannySmith will fallback to displaying the lower-res versions that Photos.app already has.
  • Building a website will build all of your albums. Ideally you need to be able to build from only the selected ones.
  • Building a website will not automatically download originals. Instead, it will use your low-res cached versions. If you want orignials included in the website export, you can select and download all first, then build the website.
  • Videos do not currently play in the app. But you can export and view them.
  • I also want to add support for scripting the app via the command line or some other type of built-in automated task so you can have GrannySmith automatically do a backup of your latest items every night, etc.

I also want to point out that GrannySmith does not store or transmit your photos, videos, comments, etc. off your Mac. Everything is done 100% locally. I see none of your data and don’t want to see any of your data. Keep all those cute kid pictures to yourself.

Download GrannySmith

You can download the latest preview release of GrannySmith from here. The app will check on launch with my web server for updates and to submit crash reports.

As with all the dumb things I post to this blog, any and all feedback is very much welcome – especially on this project.

Do You Hear That?

Shortly into quarantine at the beginning of March, I realized I had a problem. My iMac has too many audio devices, and managing them was becoming a pain in the ass. And it was all because working full-time at home again, in this new age of frequent work video meetings, Slack and Discord calls, and dealing with two young, screaming kids with no school to attend, created a perfect storm of audio requirements.

Prior to being stuck at home, I would take all of my standup and other phone calls in my car on the way to work and then handoff to my AirPods to wrap up. And because my coworkers are nice people and we all typically leave each other alone to get work done, I was happy to sit in my quiet office all day and do my thing.

I don’t typically listen to music at work, so my AirPods only got intermittent use throughout the day which worked great.

But I soon found that working at home posed two new problems:

  1. Way more phone calls and video meetings. I was on so many that my AirPods battery life was precariously low at times.
  2. My kids are insane noise monsters. And getting any kind of deep, focused work was nearly impossible without some sort of music playing in my ears. The AirPods ended up getting way more use than normal, and battery life really became a gating factor.

So, I bought a decent pair of noise cancelling, over-the-ear Bluetooth headphones that can also connect to my iMac with a wired audio cable. They’re awesome. The battery life is 40+ hours on a single charge, and they block out my kids so well that my wife gets mad at me because I can’t hear their actual screaming anymore.

But here’s the problem. My iMac now has:

  • Built-in speakers
  • Audio cable line-out
  • AirPods audio out
  • Noise cancelling headphones audio out

And also

  • Built-in microphone
  • AirPods audio in
  • Noise cancelling headphones audio in

But it’s actually slightly more complicated than that. I mentioned above that my new headphones can be wired-in in case their battery dies. That’s great! But, when wired, the microphone doesn’t work. It’s only available while wireless.

Also, if you’ve used combined Bluetooth input/output devices like AirPods before, you’ll know that when the microphone is active, there isn’t enough bandwidth to do high quality audio out at the same time. So when my AirPods are connected listening to music, and I take a call, the audio out degrades. That’s fine. But then when the call is over, my music starts playing again and sounds like crap until I manually switch my iMac’s audio input to another device.

Add to that my new work from home requirements where I frequently bounce between music, Slack calls, Discord video chats, RingCentral meetings, actual phone calls, etc. Basically, it just became incredibly annoying to keep digging into the Sound panel of System Preferences or option-clicking the volume icon in the menubar to make fiddly adjustments.

And, oh my god, don’t even get me started on the nightmare that is sharing AirPods between an iPhone and Mac that are within range of each other. (As a stupid joke, I very nearly bought www.haveifactoryresetmyairpodstoday.com and filled it with a giant YES just to put into this blog post.)

Anyway, all I wanted was a super-simple, fast audio input/output switcher app. I swear there used to be something out there that did this, but my googling failed me.

I already own SoundSource from the amazing (incredible?) software wizards over at Rogue Amoeba. (Seriously. Go buy it.) And while it will totally perform the audio adjustments I want and then some, it’s a mouse-required type of app. As readers of this blog will know, I’m a keyboard junkie. So if I’m going to be forced to use a mouse, I might as well just go ahead and use the native macOS volume menubar icon.

So I did what I always end up doing, and wrote the app I wanted for myself. It’s called Ears. And you can have it, too.

Ears for macOS app icon

The idea is simple. Press a hotkey and Ears opens. And still without touching a mouse, pick a new audio output or input (or both!) device, and be done. That’s it.

Here’s Ears in action.

In that video you can see me summon Ears with a hotkey, and then move up and down and between the two lists of input and output devices to select what I want, and then press return to dismiss. It’s that simple.

But it can be even faster than that. You don’t have to use the arrow keys to navigate up and down and between the lists. Your output devices are numbered 1 through 9. And your input devices are A through Z. Just type one of those keys and Ears will select each device.

So, if your global Ears hotkey is ^4 (that’s mine), then in this screenshot…

Ears audio device picker window

opening Ears and picking my headphones as output and internal iMac microphone as input is simply:

^4 3 a ↵

But, we can actually make it even faster than that. There’s a setting in Ears Preferences called “Change devices immediately”.

Ears Preferences window

If that’s enabled, then typing a device number/letter will instantly switch to it and dismiss the picker window. So, if I just want to switch to my headphones, my keystrokes become:

^4 3

Boom. Done. ?

Ok, but can we make it even easier still? You betcha.

This isn’t something I had initially planned to add into the app when I built it. My original goal was to make it purely a way to change audio devices. And so this extra feature was added just because it seemed to make sense – even though I feel bad about it because it treads so closely to the great work done in ToothFairy by Michael Tsai and AirBuddy by Guilherme Rambo. (I own both!)

If you enable Ears’s “Auto Connect” feature, you can mark Bluetooth audio devices as favorites. And then pressing the “Auto Connect” hotkey will instruct your Mac to search for a favorite device and attempt to connect.

Auto Connect is flexible, however. Your favorite input and output devices don’t have to be the same ones. You can set your AirPods as a favorite output device and auto connect to them, but your audio input can remain with whichever device was already selected. That way, your AirPods music won’t degrade in quality. You can set any combination of devices with any combination of inputs and outputs.

And, now, finally. One last incredibly nerdy feature of Ears that I’m hoping appeals to at least one other person than myself.

Ears is scriptable.

Both from the command line and via AppleScript.

> Ears --help
USAGE: ears [--input <input>] [--output <output>] [--list-outputs] [--list-inputs]

OPTIONS:
  -i, --input <input>     The audio input device to make current.
        The name must be an exact match.
  -o, --output <output>   The audio output device to make current.
        The name must be an exact match.
  --list-outputs          Show available output devices.
  --list-inputs           Show available input devices.
  -h, --help              Show help information.

> Ears --list-outputs
*Soundcore Life Q20
External Headphones
iMac Pro Speakers

> Ears --output "External Headphones"
> Ears --input "Tyler's AirPods"
tell application "Ears"
    set audio input "Soundcore Life Q20"
    set audio output "iMac Pro Speakers"
end tell

You can set your active audio devices and also query a list of available devices on the system and read which ones are active.

So that’s Ears. I built it to solve my own, dumb workflow problems and find it super useful every day. I hope you do, too.

Ears is completely free to use, but if you find the app helpful, I would love your support. You can make the nag screen that opens when the app launches go away forever with a one-time, pay-what-you-want purchase.

Absolutely Priceless

Scott said it best fourteen years ago at WWDC 2006.

When I look on my Mac, I find these pictures of my kids that, to me, are absolutely priceless. In fact, I have thousands of these photos. If I were to lose a single one of these photos, it would be awful. But if I were to lose all of these photos because my hard drive died, I’d be devastated.

I never, ever want to lose these photos.

Just in case anyone is still worried about all those irreplaceable memories – and the years of comments and likes from friends and family that go along with them – I’m workin’ on it.