#!/bin/sh

absolutiseScripts() { SCRIPTS="$1" ; echo "$SCRIPTS" | grep -q ^/ || SCRIPTS="`dirname "$2"`/$SCRIPTS" ; } ; absolutiseScripts "`command -v "$0"`" "`pwd`/." ; while [ -h "$SCRIPTS" ] ; do absolutiseScripts "`readlink "$SCRIPTS"`" "$SCRIPTS" ; done ; SCRIPTS="`dirname "$SCRIPTS"`"

set -e

racines="/Users/gui/mp3:/Users/gui/mp3/Récup +"

TMP=/tmp/temp.$$.encogg
temp=$TMP/morceaux
mkdir -p "$temp"

commande() { command -v "$@" > /dev/null 2>&1 || { local r=$? ; echo "# $# introuvable." >&2 ; return $r ; } ; }

prerequis()
{
	local r=0
	
	# Pour MusicBrainz
	commande "$SCRIPTS/discid" || r=$?
	PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig:/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH" pkg-config libdiscid || { r=$? ; echo "# libdiscid introuvable." >&2 ; }
	commande php || r=$?
	
	# Pour l'encodage
	commande opusenc || r=$?
	#commande oggenc || r=$?
	#commande vorbiscomment || r=$?
	commande ffmpeg || r=$?
	
	# Pour diffuser
	commande rsync || r=$?
	
	return $r
}

champ()
{
	cat $TMP/pistes.encogg | awk FNR==${numero} | cut -f $1
}

champs()
{
	arg=1
	while [ "$1" ]
	do
		contenu=`champ ${arg}`
		if [ "${contenu}" ]
		then
			echo $1=${contenu}
		fi
		arg=`expr $arg + 1`
		shift
	done
}

convertir_opus()
{
	opusenc --bitrate 192 \
		--comment track="$piste" \
		--title "`champ 1`" \
		--artist "`champ 2`" \
		--comment composer="`champ 3`" \
		--album "`champ 4`" \
		--comment discid="$g_idd" \
		--date "`champ 5`" \
		"$1" "$fichier"
}

convertir_ogg()
{
	fichier1=$temp/${numero}.ogg
	oggenc -q 5 -o "$fichier1" "$1"
	echo TRACKNUMBER=${piste} > $TMP/champs.encogg
	champs TITLE ARTIST COMPOSER ALBUM DATE DISCNUMBER >> $TMP/champs.encogg
	vorbiscomment -a -R -c $TMP/champs.encogg "$fichier1" "$fichier"
	rm "$fichier1"
}

convertir_m4a()
{
	ffmpeg -v quiet -i "$1" -ab 160k -strict -2 \
		-metadata track="$piste" \
		-metadata title="`champ 1`" \
		-metadata artist="`champ 2`" \
		-metadata composer="`champ 3`" \
		-metadata album="`champ 4`" \
		-metadata year="`champ 5`" \
		"$fichier" < /dev/null # Cet abruti me bouffe mon entrée standard.
}

edulcorerChemin()
{
	# Filtre sur les futurs noms de fichier pour qu'ils puissent plaire à tout le monde (Windows, Mac, etc.).
	#tr '/:\!' ',  .' | sed -e 's/  */ /g'
	sed -e 's# */ *#, #g'
}

normaliserChemin()
{
	case `uname` in
		Darwin) /usr/bin/iconv -f utf8-mac -t utf8 ;;
		*) cat ;;
	esac
}

placement()
{
	sep="`echo | tr '\012' '\003'`"
	champDossier=2
	[ $classique = oui ] && champDossier=3
	place="`champ $champDossier`$sep`champ 1`"
	place="`echo "$place" | edulcorerChemin | tr '\003' /`"
	exprPlace="`echo "$place" | sed -e 's/[^- A-Za-z0-9]/./g'`"
	n=0
	suffixe=""
	exprSuffixe=""
	while grep -q "^$exprPlace$exprSuffixe$" < "$TMP/dejaEnPlace" ; do
		n="`expr $n + 1`"
		suffixe=".$n"
		exprSuffixe="\\$suffixe"
	done
	echo "$place$suffixe"
}

affecterPlacement()
{
	# Initialisation.
	# Les noms de fichier déjà pris sont ceux que l'on trouve dans l'un des dossiers cibles.
	
	awk -F '\011' '{ print $2; print $3; }' < "$TMP/pistes.encogg" | edulcorerChemin | sort -u | while read dossier ; do
		echo "$racines" | tr : '\012' | while read racine ; do
			( [ ! -z "$dossier" -a -d "$racine/$dossier" ] && cd "$racine/$dossier" 2> /dev/null && ls | sed -E -e 's/\.[0-9A-Za-z]{1,4}$//' -e "s#^#$dossier/#" )
		done
	done | normaliserChemin > "$TMP/dejaEnPlace"
	
	# Voyons maintenant nos pistes à encoder.
	
	numero=0
	cat "$TMP/listeselection" | while read numero poubelle ; do
		placement | tee -a "$TMP/dejaEnPlace"
	done | paste - "$TMP/listeselection" > "$TMP/liste"
}

placer()
{
	place="$dest/$sousdest`cut -d '	' -f 1 < "$TMP/liste" | sed -e $numero\!d`.$format"
	mkdir -p "`dirname "$place"`"
	mv -i "$1" "$place"
}

faire()
{
	numero=`expr $numero + 1`
	if [ "x$1" = x-n ]
	then
		shift
		piste=$1
		shift
	else
		piste=$numero
	fi
	#fichier="`basename "$1"`"
	#numero=`echo $fichier | cut -d ' ' -f 1 | cut -d - -f 2`
	
	printf "($format) Piste $piste... " > /dev/tty
	fichier="$temp/`champ 1 | tr / :`.$format"
	convertir_$format "$@"
	placer "$fichier"
	( basename "$fichier" | tr -d '\012' ; printf " -> " ; echo "$place" ) > /dev/tty
}

preparerEntreeStandard()
{
	echo Veuillez afficher dans iTunes les colonnes suivantes, dans cet ordre, et les
	echo coller ici, puis faites un Ctrl-D sur une ligne vide:
	echo Titre Interprète Compositeur Album Année Numéro de disque
	
	preparerDossier "$@"
}

sep()
{
	args="`for arg in "$@" ; do printf "%s" "$arg" ; done`"
	for sep in ' ' '#' @ '|' "`printf '\t'`" / ; do
		printf "%s" "$args" | fgrep -q "$sep" || return 0
	done
	return 1
}

preparerDossier()
{
	cat > $TMP/pistes.encogg
	for dossier in "$@" ; do
		dossier="`echo "$dossier" | sed -e 's#/$##'`"
		dossierDespe="`echo "$dossier" | sed -e 's#[&]#\\\&#g'`"
		sep '^\([/]' "$dossierDespe"
		ls "$dossier" | sort -n | sed -e "s$sep^\([^/]\)$sep$dossierDespe/\1$sep"
	done | awk '{print FNR"	"$0}' > $TMP/listeselection
}

listePistesParMusicBrainz()
{
	g_idd="`"$SCRIPTS/discid" "$1"`"
	echo "$g_idd" > "$TMP/idd"
	php "$SCRIPTS/musicbrainz.php" "$g_idd"
}

listePistes()
{
	listePistesParMusicBrainz "$@"
}

preparerDisque()
{
	tab="`echo | tr '\012' '\011'`"
	disque="`mount | egrep 'cdda' | head -1 | awk '{print $1}'`"
	case `uname` in
		Darwin) dMontage="$disque" ; dId="`echo "$dMontage" | sed -e 's/disk/rdisk/g'`" ;;
	esac
	montage="`mount | grep "^$dMontage[ $tab]" | sed -e "s/^[^ $tab]*[ $tab]*on[ $tab]*//" -e "s/[ $tab]*([^)]*)$//"`"
	listePistes "$dId" | preparerDossier "$montage"
	g_idd="`cat "$TMP/idd"`"
}

transferer()
{
	until ping -W 2000 -c 1 bonemine.local > /dev/null
	do
		sleep 30
	done
	rsync -avz "$dest/" bonemine.local:"/Users/Shared/Musique\\ Guillaume/"
	# Pas d'open, car après l'import iTunes joue sans crier gare le premier morceau non des nouveaux mais de tous les importés, donc toujours le même (Shimmy Shake), ce qui est assez lourd à la longue.
	#ssh bonemine.local 'sudo -u clotilde open -a iTunes /Users/Shared/Musique\ Guillaume/'
}

preparerSelection()
{
	osascript "$SCRIPTS/encogg.applescript" "$TMP/listeselectionetpistes"
	cut -d '	' -f 1,2 < $TMP/listeselectionetpistes > $TMP/listeselection
	cut -d '	' -f 3- < $TMP/listeselection > $TMP/pistes.encogg
}

copierLocalement()
{
	# On se permet une petite copie locale, les lecteurs optiques préférant parfois tourner à plein régime que d'être soumis à une multitude de petits accès durant l'encodage.
	cat "$TMP/listeselection" | while read numPiste chemin ; do
		dirname "$chemin"
	done | sort -u | while read dossier
	do
		rsync -a "$dossier/" "$TMP/source/"
	done
}

fairePasse()
{
	numero=0
	cat $TMP/listeselection | while read numPiste fichierOrigine ; do
		# Le fichier est (après copierLocalement()) à aller chercher dans /source/.
		fichierOrigine="$TMP/source/`basename "$fichierOrigine"`"
		faire -n "$numPiste" "$fichierOrigine"
	done
	
	if [ $transferer = x ]
	then
		transferer &
	fi
}

lieuCommun()
{
	# Les champs qui peuvent nous donner le titre sous lequel classer les morceaux: on prend la première des infos commune à toutes les pistes.
	for i in 7 8 9 10 11 # Le dernier est un garde-fou, rempli avec toujours la même valeur (Various artists), donc apte à passer le filtre.
	do
		cat $TMP/piste.encogg | cut -d '	' -f $i | sort -u > $TMP/info
		[ `wc -l < $TMP/info` -eq 1 -a `wc -c < $TMP/info` -gt 1 ] || continue # Il faut que le sort -u nous sort(e) une seule ligne, et composée de plus de caractères que du seul retour à la ligne.
		lieu="`cat $TMP/info`"
		break
	done
}

#quefaire=ogg:.:/Users/gui/mp3
quefaire=opus:.:/Users/gui/mp3
quefaire="m4a:x:/tmp/mp3 $quefaire" # Si c'est pour Clo, c'est pour l'iPhone, donc AAC.

analyserParametres()
{
	recuperer=oui
	editer=oui
	classique=non
	sousdest="Récup +/" # Par défaut on encode vers notre dossier Récup + (Récup comme récupéré, parce qu'on n'a pas acheté nous-mêmes le morceau, + parce que, l'ayant encodé nous-mêmes, on est confiants dans sa qualité).
	g_idd=
	> "$TMP/parametres"
	while [ $# -gt 0 ]
	do
		case "$1" in
			-c|--classique) classique=oui ;;
			-m|--moi) sousdest= ;; # Si l'achat est de nous, il va dans le dossier principal.
			-d)
				shift
				mv "$TMP/parametres" "$1/parametres"
				TMP="$1"
				recuperer=non # On estime que si l'on reprend un encodage, c'est que la copie a déjà été faite et que c'est justement LE gros morceau de ce qu'on veut récupérer.
				;;
			*) echo "$1" >> "$TMP/parametres" ;;
		esac
		shift
	done
}

analyserParametres "$@"
prerequis

if [ $recuperer = oui ] ; then
case "`head -1 < "$TMP/parametres"`" in
	--itunes|--iTunes) preparerSelection ;;
	"") preparerDisque ;;
	*) preparerEntreeStandard "`cat "$TMP/parametres"`" ;;
esac
copierLocalement &
fi
if [ "$editer" = oui ] ; then
	vim -X "$TMP/pistes.encogg"
fi
affecterPlacement
wait # Le copierLocalement
for passe in $quefaire
do
	format="`echo "$passe" | cut -d : -f 1`"
	transferer="`echo "$passe" | cut -d : -f 2`"
	dest="`echo "$passe" | cut -d : -f 3-`"
	fairePasse
done

wait

chmod -R u+w "$TMP/source"
rm -R $TMP/
