Fix bug in parsing the output from freedb.
[zcdrip] / zcdrip.in
1 #!/bin/zsh
2
3 ## Copyright (C) 2006 - 2011 Steve Youngs
4
5 ## Author:        Steve Youngs <steve@steveyoungs.com>
6 ## Maintainer:    Steve Youngs <steve@steveyoungs.com>
7 ## Created:       <2006-08-08>
8 ## Time-stamp:    <Sunday Jun 19, 2011 16:47:17 steve>
9
10 ## Redistribution and use in source and binary forms, with or without
11 ## modification, are permitted provided that the following conditions
12 ## are met:
13 ##
14 ## 1. Redistributions of source code must retain the above copyright
15 ##    notice, this list of conditions and the following disclaimer.
16 ##
17 ## 2. Redistributions in binary form must reproduce the above copyright
18 ##    notice, this list of conditions and the following disclaimer in the
19 ##    documentation and/or other materials provided with the distribution.
20 ##
21 ## 3. Neither the name of the author nor the names of any contributors
22 ##    may be used to endorse or promote products derived from this
23 ##    software without specific prior written permission.
24 ##
25 ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
26 ## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 ## DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 ## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 ## SUBSTITUTE GOODS OR SERVICES# LOSS OF USE, DATA, OR PROFITS# OR
32 ## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 ## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
34 ## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
35 ## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37 ### Commentary:
38 ## 
39 ##    Ease the process of ripping audio CDs to .mp3 or .ogg.  See
40 ##    help (zcdrip -h) for full details.
41 ##
42
43 ### Todo:
44 ##    
45 ##    o Partial album ripping.  Specify track numbers or a range of
46 ##      track numbers to only rip/encode those tracks.
47 ##
48 ##    o Ripping from music DVDs
49 ##
50
51 ### Bugs:
52 ##
53 ##    Bugs?  What bugs?  Seriously though, if you find any, let me
54 ##    know.
55 ##
56
57 # Debug
58 [[ -n $DEBUG ]] && set -x; zdebug=${TMPPREFIX}/zdebug
59
60 ### Code:
61 ourname=${0##*/}
62
63 # Version info.
64 VERSION=@VERSION@
65 COPYRIGHT="Copyright (C) 2006 - 2011 Steve Youngs <steve@steveyoungs.com>"
66
67 version_str="${ourname}: ${VERSION}
68 ${COPYRIGHT}"
69
70 _version () { echo $version_str }
71
72 # Help
73 usage ()
74 {
75     # If you use eshell you will have a problem displaying this help.
76     # This is the only part of the script that eshell has a problem
77     # with, but if you really want to be able to view this help in
78     # eshell, create a symlink and call it `ecdrip'.
79
80     [[ ${LINES} -lt 70 && $TERM != dumb ]] && _doc=${PAGER:-less} || _doc=cat
81     [[ $ourname == ecdrip ]] && _doc=cat
82     $_doc<<EOF
83
84                                $ourname
85          ${VERSION}
86
87
88 Synopsis:
89 --------
90
91   $ourname 
92         [ -moi ] [ --mp3 | --ogg ] [ -r FILE ] [ --interactive | --rcfile=FILE ]
93         [ -a ALBUM ] [ --album=ALBUM ] [ -s ARTIST ] [ --sameartist=ARTIST ]
94         [ -t ENCODING_TYPE ] [ --type=ENCODING_TYPE ] [ -f | --flac_copy ]
95         [ -e FILE | --edit_rcfile=FILE ] [ -O | --online ] [ -d DIR | --dir=DIR ]
96         [ -p PLAYLISTFILE | --playlist=PLAYLISTFILE ]
97   $ourname 
98         [ -h | --help ]
99   $ourname
100         [ -V | --version ]
101
102 Description:
103 -----------
104
105   $ourname is a "frontend" to the process of ripping audio (cdda) CDs
106   to a hard disk and encoding the audio tracks to either MP3 format or
107   Ogg Vorbis format.
108
109   File names are auto-generated from track titles, with illegal
110   characters removed and spaces converted to underscores.
111
112   Track title, artist, and album names are added to the ID3 tags or
113   Vorbis comments header.
114
115 Options:
116 -------
117
118   -a ALBUM
119   --album=ALBUM
120         Specify the ALBUM name.  Argument ALBUM is _NOT_ optional.
121         Whitespace and punctuation is permitted, but you must protect
122         them from the shell.  If this option is omitted, the album
123         name will be prompted for.
124
125   -d DIR
126   --dir=DIR
127         Save encoded files to the directory, DIR.  If flac encoding
128         is also requested, see '--flac_copy' option below, the flac
129         files will be saved to DIR/flac.  If this option is omitted,
130         it defaults to 'PWD/ARTIST/ALBUM' the album name is first
131         converted to a sane filename.
132
133   -e FILE
134   --edit_rcfile=FILE
135         Edit/create rcfile, FILE, in an editor.  If the environment
136         variable EDITOR is not set, vi is used.  This implicitly sets
137         rcfile, see '--rcfile' option below.
138
139   -f
140   --flac_copy
141         In addition to encoding the CD audio tracks to MP3 or Ogg
142         Vorbis, create a FLAC audio file for archival purposes.
143
144   -h
145   --help
146         Display this help text and exit.
147
148   -i
149   --interactive
150         Prompt for track titles and artist names.
151
152   -m
153   --mp3
154         Specify MP3 encoding.
155
156   -o
157   --ogg
158         Specify Ogg Vorbis encoding.
159
160   -O
161   --online
162         Attempt to grab the track info from freedb.freedb.org.
163
164   -p PLAYLISTFILE
165   --playlist=PLAYLISTFILE
166         Write a playlist file to PLAYLISTFILE.  Argument PLAYLISTFILE
167         is _NOT_ optional, and should be given as the full path to the 
168         file.
169
170   -r FILE
171   --rcfile=FILE
172         Get track titles and artist names from FILE.  Argument FILE
173         is _NOT_ optional.  The format of FILE is:
174
175            Artist Name|Track Title
176
177         One "record" per line.  Whitespace and punctuation is permitted,
178         blank lines are not.  And there is no "comment" lines.
179
180   -s ARTIST
181   --sameartist=ARTIST
182         All tracks on the album are by the same ARTIST.  Argument
183         ARTIST is _NOT_ optional.
184
185   -t ENCODING_TYPE
186   --type=ENCODING_TYPE
187         This is an alternative to using the -m or -o options.
188         Use ENCODING_TYPE to encode the audio.  Valid values for
189         ENCODING_TYPE are "mp3", "ogg".
190
191   -V
192   --version
193         Display version info and exit.
194
195 Requirements:
196 ------------
197
198     zsh         http://www.zsh.org/  (mandatory)
199
200     cdparanoia  http://www.xiph.org/paranoia/
201                 For ripping the audio tracks from CD. (mandatory)
202
203     lame        http://www.mp3dev.org/
204                 For encoding to MP3 format. (optional if encoding to
205                 Ogg Vorbis)
206
207     oggenc      http://www.xiph.org/
208                 For encoding to Ogg Vorbis format (optional if encoding
209                 to MP3)
210
211     flac        http://flac.sourceforge.net/
212                 For additionally storing audio tracks in FLAC format.
213                 (optional)
214
215 Files:
216 -----
217
218     ${TMPPREFIX}/$ourname.log
219                 A log of the incoming TCP traffic from the CDDB server.
220                 This will be kept if debugging is turned on, otherwise
221                 it is deleted upon successful exit.
222
223     $zdebug
224                 Some extra debugging info is logged here.
225
226     rcfile
227                 Where $ourname gets track info from.  It can be
228                 specified on the command line (see -r above) when
229                 not using an online CDDB server, otherwise it is
230                 created automatically by $ourname.
231
232 Environment Variables:
233 ---------------------
234
235   Some aspects of $ourname can be tweaked by setting the following
236   environment variables.
237
238     DEBUG       Set to a non-nil string to turn on debugging.
239
240     zcddb       CDDB server to use (default: freedb.freedb.org).
241
242     zuser       Name used to log into CDDB server (default: $USER).
243
244     zhost       Host used to log into CDDB server (default: $HOST).
245
246     zedit       Set to a non-nil string to force $ourname to invoke an
247                 editor to create a rcfile.
248
249     zcomment    Extra comment field/value to add to ID3 tags/Vorbis 
250                 comments (default: "Encoded with $ourname").
251
252   Occasionally, the CDDB entries for a given CD are either wrong or
253   have not been formatted correctly.  In an attempt to compensate for
254   these types of quirks you can set the following environment variables
255   with $ourname invocation to override the madness...
256
257     ARTIST      Override the artist field.
258
259     ALBUM       Override the album name.
260
261     YEAR        Override year.
262
263     GENRE       Override genre.
264
265 Example Usage:
266 -------------
267
268   Probably the most common usage would be to encode to Ogg/Vorbis
269   format using track info obtained from freedb.freedb.org.  Like
270   this...
271
272     \$ $ourname -oO
273
274   Encode to MP3 format, prompting for album name, year, genre, artist,
275   and track titles...
276
277     \$ $ourname -mi
278
279   Encode to Ogg/Vorbis, set album name on the command line, taking
280   track title info from a file, and make a FLAC format backup copy of
281   each track...
282
283     \$ $ourname -a "The Album Name" -o -f -r /path/to/rcfile
284
285   Encode to Ogg/Vorbis, taking track info from a online CDDB server,
286   and override the genre for the album...
287
288     \$ GENRE=alternate $ourname -oO
289
290 Exit Status:
291 -----------
292
293   $ourname will return the following status codes on exit:
294
295     0 -- Clean exit (no errors)
296     2 -- Command line option error
297     3 -- Missing external command
298     4 -- CDDB error
299
300 Debugging:
301 ---------
302
303   If you call $ourname with the environment variable DEBUG set to a
304   non nil value, for example: DEBUG=yes $ourname <opts>, $ourname will
305   be called with "set -x".
306
307   "set -x" spams your stdout with a _LOT_ of messages, it would most
308   likely pay you to redirect stdout/stderr to a file.
309
310 ${COPYRIGHT}
311
312 EOF
313 }
314
315 # Convert song title to something resembling a sane filename... no
316 # whitespace, no punctuation, etc.  Also adds .ogg/.mp3 extension.
317 fnamefix ()
318 {
319     local psub="[[:cntrl:],\*\?\`';/\\\\\"]"
320     local prep=""
321     local wsub="[[:space:][:blank:]]"
322     local wrep="_"
323
324     setopt extendedglob
325
326     for (( i=1; i<=$tracks; ++i )); do
327         tf=$filename[$i]
328         tf=${tf//\\t/ }
329         tf=${tf//${~psub}/$prep}
330         tf=${tf//[ ]##/ }
331         tf=${tf//${~wsub}/$wrep}
332         filename[$i]=$tf.$prepargs[1]
333     done
334 }
335
336 ### freedb magic
337 _freedb_login ()
338 {
339     local args
340     if [[ -z $1 ]]; then
341         print invalid args >&2
342         return 1
343     fi
344
345     args="$@"
346     # login
347     tcp_send "cddb hello $args"
348     tcp_expect -T 10 -s $ourname "*Hello and welcome*"
349     if [[ $? -eq 2 ]]; then
350         print Timeout waiting for cddb server >&2
351         exit 4
352     fi
353     # set protocol level
354     tcp_send "proto 6"
355     tcp_expect -T 10 -s $ourname "*CDDB protocol*"
356     if [[ $? -eq 2 ]]; then
357         print Timeout waiting for cddb server >&2
358         exit 4
359     fi
360     return 0
361 }
362
363 _parse_cddb ()
364 {
365     local various=yes
366     art=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f1|sed '1!d')
367     art=${art/%[[:space:]]/}
368     art=${art//'&'/'\&'}
369
370     # Possibly override.
371     art=${ARTIST:-$art}
372
373     # Artist
374     if [[ "$art" != "Various Artists" && "$art" != "Various" ]]; then
375         various=no
376     fi
377
378     # Album, year, genre, number or tracks
379     album=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f2)
380     album=${album/#[[:space:]]/}
381     album=${album//[[:cntrl:]]/}
382     year=$(grep DYEAR $zlog|cut -d= -f2)
383     year=${year//[[:cntrl:]]/}
384     genre=$(grep DGENRE $zlog|cut -d= -f2)
385     genre=${genre//[[:cntrl:]]/}
386     tracks=$zid[2]
387
388     # Possibly override album, year, genre
389     album=${ALBUM:-$album}
390     year=${YEAR:-$year}
391     genre=${GENRE:-$genre}
392
393     # print what we got when we're debugging
394     if [[ -n $DEBUG ]]; then
395         printf "Artist: %s\nAlbum: %s\nYear: %s\nGenre: %s\nNum Tracks: %s\n" \
396             $art $album $year $genre $tracks > $zdebug
397         printf "Various: %s\n" $various >> $zdebug
398         echo --- Titles --- >> $zdebug
399         grep TTITLE $zlog >> $zdebug
400     fi
401
402     # create an rcfile
403     :>$rcfile                   # make sure it is empty
404
405     for (( i=0; i<$tracks; i++ )); do
406         TRACK=""
407         for TITLE in $(grep TTITLE${i}= ${zlog}|cut -d= -f2); do
408             TRACK="${TRACK} ${TITLE}"
409         done
410         TRACK=${TRACK//[[:cntrl:]]/}
411         TRACK=${TRACK/[[:space:]]/}
412         echo ${TRACK} >> ${rcfile}
413     done
414
415     if [[ $various == yes || -n $(grep TTITLE $zlog|grep $art) ]]; then
416         sed -i 's@ [-/] @|@g' $rcfile
417     else
418         sed -i "s@^@${art}|@g" $rcfile
419     fi
420     
421 }
422
423 _freedb_read ()
424 {
425     if [[ -z $1 ]]; then
426         print invalid args >&2
427         return 1
428     fi
429
430     tcp_send "cddb read $1 $2"
431     tcp_expect -T 25 -s $ourname "*PLAYORDER*"
432     if [[ $? -eq 2 ]]; then
433         print Timeout waiting for cddb server >&2
434         exit 4
435     fi
436
437     _parse_cddb
438     
439 }
440
441 _freedb_query ()
442 {
443     if [[ -z $1 ]]; then
444         print invalid args >&2
445         return 1
446     fi
447
448     tcp_send "cddb query $zid"
449     tcp_expect -T 10 -p idx -s $ourname "*No match for disc ID*" \
450         "<-\[$ourname\] 200*" "<-\[$ourname\] .*"
451     if [[ $? -eq 2 ]]; then
452         print Timeout waiting for cddb server >&2
453         exit 4
454     fi
455     case $idx in
456         (1)
457             print No entry listed for disc: $zid[1] >&2
458             print You will have to do this disc manually >&2
459             exit 4
460             ;;
461         (2)
462             category=$TCP_LINE
463             category=${category/*200 /}
464             category=${category/ $zid[1]*/}
465             _freedb_read $category $zid[1]
466             ;;
467         (3)
468             echo Multiple entries found...
469             echo
470             tmulti=(${(ps:\r:)${tcp_expect_lines}})
471             [[ $tmulti[1] == *inexact* ]] && exact=no
472             tmulti[1]=${tmulti[1]:#${tmulti[1]}}
473             multi=($tmulti)
474             for (( i=1; i<${#multi}; ++i )); do
475                 multi[$i]=${multi[$i]/<-\[$ourname\] /}
476                 printf "\t[%s]%s\n" $i $multi[$i]
477             done
478             echo
479             echo -n "Which CDDB entry (q to quit): "
480             read choice
481             case $choice in
482                 ([qQ]) do_offline; exit 0 ;;
483                 ([^[:digit:]]) 
484                     print Invalid response >&2
485                     do_offline
486                     exit 2
487                     ;;
488                 ([[:digit:]])
489                     category=$multi[$choice]
490                     if [[ $exact == no ]]; then
491                         tcategory=(${(ps: :)category})
492                         _freedb_read $tcategory[1,2]
493                     else
494                         category=${category/ $zid[1]*/}
495                         _freedb_read $category $zid[1]
496                     fi
497                     ;;
498                 (*)
499                     print Unknown error >&2
500                     do_offline
501                     exit 2
502                     ;;
503             esac
504             ;;
505         (*) print Unknown error >&2 ;;
506     esac
507 }
508
509 do_online ()
510 {
511     autoload -U tcp_open
512     autoload -U tcp_log
513     [[ -n $DEBUG ]] || TCP_SILENT=nodebugging
514
515     zcddb=${zcddb:-freedb.freedb.org}
516     port=8880
517     zuser=${zuser:-$USER}
518     zhost=${zhost:-$HOST}
519     proto=6
520     zlog=${TMPPREFIX}/zcdrip.log
521
522     # open the log and connect
523     tcp_log $zlog
524     tcp_open $zcddb $port $ourname
525     tcp_expect -T 10 -s $ourname "<-\[$ourname\] 201*ready*"
526     if [[ $? -eq 2 ]]; then
527         print Timeout waiting for cddb server >&2
528         exit 4
529     else
530         _freedb_login $zuser $zhost $ourname $VERSION
531     fi
532
533     # query cddb server to find out if the CD is listed
534     _freedb_query $zid
535
536 }
537
538 # Close tcp connection
539 do_offline ()
540 {
541     tcp_close $ourname
542     tcp_log -c
543 }
544
545 # Tidy up if not debugging
546 cleanup ()
547 {
548     rm -f $zlog $rcfile $zdebug
549     unset ARTIST ALBUM YEAR GENRE
550 }
551
552 # convert album/artist name into a sane filename for output dir
553 _album_to_dir ()
554 {
555     local talbum=$album
556     local tart=$art
557     local psub="[[:cntrl:],\`';/\\\\\"]"
558     local prep=""
559     local wsub="[[:space:][:blank:]]"
560     local wrep="_"
561
562     setopt extendedglob
563
564     talbum=${talbum//\\t/ }
565     talbum=${talbum//${~psub}/$prep}
566     talbum=${talbum//[ ]##/ }
567     talbum=${talbum//${~wsub}/$wrep}
568
569     tart=${tart//\\t/ }
570     tart=${tart//${~psub}/$prep}
571     tart=${tart//[ ]##/ }
572     tart=${tart//${~wsub}/$wrep}
573
574     # Various Artists is sometimes "Various" and other times "Various
575     # Artists", we'll call them all "Various_Artists".
576     if [[ "${tart}" == "Various" ]]; then
577         tart=Various_Artists
578     fi
579
580     dir=$(pwd)/${tart}/${talbum}
581     [[ -d ${dir} ]] || mkdir -p ${dir}
582     [[ $keep_flac == yes ]] && fdir=${dir}/flac; mkdir -p ${fdir}
583 }
584         
585
586 # Store song titles, artist, and album names.
587 prep ()
588 {
589     zid=($(zdiscid))
590     tracks=$zid[2]
591
592     [[ -d ${TMPPREFIX} ]] || mkdir -p ${TMPPREFIX}
593
594     if [[ $online == yes ]]; then
595         do_online
596         do_offline
597     fi
598
599     typeset -A artist
600     typeset -A song
601     typeset -A filename
602
603     if [[ $zedit == yes && -n $rcfile ]]; then
604         _zedit=${EDITOR:-vi}
605         cat>$rcfile<<EOF
606 The format of this file is...
607     Artist Name|Track Title
608 One "record" per line.  Punctuation and whitespace is OK.
609 You MUST delete these instructions before saving.
610 EOF
611         $_zedit $rcfile
612     fi
613
614     if [[ -z $album ]]; then
615         echo -n "Please enter the name of this album: "
616         read album
617         echo
618     fi
619
620     [[ -n $dir ]] || _album_to_dir
621
622     if [[ ! -d ${dir} ]]; then
623         mkdir -p ${dir}
624         if [[ $keep_flac == yes && ! -d ${fdir} ]]; then
625             mkdir -p ${fdir}
626         fi
627     fi
628
629     if [[ -z $year ]]; then
630         echo -n "Please enter the year this album was released: "
631         read year
632         echo
633     fi
634
635     if [[ -z $genre ]]; then
636         echo -n "Please enter the genre of this album: "
637         read genre
638         echo
639     fi
640
641     zcomment=${zcomment:-"Encoded with $ourname"}
642
643     if [[ $prepargs[2] == yes ]]; then
644         for (( i=1; i<=$tracks; ++i )); do
645             if [[ -n $art ]]; then
646                 artist[$i]=$art
647             else
648                 echo -n "Track $i artist: "
649                 read art
650                 artist[$i]=$art
651                 unset art
652             fi
653             echo -n "Track $i title: "
654             read sg
655             song[$i]=$sg
656             filename[$i]=$sg
657         done
658     else
659         IFS="|"
660         i=0
661         while read art sg; do
662             (( ++i ))
663             artist[$i]=$art
664             sg=${sg/#[[:space:]]/}
665             sg=${sg//[[:cntrl:]]/}
666             song[$i]=${sg}
667             filename[$i]=${sg}
668         done < $prepargs[3]
669     fi
670
671     fnamefix $prepargs[1]
672     wavfile=dumpaudio.wav
673     ${prepargs[1]}rip
674
675     [[ -n $DEBUG ]] || cleanup
676 }
677
678 # Flac
679 flacenc ()
680 {
681     file=$1
682     shift                       # pop off $1 (flacfile)
683     flac -8 --delete-input-file -o ${fdir}/${file} ${1}
684     shift                       # pop off next arg (wavfile)
685     for tag in title artist album year genre tracknumber comment; do
686         metaflac --set-tag="$tag=${1}" ${fdir}/${file}
687         shift
688     done
689 }
690
691 flactomp3 ()
692 {
693     flac=$1
694     mp3=$2
695
696     # tags
697     title=$(metaflac --show-tag=title|cut -d= -f2)
698     artist=$(metaflac --show-tag=artist|cut -d= -f2)
699     album=$(metaflac --show-tag=album|cut -d= -f2)
700     year=$(metaflac --show-tag=year|cut -d= -f2)
701     genre=$(metaflac --show-tag=genre|cut -d= -f2)
702     track=$(metaflac --show-tag=tracknumber|cut -d= -f2)
703     comment=$(metaflac --show-tag=comment|cut -d= -f2)
704
705     flac -c -d $flac|lame -h --tt ${title} --ta ${artist} --tl ${album} \
706         --ty $year --tg $genre --tn $track --tc ${comment} - $mp3
707 }
708
709 # Encode to MP3
710 mp3rip ()
711 {
712     # Work around lame being too anal about genre
713     lame --genre-list|grep ${genre} 1>/dev/null || genre=Other
714
715     for (( i=1; i<=$tracks; ++i )); do
716         echo MP3-Ripping: $song[$i], by: $artist[$i], to: $filename[$i]
717         cdparanoia -X $i $wavfile
718         if [[ -f $wavfile ]]; then
719             if [[ $keep_flac == yes ]]; then
720                 flacfile=${filename[$i]/%mp3/flac}
721                 flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \
722                     $year $genre $i $zcomment
723                 flactomp3 ${flacfile} ${dir}/$filename[$i]
724             else
725                 lame -h --tt $song[$i] --ta $artist[$i] --tl $album \
726                     --ty $year --tg $genre --tc $zcomment $wavfile \
727                     --tn $i ${dir}/$filename[$i]
728             fi
729             [[ $write_playlist == yes ]] && echo ${dir}$filename[$i] >> $plfile
730         fi
731         [[ -f $wavfile ]] && rm -f $wavfile
732     done
733 }
734
735 # Encode to OGG Vorbis
736 oggrip ()
737 {
738     for (( i=1; i<=$tracks; ++i )); do
739         echo OGG-Ripping: $song[$i], by: $artist[$i], to: $filename[$i]
740         cdparanoia -X $i $wavfile
741         if [[ -f $wavfile ]]; then
742             if [[ $keep_flac == yes ]]; then
743                 flacfile=${filename[$i]/%ogg/flac}
744                 flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \
745                     $year $genre $i $zcomment
746                 oggenc -q3 -o ${dir}/$filename[$i] ${fdir}/$flacfile
747             else
748                 oggenc -q3 -o ${dir}/$filename[$i] -t $song[$i] -a $artist[$i] \
749                     -l $album -d $year -G $genre -c "comment=$zcomment" \
750                     -N $i $wavfile
751                 rm $wavfile
752             fi
753             [[ $write_playlist == yes ]] && echo ${dir}/$filename[$i] >> $plfile
754         fi
755     done
756 }
757
758 # Make sure we have everything we need.
759 # This might be a little over the top, but I don't see any point in
760 # checking for `oggenc' if you are encoding to MP3, likewise, there's
761 # no point in checking for `lame' if you are encoding to Ogg Vorbis.
762 chkreqs ()
763 {
764     reqs=(cdparanoia lame oggenc flac)
765     whence -w $reqs[1] 1>/dev/null
766     if [[ $? -gt 0 ]]; then
767         echo $ourname: error: Missing $reqs[1] >&2
768         rv=3
769     fi
770     case $atype in
771         (mp3)
772             whence -w $reqs[2] 1>/dev/null
773             if [[ $? -gt 0 ]]; then
774                 echo $ourname: error: Missing $reqs[2] >&2
775                 rv=3
776            fi
777             ;;
778         (ogg)
779             whence -w $reqs[3] 1>/dev/null
780             if [[ $? -gt 0 ]]; then
781                 echo $ourname: error: Missing $reqs[3] >&2
782                 rv=3
783             fi
784             ;;
785     esac
786     if [[ $keep_flac == yes ]]; then
787         whence -w $reqs[4] 1>/dev/null
788         if [[ $? -gt 0 ]]; then
789             echo $ourname: error: Missing $reqs[4] >&2
790             rv=3
791         fi
792     fi
793     if [[ $rv -eq 3 ]]; then
794         exit $rv
795     else
796         return 0
797     fi
798 }
799         
800
801 # Command line parsing
802 args=mofihVO-:r:a:s:t:e:d:p:
803 flavour=0
804 rc=0
805 interactive=no
806 rcfile=" "
807 zedit=" "
808
809 while getopts $args opts; do
810     case $opts in
811         (-)
812             case $OPTARG in
813                 (mp3) atype=mp3; (( ++flavour )) ;;
814                 (ogg) atype=ogg; (( ++flavour )) ;;
815                 (edit_rcfile?*)
816                     rcfile=${OPTARG/edit_rcfile=/}
817                     (( ++rc ))
818                     zedit=yes
819                     ;;
820                 (flac_copy) keep_flac=yes ;;
821                 (type?*) atype=${OPTARG/type=/}; (( ++flavour )) ;;
822                 (interactive) interactive=yes; (( ++rc )) ;;
823                 (online) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;;
824                 (rcfile?*) rcfile=${OPTARG/rcfile=/}; (( ++rc )) ;;
825                 (album?*) album=${OPTARG/album=/} ;;
826                 (sameartist?*) art=${OPTARG/sameartist=/} ;;
827                 (dir?*) dir=${OPTARG/dir=/} ;;
828                 (playlist?*) write_playlist=yes; plfile=${OPTARG/playlist=/} ;;
829                 (version) _version; exit 0 ;;
830                 (help) cmd=usage; rv=0 ;;
831                 (*) 
832                     echo $ourname: error: bad option: --$OPTARG >&2
833                     exit 2
834                     ;;
835             esac
836             ;;
837         (i) interactive=yes; (( ++rc )) ;;
838         (O) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;;
839         (m) atype=mp3; (( ++flavour )) ;;
840         (o) atype=ogg; (( ++flavour )) ;;
841         (e) rcfile=$OPTARG; (( ++rc )); zedit=yes ;;
842         (f) keep_flac=yes ;;
843         (r) rcfile=$OPTARG; (( ++rc )) ;;
844         (a) album=$OPTARG ;;
845         (s) art=$OPTARG ;;
846         (t) atype=$OPTARG; (( ++flavour )) ;;
847         (d) dir=$OPTARG ;;
848         (p) write_playlist=yes; plfile=$OPTARG ;;
849         (V) _version; exit 0 ;;
850         (h) cmd=usage; rv=0 ;;
851         (*) rv=2 ;;
852     esac
853 done
854 shift $(( $OPTIND - 1 ))
855
856 if [[ $cmd != usage ]]; then
857     case $flavour in
858         (0)
859             echo $ourname: error: no audio format specified >&2
860             if [[ $rc -ne 1 ]]; then
861                 echo $ourname: error: improper use of interactice/rcfile option >&2
862             fi
863             rv=2
864             ;;
865         (1)
866             if [[ $rc -ne 1 ]]; then
867                 echo $ourname: error: improper use of interactive/rcfile option >&2
868                 rv=2
869             else
870                 typeset -A prepargs
871                 prepargs=(1 $atype 2 $interactive 3 $rcfile 4 $zedit)
872                 chkreqs
873                 prep $prepargs
874             fi
875             ;;
876         (*)
877             echo $ourname: error: multiple or invalid audio formats specified >&2
878             if [[ $rc -ne 1 ]]; then
879                 echo $ourname: error: improper use of interactice/rcfile option >&2
880             fi
881             rv=2
882             ;;
883     esac
884 else
885     usage
886 fi
887
888 exit $rv
889
890 ### zcdrip ends here