1 #!/bin/bash 2 3 ############################################################################# 4 # Back up photos from an iPhone 5 ############################################################################# 6 # Includes mutation .plist files saved as .AAE files 7 # and their corresponding edited jpegs 8 9 # This script only works if the full resolution ORIGINAL images are stored 10 # on the iPhone and not on iCloud. I don't think this is the default 11 # if you have iCloud Photos enabled, so check your settings! 12 # 13 # 14 # Usage: Modify the directory variables where indicated below 15 # then run the script without any arguments. 16 # 17 # Pay attention to any warnings generated. 18 # You can safely ignore any skip messages genreated while processing 19 # the Adjustments directories. It's just letting you know that 20 # no edits were found for a particular photo. 21 # 22 ############################################################################# 23 # This script makes the following assumptions, which are true 24 # as of iOS version 12. If Apple changes any of these things, 25 # the script may behave unexpectedly. 26 ############################################################################# 27 # 1: The DCIM and PhotoData directories are accessible from the iPhone's root 28 # 2: The DCIM directory has subfolders in the format of ###APPLE 29 # and all the photos we want synced are inside that 30 # 3: The PhotoData directory structure is as follows: 31 # (iphone)/Photodata/Mutations/DCIM/ 32 # with subfolders in the same ###APPLE format 33 # 4: Within these PhotoData directories we expect to find 34 # an Adjustments subfolder and some files within that: 35 # an Adjustments.plist file and either a FullSizeRender.jpg 36 # or an IMG_####.jpg for slowmo's and timelapses. 37 ############################################################################# 38 # made with <3 by ~inthreedee ( https://tilde.town/~inthreedee/ ) 39 ############################################################################# 40 41 42 ############################################################################# 43 ######################### Edit these directories! ########################### 44 ############################################################################# 45 # Source MUST be the root iPhone directory that has 46 # the subfolders DCIM and PhotoData within it. 47 # If auto-mounted by GNOME, it will look something like this: 48 # src="/run/user/1000/gvfs/afc:host=295ad715b7ff8ec030151d433d446db89e576df99" 49 # example dest="/mnt/backups/pictures/example" 50 source="/run/user/1000/gvfs/afc:host=######" 51 dest="/mnt/backups/Pictures/example" 52 53 # Which of the ###APPLE directories do we want to sync? 54 # This array MUST be formatted as a list of numbers separated by spaces. 55 # {#..#} can be used for an inclusive sequence of numbers. For example: 56 # =(111) 57 # =(111 112 114) 58 # =({111..115} 118 121) 59 processdirs=(111..121) 60 61 ############################################################################# 62 ########################### No touchy beyond here! ########################## 63 ############################################################################# 64 65 # Append APPLE to each of the array elements so we get the full 66 # folder name structure of ####APPLE 67 processdirs=( "${processdirs[@]/%/APPLE}" ) 68 69 # These directories should be left alone unless Apple 70 # changes their iOS directory structure 71 photos="$source/DCIM" 72 photodata="$source/PhotoData/Mutations/DCIM" 73 74 if [ ! -d "$source" ] || [ ! -d "$photos" ] || [ ! -d "$photodata" ]; then 75 echo "Source directory does not exist, exiting." 76 elif [ ! -d "$dest" ]; then 77 echo "Destination directory does not exist, exiting." 78 elif [ ! -x "$(command -v rsync)" ]; then 79 echo "This script requires rsync" 80 else 81 # First, sync the photo originals 82 echo "Syncing photos..." 83 84 # loop through all the ###APPLE directories 85 for appledir1 in "$photos"/*; do 86 # make sure it is a directory, not some random file 87 if [ -d "$appledir1" ]; then 88 appledirname="$( echo "$appledir1" | grep -o "........$")" 89 # Is the current directory one we want to process? 90 if echo "${processdirs[@]}" | grep -q -w "$appledirname"; then 91 # back up everything we find here 92 rsync -ah --info=progress2 "$photos"/"$appledirname"/ "$dest" 93 else 94 echo "Skipping photos in $appledirname" 95 fi 96 else 97 echo "WARNING Skipping invalid directory: $appledir1" 98 fi 99 done 100 echo "Done." 101 102 103 # The photo originals are synced, now sync the edits 104 echo "Syncing photo data..." 105 106 # loop through all the ###APPLE directories 107 for appledir2 in "$photodata"/*; do 108 # make sure it is a directory, not some random file 109 if [ -d "$appledir2" ]; then 110 appledirname="$( echo "$appledir2" | grep -o "........$")" 111 # Is the current directory one we want to process? 112 if echo "${processdirs[@]}" | grep -q -w "$appledirname"; then 113 # loop through all the IMG_#### directories 114 for imgdir in "$photodata"/"$appledirname"/*; do 115 if [ -d "$imgdir" ]; then 116 iname="$(echo "$imgdir" | grep -o "........$")" 117 118 if [ -d "$imgdir/Adjustments" ]; then 119 adjustsdir="$imgdir/Adjustments" 120 121 # Adjustments.plist files get renamed and saved as *.AAE 122 if [ -f "$adjustsdir"/Adjustments.plist ]; then 123 rsync -a --no-relative --no-implied-dirs "$adjustsdir"/Adjustments.plist "$dest"/"$iname".AAE 124 else 125 echo "No Adjustments.plist found for $iname, skipping." 126 fi 127 128 # Save the edited image alongside the original as *e.jpg 129 if [ -f "$adjustsdir"/FullSizeRender.jpg ]; then 130 rsync -a --no-relative --no-implied-dirs "$adjustsdir"/FullSizeRender.jpg "$dest"/"$iname"e.jpg 131 # NOTE there may be a lower resolution IMG_####.jpg here 132 # Not sure why. Might be a lower quality version if the full 133 # quality version is stored only on iCloud? 134 # Obviously the full quality version must be on the phone for backups 135 136 # Slowmos and timelapses won't have a FullSizeRender.jpg, but they will 137 # have thumbnail screencaps already named IMG_####.jpg. Back these up too 138 elif [ -f "$adjustsdir"/"$iname".jpg ]; then 139 rsync -a --no-relative --no-implied-dirs "$adjustsdir"/"$iname".jpg "$dest"/"$iname".jpg 140 141 else 142 echo "No jpg image found for $iname, skipping." 143 fi 144 else 145 echo "No Adjustments directory found for $iname, skipping." 146 fi 147 else 148 echo "WARNING Skipping invalid directory: $imgdir" 149 fi 150 done 151 else 152 echo "Skipping photos in $appledirname" 153 fi 154 else 155 echo "WARNING Skipping invalid directory: $appledir2" 156 fi 157 done 158 echo "Done." 159 echo "Photo backup complete." 160 fi