#!/bin/bash
SCRIPT="${0##*/}"

## Script to parse playlists and build up a tunes heirarchy.
##
## To-Do:
## Merge multiple empeg trees together, resolving FID conflicts.
## Hard links instead of symlinks for tunes?
## Re-insert mp3 tags into copies-of the data files from the tag info?
## Inverse script to regenerate fids for empeg, using a fid:inode database to minimize deltas.
##

function get_tag(){
	sed -n -e's/"/\\"/g' -e"s/^${2}=\(.*\)/\1/p" < "$1"
}

function indent_print(){
	local depth="$1" fid="$2"
	shift ; shift
	[ "$fid" = "" ] && echo -n "          " || echo -n "$fid: " 
	while [ $depth -gt 0 ]; do
		echo -n "        "
		depth=$((depth - 1))
	done
	echo "$*"
}

function fix_duplicate(){
	local dir="$1" title="$2" codec="$3" i=2
	while [ -e "$dir/${title}__$i$codec" ]; do
		i=$((i + 1))
	done
	echo "${title}__$i"
}

function walk_playlist(){
	local depth=$1 dir="$2" dotdot="$3" nentries="$4" fid tags data type title subdir length index_target
	while read fid ; do
		[ $nentries -eq 0 ] && continue
		nentries=$((nentries - 1))
		if [ "$fid" == "00000000" ]; then
			echo "$dir: fid=$fid"
			killall $SCRIPT
		fi
		tags="fids/_${fid:0:5}/${fid:5:2}"
		data="${tags}0"
		tags="${tags}1"
		title=$(get_tag $tags 'title')
		codec=$(get_tag $tags 'codec')
		type=$(get_tag $tags 'type')
		if [ "$type" = "playlist" ]; then
			length=$(get_tag $tags 'length')
			if [ "$length" = "" ]; then
				echo "$tags: length=$length"
				killall $SCRIPT
			fi
			length=$((length / 4))
			subdir="$dir/$title"
			if [ -e "$subdir" ]; then
				title=$(fix_duplicate "$dir" "$title")
				subdir="$dir/$title"
			fi
			if [ $depth -eq 0 ]; then
				INDEX="$subdir/fids"
				echo "INDEX=$INDEX"
				mkdir -p "$INDEX" || killall $SCRIPT
				index_target=".."
			else
				index_target="../${subdir#playlists/*/}"
			fi
			echo "${title}" >>"$dir/00_ORDER" || killall $SCRIPT
			ln -s "$dotdot/$tags" "$subdir.tags" || killall $SCRIPT
			if [ -e "$INDEX/$fid" ]; then
				other=$(readlink "$INDEX/$fid")
				ln -s "${dotdot#../../}/${other#../}" "$subdir" || killall $SCRIPT
				indent_print $depth $fid "$subdir" "(SYMLINK)"
			else
				mkdir -p "$subdir" || killall $SCRIPT
				indent_print $depth $fid "$subdir"
				[ -e "$INDEX/$fid" ] || ln -s "$index_target" "$INDEX/$fid" || killall $SCRIPT
				if [ $length -gt 0 ]; then
					if [ ! -s "$data" ]; then
						ls -lF "$data"
						killall $SCRIPT
					fi
					od -An -t x4 -v -w4 $data | walk_playlist $((depth + 1)) "$subdir" "$dotdot/.." $length
				fi
			fi
		elif [ "$type" = "tune" ]; then
			indent_print $depth $fid "$title.$codec"
			[ -e "$dir/$title.$codec" ] && title=$(fix_duplicate "$dir" "$title" ".$codec")
			ln -s "$dotdot/$data" "$dir/$title.$codec" || killall $SCRIPT
			ln -s "$dotdot/$tags" "$dir/$title.tags" || killall $SCRIPT
			echo "$title.$codec" >> "$dir/00_ORDER" || killall $SCRIPT
			[ -e "$INDEX/$fid" ] || ln -s "../${dir#playlists/*/}/$title.$codec" "$INDEX/$fid"
		else
			echo "type=$type ??"
			killall $SCRIPT
		fi
	done
}

if [ -d drive0/fids ]; then
	cd drive0
fi
[ -d fids ] || exit 1
rm -r playlists
mkdir -p playlists || killall fidtomp3.sh

echo "First pass: walking the playlist tree:"
echo 00000100 | walk_playlist 0 playlists '..' 1

INDEX=$(echo playlists/*/fids)
echo
echo "Second pass: searching for unattached items: INDEX=$INDEX"

for file in fids/_[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]/[0-9a-f][0-9a-f]1 ; do
	data="${file%1}0"
	if [ ! -e "$data" ]; then
		echo "$f: data file ($data) not found"
		continue
	fi
	fid="${data##*fids/}"
	fid="${fid:1:5}${fid:7}"
	#[ "$fid" == "00000100" ] && continue
	[ -e "$INDEX/$fid" ] && continue
	echo "$file: unattached ($fid)"
done

echo
echo "Done."
exit 
