#!/bin/sh
# 
# $Log: mpdplaylist.in,v $
# Revision 1.21  2022-06-20 01:04:54+05:30  Cprogrammer
# use directories set in ./configure
#
# Revision 1.20  2022-05-10 21:33:16+05:30  Cprogrammer
# added --incartist, --exlartist to include, exclude artists in query
#
# Revision 1.19  2021-09-30 20:31:46+05:30  Cprogrammer
# use -noheader option to prevent .sqlitrc settings messing with results
#
# Revision 1.18  2021-04-24 11:56:20+05:30  Cprogrammer
# minor fixes for display and error messages
#
# Revision 1.17  2021-04-18 16:39:41+05:30  Cprogrammer
# fix for space in command line argument values
#
# Revision 1.16  2021-04-16 12:56:50+05:30  Cprogrammer
# added --options-file feature to take command line arguments from an options file
#
# Revision 1.15  2021-04-15 22:06:27+05:30  Cprogrammer
# added --karma option
#
# Revision 1.14  2021-04-14 16:40:22+05:30  Cprogrammer
# added --play option
#
# Revision 1.13  2021-04-14 13:11:29+05:30  Cprogrammer
# added --playcount option to get songs that match play counts
#
# Revision 1.12  2021-04-10 13:05:38+05:30  Cprogrammer
# set default options (command line arguments) from .mpdplaylist.options
#
# Revision 1.11  2021-04-10 11:15:39+05:30  Cprogrammer
# updated usage message for --playlist option
#
# Revision 1.10  2021-01-07 12:20:20+05:30  Cprogrammer
# added last_played is NULL to query daysnotheard
#
# Revision 1.9  2020-09-05 12:32:29+05:30  Cprogrammer
# added --limit option
#
# Revision 1.8  2020-09-03 20:36:39+05:30  Cprogrammer
# fixed --clear option
#
# Revision 1.7  2020-09-03 11:10:32+05:30  Cprogrammer
# fixed stats_db path
#
# Revision 1.6  2020-08-30 11:34:59+05:30  Cprogrammer
# fixed stats.db path
#
# Revision 1.5  2020-08-06 16:15:39+05:30  Cprogrammer
# renamed --dummy option to --query
#
# Revision 1.4  2020-08-05 12:08:02+05:30  Cprogrammer
# renamed --save to --playlist
#
# Revision 1.3  2020-08-02 20:48:38+05:30  Cprogrammer
# added --shuffle option to shuffle playlist
#
# Revision 1.2  2020-08-02 17:52:35+05:30  Cprogrammer
# added --host option to specify mpd host
#
# Revision 1.1  2020-07-19 18:17:52+05:30  Cprogrammer
# Initial revision
#
#
# $Id: mpdplaylist.in,v 1.21 2022-06-20 01:04:54+05:30 Cprogrammer Exp mbhangui $
#

get_mpd_conf_value()
{
  grep "^$1" /etc/mpd.conf|awk '{print $2}' | \
  sed -e 's{"{{g'
}

usage()
{
if [ -f /usr/bin/less ] ; then
	MORE=/usr/bin/less
else
	MORE=/usr/bin/more
fi
echo "Press ENTER for options, Cntrl C to quit" 1>&2
read key
$MORE 1>&2 <<EOF
Usage: mpdplaylist [OPTION]

Known values for OPTION are:

--options-file=filename
  Take extra command line options from filename

--fromyear=From Year
  Year in YYYY format

--toyear=To Year
  Year in YYYY format

--incgenre=Genre List to be included
  comma separated list of genre.

--exlgenre=Genre List to be excluded
  comma separated list of genre

--incartist=Arist List to be included
  comma separated list of artist.

--exlartist=Arist List to be excluded
  comma separated list of artist

--minrating=Minimum Rating (value from 0 to 10, or -1 for unrated songs)

--artist=Artist
  Find songs with Artist exactly matching 'Artist'

--artistany=keyword
  Find songs with Artist having 'keyword' anywhere in the Artist field

--new=d
  Find songs added in the last 'd' days

--daysnotheard=d
  Find songs not heard in the last 'd' days, use d=0 for songs never played

--daysheard=d
  Find songs heard in the last 'd' days
  
--oldfirst
  Order playlist in increaing order of Last Played field
  (Song played earlier come at top)
  
--popular
  Order playlist in decreasing order of Rating field
  (Songs with high rating come at top)

--karma
  Find songs with karma as per expression. e.g.
  --karma<50  means songs with karma less than 50
  --karma<=50 means songs with karma less than or equal to 50
  --karma=50  means songs with karma equal to 50
  --karma>=50 means songs with karma greater than or equal to 50
  --karma>50  means songs with karma greater than 50

--playcount=exp
  Find songs with playcounts as per expression. e.g.
  --playcount<5  means songs with play counts less than 5
  --playcount<=5 means songs with play counts less than or equal to 5
  --playcount=5  means songs with play counts equal to 5
  --playcount>=5 means songs with play counts greater than or equal to 5
  --playcount>5  means songs with play counts greater than 5

--playlist=playlist
  save the playlist in the filename $playlist_dir/playlist.
  If the playlist is named now, new playlist will be added to the
  current mpd playlist. If --clear is also specified, the current
  playlist will be cleared and loaded. The 'now' playlist is not
  saved to the playlist directory. Without --playlist option,
  result will be displayed on screen.

--host=host
  mpd host to use

--shuffle
  shuffle playlist

--limit=n
  Limit the playlist to n entries

--play
  Play songs when playlist=now
  
--clear
  clear playlist before adding. See --playlist option

--query
  Display the SQL query and exit

--help

  display this help and exit

--version

  output version information
EOF
exit $1
}

process_cmdline()
{
while test $# -gt 0; do
	case "$1" in
	-*=*)
	optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'`
	optval=`echo "$1" | cut -d'=' -f1`
	prog_args="$prog_args $optval=\"$optarg\""
	;;
	-*\>*)
	optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*>//'`
	optarg=">$optarg"
	optval=`echo "$1" | cut -d'>' -f1`
	prog_args="$prog_args $optval\"$optarg\""
	;;
	-*\<*)
	optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*<//'`
	optarg="<$optarg"
	optval=`echo "$1" | cut -d'<' -f1`
	prog_args="$prog_args $optval\"$optarg\""
	;;
	*)
	optarg=
	prog_args="$prog_args $1"
	;;
	esac

	case "$1" in
	--options-file=*)
	options_file=$optarg
	;;
	--fromyear=*)
	fromyear=$optarg
	;;
	--toyear=*)
	toyear=$optarg
	;;
	--incgenre=*)
	if [ -n "$exlgenre" ] ; then
		echo "you cannot give both incgenre and exlgenre together" 1>&2
		usage 1
	fi
	incgenre=`echo $optarg| sed "s/ /_/g"`
	;;
	--exlgenre=*)
	if [ -n "$incgenre" ] ; then
		echo "you cannot give both incgenre and exlgenre together" 1>&2
		usage 1
	fi
	exlgenre=`echo $optarg| sed "s/ /_/g"`
	;;
	--incartist=*)
	if [ -n "$exlartist" ] ; then
		echo "you cannot give both incartist and exlartist together" 1>&2
		usage 1
	fi
	incartist=`echo $optarg| sed "s/ /_/g"`
	;;
	--exlartist=*)
	if [ -n "$incartist" ] ; then
		echo "you cannot give both incartist and exlartist together" 1>&2
		usage 1
	fi
	exlartist=`echo $optarg| sed "s/ /_/g"`
	;;
	--minrating=*)
	minrate=$optarg
	;;
	--artist=*)
	exact=1
	artist=`echo "$optarg"| sed "s/ /_/g"`
	;;
	--artistany=*)
	exact=0
	artist=`echo $optarg| sed "s/ /_/g"`
	;;
	--karma=*|--karma\>*|--karma\<*)
	first_char=$(echo $optarg | cut -c1)
	if [ ! "$first_char" = ">" -a ! "$first_char" = "<" ] ; then
		karma="karma=$optarg"
	else
		karma="karma$optarg"
	fi
	;;
	--playcount=*|--playcount\>*|--playcount\<*)
	first_char=$(echo $optarg | cut -c1)
	if [ ! "$first_char" = ">" -a ! "$first_char" = "<" ] ; then
		play_counts="play_count=$optarg"
	else
		play_counts="play_count$optarg"
	fi
	;;
	--new=*)
	daysadded=$optarg
	;;
	--daysheard=*)
	daysheard=$optarg
	;;
	--daysnotheard=*)
	daysnotheard=$optarg
	;;
	--playlist=*)
	playlist=$optarg
	;;
	--oldfirst)
	oldfirst=1
	;;
	--popular)
	sort_popular=1
	;;
	--query)
	dummy=1
	;;
	--shuffle)
	shuffle=1
	;;
	--clear)
	do_clear=1
	;;
	--limit=*)
	limit=$optarg
	;;
	--play)
	do_play=1
	;;
	--verbose)
	verbose="-v"
	;;
	--host=*)
	mpd_host=$optarg
	;;
	--help)
	playlist_dir=`get_mpd_conf_value playlist_dir`
	usage 0
	;;
	*)
	echo "invalid option [$1]" 1>&2
	usage 1
	;;
	esac
	shift
done
}

verbose=""
fromyear=""
toyear=""
incgenre=""
exlgenre=""
incarist=""
exlarist=""
artist=""
minrate=""
oldfirst=0
sort_popular=0
dummy=0
shuffle=0
do_clear=0
limit=0
do_play=0
play_counts=""
karma=""
playlist=""
daysadded=""
daysheard=""
daysnotheard=""
mpd_host=""
options_file=""
prog_args="$0"

if [ $# -eq 0 -a -f $HOME/.mpdplaylist.options ] ; then
	options=$(grep -v '^#' -h $HOME/.mpdplaylist.options)
	set -- $options
fi
process_cmdline "$@"
if [ -n "$options_file" ] ; then
	options=$(grep -v '^#' -h $options_file)
	set -- $options
	process_cmdline "$@"
fi

music_dir=`get_mpd_conf_value music_directory`
if [ $? -ne 0 ] ; then
  echo "could not get music directory from mpd.conf" 1>&2
  exit 1
fi
sticker_file=`get_mpd_conf_value sticker_file`
if [ $? -ne 0 ] ; then
  echo "could not get sticker database from mpd.conf" 1>&2
  exit 1
fi
playlist_dir=`get_mpd_conf_value playlist_dir`
if [ $? -ne 0 ] ; then
  echo "could not get playlist directory from mpd.conf" 1>&2
  exit 1
fi
stats_dir=$(dirname $sticker_file)
stats_file=$stats_dir/stats.db
if [ -z "$stats_file" ] ; then
  echo "Unable to get stats.db location" 1>&2
  exit 1
fi
if [ ! -f "$stats_file" ] ; then
  echo "$stats_file: No such file or directory" 1>&2
  exit 1
fi

sql_query="SELECT uri FROM song "
first_condition=""
if [ -n "$fromyear" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	sql_query="$sql_query date >= $fromyear"
fi
if [ -n "$toyear" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	sql_query="$sql_query date <= $toyear"
fi
count=0
if [ -n "$exlgenre" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	for i in $(echo $exlgenre | sed "s/,/ /g")
	do
		f=`echo $i|sed "s/_/ /g"`
		if [ $count -eq 0 ] ; then
			sql_query="$sql_query genre NOT IN ('$f'"
		else
			sql_query="$sql_query, '$f'"
		fi
		count=`expr $count + 1`
	done
	sql_query="$sql_query)"
fi
count=0
if [ -n "$incgenre" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	for i in $(echo $incgenre | sed "s/,/ /g")
	do
		f=`echo $i|sed "s/_/ /g"`
		if [ $count -eq 0 ] ; then
			sql_query="$sql_query genre IN ('$f'"
		else
			sql_query="$sql_query, '$f'"
		fi
		count=`expr $count + 1`
	done
	sql_query="$sql_query)"
fi
count=0
if [ -n "$exlartist" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	for i in $(echo $exlartist | sed "s/,/ /g")
	do
		f=`echo $i|sed "s/_/ /g"`
		if [ $count -eq 0 ] ; then
			sql_query="$sql_query artist NOT IN ('$f'"
		else
			sql_query="$sql_query, '$f'"
		fi
		count=`expr $count + 1`
	done
	sql_query="$sql_query)"
fi
count=0
if [ -n "$incartist" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	for i in $(echo $incartist | sed "s/,/ /g")
	do
		f=`echo $i|sed "s/_/ /g"`
		if [ $count -eq 0 ] ; then
			sql_query="$sql_query artist IN ('$f'"
		else
			sql_query="$sql_query, '$f'"
		fi
		count=`expr $count + 1`
	done
	sql_query="$sql_query)"
fi
if [ -n "$minrate" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	if [ "$minrate" -lt 0 ] ; then
		sql_query="$sql_query rating = 0"
	else
		sql_query="$sql_query rating >= $minrate"
	fi
fi
if [ -n "$artist" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	f=`echo $artist|sed "s/_/ /g"`
	if [ $exact -eq 1 ] ; then
		sql_query="$sql_query artist = '$f'"
	else
		sql_query="$sql_query artist like '%$f%'"
	fi
fi
if [ -n "$daysadded" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	tmval=`date +'%s'`
	tmval=`expr $tmval - $daysadded \* 86400`
	sql_query="$sql_query date_added >= $tmval"
fi
if [ -n "$karma" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	sql_query="$sql_query $karma"
fi
if [ -n "$play_counts" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	sql_query="$sql_query $play_counts"
fi
if [ -n "$daysheard" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	tmval=`date +'%s'`
	tmval=`expr $tmval - $daysheard \* 86400`
	sql_query="$sql_query last_played >= $tmval"
fi
if [ -n "$daysnotheard" ] ; then
	if [ -z "$first_condition" ] ; then
		sql_query="$sql_query WHERE"
		first_condition=1
	elif [ -n "$first_condition" ] ; then
		sql_query="$sql_query AND"
	fi
	if [ ! "$daysnotheard" = "0" ] ; then
		tmval=`date +'%s'`
		tmval=`expr $tmval - $daysnotheard \* 86400`
		sql_query="$sql_query (last_played < $tmval OR last_played IS NULL)"
	else
		sql_query="$sql_query last_played IS NULL"
	fi
fi
order_by=0
if [ $oldfirst -eq 1 ] ; then
	if [ $order_by -eq 0 ] ; then
		sql_query="$sql_query ORDER BY last_played ASC"
		order_by=1
	else
		sql_query="$sql_query, last_played ASC"
	fi
fi
if [ $sort_popular -eq 1 ] ; then
	if [ $order_by -eq 0 ] ; then
		sql_query="$sql_query ORDER BY rating DESC"
		order_by=1
	else
		sql_query="$sql_query, rating DESC"
	fi
fi
if [ -n "$daysadded" ] ; then
	if [ $order_by -eq 0 ] ; then
		sql_query="$sql_query ORDER BY date_added ASC"
		order_by=1
	else
		sql_query="$sql_query, date_added ASC"
	fi
fi
if [ $limit -gt 0 ] ; then
		sql_query="$sql_query limit $limit"
fi
if [ -z "$fromyear" -a -z "$toyear" -a -z "$incgenre" -a -z "$exlgenre" \
	-a -z "$incartist" -a -z "$exlartist" -a -z "$minrate" \
	-a -z "$artist" -a -z "$daysadded" -a -z "$daysheard" -a -z "$daysnotheard" \
	-a -z "$play_counts" -a -z "$karma" ] ; then
	echo "No options given and no default usage configuration found" 1>&2
	usage 1
	exit 1
fi
if [ $dummy -eq 0 ] ; then
	if [ -n "$playlist" ] ; then
		if [ "$playlist" = "now" ] ; then
			if [ $shuffle -eq 1 ] ; then
				/usr/bin/sqlite3 -noheader $stats_file "$sql_query;" | shuf > $playlist_dir/now.m3u
			else
				/usr/bin/sqlite3 -noheader $stats_file "$sql_query;" > $playlist_dir/now.m3u
			fi
			if [ -z "$mpd_host" ] ; then
				mpd_host=localhost
			fi
			if [ $do_clear -eq 1 ] ; then
				mpc --host="$mpd_host" clear
			fi
			mpc --host="$mpd_host" load now
			mpc --host="$mpd_host" rm now
			if [ $do_play -eq 1 ] ; then
				mpc --host="$mpd_host" play
			fi
		else
			if [ $shuffle -eq 1 ] ; then
				(
				echo "# $prog_args"
				/usr/bin/sqlite3 -noheader $stats_file "$sql_query;" | shuf
				) | tee $playlist_dir/"$playlist".m3u
			else
				(
				echo "# $prog_args"
				/usr/bin/sqlite3 -noheader $stats_file "$sql_query;" 
				) | tee $playlist_dir/"$playlist".m3u
			fi
		fi
	else
		echo "# $prog_args"
		/usr/bin/sqlite3 -noheader $stats_file "$sql_query;"
	fi
else
	echo "$sql_query;"
fi
exit 0
