Auto import from SD card to Immich

Here's a quick write up on how to import pictures and videos from SD card reader to Immich using systemd on Linux

I recently bought a Fuji mirrorless camera, and want to make it as smooth as possible to upload photos to Immich. After I have imported, I delete the images I do not want.

Labeling the SD card and automount

Fuji does not set a UUID or a label on the SD card when you format it. This is a bit annoying, since it makes is harder to automate the process that all cards formatted with a Fuji camera should automatically mount to /mnt/fuji. The workaround I went for is to create a label on the SD card manually after each format.

First find the path to your memory card with fdisk -l. Mine was /dev/sdg1

Then I put a label (DCIM) on it with:

sudo exfatlabel /dev/sdg1 DCIM

We can now edit the file /etc/fstab
Add the line:

/dev/disk/by-label/DCIM  /mnt/fuji  exfat  noexec,nodev,nosuid,nofail  0 0

We also need to add a udev rule, to have it automount.

Edit the file /etc/udev/rules.d/99-dcim-mount.rules

With the content:

# Mount when the card appears
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_LABEL}=="DCIM", TAG+="systemd", \
  ENV{SYSTEMD_WANTS}+="mnt-fuji.mount"

# (Optional) cleanly unmount when it’s pulled
ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_LABEL}=="DCIM", RUN+="/usr/bin/umount /mnt/fuji"

Create the dir, reload systemd, and test mount:

mkdir /mnt/fuji
udevadm control --reload
systemctl daemon-reload
mount -a

Creating systemd file to start bash script

Create the systemd service file for running the script:

/etc/systemd/system/auto-upload-immich.service

With the content:

[Unit]
Description=Archive .raf  and import jpeg to Immich
BindsTo=dev-disk-by\x2dlabel-DCIM.device     # die when the device goes away
After=dev-disk-by\x2dlabel-DCIM.device
RequiresMountsFor=/mnt/fuji                  # systemd mounts it for us
ConditionPathIsMountPoint=/mnt/fuji

[Service]
Type=oneshot
Environment="IMMICH_API_KEY=<yourAPIkey"
Environment="IMMICH_INSTANCE_URL=https://<yourdomain.immich.domain>"
Environment="MOUNT_DIR=/mnt/fuji/DCIM/100_FUJI/"
Environment="RAW_DIR=/mnt/appdata/rawfiles/"
Environment="WEBHOOK_ENDPOINT=<endpoint if you want to ping a webhook>"
Environment="SD_CARD_MOUNT=/mnt/fuji"
Environment="HA_URL=https://homeassistant.yourdomain.com/api/webhook/-webhookID"
ExecStart=/usr/local/bin/auto-upload-immich.sh --when=inserted --mount-point=/mnt/fuji

[Install]
WantedBy=dev-disk-by\x2dlabel-DCIM.device

Please make sure to edit the environment variables for your environment. Take note that I have set the variable MOUNT_DIR to DCIM/100_FUJI, so Immich doesn't need to scan the whole SD card for the media files.

The environment variable $RAW_DIR is for moving the .raf files to a separate directory before running the Immich import. This way I can store my .raf files independently, if I have a banger of a photo that the jpeg did not end up looking nice.

The env $WEBHOOK_ENDPOINT is for sending a POST to a webhook. I have another service that checks my geolocation from Home Assistant, and ads that data to the images on Immich. This way, I get geolocation on the photos without draining my battery with BLE connecting to the camera when I shoot.

The env HA_URL is for sending a http PUT request to a Home Assistant automation. (I have a automation that says on my speakers in the kitchen that the import is finished, so I remember to put the SD card back in the camera).

The bash script

So finally it is the script. Create and edit the file:

/usr/local/bin/auto-upload-immich.sh

With the content:


#!/bin/bash

# set immich_cli variable
IMMICH_CLI="docker run --rm  --pull=always \
-v $MOUNT_DIR:/import:ro \
-e IMMICH_INSTANCE_URL=$IMMICH_INSTANCE_URL \
-e IMMICH_API_KEY=$IMMICH_API_KEY \
ghcr.io/immich-app/immich-cli:latest upload -r /import"

echo "script started"
echo "Moving raw files"
shopt -s nullglob
for file in "$MOUNT_DIR"*.RAF; do
  # the -- protects against filenames starting with “-”
  mv -- "$file" "$RAW_DIR"/
done
echo "Starting Immich import"
$IMMICH_CLI

#echo "unmounting sd card"
#umount $SD_CARD_MOUNT
echo "Sending curl"
curl --silent --show-error --fail -X POST $WEBHOOK_ENDPOINT
curl --silent --show-error --fail -X PUT $HA_URL
echo "Done, exiting"

  • You need docker (or podman) to run this.
  • We also pull=always, so we do not end up with a stale immich cli image.
  • We do not delete the files from the SD card, and mount it as read only inside the container.

fin

Finally we need to reaload systemd.

systemctl daemon-reload
systemctl enable /etc/systemd/system/auto-upload-immich.service

You can check your services with:

journalctl -u /etc/systemd/system/auto-upload-immich.service -f