#!/usr/bin/env bash red="\033[1;31m" greenbold="\033[1;32m" green="\033[0;32m" yellow="\033[0;33m" bold="\033[1m" #bold_under="\033[1;4m" underline="\033[4m" reset="\033[0m" # Tags automatically added # You can add tags to this 4 arrays wild=("wildlife" "wildlifephoto" "wildlifephotographer") nat=("naturelovers" "natureshot" "naturephotography") reg=("Bourgogne" "Burgundy" "Bourgogne Franche-Comté" "Côte d'or") #others=("lanscape" "animal") others=() # Display Instagram AND/OR Flickr tags insta=true flickr=true opt_others=false opt_lens=false opt_model=false opt_region=false opt_nature=false opt_wildlife=false opt_all=true long_path=`pwd`"/"`basename "$0"` # /Users/bruno/Documents/Scripts/kymsu2/keywords2insta.sh #long_path=$(realpath "$0") # vide echo "long: $long_path" dir=$(dirname "$0") #dir="$0" echo "dir: $dir" trim () { read -rd '' $1 <<<"${!1}" } alpha_name= alpha () { array=() #declare -A ilce=( ['ILCE-7M3']="Alpha 7 III" ['ILCE-7M4']="α7 IV" ['ILCE-7MRM5']="α7R V" ['ILCE-7SM3']="Alpha 7S III" ['ILCE-7RM4']="α7R IV" ['ILCE-7RM3']="α7R III" ['ILCE-7C']="Alpha 7C" ) declare -A ilce if [ -f $dir/sony.csv ]; then #echo "Loading Sony APNs..." while IFS=';' read -ra array; do key="${array[0]}" value="${array[1]}" ilce["$key"]="$value" done < $dir/sony.csv fi for val in "${!ilce[@]}" do [[ ${val} == "$model" ]] && alpha_name="${ilce[$val]}" done } showHelp() { echo -e "${greenbold}keywords2insta${reset} v1.1" echo -e "Bruno " echo -e "Read exif and keywords from an image file, and copy them to the clipboard, " echo -e " ready for Instagram and Flickr." echo echo -e "${yellow}USAGE:${reset}" echo -e "${green}keyword2insta [-Options...] -f ${reset}" echo -e "If no option is chosen, all tags are added (default)." echo -e "Keywords taken from exifs are automatically added." echo -e "You can add keywords permanently by adding them to the ${underline}others array${reset} at the start of the script. (See others=())" echo -e "The images files are not modified." echo echo -e "${yellow}OPTIONS:${reset}" echo -e " ${green}-f${reset}, ${green}--file ${reset} Image file" echo -e " ${green}-l${reset}, ${green}--lens${reset} Add lens exif" echo -e " ${green}-m${reset}, ${green}--model${reset} Add APN model exif" echo -e " ${green}-n${reset}, ${green}--nature${reset} Add nature related keywords" echo -e " ${green}-r${reset}, ${green}--region${reset} Add region related keywords" echo -e " ${green}-t${reset} ${reset} Add some additionnals keywords" echo -e " ${green}-w${reset}, ${green}--wildlife${reset} Add wildlife related keywords" echo -e " ${green}-h${reset}, ${green}--help${reset} Display this help" echo echo -e "${yellow}REQUIEREMENTS:${reset}" echo -e " -${underline}exiftool${reset} for extract exifs ${bold}(requis)${reset}" echo -e " brew install exiftool" echo -e " -${underline}iconv${reset} for suppress accent (optional" echo -e " brew install iconv" echo -e " -${underline}gawk${reset} for suppress doubles (optional)" echo -e " brew install gawk" echo echo -e "${yellow}EXAMPLES:${reset}" echo -e " keyword2insta -f image.jpg" echo -e " keyword2insta -lm -f image.jpg" echo -e " keyword2insta --lens --model --file image.jpg" echo -e " keyword2insta -lm -t deer mammal animal -f deer.jpg" echo echo -e "${yellow}EXIT CODES:${reset}" echo -e " 0: Success !" echo -e " 1: Exiftool could not be found." echo -e " 2: No image file." echo -e " 3: Unknown long option." echo -e " 4: Unknown short option." echo -e " 5: No Keywords found in image file." } # https://stackoverflow.com/questions/402377/using-getopts-to-process-long-and-short-command-line-options # le 1er : de $optspec supprime le message d'erreur unset -v tags #OPTIND=1 optspec=":wnrf:t:mlh-:" while getopts "$optspec" opt do case $opt in -) case "${OPTARG}" in help) showHelp; exit;; wildlife) opt_wildlife=true;; nature) opt_nature=true;; region) opt_region=true;; file) file="${!OPTIND}"; OPTIND=$(( OPTIND + 1 )) ;; file=*) file=${OPTARG#*=} #opt=${OPTARG%=$file} opt="$(printf "%s\n" "${OPTARG}" | cut -d'=' -f1 )" ; file="$(printf "%s\n" "${OPTARG}" | cut -d'=' -f2-)" ;; model) opt_model=true;; lens) opt_lens=true;; *) if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" = ":" ]; then echo "Unknown option --${OPTARG}" >&2 fi exit 3 ;; esac;; w) opt_wildlife=true;; n) opt_nature=true;; r) opt_region=true;; f) file="${OPTARG}";; t) tags=("$OPTARG") until [[ $(eval "echo \${$OPTIND}") =~ ^-.* ]] || [ -z $(eval "echo \${$OPTIND}") ]; do tags+=($(eval "echo \${$OPTIND}")) OPTIND=$((OPTIND + 1)) done ;; m) opt_model=true;; l) opt_lens=true;; h) showHelp exit 0 ;; *) if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then echo "Non-option argument: '-${OPTARG}'" >&2 fi exit 4 ;; esac done #shift $((OPTIND-1)) if [ $opt_lens = true ] || [ $opt_model = true ] || [ $opt_region = true ] || [ $opt_nature = true ] || [ $opt_wildlife = true ]; then opt_all=false fi if [ ${#others[@]} -gt 0 ] || [ ${#tags[@]} -gt 0 ]; then opt_others=true fi t=$(echo "${tags[@]}" | sed -r 's/[^ ]+/,&/g') if ! command -v exiftool &> /dev/null; then echo -e "${bold}exiftool${reset} could not be found !\n" echo -e "You should install ${bold}exiftool${reset}:\n" echo -e " - brew install exiftool" echo -e "" exit 1 fi [ ! -f "$file" ] && echo -e "${bold}${red}No input file !${reset}" && exit 2 # dico français / anglais fr=() en=() array2=() declare -A dico if [ -f $dir/keywords.csv ]; then echo "Loading keyword dictionary..." while IFS=';' read -ra array2; do fr+=("${array2[0]}") en+=("${array2[1]}") done < $dir/keywords.csv j=0 for i in "${fr[@]}" do x="${en[$j]}" dico+=( ["$i"]="$x" ) ((j=j+1)) done fi echo -e "\n${greenbold}keywords2insta${reset} v2.0" echo -e "\n${bold}Reading $file exif...${reset}" #exif=$(exiftool -Canon -s -Keywords "$file") # The exiftool application exits with a status of 0 on success, or 1 if an # error occurred, or 2 if all files failed the -if condition (for any of # the commands if -execute was used). #exif=$(exiftool -Canon -s -Keywords -j "$file") exif=$(exiftool -j "$file") # The exiftool application exits with a status of 0 on success, or 1 if an # error occurred, or 2 if all files failed the -if condition (for any of # the commands if -execute was used). # exif #echo "$exif" #if (jq -e '.[] | has("Make")' <<< "$exif"); then # make=$(echo "$exif" | jq -j '.[] | .Make') #else # make="z" #fi #make=$(echo "$exif" | jq -e '.[] | has("Make") | .Make') make=$(echo "$exif" | jq -j '.[] | .Make | select( . != null )') model=$(echo "$exif" | jq -j '.[] | .Model | select( . != null )') date_original=$(echo "$exif" | jq -j '.[] | .DateTimeOriginal | select( . != null )') speed=$(echo "$exif" | jq -j '.[] | .ShutterSpeed | select( . != null )') aperture=$(echo "$exif" | jq -j '.[] | .Aperture | select( . != null )') iso=$(echo "$exif" | jq -j '.[] | .ISO | select( . != null )') lens=$(echo "$exif" | jq -j '.[] | .Lens | select( . != null )') lensID=$(echo "$exif" | jq -j '.[] | .LensID | select( . != null )') lensModel=$(echo "$exif" | jq -j '.[] | .LensModel | select( . != null )') focal=$(echo "$exif" | jq -j '.[] | .FocalLength | select( . != null )') echo if [[ -n $iso ]] && [[ -n $speed ]] && [[ -n $aperture ]]; then printf " %-10s %-35s \n" "Speed:" "${speed}" printf " %-10s %-35s \n" "Aperture:" "f/${aperture}" printf " %-10s %-35s \n" "ISO:" "${iso}" printf " %-10s %-35s \n" "Date:" "${date_original}" printf " %-10s %-35s \n" "Maker:" "${make}" [[ "$make" =~ ^SONY ]] && alpha printf " %-10s %-35s \n" "APN:" "$alpha_name (${model})" printf " %-10s %-35s \n" "Focal:" "${focal}" if [[ -n $lensID ]]; then printf " %-10s %-35s \n" "LensID:" "${lensID}" l="$lensID" elif [[ -n $lensModel ]]; then printf " %-10s %-35s \n" "LensModel:" "${lensModel}" l="$lensModel" else printf " %-10s %-35s \n" "Lens:" "${lens}" l="$lens" fi echo fi # keywords k=$(echo "$exif" | jq --compact-output --raw-output '.[] | .Keywords[]?' | tr "\n" "," | sed 's/\,$//') #k=$(echo "$exif" | sed -n '/^Keywords/p' | awk -F":" '{print $2}' | sed 's/^ *//g') if [ -z "$k" ]; then echo -e "\n${bold}${red}No Keywords found !${reset}" echo "Quit." #exit 5 fi IFS="," read -a key <<< "$k" #echo "key:${key[@]}_" #echo "dico:${dico[@]}_" for i in "${key[@]}" do #echo "@$i@" # @ bouton d'or@ # xargs: unterminated quote #ii=$(echo "$i" | xargs -0) # trim $i #ii=$(echo "$i" | sed 's/ *$//g') ii="$i" trim ii #trim i #echo "i:$i" #echo "ii:$ii" if [[ ! "$ii" =~ ^_ ]]; then #echo "ii: $ii" #echo ${dico["$ii"]} if [[ ${dico["$ii"]} ]] ; then k_en=${dico["$ii"]} else k_en="" fi k_fr="$ii" #echo "k_fr:$k_fr" #echo "k_en:$k_en" if [ -n "$k_en" ]; then [[ "$k_fr" = *" "* ]] && keyword_flickr+="\"${k_fr}\" " || keyword_flickr+="${k_fr} " [[ "$k_en" = *" "* ]] && keyword_flickr+="\"${k_en}\" " || keyword_flickr+="${k_en} " keyword_insta+="#${k_fr// /} #${k_en// /} " else [[ "$k_fr" = *" "* ]] && keyword_flickr+="\"${k_fr}\" " || keyword_flickr+="${k_fr} " keyword_insta+="#${k_fr// /} " fi #echo "keyword_insta:$keyword_insta" #echo "keyword_flickr:$keyword_flickr" fi done # model # Canon EOS R6 Canon EOS 5D Mark III Canon EOS-1D Mark IV Canon EOS 20D #m=$(echo "$exif" | sed -n '/^Model/p' | awk -F":" '{print $2}' | xargs) #mod=("${m}") # Canon EOS R6 # "Make": "OM Digital Solutions", # "Model": "OM-5", "OM-1" # "Make": "SONY", # "Model": "ILCE-7M3", "ILCE-7M4" # "Make": "FUJIFILM", # "Model": "X-T5", # "Make": "Panasonic", # "Model": "DC-S5", # "Make": "LEICA CAMERA AG", # "Model": "LEICA Q3", "LEICA SL2-S" # "Make": "NIKON CORPORATION", # "Model": "NIKON D850", # "Make": "NIKON CORPORATION", # "Model": "NIKON Z 9", # "Make": "Canon", # "Model": "Canon EOS R7", #mod=("${model}") #m=("${model}") #echo "mod:${mod[@]}_" #echo "m:${m[@]}_" if [[ "$make" =~ ^Panasonic ]] || [[ "$make" =~ ^SONY ]] || [[ "$make" =~ ^FUJI ]]; then mod=("${make} ${model}") mod+=("${make}") mod+=("${model}") mod+=("${make,,}photography") elif [[ "$make" =~ ^"OM Digital Solutions" ]]; then mod=("${make} ${model}") # OM Digital Solutions OM-5 mod+=("Olympus") # Olympus mod+=("${model}") # OM-5 elif [[ "$model" =~ ^NIKON ]] || [[ "$model" =~ ^LEICA ]]; then mod=("${make}") z=$(echo "${make,,}" | awk '{print $1}') ## nikon y=$(echo "${make}" | awk '{print $1}') ## NIKON mod+=("${z}photography") # nikonphotography leicaphotography mod+=("${y}") # NIKON LEICA mod+=("${model}") # NIKON Z 9 LEICA Q3 # awk -F"|" '{$1=$2=$3=""; print $0}' PURCHASE_testing.csv > testing.csv w=$(echo "${model}" | awk '{$1=""; print $0}' | xargs) mod+=("${w}") elif [[ "$model" =~ ^Canon ]]; then mod+=("Canon") mod+=("${make,}photography") [[ "$model" = *EOS* ]] || mod+=("EOS") # EOS z=$(echo "$model" | sed 's/Canon\ //g' | xargs) y=$(echo "$model" | sed 's/EOS//g' | sed 's/[ ][ ]*/ /g' | xargs) mod+=("${z}") # EOS R6 mod+=("${y}") # Canon R6 fi #echo "mod:${mod[@]}_" for i in "${mod[@]}" do #model+="${i} " if [[ "$i" = *" "* ]]; then model_flickr+="\"${i}\" " else model_flickr+="${i} " fi model_insta+="#${i// /} " # supprime tous les espaces et ajoute le # done #echo "model_flickr: $model_flickr" #echo "model_insta: $model_insta" #lens # "LensModel": "E 28-200mm F2.8-5.6 A071", # "Lens": "E 28-200mm F2.8-5.6 A071", # "LensID": "Tamron 28-200mm F2.8-5.6 Di III RXD", # "LensModel": "FE 35mm F2.8 ZA", # "Lens": "FE 35mm F2.8 ZA", # "LensID": "FE 35mm F2.8 ZA" # LensID": "OLYMPUS M.12-45mm F4.0" # "LensModel": "OLYMPUS M.12-45mm F4.0", # "Lens": "OLYMPUS M.12-45mm F4.0", # "LensModel": "OLYMPUS M.300mm F4.0", # "Lens": "OLYMPUS M.300mm F4.0", # "LensID": "OLYMPUS M.300mm F4.0" # "Lens": "OLYMPUS M.300mm F4.0", "Lens": "OLYMPUS M.12-45mm F4.0", # "LensModel": "OLYMPUS M.300mm F4.0", "LensModel": "OLYMPUS M.12-45mm F4.0", # Leica no Lens no LensID # "LensModel": "SUMMILUX 1:1.7/28 ASPH.", "Leica APO-Summicron-SL 35mm f/2 ASPH", # "LensModel": "Leica APO-Summicron-SL 35mm f/2 ASPH", # "Lens": "Leica APO-Summicron-SL 35mm f/2 ASPH", # "LensID": "Leica APO-Summicron-SL 35mm f/2 ASPH" # "Lens": "Fujifilm Fujinon XF18mmF1.4 R LM WR", # "LensModel": "Fujifilm Fujinon XF18mmF1.4 R LM WR", # LensID": "LUMIX S 20-60mm F3.5-5.6" # "Lens": "LUMIX S 20-60/F3.5-5.6", # "LensModel": "LUMIX S 20-60/F3.5-5.6", # "LensID": "Fujifilm Fujinon XF18mm F1.4 R LM WR" # "Lens": "400mm f/2.8", # "LensID": "AF-S VR Nikkor 400mm f/2.8G ED", # Nikon si LensModel vide => LensID # "LensModel": "VR 300mm f/2.8G", # "Lens": "300.0 mm f/2.8", # "LensID": "VR 300mm f/2.8G" # "LensModel": "EF600mm f/4L IS III USM", # "LensID": "Canon EF 600mm f/4L IS III USM" # "Lens": "EF600mm f/4L IS III USM", # 1 LensID puis 2 LendModel lens_flickr="\"${l}\" " lens_insta="$(echo "$l" | sed 's/ //g' | sed -r 's/[^ ]+/#&/g') " #echo "lens_flickr: $lens_flickr" #echo "lens_insta: $lens_insta" for i in "${wild[@]}" do if [[ "$i" = *" "* ]]; then wildlife_flickr+="\"${i}\" " else wildlife_flickr+="${i} " fi #wildlife_insta+="#"$(echo "${i}" | iconv -f UTF-8-MAC -t ascii//translit | sed 's/[^a-zA-Z 0-9]//g' | sed 's/ //g')" " wildlife_insta+="#$(echo "${i}" | iconv -f UTF-8-MAC -t ascii//translit | sed 's/[^a-zA-Z 0-9]//g' | sed 's/ //g') " done for i in "${nat[@]}" do if [[ "$i" = *" "* ]]; then nature_flickr+="\"${i}\" " else nature_flickr+="${i} " fi nature_insta+="#$(echo "${i}" | iconv -f UTF-8-MAC -t ascii//translit | sed 's/[^a-zA-Z 0-9]//g' | sed 's/ //g') " done for i in "${reg[@]}" do if [[ "$i" = *" "* ]]; then region_flickr+="\"${i}\" " else region_flickr+="${i} " fi region_insta+="#$(echo "${i}" | iconv -f UTF-8-MAC -t ascii//translit | sed 's/[^a-zA-Z 0-9]//g' | sed 's/ //g') " done : <<'END_COMMENT' echo "Model flickr: $model_flickr" echo "Model insta: $model_insta" echo echo "Keywords flickr: $keyword_flickr" echo "Keywords insta: $keyword_insta" echo echo "Lens flick: $lens_flickr" echo "Lens_insta: $lens_insta" echo echo "Wildlife flickr: $wildlife_flickr" echo "Wildlife insta: $wildlife_insta" echo echo "Nature flickr: $nature_flickr" echo "Nature insta: $nature_insta" echo echo "Region flickr: $region_flickr" echo "Region insta: $region_insta" echo echo "tags: ${tags[@]}" echo "others: ${others[@]}" echo "file: $file" echo "wildlife: $opt_wildlife" echo "nature: $opt_nature" echo "region: $opt_region" echo "model: $opt_model" echo "lens: $opt_lens" echo "all: $opt_all" echo END_COMMENT if [ $opt_all = false ]; then if [ $opt_wildlife = false ]; then wildlife_flickr="" wildlife_insta="" fi if [ $opt_nature = false ]; then nature_flickr="" nature_insta="" fi if [ $opt_region = false ]; then region_flickr="" region_insta="" fi if [ $opt_lens = false ]; then lens_flickr="" lens_insta="" fi if [ $opt_model = false ]; then model_flickr="" model_insta="" fi fi keywords_flickr="$keyword_flickr$model_flickr$lens_flickr$wildlife_flickr$nature_flickr$region_flickr" keywords_insta=$(echo "$keyword_insta$model_insta$lens_insta$wildlife_insta$nature_insta$region_insta" | awk '{print tolower($0)}') if [ $opt_others = true ]; then # insert tags added with option -t to others's tag array others+=($(echo "$t" | tr ',' ' ')) for i in "${others[@]}" do if [[ ${dico["$i"]} ]] ; then o_en=${dico["$i"]} else o_en="" fi if [ -n "$o_en" ]; then [[ "$i" = *" "* ]] && others_flickr+="\"${i}\" " || others_flickr+="${i} " [[ "$o_en" = *" "* ]] && others_flickr+="\"${o_en}\" " || others_flickr+="${o_en} " others_insta+="#${i// /} #${o_en// /} " else [[ "$i" = *" "* ]] && others_flickr+="\"${i}\" " || others_flickr+="${i} " others_insta+="#${i// /} " fi done keywords_flickr+="$others_flickr" keywords_insta+="$others_insta" fi # suppress accent (bug in macos) => add sed => suppress punctuation too # https://stackoverflow.com/questions/806199/how-to-fix-weird-issue-with-iconv-on-mac-os-x if ! command -v iconv &> /dev/null; then echo -e "\n${bold}iconv${reset} could not be found !\n" echo -e "It's required for suppress accents." echo -e "You should install ${bold}icon${reset}:" echo -e " - brew install iconv" echo -e "" else keywords_insta=$(echo "$keywords_insta" | iconv -f UTF-8-MAC -t ascii//translit | sed 's/[^a-zA-Z 0-9 \#]//g') fi # suppress duplicates (gawk) if ! command -v gawk &> /dev/null; then echo -e "\n${bold}gawk${reset} could not be found !\n" echo -e "It's required for suppress duplicates." echo -e "You should install ${bold}gawk${reset}:" echo -e " - brew install gawk" echo -e "" else #keywords_flickr=$(echo "$keywords_flickr" | gawk -v RS="[ \n]" -v ORS=" " '!($0 in a){print;a[$0]}') keywords_insta=$(echo "$keywords_insta" | gawk -v RS="[ \n]" -v ORS=" " '!($0 in a){print;a[$0]}') fi # copy tags to clipboard if [ "$insta" = true ]; then if [[ "$OSTYPE" == "linux-gnu" ]] && [ -x "$(command -v xsel)" ]; then xsel -b <<< "$keywords_insta" elif [[ "$OSTYPE" == "darwin"* ]] && [ -x "$(command -v pbcopy)" ]; then pbcopy <<< "$keywords_insta" fi echo -e "\n${bold}The Instagram's tags are available in your clipboard !${reset}" echo "$keywords_insta" echo -e "\nPress to get the Flickr' tags..." read -p "" fi if [ "$flickr" = true ]; then if [[ "$OSTYPE" == "linux-gnu" ]] && [ -x "$(command -v xsel)" ]; then xsel -b <<< "$keywords_flickr" elif [[ "$OSTYPE" == "darwin"* ]] && [ -x "$(command -v pbcopy)" ]; then pbcopy <<< "$keywords_flickr" fi [ "$insta" = true ] && echo -e "\n${bold}Here the Flickr's tags too !${reset}" || echo -e "\n${bold}The Flickr's tags are available in your clipboard !${reset}" echo "$keywords_flickr" fi