ShareX image host
An image uploader that spoke ShareX's custom-uploader format, so the screenshot key on my keyboard put a file on my own box instead of someone else's. Express, EJS and Bootstrap, in 2023, translated into four languages nobody needed. 2023–2024.
- Implemented ShareX's custom uploader contract, so pressing print screen uploaded to my server and put the link on the clipboard.
- Express and Multer doing the upload handling, EJS rendering the pages server-side, Bootstrap making them look like every other Bootstrap site.
- Localised into English, Polish, German and French — for a personal image host with one user.
- Plain JavaScript, no types, at the point where everything else I wrote was TypeScript.
- Didn't last long, and didn't deserve to.
outcome — Ran about a year for exactly one user — me. Retired when keeping the box up got more annoying than not having one.
- ExpressJS
- JavaScript
- EJS
- Bootstrap
- Multer
I called it a CDN. It was not a CDN.
A CDN is geographically distributed edge caching — the whole point is copies of your file near the person requesting it. This was one box, in one place, serving files over HTTP. What it actually was is an image host with an upload endpoint, which is a completely reasonable thing to build and not the thing the name claimed.
the actual point: the print screen key#
The reason it existed is ShareX, which lets you point the screenshot key at an arbitrary HTTP endpoint instead of a hosted service. You describe your uploader in a small JSON config — where to POST, what field the file goes in, how to dig the resulting URL out of the response — and from then on the key does what it always did, except the file lands on your server and the link is on your clipboard before you've finished letting go.
So the brief was narrow and completely defined by somebody else: accept a multipart POST, store the file, return JSON in a shape ShareX can parse. That's it. Multer handled the multipart side, Express handled the rest — the same Express I'd used on the casino project the year before, and about the last time I reached for it before Fastify.
Working against a fixed external contract is a good exercise precisely because there's no room to negotiate. It either produces what the client expects or the key doesn't work, and "the key doesn't work" is immediate, unambiguous feedback of a kind most of my own projects don't give me.
bootstrap and ejs, in 2023#
Server-rendered EJS templates with Bootstrap on top, at a point where everything else I was writing was React and TypeScript.
I want to defend this and can only half do it. The defensible half: it's an upload endpoint with a couple of pages hanging off it, and the pages exist to show you a file you already have. There is no interactivity to speak of, and reaching for a frontend framework and a build step for that is how a weekend project becomes a thing you maintain. Server-rendered templates were genuinely the right weight.
The indefensible half is Bootstrap in 2023, and the fact that it was all plain JavaScript with no types while I was already using TypeScript everywhere else. Neither was a decision. Both were what my hands did when the project didn't feel serious enough to think about, which is exactly when I make the choices I later can't explain.
four languages, one user#
It was localised into English, Polish, German and French.
The user count was one. I speak two of those.
I don't have a good reason for this and I've stopped looking for one. The honest version is that i18n was a self-contained problem with a clear finish line, and doing it felt like progress in a way that the actual remaining work — quotas, cleanup, anything to do with the files piling up — did not. It's procrastination that produces commits, which is the hardest kind to catch yourself doing.
It's also the second time I did it. The casino project the year before shipped English and Polish, for a class assignment that got demoed once to a room of Polish speakers. Twice makes it a habit, and the habit is reaching for the tidy, finishable problem when the untidy one is the one that matters.
It's the funniest thing on this page and the most useful thing on it, in the sense that I now recognise the feeling.
why it stopped#
Nothing killed it. It worked, right up until I stopped pointing ShareX at it.
An image host is infrastructure for one person, and infrastructure for one person has to be less annoying than the hosted alternative or it loses. Mine was fine and free, but it was also a box I had to keep running, with storage that only ever grew and no cleanup story, and the day it broke would be a day I wanted to paste a screenshot rather than debug an upload endpoint.
The version worth building, if I did it again, is the same endpoint with none of the site attached: no templates, no Bootstrap, no translations. Just the contract ShareX needs and something that deletes old files. The whole rest of it was me making a project out of a script.