#!/bin/zsh

# zomg: ZOMG
#   Copyright (C) 2005, 2006, 2007, 2008, 2009  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 2 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
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

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

typeset -A sessionid submit npurl submiturl

cat <<EOF;
zomg version ${ZOMG_VERSION}, Copyright (C) 2005, 2006, 2007, 2008, 2009  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] [-t] musicfile1 [musicfile2] [...musicfileN]
       $0 -r [lastfm url]

  -z    shuffle tracks
  -n    do not make outgoing network connections
  -t    treat arguments as directories instead of files

  -r    last.fm radio mode
EOF
    exit 0
    ;;
    (t)
    totes=1
    ;;
    (*)
    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 }

    if (( totes == 1 )); then
      for i in "$@"
      do
       [[ -d "$i" ]] && playlist+=( $i/**/*.(ogg|mp3|flac) )
      done
    else
      playlist=("$@")
    fi

    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
