#!/bin/bash

######## Functions ########

function usage_msg {
xmessage -name 'Usage' -nearmouse -buttons OK -default OK -timeout 5 -file - <<- -EOF-
Drag and drop video files
on the icon you clicked
to extract audio.
-EOF-
exit
}

function check_file {
if [ ! -f "$source_file" ]; then
  xmessage -name 'No regular file' -buttons OK -default OK -file - <<- -EOF-
$source_file
is no regular file.
-EOF-
  return 1
fi
audiocodecs_streamnrs=$(ffmpeg -i "$source_file" 2<&1 | sed -ne 's/.*Stream *\(#[0-9\.]*\).*Audio: *\([a-z0-9_]*\).*/\2\1/p')
audio_count=0
for audiocodec_streamnr in $audiocodecs_streamnrs; do
  ((audio_count++))
done
if [ $audio_count -eq 0 ]; then
  xmessage -name 'No audio' -buttons OK -default OK -file - <<- -EOF-
$source_file
seems to contain no ffmpeg-readable audio stream.
-EOF-
  return 1
fi
}

function new_codec {
if echo "$decodable_codecs" | grep -q "^$audio_codec$"; then
  target_suffix=$(xmessage -name 'No direct copy' -buttons flac,wav,Cancel -default Cancel -print "$source_file
contains audio codec $audio_codec in stream #$stream_nr.
Direct copying of $audio_codec is not implemented.

Convert audio to:")
echo $target_suffix
  case $target_suffix in
    flac) target_codec=flac; audio_codec=flac;;
    wav) target_codec=pcm_s16le; audio_codec=pcm_s16le;;
    *) return 1;;
  esac
else
  xmessage -name 'No decoder' -buttons OK -default OK "Can't decode $audio_codec audio from stream #$stream_nr in
$source_file"
  return 1
fi
}

function get_target_suffix {
case $audio_codec in
  aac|libfaad|mpeg4aac|ac3|alac) target_codec=copy; target_suffix="m4a";;
  flac) target_codec=copy; target_suffix="flac";;
  mp2) target_codec=copy; target_suffix="mp2";;
  mp3) target_codec=copy; target_suffix="mp3";;
  pcm_s*le|pcm_f*le) target_codec=copy; target_suffix="wav";;
  pcm_s*be) target_codec=copy; target_suffix="aif";;
  vorbis) target_codec=copy; target_suffix="ogg";;
  wma*) target_codec=copy; target_suffix="wma";;
  *) new_codec || return 1;;
esac
}

function get_target_dir {
target_dir=$(dirname "$source_file")
if [ -w "$target_dir" ]; then
  return 0
fi
for ((i=0;i<${#change_dir[*]};i+=2)); do
  if [ "${change_dir[$i]}" = "$target_dir" ]; then
    target_dir="${change_dir[$(( $i + 1))]}"
    return 0
  fi
done
if [ -d "$HOME/Desktop/extracted-audio" -a -w "$HOME/Desktop/extracted-audio" ]; then
  local new_target_dir="$HOME/Desktop/extracted-audio"
elif [ -d "$HOME/extracted-audio" -a -w "$HOME/extracted-audio" ]; then
  local new_target_dir="$HOME/extracted-audio"
elif [ -d "$HOME/Desktop" -a -w "$HOME/Desktop" -a ! -e "$HOME/Desktop/extracted-audio" ]; then
  local new_target_dir="$HOME/Desktop/extracted-audio"
elif [ -d "$HOME" -a -w "$HOME" -a ! -e "$HOME/extracted-audio" ]; then
  local new_target_dir="$HOME/extracted-audio"
else
  xmessage -name 'Permission error' -buttons OK -default OK -file - <<- -EOF-
No write permissions for directory
$target_dir/
Can't extract audio from
$source_file
-EOF-
  return 1
fi 
if  xmessage -name 'Target directory' -buttons OK:0,Cancel:1 -default OK -file - <<- -EOF-
Can't write extracted audio to directory
$target_dir/ !

Write extracted audio to
$new_target_dir/ ?
-EOF-
then
  change_dir[${#change_dir[*]}]="$target_dir"
  change_dir[${#change_dir[*]}]="$new_target_dir"
  target_dir="$new_target_dir"
  if [ ! -e "$target_dir" ]; then
    mkdir "$target_dir"
  fi
else
  return 1
fi
}

function get_target_name {
if [ $audio_count -gt 1 ]; then
  target_name="$target_name#$stream_nr"
fi
if [ ! -e "$target_dir/$target_name.$target_suffix" ]; then
  return 0
fi
i=1 
while [ -e "$target_dir/$target_name-$i.$target_suffix" ]; do
  ((i++))
done
if [ ! -e "$target_dir/$target_name-$i.$target_suffix" ] &&\
  xmessage -name 'File exists' -buttons OK:0,Cancel:1 -default Cancel -file - << -EOF-
$target_dir/$target_name.$target_suffix
already exists.

Extract audio from
$(dirname "$source_file")/$target_name
to 
$target_dir/$target_name-$i.$target_suffix ?
-EOF-
then
  target_name="$target_name-$i"
else
  return 1
fi
}

function get_target_file {
audio_codec=$(echo "$audiocodec_streamnr" | sed -e 's/#.*$//')
stream_nr=$(echo "$audiocodec_streamnr" | sed -e 's/^.*#//')
get_target_suffix || return 1
get_target_dir || return 1
source_basename=$(basename "$source_file")
target_name="$source_basename"
get_target_name || return 1
target_file="$target_dir/$target_name.$target_suffix"
}

function extract_audiostream {
if ffmpeg_output=$(ffmpeg -i "$source_file" -vn -map $stream_nr -acodec $target_codec "$target_file" 2>&1)
then
  audio_codec_="$audio_codec"
  while (( ${#audio_codec_} < 10 )); do
    audio_codec_="$audio_codec_ "
  done
  audio_extracted="$audio_extracted"$'\x0a'"$audio_codec_$target_file"
else
  xmessage -name 'Extraction failed' -buttons OK -default OK -file - <<- -EOF-
Could not extract audio stream #$stream_nr from
$source_file !

Command:
ffmpeg -i "$source_file" -vn -map $stream_nr -acodec $target_codec "$target_file"

Output:
$ffmpeg_output
-EOF-
  [ -e "$target_file" ] && rm "$target_file"
fi
}

function proceed_file {
extract_count=0
for audiocodec_streamnr in $audiocodecs_streamnrs; do
  get_target_file && extract_audiostream
done
}

function final_message {
if [ -n "$audio_extracted" ]; then
  xmessage -name 'Extracted audio:' -buttons OK -default OK -file - <<- -EOF-
Codec:    Audiofile:$audio_extracted
-EOF-
fi
}


##### Initialization  #####

umask 022

######## Main Script ########

if [ $# -eq 0 ]; then
  usage_msg
fi
decodable_codecs=$(ffmpeg -formats 2>&1 | sed -ne 's/ *D[E ]A *\([a-z0-9_]*\).*/\1/p')
audio_extracted=""
change_dir=()
while [ -n "$1" ]; do
  source_file="$1"
  check_file && proceed_file
  shift
done
final_message
