Skip to content

Instantly share code, notes, and snippets.

@ljm42
Last active July 5, 2024 10:44
Show Gist options
  • Save ljm42/02b54ce9cc36f992515b to your computer and use it in GitHub Desktop.
Save ljm42/02b54ce9cc36f992515b to your computer and use it in GitHub Desktop.
unRAID - automatically move photos to array
#!/bin/bash
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
## Usage (after configuration):
## 1. Insert camera's memory card into a USB port on your unRAID system
## 2. The system will automatically move (or copy) any images/videos from the memory card to the array
## If jhead was installed, it will automatically rotate images according to the exif data
## 3. Wait for the imperial theme to play, then remove the memory card
## Preparation:
## 1. Install jhead (to automatically rotate photos) using the Nerd Pack plugin
## 2. Install the "Unassigned Devices" plugin
## 3. Use that plugin to set this script to run *in the background* when a memory card is inserted
## 4. Configure variables in this script as described below
## Warning:
## The newperms script has a bug in unRAID 6.1.3 - 6.1.7
## see https://lime-technology.com/forum/index.php?topic=43388.0
## --- BEGIN CONFIGURATION ---
## SET THIS FOR YOUR CAMERAS:
## array of directories under /DCIM/ that contain files you want to move (or copy)
## can contain regex
VALIDDIRS=("/DCIM/[0-9][0-9][0-9]___[0-9][0-9]" "/DCIM/[0-9][0-9][0-9]CANON" "/DCIM/[0-9][0-9][0-9]_FUJI" "/DCIM/[0-9][0-9][0-9]NIKON" \
"/DCIM/[0-9][0-9][0-9]MSDCF" "/DCIM/[0-9][0-9][0-9]OLYMP" "/DCIM/[0-9][0-9][0-9]MEDIA" "/DCIM/[0-9][0-9][0-9]GOPRO" "/DCIM/[0-9][0-9][0-9]_PANA")
## SET THIS FOR YOUR SYSTEM:
## location to move files to. use date command to ensure unique dir
DESTINATION="/mnt/user/Photos/To Be Filed/incoming/$(date +"%Y-%m-%d-%H-%M-%S-%N")/"
## SET THIS FOR YOUR SYSTEM:
## change to "move" when you are confident everything is working
MOVE_OR_COPY="copy"
## set this to 1 and check the syslog for additional debugging info
DEBUG=""
## Available variables:
# AVAIL : available space
# USED : used space
# SIZE : partition size
# SERIAL : disk serial number
# ACTION : if mounting, ADD; if unmounting, REMOVE
# MOUNTPOINT : where the partition is mounted
# FSTYPE : partition filesystem
# LABEL : partition label
# DEVICE : partition device, e.g /dev/sda1
# OWNER : "udev" if executed by UDEV, otherwise "user"
# PROG_NAME : program name of this script
# LOGFILE : log file for this script
log_all() {
log_local "$1"
logger "$PROG_NAME-$1"
}
log_local() {
echo "`date` $PROG_NAME-$1"
echo "`date` $PROG_NAME-$1" >> $LOGFILE
}
log_debug() {
if [ ${DEBUG} ]
then
log_local "$1"
fi
}
beep_imperial() {
for i in $(seq 1 ${1}); do
beep -f 392 -l 450 -r 3 -D 150 -n -f 311.13 -l 400 -D 50 \
-n -f 466.16 -l 100 -D 50 -n -f 392 -l 500 -D 100 \
-n -f 311.13 -l 400 -D 50 -n -f 466.16 -l 100 -D 50 \
-n -f 392 -l 600 -D 600 -n -f 587.33 -l 450 -r 3 -D 150 \
-n -f 622.25 -l 400 -D 50 -n -f 466.16 -l 100 -D 50 \
-n -f 369.99 -l 500 -D 100 -n -f 311.13 -l 400 -D 50 \
-n -f 466.16 -l 100 -D 50 -n -f 392 -l 500 -D 100
sleep 2
done
}
case $ACTION in
'ADD' )
#
# Beep that the device is plugged in.
#
beep -l 200 -f 600 -n -l 200 -f 800
sleep 2
if [ -d ${MOUNTPOINT} ]
then
# only process an automount. manual mount is messy, users may or may not expect it to unmount afterwards
if [ "$OWNER" = "udev" ]; then
log_all "Started"
log_debug "Logging to $LOGFILE"
RSYNCFLAG=""
MOVEMSG="copying"
if [ ${MOVE_OR_COPY} == "move" ]; then
RSYNCFLAG=" --remove-source-files "
MOVEMSG="moving"
fi
# only operate on USB disks that contain a /DCIM directory, everything else will simply be mounted
if [ -d "${MOUNTPOINT}/DCIM" ]; then
log_debug "DCIM exists ${MOUNTPOINT}/DCIM"
# loop through all the subdirs in /DCIM looking for dirs defined in VALIDDIRS
for DIR in ${MOUNTPOINT}/DCIM/*; do
if [ -d "${DIR}" ]; then
log_debug "checking ${DIR}"
for element in "${VALIDDIRS[@]}"; do
if [[ ${DIR} =~ ${element} ]]; then
# process this dir
log_local "${MOVEMSG} ${DIR}/ to ${DESTINATION}"
rsync -a ${RSYNCFLAG} "${DIR}/" "${DESTINATION}"
# remove empty directory from memory card
if [ ${MOVE_OR_COPY} == "move" ]; then
rmdir ${DIR}
fi
fi
done
fi
done
# files were moved (or copied). rotate images, fix permissions
if [ -d "${DESTINATION}" ]; then
if [ -e "/usr/bin/jhead" -a -e "/usr/bin/jpegtran" ]; then
log_debug "running jhead on ${DESTINATION}"
jhead -autorot -ft "${DESTINATION}"*.[jJ][pP][gG]
fi
log_debug "fixing permissions on ${DESTINATION}"
newperms "${DESTINATION}"
fi
# sync and unmount USB drive
sync -f ${DESTINATION}
sync -f ${MOUNTPOINT}
sleep 1
/usr/local/sbin/rc.unassigned umount $DEVICE
# send notification
beep_imperial 1
/usr/local/emhttp/webGui/scripts/notify -e "unRAID Server Notice" -s "Photo Import" -d "Photo Import completed" -i "normal"
fi # end check for DCIM directory
else
log_all "Photo Import drive not processed, owner is $OWNER"
fi # end check for valid owner
else
log_all "Mountpoint doesn't exist ${MOUNTPOINT}"
fi # end check for valid mountpoint
;;
'REMOVE' )
#
# Beep that the device is unmounted.
#
beep -l 200 -f 800 -n -l 200 -f 600
log_all "Photo Import drive unmounted, can safely be removed"
;;
esac
@ljm42
Copy link
Author

ljm42 commented Jun 17, 2017

Thanks for the feedback! Wasn't sure if anyone else was using it, although it makes my life a lot easier.

I'm not sure about the directory that starts with '/MP_ROOT/', it seems like the code would skip it since it is hard coded to assume everything will start with /DCIM/. Which camera uses /MP_ROOT/, and do the files actually get copied?

@evenwebb
Copy link

Thanks for the feedback! Wasn't sure if anyone else was using it, although it makes my life a lot easier.

I'm not sure about the directory that starts with '/MP_ROOT/', it seems like the code would skip it since it is hard coded to assume everything will start with /DCIM/. Which camera uses /MP_ROOT/, and do the files actually get copied?

Hi @ljm42, is it possible to add the Camera Make/Model as a folder in the destination? I don't know much about scripting etc. I try to get by but I would be worried about not correctly error checking it and damaging my files :)

Thank you in advance

@ljm42
Copy link
Author

ljm42 commented Feb 6, 2019

Hmm, I don't seem to get notified when someone comments here.

This script only has access to filenames, so it wouldn't have the camera details. As written, it creates a new folder based on the current date/time so you don't have to worry much about it stomping on your existing files.

@ljm42
Copy link
Author

ljm42 commented Feb 6, 2019

Oh maybe you mean you don't want to modify the list of VALIDDIRS. Well, the good news is that MOVE_OR_COPY is set to "copy" by default. You can try it out, and only switch it to "move" when you are confident the files are going to the right place.

@Blindside995
Copy link

@ljm42
Love your script been using it a while now. Just wanted to clarify a couple of things.
Should I be letting the script mount the SD card or should I have unassigned devices mounting the drive? Currently, I have it set to automount and the only issue I get then is that the user is "user" instead of "udev"
2. evenwebb was saying would it be possible to have folders for different cameras. A parent dir for canon, GoPro, etc. Personally, I haven't been able to come up with a way of doing that without messing things up. But I'm not the best with script work anyway.
3. Anyone that sees this comment and uses Panasonic cameras I got it to work with "/DCIM/[0-9][0-9][0-9]_PANA"
Thank you for the script! Importing pictures from my camera have never been this easy even with the weird permission issue that happens ever now and again.

@Blindside995
Copy link

You can ignore #2 you already addressed that it seems. Thanks!

@robohead456
Copy link

mkdir -p "${DESTINATION}" needs to be added before the rsync line, otherwise the directory will not be created and nothing will be copied

@ljm42
Copy link
Author

ljm42 commented Dec 12, 2022

mkdir -p "${DESTINATION}" needs to be added before the rsync line, otherwise the directory will not be created and nothing will be copied

Ah, I could see how that would be needed if your DESTINATION directory was something was something like /incoming/year/month/ instead of /incoming/date/. rsync will create a single new directory but probably not two.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment