scripts/src/scripts/photos-metadata.sh

194 lines
7.4 KiB
Bash

#! /usr/bin/env nix-shell
#! nix-shell -i bash -p bash exiftool
# Directory to start the search
base_dir=~/Pictures/Photos/Camera
log_file="metadata_changes.log"
temp_file="metadata_changes_temp.log"
# Function to extract date and time from filename
extract_datetime_from_filename() {
filename=$(basename "$1")
datetime=""
# Patterns to match filenames with date and time
if [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2})_([0-9]{2})_([0-9]{2})_([0-9]{2}) ]]; then
datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
elif [[ "$filename" =~ ([0-9]{4})([0-9]{2})([0-9]{2})_([0-9]{2})([0-9]{2})([0-9]{2}) ]]; then
datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
elif [[ "$filename" =~ ([0-9]{8})_([0-9]{6}) ]]; then
datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} ${BASH_REMATCH[2]:0:2}:${BASH_REMATCH[2]:2:2}:${BASH_REMATCH[2]:4:2}"
elif [[ "$filename" =~ ([0-9]{8})([0-9]{6}) ]]; then
datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} ${BASH_REMATCH[2]:0:2}:${BASH_REMATCH[2]:2:2}:${BASH_REMATCH[2]:4:2}"
elif [[ "$filename" =~ ([0-9]{8}) ]]; then
datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} 00:00:00"
elif [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2})\ ([0-9]{2})_([0-9]{2})_([0-9]{2}) ]]; then
datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
elif [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2}) ]]; then
datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} 00:00:00"
fi
# Validate extracted date
if echo "$datetime" | grep -qE '^([0-9]{4}):([0-9]{2}):([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$'; then
year=$(echo "$datetime" | cut -d':' -f1)
month=$(echo "$datetime" | cut -d':' -f2)
day=$(echo "$datetime" | cut -d':' -f3 | cut -d' ' -f1)
hour=$(echo "$datetime" | cut -d' ' -f2 | cut -d':' -f1)
minute=$(echo "$datetime" | cut -d':' -f2 | cut -d':' -f2)
second=$(echo "$datetime" | cut -d':' -f2 | cut -d':' -f3)
# Remove leading zeros for validation
year=$((10#$year))
month=$((10#$month))
day=$((10#$day))
hour=$((10#$hour))
minute=$((10#$minute))
second=$((10#$second))
if ((year < 2009 || year > 2024)) || ((month < 1 || month > 12)) || ((day < 1 || day > 31)) || ((hour > 23)) || ((minute > 59)) || ((second > 59)); then
datetime=""
fi
else
datetime=""
fi
echo "$datetime"
}
# Function to log changes
log_change() {
photo="$1"
old_date="$2"
new_date="$3"
action="$4"
touch "$temp_file"
{
echo "File: $photo"
echo " Old Date: $old_date"
echo " New Date: $new_date"
if [ -n "$action" ]; then
echo " Suggested action: $action"
fi
echo ""
} >>"$temp_file"
}
# Function to handle errors and convert images to JPEG using ImageMagick
handle_conversion_error() {
photo="$1"
file_type=$(file --mime-type -b "$photo")
if [[ $file_type == image/* ]]; then
echo "Converting $photo to jpg using ImageMagick."
mogrify -format jpg "$photo"
else
echo "File is a video or unsupported type: $photo. Skipping conversion."
fi
}
# Loop through each year directory
for year_dir in "$base_dir"/*/; do
year=$(basename "$year_dir")
# Exclude VFS directory
if [ "$year" == "VFS" ]; then
continue
fi
# Loop through each month directory
for month_dir in "$year_dir"*/; do
month=$(basename "$month_dir")
# Loop through each photo in the month directory
for photo in "$month_dir"*; do
if [ -f "$photo" ]; then
# Extract the date from the photo metadata
photo_date=$(exiftool -DateTimeOriginal -d "%Y:%m:%d %H:%M:%S" "$photo" | awk -F': ' '{print $2}')
if [ -z "$photo_date" ]; then
# Scenario 2: No date metadata or invalid date
filename_datetime=$(extract_datetime_from_filename "$photo")
if [ -n "$filename_datetime" ]; then
new_date="$filename_datetime"
log_change "$photo" "No date metadata" "$new_date"
echo "Found: $photo"
echo " Extracted date from filename: $new_date"
else
new_date="$year:$month:01 00:00:00"
log_change "$photo" "No date metadata" "$new_date"
echo "Found: $photo"
echo " Defaulting to directory date: $new_date"
fi
else
photo_year=$(echo "$photo_date" | cut -d':' -f1)
photo_month=$(echo "$photo_date" | cut -d':' -f2)
if [ "$photo_year" != "$year" ] || [ "$photo_month" != "$month" ]; then
# Scenario 1: Date mismatch
filename_datetime=$(extract_datetime_from_filename "$photo")
if [ -n "$filename_datetime" ]; then
filename_year=$(echo "$filename_datetime" | cut -d':' -f1)
filename_month=$(echo "$filename_datetime" | cut -d':' -f2)
if [ "$photo_year" == "$filename_year" ] && [ "$photo_month" == "$filename_month" ]; then
echo "Mismatch found: $photo"
echo " Directory date: $year/$month"
echo " Photo date: $photo_date"
echo " Filename date matches photo date, file is in the wrong directory."
action="Move to $filename_year/$filename_month"
log_change "$photo" "$photo_date" "$filename_datetime" "$action"
else
new_date="$filename_datetime"
log_change "$photo" "$photo_date" "$new_date"
echo "Mismatch found: $photo"
echo " Directory date: $year/$month"
echo " Photo date: $photo_date"
echo " Filename date: $filename_datetime"
echo " Suggested action: Update photo metadata to match filename date."
fi
else
new_date="$year:$month:01 00:00:00"
log_change "$photo" "$photo_date" "$new_date"
echo "Mismatch found: $photo"
echo " Directory date: $year/$month"
echo " Photo date: $photo_date"
echo " No valid date found in filename. Defaulting to directory date."
fi
fi
fi
fi
done
done
# Ask for confirmation before proceeding to the next year
read -rp "Finished processing year $year. Do you want to save the changes and continue to the next year? (y/n): " response
if [[ "$response" != "y" ]]; then
echo "Stopping script."
rm -f "$temp_file"
touch "$temp_file"
exit 0
else
# Apply changes and save log
while IFS= read -r line; do
if [[ "$line" == File:* ]]; then
photo=$(echo "$line" | cut -d' ' -f2-)
elif [[ "$line" == " New Date:"* ]]; then
new_date=$(echo "$line" | cut -d' ' -f3-)
if ! exiftool -overwrite_original -DateTimeOriginal="$new_date" "$photo"; then
handle_conversion_error "$photo"
fi
elif [[ "$line" == " Suggested action: Move to"* ]]; then
target_directory=$(echo "$line" | cut -d' ' -f4-)
target_path="$base_dir/$target_directory"
echo "$target_path"
mkdir -p "$target_path" && mv "$photo" "$target_path/"
fi
done <"$temp_file"
cat "$temp_file" >>"$log_file"
rm -f "$temp_file"
touch "$temp_file"
fi
done