#!/bin/zsh

# zomg: ZOMG
#   Copyright (C) 2005-2013  Clint Adams

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# alonglong with this program.  If not, see <http://www.gnu.org/licenses/>.

ZOMG_VERSION="0.6"
zomgconfdir=~/.zomg
zomgdatadir=~/.zomg

typeset -A sessionid submit npurl submiturl

cat <<EOF;
zomg version ${ZOMG_VERSION}, Copyright (C) 2005-2013  Clint Adams
zomg comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions.
EOF

emulate -R zsh

zmodload -i zsh/zselect || exit 244
zmodload -i zsh/datetime || exit 245
zmodload -i zsh/parameter || exit 246
autoload -Uz is-at-least
if ! is-at-least 4.3.4; then
   print "Your copy of zsh is ancient.  Upgrade."
   exit 1
fi
(( $#commands[wget] )) || { print "wget is now required for both radio and submission" ; exit 1; }

setopt extendedglob nonomatch nonotify

TCP_SILENT=yes
TCP_PROMPT=
ctrlc=0

skippy()
{
  (( ctrlc++ ))
  if (( ctrlc > 1 ))
  then
    exit 0
  fi
}

zomg_scriptname=$0

#include screenoutput functions
source /usr/share/zomg/screenoutput

#include audioscrobbler functions
source /usr/share/zomg/audioscrobbler

#include caching functions
source /usr/share/zomg/caching

#include urlparse functions
source /usr/share/zomg/urlparse

#include parsemedium functions
source /usr/share/zomg/parsemedium

#include shuffle functions
source /usr/share/zomg/shuffle

#include lastfmradio functions
source /usr/share/zomg/lastfmradio

if [[ ! -d $zomgconfdir ]];
then
  mkdir $zomgconfdir || exit 9
fi

if [[ ! -d $zomgdatadir ]];
then
  mkdir $zomgdatadir || exit 10
fi

truncate_log

local starttime=0 endtime=0 filetype shuffle=0 dolastfmradio=0 nonet=0 totes=0

skip=0

[[ -d /usr/lib/zomg ]] && PATH="$PATH:/usr/lib/zomg"

while getopts "nrtzh" opt; do
  case "$opt" in
    (z)
    shuffle=1
    ;;
    (r)
    dolastfmradio=1
    ;;
    (n)
    nonet=1
    ;;
    (h)
    cat <<EOF
usage: $0 [-z] [-n] musicfile1 [musicfile2] [...musicfileN]
       $0 -r [lastfm url]

  -z    shuffle tracks
  -n    do not make outgoing network connections

  -r    last.fm radio mode
EOF
    exit 0
    ;;
    (t)
    print >&2 "The -t option is obsolete."
    ;;
    (*)
    print -- "Run $0 -h for help."
    exit 99
    ;;
  esac
done

(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))

LASTFM_USER=""
LASTFM_PASSWORD=""
LIBREFM_USER=""
LIBREFM_PASSWORD=""
sitechoice=""

if [[ ! -f $zomgconfdir/conf ]];
then
  print "Do you have accounts with last.fm, libre.fm, or both?"
  print "1) last.fm"
  print "2) libre.fm"
  print "3) last.fm and libre.fm"
  while [[ $sitechoice != [123] ]]; do
    vared -p "site choice> " sitechoice
  done

conffile=(
"zomg_config_version=2"
"typeset -A handshake_host username password"
"handshake_host[lastfm]=post.audioscrobbler.com"
"handshake_host[librefm]=turtle.libre.fm"
)

  case "$sitechoice" in
    ([13])
      vared -p "last.fm username> " LASTFM_USER
      vared -p "last.fm password> " LASTFM_PASSWORD
      conffile+=(
      $(printf 'username[lastfm]="%s"' "${LASTFM_USER}")
      $(printf 'password[lastfm]="%s"' "${LASTFM_PASSWORD}")
      )
      ;|
    ([23])
      vared -p "libre.fm username> " LIBREFM_USER
      vared -p "libre.fm password> " LIBREFM_PASSWORD
      conffile+=(
      $(printf 'username[librefm]="%s"' "${LIBREFM_USER}")
      $(printf 'password[librefm]="%s"' "${LIBREFM_PASSWORD}")
      )
      ;|
    (1)
      conffile+=(
      'submission_sites=(lastfm)'
      )
      ;|
    (2)
      conffile+=(
      'submission_sites=(librefm)'
      )
      ;|
    (3)
      conffile+=(
      'submission_sites=(lastfm librefm)'
      )
      ;;
  esac

print -l $conffile >$zomgconfdir/conf

fi

[[ -r $zomgconfdir/conf ]] || exit 12

unset zomg_config_version
source $zomgconfdir/conf

if [[ $zomg_config_version -ne 2 ]];
then
  print >&2 "The config version is incorrect.  Please rename $zomgconfdir/conf"
  print >&2 "to $zomgconfdir/conf.old and invoke zomg again to create the"
  print >&2 "config in the proper format."
  exit 1
fi

if [[ -f $zomgdatadir/cache ]];
then
  if [[ -f $zomgdatadir/cache.lastfm ]];
  then
    print >&2 "You have both a $zomgdatadir/cache and a"
    print >&2 "$zomgdatadir/cache.lastfm.  Please remove one and re-invoke zomg."
    exit 1
  else
    mv -f $zomgdatadir/cache $zomgdatadir/cache.lastfm
  fi
fi

if (( nonet == 0 )); then

  for site in $submission_sites
  do

  if [[ -f $zomgdatadir/cache.$site ]];
  then
    if as_validate_handshake $site $username[$site] $password[$site]
    then
      parse_submiturl $site
      parse_np_submiturl $site
      status_msg "Flushing cache for $site..."
      audioscrobbler_flushcache $site $username[$site] $sessionid[$site] &&
      { submit[$site]=1; mv $zomgdatadir/cache.$site $zomgdatadir/cache.$site.old ; status_msg "Flushed $site" } ||
      { submit[$site]=0; status_msg "Failed"; as_invalidate_handshake $site $username[$site] }
      else
	status_msg "HANDSHAKE FAILED"
	submit[$site]=0
	as_invalidate_handshake $site $username[$site]
      fi
    else
      submit[$site]=1
      as_validate_handshake $site $username[$site] $password[$site] && parse_submiturl $site && parse_np_submiturl $site || submit[$site]=0
    fi

  done

  else
  for site in $submission_sites
  do
    print "Not handshaking."
    submit[$site]=0
  done
  fi

  if (( dolastfmradio == 1 )); then
    case "$1" in
    (lastfm://*) ;&
    (librefm://*) lastfm_radio "$@" ;;
    (*) status_msg "Bad radio station given. Try again." ; exit 1 ;;
    esac
    exit 0
  else

    trap 'skippy' INT

    [[ $# -gt 0 ]] || { print "No arguments; exiting."; exit 0 }

    for i in "$@"
    do
     [[ -d "$i" ]] && playlist+=( $i/**/*.(ogg|mp3|flac) ) || playlist+=("$i")
    done

    if (( shuffle == 1 )); then
      print Shuffling $#playlist files...
      zomg_shuffle $playlist
      set -- "$reply[@]"
    else
      set -- "$playlist[@]"
    fi

    for i in "$@"
    do
      if [[ ! -r "$i" ]]; then
	  print "Cannot read file: $i; skipping"
	  continue
      fi
      case "$i" in
	(*.ogg)
	# assume vorbis
	[[ -x =zomghelper ]] && parse_zomghelper $i || parse_ogginfo $i
	trackreply=("$reply[@]")

	if [[ -n $trackreply[1] && -n $trackreply[2] ]]; then
        for site in $submission_sites
        do
	audioscrobbler_construct_np_query $username[$site] $sessionid[$site] "$trackreply[1]" \
	"$trackreply[2]" \
	"$trackreply[3]" \
	"$trackreply[4]" \
	"$trackreply[5]" \
	"$EPOCHSECONDS" && audioscrobbler_np_submit "$site" ${(j::)reply} "$username[$site]"
        done
	fi

	starttime=$EPOCHSECONDS
	ogg123 --audio-buffer 2048 -v $i
	endtime=$EPOCHSECONDS
	;;
	(*.mp3)
	[[ -x =mutagen-inspect ]] && parse_mutagen $i || parse_eyeD3 $i
	trackreply=("$reply[@]")

	if [[ -n $trackreply[1] && -n $trackreply[2] ]]; then
        for site in $submission_sites
        do

	audioscrobbler_construct_np_query $username[$site] $sessionid[$site] "$trackreply[1]" \
	"$trackreply[2]" \
	"$trackreply[3]" \
	"$trackreply[4]" \
	"$trackreply[5]" \
	"$EPOCHSECONDS" && audioscrobbler_np_submit $site ${(j::)reply} "$username[$site]"

        done
	fi

	starttime=$EPOCHSECONDS
	mpg123 -C -v $i
	endtime=$EPOCHSECONDS
	;;
	(*.flac)
	parse_mutagenflac $i
	trackreply=("$reply[@]")

	if [[ -n $trackreply[1] && -n $trackreply[2] ]]; then
        for site in $submission_sites
        do

	audioscrobbler_construct_np_query $username[$site] $sessionid[$site] "$trackreply[1]" \
	"$trackreply[2]" \
	"$trackreply[3]" \
	"$trackreply[4]" \
	"$trackreply[5]" \
	"$EPOCHSECONDS" && audioscrobbler_np_submit $site ${(j::)reply} "$username[$site]"

        done
	fi

	starttime=$EPOCHSECONDS
	ogg123 --audio-buffer 2048 -v $i
	endtime=$EPOCHSECONDS
	;;
	(*)
	print "Unknown file extension: $i" >&2
	continue
	;;
      esac

      (( ctrlc >= 1 )) && (( ctrlc = 0 ))

      print Played for $(( endtime - starttime )) secs out of $trackreply[5] secs.
      (( endtime - starttime <= ($trackreply[5] / 2.0 ) )) &&
      (( endtime - starttime < 240 )) && skip=1

      (( $trackreply[5] < 30 )) && skip=1
      [[ -n "$trackreply[1]" && -n "$trackreply[2]" ]] || skip=1

      if [[ $skip -eq 1 ]];
      then
	status_msg "SKIPPING"
	skip=0
      else


	if [[ -n $trackreply[1] && -n $trackreply[2] ]]; then
	for site in $submission_sites
        do

	audioscrobbler_constructquery "$sessionid[$site]" "$trackreply[1]" \
	"$trackreply[2]" \
	"$trackreply[3]" \
	"$trackreply[4]" \
	"$trackreply[5]" \
	"$starttime" P || exit 2
	audioscrobbler_submit $site ${(j::)reply} "$username[$site]" || { submit[$site]=0; audioscrobbler_cache $site $reply[2] }

        done
	else
		status_mgs "Skipping submission of poorly-tagged file $i."
	fi
      fi
    done
  fi
