Often I'll want to share a screenshot and over the years I've used a number of different tools, but I'm always beholden to when they eventually become unsupported or the company "pivots" and the pricing model goes silly. So after all this time, I finally worked out how to roll my own.
Forewarning though, this is MacOS specific, but I'm sure same thinking can be applied to other operating systems.
UK EVENTAttend ffconf.org 2024
The conference for people who are passionate about the web. 8 amazing speakers with real human interaction and content you can't just read in a blog post or watch on a tiktok!
£249+VAT - reserve your place today
The spec
I want to be able to take a screenshot and then, without any interaction, have a sharable URL in my clipboard.
The steps to achieve this (on my mac) are:
- When a new file appears in my screenshot folder, perform an action
- Read the latest file in the folder and upload to a hosting service
- Copy the URL of that image to my clipboard
There's a couple of bonus features that I can add to this:
- Compress the image first then upload it
- Play some kind of notification so I know the upload is complete
- Only apply this action to new screenshots - not a file I might have renamed
This lose outline gives me the power to use my own screenshot software, whether it be a plain native screenshot, or shottr (which I really like for quick annotations before getting dropped into my screenshot folder). If (or when) shottr stops working, my process can still work.
I'm also free to decide how I host the images. For the time being, this is via AWS S3.
Finally, I want a fancy url for the images, so I'll lean on Netlify for this.
The implementation
I've tried to break this down into readable blocks, but this isn't intended as a copy and paste solution (though you probably could copy all the blocks).
1. When a new file appears
I originally tried to achieve this using MacOS's Automator app but frankly I've no idea how it works, where configuration files live or anything.
However, a simpler solution (to me!) is a WatchPath
service to monitor a directory for MacOS. This means when the directory contents changes, it will let me run a terminal command.
The command I run will then do all the heavy lifting to work out what's changed and what to do:
I created ~/Library/LaunchAgents/upload_screenshot.plist
and registered it with:
$ launchctl load ~/Library/LaunchAgents/upload_screenshot.plist
The upload_screenshot.plist
file contains the following XML (note that ~/Desktop/Screenshots
is where my screenshots land):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
<key>Label</key>
<string>Upload Screenshot</string>
<key>ProgramArguments</key>
<array>
<string>~/bin/upload_screenshot</string>
</array>
<key>WatchPaths</key>
<array>
<string>~/Desktop/Screenshots</string>
</array>
</dict>
</plist>
2. Doing a thing with that screenshot
What this script does is:
- if the file hasn't been processed already, then –
- copy the predicted url to the clipboard
- compress the file (adding
-min.png
to the end) - remove the old image
- upload the file
- play a notification sound
The file lives in ~/bin/upload_screenshot
(~
being short hand for my $HOME
directory), and it has execute properties, i.e. chmod +x ~/bin/upload_screenshot
.
There's also a few external programs being used:
pbcopy
a macos command to copy a string to the clipboardafplay
another macos native command, plays audio - theBlow.aiff
was just a sound I found in the operating systempingquant
a third party png compressor - it helped upload speeds to compress the image (and of course, bandwidth, costs, etc)aws
the command line tool to actually run the upload to AWS using a profile I created calledscreenshot
Below is the script itself:
DIR=/Users/remy/Desktop/Screenshots
# get the latest file
FILE=$(ls -rAt $DIR | tail -n 1)
# if it's a junk file, or it's already processed, exit early
if [[ "$FILE" == .DS_Store ]]; then exit; fi
if [[ "$FILE" == *-min.png ]]; then exit; fi
# copy the URL to the clipboard as early as possible
echo https://remysharp.com/shot/$(basename $FILE .png)-min.png | pbcopy
# compress the original and output as $FILE-min.png
/Users/remy/bin/pngquant $DIR/$FILE --ext -min.png
# remove the original
rm $DIR/$FILE
# upload to AWS under my "screenshot" profile
AWS_PROFILE=screenshot /usr/local/bin/aws s3 cp $DIR/$(basename $FILE .png)-min.png s3://screenshots.remysharp.com
# play tone so I know it's ready
afplay /System/Library/Sounds/Blow.aiff
3. AWS policy
AWS policies always bite me, so I've included it in this write up. I created a bucket called screenshots.remysharp.com
which the policy below can write to. The policy was created against a new user called screenshot
.
Note that I also configured the AWS bucket to be public so that when I shared a URL the image could be actually read.
{
"Version": "2012-10-17",
"Id": "Policy1397632521960",
"Statement": [
{
"Sid": "Stmt1397633323327",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::screenshots.remysharp.com/*"
}
]
}
4. Fancy URLs
Finally, when the images are uploaded, you might have noticed that I didn't copy the AWS URL (because they're ugly), but a "nice" URL under my own domain.
To achieve this, since my blog (the domain remysharp.com
) is hosted on Netlify, and Netlify offers a really superb redirect service, I'm able to use their "splats" to hide the AWS URL and make it nice.
It also means should I ever move to a new image hosting provider, and I wanted to keep my screenshots, I can keep supporting these URLs as I have full control of them.
In my _redirects
file I include the following line:
/shot/* https://s3.eu-west-2.amazonaws.com/screenshots.remysharp.com/:splat 200
There you go
I think it's pretty neat 😉 https://remysharp.com/shot/SCR-20221128-doc-min.png