Automatically Importing Photos From My Camera

July 11, 2020 - cat | grep

Context

I took up photography as a hobby a few years ago. As soon as I began, I found myself unexpectedly drawn to the entire process. The complexity (and simplicity) of composition, the relationship of shutter speed, aperture, and iso. A hobby where you have fine tuned control over every step of the process. You could go the opposite way as well, throw everything in auto and let the camera fade into the background as your sense of curiosity guides you to the next subject.

I could go on forever about the beauty and intricacies of photography, but that's not what we're here for. I write this preamble to set the backdrop for today's script of interest. As mentioned above, it's easy to get lost in the minutia of the process. One spot I found myself spending many hours on is properly organizing my photo library. After a good amount of iterations and refinement, I believe I've finally settled on something simple and elegant.

A Sorted Library Is A Happy Library

As the format matured, the storage of film negatives converged towards a few basic setups. Either a box, drawer, or binder of some sort which stores sleeves of negatives, typically sorted by date. Sometimes delineated by format / film stock / camera. But the same principle applies, film goes in sleeve goes in container. With digital, we are no longer constrained by the limits of tangibility. This freedom brings its own set of issues. "I can store my files any way I want, but which way is the best?" I've seen the classic "dump everything in one folder and let Lightroom figure it out" work for a good amount of people. However, I see two issues with both this and other database driven methods. For starters, I don't have Lightroom. My current RAW editor of choice, Darktable doesn't organize photos. Second, I want my photos organized at the file system level, independent of any one program. The end result is a folder structure of the following format:


    year
    |-month
        |-day
            |-picture01
            |-picture02

in practice,


    2020
    |-01
        |-01
            |-picture01
            |-picture02
        |-02
            |-picture03
    |-02

and so on.

Of course, creating and maintaining this layout by hand would be a real pain in the aperture. If only there were some way to sort these files automatically...

ExifTool

ExifTool , a collection of Perl modules that can do just about any exif-related operation. It may seem a bit, utilitarian at first glance. However, after looking through a few examples, it's easy to get ExifTool to do exactly what you need. I'll leave it to the curiosity of the reader to explore all of the tagging and sorting possibilities that ExifTool has to offer. Know that my application of the program is not even scratching the surface of ExifTool's utility.


exiftool '-Directory<CreateDate' -d %Y/%m/%d -r /directory/with/photos/* 

is what I use to archive my photos as described above.

How Lazy Efficient Can We Get?

Well, I've got a way to sort my photos. Importing them should be easy enough using rsync . I'll just run the rsync command to import everything, then run my ExifTool command after that. Every single time I have new photos to import. Eh, we can do better! "Put them in a script!", you say. Then I'll only have to run one command every time! I assure you we can do even better than that! Here's where inotify-tools comes into play. More specifically, inotifywait will do the trick.

See, I don't want to run a command, press a button, what have you, every single time I have photos to import. It's just too much trouble! With inotifywait, I can have a script running at all times that watches a directory for changes (say, my mount directory). Then, upon mounting a drive 1 , look for a certain folder (say, DCIM), and begin importing and sorting. After all of that, unmount and power off my card reader. And all I had to do was plug the thing in!

The Script


#!/bin/bash
LIBRARY='/path/to/photo/library'
INCOMING="$LIBRARY/incoming"
WATCHDIR='/path/to/mount/directory'
MOUNTDIR="$WATCHDIR/disk"
CAMERADIR="$MOUNTDIR/DCIM"

watch_dir () {
    while inotifywait -e CREATE $WATCHDIR
    do
        copy_photos
    done
}

wait_for_dir () {
    while [ ! -d "$WATCHDIR" ];
    do
        sleep 2
    done
    copy_photos
    watch_dir
}

copy_photos () {
    sleep 5
    if [ -d "$CAMERADIR" ];
    then
        mkdir $INCOMING
        rsync -ravP $CAMERADIR/* $INCOMING
        cd $LIBRARY
        exiftool '-Directory<CreateDate' -d %Y/%m/%d -r $INCOMING/*
        rm -r $INCOMING
        udiskie-umount --detach $MOUNTDIR
    fi
}

if [ -d "$WATCHDIR" ];
then
    watch_dir
else
    wait_for_dir
fi

How It Works

Once executed, the script will continuously run, only taking action when a new folder is created in my mount directory. 2 Once a directory is created (something is mounted), the directory structure is checked to see if it matches that of my camera's SD card. If so, make a temporary "incoming" directory, copy the contents of the SD card to it, and then put the files in their respective date-ordered directories. Once all of the copying and sorting is squared away, eject the SD card and power off the card reader using --detatch . Afterwards, go back to monitoring my mount directory for new folders.

Conclusion

I like it! I've been using this script for the past week and haven't run into any trouble. I've found my card reader provides me with an unintended benefit - it has a red LED on it that turns off when the script finishes. Now, I don't even need to double check the file system to see if the script completed (although I probably still should and will).


1. I have auto-mounting set up using udiskie.

2. udiskie defaults to /run/media/<user>