#!/bin/bash
# iterates on files in current directory
# takes the first audio file found, unless one is specified and stores artist/album metadata
# renames all other audio files in directory sharing the same data based on track# metadata

# search the document for instances of "#echo" 
# those are all debug messages

echo ""
echo "Prefix Songs By Track v1.0"
echo "--------------------------------"
echo "AUTHOR : Packrat"
echo "COMPANY: GMR Toolz & Software"
echo "LICENSE: UNLICENSED"
echo "" 
echo '+----------------------------------+
|        ###   #    #  ####        |
|       #   #  ##  ##  #   #       |
|       #      # ## #  ####        |
|       #  ##  #    #  # #         |
|       #   #  #    #  #  #        |
|        ####  #    #  #   #       |
+----------------------------------+'
echo ""
echo "in using this script, you're waiving me, packrat, of any liability for damages done to your computer"
echo "" 
echo 'Continue?'
read -p 'y/n : '



if [ $REPLY != "y" ]; then
  echo "did not receive 'y', exiting.."
  exit
fi

declare -A TRACKS
ALBUM=""
ARTIST=""
let MAX_TRACK=0 # stores the biggest track number found 
let GREATEST_TEN=10000  # edit this value if your album has 10,001+ tracks

sample_file() {
	if [ $# -gt 0 ]; then
		TRACK="$(ffmpeg -i "$1" 2>&1>/dev/null | grep -iwe 'ALBUM *:' -iwe 'ARTIST *:')"
		ALBUM=$(echo "$TRACK" | grep -iw "ALBUM" | sed -E 's/^[^:]*://')
		ARTIST=$(echo "$TRACK" | grep -iw "ARTIST" | sed -E 's/^[^:]*://')
	fi
}

if [ "$1" ]; then
  file "$1" | grep -i "audio" > /dev/null
  if [ $? == 0 ]; then
    sample_file "$1"
  else
    echo "sample file: $1: is not an audio file"
    echo "giving up.."
    exit
  fi

else
  for FILE in *; do
    file "$FILE" | grep -i "audio" > /dev/null
    if [ $? == 0 ]; then
      echo "sampling metadata from $FILE"
      sample_file "$FILE"
      break
    fi
  done
fi

echo "ARTIST: $ARTIST"
echo "ALBUM : $ALBUM"

for FILE in *; do
  file "$FILE" | grep audio -i > /dev/null
  if [ $? -gt 0 ]; then
    #echo "$FILE is not an audio file. skipping.."
    continue
  fi
  
  TRACKDATAS="$(ffmpeg -i "$FILE" 2>&1>/dev/null | grep -iwe 'TRACK *:' -iwe 'ALBUM *:' -iwe 'ARTIST *:')"
  #echo $TRACKDATAS
  if [ "$(echo "$TRACKDATAS" | grep -iw "ARTIST" | sed -E 's/^[^:]*://')" != "$ARTIST" ]; then
    #echo "$FILE: Artist doesn't match the sample file..giving up"
    continue
  fi
  if [ "$(echo "$TRACKDATAS" | grep -iw "ALBUM" | sed -E 's/^[^:]*://')" != "$ALBUM" ]; then
    #echo "$FILE: Album doesn't match the sample file..giving up"
    continue
  fi
  # check that grep found an instance of "track". returns non-zero exit if it did not
  if [ $? -gt 0 ]; then
    continue
  fi
  # remove whitespace, ensure its interpreted as a base10 integer
  let TRACKI=10#$(echo "$TRACKDATAS" | grep -iw "track" |  sed -E 's/^[^:]*://' | sed -E 's/\ //g')
  if [ $TRACKI -gt $MAX_TRACK ]; then
    let MAX_TRACK=$TRACKI
  fi
  TRACKS["$FILE"]=$TRACKI
done  

# count number of zeros to pad filenames with
for file in ${!TRACKS[@]}; do
  while true; do
    let A=$MAX_TRACK/$GREATEST_TEN
    if [ $A -ge 1 ]; then
      break
    fi
    let GREATEST_TEN=$GREATEST_TEN/10
    if [ $GREATEST_TEN -le 1 ]; then
      break
    fi
  done
done
declare -a NEW_TRACKS # hold the new tracks in a new array ordered from lowest to highest
# rename the files
for FILENAME in "${!TRACKS[@]}"; do
  #echo "$FILENAME"
  TRACKPREFIX=${TRACKS["$FILENAME"]}
  INDEX=$TRACKPREFIX
  I=0
  while true; do
    let B=10**$I
    let A=$TRACKPREFIX*$B
    let A=$A/$GREATEST_TEN
    if [ $A -lt 1 ]; then
      let I=$I+1
      continue
    fi
    break
  done
  for ((x=0; x < $I; x++)); do
    TRACKPREFIX="0$TRACKPREFIX"
  done
  NEW_TRACKS[$INDEX]="$TRACKPREFIX.$FILENAME"
done
# iterate the files to verify nothing's getting overwritten
for FILE in *; do
  for NEW_TRACK in "${NEW_TRACKS[@]}"; do
    if [ "$FILE" == "$NEW_TRACK" ]; then
      echo "ERROR: $FILE is identical to an existing file"
      echo "this script can't handle that scenario"
      echo "giving up..."
      exit
    fi
  done
done
echo ""
for NEW_TRACK_NAME in "${NEW_TRACKS[@]}"; do
  echo "$NEW_TRACK_NAME"
done
echo "Commit?"
read -p "y/n : "
if [ "$REPLY" != 'y' ]; then
  echo "did not receive 'y', giving up.."
  exit
fi
# execute the cp operations
# i know having filenames as the key in one array, yet track numbers as the key in the
# other is confusing..but it's written and it works. sorry :(
for INDEX in "${!NEW_TRACKS[@]}"; do
  for FILENAME in "${!TRACKS[@]}"; do
    if [ ${TRACKS[$FILENAME]} -eq $INDEX ]; then
      cp "$FILENAME" "${NEW_TRACKS[$INDEX]}"
      echo "$FILENAME -> ${NEW_TRACKS[$INDEX]}"
    fi
  done
done
