summaryrefslogtreecommitdiff
path: root/bin/pmp3p
blob: 728f77098a6e035f92ad95251164f184685f397c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#!/usr/bin/env zsh
#
# pmp3p - "Populate" MP3 Player
#
# Copyright © 2009, 2010 by Daniel Friesel <derf@derf.homelinux.org>
# License: WTFPL <http://sam.zoy.org/wtfpl>
#
# Usage: pmp3p [--remove] <basedir> <files ...>
#
# Requires: atag/arename, oggdec, flac, lame
# For playlist generation: sed, unix2dos
#
# pmp3p will put all files into basedir, more specifically to
# basedir/artist/album/id_title.mp3 .
#
# If the --remove option is specified, pmp3p will try to remove files which
# are present in basedir but not mentioned on the commandline
#
# I use it like this:
# I put symlinks to everything I want on my music player into
# ~/lib/audio/.mp3-player, then regularly call
#    cd ~/lib/audio/.mp3-player
#    pmp3p --remove /data/derf/sansa-tmp/MUSIC ***/*(-.)
#
# /data/derf/sansa-tmp is then later (whenever the player is connected for
# recharing) synced onto it.
# Of course, you can also directly encode to your music player.
#
# Playlist support:
# This is very specific to the "Sansa Fuze", for other players it's probably
# useless.
# Put glob expressions (one per line) to the songs you want in the playlist
# into .playlists/playlist_name .
# pmp3p will then expand those expressions and put the correct filenames into
# the playlist.
# Example:
#    remnant ~/l/a/.mp3-player > cat .playlists/chill
#    bluechel/*/*
#    schiller/*
#
# PS: Yes, I know that the Sansa Fuze also supports flac and ogg.
# And of course: No warranty for lost data or whatever else might happen.

autoload atag
typeset IFS=$'\n'
typeset -i bitrate=196

# If mp3info is installed, all MP3s with a bitrate > max_bitrate will be
# re-encoded to preserve space
typeset -i max_bitrate=260
typeset -a -U files files_done
typeset -A tags rtags
typeset result
typeset tmp_wav=/tmp/tempfile.wav tmp_mp3=/tmp/tempfile.mp3
typeset -i remove

while [[ ${1} == --* ]] {
	case ${1} in
		--remove) remove=1 ;;
	esac
	shift
}

typeset basedir=${1}
shift
files=(${*})

function filestate {
	typeset color=${1} message=${2}
	shift 2
	print -P -f '%s%-4s%s [%-15s - %-25s] %s\n' "%F{${color}}" ${message} \
	'%F{default}' ${rtags[artist][1,15]} ${rtags[tracktitle][1,25]} ${file}
}

function prepare_tags {
	rtags=(
		artist     unknown
		album      unknown
		tracktitle unknown
		tracknumber 00
	)
	tags=()
	result=
}

function read_tags {
	typeset cfile=${1}
	atag ${cfile} -e
	rtags=(
		artist      "${_ar}"
		album       "${_al}"
		tracktitle  "${_tt}"
		tracknumber "${_tnp}"
	)
	tags[artist]=${(L)rtags[artist]//[^[:alnum:]]/_}
	tags[album]=${(L)rtags[album]//[^[:alnum:]]/_}
	tags[tracktitle]=${(L)rtags[tracktitle]//[^[:alnum:]]/_}
	tags[tracknumber]=$(printf "%02d" ${rtags[tracknumber]//[^[:digit:]]})

	if [[ -n ${tags[artist]} && -n ${tags[tracktitle]} ]] {
		result=${basedir}/${tags[artist]}/${tags[album]}/${tags[tracknumber]}_${tags[tracktitle]}.mp3
	} else {
		result=${basedir}/unknown/${cfile:t:r}.mp3
	}
}

if [[ ! -d ${basedir} ]] {
	echo "Cannot use ${basedir}" >&2
	exit 1
}

if ((remove)) {
	i=0
	for file in ${files}; {
		echo -n "\rChecking for removed files... $((++i))/${#files}"
		prepare_tags
		read_tags ${file}
		files_done+=${result}
	}
	echo

	for file in ${basedir}/*/*/*(.N); {
		if [[ ${files_done[(I)$file]} == 0 ]] {
			prepare_tags
			read_tags ${file}
			filestate red rm
			rm -f ${file}
		}
	}
}

echo "Creating playlists..."

for p in .playlists/*(.N); {
	playlist=()
	echo "\t${p:t}"

	while read line; do
		playlist+=(${~line})
	done < ${p}

	for file in ${playlist}; {
		prepare_tags
		read_tags ${file}
		echo ${result#${basedir}/}
	} |\
		sed 's:/:\\:g' > ${basedir}/${p:t}.m3u
	unix2dos -q ${basedir}/${p:t}.m3u
}


mkdir -p ${basedir}/unknown

for file in ${files}; {
	typeset filetype=${file:e:l}
	rm -f ${tmp_wav} ${tmp_mp3}
	prepare_tags
	read_tags ${file}

	if [[ -r ${result} ]] {
		filestate yellow skip
		continue
	}

	filestate green lame

	case ${filetype} in
		ogg)  oggdec --quiet -o ${tmp_wav} ${file} > /dev/null ;;
		mp3)  cp ${file} ${tmp_mp3} > /dev/null ;;
		flac) flac --silent --decode -o ${tmp_wav} ${file} > /dev/null ;;
		*)    echo "Unrecognized format: ${file}" >&2; continue ;
	esac

	if [[ -r ${tmp_wav} && ! -r ${tmp_mp3} ]] {

		lame --quiet --ta "${rtags[artist]}" --tt "${rtags[tracktitle]}" \
		--tl "${rtags[album]}" --ty "${rtags[year]}" -h -b ${bitrate} \
		${tmp_wav} ${tmp_mp3}

	} elif [[ ${filetype} == mp3 && -n ${commands[mp3info]} \
		&& $(mp3info -r m -p '%r' ${file}) -gt ${max_bitrate} ]] \
	{

		lame --quiet --mp3input --ta "${rtags[artist]}" \
		--tt "${rtags[tracktitle]}" --tl "${rtags[album]}" \
		--ty "${rtags[year]}" -h -b ${bitrate} ${file} ${tmp_mp3}

	}

	if [[ -r ${tmp_mp3} ]] {
		mkdir -p ${basedir}/${tags[artist]}/${tags[album]}
		cp ${tmp_mp3} ${result}
	}
}