Clipboard automation with Slack, Automator, and AppleScript.

Several weeks ago I wrote about using a personal Slack team for notifications and other personal info. Since then, I’ve continued to experiment with adding channels and connecting services, trying to find the right mix of utility and centralized information gathering for me.

One of the things I really love is using a #clipboard channel, which allows me to instantly synchronize anything between my Mac and iOS devices. Some people use Slackbot for this, and yes, you could also use AirDrop or any of the myriad clipboard syncing apps, but I’ve tried almost all of them, and they all disappoint in some way. Nothing beats Slack for sheer speed and reliability in this arena, believe it or not.

Given that I’m always looking for ways to waste time streamline workflows for maximum productivity power ups, I was curious to know if I could make the copying of text (my main use case) faster within this process. I asked the following question:

and was met with a chasm of silence. And a few people who wanted me to let them know if I figured out a way to do it.

Slack’s Mac app is essentially a web wrapper for the site itself. Which isn’t a horrible thing, but does make for some less-than-stellar integration points. It’s actually easier to automate this kind of thing on iOS, believe it or not, due to the extension system provided to developers beginning with iOS 8. But I had a little time this weekend and was determined to figure it out, so I decided to get my hands dirty with Automator like any other rational person. I was able to get highlighted input text copied to the clipboard and sent to the right channel on the web easily, but that meant I needed to open a web page every time and wait for it to load… like an animal. So I began thinking about UI scripting and decided to try it with the Mac app using AppleScript.

I will admit this right now: I’ve never really used AppleScript before, and I’ve used Automator only peripherally over the years, so the result of this little experiment is a bit of a dumpster fire. But it actually does what I want it to, which is kind of cool.

First, I needed to understand at least basic AS stuff. I did a little reading and managed to get a handle on it fairly quickly. It’s quite a bit of fun, and I’m actually sorry I waited this long to play with it. Once I felt comfortable, I put together as much as I could in Automator to get the app focused and ready. Then I began assembling the script. In order to really win, once Automator launched the app, it needed to do the following:

  • from whatever team I last left the app in, switch to my personal team (Cmd-1)
  • activate the quick launch dialogue (Cmd-K)
  • enter “cl” to highlight my #clipboard channel
  • simulate a press of the return/enter key
  • paste the text into the field (Cmd-V)
  • simulate another press of the return/enter key
  • switch back to the app I was working in (Cmd-Tab)

All of this is totally possible, and not even that hard in AS. I found this awesome app that displays the key codes and other info for keys as you press them, so I was able to keep the script a little bit tidier. The tricky part–the part that drove me nuts and took me the longest to figure out because it wasn’t instantly apparent–was that I needed to build tiny delays into the script to allow the Slack app to catch up to the simulated inputs. I added a few tenths of a second between the steps in the script, and the result was that the app looked like I was just typing super fast, pasting, and tabbing back to the previous app, as opposed to just farting out the failed alert sound your computer makes when you do a thing it doesn’t want you to (which happened a lot as I was tripping through figuring this out). The finished result looks like this (seasoned AS users, avert your gaze; don’t look upon this atrocity):

tell application "System Events"
key code 18 using command down
delay 0.3
key code 40 using command down
delay 0.5
keystroke "cl"
delay 0.3
key code 36
delay 0.3
key code 9 using command down
delay 0.3
key code 36
end tell

Like I said, not the prettiest piece of work. A second smaller AS block just handles the Cmd-Tab after this is done. But it works, and I’m pleased as punch that it does. I mapped a keyboard shortcut to the Services menu entry in System Preferences, so now I can highlight text with my right hand, and with my left, hit a key combo and instantly run the action, returning to the current app in about 3 seconds. And the pasted snippet is available on all my devices, instantly.

So yeah. There you go. Waste of time? Probably. Useful? Actually, yeah, very. And I learned a little something. So let’s just move on.

Using Slack as a personal information center.

At this point, we can probably all just admit that Slack wins all the things. It’s an absolutely fantastic tool, with great support and constant updates, and it just seems like it’s headed in all the right directions for almost every kind of user. Sure, there are things we’d all like to see changed (managing teams if you’re on more than a few is still insane), but the consensus is that we love it and it’s great, and I’d agree, so let’s just keep going.

I’ve been making changes to the way I use my devices and think about apps in the past few months, and a large part of that process has been looking at what apps I do use or must use, and don’t want to do without. Put differently, how can I do more with the apps I am using already, as opposed to adding other single-use apps to my devices? Drafts is a good example of this–it’s a single, simple jumping off point for so many text actions and much more on iOS and beyond. Slack has quickly become one of those apps for me–a “must install” on any device. So since it’s always going to be there, I decided to start thinking about it in a new way.

I read Federico’s post on using Slack as a shared notification layer, and how the MacStories team was piping content into their Slack channels to better inform everyone of things at once. It’s a great idea, since everyone is in there anyway–you can really cut down on miscommunication and make sure people are up to date easily. I wondered if it could work in a similar way for a single user. And how effective would it be? Slack provides many super cool integration points to connect to other services and even more interoperation is coming, which is very exciting, and led to me conducting this experiment. I signed up for a new team (sigh) and set it up with a few key channels, just for me.

I think it’s safe to say that notifications are the most obvious way to extend Slack right out of the gate. I set up an #alerts channel, hooked it up to IFTTT and Twitter. So far, I’ve configured:

  • Updates from our local police department about things going on in town
  • Updates from a few select Twitter accounts for things like system status of services I use
  • Weather forecasts (duh)
  • Updates to saved searches on eBay (for classic video game consoles, et. al.)
  • ESPN updates for baseball game start times (not that I ever have the time to sit down and watch a game, but still)
  • Surf height changes past a certain threshold at my preferred spot (yes, we surf in NJ, deal with it)

I also decided to break out a separate channel for Zendesk tickets that might show up. I thought it made sense to get them within Slack as well, but didn’t want them to get lost in a stream of personal stuff.

Of course, notifications can be an issue themselves, so I made sure to only allow Slack to tell me about the stuff I want to know about as it changes. Basically, this #alerts channel is (based on the sources) fairly low-volume despite all the crap I stuffed in there, so it’s not constantly pinging me all day long, which of course is an entirely different discussion about mental attention and prioritizing information delivery. Some other time, perhaps.

Beyond notifications, I’m thinking of other ways to get inventive with pulling data into a single, unified space.

Slack has an RSS integration. Now, if you’re still reading a thousand sites a day in a dedicated reader, this would be a terrible idea for you. But, if like me, you only read a few sites a day, you can give this a spin. I created an #rss channel, added the dozen or so sites I follow into the integration, and was done. I now have a little feed reader built right into Slack, which even tells me when new posts have come in since I last checked it, thanks to the built-in read status feature.

Extending this further, I created a #readlater channel, where I can dump links that I might want to follow up on. Again, if you’re high volume, forget it, but for a handful of things here and there, it’s a neat idea. And this might not necessarily be articles I want to read, but a scratchpad for links that don’t really fit in a traditional read later app, or necessarily need to become an OmniFocus task–stuff I can come back to whenever, with no implicit priority assigned.

Next, I figured I’d try something different. I generally don’t read or follow the news, because in most cases, it just makes me upset for a variety of reasons. But I decided to try a #news channel, with some parameters set within IFTTT actions. I added Entertainment Weekly, Time, NPR, and the New York Times actions with modifiers for how popular any given story might be, or from certain sections of those publications. So it’s not a firehose of all the things those areas publish, but a few links here and there throughout the day. The jury is still out on whether or not I even like this, but it’s working pretty well.

I also added IFTTT actions to this channel for Wikipedia’s article of the day, and Vimeo Staff Picks, just to add a little more variety into the mix. I think if I consider the sources a little more, and choose a few keys sites I don’t read all of, but like little blips from occasionally, this could be pretty fun.

Finally, I created #clipboard which allows me to paste text, images, links, etc. between iOS and the Mac. Again–yes, there are a thousand dedicated clipboard syncing apps, and you can use AirDrop blah blah–you know what? Slack’s always on and it’s fast, and it works.

Since it’s just me posting into all of these channels, and I’m on a free plan, it’ll be a while before I hit the 10,000 message archive limit, which means up until that point, I can also search against my channels to see something historically that I may have added weeks ago and want to return to for any reason. Certainly I can also delete messages as I go, keeping my channels clean each time I return to them, processing them like little inboxes. This may sound like anathema to some of you (another inbox? HERESY) but don’t forget–it’s just you in here. You control the flow of info.

I haven’t even begun to scratch the surface here. Slack’s hit on something really terrific that so many apps fall short on: make something useful, and make it super fun. If you’re doing anything cool I might like to try with your Slack channels, by all means, let me know.

Private APIs aren’t open to interpretation.

There are a lot of political injustices imposed on people around the world every day. Suffering is nearly limitless, and horrible problems erode basic human needs and rights almost everywhere. Developers misusing a service’s APIs and then being shocked when their behaviors are called out is not among these injustices.

Ars has a story about a kid who built an app to upload photos to Instagram being “threatened” to take it down. At first glance, a lot of us that don’t work in the corporate world or for a large company see this and would probably think, “Man, that sucks. Boo, Instagram.” The problem is that Instagram’s API has never allowed for uploading to the service. That’s why you could only ever use the main app to send pictures in. Caleb Benn decided that when he saw all the other Mac apps that didn’t have this functionality, he had a market opportunity on which to capitalize.

As a developer, he had enough savvy to hook into the service and build and release a functional Mac app. But whether out of naiveté, ignorance, or disregard, he decided to use a private API to do something the service didn’t permit. The story on Ars positions him as a pawn entangled in a corporate maneuver to oppress independent developers. It talks about how he’s headed off to UC Berkeley to study CS, and he was just solving a problem.

If you read the API terms of use, it doesn’t explicitly say you can’t upload, which may be the problem. But any developer who sees over a dozen apps for a photo service that all don’t do what seems to be the obvious thing they need to do has to then ask “why is that?” and be prepared to do a little digging, and potentially not like the answer. That the company came after him is unsurprising, and well within its rights. That he’s disappointed with this outcome is within his rights. It’s a lesson. That it’s being picked up as a David and Goliath story is bad journalism.

The EFF is now weighing in on this, which really saddens me.

The Electronic Frontier Foundation’s “Coders’ Rights Project” suggests that Benn might be within his legal rights to make the app.

“According Instagram’s [sic] website, reverse engineering the API is indeed a violation of the terms of use,” Corynne McSherry, the legal director at the Electronic Frontier Foundation, told Ars in an e-mail. “That said, the general terms of use refer in turn to an API ‘license.’ Whether or not an API is copyrightable expression as opposed to a method of operation, is by no means a settled question.”

“It’s shameful that Instagram is trying to use its its [sic] terms of service to impede users’ fair use rights and stifle add-on innovation,” she added.

The EFF has many, many, MANY better battles to fight around the world. That it’s deciding to spend its resources re-interpreting the language of an API optionally provided by a service that does not need to do it at all is troubling.

Believe me, in 99% of these matters, I’m almost always in favor of the little guy getting a shot to do something. But this is either a) careless development and unfortunate overall, or b) a calculated stunt by a smart kid who wanted some attention. It’s not political oppression, and it’s not worth the EFF’s time. It’s business, and it’s totally reasonable, although maybe not what you’d want.

Life isn’t always what we want it to be.

Siri, SMS, IFTTT, and Todoist.

When a lot of us started checking out Todoist after Federico’s comprehensive review, one of the things I noticed I’d be giving up was the Siri integration that I’d come to rely on with OmniFocus. OF has a nice feature where it would watch your Reminders for things you added, presumably using Siri, and pull them into your inbox within the app. Todoist is insanely flexible in so many ways, but there’s not currently a direct parallel for this feature.

I started looking to IFTTT for a solution to this. I noticed some recipes that attempt to do the same thing, as IFTTT can monitor your iOS Reminders as well. But since it needs to occasionally be brought up from the background, if you don’t jump into the app regularly, the reminders may never show up. Which defeats the purpose of capturing this way.

I had forgotten that IFTTT can process incoming SMS data as a trigger as well as use it as an endpoint. So today I looked into pushing text messages to IFTTT and having them then get redirected to Todoist. Since both services talk to one another directly on the web (one of the most interesting parts of Todoist in my opinion), this actually works incredibly well, and way faster than I’d anticipated.

You’ll need to set up a recipe in the following way:

  • Start with the SMS channel, and choose either the plain incoming SMS option or a tagged one if you prefer (my suggestion would be to keep it simple, since we’re relying on Siri to do the work and you want accuracy).
  • Then choose the Todoist channel (activate it if you haven’t already) and have the task sent to whatever project you like. I always use inbox, as it’s just for general capture anyway.
  • Once the recipe is made, you can tap to edit certain parameters of the Todoist action (priority, task content, due date1, and note for premium subscribers).
  • I created a contact simply called “Inbox” on my iPhone, again to keep things simple for Siri.

So now, I just say: “Send a message to Inbox that says remember to follow up with the team” and Siri parses it as you’d expect, and sends the message2 directly to IFTTT. Seconds later (it’s shockingly fast in my experience) the task is in my Todoist inbox. It’s way faster and more reliable than hoping the IFTTT app is running often enough to pull reminders directly, and since sending text messages is one of those easier Siri things that works more often than it doesn’t, it’s pretty solid.

Todoist’s web core makes it an interesting way to funnel things into your task list. I’m so glad I thought to do this, because it makes that instant capture I was missing totally achievable again.

  1. I noticed one weird thing related to applying due dates to Todoist via IFTTT. I have my Todoist account set to add a reminder notification to any task that has a date and time associated with it. However, while tasks with times were added correctly, the reminder notification was not. I reached out to support about this and was told that this connection probably isn’t currently supported via IFTTT. If you’re just collecting inbox items this way and processing them later, it’s a nonissue. If you edit the recipe to add dates/times however, just be aware of this potential limitation. 
  2. You can do this with Siri and email too, using the subject line as the task item and the body as the note (if you’re a premium subscriber). But I found that since I’m usually only doing the name of the task anyway, as it’s the bit I need to think about and SMS is so fast and easy, it’s preferable to email in this case. 

Direct Searches with Duck Duck Go and Launch Center Pro.

Since the release of iOS 8 and Yosemite, Duck Duck Go has been available as a default search option in Safari. I recently switched over to it for a few weeks as a trial. It’s a cool search engine with a lot of upsides (a strong stance on privacy, cool customization) but in my tests, I found that my results weren’t as accurate as Google’s in almost every case. This weekend while I was searching for information on Transmit’s terrific iOS version, the first two results were about the app, and then I saw a page full of other… things.


Now I’m not signed into Google in this example, so that’s a straight search, not tailoring of results as far as I know. So going forward, I’ll be starting searches there, as the information returned seems to be far more accurate for what I’m looking for in a general case.

But there’s something really cool that Duck Duck Go can do, and it’s extremely valuable and interesting. The search engine has its own syntax that can be used to really get results differently. More importantly, there’s an entire system of bangs that can do direct searches on hundreds of sites, parsing your queries automatically. Needless to say, once you start down this rabbit hole, it’s a lot of fun.

My current application for this is created as a menu in Launch Center Pro. I read through the list of supported sites and created a scrolling list of all the places I could potentially want to search (shopping sites, different search engines, review sites, etc.) which then just asks for text input. The request is then sent to Safari, where the it’s parsed quickly and followed to the site. For instance, if you want to look for “Tron” on Amazon, you would type “!a tron” and you’re sent to the browser, to Amazon, and then a search on Tron is run.

Using Duck Duck Go as the default search on iOS means you can do this right from Spotlight, which is super cool. But I knew I’d forget the bangs, and I wanted it to be faster (and I wanted to revert to Google as my default search) so LCP was the perfect place to put it. Now with one tap, I can visually browse a list that looks like this:

DDG Menu

and immediately jump to results. The list item URL looks like this:


So all you need to do is create a new entry, select “List” from the text input, add this string, and then edit the list item name and specific bang for each site, keeping the rest of the URL intact.

If you know where you want to go, it saves a little time, and it’s really fun. If you’re curious, I’d recommend exploring Duck Duck Go. There’s a lot to like about it.