ArtCraft is pretty good

I just want to mark this time with a blog post. For years people have been looking for Lightroom (and then Lightroom Classic) alternatives. And for years there have been alternatives for Lightroom/LrC and Photoshop like GIMP, DigiKam, Darktable and others. The advent of AI tools made it easier to create these sorts of projects, but Adobe posted record profits this year, so I don’t think they’re worried just yet. Their stock price is down, maybe reflecting investor attitudes to the new tools, but coding an app is only one part of it. Distribution and getting people to use it is another.

RapidRaw appeared just over a year ago that looks like Lightroom, and it’s a pretty decent editor. However, it displays compressed DNG files in a strange purple shaded almost mono way but displays Sony ARW files perfectly. An earlier version I tried didn’t have recursive display of photos in a directory tree (or maybe I didn’t find that setting) but the latest version does. I might be to help them figure out the problem with compressed DNG files.

Meanwhile, the latest Lightroom clone to hit the internets is LightCraft, part of the ArtCraft series of apps that replace the entire Adobe suite and some Microsoft apps.

They’re only a couple of weeks old, but the user interface of LightCraft looks very like Adobe’s Lightroom. My YouTube history this week is full of videos talking about it, about what’s missing from it usually, but there’s an optimistic feeling that these apps might be able to replace your Adobe subscription sooner rather than later.

I tried it and it behaved well. Like RapidRaw, it didn’t play well with compressed DNG files, displaying a message saying:

LightCraft can’t decode this raw variant vet (lossy JPEG XL tile with a declared encoding that is not linear RGB). You’re editing the camera’s embedded JPEG preview, which already includes the camera’s picture style (e.g.
Monochrome) and white balance.

It had no such problem with Sony ARW files, but wasn’t able to apply lens correction.

Anyway, they’re worth keeping an eye on if you don’t want to send Adobe any money. LightCraft shows how much you can do quickly with AI, but RapidRaw is a slightly older project developed using AI tools too. That project impressed me but there’s a huge amount of work to do, regardless of what magic pixie dust you throw at it.

Here are a couple of videos you should watch. Fstoppers put PhotoCraft through its paces, while Andy Hutchinson goes through LightCraft. Whatever you think of the apps now, it’s early days yet. I think they’ll have a pretty good chance of persuading a few people to stop using the Adobe Suite.

BOI doesn’t confirm your email address

Your new Bank of Ireland eStatement

FYI – if you open a Bank of Ireland account, please ensure you give them the correct email address or private correspondence will be sent to someone else.

Luckily, BOI is off the hook:

This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. It is possible for data transmitted by email to be deliberately or accidentally corrupted or intercepted. For this reason, where the communication is by email, the Bank of Ireland Group does not accept any responsibility for any breach of confidence which may arise through the use of this medium.

25 years ago

I was sitting at my desk in a small office in Ballincollig when John burst through the open doorway, “A plane has hit the World Trade Center!”

My office, a few years later.

The rest of the day was a blur, but someone found a TV and set it up in the next office, where John and Una worked, I think. We went in and out looking at it and keeping an eye on news sites.

It’s hard to say for sure, but I think it was the first time I became aware of the World Trade Center. This was 2001. I’d only left the country a couple of times, and never been to the US. In an age before we were so connected the world wasn’t so small.

It didn’t matter because the enormity of it soon became clear, and the horror was plain to see. I remember being very upset that evening.

The meaning of numbers

I spent 3 or 4 years coding in assembler on the C64. I’ve been a retro fan of the machine for far longer now but haven’t really immersed myself in it like I did in the early to mid nineties.

Despite the time that has passed since then, and all that had happened, some things are still stuck in my brain and one of those things is the common hex locations used for various functions.

BASIC programmes were stored at $0801 so when you typed the following it was stored there in memory.

10 PRINT "HELLO WORLD"
20 GOTO 10

If you were programming in assembler you could create a BASIC programme to execute it like this, and it would run the assembler at $080d, the hex equivalent of 2061, and the next byte of memory after this BSSIC instruction.

10 SYS 2061

This all popped into my head when I saw my posting streak for my photo blog today.

Yay, 2061 days posting photos on inphotos.org.

Other numbers that live in my brain without thinking are $1000 and 4096 (where many sid tunes lived), or even $c000 and 49152. I have so many disks with chunks of code at $c000.

So, this is what those numbers mean to me. A nostalgic trip down memory lane.

Do you have a similar association with numbers from long ago?

My eyes hurt after the eclipse

Searches for “eclipse hurt eyes” jumped 170% in the last 24 hours after the eclipse yesterday evening. Ouch. I hope those people didn’t stare too long and that no permanent damage was done.

The sky was cloudy where I live, but I still managed to get a photo, even if it was only with my phone as the clouds briefly allowed the sun through. So much for my plans to use eclipse glasses with my compact camera.

Instead, I spent a nice evening with my wife, our pets and a neighbour who called over for a chat. Lovely!

As expected, Facebook is full of amazing photos of the eclipse, but I love this.

Sharing a large Immich library without melting the server

I share a photo library between two Immich users, my photos visible in my partner’s account, using an external library. Instead of uploading, Immich points at a folder on disk and imports whatever it finds there. It’s a lovely setup right up until the library gets big. Mine is big: over 750,000 photos, with more than half a million in a single external library.

Running out of memory

My server was struggling, chewing into swap all the time and running out of memory.

microservices worker error: Error [ERR_WORKER_OUT_OF_MEMORY]:
Worker terminated due to reaching memory limit: JS heap out of memory

I had Immich running in a 6GB Docker container but reduced that to 4GB for other reasons, and it appeared to work ok for a while, but it took a while for me to notice it was using the entirety of the 4GB of RAM. I increased the RAM allocated to the container, but it was still a heavy user.

The library watcher

External libraries have two ways to notice new files. There’s a periodic scan, which I’d already disabled because it’s brutal at this size. And there’s the watcher, which uses filesystem notifications to spot new files the moment they land. That’s what makes photos I add show up automatically.

The watcher is the convenient one. It’s also the expensive one. Watching a folder tree with 750,000 files means holding an enormous number of filesystem watches plus the bookkeeping that goes with them, and on my library that was around 3GB of resident memory, sitting there permanently doing nothing most of the time.

I turned it off in the admin settings. Memory use went from ~4GB pinned at the limit to about 1GB. Nightly jobs suddenly had room to breathe and the crash loop stopped.

Except now new photos don’t get imported, because the watcher was the thing importing them. So: how do you add a photo to a huge external library without a watcher and without a full scan?

The obvious fix that doesn’t work

Immich has an API endpoint to scan a library:

POST /api/libraries/{id}/scan

It scans the whole library. On my photo archive that’s a long, heavy crawl, and I’d already learned the hard way what a scan does to this box. Not something you run every time you drop in a picture.

Enqueue the import job yourself

So I went looking at what the watcher actually does when it sees a new file, expecting something complicated. It’s almost nothing. It queues one background job:

jobRepository.queue({
    name: 'LibrarySyncFiles',
    data: { libraryId, paths: [path] },
})

LibrarySyncFiles takes an explicit list of paths and imports exactly those files, without crawling the other 500,000. The per-file import I wanted was already sitting there. The watcher was only ever the trigger, and I was paying 3GB for the trigger.

I can pull that trigger myself. Immich uses BullMQ (backed by Redis/Valkey) for its job queue, so I can push the same job onto the same queue. The photos I add already go through a little script that moves them into the library folder by date, so the import hooks straight into that. When the script moves a new file in, it queues a LibrarySyncFiles job for that exact file:

docker exec -w /usr/src/app/server immich_server node -e '
  const { Queue } = require("bullmq");
  const q = new Queue("library", {
    prefix: "immich_bull",
    connection: { host: "redis", port: 6379 },
  });
  q.add("LibrarySyncFiles", {
    libraryId: "your-library-id",
    paths: ["/path/inside/the/container/to/new-photo.jpg"],
  }).then(() => q.close());
'

Immich picks it up, runs its normal import pipeline on that one file (metadata, thumbnails, the lot) and the photo appears. No watcher sitting on gigabytes of RAM, no full-library scan, and new photos still land within a cycle of my import script.

The caveats, because this is a hack

It leans on Immich’s internals, so: only send files that are genuinely new. The job handler inserts unconditionally, so hand it a path that’s already imported and you get a duplicate-key error in the logs. My script only queues files it actually moved.

More seriously, this is an internal job queue, not a public API. The queue name, the job name and the payload shape are implementation details, and an upgrade could rename or reshape any of them. The failure mode is silent: photos would just quietly stop importing and I wouldn’t find out until I went looking for one. My script shouts if the enqueue fails, which covers some of that but not all of it. This was working on Immich 3.0.2.

And turning off the watcher also turns off deletion detection, since the watcher is what removes assets when their files vanish. My workflow only ever adds files, so it doesn’t bite me. It might bite you.

There is a discussion here asking for an API endpoint to scan single files, but it hasn’t received much attention in 2 years, so I guess not many people have this issue, or realise it is an issue.

Was it worth it?

For a library this size, yes. About 3GB of RAM back, no more crash loop, and photos still import on their own. If your external library is small this is all irrelevant, so leave the watcher on and get on with your life. But if you’re in the hundreds of thousands of files and your server keeps falling over, check the watcher first.

Ireland’s Russian Problem

I remember watching this video by Kev Collins a while back where he covered the Aughinish plant in Co. Limerick. His documentary revealed a horrible site on the west coast of Ireland. Red ponds of waste that blow into neighbouring farms and a family that had to move out of their family home because of it.

Then comes the fact that most of the aluminum produced there ends up in Russia and will inevitably end up in weapons and munitions used against Ukraine.

A month ago Caolon Robertson shared a video short about the same plant, showing a ship that had just left Aughinish for St. Petersburg in Russia. A few hours ago he posted his documentary on Aughinish. It’s worth watching.

It’s shameful that Ireland is allowing this plant to export to Russia.