c874b1f75e72f790aa98d26615f54c93ad800870
[abcde.git] / abcde
1 #!/bin/sh
2 # Copyright (c) 1998-2001 Robert Woodcock <rcw@debian.org>
3 # Copyright (c) 2003-2004 Jesus Climent <jesus.climent@hispalinux.es>
4 # This code is hereby licensed for public consumption under either the
5 # GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice.
6 #
7 # You should have received a copy of the GNU General Public License
8 # along with this program; if not, write to the Free Software
9 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10 #
11 # Copyright for this work is to expire January 1, 2010, after which it
12 # shall be public domain.
13
14 VERSION="2.1pre2.2.0"
15
16 usage ()
17 {
18 echo "This is abcde v$VERSION."
19 echo "Usage: abcde [options] [tracks]"
20 echo "Options:"
21 echo "-1    Encode the whole CD in a single file"
22 echo "-a    Actions to perform (cddb,read,normalize,encode,tag,move,playlist,clean)"
23 echo "-A    Experimental actions (retag, transcode)"
24 echo "-b    Batch mode: enable album normalization and nogap encoding"
25 echo "-c    Specify a configuration file (overrides system and user config files)"
26 echo "-C    Specify discid to resume from (only needed if you no longer have the cd)"
27 echo "-d    Specify CDROM device to grab"
28 echo "-D    Debugging mode (equivalent to sh -x abcde)"
29 echo "-f    Force the use of a local CDDB entry. Use an empty template if not found"
30 echo "-h    This help information"
31 #echo "-i    Tag files while encoding, when possible (local only) -NWY-"
32 echo "-j    Number of encoder processes to run at once"
33 echo "-k    Keep the wav tracks for later use"
34 echo "-l    Use low disk space algorithm"
35 echo "-L    Use local CDDB storage directory"
36 echo "-n    No lookup. Don't query CDDB, just create and use template"
37 echo "-N    Noninteractive. Never prompt for anything"
38 echo "-m    Modify playlist to include CRLF endings, to comply with some players"
39 echo "-o    Output file type(s) (ogg,mp3,flac,spx,mpc). Defaults to ogg"
40 echo "-p    Pad track numbers with 0's (if less than 10 tracks)"
41 echo "-r    [host1,host2...] Also encode on these remote hosts"
42 echo "-R    Add replaygain values to the tag info (ogg,flac)"
43 echo "-s    Start the track numbering at a given number [DEPRECATED: use -t]"
44 echo "-S    Set the CD speed"
45 #echo "-t    File types to preprocess (wav)"
46 #echo "-T    Set postprocessing options"
47 echo "-t    Start the track numbering at a given number"
48 echo "-T    Start the track numbering at a given number, modifying tag numbering"
49 echo "-v    Show version number and exit"
50 echo "-V    Be a bit more verbose about what is happening behind the scenes"
51 echo "-x    Eject CD after all tracks are read"
52 echo "-w    <comment> Add a comment to the CD tracks"
53 echo "Tracks is a space-delimited list of tracks to grab."
54 echo "Ranges specified with hyphens are allowed."
55 }
56
57 # Funtions to replace the need of seq, which is too distribution dependant.
58 f_seq_row ()
59 {
60         i=$1
61         while [ $i -ne `expr $2 + 1` ]
62         do
63                 echo $i
64                 i=`expr $i + 1`
65         done
66 }
67
68 f_seq_line ()
69 {
70         i=$1
71         while [ $i -ne `expr $2 + 1` ]
72         do
73                 printf $i" "
74                 i=`expr $i + 1`
75         done
76         echo
77 }
78
79 # checkstatus [blurb]
80 # Returns "0" if the blurb was found, returns 1 if it wasn't
81 # Puts the blurb content, if available, on stdout.
82 # Otherwise, returns "".
83 checkstatus ()
84 {
85         # Take the last line in the status file if there's multiple matches
86         PATTERN="^$1(=.*)?$"
87         BLURB=$(egrep $PATTERN "$ABCDETEMPDIR/status" | tail -n 1)
88
89         if [ -z "$BLURB" ]; then
90                 # No matches found
91                 return 1
92         else
93                 # Matches found
94                 # See if there's a = in it
95                 if [ "$(echo $BLURB | grep -c =)" != "0" ]; then
96                         echo "$(echo $BLURB | cut -f2- -d=)"
97                 fi
98                 return 0
99         fi
100 }
101
102 # checkerrors [blurb]
103 # Returns "0" if the blurb was found (meaning there was an error),
104 # returns 1 if it wasn't (yes this is a little backwards).
105 # Does not print the blurb on stdout.
106 # Otherwise, returns "".
107 checkerrors ()
108 {
109         if [ -e "$ABCDETEMPDIR/errors" ]; then :; else
110                 return 1
111         fi
112         # Take the last line in the status file if there's multiple matches
113         PATTERN="^$1(:.*)?$"
114         BLURB="$(egrep $PATTERN $ABCDETEMPDIR/errors | tail -n 1)"
115
116         if [ -z "$BLURB" ]; then
117                 # negative, we did not have a negative...
118                 return 1
119         else
120                 # affirmative, we had a negative...
121                 return 0
122         fi
123 }
124
125 # run_command [blurb] [command...]
126 # Runs a command, silently if necessary, and updates the status file
127 run_command ()
128 {
129         BLURB="$1"
130         shift
131         # See if this is supposed to be silent
132         if [ "$(checkstatus encode-output)" = "loud" ]; then
133                 "$@" >&2
134                 RETURN=$?
135         else
136                 # Special case for SMP, since
137                 # encoder output is never displayed, don't mute echos
138                 if [ -z "$BLURB" -a "$MAXPROCS" != "1" ]; then
139                         "$@" >&2
140                         RETURN=$?
141                 else
142                         "$@" >/dev/null 2>&1
143                         RETURN=$?
144                 fi
145         fi
146         case "$1" in
147         normalize)
148                 if [ "$RETURN" = "2" ]; then
149                         # File was already normalized.
150                         RETURN=0
151                 fi
152                 ;;
153         esac
154         if [ "$RETURN" != "0" ]; then
155                 # Put an error in the errors file. For various reasons we
156                 # can't capture a copy of the program's output but we can
157                 # log what we attempted to execute and the error code
158                 # returned by the program.
159                 if [ "$BLURB" ]; then
160                         TWEAK="$BLURB: "
161                 fi
162                 echo "${TWEAK}returned code $RETURN: $@" >> "$ABCDETEMPDIR/errors"
163                 return $RETURN # Do not pass go, do not update the status file
164         fi
165         if [ "$BLURB" ]; then
166                 echo $BLURB >> "$ABCDETEMPDIR/status"
167         fi
168 }
169
170 # relpath() and slash() are Copyright (c) 1999 Stuart Ballard and
171 # distributed under the terms of the GNU GPL v2 or later, at your option
172
173 # Function to determine if a word contains a slash.
174 slash ()
175 {
176         case "$1" in
177         */*) return 0;;
178         *) return 1;;
179         esac
180 }
181
182 # Function to give the relative path from one file to another.
183 # Usage: relpath fromfile tofile
184 # eg relpath music/Artist/Album.m3u music/Artist/Album/Song.mp3
185 # (the result would be Album/Song.mp3)
186 # Output is relative path to $2 from $1 on stdout
187
188 # This code has the following restrictions:
189 # Multiple ////s are not collapsed into single /s, with strange effects.
190 # Absolute paths and ../s are handled wrong in FR (but they work in TO)
191 # If FR is a directory it must have a trailing /
192
193 relpath ()
194 {
195         FR="$1"
196         TO="$2"
197
198         case "$TO" in
199         /*) ;; # No processing is needed for absolute paths
200         *)
201                 # Loop through common prefixes, ignoring them.
202                 while slash "$FR" && [ "$(echo "$FR" | cut -d/ -f1)" = "$(echo "$TO" | cut -d/ -f1)" ]
203                 do
204                         FR="$(echo "$FR" | cut -d/ -f2-)"
205                         TO="$(echo "$TO" | cut -d/ -f2-)"
206                 done
207                 # Loop through directory portions left in FR, adding appropriate ../s.
208                 while slash "$FR"
209                 do
210                         FR="$(echo "$FR" | cut -d/ -f2-)"
211                         TO="../$TO"
212                 done
213         esac
214
215         echo $TO
216 }
217
218 # This code splits the a Various Artist track name from one of the following
219 # forms:
220 #
221 #  forward:        Artist / Track
222 #  forward-dash:   Artist - Track
223 #  reverse:        Track / Artist
224 #  reverse-dash:   Track - Artist
225 #  colon:          Artist: Track
226 #  trailing-paren: Artist (Track)
227 #
228 # variables used:
229 # VARIOUSARTISTS, VARIOUSARTISTSTYLE, TRACKNAME, TRACKARTIST
230 splitvarious ()
231 {
232         if [ "$VARIOUSARTISTS" = "y" ] && [ ! "$ONETRACK" = "y" ]; then
233                 case "$VARIOUSARTISTSTYLE" in
234                 forward)
235                         DTITLEARTIST="$(echo $TRACKNAME | sed 's- / -~-g')"
236                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f1 -d~)"
237                         TRACKNAME="$(echo $DTITLEARTIST | cut -f2 -d~)"
238                         ;;
239                 forward-dash)
240                         DTITLEARTIST="$(echo $TRACKNAME | sed 's, - ,~,g')"
241                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f1 -d~)"
242                         TRACKNAME="$(echo $DTITLEARTIST | cut -f2 -d~)"
243                         ;;
244                 reverse)
245                         DTITLEARTIST="$(echo $TRACKNAME | sed 's- / -~-g')"
246                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f2 -d~)"
247                         TRACKNAME="$(echo $DTITLEARTIST | cut -f1 -d~)"
248                         ;;
249                 reverse-dash)
250                         DTITLEARTIST="$(echo $TRACKNAME | sed 's, - ,~,g')"
251                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f2 -d~)"
252                         TRACKNAME="$(echo $DTITLEARTIST | cut -f1 -d~)"
253                         ;;
254                 colon)
255                         DTITLEARTIST="$(echo $TRACKNAME | sed 's-: -~-g')"
256                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f1 -d~)"
257                         TRACKNAME="$(echo $DTITLEARTIST | cut -f2 -d~)"
258                         ;;
259                 trailing-paren)
260                         DTITLEARTIST="$(echo $TRACKNAME | sed 's,^\(.*\) (\(.*\)),\1~\2,')"
261                         TRACKARTIST="$(echo $DTITLEARTIST | cut -f2 -d~)"
262                         TRACKNAME="$(echo $DTITLEARTIST | cut -f1 -d~)"
263                         ;;
264                 esac
265         elif [ "$ONETRACK" = "y" ]; then
266                 TRACKARTIST="Various"
267         else
268                 TRACKARTIST=$DARTIST
269         fi
270 }
271
272 # do_tag [tracknumber]
273 # id3 tags a filename
274 # variables used:
275 # TRACKS, TRACKNAME, TRACKARTIST, TAGGER, TAGGEROPTS, VORBISCOMMENT, METAFLAC, 
276 # COMMENT, DALBUM, DARTIST, CDYEAR, CDGENRE (and temporarily) ID3TAGV
277 do_tag ()
278 {
279         COMMENTOUTPUT="$(eval echo ${COMMENT})"
280         run_command '' echo "Tagging track $1 of $TRACKS: $TRACKNAME..."
281         # If we want to start the tracks with a given number, we need to modify the
282         # TRACKNUM value before evaluation
283         if [ -n "$STARTTRACKNUMBER" -a -n "$STARTTRACKNUMBERTAG" ] ; then
284                 # Get the trackpadding from the current track
285                 CURRENTTRACKPADDING=$(echo -n $UTRACKNUM | wc -c)
286                 TRACKNUM=$( printf %0.${CURRENTTRACKPADDING}d $(expr ${UTRACKNUM} + ${STARTTRACKNUMBER} - 1 ))
287         fi
288         for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
289         do
290         case "$OUTPUT" in
291         mp3)
292                 # id3v2 v0.1.9 claims to have solved the -c bug, so we merge both id3 and id3v2
293                 run_command tagtrack-$1 $TAGGER $TAGGEROPTS -c "$COMMENTOUTPUT" \
294                         -A "$DALBUM" -a "$TRACKARTIST" -t "$TRACKNAME" -y "$CDYEAR" \
295                         -g "$CDGENRE" -T "$1/$TRACKS" "$ABCDETEMPDIR/track$1.$OUTPUT"
296                 ;;
297         ogg)
298                 case "$OGGENCODERSYNTAX" in
299                         vorbize|oggenc)
300                                 # vorbiscomment can't do in-place modification, mv the file first
301                                 if [ -f "$ABCDETEMPDIR/track$1.$OUTPUT" -a ! -f "$ABCDETEMPDIR/track$1.uncommented.$OUTPUT" ]; then
302                                         mv "$ABCDETEMPDIR/track$1.$OUTPUT" "$ABCDETEMPDIR/track$1.uncommented.$OUTPUT"
303                                 fi
304                                 (
305                                 # These are from http://www.xiph.org/ogg/vorbis/doc/v-comment.html
306                                 echo ARTIST=$TRACKARTIST
307                                 echo ALBUM="$DALBUM"
308                                 echo TITLE=$TRACKNAME
309                                 if [ -n "$CDYEAR" ]; then
310                                         echo DATE="$CDYEAR"
311                                 fi
312                                 if [ -n "$CDGENRE" ]; then
313                                         echo GENRE="$CDGENRE"
314                                 fi      
315                                 echo TRACKNUMBER=$1
316                                 echo CDDB=$CDDBDISCID
317                                 if [ "$(eval echo ${COMMENT})" != "" ]; then
318                                         case "$COMMENTOUTPUT" in
319                                                 *=*) echo "$COMMENTOUTPUT";;
320                                                 *)   echo COMMENT="$COMMENTOUTPUT";;
321                                         esac    
322                                 fi
323                                 ) | run_command tagtrack-$1 $VORBISCOMMENT -w \
324                                         "$ABCDETEMPDIR/track$1.uncommented.$OUTPUT" "$ABCDETEMPDIR/track$1.$OUTPUT"
325                                 # Doublecheck that the commented file was created successfully before wiping the original
326                                 if [ -f "$ABCDETEMPDIR/track$1.$OUTPUT" ]; then
327                                         rm -f "$ABCDETEMPDIR/track$1.uncommented.$OUTPUT"
328                                 else
329                                         mv "$ABCDETEMPDIR/track$1.uncommented.$OUTPUT" "$ABCDETEMPDIR/track$1.$OUTPUT"
330                                 fi
331                                 ;;
332                 esac
333                 ;;
334         flac)
335                 (
336                 echo ARTIST="$TRACKARTIST"
337                 echo ALBUM="$DALBUM"
338                 echo TITLE="$TRACKNAME"
339                 if [ -n "$CDYEAR" ]; then
340                         echo DATE="$CDYEAR"
341                 fi
342                 if [ -n "$CDGENRE" ]; then
343                         echo GENRE="$CDGENRE"
344                 fi      
345                 echo TRACKNUMBER=${TRACKNUM:-$1}
346                 echo CDDB=$CDDBDISCID
347                 if [ "$(eval echo ${COMMENT})" != "" ]; then
348                         case "$COMMENTOUTPUT" in
349                                 *=*) echo "$COMMENTOUTPUT";;
350                                 *)   echo COMMENT="$COMMENTOUTPUT";;
351                         esac    
352                 fi
353                 ) | run_command tagtrack-$1 $METAFLAC --import-vc-from=- --no-utf8-convert "$ABCDETEMPDIR/track$1.$OUTPUT"
354                 ;;
355         spx)
356                 run_command tagtrack-$1 true
357                 ;;
358         mpc)
359                 run_command tagtrack-$1 true
360                 ;;
361         esac
362         done
363 }
364
365 # do_batch_encode
366 # variables used:
367 # OUTPUTTYPE, {FOO}ENCODERSYNTAX, ENCNICE, ENCODER, ENCODEROPTS
368 do_batch_encode ()
369 {
370         # The commands here don't go through run_command because they're never supposed to be silenced
371         echo "Batch encoding tracks: $TRACKQUEUE"
372         OUTPUT=$(echo $OUTPUTTYPE | grep "mp3" )
373         case "$OUTPUT" in
374         mp3)
375                 case "$MP3ENCODERSYNTAX" in
376                 lame)
377                         (
378                         cd "$ABCDETEMPDIR"
379                         TRACKFILES=
380                         for UTRACKNUM in $TRACKQUEUE
381                         do
382                                 TRACKFILES="$TRACKFILES track$UTRACKNUM.wav"
383                         done
384                         nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS --nogap $TRACKFILES
385                         RETURN=$?
386                         if [ "$RETURN" != "0" ]; then
387                                 echo "batch-encode: $ENCODER returned code $RETURN" >> errors
388                         else
389                                 for UTRACKNUM in $TRACKQUEUE
390                                 do
391                                         echo encodetrack-$UTRACKNUM >> status
392                                 done
393                         fi
394                         )
395                         ;;
396                 esac
397                 ;;
398         esac
399         # Other encoders fall through to normal encoding as the tracks
400         # have not been entered in the status file.
401 }
402
403 # do_encode [tracknumber] [hostname]
404 # If no hostname is specified, encode locally
405 # variables used:
406 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
407 do_encode ()
408 {
409         IN="$ABCDETEMPDIR/track$1.wav"
410         # We need IN to proceed.
411         if [ -s "$IN" ] ; then
412                 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
413                 do
414                         OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
415                         run_command '' echo "Encoding track $1 of $TRACKS: $TRACKNAME..."
416                         case "$OUTPUT" in
417                         mp3)
418                                 case "$2" in
419                                 %local*%)
420                                         case "$MP3ENCODERSYNTAX" in
421                                         lame|gogo) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS "$IN" "$OUT" ;;
422                                         bladeenc) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS -quit "$IN" ;;
423                                         l3enc|xingmp3enc) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $MP3ENCODER "$IN" "$OUT" $MP3ENCODEROPTS ;;
424                                         mp3enc) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $MP3ENCODER -if "$IN" -of "$OUT" $MP3ENCODEROPTS ;;
425                                         esac
426                                         ;;
427                                 *)
428                                         run_command encodetrack-$OUTPUT-$1 nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" >/dev/null 2>&1
429                                         ;;
430                                 esac
431                                 ;;
432                         ogg)
433                                 case "$2" in
434                                 %local*%)
435                                         case "$OGGENCODERSYNTAX" in
436                                         vorbize) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $OGGENCODER $OGGENCODEROPTS -w "$OUT" "$IN" ;;
437                                         oggenc) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $OGGENCODER $OGGENCODEROPTS -o "$OUT" "$IN" ;;
438                                         esac
439                                         ;;
440                                 *)
441                                         run_command encodetrack-$OUTPUT-$1 nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" >/dev/null 2>&1
442                                         ;;
443                                 esac
444                                 ;;
445                         flac)
446                                 case "$2" in
447                                 %local*%)
448                                         case "$FLACENCODERSYNTAX" in
449                                         flac) run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $FLACENCODER  $FLACENCODEROPTS -o "$OUT" "$IN" ;; 
450                                         esac
451                                         ;;
452         
453                                 *)
454                                         echo -n "DISTMP3:"
455                                         echo "$DISTMP3 $DISTMP3OPTS $2 $IN $OUT >/dev/null 2>&1"
456                                         run_command encodetrack-$OUTPUT-$1 nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" > /dev/null 2>&1
457                                         ;;
458                                 esac
459                                 ;;
460                         spx)
461                                 if [ "$(eval echo ${COMMENT})" != "" ]; then
462                                         case "$COMMENT" in
463                                                 *=*) ;;
464                                                 *)   COMMENT="COMMENT=$COMMENT" ;;
465                                         esac    
466                                         COMMENT="--comment \"$COMMENT\""
467                                 fi
468                                 # Quick hack to avoid tagging Ogg/Speex, since there is no other way to tag than inline tagging
469                                 if [ ! "$DOTAG" = "y" ]; then
470                                         run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $SPEEXENCODER $SPEEXENCODEROPTS --author "$TRACKARTIST" --title "$TRACKNAME" "$COMMENT" "$IN" "$OUT"
471                                 else
472                                         run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $SPEEXENCODER $SPEEXENCODEROPTS "$IN" "$OUT"
473                                 fi
474                                 ;;
475                         mpc)    
476                                 # MPP/MP+(Musepack) format (.mpc) is done locally, with inline
477                                 # tagging.
478                                 # I tried compiling the mppenc from corecodecs.org and got some
479                                 # errors, so I have not tried it myself.
480                                 ## FIXME ## Needs some cleanup to determine if an empty tag sent
481                                 ## FIXME ## to the encoder ends up empty.
482                                 run_command encodetrack-$OUTPUT-$1 nice $ENCNICE $MPPENCODER $MPPENCODEROPTS --artist "$TRACKARTIST" --album "$DALBUM" --title "$TRACKNAME" --track "$1" --genre "$CDGENRE" --year "$CDYEAR" --comment "$COMMENT" "$IN" "$OUT"
483                                 ;;
484                         esac
485                 done
486                 # Only remove .wav if the encoding succeeded
487                 if checkerrors "encodetrack-(.{3,4})-$1"; then 
488                         run_command encodetrack-$1 false
489                 else
490                         run_command encodetrack-$1 true
491                         if [ ! "$KEEPWAVS" = "y" ] ; then
492                                 rm -f "$IN"
493                         fi
494                 fi
495         else
496                 if [ "$(checkstatus encode-output)" = "loud" ]; then
497                         echo "HEH! The file we were about to encode disappeared:"
498                         echo ">> $IN"
499                 fi
500                 run_command encodetrack-$1 false
501         fi
502 }
503
504 # do_preprocess [tracknumber]
505 # variables used:
506 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
507 #do_preprocess ()
508 #{
509 #       IN="$ABCDETEMPDIR/track$1.wav"
510 #       # We need IN to proceed.
511 #       if [ -s "$IN" ] ; then
512 #               for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
513 #               do
514 #                       #OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
515 #                       run_command '' echo "Pre-processing track $1 of $TRACKS..."
516 #                       case "$POSTPROCESSFORMAT" in
517 #                       all|wav*)
518 #                               run_command preprocess-$OUTPUT-$1 nice $PRENICE $WAV_PRE $IF $OF ;;
519 #                       mp3)
520 #                               run_command preprocess-$OUTPUT-$1 nice $PRENICE $MP3_PRE $IF $OF ;;
521 #                       ogg)
522 #                               run_command preprocess-$OUTPUT-$1 nice $PRENICE $OGG_PRE $IF $OF ;;
523 #                       flac)
524 #                               run_command preprocess-$OUTPUT-$1 nice $PRENICE $FLAC_PRE $IF $OF ;;
525 #                       spx)
526 #                               run_command preprocess-$OUTPUT-$1 nice $PRENICE $SPX_PRE $IF $OF ;;
527 #                       esac
528 #               done
529 #               # Only remove .wav if the encoding succeeded
530 #               if checkerrors "preprocess-(.{3,4})-$1"; then 
531 #                       run_command preprocess-$1 false
532 #               else
533 #                       run_command preprocess-$1 true
534 #               fi
535 #       else
536 #               if [ "$(checkstatus encode-output)" = "loud" ]; then
537 #                       echo "HEH! The file we were about to pre-process disappeared:"
538 #                       echo ">> $IN"
539 #               fi
540 #               run_command preprocess-$1 false
541 #       fi
542 #}
543
544
545 # do_postprocess [tracknumber]
546 # variables used:
547 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
548 #do_postprocess ()
549 #{
550 #       for POSTPROCESSFORMAT in $(echo $POSTPROCESSFORMATS | tr , \ )
551 #       do
552 #               IN="$ABCDETEMPDIR/track$1.$POSTPROCESSFORMAT"
553 #               # We need IN to proceed.
554 #               if [ -s "$IN" ] ; then
555 #                       #OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
556 #                       run_command '' echo "Post-processing track $1 of $TRACKS..."
557 #                       case "$POSTPROCESSFORMAT" in
558 #                               mp3)
559 #                                       run_command postprocess-$OUTPUT-$1 nice $POSTNICE $MP3_POST $IF $OF ;;
560 #                               ogg)
561 #                                       run_command postprocess-$OUTPUT-$1 nice $POSTNICE $OGG_POST $IF $OF ;;
562 #                               flac)
563 #                                       run_command postprocess-$OUTPUT-$1 nice $POSTNICE $FLAC_POST $IF $OF ;;
564 #                               spx)
565 #                                       run_command postprocess-$OUTPUT-$1 nice $POSTNICE $SPX_POST $IF $OF ;;
566 #                       esac
567 #                       # Only remove .wav if the encoding succeeded
568 #                       if checkerrors "postprocess-(.{3,4})-$1"; then 
569 #                               run_command postprocess-$1 false
570 #                       else
571 #                               run_command postprocess-$1 true
572 #                       fi
573 #               else
574 #                       if [ "$(checkstatus encode-output)" = "loud" ]; then
575 #                               echo "HEH! The file we were about to post-process disappeared:"
576 #                               echo ">> $IN"
577 #                       fi
578 #                       run_command postprocess-$1 false
579 #               fi
580 #       done
581 #}
582
583 # do_batch_gain
584 # variables used:
585 # MP3GAIN, MP3GAINOPTS, VORBISGAIN, VORBISGAINOPTS
586 do_batch_gain ()
587 {
588         # The commands here don't go through run_command because they're never supposed to be silenced
589         echo "Batch analizing gain in tracks: $TRACKQUEUE"
590         (
591         cd "$ABCDETEMPDIR"
592         BLURB=
593         TRACKFILES=
594         for UTRACKNUM in $TRACKQUEUE
595         do
596                 MP3FILES="$TRACKFILES track$UTRACKNUM.mp3"
597         done
598         # XXX: Hard-coded batch option!
599         $NORMALIZER -b $NORMALIZEROPTS $TRACKFILES
600         RETURN=$?
601         if [ "$RETURN" != "0" ]; then
602                 echo "batch-normalize: $NORMALIZER returned code $RETURN" >> errors
603         else
604                 for UTRACKNUM in $TRACKQUEUE
605                 do
606                         echo normalizetrack-$UTRACKNUM >> status
607                 done
608         fi
609         )
610 }
611
612 # do_batch_normalize
613 # variables used:
614 # NORMALIZER, NORMALIZEROPTS
615 do_batch_normalize ()
616 {
617         # The commands here don't go through run_command because they're never supposed to be silenced
618         echo "Batch normalizing tracks: $TRACKQUEUE"
619         (
620         cd "$ABCDETEMPDIR"
621         BLURB=
622         TRACKFILES=
623         for UTRACKNUM in $TRACKQUEUE
624         do
625                 TRACKFILES="$TRACKFILES track$UTRACKNUM.wav"
626         done
627         # XXX: Hard-coded batch option!
628         $NORMALIZER -b $NORMALIZEROPTS $TRACKFILES
629         RETURN=$?
630         if [ "$RETURN" != "0" ]; then
631                 echo "batch-normalize: $NORMALIZER returned code $RETURN" >> errors
632         else
633                 for UTRACKNUM in $TRACKQUEUE
634                 do
635                         echo normalizetrack-$UTRACKNUM >> status
636                 done
637         fi
638         )
639 }
640
641 # do_normalize [tracknumber]
642 # variables used:
643 # TRACKS, TRACKNAME, NORMALIZER, NORMALIZEROPTS
644 do_normalize ()
645 {
646         IN="$ABCDETEMPDIR/track$1.wav"
647         if [ -e "$IN" ] ; then
648                 run_command '' echo "Normalizing track $1 of $TRACKS: $TRACKNAME..."
649                 run_command normalizetrack-$1 $NORMALIZER $NORMALIZEROPTS "$IN"
650         else
651                 if [ "$(checkstatus encode-output)" = "loud" ]; then
652                         echo "HEH! The file we were about to normalize disappeared:"
653                         echo ">> $IN"
654                 fi
655                 run_command normalizetrack-$1 false "File $IN was not found"
656         fi
657 }
658
659 # do_move [tracknumber]
660 # Deduces the outfile from environment variables
661 # Creates directory if necessary
662 # variables used:
663 # TRACKNUM, TRACKNAME, TRACKARTIST, DALBUM, OUTPUTFORMAT, CDGENRE, CDYEAR
664 do_move ()
665 {
666         for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
667         do
668                 # Create ALBUMFILE, ARTISTFILE, TRACKFILE
669                 # Munge filenames as follows:
670                 # ' ' -> '_'
671                 # '/' -> '_'
672                 # ''' -> ''
673                 # '?' -> ''
674                 # Eat control characters
675                 ALBUMFILE=$(mungefilename "$DALBUM")
676                 ARTISTFILE=$(mungefilename "$TRACKARTIST")
677                 TRACKFILE=$(mungefilename "$TRACKNAME")
678                 GENRE=$(mungegenre "$GENRE")
679                 YEAR=$(echo $CDYEAR)
680                 # If we want to start the tracks with a given number, we need to modify the
681                 # TRACKNUM value before evaluation
682                 if [ -n "$STARTTRACKNUMBER" ] ; then
683                         # Get the trackpadding from the current track
684                         CURRENTTRACKPADDING=$(echo -n $UTRACKNUM | wc -c)
685                         TRACKNUM=$( printf %0.${CURRENTTRACKPADDING}d $(expr ${UTRACKNUM} + ${STARTTRACKNUMBER} - 1 ))
686                 else
687                         TRACKNUM=${UTRACKNUM}
688                 fi
689                 # Supported variables for OUTPUTFORMAT are GENRE, ALBUMFILE, ARTISTFILE,
690                 # TRACKFILE, and TRACKNUM.
691                 if [ "$VARIOUSARTISTS" = "y" ]; then
692                         OUTPUTFILE=$(eval echo $VAOUTPUTFORMAT)
693                         else
694                         OUTPUTFILE=$(eval echo $OUTPUTFORMAT)
695                 fi
696                 # Check that the directory for OUTPUTFILE exists, if it doesn't, create it
697                 OUTPUTFILEDIR=$(dirname "$OUTPUTDIR/$OUTPUTFILE")
698                 # mkdir -p shouldn't return an error if the directory already exists
699                 mkdir -p "$OUTPUTFILEDIR"
700                 run_command movetrack-$1 mv "$ABCDETEMPDIR/track$1.$OUTPUT" "$OUTPUTDIR/$OUTPUTFILE.$OUTPUT"
701         done
702 }
703
704 # do_playlist
705 # Create the playlist if wanted
706 # Variables used:
707 # PLAYLISTFORMAT, PLAYLISTDATAPREFIX, VAPLAYLISTFORMAT, VAPLAYLISTDATAPREFIX,
708 # VARIOUSARTISTS, OUTPUTDIR
709 do_playlist ()
710 {
711         for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
712         do
713                 # Create a playlist file for the playlist data to go into.
714                 # We used to wipe it out if it existed. Now we request permision if interactive.
715                 for LASTTRACK in $TRACKQUEUE; do :; done
716                 ALBUMFILE=$(mungefilename "$DALBUM")
717                 ARTISTFILE=$(mungefilename "$DARTIST")
718                 GENRE=$(mungegenre "$GENRE")
719                 if [ "$VARIOUSARTISTS" = "y" ] ; then
720                         PLAYLISTFILE=$(eval echo $VAPLAYLISTFORMAT)
721                 else
722                         PLAYLISTFILE=$(eval echo $PLAYLISTFORMAT)
723                 fi
724                 FINALPLAYLISTDIR=$(dirname "$OUTPUTDIR/$PLAYLISTFILE")
725                 mkdir -p "$FINALPLAYLISTDIR"
726                 if [ -s "$OUTPUTDIR/$PLAYLISTFILE" ]; then
727                         #echo -n "Erase any existing playlist file? [y/n] (y): " >&2
728                         echo -n "Erase, Append to, or Keep the existing playlist file? [e/a/k] (e): " >&2
729                         if [ "$INTERACTIVE" = "y" ]; then
730                                 while [ "$DONE" != "y" ]; do
731                                         read ERASEPLAYLIST
732                                         case $ERASEPLAYLIST in
733                                                 e|E|a|A|k|K) DONE=y ;;
734                                                 *) ;;
735                                         esac
736                                 done
737                         else
738                                 echo e >&2
739                                 ERASEPLAYLIST=e
740                         fi
741                         # Once we erase the playlist, we use append to create the new one.
742                         [ "$ERASEPLAYLIST" = "e" -o "$ERASEPLAYLIST" = "E" ] && rm -f "$OUTPUTDIR/$PLAYLISTFILE" && ERASEPLAYLIST=a
743                 else
744                         # The playlist does not exist, so we can safelly use append to create the new list
745                         ERASEPLAYLIST=a
746                 fi
747                 if [ "$ERASEPLAYLIST" = "a" -o "$ERASEPLAYLIST" = "A" ]; then
748                         touch "$OUTPUTDIR/$PLAYLISTFILE"
749                         for UTRACKNUM in $TRACKQUEUE
750                         do
751                                 # Shares some code with do_move since the filenames have to match
752                                 CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
753                                 TRACKNAME=$(grep ^TTITLE$CDDBTRACKNUM= "$CDDBDATA" | head -n 1 | cut -f2 -d= | tr -d \[:cntrl:\])
754                                 splitvarious
755                                 TRACKFILE=$(mungefilename "$TRACKNAME")
756                                 ARTISTFILE=$(mungefilename "$TRACKARTIST")
757                                 # If we want to start the tracks with a given number, we need to modify the
758                                 # TRACKNUM value before evaluation
759                                 if [ -n $STARTTRACKNUMBER ] ; then
760                                         # Get the trackpadding from the current track
761                                         CURRENTTRACKPADDING=$(echo -n $UTRACKNUM | wc -c)
762                                         TRACKNUM=$( printf %0.${CURRENTTRACKPADDING}d $(expr ${UTRACKNUM} + ${STARTTRACKNUMBER} - 1 ))
763                                 else
764                                         TRACKNUM=${UTRACKNUM}
765                                 fi
766                                 if [ "$VARIOUSARTISTS" = "y" ]; then
767                                         OUTPUTFILE=$(eval echo $VAOUTPUTFORMAT)
768                                 else
769                                         OUTPUTFILE=$(eval echo $OUTPUTFORMAT)
770                                 fi
771                                 if [ "$VARIOUSARTISTS" = "y" ]; then
772                                         if [ "$VAPLAYLISTDATAPREFIX" ] ; then
773                                                 echo ${VAPLAYLISTDATAPREFIX}$OUTPUTFILE.$OUTPUT >> "$OUTPUTDIR/$PLAYLISTFILE"
774                                         else
775                                                 relpath "$PLAYLISTFILE", "$OUTPUTFILE.$OUTPUT" >> "$OUTPUTDIR/$PLAYLISTFILE"
776                                         fi
777                                 else
778                                         if [ "$PLAYLISTDATAPREFIX" ]; then
779                                                 echo ${PLAYLISTDATAPREFIX}$OUTPUTFILE.$OUTPUT >> "$OUTPUTDIR/$PLAYLISTFILE"
780                                         else
781                                                 relpath "$PLAYLISTFILE", "$OUTPUTFILE.$OUTPUT" >> "$OUTPUTDIR/$PLAYLISTFILE"
782                                         fi
783                                 fi
784                         done
785                 fi
786                 ## this will convert the playlist to have CRLF line-endings, if specified
787                 ## (some hardware players insist on CRLF endings)
788                 if [ "$DOSPLAYLIST" = "y" ]; then
789                         awk '{substr("\r",""); printf "%s\r\n", $0}' "$OUTPUTDIR/$PLAYLISTFILE" > "$ABCDETEMPDIR/PLAYLISTFILE.tmp"
790 #                       mv -f "$ABCDETEMPDIR/PLAYLISTFILE.tmp" "$OUTPUTDIR/$PLAYLISTFILE"
791                         cat "$ABCDETEMPDIR/PLAYLISTFILE.tmp" | sed 's/\//\\/' > "$OUTPUTDIR/$PLAYLISTFILE"
792                 fi
793                 echo "playlistcomplete" >> "$ABCDETEMPDIR/status"
794         done
795 }
796
797 # do_discid
798 # This essentially the start of things
799 do_discid ()
800 {
801         # Query the CD to get the track info, unless the user specified -C
802         # or we are using some actions which do not need the CDDB data at all
803         #if [ ! X"$EXPACTIONS" = "X" ]; then
804         #       :
805         #elif [ -z "$DISCID" ]; then
806         if [ -z "$DISCID" ]; then
807                 vecho -n "Getting CD track info... "
808                 TRACKINFO=$($CDDISCID $CDROM)
809                 # Make sure there's a CD in there by checking cd-discid's return code
810                 if [ "$?" = "1" ]; then
811                         echo "abcde error: CD could not be read. Perhaps there's no CD in the drive?" >&2
812                         exit 1
813                 fi
814                 WEHAVEACD=y
815         else
816                 TRACKINFO=$(cat "$WAVOUTPUTDIR/abcde.$DISCID/discid")
817         fi
818
819         # Get a full enumeration of tracks, sort it, and put it in the TRACKQUEUE.
820         # This needs to be done now because a section of the resuming code will need
821         # it later.
822
823         # get the number of digits to pad TRACKNUM with - we'll use this later
824         # a CD can only hold 99 tracks, but since we support a feature for starting
825         # numbering the tracks from a given number, we might need to set it as a
826         # variable for the user to define... or obtain it somehow.
827         if [ "$PADTRACKS" = "y" ] ; then
828                 TRACKNUMPADDING=2
829         fi
830
831         ABCDETEMPDIR="$WAVOUTPUTDIR/abcde.$(echo $TRACKINFO | cut -f1 -d' ')"
832         if [ -z "$TRACKQUEUE" ]; then
833                 if [ ! "$STRIPDATATRACKS" = "y" ]; then
834                         case "$CDROMREADERSYNTAX" in
835                                 cdparanoia|debug)
836                                         if [ "$WEHAVEACD" = "y" ]; then
837                                                 vecho "Querying the CD for audio tracks..."
838                                                 TRACKS=$( $CDROMREADER -Q 2>&1 | egrep '^[[:space:]]+[[:digit:]]' | tail -n 1 |  awk '{print $1}' | tr -d "." | tr '\n' ' ' )
839                                                 CDPARANOIAAUDIOTRACKS="$TRACKS"
840                                         else
841                                                 if [ -f "$ABCDETEMPDIR/status" ] && checkstatus cdparanoia-audio-tracks ; then
842                                                         TRACKS=$( cat $ABCDETEMPDIR/cdparanoia-audio-tracks )
843                                                 else
844                                                         TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
845                                                 fi
846                                         fi
847                                         ;;
848                                 *)      TRACKS=$(echo $TRACKINFO | cut -f2 -d' ') ;;
849                         esac
850                 else
851                         TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
852                 fi
853                 echo -n "Grabbing entire CD - tracks: "
854                 if [ ! "$PADTRACKS" = "y" ] ; then
855                         TRACKNUMPADDING=$(echo -n $TRACKS | wc -c | tr -d ' ')
856                 fi
857                 TRACKS=$(printf "%0.${TRACKNUMPADDING}d" $TRACKS)
858                 X=0
859                 while [ "$X" -ne "$TRACKS" ]
860                 do
861                         X=$(printf "%0.${TRACKNUMPADDING}d" $(expr $X + 1))
862                         TRACKQUEUE=$(echo "$TRACKQUEUE" $X)
863                 done
864                 echo $TRACKQUEUE
865         else
866                 TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
867                 # User-supplied track queue.
868                 # Weed out non-numbers, whitespace, then sort and weed out duplicates
869                 TRACKQUEUE=$(echo $TRACKQUEUE | sed 's-[^0-9 ]--g' | tr ' ' '\n' | grep -v ^$ | sort -n | uniq | tr '\n' ' ' | sed 's- $--g')
870                 # Once cleaned, obtain the highest value in the trackqueue for number padding
871                 for LASTTRACK in $TRACKQUEUE; do :; done
872                 if [ ! "$PADTRACKS" = "y" ] ; then
873                         TRACKNUMPADDING=$(echo -n $LASTTRACK | wc -c | tr -d ' ')
874                 fi
875                 # Now we normalize the trackqueue
876                 for TRACK in $TRACKQUEUE ; do
877                         TRACKNUM=$(printf %0.${TRACKNUMPADDING}d $(expr ${TRACK} + 0 ))
878                         PADTRACKQUEUE=$(echo $PADTRACKQUEUE $TRACKNUM)
879                 done
880                 TRACKQUEUE=$PADTRACKQUEUE
881                 echo Grabbing tracks: "$TRACKQUEUE"
882         fi
883
884 #       for LASTTRACK in $TRACKQUEUE; do :; done
885
886         QUEUEDTRACKS=$(echo $TRACKQUEUE | wc -w | tr -d ' ')
887
888         # We have the discid, create a temp directory after it to store all the temp
889         # info
890
891         if [ -e "$ABCDETEMPDIR" ]; then
892                 echo -n "abcde: attempting to resume from $ABCDETEMPDIR"
893                 # It already exists, see if it's a directory
894                 if [ ! -d "$ABCDETEMPDIR" ]; then
895                         # This is a file/socket/fifo/device/etc, not a directory
896                         # Complain and exit
897                         echo >&2
898                         echo "abcde: file $ABCDETEMPDIR already exists and does not belong to abcde." >&2
899                         echo "Please investigate, remove it, and rerun abcde." >&2
900                         exit 1
901                 fi
902                 echo -n .
903                 # It's a directory, let's see if it's owned by us
904                 if [ ! -O "$ABCDETEMPDIR" ]; then
905                         # Nope, complain and exit
906                         echo >&2
907                         echo "abcde: directory $ABCDETEMPDIR already exists and is not owned by you." >&2
908                         echo "Please investigate, remove it, and rerun abcde." >&2
909                         exit 1
910                 fi
911                 echo .
912                 # See if it's populated
913                 if [ ! -f "$ABCDETEMPDIR/discid" ]; then
914                         # Wipe and start fresh
915                         echo "abcde: $ABCDETEMPDIR/discid not found. Abcde must remove and recreate" >&2
916                         echo -n "this directory to continue. Continue? [y/n] (n)" >&2
917                         if [ "$INTERACTIVE" = "y" ]; then
918                                 read ANSWER
919                         else
920                                 echo y >&2
921                                 ANSWER=y
922                         fi
923                         if [ "$ANSWER" != "y" ]; then
924                                 exit 1
925                         fi
926                         rm -rf "$ABCDETEMPDIR" || exit 1
927                         mkdir "$ABCDETEMPDIR"
928                         if [ "$?" -gt "0" ]; then
929                                 # Directory already exists or could not be created
930                                 echo "abcde: Temp directory $ABCDETEMPDIR could not be created." >&2
931                                 exit 1
932                         fi
933                 else
934                         # Everything is fine. Check for ^encodetracklocation-
935                         # and encode-output entries in the status file and
936                         # remove them. These are not relevant across sessions.
937                         if [ -f "$ABCDETEMPDIR/status" ]; then
938                                 mv "$ABCDETEMPDIR/status" "$ABCDETEMPDIR/status.old"
939                                 grep -v ^encodetracklocation- < "$ABCDETEMPDIR/status.old" \
940                                         | grep -v ^encode-output > "$ABCDETEMPDIR/status"
941                         fi
942                         # Remove old error messages
943                         if [ -f "$ABCDETEMPDIR/errors" ]; then
944                                 rm -f "$ABCDETEMPDIR/errors"
945                         fi
946                 fi
947         else
948                 # We are starting from scratch
949                 mkdir "$ABCDETEMPDIR"
950                 if [ "$?" -gt "0" ]; then
951                         # Directory already exists or could not be created
952                         echo "abcde: Temp directory $ABCDETEMPDIR could not be created." >&2
953                         exit 1
954                 fi
955                 cat /dev/null > "$ABCDETEMPDIR/status"
956         fi
957         
958         # If we got the CDPARANOIA status and it is not recorded, save it now
959         ## FIXME ## ! is non-portable
960         if [ -n "$CDPARANOIAAUDIOTRACKS" ] && ! checkstatus cdparanoia-audio-tracks; then
961                 if echo "$CDPARANOIAAUDIOTRACKS" >> "$ABCDETEMPDIR/cdparanoia-audio-tracks"; then
962                         echo "cdparanoia-audio-tracks" >> "$ABCDETEMPDIR/status"
963                 fi
964         fi
965         
966         # Create the discid file
967         echo "$TRACKINFO" > "$ABCDETEMPDIR/discid"
968
969         # Determine what actions are to be done from $ACTIONS and set the
970         # following environment variables for them:
971         DOCDDB=n
972         DOREAD=n
973         DONORMALIZE=n
974         DOPREPROCESS=n
975         DOENCODE=n
976         DOPOSTPROCESS=n
977         DOTAG=n
978         DOMOVE=n
979         DOPLAYLIST=n
980         DOCLEAN=n
981
982         for ACTION in $(echo $ACTIONS | tr , \ )
983         do
984                 case $ACTION in
985                 cddb) DOCDDB=y;;
986                 read) DOREAD=y;;
987                 normalize) DONORMALIZE=y; DOREAD=y;;
988                 preprocess) DOPREPROCESS=y; DOREAD=y;;
989                 encode) DOENCODE=y; DOREAD=y;;
990                 postprocess) DOPREPROCESS=y; DOENCODE=y; DOREAD=y;;
991                 tag) DOTAG=y; DOREAD=y; DOENCODE=y; DOCDDB=y;;
992                 move) DOMOVE=y; DOTAG=y; DOREAD=y; DOENCODE=y; DOCDDB=y;;
993                 playlist) DOCDDB=y; DOPLAYLIST=y;;
994                 clean) DOCLEAN=y;;
995                 esac
996         done
997 }
998
999 # do_cddbparse
1000 # Parses a CDDB file and outputs the title and the track names.
1001 # Variables: CDDBFILE
1002 do_cddbparse ()
1003 {
1004         CDDBPARSEFILE="$1"
1005         # List out disc title/author and contents
1006         if [ "$ONETRACK" = "y" ]; then
1007                 vecho "ONETRACK mode selected: displaying only the title of the CD..."
1008         fi
1009         echo "---- $(grep DTITLE "${CDDBPARSEFILE}" | cut '-d=' -f2- | tr -d \\r\\n ) ----"
1010         if [ ! "$ONETRACK" = "y" ]; then
1011                 for TRACK in $(f_seq_row 1 $TRACKS)
1012                 do
1013                         echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "${CDDBPARSEFILE}" | cut -f2- -d= | tr -d \\r\\n)"
1014                 done
1015         fi
1016 }
1017
1018 # do_localcddb
1019 # Check for a local CDDB file, and report success
1020 do_localcddb ()
1021 {
1022         if checkstatus cddb-readcomplete && checkstatus cddb-choice >/dev/null; then :; else
1023         
1024                 CDDBLOCALSUCCESS="n"
1025                 CDDBDISCID=$(echo $TRACKINFO | cut -d' ' -f1)
1026                 CDDBLOCALFILE="${CDDBLOCALDIR}/${CDDBDISCID}"
1027                 USELOCALRESP="y"
1028                 
1029                 # If the user has selected to check a local CDDB repo, we proceed with it
1030                 if [ -r "${CDDBLOCALFILE}" ]; then
1031                         # List out disc title/author and contents
1032                         do_cddbparse "${CDDBLOCALFILE}"
1033                         echo -n "Locally cached CDDB entry found, use it? [y/n] (y): "
1034                         if [ "$INTERACTIVE" = "y" ]; then
1035                                 read USELOCALRESP
1036                                 while [ "$USELOCALRESP" != "y" ] && [ "$USELOCALRESP" != "n" ] && [ "$USELOCALRESP" != "" ] ; do
1037                                         echo -n 'Invalid selection. Please answer "y" or "n": '
1038                                         read USELOCALRESP
1039                                 done
1040                                 [ x"$USELOCALRESP" = "x" ] && USELOCALRESP="y"
1041                         else
1042                                 echo "y" >&2
1043                         fi
1044                         if [ "$USELOCALRESP" = "y" ]; then
1045                         #echo "Using local copy of CDDB data"
1046                                 cp "${CDDBLOCALFILE}" "$ABCDETEMPDIR/cddbread.1"
1047                                 echo 999 > "$ABCDETEMPDIR/cddbquery" # Assuming 999 isn't used by CDDB
1048                                 echo cddb-readcomplete >> "$ABCDETEMPDIR/status"
1049                                 do_cddbparse "${CDDBLOCALFILE}" > "$ABCDETEMPDIR/cddbchoices"
1050                                 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1051                                 CDDBLOCALSUCCESS="y"
1052                         else
1053                                 #echo "Not using local copy of CDDB data"
1054                                 CDDBLOCALSUCCESS="n"
1055                         fi
1056                 elif [ "$FORCECDDBUSELOCAL" = "y" ]; then
1057                         $CDDBTOOL template $(cat "$ABCDETEMPDIR/discid") > "$ABCDETEMPDIR/cddbread.0"
1058                         echo 998 > "$ABCDETEMPDIR/cddbquery" # Assuming 998 isn't used by CDDB
1059                         echo cddb-readcomplete >> "$ABCDETEMPDIR/status"
1060                         do_cddbparse "${CDDBLOCALFILE}" > "$ABCDETEMPDIR/cddbchoices"
1061                         echo cddb-choice=0 >> "$ABCDETEMPDIR/status"
1062                         CDDBLOCALSUCCESS="y"
1063                 else
1064                         CDDBLOCALSUCCESS="n"
1065                 fi
1066         fi
1067 }
1068
1069 # do_cddbstat
1070 do_cddbstat ()
1071 {
1072         # Perform CDDB protocol version check if it hasn't already been done
1073         if checkstatus cddb-statcomplete; then :; else
1074                 if [ "$CDDBAVAIL" = "n" ]; then
1075                         ERRORCODE=no_query
1076                         echo 503 > "$ABCDETEMPDIR/cddbstat"
1077                 else
1078                         rc=1
1079                         CDDBUSER=$(echo $HELLOINFO | cut -f1 -d'@')
1080                         CDDBHOST=$(echo $HELLOINFO | cut -f2- -d'@')
1081                         while test $rc -eq 1 -a $CDDBPROTO -ge 3; do
1082                                 vecho "Checking CDDB server status..."
1083                                 $CDDBTOOL stat $CDDBURL $CDDBUSER $CDDBHOST $CDDBPROTO > "$ABCDETEMPDIR/cddbstat"
1084                                 RESPONSECODE=$(head -n 1 "$ABCDETEMPDIR/cddbstat" | cut -f1 -d' ')
1085                                 case "$RESPONSECODE" in
1086                                 210)    # 210 OK, status information follows (until terminating `.')
1087                                         rc=0;
1088                                         ;;
1089                                 501|*)  # 501 Illegal CDDB protocol level: <n>. 
1090                                         CDDBPROTO=`expr $CDDBPROTO - 1`
1091                                         ;;
1092                                 esac 
1093                         done
1094                         if test $rc -eq 1; then
1095                                 CDDBAVAIL="n" 
1096                         fi
1097                 fi
1098                 echo cddb-statcomplete >> "$ABCDETEMPDIR/status"
1099         fi
1100 }
1101
1102
1103 # do_cddbquery
1104 do_cddbquery ()
1105 {
1106         CDDBDISCID=$(echo $TRACKINFO | cut -d' ' -f1)
1107         CDDBLOCALFILE="${CDDBLOCALDIR}/${CDDBDISCID}"
1108         
1109         # Perform CDDB query if it hasn't already been done
1110         if checkstatus cddb-querycomplete; then :; else
1111                 if [ "$CDDBAVAIL" = "n" ]; then
1112                         ERRORCODE=no_query
1113                         echo 503 > "$ABCDETEMPDIR/cddbquery"
1114                 # The default CDDBLOCALSUCCESS is "n"
1115                 # This part will be triggered if the user CDDB repo does not 
1116                 # contain the entry, or if we are not trying to use the repo.
1117                 else
1118                         vecho "Querying the CDDB server..."
1119                         CDDBUSER=$(echo $HELLOINFO | cut -f1 -d'@')
1120                         CDDBHOST=$(echo $HELLOINFO | cut -f2- -d'@')
1121                         $CDDBTOOL query $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $TRACKINFO > "$ABCDETEMPDIR/cddbquery"
1122                         ERRORCODE=$?
1123                         case $ERRORCODE in
1124                                 0)  # success
1125                                 ;;
1126                                 12|13|14)
1127                                         # no match found in database,
1128                                         # wget/fetch error, or user requested not to use CDDB
1129                                         # Make up an error code (503) that abcde
1130                                         # will recognize in do_cddbread
1131                                         # and compensate by making a template
1132                                         echo 503 > "$ABCDETEMPDIR/cddbquery"
1133                                 ;;
1134                                 *) # strange and unknown error
1135                                         echo ERRORCODE=$ERRORCODE
1136                                         echo "abcde: $CDDBTOOL returned unknown error code"
1137                                 ;;
1138                         esac
1139                 fi
1140                 echo cddb-querycomplete >> "$ABCDETEMPDIR/status"
1141         fi
1142 }
1143
1144 # do_cddbread
1145 do_cddbread ()
1146 {
1147         # If it's not to be used, generate a template.
1148         # Then, display it (or them) and let the user choose/edit it
1149         if checkstatus cddb-readcomplete; then :; else
1150                 vecho "Obtaining CDDB results..."
1151                 # If CDDB is to be used, interpret the query results and read all
1152                 # the available entries.
1153                 rm -f "$ABCDETEMPDIR/cddbchoices"
1154                 CDDBCHOICES=1 # Overridden by multiple matches
1155                 RESPONSECODE=$(head -n 1 "$ABCDETEMPDIR/cddbquery" | cut -f1 -d' ')
1156                 case "$RESPONSECODE" in
1157                 200)
1158                         # One exact match, retrieve it
1159                         # 200 [section] [discid] [artist] / [title]
1160                         if checkstatus cddb-read-1-complete; then :; else
1161                                 echo -n "Retrieving 1 CDDB match..." >> "$ABCDETEMPDIR/cddbchoices"
1162                                 $CDDBTOOL read $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $(cut -f2,3 -d' ' "$ABCDETEMPDIR/cddbquery") > "$ABCDETEMPDIR/cddbread.1"
1163                                 echo "done." >> "$ABCDETEMPDIR/cddbchoices"
1164                                 echo cddb-read-1-complete >> "$ABCDETEMPDIR/status"
1165                                 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1166                         fi
1167                         # List out disc title/author and contents
1168                         echo ---- "$(cut '-d ' -f4- "$ABCDETEMPDIR/cddbquery")" ---- >> "$ABCDETEMPDIR/cddbchoices"
1169                         for TRACK in $(f_seq_row 1 $TRACKS)
1170                         do
1171                                 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.1" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1172                         done
1173                         echo >> "$ABCDETEMPDIR/cddbchoices"
1174                         ;;
1175                 202|403|409|503)
1176                         # No match
1177                         case "$RESPONSECODE" in
1178                         202) echo "No CDDB match." >> "$ABCDETEMPDIR/cddbchoices" ;;
1179                         403|409) echo "CDDB entry is corrupt, or the handshake failed." >> "$ABCDETEMPDIR/cddbchoices" ;;
1180                         503) echo "CDDB unavailable." >> "$ABCDETEMPDIR/cddbchoices" ;;
1181                         esac
1182                         $CDDBTOOL template $(cat "$ABCDETEMPDIR/discid") > "$ABCDETEMPDIR/cddbread.0"
1183                         # List out disc title/author and contents of template
1184                         echo ---- Unknown Artist / Unknown Album ---- >> "$ABCDETEMPDIR/cddbchoices"
1185                         UNKNOWNDISK=y
1186                         for TRACK in $(f_seq_row 1 $TRACKS)
1187                         do
1188                                 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.0" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1189                         done
1190                         echo >> "$ABCDETEMPDIR/cddbchoices"
1191                         echo cddb-read-0-complete >> "$ABCDETEMPDIR/status"
1192                         echo cddb-choice=0 >> "$ABCDETEMPDIR/status"
1193                         ;;
1194                 210|211)
1195                         # Multiple exact, (possibly multiple) inexact matches
1196                         IN=
1197                         if [ "$RESPONSECODE" = "211" ]; then IN=in; fi
1198                         if [ "$(wc -l < $ABCDETEMPDIR/cddbquery | tr -d ' ')" -eq 3 ]; then
1199                                 echo "One ${IN}exact match:" >> "$ABCDETEMPDIR/cddbchoices"
1200                                 tail -n +2 "$ABCDETEMPDIR/cddbquery" | head -n 1 >> "$ABCDETEMPDIR/cddbchoices"
1201                                 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1202                         else
1203                                 echo "Multiple ${IN}exact matches:" >> "$ABCDETEMPDIR/cddbchoices"
1204                         fi
1205                         vecho -n "Retrieving multiple matches... "
1206                         grep -v ^[.]$ "$ABCDETEMPDIR/cddbquery" | ( X=0
1207                         read DISCINFO # eat top line
1208                         while read DISCINFO
1209                         do
1210                                 X=$(expr $X + 1)
1211                                 if checkstatus cddb-read-$X-complete; then :; else
1212                                         $CDDBTOOL read $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $(echo $DISCINFO | cut -f1,2 -d' ') > "$ABCDETEMPDIR/cddbread.$X"
1213                                         echo cddb-read-$X-complete >> "$ABCDETEMPDIR/status"
1214                                 fi
1215                                 # List out disc title/author and contents
1216                                 echo \#$X: ---- "$DISCINFO" ---- >> "$ABCDETEMPDIR/cddbchoices"
1217                                 for TRACK in $(f_seq_row 1 $TRACKS)
1218                                 do
1219                                         echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.$X" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1220                                 done
1221                                 echo >> "$ABCDETEMPDIR/cddbchoices"
1222                         done )
1223                         vecho "done."
1224                         CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
1225                         ;;
1226                 999)
1227                         # Using local copy.
1228                         for TRACK in $(f_seq_row 1 $TRACKS)
1229                         do
1230                                 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.1" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1231                         done
1232                         echo >> "$ABCDETEMPDIR/cddbchoices"
1233                         echo cddb-read-1-complete >> "$ABCDETEMPDIR/status"
1234                         echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1235                         ;;
1236                 esac    
1237                 echo "cddb-readcomplete" >> "$ABCDETEMPDIR/status"
1238         fi
1239 }
1240
1241 # do_cddbedit
1242 do_cddbedit ()
1243 {
1244         if checkstatus cddb-edit >/dev/null; then
1245                 CDDBDATA="$ABCDETEMPDIR/cddbread.$(checkstatus cddb-choice)"
1246                 VARIOUSARTISTS="$(checkstatus variousartists)"
1247                 VARIOUSARTISTSTYLE="$(checkstatus variousartiststyle)"
1248                 return 0
1249         fi
1250         if [ "$INTERACTIVE" = "y" ]; then
1251                 # We should show the CDDB results both when we are not using the local CDDB repo
1252                 # or when we are using it but we could not find a proper match
1253                 if [ "$CDDBUSELOCAL" = "y" ] && [ ! "$CDDBLOCALSUCCESS" = "y" ] || [ ! "$CDDBUSELOCAL" = "y" ]; then
1254                         # Display the $ABCDETEMPDIR/cddbchoices file created above
1255                         # Pick a pager so that if the tracks overflow the screen the user can still view everything
1256                         if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
1257                                 CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
1258                                 CHOICE=$(checkstatus cddb-choice)
1259                                 if [ -n "$CHOICE" ] ; then
1260                                         case $CDDBCHOICES in
1261                                                 1) cat "$ABCDETEMPDIR/cddbchoices" ;;
1262                                                 *)
1263                                                 echo "Selected: #$CHOICE"
1264                                                 do_cddbparse "$ABCDETEMPDIR/cddbread.$CHOICE"
1265                                                 ;;
1266                                         esac
1267                                 else
1268                                         # The user has a choice to make, display the info in a pager if necessary
1269                                         if [ $(cat "$ABCDETEMPDIR/cddbchoices" | wc -l) -ge 24 ]; then
1270                                                 # Use the debian sensible-pager wrapper to pick the pager
1271                                                 # user has requested via their $PAGER environment variable
1272                                                 if [ -x "/usr/bin/sensible-pager" ]; then
1273                                                         /usr/bin/sensible-pager "$ABCDETEMPDIR/cddbchoices"
1274                                                 elif [ -x "$PAGER" ]; then
1275                                                         # That failed, try to load the preferred editor, starting
1276                                                         # with their PAGER variable
1277                                                         $PAGER "$ABCDETEMPDIR/cddbchoices"
1278                                                         # If that fails, check for less
1279                                                 elif [ -x /usr/bin/less ]; then
1280                                                         /usr/bin/less -f "$ABCDETEMPDIR/cddbchoices"
1281                                                         # more should be on all UNIX systems
1282                                                 elif [ -x /bin/more ]; then
1283                                                         /bin/more "$ABCDETEMPDIR/cddbchoices"
1284                                                 else
1285                                                         # No bananas, just cat the thing
1286                                                         cat "$ABCDETEMPDIR/cddbchoices" >&2
1287                                                 fi
1288                                         else
1289                                                 # It's all going to fit in one page, cat it
1290                                                 cat "$ABCDETEMPDIR/cddbchoices" >&2
1291                                         fi
1292                                         
1293                                         # I'll take CDDB read #3 for $400, Alex
1294                                         echo -n "Which entry would you like abcde to use (0 for none)? [0-$CDDBCHOICES]: " >&2
1295                                         read CDDBCHOICE
1296                                         # Make sure we get a valid choice
1297                                         CDCHOICENUM=$(echo $CDDBCHOICE | xargs printf %d 2>/dev/null)
1298                                         while [ $CDCHOICENUM -lt 0 ] || [ $CDCHOICENUM -gt $CDDBCHOICES ]; do
1299                                                 echo "Invalid selection. Please choose a number between 1 and $CDDBCHOICES." >&2
1300                                                 echo -n "Selection [0-$CDDBCHOICES]: " >&2
1301                                                 read CDDBCHOICE
1302                                                 CDCHOICENUM=$(echo $CDDBCHOICE | xargs printf %d 2>/dev/null)
1303                                         done
1304                                         if [ "$CDCHOICENUM" = "0" ]; then
1305                                                 vecho "Creating empty CDDB template..."
1306                                                 UNKNOWNDISK=y
1307                                                 $CDDBTOOL template $(cat "$ABCDETEMPDIR/discid") > $ABCDETEMPDIR/cddbread.0
1308                                         else
1309                                                 echo "Selected: #$CDCHOICENUM ($(grep ^DTITLE= $ABCDETEMPDIR/cddbread.$CDCHOICENUM | cut -f2- -d= | tr -d \\r\\n))" >&2
1310                                                 do_cddbparse "$ABCDETEMPDIR/cddbread.$CDCHOICENUM"
1311                                         fi
1312                                         echo "cddb-choice=$CDCHOICENUM" >> "$ABCDETEMPDIR/status"
1313                                 fi
1314                         fi
1315                 else
1316                         # We need some code to show the selected option when local repository is selected and we have found a match
1317                         vecho "Using cached CDDB match..." >&2
1318                         # Display the $ABCDETEMPDIR/cddbchoices file created above
1319                         # Pick a pager so that if the tracks overflow the screen the user can still view everything
1320                         if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
1321                                 CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
1322                                 CHOICE=$(checkstatus cddb-choice)
1323                                 if [ "$USELOCALRESP" = "y" ]; then :; else
1324                                         if [ -n "$CHOICE" ] ; then
1325                                                 case $CDDBCHOICES in
1326                                                         0) 
1327                                                         UNKNOWNDISK=y
1328                                                         echo "Selected template."
1329                                                         ;;
1330                                                         1) cat "$ABCDETEMPDIR/cddbchoices" ;;
1331                                                         *)
1332                                                         echo "Selected: #$CHOICE"
1333                                                         do_cddbparse "$ABCDETEMPDIR/cddbread.$CHOICE"
1334                                                         ;;
1335                                                 esac
1336                                         fi
1337                                 fi
1338                         fi
1339                 fi
1340         else
1341                 # We're noninteractive - pick the first choice.
1342                 # But in case we run a previous instance and selected a choice, use it.
1343                 if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
1344                         # Show the choice if we are not using the locally stored one
1345                         # or when the local search failed to find a match.
1346                         PREVIOUSCHOICE=$(checkstatus cddb-choice)
1347                         if [ "$CDDBUSELOCAL" = "y" ] && [ "$CDDBLOCALSUCCESS" = "n" ] || [ ! "$CDDBUSELOCAL" = "y" ]; then
1348                                 #if [ "$PREVIOUSCHOICE" ]; then
1349                                         cat "$ABCDETEMPDIR/cddbchoices"
1350                                 #fi
1351                         fi
1352                         if [ ! -z "$PREVIOUSCHOICE" ] ; then
1353                                 CDCHOICENUM=$PREVIOUSCHOICE
1354                         else
1355                                 CDCHOICENUM=1
1356                                 echo "cddb-choice=$CDCHOICENUM" >> "$ABCDETEMPDIR/status"
1357                         fi
1358                         echo "Selected: #$CDCHOICENUM ($(grep ^DTITLE= $ABCDETEMPDIR/cddbread.$CDCHOICENUM | cut -f2- -d= | tr -d \\r\\n))" >&2
1359                 fi
1360         fi
1361
1362         # sanity check
1363         if checkstatus cddb-choice >/dev/null; then :; else
1364                 echo "abcde: internal error: cddb-choice not recorded." >&2
1365                 exit 1
1366         fi
1367         CDDBDATA="$ABCDETEMPDIR/cddbread.$(checkstatus cddb-choice)"
1368         echo -n "Edit selected CDDB data? [y/n] (" >&2
1369         if [ "$INTERACTIVE" = "y" ]; then
1370                 if [ "$UNKNOWNDISK" = "y" ]; then
1371                         echo -n "y): " >&2
1372                         read EDITCDDB
1373                         [ "$EDITCDDB" != "n" ] && EDITCDDB=y
1374                 else
1375                         echo -n "n): " >&2
1376                         read EDITCDDB
1377                 fi
1378         else
1379                 echo "n): n" >&2
1380                 EDITCDDB=n
1381         fi
1382         if [ "$EDITCDDB" = "y" ]; then
1383                 CDDBDATAMD5SUM=$($MD5SUM "$CDDBDATA" | cut -d " " -f 1);
1384                 
1385                 # Use the debian sensible-editor wrapper to pick the editor that the
1386                 # user has requested via their $EDITOR environment variable
1387                 if [ -x "/usr/bin/sensible-editor" ]; then
1388                         /usr/bin/sensible-editor "$CDDBDATA"
1389                 elif [ -n "$EDITOR" ]; then
1390                         if [ -x $(which "${EDITOR%%\ *}") ]; then
1391                                 # That failed, try to load the preferred editor, starting
1392                                 # with their EDITOR variable
1393                                 eval $(echo "$EDITOR") "$CDDBDATA"
1394                         fi
1395                 # If that fails, check for a vi
1396                 elif [ -x /usr/bin/vi ]; then
1397                         /usr/bin/vi "$CDDBDATA"
1398                 # nano should be on all (modern, i.e., sarge) debian systems
1399                 elif [ -x /usr/bin/nano ]; then
1400                         /usr/bin/nano "$CDDBDATA"
1401                 # mg should be on all OpenBSD systems
1402                 elif [ -x /usr/bin/mg ]; then
1403                         /usr/bin/mg "$CDDBDATA"
1404                 # bomb out
1405                 else
1406                         echo "No editor available. Check your EDITOR environment variable." >&2
1407                 fi
1408                 # delete editor backup file if it exists
1409                 if [ -w "$CDDBDATA~" ]; then
1410                         rm -f "$CDDBDATA~"
1411                 fi
1412         fi
1413
1414         # Some heuristics first. Look at Disc Title, and if it starts with
1415         # "Various", then we'll assume Various Artists
1416         if [ "$(grep ^DTITLE= "$CDDBDATA" | cut -f2 -d= | egrep -ci '^(various|soundtrack|varios|sonora|ost)')" != "0" ]; then
1417                 echo "Looks like a Multi-Artist CD" >&2
1418                 VARIOUSARTISTS=y
1419         else
1420                 echo -n "Is the CD multi-artist? [y/n] (n): " >&2
1421                 if [ "$INTERACTIVE" = "y" ]; then
1422                         read VARIOUSARTISTS
1423                 else
1424                         echo n >&2
1425                         VARIOUSARTISTS=n
1426                 fi
1427         fi
1428         if [ "$VARIOUSARTISTS" = "y" ] && [ ! "$ONETRACK" = "y" ]; then
1429                 # Set a default
1430                 DEFAULTSTYLE=1
1431                 # Need NUMTRACKS before cddb-tool will return it:
1432                 NUMTRACKS=$(egrep '^TTITLE[0-9]+=' "$CDDBDATA" | wc -l)
1433                 if [ "$(grep -c "^TTITLE.*\/" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
1434                         # More than 1/2 tracks contain a "/", so guess forward
1435                         DEFAULTSTYLE=1
1436                 elif [ "$(grep -c "^TTITLE.*\-" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
1437                         # More than 1/2 contain a "-", so guess forward-dash
1438                         DEFAULTSTYLE=2
1439                 elif [ "$(grep -c "^TTITLE.*(.*)" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
1440                         # More than 1/2 contain something in parens, so guess trailing-paren
1441                         DEFAULTSTYLE=6
1442                 fi
1443
1444                 echo "1) Artist / Title" >&2
1445                 echo "2) Artist - Title" >&2
1446                 echo "3) Title / Artist" >&2
1447                 echo "4) Title - Artist" >&2
1448                 echo "5) Artist: Title" >&2
1449                 echo "6) Title (Artist)" >&2
1450                 echo "7) This is a single-artist CD" >&2
1451                 echo -n "Which style of multiple artist entries is it? [1-7] ($DEFAULTSTYLE): " >&2
1452                 if [ "$INTERACTIVE" = "y" ]; then
1453                         read VARIOUSARTISTSTYLE
1454                 else
1455                         echo $DEFAULTSTYLE >&2
1456                         VARIOUSARTISTSTYLE=$DEFAULTSTYLE
1457                 fi
1458                 VARIOUSARTISTSTYLE=$(echo 0$VARIOUSARTISTSTYLE | xargs printf %d)
1459                 # If they press Enter, then the default style (0) was chosen
1460                 while [ $VARIOUSARTISTSTYLE -lt 0 ] || [ $VARIOUSARTISTSTYLE -gt 7 ]; do
1461                         echo "Invalid selection. Please choose a number between 1 and 7."
1462                         echo -n "Selection [1-7]: "
1463                         read VARIOUSARTISTSTYLE
1464                         VARIOUSARTISTSTYLE=$(echo 0$VARIOUSARTISTSTYLE | xargs printf %d)
1465                 done
1466                 if [ "$VARIOUSARTISTSTYLE" = "0" ]; then
1467                         VARIOUSARTISTSTYLE=$DEFAULTSTYLE
1468                 fi
1469                 vecho "Selected: $VARIOUSARTISTSTYLE"
1470                 case "$VARIOUSARTISTSTYLE" in
1471                 1) # Artist / Title
1472                         VARIOUSARTISTSTYLE=forward
1473                         ;;
1474                 2) # Artist - Title
1475                         VARIOUSARTISTSTYLE=forward-dash
1476                         ;;
1477                 3) # Title / Artist
1478                         VARIOUSARTISTSTYLE=reverse
1479                         ;;
1480                 4) # Title - Artist
1481                         VARIOUSARTISTSTYLE=reverse-dash
1482                         ;;
1483                 5) # Artist: Title
1484                         VARIOUSARTISTSTYLE=colon
1485                         ;;
1486                 6) # Title (Artist)
1487                         VARIOUSARTISTSTYLE=trailing-paren
1488                         ;;
1489                 7) # Single Artist
1490                         VARIOUSARTISTS=n
1491                         ;;
1492                 esac
1493         fi
1494
1495         echo "variousartists=$VARIOUSARTISTS" >> "$ABCDETEMPDIR/status"
1496         echo "variousartiststyle=$VARIOUSARTISTSTYLE" >> "$ABCDETEMPDIR/status"
1497
1498         if [ "$EDITCDDB" = "y" ] && [ "$UNINTENTIONALLY_ANGER_THE_FREEDB_PEOPLE" = "y" ]; then
1499                 if [ $CDDBDATAMD5SUM != "" ]  && [ $CDDBDATAMD5SUM != $($MD5SUM "$CDDBDATA" | cut -d " " -f 1) ]; then
1500                         # This works but does not have the necessary error checking
1501                         # yet. If you are familiar with the CDDB spec
1502                         # (see http://www.freedb.org/src/latest/DBFORMAT) 
1503                         # and can create an error-free entry on your own, then put
1504                         # UNINTENTIONALLY_ANGER_THE_FREEDB_PEOPLE=y in your
1505                         # abcde.conf to enable it. Put CDDBSUBMIT=email@address in
1506                         # your abcde.conf to change the email address submissions are
1507                         # sent to.
1508
1509                         # submit the modified file, if they want
1510                         if [ "$NOSUBMIT" != "y" ]; then
1511                                 echo -n "Do you want to submit this entry to $CDDBSUBMIT? [y/n] (n): "
1512                                 read YESNO
1513                                 while [ "$YESNO" != "y" ] && [ "$YESNO" != "n" ] && [ "$YESNO" != "Y" ] && \
1514                                         [ "$YESNO" != "N" ] && [ "$YESNO" != "" ]
1515                                 do
1516                                         echo -n 'Invalid selection. Please answer "y" or "n": '
1517                                         read YESNO
1518                                 done
1519                                 if [ "$YESNO" = "y" ] || [ "$YESNO" = "Y" ]; then
1520                                         echo -n "Sending..."
1521                                         $CDDBTOOL send "$CDDBDATA" $CDDBSUBMIT
1522                                         echo "done."
1523                                 fi
1524                         fi
1525                 fi
1526         fi
1527         # Make sure the cache directory exists
1528         mkdir -p $CDDBLOCALDIR
1529         # Cache edited CDDB entry in the user's cddb dir
1530         if [ "$CDDBCOPYLOCAL" = "y" ] || [ "$COPYCDDBLOCAL" = "Y" ]; then
1531                 cat "$CDDBDATA" | tail -n $(expr $(cat "$CDDBDATA" | wc -l ) - 1 ) > ${CDDBLOCALDIR}/$(echo "$TRACKINFO" | cut -d' ' -f1)
1532         fi
1533
1534         echo "cddb-edit" >> "$ABCDETEMPDIR/status"
1535 }
1536
1537 # do_cdread_one [lasttrack] [firsttrack]
1538
1539 # Reads the CD in a single track. Live performances, concerts, mixes,... benefit from this.
1540 do_cdread_one ()
1541 {
1542         # The commands here don't go through run_command because they're never supposed to be silenced
1543         # return codes need to be doublechecked anyway, however
1544         LASTTRACKNUMBER=$1
1545         FIRSTTRACKNUMBER=$2
1546         WAVDATA="$ABCDETEMPDIR/track$FIRSTTRACKNUMBER.wav"
1547         echo "Grabbing the CD to a single track..." >&2
1548         case "$CDROMREADERSYNTAX" in
1549                 cdparanoia) nice $READNICE $CDROMREADER -d $CDROM "1-" "$WAVDATA" >&2 ;;
1550                 cdda2wav)
1551                         if [ "$OSFLAVOUR" = "OSX" ] ; then
1552                                 # Hei, we have to unmount the device before running anything like cdda2wav in OSX
1553                                 disktool -u ${CDROM#/dev/} 0
1554                                 # Also, in OSX the cdrom device for cdda2wav changes...
1555                                 CDDA2WAVCDROM="IODVDServices"
1556                         elif [ "$OSFLAVOUR" = "FBSD" ] ; then
1557                                 CDDA2WAVCDROM="$CDROMID"
1558                         else
1559                                 if [ "$CDROMID" = "" ]; then
1560                                         CDDA2WAVCDROM="$CDROM"
1561                                 else
1562                                         CDDA2WAVCDROM="$CDROMID"
1563                                 fi
1564                         fi
1565                         nice $READNICE $CDROMREADER -D $CDDA2WAVCDROM -t 1+$LASTTRACKNUM "$WAVDATA" >&2 
1566                         ;;
1567                 dagrab) nice $READNICE $CDROMREADER -d $CDROM -f $WAVDATA -v $UTRACKNUM >&2 ;;
1568                 cddafs)
1569                         # Find the track's mounted path
1570                         REALTRACKNUM=$(expr $UTRACKNUM + 0)
1571                         FILEPATH=$(mount | grep "$CDROM on" | sed 's/^[^ ]* on \(.*\) (.*/\1/')
1572                         FILEPATH=$(find "$FILEPATH" | grep "/$REALTRACKNUM ");
1573                         # If the file exists, copy it
1574                         if [ -e "$FILEPATH" ] ; then
1575                                 nice $READNICE $CDROMREADER "$FILEPATH" "$WAVDATA" >&2
1576                         else
1577                                 false
1578                         fi ;;
1579                 debug) nice $READNICE $CDROMREADER -d $CDROM -w $UTRACKNUM-[:1] "$WAVDATA" >&2 ;;
1580         esac
1581         RETURN=$?
1582         if [ "$RETURN" != "0" -o ! -s "$WAVDATA" ]; then
1583                 # Thank goodness errors is only machine-parseable up to the
1584                 # first colon, otherwise this woulda sucked
1585                 if [ "$RETURN" = "0" -a ! -s "$WAVDATA" ]; then
1586                         RETURN=73 # fake a return code as cdparanoia return 0 also on aborted reads
1587                 fi
1588                 echo "readtrack-$FIRSTTRACKNUMBER: $CDROMREADER returned code $RETURN" >> "$ABCDETEMPDIR/errors"
1589                 return $RETURN
1590         else
1591                 echo readtrack-$FIRSTTRACKNUMBER >> "$ABCDETEMPDIR/status"
1592         fi
1593 }
1594
1595 # do_cdread [tracknumber]
1596
1597 do_cdread ()
1598 {
1599         # The commands here don't go through run_command because they're never supposed to be silenced
1600         # return codes need to be doublechecked anyway, however
1601         UTRACKNUM=$1
1602         CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
1603         WAVDATA="$ABCDETEMPDIR/track$UTRACKNUM.wav"
1604         OUTDATA="$ABCDETEMPDIR/track$UTRACKNUM.$OUTPUTTYPE"
1605         if [ -r "$CDDBDATA" ]; then
1606                 TRACKNAME=$(grep ^TTITLE$CDDBTRACKNUM= "$CDDBDATA" | head -n 1 | cut -f2 -d= | tr -d \[:cntrl:\])
1607                 echo "Grabbing track $UTRACKNUM: $TRACKNAME..." >&2
1608         else
1609                 echo "Grabbing track $UTRACKNUM..." >&2
1610         fi
1611         case "$CDROMREADERSYNTAX" in
1612                 cdparanoia) nice $READNICE $CDROMREADER -d $CDROM $UTRACKNUM "$WAVDATA" >&2 ;;
1613                 cdda2wav)
1614                         if [ "$OSFLAVOUR" = "OSX" ] ; then
1615                                 # Hei, we have to unmount the device before running anything like cdda2wav in OSX
1616                                 disktool -u ${CDROM#/dev/} 0
1617                                 # Also, in OSX the cdrom device for cdda2wav changes...
1618                                 CDDA2WAVCDROM="IODVDServices"
1619                         elif [ "$OSFLAVOUR" = "FBSD" ] ; then
1620                                 CDDA2WAVCDROM="$CDROMID"
1621                         else
1622                                 if [ "$CDROMID" = "" ]; then
1623                                         CDDA2WAVCDROM="$CDROM"
1624                                 else
1625                                         CDDA2WAVCDROM="$CDROMID"
1626                                 fi
1627                         fi
1628                         nice $READNICE $CDROMREADER -D $CDDA2WAVCDROM -t $UTRACKNUM "$WAVDATA" >&2 
1629                         ;;
1630                 dagrab) nice $READNICE $CDROMREADER -d $CDROM -f $WAVDATA -v $UTRACKNUM >&2 ;;
1631                 cddafs)
1632                         # Find the track's mounted path
1633                         REALTRACKNUM=$(expr $UTRACKNUM + 0)
1634                         FILEPATH=$(mount | grep "$CDROM on" | sed 's/^[^ ]* on \(.*\) (.*/\1/')
1635                         FILEPATH=$(find "$FILEPATH" | grep "/$REALTRACKNUM ");
1636                         # If the file exists, copy it
1637                         if [ -e "$FILEPATH" ] ; then
1638                                 nice $READNICE $CDROMREADER "$FILEPATH" "$WAVDATA" >&2
1639                         else
1640                                 false
1641                         fi ;;
1642                 debug) nice $READNICE $CDROMREADER -d $CDROM -w $UTRACKNUM-[:1] "$WAVDATA" >&2 ;;
1643         esac
1644         RETURN=$?
1645         if [ "$RETURN" != "0" -o ! -s "$WAVDATA" ]; then
1646                 # Thank goodness errors is only machine-parseable up to the
1647                 # first colon, otherwise this woulda sucked
1648                 if [ "$RETURN" = "0" -a ! -s "$WAVDATA" ]; then
1649                         RETURN=73 # fake a return code as cdparanoia return 0 also on aborted reads
1650                 fi
1651                 echo "readtrack-$UTRACKNUM: $CDROMREADER returned code $RETURN" >> "$ABCDETEMPDIR/errors"
1652                 return $RETURN
1653         else
1654                 echo readtrack-$UTRACKNUM >> "$ABCDETEMPDIR/status"
1655         fi
1656 }
1657
1658 # do_cdspeed
1659 # No values accepted, only uses env variables
1660 do_cdspeed () 
1661 {
1662         if "$CDSPEED" "$CDSPEEDOPTS" "$CDSPEEDVALUE" >/dev/null ; then
1663                 vecho "Setting CD speed to ${CDSPEEDVALUE}x"
1664         else
1665                 echo "abcde: unable to set the device speed" >&2
1666         fi
1667 }
1668
1669 # vecho [message]
1670 #
1671 # vecho outputs a message if EXTRAVERBOSE is selected
1672 vecho ()
1673 {
1674 if [ x"$EXTRAVERBOSE" != "x" ]; then
1675         echo $@
1676 fi
1677 }
1678
1679 # Start of execution
1680
1681 # Builtin defaults
1682 CDDBURL="http://freedb.freedb.org/~cddb/cddb.cgi"
1683 CDDBSUBMIT=freedb-submit@freedb.org
1684 CDDBPROTO=5
1685 HELLOINFO="$(whoami)@$(hostname)"
1686 INTERACTIVE=y
1687 CDROMREADERSYNTAX=cdparanoia
1688 OUTPUTTYPE=ogg
1689 ENCODERSYNTAX=default
1690
1691 MP3ENCODERSYNTAX=default
1692 OGGENCODERSYNTAX=default
1693 FLACENCODERSYNTAX=default
1694 SPEEXENCODERSYNTAX=default
1695 MPPENCODERSYNTAX=default
1696 NORMALIZERSYNTAX=default
1697
1698 OUTPUTFORMAT='${ARTISTFILE}-${ALBUMFILE}/${TRACKNUM}.${TRACKFILE}'
1699 # Use the following VAOUTPUTFORMAT to revert to 2.0.x VA format:
1700 #VAOUTPUTFORMAT=${OUTPUTFORMAT}
1701 VAOUTPUTFORMAT='Various-${ALBUMFILE}/${TRACKNUM}.${ARTISTFILE}-${TRACKFILE}'
1702 ONETRACKOUTPUTFORMAT='${ARTISTFILE}-${ALBUMFILE}/${ALBUMFILE}'
1703 VAONETRACKOUTPUTFORMAT='Various-${ALBUMFILE}/${ALBUMFILE}'
1704 PLAYLISTFORMAT='${ARTISTFILE}-${ALBUMFILE}.${OUTPUT}.m3u'
1705 PLAYLISTDATAPREFIX=''
1706 VAPLAYLISTFORMAT='${ARTISTFILE}-${ALBUMFILE}.${OUTPUT}.m3u'
1707 VAPLAYLISTDATAPREFIX=''
1708 DOSPLAYLIST=n
1709 COMMENT=''
1710 ID3TAGV=2
1711 ENCNICE=10
1712 READNICE=10
1713 DISTMP3NICE=10
1714 VARIOUSARTISTS=n
1715 VARIOUSARTISTSTYLE=forward
1716 KEEPWAVS=n
1717 PADTRACKS=n
1718 CDDBCOPYLOCAL="n"
1719 CDDBLOCALDIR="$HOME/.cddb"
1720 CDDBUSELOCAL="n"
1721
1722 # If using scsi devices, cdda2wav needs a CDROMID, instead of a device node
1723 # i.e. CDROMID="1,0,0"
1724 CDROMID=""
1725
1726 # program paths - defaults to checking your $PATH
1727 # mp3
1728 LAME=lame
1729 GOGO=gogo
1730 BLADEENC=bladeenc
1731 L3ENC=l3enc
1732 XINGMP3ENC=xingmp3enc
1733 MP3ENC=mp3enc
1734 # ogg
1735 VORBIZE=vorbize
1736 OGGENC=oggenc
1737 # flac
1738 FLAC=flac
1739 # speex
1740 SPEEXENC=speexenc
1741 # mpp (Musepack)
1742 MPPENC=mppenc
1743
1744 ID3=id3
1745 ID3V2=id3v2
1746 CDPARANOIA=cdparanoia
1747 CDDA2WAV=cdda2wav
1748 DAGRAB=dagrab
1749 CDDAFS=cp
1750 CDDISCID=cd-discid
1751 CDDBTOOL=cddb-tool
1752 EJECT=eject
1753 MD5SUM=md5sum
1754 DISTMP3=distmp3
1755 VORBISCOMMENT=vorbiscomment
1756 METAFLAC=metaflac
1757 NORMALIZE=normalize-audio
1758 CDSPEED=eject
1759 VORBISGAIN=vorbisgain
1760
1761 # Options for programs called from abcde
1762 # mp3
1763 LAMEOPTS=
1764 GOGOOPTS=
1765 BLADEENCOPTS=
1766 L3ENCOPTS=
1767 XINGMP3ENCOPTS=
1768 MP3ENCOPTS=
1769 # ogg
1770 VORBIZEOPTS=
1771 OGGENCOPTS=
1772 # flac
1773 FLACOPTS=
1774 # speex
1775 SPEEXENCOPTS=
1776 # mpc
1777 MPPENCOPTS=
1778
1779 ID3OPTS=
1780 ID3V2OPTS=
1781 CDPARANOIAOPTS=
1782 CDDA2WAVOPTS=
1783 DAGRABOPTS=
1784 CDDAFSOPTS="-f"
1785 CDDBTOOLOPTS=
1786 EJECTOPTS=
1787 DISTMP3OPTS=
1788 NORMALIZEOPTS=
1789 CDSPEEDOPTS="-x"
1790 CDSPEEDVALUE=
1791
1792 # Default to one process if -j isn't specified
1793 MAXPROCS=1
1794
1795 # List of actions to perform - by default, run to completion
1796 ACTIONS=cddb,read,encode,tag,move,clean
1797
1798 # User-redefinable functions
1799 # Custom filename munging:
1800 mungefilename ()
1801 {
1802         echo "$@" | sed s,:,\ -,g | tr \ /\* __+ | tr -d \'\"\?\[:cntrl:\]
1803 }
1804
1805 # Custom genre munging:
1806 mungegenre ()
1807 {
1808         echo $CDGENRE | tr "[:upper:]" "[:lower:]"
1809 }
1810
1811 # pre_read
1812 # Empty pre_read function, to be defined in the configuration file.
1813 pre_read ()
1814 {
1815 :
1816 }
1817
1818 # Asume fetch if under FreeBSD. curl is used for Mac OS X. wget is used for Linux/OpenBSD/NetBSD.
1819 # Let's use these checkings to determine the OS flavour, which will be used later
1820 if [ X$(uname) = "XFreeBSD" ] ; then
1821         HTTPGET=fetch
1822         NEEDCDROMID=y
1823         OSFLAVOUR=FBSD
1824 elif [ X$(uname) = "XDarwin" ] ; then
1825         HTTPGET=curl
1826         OSFLAVOUR=OSX
1827         # We should have disktool in OSX, but let's be sure...
1828         NEEDDISKTOOL=y
1829 elif [ X$(uname) = "XOpenBSD" ] ; then
1830         HTTPGET=wget
1831         MD5SUM=md5
1832 else
1833         HTTPGET=wget
1834 fi
1835
1836 # If CDDBAVAIL is set to n, no CDDB read is done
1837 # If USEID3 is set to n, no ID3 tagging is done
1838 CDDBAVAIL=y
1839 USEID3=y
1840
1841 if [ -z "$OUTPUTDIR" ]; then
1842         OUTPUTDIR=$(pwd)
1843 fi
1844
1845 if [ -z "$WAVOUTPUTDIR" ]; then
1846         WAVOUTPUTDIR="$OUTPUTDIR"
1847 fi
1848
1849 # Load system defaults
1850 if [ -r /etc/abcde.conf ]; then
1851         . /etc/abcde.conf
1852 fi
1853 # Load user preference defaults
1854 if [ -r $HOME/.abcde.conf ]; then
1855         . $HOME/.abcde.conf
1856 fi
1857
1858 # By this time, we need some HTTPGETOPTS already defined.
1859 # If the user has defined its own, we should not be empty.
1860
1861 if [ "$HTTPGETOPTS" = "" ] ; then
1862         case $HTTPGET in
1863                 wget) HTTPGETOPTS="-q -O -";;
1864                 curl) HTTPGETOPTS="-f -s";;
1865                 fetch)HTTPGETOPTS="-q -o -";;
1866                 *) echo "abcde warning: HTTPGET in non-standard and HTTPGETOPTS are not defined." >&2 ;;
1867         esac
1868 fi
1869
1870 # If the CDROM has not been set yet, find a suitable one.
1871 # If this is a devfs system, default to /dev/cdroms/cdrom0
1872 # instead of /dev/cdrom
1873 if [ "$CDROM" = "" ] ; then
1874         if [ -e /dev/cdroms/cdrom0 ]; then
1875                 CDROM=/dev/cdroms/cdrom0
1876         elif [ -e /dev/cdrom ]; then
1877                 CDROM=/dev/cdrom
1878         elif [ -e /dev/cd0c ]; then
1879                 CDROM=/dev/cd0c
1880         elif [ -e /dev/acd0c ]; then
1881                 CDROM=/dev/acd0c
1882         elif [ -e /dev/disk1 ]; then
1883                 CDROM=/dev/disk1
1884         fi
1885 fi
1886
1887 # Parse command line options
1888 #while getopts 1a:bc:C:d:Dhj:klLnNo:pr:S:t:T:vVx opt ; do
1889 while getopts 1a:A:bc:C:d:Dfhj:klLnNo:pr:Rs:S:t:T:vVxw: opt ; do
1890         case "$opt" in
1891                 1) ONETRACK=y ;;
1892                 a) ACTIONS="$OPTARG" ;;
1893                 A) EXPACTIONS="$OPTARG";;
1894                 b) BATCH=y ;;
1895                 c) if [ -e "$OPTARG" ] ; then . "$OPTARG" ; else echo "abcde error: config file \"$OPTARG\" cannot be found." >&2 ; exit 1 ; fi ;;
1896                 C) DISCID="${OPTARG#abcde.}" ;;
1897                 d) CDROM="$OPTARG" ;;
1898                 D) set -x ;;
1899                 h) usage; exit ;;
1900                 f) FORCECDDBUSELOCAL=y ;;
1901                 i) INLINETAG=y ;;
1902                 j) MAXPROCS="$OPTARG" ;;
1903                 k) KEEPWAVS=y ;;
1904                 l) LOWDISK=y ;;
1905                 L) CDDBUSELOCAL="y" ;;
1906                 n) CDDBAVAIL="n" ;;
1907                 N) INTERACTIVE="n" ;;
1908                 m) DOSPLAYLIST=y ;;
1909                 o) OUTPUTTYPE="$OPTARG" ;;
1910                 p) PADTRACKS="y" ;;
1911                 r) REMOTEHOSTS="$OPTARG" ;;
1912                 R) REPLAYGAIN=y ;;
1913                 s) STARTTRACKNUMBER="$OPTARG" ;;
1914                 S) CDSPEEDVALUE="$OPTARG" ;;
1915 #               t) PREPROCESSFORMATS="$OPTARG"
1916 #                  PREPROCESS=y ;;
1917 #               T) POSTPROCESSFORMATS="$OPTARG" ;;
1918                 t) STARTTRACKNUMBER="$OPTARG" ;;
1919                 T) STARTTRACKNUMBER="$OPTARG" ; STARTTRACKNUMBERTAG="y" ;;
1920                 v) 
1921                    echo "This is abcde v$VERSION."
1922                    echo "Usage: abcde [options] [tracks]"
1923                    echo "abcde -h for extra help"
1924                    exit
1925                    ;;
1926                 V) EXTRAVERBOSE="y" ;;
1927                 x) EJECTCD="y" ;;
1928                 w) COMMENT="$OPTARG" ;;
1929                 ?) usage; exit ;;
1930         esac
1931 done
1932
1933 shift $(($OPTIND - 1))
1934
1935 # Decide if we can continue. TO_REMOVE as soon as we find out about dagrab
1936 if [ "$ONETRACK" = "y" ] ; then 
1937         case "$CDROMREADERSYNTAX" in
1938                 dagrab|debug) echo "abcde error: ONETRACK reading is not suported with "$CDROMREADERSYNTAX" yet"
1939                               exit 1 ;;
1940         esac
1941         if [ "$BATCH" = "y" ]; then
1942                 echo "abcde error: BATCH mode is not compatible with ONETRACK mode"
1943         fi
1944         # It does not matter how many tracks we want. In ONETRACK mode we grab them all
1945         if [ $# -gt 0 ]; then
1946                 vecho "ONETRACK mode selected: grabbing all tracks..."
1947         fi
1948 else
1949         while [ $# -gt 0 ]; do
1950                 # Range parsing code courtesy of Vincent Ho
1951                 RSTART=$(echo $1 | cut -f1 -d-)
1952                 REND=$(echo $1 | cut -f2 -d-)
1953                 if [ "$RSTART" = "$REND" ]; then
1954                         NEWTRACKS="$RSTART"
1955                 else
1956                         NEWTRACKS=$(f_seq_line $RSTART $REND)
1957                 fi
1958                 TRACKQUEUE=$(echo "$TRACKQUEUE" "$NEWTRACKS")
1959                 shift
1960         done
1961 fi
1962
1963 # At this point a CDROM has to be defined, so we check it exists.
1964 if [ "$CDROM" != "" ] ; then 
1965         if [ "$CDROMREADERSYNTAX" = "cdda2wav" ] && [ "$NEEDCDROMID" = "y" ] ; then
1966                 if [ "$OSFLAVOUR" = "FBSD" ]; then
1967                         if ! echo "$CDROMID" | grep "^[0-9],[0-9],[0-9]$" >/dev/null 2>&1 ; then
1968                                 echo "abcde error: CDROMID not in the right format for $CDROMREADERSYNTAX"
1969                                 echo "Use \"cdrecord -scanbus\" to obtain a adecuate ID an set CDROMID accordingly"
1970                                 exit 1
1971                         fi
1972                 fi
1973         elif [ ! -e $CDROM ] ; then
1974                 echo "abcde error: CDROM device cannot be found." >&2
1975                 exit 1
1976         fi
1977 else
1978         echo "abcde error: CDROM has not been defined or cannot be found" >&2
1979         exit 1
1980 fi
1981
1982 # Decide which CDROM reader we're gonna use
1983 case "$CDROMREADERSYNTAX" in
1984         cdparanoia|debug)
1985                 CDROMREADER="$CDPARANOIA"
1986                 CDROMREADEROPTS="$CDPARANOIAOPTS"
1987                 ;;
1988         cdda2wav)
1989                 CDROMREADER="$CDDA2WAV"
1990                 CDROMREADEROPTS="$CDDA2WAVOPTS"
1991                 ;;
1992         dagrab)
1993                 CDROMREADER="$DAGRAB"
1994                 CDROMREADEROPTS="$DAGRABOPTS"
1995                 ;;
1996         cddafs)
1997                 CDROMREADER="$CDDAFS"
1998                 CDROMREADEROPTS="$CDDAFSOPTS"
1999                 ;;
2000 esac
2001
2002 # There's only one normalize...
2003 case "$NORMALIZERSYNTAX" in
2004         default|normalize)
2005                 NORMALIZER="$NORMALIZE"
2006                 NORMALIZEROPTS="$NORMALIZEOPTS"
2007                 ;;
2008 esac
2009
2010 # If nothing has been specified, use oggenc for oggs and lame for mp3s and flac for flacs and speexenc for speex and mppenc for mpps
2011
2012 # Getting ready for multiple output changes
2013 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
2014 do
2015         case $OUTPUT in
2016                 ogg)  [ "$OGGENCODERSYNTAX" = "default" ] && OGGENCODERSYNTAX=oggenc
2017                       echo $ACTIONS | grep tag > /dev/null 2>&1 && NEEDCOMMENTER=y
2018                       if [ "$REPLAYGAIN" = "y" ]; then NEEDVORBISGAIN=y; fi
2019                         ;;
2020                 mp3)  [ "$MP3ENCODERSYNTAX" = "default" ] && MP3ENCODERSYNTAX=lame
2021                       echo $ACTIONS | grep tag > /dev/null 2>&1 && NEEDTAGGER=y
2022                         ;;
2023                 flac) [ "$FLACENCODERSYNTAX" = "default" ] && FLACENCODERSYNTAX=flac
2024                       echo $ACTIONS | grep tag > /dev/null 2>&1 && NEEDMETAFLAC=y
2025                         ;;
2026                 spx) [ "$SPEEXENCODERSYNTAX" = "default" ] && SPEEXENCODERSYNTAX=speexenc ;;
2027                 mpc) [ "$MPPENCODERSYNTAX" = "default" ] && MPPENCODERSYNTAX=mppenc ;;
2028                 *) echo "abcde error: Invalid OUTPUTTYPE defined" >&2
2029                    exit 1
2030                    ;;
2031         esac
2032 done
2033
2034 # decide which encoder
2035 case "$MP3ENCODERSYNTAX" in
2036         lame)
2037                 MP3ENCODEROPTS="$LAMEOPTS"
2038                 MP3ENCODER="$LAME"
2039                 ;;
2040         gogo)
2041                 MP3ENCODEROPTS="$GOGOOPTS"
2042                 MP3ENCODER="$GOGO"
2043                 ;;
2044         bladeenc)
2045                 MP3ENCODEROPTS="$BLADEENCOPTS"
2046                 MP3ENCODER="$BLADEENC"
2047                 ;;
2048         l3enc)
2049                 MP3ENCODEROPTS="$L3ENCOPTS"
2050                 MP3ENCODER="$L3ENC"
2051                 ;;
2052         xingmp3enc)
2053                 MP3ENCODEROPTS="$XINGMP3ENCOPTS"
2054                 MP3ENCODER="$XINGMP3ENC"
2055                 ;;
2056         mp3enc)
2057                 MP3ENCODEROPTS="$MP3ENCOPTS"
2058                 MP3ENCODER="$MP3ENC"
2059                 ;;
2060 esac
2061 case "$OGGENCODERSYNTAX" in
2062         vorbize)
2063                 OGGENCODEROPTS="$VORBIZEOPTS"
2064                 OGGENCODER="$VORBIZE"
2065                 ;;
2066         oggenc)
2067                 OGGENCODEROPTS="$OGGENCOPTS"
2068                 OGGENCODER="$OGGENC"
2069                 ;;
2070 esac
2071 case "$FLACENCODERSYNTAX" in
2072         flac)
2073                 FLACENCODEROPTS="$FLACOPTS"
2074                 FLACENCODER="$FLAC"
2075                 ;;
2076 esac
2077 case "$SPEEXENCODERSYNTAX" in
2078         speexenc)
2079                 SPEEXENCODEROPTS="$SPEEXENCOPTS"
2080                 SPEEXENCODER="$SPEEXENC"
2081                 ;;
2082 esac
2083 case "$MPPENCODERSYNTAX" in
2084         mppenc)
2085                 MPPENCODEROPTS="$MPPENCOPTS"
2086                 MPPENCODER="$MPPENC"
2087                 ;;
2088 esac
2089
2090 # and which tagger
2091
2092 if [ "$ID3TAGV" = "1" ]; then
2093         TAGGER="$ID3"
2094         TAGGEROPTS="$ID3OPTS"
2095 else
2096         TAGGER="$ID3V2"
2097         TAGGEROPTS="$ID3V2OPTS"
2098 fi
2099
2100 # Clean up nice options (either use '-n NICELEVEL or -NICELEVEL')
2101
2102 if [ "$ENCNICE" ]; then
2103         ENCNICE="-n $ENCNICE"
2104 fi
2105 if [ "$READNICE" ]; then
2106         READNICE="-n $READNICE"
2107 fi
2108 if [ "$DISTMP3NICE" ]; then
2109         DISTMP3NICE="-n $DISTMP3NICE"
2110 fi
2111
2112 # Don't check for stuff if it's not needed
2113 if [ "$REMOTEHOSTS" ]; then NEEDDISTMP3=y; fi
2114 if echo $ACTIONS | grep normalize > /dev/null 2>&1 ; then NEEDNORMALIZER=y; fi
2115 if [ "$EJECTCD" = "y" ]; then NEEDEJECT=y; fi
2116 if echo $ACTIONS | grep cddb > /dev/null 2>&1 ; then NEEDHTTPGET=y ; fi
2117
2118 if [ X"$CDSPEEDVALUE" != "X" ]; then
2119         case "$CDROMREADERSYNTAX" in
2120                 cdparanoia|debug) CDROMREADEROPTS="$CDPARANOIAOPTS -S $CDSPEEDVALUE" ;;
2121                 *) NEEDCDSPEED=y ;;
2122         esac
2123 fi
2124
2125
2126 # Make sure a buncha things exist
2127 for X in $CDROMREADER $CDDISCID ${NEEDTAGGER+$TAGGER} $MP3ENCODER \
2128         $OGGENCODER $FLACENCODER $SPEEXENCODER $MPPENCODER \
2129         ${NEEDHTTPGET+$HTTPGET} ${NEEDDISTMP3+$DISTMP3} \
2130         ${NEEDCOMMENTER+$VORBISCOMMENT} ${NEEDMETAFLAC+$METAFLAC} \
2131         ${NEEDNORMALIZER+$NORMALIZER} ${NEEDEJECT+$EJECT} \
2132         ${NEEDDISKTOOL+disktool} ${NEEDCDSPEED+$CDSPEED} \
2133         ${NEEDVORBISGAIN+$VORBISGAIN}
2134 do
2135         # Cut off the command-line options we just added in
2136         X=$(echo $X | cut -d' ' -f2)
2137         if [ "$(which $X)" = "" ]; then
2138                 echo "abcde error: $X is not in your path." >&2
2139                 exit 1
2140         elif [ ! -x $(which $X) ]; then
2141                 echo "abcde error: $X is not executable." >&2
2142                 exit 1
2143         fi
2144 done
2145
2146 CDROMREADER="$CDROMREADER $CDROMREADEROPTS"
2147 CDDBTOOL="$CDDBTOOL $CDDBTOOLOPTS"
2148 HTTPGET="$HTTPGET $HTTPGETOPTS"
2149
2150 # Here it used to say:
2151 # One thousand lines in, we can start doing stuff with things
2152 # Well, right now we are at line 2139 ;)
2153
2154 # List of valid actions: cddb,read,normalize,encode,tag,playlist,move,clean
2155 # List of experimental actions: retag,transcode
2156
2157 # Export needed things so they can be read in this subshell
2158 export CDDBTOOL ABCDETEMPDIR TRACKQUEUE LOWDISK EJECTCD EJECT EJECTOPTS
2159 export CDROM CDDBDATA REMOTEHOSTS MAXPROCS HTTPGET MD5SUM
2160
2161 # User-definable function to set some things. Use it for
2162 #  - closing the CD tray with eject -t
2163 #  - set the CD speed value with eject -x
2164 vecho -n "Executing customizable pre-read function... "
2165
2166 pre_read # Execute the user-defined pre-read funtion. Close the CD with it.
2167
2168 vecho "done."
2169
2170 do_discid # Get ABCDETEMPDIR created and status file initialized
2171
2172 if [ "$DOCDDB" = "y" ]; then
2173         if [ $CDDBUSELOCAL = "y" ]; then
2174                 do_localcddb
2175         fi
2176         ## FIXME ## ! is non-portable
2177         if ! checkstatus cddb-choice > /dev/null && [ ! "$CDDBLOCALSUCCESS" = "y" ] ; then
2178                 do_cddbstat
2179                 do_cddbquery
2180                 do_cddbread
2181         fi
2182         do_cddbedit
2183
2184         eval $($CDDBTOOL parse "$CDDBDATA")
2185 fi
2186
2187 # Before reading tracks, we set the speed of the device
2188
2189 if [ X"$CDSPEEDVALUE" != "X" ]; then
2190         case "$CDROMREADERSYNTAX" in
2191                 cdparanoia|debug) : ;;
2192                 *) do_cdspeed ;;
2193         esac
2194 fi
2195
2196 if [ "$STRIPDATATRACKS" = "y" ] && [ ! "$ONETRACK" = "y" ]; then
2197         case "$CDROMREADERSYNTAX" in
2198                 cdparanoia|debug) 
2199                         # cdparanoia can query the CD, so let's process the TRACKQUEUE list with the results.
2200                         if checkstatus cdparanoia-audio-tracks; then
2201                                 CDTRACKQUEUE=$( cat $ABCDETEMPDIR/cdparanoia-audio-tracks )
2202                         else
2203                                 ## FIXME ##
2204                                 vecho "Querying the CD to obtain a list of valid audio tracks..."
2205                                 $CDROMREADER -Q > $ABCDETEMPDIR/cdparanoia-query 2>&1
2206                                 # Obtain a list of valid audio tracks from the results of the query
2207                                 CDTRACKQUEUE=$( cat $ABCDETEMODIR/cdparanoia- | egrep '^[[:space:]]+[[:digit:]]' | awk '{print $1}' | tr -d "." | tr '\n' ' ' )
2208                         fi
2209                         # Obtain the track padding value from the before-processing list and pad the CD list
2210                         TRACKNUMPADDING=$( echo $TRACKQUEUE | awk '{print $1}' | tr -d " \n" | wc -c )
2211                         for TRACK in $CDTRACKQUEUE ; do
2212                                 TRACKNUM=$(printf %0.${TRACKNUMPADDING}d $(expr ${TRACK} + 0 ))
2213                                 PADNEWTRACKQUEUE=$(echo $PADNEWTRACKQUEUE $TRACKNUM)
2214                         done
2215                         CDTRACKQUEUE=$PADNEWTRACKQUEUE
2216                         # Now, compare if the values in the list are valid tracks in the CD
2217                         for TRACK in $TRACKQUEUE; do
2218                                 if echo $CDTRACKQUEUE | grep $TRACK >/dev/null ; then
2219                                         NEWTRACKQUEUE="$NEWTRACKQUEUE $TRACK"
2220                                 fi
2221                         done
2222                         TRACKQUEUE="$NEWTRACKQUEUE"
2223                 ;;
2224         esac
2225 fi
2226
2227 # Create playlist if needed (backgroundable) and start reading in tracks
2228
2229 (
2230
2231 if [ "$ONETRACK" = "y" ]; then :; else
2232         if [ "$DOPLAYLIST" = "y" ]; then
2233                 echo Creating playlist... >&2
2234                 do_playlist
2235         fi
2236 fi
2237
2238 # For the lowdisk option, only one program is running at once so the encoder
2239 # can be unsilenced right away.
2240 if [ "$LOWDISK" = "y" ] || [ "$ONETRACK" = "y" ]; then
2241         echo "encode-output=loud" >> "$ABCDETEMPDIR/status"
2242 fi
2243
2244 if [ "$ONETRACK" = "y" ]; then 
2245         FIRSTTRACK=$( echo $TRACKQUEUE | awk '{print $1}' )
2246         TRACKS="$FIRSTTRACK"
2247         for UTRACKNUM in $TRACKQUEUE; do :;done
2248         if checkstatus readtrack-$FIRSTTRACK; then :; else
2249                 do_cdread_one $UTRACKNUM $FIRSTTRACK
2250         fi
2251 else
2252         for UTRACKNUM in $TRACKQUEUE
2253         do
2254                 if [ "$DOREAD" = "y" ]; then
2255                         if checkstatus readtrack-$UTRACKNUM; then :; else
2256                                 do_cdread $UTRACKNUM
2257                                 if [ "$?" != "0" ]; then
2258                                         # CD read failed - don't give the goahead to
2259                                         # the encoder
2260                                         echo NO
2261                                         exit
2262                                 fi
2263                         fi
2264                 fi
2265                 if [ "$BATCH" = "y" ]; then
2266                     :
2267                 else
2268                         echo NEXTTRACK # Get the encoder machine churning again
2269                         if [ "$DOREAD" = "y" ]; then
2270                                 if [ "$LOWDISK" = "y" ] && [ "$DOENCODE" = "y" ]; then
2271                                         until checkstatus encodetrack-$UTRACKNUM
2272                                         do
2273                                                 if checkerrors encodetrack-$UTRACKNUM; then
2274                                                         break
2275                                                 fi
2276                                                 sleep 2
2277                                         done
2278                                 fi
2279                         fi
2280                 fi
2281         done
2282 fi
2283
2284 # Now that we're done the encoding can be loud again -
2285 # if we're not using SMP.
2286 if [ "$MAXPROCS" = "1" ]; then
2287         echo "encode-output=loud" >> "$ABCDETEMPDIR/status"
2288 fi
2289
2290 # All tracks read, start encoding.
2291 if [ "$BATCH" = "y" ] || [ "$ONETRACK" = "y" ]; then
2292         echo NEXTTRACK
2293 fi
2294
2295 # We are now finished with the cdrom - it can be safely ejected. Note that
2296 # abcde will not have completed yet.
2297 if [ "$EJECTCD" = "y" ] && [ -x $(which $EJECT) ]; then
2298         # We check if the disk we are processing is actually the disk inside the 
2299         # CD tray. If not, we do not eject the CD, since it might be so that the
2300         # user ejected it manually.
2301         #CURRENTTRACKINFO=$($CDDISCID $CDROM)
2302         #if if [ "$?" != "1" ] && [ "$CURRENTTRACKINFO" = "$TRACKINFO" ] ; then 
2303         # More FreeBSD bits.
2304         if [ X"$(uname)" = X"FreeBSD" ] ; then
2305                 # FreeBSD eject uses the EJECT environment variable to name the CDROM
2306                 # but in this script EJECT is in the envionment and names the program
2307                 eject=$EJECT
2308                 unset EJECT
2309                 # The FreeBSD eject needs "adc0" not "/dev/adc0c"
2310                 cd="$(echo $CDROM | sed -e 's=.*/==;s=[a-h]$==;')"
2311                 $eject $EJECTOPTS $cd
2312         elif [ X"$(uname)" = X"Darwin" ] ; then
2313                 disktool -e ${CDROM#/dev/} 0
2314         else
2315                 $EJECT $EJECTOPTS $CDROM
2316         fi
2317         #fi
2318 fi
2319
2320 ) | (
2321
2322 ## Do we need to pre-process 
2323 #if [ x"$PREPROCESS" = "x" ] ; then
2324 #       cat
2325 #else
2326 #       for PRETRACKNUM in $TRACKQUEUE
2327 #       do
2328 #               read GOAHEAD
2329 #               if [ "$GOAHEAD" = "NO" ]; then break; fi
2330 #               PREPROCEED=
2331 #               until [ $PREPROCEED ]
2332 #               do
2333 #                       if checkstatus readtrack-$PRETRACKNUM; then PREPROCEED=y; break; fi
2334 #                       # all locations are working, wait and try again later
2335 #                       if [ ! $PREPROCEED ]; then sleep 3; fi
2336 #               done
2337 #               ( do_preprocess $PRETRACKNUM 
2338 #               echo "NEXTTRACK"
2339 #               ) &
2340 #       done
2341 #fi
2342 #
2343 #) | (
2344
2345 # In batch mode, we want all tracks to be read first.
2346 if [ "$BATCH" = "y" ]; then
2347         read GOAHEAD # For blocking - will contain either "NO" or "NEXTTRACK"
2348         if [ "$GOAHEAD" = "NO" ]; then break; fi
2349         for LASTTRACK in $TRACKQUEUE; do :; done
2350         if checkstatus readtrack-$LASTTRACK; then
2351                 if [ "$DONORMALIZE" = "y" ]; then
2352                         if checkstatus normalizetrack-$LASTTRACK; then :; else do_batch_normalize; fi
2353                         if checkerrors batch-normalize; then exit; fi
2354                 fi
2355                 if [ "$DOENCODE" = "y" ]; then
2356                         if checkstatus encodetrack-$LASTTRACK; then :; else do_batch_encode; fi
2357                         if checkerrors batch-encode; then exit; fi
2358                 fi
2359         fi
2360 fi
2361
2362 # If we are using ONETRACK, we can proceed with the normal encoding using just the $FIRSTTRACK as TRACKQUEUE
2363 if [ "$ONETRACK" = "y" ] ; then
2364         FIRSTTRACK=$( echo $TRACKQUEUE | awk '{print $1}')
2365         TRACKQUEUE=$FIRSTTRACK
2366         TRACKS="$FIRSTTRACK"
2367 fi
2368
2369 # Do the encoding, including parallelization of remote encoding
2370 # Figure out where each track is going to be encoded
2371 ENCODELOCATIONS="$(echo $REMOTEHOSTS | tr , ' ')"
2372 if [ "$MAXPROCS" != "0" ]; then
2373         for NUM in $(f_seq_row 1 "$MAXPROCS")
2374         do
2375                 ENCODELOCATIONS="$ENCODELOCATIONS %local$NUM%"
2376         done
2377 fi
2378 # Strip whitespace
2379 ENCODELOCATIONS=$(echo $ENCODELOCATIONS)
2380 for UTRACKNUM in $TRACKQUEUE
2381 do
2382         # Wait for our cue
2383         read GOAHEAD # For blocking - will contain either "NO" or "NEXTTRACK"
2384         if [ "$GOAHEAD" = "NO" ]; then break; fi
2385         # find out where this track is to be encoded
2386         if [ "$DOENCODE" = "y" ]; then
2387                 # Make sure we have a place to encode this, if not, exit stage right
2388                 if [ -z "$ENCODELOCATIONS" ]; then
2389                         continue
2390                 fi
2391                 PROCEED=
2392                 until [ $PROCEED ]
2393                 do
2394                         for LOCATION in $ENCODELOCATIONS
2395                         do
2396                                 PREVIOUSTRACK="$(checkstatus encodetracklocation-$LOCATION)"
2397                                 # check first if a track has ever been assigned to this location
2398                                 if [ -z "$PREVIOUSTRACK" ]; then PROCEED=y; break; fi
2399                                 # If it errored out, rebuild $ENCODELOCATIONS without this location in it
2400                                 if checkerrors encodetrack-$PREVIOUSTRACK; then
2401                                         for TEMPLOCATION in $ENCODELOCATIONS
2402                                         do
2403                                                 if [ "$TEMPLOCATION" != "$LOCATION" ]; then
2404                                                         TEMPENCODELOCATIONS="$TEMPENCODELOCATIONS $TEMPLOCATION"
2405                                                 fi
2406                                         done
2407                                         ENCODELOCATIONS=$(echo $TEMPENCODELOCATIONS)
2408                                         ABORT=y
2409                                         PROCEED=y
2410                                         break
2411                                 fi
2412                                 # We're still here, this location must have been previously assigned,
2413                                 # and last completed without error - check if it's done with the
2414                                 # previous track yet
2415                                 if checkstatus encodetrack-$PREVIOUSTRACK; then PROCEED=y; break; fi
2416                         done
2417                         # all locations are working, wait and try again later
2418                         if [ ! $PROCEED ]; then sleep 3; fi
2419                 done
2420                 # Record the location we're about to encode the next track at
2421                 echo "encodetracklocation-$LOCATION=$UTRACKNUM" >> "$ABCDETEMPDIR/status"
2422         fi
2423         # Don't proceed with the rest of the loop if we can't encode
2424         if [ "$ABORT" ]; then continue; fi
2425         # Set TRACKNUM, TRACKNAME
2426         if [ -e "$CDDBDATA" ]; then
2427                 if [ "$ONETRACK" = "y" ]; then 
2428                         TRACKNAME="$DALBUM"
2429                         TRACKNUM="$FIRSTTRACK"
2430                         splitvarious
2431                 else
2432 #                       TRACKNUM=$(printf %0.${TRACKNUMPADDING}d $(expr ${UTRACKNUM} + 0))
2433                         TRACKNUM=$UTRACKNUM
2434                         CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
2435                         TRACKNAME=$(grep ^TTITLE$CDDBTRACKNUM= "$CDDBDATA" | head -n 1 | cut -f2 -d= | tr -d \[:cntrl:\])
2436                         splitvarious
2437                 fi
2438         fi
2439         # You can't encode a file which needs to be normalized before finishing
2440         # You can't tag a file before it's finished encoding -
2441         # thus all of this is backgrounded together
2442         (
2443         if [ "$DONORMALIZE" = "y" ]; then
2444                 if checkstatus readtrack-$UTRACKNUM; then
2445                         if checkstatus normalizetrack-$UTRACKNUM; then :; else do_normalize $UTRACKNUM; fi
2446                 fi
2447         fi
2448         if [ "$DOENCODE" = "y" ]; then
2449                 if checkstatus readtrack-$UTRACKNUM; then
2450                         #if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION; fi
2451                         if [ "$DONORMALIZE" = "y" ]; then
2452                                 if checkstatus normalizetrack-$UTRACKNUM; then
2453                                         if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION $OUTPUT; fi
2454                                 fi
2455                         else
2456                                 if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION $OUTPUT; fi
2457                         fi
2458                 fi
2459         fi
2460         if [ "$DOTAG" = "y" ]; then
2461                 if checkstatus encodetrack-$UTRACKNUM; then
2462                         if checkstatus tagtrack-$UTRACKNUM; then :; else do_tag $UTRACKNUM; fi
2463                 fi
2464         fi
2465         if [ "$DOMOVE" = "y" ]; then
2466                 if checkstatus tagtrack-$UTRACKNUM; then
2467                         if checkstatus movetrack-$UTRACKNUM; then :; else do_move $UTRACKNUM; fi
2468                 fi
2469         fi
2470         ) &
2471 done
2472 # Go through it again and make sure there's no distmp3 stragglers, otherwise
2473 # we'll delete the files they're working on
2474 if [ "$DOENCODE" = "y" ]; then
2475         PROCEED=
2476         until [ $PROCEED ]
2477         do
2478                 PROCEED=y
2479                 for LOCATION in $ENCODELOCATIONS
2480                 do
2481                         CHECKTRACK="$(checkstatus encodetracklocation-$LOCATION)"
2482                         # "How can he give us a status update, if he's DEAD?"
2483                         if checkstatus encodetrack-$CHECKTRACK; then
2484                                 continue
2485                         fi
2486                         # Nothing to see here please go quietly back to your homes
2487                         if [ -z "$CHECKTRACK" ]; then continue; fi
2488                         # You're still here? Maybe there is something...
2489                         if checkstatus encodetrack-$CHECKTRACK; then :; else PROCEED= ; break; fi
2490                 done
2491                 # hold up
2492                 if [ ! $PROCEED ]; then sleep 5; fi
2493         done
2494 fi
2495 # If the above didn't catch the stragglers, this will
2496 wait
2497 # Check to see if run_command logged any errors
2498 if [ -f "$ABCDETEMPDIR/errors" ]; then
2499         echo "The following commands failed to run:"
2500         cat "$ABCDETEMPDIR/errors"
2501         # Don't clean up
2502         DOCLEAN=n
2503 fi
2504 if [ "$KEEPWAVS" = "y" ];then
2505         # Don't clean up
2506         DOCLEAN=n
2507 fi
2508 if [ "$DOCLEAN" = "y" ]; then
2509         # Wipe all the evidence
2510         # Gimme gimme gimme some more time!
2511         sleep 5
2512         rm -rf "$ABCDETEMPDIR"
2513         echo "Finished."
2514 else
2515         echo "Finished. Not cleaning $ABCDETEMPDIR."
2516 fi
2517 )
2518 exit 0