Typo in cdda2wav LASTTRACK corrected.
[clinton/abcde.git] / abcde
1 #!/bin/bash
2 # Copyright (c) 1998-2001 Robert Woodcock <rcw@debian.org>
3 # Copyright (c) 2003-2005 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 # $Id$
15
16 VERSION='2.3.99-$Revision$'
17
18 usage ()
19 {
20 echo "This is abcde v$VERSION."
21 echo "Usage: abcde [options] [tracks]"
22 echo "Options:"
23 echo "-1 Encode the whole CD in a single file"
24 echo "-a <action1[,action2]...>"
25 echo " Actions to perform:"
26 echo " cddb,read,normalize,encode,tag,move,replaygain,playlist,clean"
27 #echo "-A Experimental actions (retag, transcode)"
28 echo "-b Enable batch normalization"
29 #echo "-B Disable batch replaygain (do file by file)"
30 echo "-c <file>"
31 echo " Specify a configuration file (overrides system and user config files)"
32 echo "-C <discid#>"
33 echo " Specify discid to resume from (only needed if you no longer have the cd)"
34 echo "-d <device>"
35 echo " Specify CDROM device to grab (flac uses a single-track flac file)"
36 echo "-D Debugging mode (equivalent to sh -x abcde)"
37 echo "-e Erase encoded track information from status file"
38 echo "-f Force operations that otherwise are considered harmful. Read \"man abcde\""
39 echo "-g Use \"lame --nogap\" for MP3 encoding. Disables low disk and pipes flags"
40 echo "-h This help information"
41 #echo "-i Tag files while encoding, when possible (local only) -NWY-"
42 echo "-j <#> Number of encoder processes to run at once (localhost)"
43 echo "-k Keep the wav tracks for later use"
44 echo "-l Use low disk space algorithm"
45 echo "-L Use local CDDB storage directory"
46 echo "-n No lookup. Don't query CDDB, just create and use template"
47 echo "-N Noninteractive. Never prompt for anything"
48 echo "-m Modify playlist to include CRLF endings, to comply with some players"
49 echo "-M Create a CUE file"
50 echo "-o <type1[,type2]...>"
51 echo " Output file type(s) (vorbis,mp3,flac,spx,mpc,wav,m4a). Defaults to vorbis"
52 echo "-p Pad track numbers with 0's (if less than 10 tracks)"
53 echo "-P Use UNIX pipes to read+encode without wav files"
54 echo "-r <host1[,host2]...>"
55 echo " Also encode on these remote hosts"
56 echo "-R Use local CDDB in recursive mode"
57 #echo "-R Add replaygain values to the tag info (only for vorbis,flac,mp3)"
58 echo "-s <field>"
59 echo " Show dielfs from the CDDB info (year,genre)"
60 echo "-S <#> Set the CD speed"
61 echo "-t <#> Start the track numbering at a given number"
62 echo "-T <#> Same as -t but modifies tag numbering"
63 echo "-u Use UNICODE tags and comments"
64 echo "-v Show version number and exit"
65 echo "-V Be a bit more verbose about what is happening behind the scenes"
66 echo "-x Eject CD after all tracks are read"
67 echo "-w <comment>"
68 echo " Add a comment to the CD tracks"
69 echo "-W <#> Contatenate CDs: -T #01 -w \"CD #\""
70 echo "-z Use debug CDROMREADERSYNTAX option (needs cdparanoia)"
71 echo ""
72 echo "Tracks is a space-delimited list of tracks to grab."
73 echo "Ranges specified with hyphens are allowed (i.e., 1-5)."
74 echo ""
75 #echo "Double hyphens are used to concatenate tracks"
76 }
77
78 addstatus ()
79 {
80 echo "$@" >> "$ABCDETEMPDIR/status"
81 }
82
83 # log [level] [message]
84 #
85 # log outputs the right message in a common format
86 log ()
87 {
88 BLURB="$1"
89 shift
90 case $BLURB in
91 error) echo "[ERROR] abcde: $@" >&2 ;;
92 warning) echo "[WARNING] $@" >&2 ;;
93 info) echo "[INFO] $@" ;;
94 esac
95 }
96
97 # Funtions to replace the need of seq, which is too distribution dependant.
98 f_seq_row ()
99 {
100 i=$1
101 while [ $i -ne `expr $2 + 1` ]
102 do
103 echo $i
104 i=`expr $i + 1`
105 done
106 }
107
108 f_seq_line ()
109 {
110 i=$1
111 if echo $i | grep -q "[[:digit:]]" ; then
112 while [ $i -ne `expr $2 + 1` ]
113 do
114 printf $i" "
115 i=`expr $i + 1`
116 done
117 echo
118 else
119 log error "syntax error while processing track numbers"
120 exit 1
121 fi
122 }
123
124 # Functions to replace the need of awk {print $1} and {print $NF}
125 get_first()
126 {
127 if [ X"$1" = "X" ]; then
128 for first in `cat`; do
129 break
130 done
131 else
132 first=$1
133 fi
134 echo $first
135 }
136
137 get_last()
138 {
139 if [ X"$1" = "X" ]; then
140 for stdin in `cat`; do
141 last=$stdin
142 done
143 else
144 for last in $@ ; do :; done
145 fi
146 echo $last
147 }
148
149 # checkstatus [blurb]
150 # Returns "0" if the blurb was found, returns 1 if it wasn't
151 # Puts the blurb content, if available, on stdout.
152 # Otherwise, returns "".
153 checkstatus ()
154 {
155 # Take the last line in the status file if there's multiple matches
156 PATTERN="^$1(=.*)?$"
157 BLURB=$(egrep $PATTERN "$ABCDETEMPDIR/status" | tail -n 1)
158
159 if [ -z "$BLURB" ]; then
160 # No matches found
161 return 1
162 else
163 # Matches found
164 # See if there's a = in it
165 if [ "$(echo $BLURB | grep -c =)" != "0" ]; then
166 echo "$(echo $BLURB | cut -f2- -d=)"
167 fi
168 return 0
169 fi
170 }
171
172 # chechwarnings [blurb]
173 # Returns "0" if the blurb was found (meaning there was an warning),
174 # returns 1 if it wasn't (yes this is a little backwards).
175 # Does not print the blurb on stdout.
176 # Otherwise, returns "".
177 checkwarnings ()
178 {
179 if [ -e "$ABCDETEMPDIR/warnings" ]; then :; else
180 return 1
181 fi
182 # Take the last line in the status file if there's multiple matches
183 PATTERN="^$1(:.*)?$"
184 BLURB="$(egrep $PATTERN "$ABCDETEMPDIR/warnings" | tail -n 1)"
185
186 if [ -z "$BLURB" ]; then
187 # negative, we did not have a negative...
188 return 1
189 else
190 # affirmative, we had a negative...
191 return 0
192 fi
193 }
194
195 # checkerrors [blurb]
196 # Returns "0" if the blurb was found (meaning there was an error),
197 # returns 1 if it wasn't (yes this is a little backwards).
198 # Does not print the blurb on stdout.
199 # Otherwise, returns "".
200 checkerrors ()
201 {
202 if [ -e "$ABCDETEMPDIR/errors" ]; then :; else
203 return 1
204 fi
205 # Take the last line in the status file if there's multiple matches
206 PATTERN="^$1(:.*)?$"
207 BLURB="$(egrep $PATTERN "$ABCDETEMPDIR/errors" | tail -n 1)"
208
209 if [ -z "$BLURB" ]; then
210 # negative, we did not have a negative...
211 return 1
212 else
213 # affirmative, we had a negative...
214 return 0
215 fi
216 }
217
218 # page [file]
219 # Finds the right pager in the system to display a file
220 page ()
221 {
222 PAGEFILE="$1"
223 # Use the debian sensible-pager wrapper to pick the pager
224 # user has requested via their $PAGER environment variable
225 if [ -x "/usr/bin/sensible-pager" ]; then
226 /usr/bin/sensible-pager "$PAGEFILE"
227 elif [ -x "$PAGER" ]; then
228 # That failed, try to load the preferred editor, starting
229 # with their PAGER variable
230 $PAGER "$PAGEFILE"
231 # If that fails, check for less
232 elif [ -x /usr/bin/less ]; then
233 /usr/bin/less -f "$PAGEFILE"
234 # more should be on all UNIX systems
235 elif [ -x /bin/more ]; then
236 /bin/more "$PAGEFILE"
237 else
238 # No bananas, just cat the thing
239 cat "$PAGEFILE" >&2
240 fi
241 }
242
243 # run_command [blurb] [command...]
244 # Runs a command, silently if necessary, and updates the status file
245 run_command ()
246 {
247 BLURB="$1"
248 shift
249 # See if this is supposed to be silent
250 if [ "$(checkstatus encode-output)" = "loud" ]; then
251 "$@" >&2
252 RETURN=$?
253 else
254 # Special case for SMP, since
255 # encoder output is never displayed, don't mute echos
256 if [ -z "$BLURB" -a "$MAXPROCS" != "1" ]; then
257 "$@" >&2
258 RETURN=$?
259 else
260 "$@" >/dev/null 2>&1
261 RETURN=$?
262 fi
263 fi
264 case "$1" in
265 normalize|normalize-audio)
266 if [ "$RETURN" = "2" ]; then
267 # File was already normalized.
268 RETURN=0
269 fi
270 ;;
271 esac
272 if [ "$RETURN" != "0" ]; then
273 # Put an error in the errors file. For various reasons we
274 # can't capture a copy of the program's output but we can
275 # log what we attempted to execute and the error code
276 # returned by the program.
277 if [ "$BLURB" ]; then
278 TWEAK="$BLURB: "
279 fi
280 echo "${TWEAK}returned code $RETURN: $@" >> "$ABCDETEMPDIR/errors"
281 return $RETURN # Do not pass go, do not update the status file
282 fi
283 if [ "$BLURB" ]; then
284 echo $BLURB >> "$ABCDETEMPDIR/status"
285 fi
286 }
287
288 # relpath() and slash() are Copyright (c) 1999 Stuart Ballard and
289 # distributed under the terms of the GNU GPL v2 or later, at your option
290
291 # Function to determine if a word contains a slash.
292 slash ()
293 {
294 case "$1" in
295 */*) return 0;;
296 *) return 1;;
297 esac
298 }
299
300 # Function to give the relative path from one file to another.
301 # Usage: relpath fromfile tofile
302 # eg relpath music/Artist/Album.m3u music/Artist/Album/Song.mp3
303 # (the result would be Album/Song.mp3)
304 # Output is relative path to $2 from $1 on stdout
305
306 # This code has the following restrictions:
307 # Multiple ////s are not collapsed into single /s, with strange effects.
308 # Absolute paths and ../s are handled wrong in FR (but they work in TO)
309 # If FR is a directory it must have a trailing /
310
311 relpath ()
312 {
313 FR="$1"
314 TO="$2"
315
316 case "$TO" in
317 /*) ;; # No processing is needed for absolute paths
318 *)
319 # Loop through common prefixes, ignoring them.
320 while slash "$FR" && [ "$(echo "$FR" | cut -d/ -f1)" = "$(echo "$TO" | cut -d/ -f1)" ]
321 do
322 FR="$(echo "$FR" | cut -d/ -f2-)"
323 TO="$(echo "$TO" | cut -d/ -f2-)"
324 done
325 # Loop through directory portions left in FR, adding appropriate ../s.
326 while slash "$FR"
327 do
328 FR="$(echo "$FR" | cut -d/ -f2-)"
329 TO="../$TO"
330 done
331 ;;
332 esac
333
334 echo $TO
335 }
336
337 checkexec ()
338 {
339 if [ ! "$@" = "" ]; then
340 # Cut off the command-line options we just added in
341 X=$(echo $@ | cut -d' ' -f2)
342 if [ "$(which $X)" = "" ]; then
343 log error "$X is not in your path." >&2
344 exit 1
345 elif [ ! -x $(which $X) ]; then
346 log error "$X is not executable." >&2
347 exit 1
348 fi
349 fi
350 }
351
352 # do_getcddbinfo
353 # Finds an specific field from cddbinfo
354 do_getcddbinfo()
355 {
356 case $1 in
357 TRACKNAME1)
358 TRACKNAME="$(grep ^TTITLE$CDDBTRACKNUM= "$CDDBDATA" | head -n 1 | cut -f2- -d= | tr -d \[:cntrl:\] | sed 's/\ \+$//')"
359 ;;
360 TRACKNAME)
361 TRACKNAME="$(grep ^TTITLE$CDDBTRACKNUM= "$CDDBDATA" | cut -f2- -d= | tr -d \[:cntrl:\] | sed 's/\ \+$//')"
362 ;;
363 esac
364 }
365
366 # do_gettracknum
367 # Get the track number we are going to use for different actions
368 do_gettracknum()
369 {
370 if [ -n "$STARTTRACKNUMBER" ] ; then
371 # Get the trackpadding from the current track
372 CURRENTTRACKPADDING=$(echo -n $UTRACKNUM | wc -c)
373 TRACKNUM=$( printf %0.${CURRENTTRACKPADDING}d $(expr ${UTRACKNUM} + ${STARTTRACKNUMBER} - $FIRSTTRACK ))
374 else
375 TRACKNUM=${UTRACKNUM}
376 fi
377 }
378
379 do_replaygain()
380 {
381 if checkstatus replaygain; then :; else
382 run_command "" echo "Adding replygain information..."
383 for OUTPUT in $( echo $OUTPUTTYPE | tr , \ )
384 do
385 case $OUTPUT in
386 vorbis|ogg)
387 OUTPUT=$OGGOUTPUTCONTAINER
388 ;;
389 flac)
390 OUTPUT=$FLACOUTPUTCONTAINER
391 ;;
392 esac
393 OUTPUTFILES=""
394 REPLAYINDEX=0
395 for UTRACKNUM in $TRACKQUEUE
396 do
397 CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
398 do_getcddbinfo TRACKNAME
399 splitvarious
400 TRACKFILE="$(mungefilename "$TRACKNAME")"
401 ARTISTFILE="$(mungefilename "$TRACKARTIST")"
402 ALBUMFILE="$(mungefilename "$DALBUM")"
403 do_gettracknum
404 if [ "$VARIOUSARTISTS" = "y" ]; then
405 OUTPUTFILE="$(eval echo $VAOUTPUTFORMAT)"
406 else
407 OUTPUTFILE="$(eval echo $OUTPUTFORMAT)"
408 fi
409 OUTPUTFILES[$REPLAYINDEX]="$OUTPUTDIR/$OUTPUTFILE.$OUTPUT"
410 (( REPLAYINDEX = $REPLAYINDEX + 1 ))
411 done
412 case "$OUTPUT" in
413 flac)
414 run_command replaygain-flac $METAFLAC --add-replay-gain "${OUTPUTFILES[@]}"
415 ;;
416 vorbis|ogg)
417 run_command replaygain-vorbis $VORBISGAIN --album "${OUTPUTFILES[@]}"
418 ;;
419 mp3)
420 run_command replaygain-mp3 $MP3GAIN -a "${OUTPUTFILES[@]}"
421 ;;
422 mpc)
423 run_command replaygain-mpc $MPPGAIN --auto "${OUTPUTFILES[@]}"
424 ;;
425 *);;
426 esac
427 done
428 if checkerrors "replaygain-.{3,6}"; then :; else
429 run_command replaygain true
430 fi
431 fi
432 }
433
434 # This code splits the a Various Artist track name from one of the following
435 # forms:
436 #
437 # forward: Artist / Track
438 # forward-dash: Artist - Track
439 # reverse: Track / Artist
440 # reverse-dash: Track - Artist
441 # colon: Artist: Track
442 # trailing-paren: Artist (Track)
443 #
444 # variables used:
445 # VARIOUSARTISTS, VARIOUSARTISTSTYLE, TRACKNAME, TRACKARTIST
446 splitvarious ()
447 {
448 if [ "$VARIOUSARTISTS" = "y" ] && [ ! "$ONETRACK" = "y" ]; then
449 case "$VARIOUSARTISTSTYLE" in
450 forward)
451 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's- / -~-g')"
452 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
453 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
454 ;;
455 forward-dash)
456 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's, - ,~,g')"
457 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
458 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
459 ;;
460 reverse)
461 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's- / -~-g')"
462 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
463 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
464 ;;
465 reverse-dash)
466 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's, - ,~,g')"
467 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
468 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
469 ;;
470 colon)
471 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's-: -~-g')"
472 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
473 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
474 ;;
475 trailing-paren)
476 DTITLEARTIST="$(echo "$TRACKNAME" | sed 's,^\(.*\) (\(.*\)),\1~\2,')"
477 TRACKARTIST="$(echo "$DTITLEARTIST" | cut -f2 -d~)"
478 TRACKNAME="$(echo "$DTITLEARTIST" | cut -f1 -d~)"
479 ;;
480 esac
481 elif [ "$VARIOUSARTISTS" = "y" ] && [ "$ONETRACK" = "y" ]; then
482 TRACKARTIST="Various"
483 else
484 TRACKARTIST="$DARTIST"
485 fi
486 }
487
488 do_getgenreid () {
489 local genre=$(echo "${@}" | tr '[A-Z]' '[a-z]')
490 local id=""
491 case ${genre} in
492 "blues") id=0 ;;
493 "classic rock") id=1 ;;
494 "country") id=2 ;;
495 "dance") id=3 ;;
496 "disco") id=4 ;;
497 "funk") id=5 ;;
498 "grunge") id=6 ;;
499 "hip-hop") id=7 ;;
500 "jazz") id=8 ;;
501 "metal") id=9 ;;
502 "new age") id=10 ;;
503 "oldies") id=11 ;;
504 "other") id=12 ;;
505 "pop") id=13 ;;
506 "r&b") id=14 ;;
507 "rap") id=15 ;;
508 "reggae") id=16 ;;
509 "rock") id=17 ;;
510 "techno") id=18 ;;
511 "industrial") id=19 ;;
512 "alternative") id=20 ;;
513 "ska") id=21 ;;
514 "death metal") id=22 ;;
515 "pranks") id=23 ;;
516 "soundtrack") id=24 ;;
517 "euro-techno") id=25 ;;
518 "ambient") id=26 ;;
519 "trip-hop") id=27 ;;
520 "vocal") id=28 ;;
521 "jazz+funk") id=29 ;;
522 "fusion") id=30 ;;
523 "trance") id=31 ;;
524 "classical") id=32 ;;
525 "instrumental") id=33 ;;
526 "acid") id=34 ;;
527 "house") id=35 ;;
528 "game") id=36 ;;
529 "sound clip") id=37 ;;
530 "gospel") id=38 ;;
531 "noise") id=39 ;;
532 "alt. rock") id=40 ;;
533 "bass") id=41 ;;
534 "soul") id=42 ;;
535 "punk") id=43 ;;
536 "space") id=44 ;;
537 "meditative") id=45 ;;
538 "instrum. pop") id=46 ;;
539 "instrum. rock") id=47 ;;
540 "ethnic") id=48 ;;
541 "gothic") id=49 ;;
542 "darkwave") id=50 ;;
543 "techno-indust.") id=51 ;;
544 "electronic") id=52 ;;
545 "pop-folk") id=53 ;;
546 "eurodance") id=54 ;;
547 "dream") id=55 ;;
548 "southern rock") id=56 ;;
549 "comedy") id=57 ;;
550 "cult") id=58 ;;
551 "gangsta") id=59 ;;
552 "top 40") id=60 ;;
553 "christian rap") id=61 ;;
554 "pop/funk"|"pop / funk") id=62 ;;
555 "jungle") id=63 ;;
556 "native american") id=64 ;;
557 "cabaret") id=65 ;;
558 "new wave") id=66 ;;
559 "psychadelic") id=67 ;;
560 "rave") id=68 ;;
561 "showtunes") id=69 ;;
562 "trailer") id=70 ;;
563 "lo-fi") id=71 ;;
564 "tribal") id=72 ;;
565 "acid punk") id=73 ;;
566 "acid jazz") id=74 ;;
567 "polka") id=75 ;;
568 "retro") id=76 ;;
569 "musical") id=77 ;;
570 "rock & roll") id=78 ;;
571 "hard rock") id=79 ;;
572 "folk") id=80 ;;
573 "folk/rock") id=81 ;;
574 "national folk") id=82 ;;
575 "swing") id=83 ;;
576 "fusion") id=84 ;;
577 "bebob") id=85 ;;
578 "latin") id=86 ;;
579 "revival") id=87 ;;
580 "celtic") id=88 ;;
581 "bluegrass") id=89 ;;
582 "avantgarde") id=90 ;;
583 "gothic rock") id=91 ;;
584 "progress. rock") id=92 ;;
585 "psychadel. rock") id=93 ;;
586 "symphonic rock") id=94 ;;
587 "slow rock") id=95 ;;
588 "big band") id=96 ;;
589 "chorus") id=97 ;;
590 "easy listening") id=98 ;;
591 "acoustic") id=99 ;;
592 "humour") id=100 ;;
593 "speech") id=101 ;;
594 "chanson") id=102 ;;
595 "opera") id=103 ;;
596 "chamber music") id=104 ;;
597 "sonata") id=105 ;;
598 "symphony") id=106 ;;
599 "booty bass") id=107 ;;
600 "primus") id=108 ;;
601 "porn groove") id=109 ;;
602 "satire") id=110 ;;
603 "slow jam") id=111 ;;
604 "club") id=112 ;;
605 "tango") id=113 ;;
606 "samba") id=114 ;;
607 "folklore") id=115 ;;
608 "ballad") id=116 ;;
609 "power ballad") id=117 ;;
610 "rhythmic soul") id=118 ;;
611 "freestyle") id=119 ;;
612 "duet") id=120 ;;
613 "punk rock") id=121 ;;
614 "drum solo") id=122 ;;
615 "a capella") id=123 ;;
616 "euro-house") id=124 ;;
617 "dance hall") id=125 ;;
618 "goa") id=126 ;;
619 "drum & bass") id=127 ;;
620 "club-house") id=128 ;;
621 "hardcore") id=129 ;;
622 "terror") id=130 ;;
623 "indie") id=131 ;;
624 "britpop") id=132 ;;
625 "negerpunk") id=133 ;;
626 "polsk punk") id=134 ;;
627 "beat") id=135 ;;
628 "christian gangsta rap") id=136 ;;
629 "heavy metal") id=137 ;;
630 "black metal") id=138 ;;
631 "crossover") id=139 ;;
632 "contemporary christian")id=140 ;;
633 "christian rock") id=141 ;;
634 "merengue") id=142 ;;
635 "salsa") id=143 ;;
636 "thrash metal") id=144 ;;
637 "anime") id=145 ;;
638 "jpop") id=146 ;;
639 "synthpop") id=147 ;;
640 "rock/pop"|"rock / pop") id=148 ;;
641 *) return 1 ;;
642 esac
643 echo ${id}
644 return 0
645 }
646
647 # do_tag [tracknumber]
648 # id3 tags a filename
649 # variables used:
650 # TRACKS, TRACKNAME, TRACKARTIST, TAGGER, TAGGEROPTS, VORBISCOMMENT, METAFLAC,
651 # COMMENT, DALBUM, DARTIST, CDYEAR, CDGENRE (and temporarily) ID3TAGV
652 do_tag ()
653 {
654 COMMENTOUTPUT="$(eval echo ${COMMENT})"
655 CDDBDISCID=$(echo $TRACKINFO | cut -d' ' -f1)
656 run_command '' echo "Tagging track $1 of $TRACKS: $TRACKNAME..."
657 # If we want to start the tracks with a given number, we need to modify the
658 # TRACKNUM value before evaluation
659 if [ -n "$STARTTRACKNUMBERTAG" ] ; then
660 do_gettracknum
661 fi
662 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
663 do
664 case "$OUTPUT" in
665 mp3)
666 # id3v2 v0.1.9 claims to have solved the -c bug, so we merge both id3 and id3v2
667 GENREID=$(do_getgenreid "${CDGENRE}")
668
669 case "$ID3SYNTAX" in
670 id3);;
671 eyed3)
672 # FIXME # track numbers in mp3 come with 1/10, so we cannot happily substitute them with $TRACKNUM
673 run_command tagtrack-$OUTPUT-$1 $TAGGER $TAGGEROPTS --commen=::"$COMMENTOUTPUT" \
674 -A "$DALBUM" -a "$TRACKARTIST" -t "$TRACKNAME" -Y "$CDYEAR" \
675 -G "$GENREID" -n "${TRACKNUM:-$1}" "${TRACKNUM:+-N $TRACKS}" \
676 "${ENCODING:+--set-encoding=$ENCODING}"
677 "$ABCDETEMPDIR/track$1.$OUTPUT"
678 ;;
679 *)
680 # FIXME # track numbers in mp3 come with 1/10, so we cannot happily substitute them with $TRACKNUM
681 run_command tagtrack-$OUTPUT-$1 $TAGGER $TAGGEROPTS -c "$COMMENTOUTPUT" \
682 -A "$DALBUM" -a "$TRACKARTIST" -t "$TRACKNAME" -y "$CDYEAR" \
683 -g "$GENREID" -T "${TRACKNUM:-$1/$TRACKS}" \
684 "$ABCDETEMPDIR/track$1.$OUTPUT"
685 ;;
686 esac
687 ;;
688 vorbis|ogg)
689 case "$OGGENCODERSYNTAX" in
690 vorbize|oggenc)
691 # vorbiscomment can't do in-place modification, mv the file first
692 if [ -f "$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER" -a ! -f "$ABCDETEMPDIR/track$1.uncommented.$OGGOUTPUTCONTAINER" ]; then
693 mv "$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER" "$ABCDETEMPDIR/track$1.uncommented.$OGGOUTPUTCONTAINER"
694 fi
695 (
696 # These are from http://www.xiph.org/ogg/vorbis/doc/v-comment.html
697 echo ARTIST="$TRACKARTIST"
698 echo ALBUM="$DALBUM"
699 echo TITLE="$TRACKNAME"
700 if [ -n "$CDYEAR" ]; then
701 echo DATE="$CDYEAR"
702 fi
703 if [ -n "$CDGENRE" ]; then
704 echo GENRE="$CDGENRE"
705 fi
706 echo TRACKNUMBER=${TRACKNUM:-$1}
707 echo CDDB=$CDDBDISCID
708 if [ "$(eval echo ${COMMENT})" != "" ]; then
709 case "$COMMENTOUTPUT" in
710 *=*) echo "$COMMENTOUTPUT";;
711 *) echo COMMENT="$COMMENTOUTPUT";;
712 esac
713 fi
714 ) | run_command tagtrack-$OUTPUT-$1 $VORBISCOMMENT $VORBISCOMMENTOPTS -w \
715 "$ABCDETEMPDIR/track$1.uncommented.$OGGOUTPUTCONTAINER" "$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER"
716 # Doublecheck that the commented file was created successfully before wiping the original
717 if [ -f "$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER" ]; then
718 rm -f "$ABCDETEMPDIR/track$1.uncommented.$OGGOUTPUTCONTAINER"
719 else
720 mv "$ABCDETEMPDIR/track$1.uncommented.$OGGOUTPUTCONTAINER" "$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER"
721 fi
722 ;;
723 esac
724 ;;
725 flac)
726 (
727 echo ARTIST="$TRACKARTIST"
728 echo ALBUM="$DALBUM"
729 echo TITLE="$TRACKNAME"
730 if [ -n "$CDYEAR" ]; then
731 echo DATE="$CDYEAR"
732 fi
733 if [ -n "$CDGENRE" ]; then
734 echo GENRE="$CDGENRE"
735 fi
736 echo TRACKNUMBER="${TRACKNUM:-$1}"
737 echo CDDB="$CDDBDISCID"
738 if [ "$(eval echo ${COMMENT})" != "" ]; then
739 case "$COMMENTOUTPUT" in
740 *=*) echo "$COMMENTOUTPUT";;
741 *) echo COMMENT="$COMMENTOUTPUT";;
742 esac
743 fi
744 ) | run_command tagtrack-$OUTPUT-$1 $METAFLAC $METAFLACOPTS ${IMPORTCUESHEET:+--import-cuesheet-from="$ABCDETEMPDIR/$CUEFILE"} --import-tags-from=- "$ABCDETEMPDIR/track$1.$FLACOUTPUTCONTAINER"
745 ;;
746 spx)
747 run_command tagtrack-$OUTPUT-$1 true
748 ;;
749 mpc)
750 run_command tagtrack-$OUTPUT-$1 true
751 ;;
752 m4a)
753 run_command tagtrack-$OUTPUT-$1 true
754 ;;
755 wav)
756 run_command tagtrack-$OUTPUT-$1 true
757 ;;
758 esac
759 done
760 if checkerrors "tagtrack-(.{3,6})-$1"; then :; else
761 run_command tagtrack-$1 true
762 fi
763
764 }
765
766 # do_nogap_encode
767 # variables used:
768 # OUTPUTTYPE, {FOO}ENCODERSYNTAX, ENCNICE, ENCODER, ENCODEROPTS
769 do_nogap_encode ()
770 {
771 # The commands here don't go through run_command because they're never supposed to be silenced
772 echo "Encoding gapless MP3 tracks: $TRACKQUEUE"
773 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
774 do
775 case "$OUTPUT" in
776 mp3)
777 case "$MP3ENCODERSYNTAX" in
778 lame)
779 (
780 cd "$ABCDETEMPDIR"
781 TRACKFILES=
782 for UTRACKNUM in $TRACKQUEUE
783 do
784 TRACKFILES="$TRACKFILES track$UTRACKNUM.wav"
785 done
786 nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS --nogap $TRACKFILES
787 RETURN=$?
788 if [ "$RETURN" != "0" ]; then
789 echo "nogap-encode: $ENCODER returned code $RETURN" >> errors
790 else
791 for UTRACKNUM in $TRACKQUEUE
792 do
793 run_command encodetrack-$OUTPUT-$UTRACKNUM true
794 #run_command encodetrack-$UTRACKNUM true
795 done
796 fi
797 )
798 ;;
799 esac
800 ;;
801 esac
802 done
803 if checkerrors "nogap-encode"; then :; else
804 if [ ! "$KEEPWAVS" = "y" ] ; then
805 if [ ! "$KEEPWAVS" = "move" ] ; then
806 rm -f "$IN"
807 fi
808 fi
809 fi
810 # Other encoders fall through to normal encoding as the tracks
811 # have not been entered in the status file.
812 }
813
814 # do_encode [tracknumber] [hostname]
815 # If no hostname is specified, encode locally
816 # variables used:
817 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
818 do_encode ()
819 {
820 if [ "$USEPIPES" = "y" ]; then
821 case "$OUTPUT" in
822 mp3)
823 TEMPARG="PIPE_$MP3ENCODERSYNTAX"
824 ;;
825 vorbis|ogg)
826 TEMPARG="PIPE_$OGGENCODERSYNTAX"
827 ;;
828 flac)
829 TEMPARG="PIPE_$FLACENCODERSYNTAX"
830 ;;
831 spx)
832 TEMPARG="PIPE_$SPEEXENCODER"
833 ;;
834 mpc)
835 TEMPARG="PIPE_$MPPENCODER"
836 ;;
837 m4a)
838 TEMPARG="PIPE_$MPPENCODER"
839 ;;
840 esac
841 IN="$( eval echo "\$$TEMPARG" )"
842 else
843 IN="$ABCDETEMPDIR/track$1.wav"
844 case "$OUTPUT" in
845 mp3)
846 case "$MP3ENCODERSYNTAX" in
847 # FIXME # check if mp3enc needs -if for pipes
848 # FIXME # I have not been able to find a working mp3enc binary
849 mp3enc)
850 FILEARG="-if $IN"
851 ;;
852 *)
853 FILEARG="$IN"
854 ;;
855 esac
856 ;;
857 *)
858 FILEARG="$IN"
859 ;;
860 esac
861 fi
862 # We need IN to proceed, if we are not using pipes.
863 if [ -s "$IN" -o X"$USEPIPES" = "Xy" ] ; then
864 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
865 do
866 case "$OUTPUT" in
867 vorbis|ogg)
868 OUT="$ABCDETEMPDIR/track$1.$OGGOUTPUTCONTAINER"
869 OUTPUT=$OGGOUTPUTCONTAINER
870 ;;
871 flac)
872 OUT="$ABCDETEMPDIR/track$1.$FLACOUTPUTCONTAINER"
873 OUTPUT=$FLACOUTPUTCONTAINER
874 ;;
875 *)
876 OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
877 ;;
878 esac
879 if [ "$NOGAP" = "y" ] && checkstatus encodetrack-$OUTPUT-$1 ; then
880 continue
881 fi
882 if [ X"$USEPIPES" = "Xy" ]; then
883 RUN_COMMAND=""
884 # We need a way to store the creation of the files when using PIPES
885 RUN_COMMAND_PIPES="run_command encodetrack-$OUTPUT-$1 true"
886 else
887 run_command '' echo "Encoding track $1 of $TRACKS: $TRACKNAME..."
888 RUN_COMMAND="run_command encodetrack-$OUTPUT-$1"
889 fi
890 case "$OUTPUT" in
891 mp3)
892 case "$2" in
893 %local*%)
894 case "$MP3ENCODERSYNTAX" in
895 lame|gogo) $RUN_COMMAND nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS "$IN" "$OUT" ;;
896 bladeenc) $RUN_COMMAND nice $ENCNICE $MP3ENCODER $MP3ENCODEROPTS -quit "$IN" ;;
897 l3enc|xingmp3enc) $RUN_COMMAND nice $ENCNICE $MP3ENCODER "$IN" "$OUT" $MP3ENCODEROPTS ;;
898 # FIXME # Relates to the previous FIXME since it might need the "-if" removed.
899 mp3enc) $RUN_COMMAND nice $ENCNICE $MP3ENCODER -if "$IN" -of "$OUT" $MP3ENCODEROPTS ;;
900 esac
901 ;;
902 *)
903 $RUN_COMMAND nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" >/dev/null 2>&1
904 ;;
905 esac
906 ;;
907 vorbis|ogg)
908 case "$2" in
909 %local*%)
910 case "$OGGENCODERSYNTAX" in
911 vorbize) $RUN_COMMAND nice $ENCNICE $OGGENCODER $OGGENCODEROPTS -w "$OUT" "$IN" ;;
912 oggenc) $RUN_COMMAND nice $ENCNICE $OGGENCODER $OGGENCODEROPTS -o "$OUT" "$IN" ;;
913 esac
914 ;;
915 *)
916 $RUN_COMMAND nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" >/dev/null 2>&1
917 ;;
918 esac
919 ;;
920 flac)
921 case "$2" in
922 %local*%)
923 case "$FLACENCODERSYNTAX" in
924 flac) $RUN_COMMAND nice $ENCNICE $FLACENCODER -f $FLACENCODEROPTS -o "$OUT" "$IN" ;;
925 esac
926 ;;
927 *)
928 vecho -n "DISTMP3:"
929 vecho "$DISTMP3 $DISTMP3OPTS $2 $IN $OUT >/dev/null 2>&1"
930 $RUN_COMMAND nice $DISTMP3NICE $DISTMP3 $DISTMP3OPTS "$2" "$IN" "$OUT" > /dev/null 2>&1
931 ;;
932 esac
933 ;;
934 spx)
935 if [ "$(eval echo ${COMMENT})" != "" ]; then
936 case "$COMMENT" in
937 *=*) ;;
938 *) COMMENT="COMMENT=$COMMENT" ;;
939 esac
940 COMMENT="--comment \"$COMMENT\""
941 fi
942 # Quick hack to avoid tagging Ogg/Speex, since there is no other way to tag than inline tagging
943 if [ ! "$DOTAG" = "y" ]; then
944 $RUN_COMMAND nice $ENCNICE $SPEEXENCODER $SPEEXENCODEROPTS --author "$TRACKARTIST" --title "$TRACKNAME" "$COMMENT" "$IN" "$OUT"
945 else
946 $RUN_COMMAND nice $ENCNICE $SPEEXENCODER $SPEEXENCODEROPTS "$IN" "$OUT"
947 fi
948 ;;
949 mpc)
950 # MPP/MP+(Musepack) format (.mpc) is done locally, with inline
951 # tagging.
952 # I tried compiling the mppenc from corecodecs.org and got some
953 # errors, so I have not tried it myself.
954 ## FIXME ## Needs some cleanup to determine if an empty tag sent
955 ## FIXME ## to the encoder ends up empty.
956 $RUN_COMMAND nice $ENCNICE $MPPENCODER $MPPENCODEROPTS --artist "$TRACKARTIST" --album "$DALBUM" --title "$TRACKNAME" --track "$1" --genre "$CDGENRE" --year "$CDYEAR" --comment "$COMMENT" "$IN" "$OUT"
957 ;;
958 m4a)
959 # Quick hack to avoid tagging Ogg/Speex, since there is no other way to tag than inline tagging
960 if [ ! "$DOTAG" = "y" ]; then
961 $RUN_COMMAND nice $ENCNICE $AACENCODER $AACENCODEROPTS --artist "$TRACKARTIST" --album "$DALBUM" --title "$TRACKNAME" --track "$1" --genre "$CDGENRE" --year "$CDYEAR" --comment "$COMMENT" -o "$OUT" "$IN"
962
963 else
964 $RUN_COMMAND nice $ENCNICE $AACENCODER $AACENCODEROPTS -o "$OUT" "$IN"
965 fi
966 ;;
967 wav)
968 # In case of wav output we need nothing. Just keep the wavs.
969 ;;
970 esac
971 $RUN_COMMAND_PIPES
972 done
973 # Only remove .wav if the encoding succeeded
974 if checkerrors "encodetrack-(.{3,6})-$1"; then :; else
975 run_command encodetrack-$1 true
976 if [ ! "$KEEPWAVS" = "y" ] ; then
977 if [ ! "$KEEPWAVS" = "move" ] ; then
978 rm -f "$IN"
979 fi
980 fi
981 fi
982 else
983 run_command "" echo "HEH! The file we were about to encode disappeared:"
984 run_command "" echo ">> $IN"
985 run_command encodetrack-$1 false
986 fi
987 }
988
989 # do_preprocess [tracknumber]
990 # variables used:
991 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
992 #do_preprocess ()
993 #{
994 # IN="$ABCDETEMPDIR/track$1.wav"
995 # # We need IN to proceed.
996 # if [ -s "$IN" ] ; then
997 # for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
998 # do
999 # #OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
1000 # run_command '' echo "Pre-processing track $1 of $TRACKS..."
1001 # case "$POSTPROCESSFORMAT" in
1002 # all|wav*)
1003 # run_command preprocess-$OUTPUT-$1 nice $PRENICE $WAV_PRE $IF $OF ;;
1004 # mp3)
1005 # run_command preprocess-$OUTPUT-$1 nice $PRENICE $MP3_PRE $IF $OF ;;
1006 # ogg)
1007 # run_command preprocess-$OUTPUT-$1 nice $PRENICE $OGG_PRE $IF $OF ;;
1008 # flac)
1009 # run_command preprocess-$OUTPUT-$1 nice $PRENICE $FLAC_PRE $IF $OF ;;
1010 # spx)
1011 # run_command preprocess-$OUTPUT-$1 nice $PRENICE $SPX_PRE $IF $OF ;;
1012 # esac
1013 # done
1014 # # Only remove .wav if the encoding succeeded
1015 # if checkerrors "preprocess-(.{3,4})-$1"; then
1016 # run_command preprocess-$1 false
1017 # else
1018 # run_command preprocess-$1 true
1019 # fi
1020 # else
1021 # if [ "$(checkstatus encode-output)" = "loud" ]; then
1022 # echo "HEH! The file we were about to pre-process disappeared:"
1023 # echo ">> $IN"
1024 # fi
1025 # run_command preprocess-$1 false
1026 # fi
1027 #}
1028
1029
1030 # do_postprocess [tracknumber]
1031 # variables used:
1032 # TRACKS, TRACKNAME, TRACKARTIST, DISTMP3, DISTMP3OPTS, {FOO}ENCODERSYNTAX, OUTPUTTYPE, ENCODEROPTS, DALBUM, DARTIST, ENCNICE, CDYEAR, CDGENRE, COMMENT
1033 #do_postprocess ()
1034 #{
1035 # for POSTPROCESSFORMAT in $(echo $POSTPROCESSFORMATS | tr , \ )
1036 # do
1037 # IN="$ABCDETEMPDIR/track$1.$POSTPROCESSFORMAT"
1038 # # We need IN to proceed.
1039 # if [ -s "$IN" ] ; then
1040 # #OUT="$ABCDETEMPDIR/track$1.$OUTPUT"
1041 # run_command '' echo "Post-processing track $1 of $TRACKS..."
1042 # case "$POSTPROCESSFORMAT" in
1043 # mp3)
1044 # run_command postprocess-$OUTPUT-$1 nice $POSTNICE $MP3_POST $IF $OF ;;
1045 # ogg)
1046 # run_command postprocess-$OUTPUT-$1 nice $POSTNICE $OGG_POST $IF $OF ;;
1047 # flac)
1048 # run_command postprocess-$OUTPUT-$1 nice $POSTNICE $FLAC_POST $IF $OF ;;
1049 # spx)
1050 # run_command postprocess-$OUTPUT-$1 nice $POSTNICE $SPX_POST $IF $OF ;;
1051 # esac
1052 # # Only remove .wav if the encoding succeeded
1053 # if checkerrors "postprocess-(.{3,4})-$1"; then
1054 # run_command postprocess-$1 false
1055 # else
1056 # run_command postprocess-$1 true
1057 # fi
1058 # else
1059 # if [ "$(checkstatus encode-output)" = "loud" ]; then
1060 # echo "HEH! The file we were about to post-process disappeared:"
1061 # echo ">> $IN"
1062 # fi
1063 # run_command postprocess-$1 false
1064 # fi
1065 # done
1066 #}
1067
1068 # do_single_gain
1069 # variables used:
1070 # FIXME #
1071 do_single_gain ()
1072 {
1073 :
1074 }
1075
1076 # do_batch_gain
1077 # variables used:
1078 # MP3GAIN, MP3GAINOPTS, VORBISGAIN, VORBISGAINOPTS, MPPGAIN, MPPGAINOPTS
1079 # FIXME #
1080 do_batch_gain ()
1081 {
1082 # The commands here don't go through run_command because they're never supposed to be silenced
1083 echo "Batch analizing gain in tracks: $TRACKQUEUE"
1084 (
1085 cd "$ABCDETEMPDIR"
1086 BLURB=
1087 TRACKFILES=
1088 for UTRACKNUM in $TRACKQUEUE
1089 do
1090 MP3FILES="$TRACKFILES track$UTRACKNUM.mp3"
1091 done
1092 # FIXME # Hard-coded batch option!
1093 $NORMALIZER -b $NORMALIZEROPTS $TRACKFILES
1094 RETURN=$?
1095 if [ "$RETURN" != "0" ]; then
1096 echo "batch-normalize: $NORMALIZER returned code $RETURN" >> errors
1097 else
1098 for UTRACKNUM in $TRACKQUEUE
1099 do
1100 echo normalizetrack-$UTRACKNUM >> status
1101 done
1102 fi
1103 )
1104 }
1105
1106 # do_batch_normalize
1107 # variables used:
1108 # NORMALIZER, NORMALIZEROPTS
1109 do_batch_normalize ()
1110 {
1111 # The commands here don't go through run_command because they're never supposed to be silenced
1112 echo "Batch normalizing tracks: $TRACKQUEUE"
1113 (
1114 cd "$ABCDETEMPDIR"
1115 BLURB=
1116 TRACKFILES=
1117 for UTRACKNUM in $TRACKQUEUE
1118 do
1119 TRACKFILES="$TRACKFILES track$UTRACKNUM.wav"
1120 done
1121 # XXX: Hard-coded batch option!
1122 $NORMALIZER -b $NORMALIZEROPTS $TRACKFILES
1123 RETURN=$?
1124 if [ "$RETURN" != "0" ]; then
1125 echo "batch-normalize: $NORMALIZER returned code $RETURN" >> errors
1126 else
1127 for UTRACKNUM in $TRACKQUEUE
1128 do
1129 echo normalizetrack-$UTRACKNUM >> status
1130 done
1131 fi
1132 )
1133 }
1134
1135 # do_normalize [tracknumber]
1136 # variables used:
1137 # TRACKS, TRACKNAME, NORMALIZER, NORMALIZEROPTS
1138 do_normalize ()
1139 {
1140 IN="$ABCDETEMPDIR/track$1.wav"
1141 if [ -e "$IN" ] ; then
1142 run_command '' echo "Normalizing track $1 of $TRACKS: $TRACKNAME..."
1143 run_command normalizetrack-$1 $NORMALIZER $NORMALIZEROPTS "$IN"
1144 else
1145 if [ "$(checkstatus encode-output)" = "loud" ]; then
1146 echo "HEH! The file we were about to normalize disappeared:"
1147 echo ">> $IN"
1148 fi
1149 run_command normalizetrack-$1 false "File $IN was not found"
1150 fi
1151 }
1152
1153 # do_move [tracknumber]
1154 # Deduces the outfile from environment variables
1155 # Creates directory if necessary
1156 # variables used:
1157 # TRACKNUM, TRACKNAME, TRACKARTIST, DALBUM, OUTPUTFORMAT, CDGENRE, CDYEAR
1158 do_move ()
1159 {
1160 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
1161 do
1162 # Create ALBUMFILE, ARTISTFILE, TRACKFILE
1163 # Munge filenames as follows:
1164 # ' ' -> '_'
1165 # '/' -> '_'
1166 # ''' -> ''
1167 # '?' -> ''
1168 # Eat control characters
1169 ALBUMFILE="$(mungefilename "$DALBUM")"
1170 ARTISTFILE="$(mungefilename "$TRACKARTIST")"
1171 TRACKFILE="$(mungefilename "$TRACKNAME")"
1172 GENRE="$(mungegenre "$GENRE")"
1173 YEAR="$(echo $CDYEAR)"
1174 # If we want to start the tracks with a given number, we need to modify the
1175 # TRACKNUM value before evaluation
1176 do_gettracknum
1177 # Supported variables for OUTPUTFORMAT are GENRE, ALBUMFILE, ARTISTFILE,
1178 # TRACKFILE, and TRACKNUM.
1179 if [ "$VARIOUSARTISTS" = "y" ]; then
1180 OUTPUTFILE="$(eval echo "$VAOUTPUTFORMAT")"
1181 else
1182 OUTPUTFILE="$(eval echo "$OUTPUTFORMAT")"
1183 fi
1184 if checkerrors "tagtrack-$OUTPUT-$1"; then :; else
1185 # Once we know the specific output was successful, we can change the OUTPUT to the value containing the container
1186 case $OUTPUT in
1187 vorbis|ogg)
1188 OUTPUT=$OGGOUTPUTCONTAINER
1189 ;;
1190 flac)
1191 OUTPUT=$FLACOUTPUTCONTAINER
1192 ;;
1193 esac
1194 # Check that the directory for OUTPUTFILE exists, if it doesn't, create it
1195 OUTPUTFILEDIR="$(dirname "$OUTPUTDIR/$OUTPUTFILE")"
1196 case $OUTPUT in
1197 wav)
1198 if [ "$DOCLEAN" != "y" ] && [ "$FORCE" != "y" ]; then
1199 # FIXME # introduce warnings?
1200 :
1201 else
1202 # mkdir -p shouldn't return an error if the directory already exists
1203 mkdir -p "$OUTPUTFILEDIR"
1204 run_command movetrack-$1 mv "$ABCDETEMPDIR/track$1.$OUTPUT" "$OUTPUTDIR/$OUTPUTFILE.$OUTPUT"
1205 if checkstatus movetrack-output-$OUTPUT; then :; else
1206 run_command movetrack-output-$OUTPUT true
1207 fi
1208 fi
1209 ;;
1210 *)
1211 # mkdir -p shouldn't return an error if the directory already exists
1212 mkdir -p "$OUTPUTFILEDIR"
1213 run_command movetrack-$1 mv "$ABCDETEMPDIR/track$1.$OUTPUT" "$OUTPUTDIR/$OUTPUTFILE.$OUTPUT"
1214 if checkstatus movetrack-output-$OUTPUT; then :; else
1215 run_command movetrack-output-$OUTPUT true
1216 fi
1217 ;;
1218 esac
1219 # Lets move the cue file
1220 if CUEFILE=$(checkstatus cuefile) >/dev/null ; then
1221 if [ -r "$ABCDETEMPDIR/$CUEFILE" ]; then
1222 if checkstatus movecue-$OUTPUT; then :; else
1223 # Silence the Copying output since it overlaps with encoding processes...
1224 #run_command '' vecho "Copying cue file to its destination directory..."
1225 if checkstatus onetrack >/dev/null ; then
1226 case $OUTPUT in
1227 wav)
1228 if [ "$DOCLEAN" != "y" ] && [ "$FORCE" != "y" ]; then
1229 # We dont have the dir, since it was not created before.
1230 :
1231 else
1232 run_command movecue-$OUTPUT cp "$ABCDETEMPDIR/$CUEFILE" "$OUTPUTDIR/$OUTPUTFILE.cue"
1233 fi
1234 ;;
1235 # NOTE: Creating a cue file with the 3-char-extension files is to comply with
1236 # http://brianvictor.tripod.com/mp3cue.htm#details
1237 [a-z0-9][a-z0-9][a-z0-9])
1238 run_command movecue-$OUTPUT cp "$ABCDETEMPDIR/$CUEFILE" "$OUTPUTDIR/$OUTPUTFILE.cue"
1239 ;;
1240 *)
1241 run_command movecue-$OUTPUT cp "$ABCDETEMPDIR/$CUEFILE" "$OUTPUTDIR/$OUTPUTFILE.$OUTPUT.cue"
1242 ;;
1243 esac
1244 else
1245 run_command movecue-$OUTPUT cp "$ABCDETEMPDIR/$CUEFILE" "$OUTPUTFILEDIR/$CUEFILE"
1246 fi
1247 echo movecue-$OUTPUT >> "$ABCDETEMPDIR/status"
1248 fi
1249 fi
1250 fi
1251 fi
1252 done
1253 }
1254
1255 # do_playlist
1256 # Create the playlist if wanted
1257 # Variables used:
1258 # PLAYLISTFORMAT, PLAYLISTDATAPREFIX, VAPLAYLISTFORMAT, VAPLAYLISTDATAPREFIX,
1259 # VARIOUSARTISTS, OUTPUTDIR
1260 do_playlist ()
1261 {
1262 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
1263 do
1264 case $OUTPUT in
1265 vorbis|ogg)
1266 OUTPUT=$OGGOUTPUTCONTAINER
1267 ;;
1268 flac)
1269 OUTPUT=$FLACOUTPUTCONTAINER
1270 ;;
1271 esac
1272 # Create a playlist file for the playlist data to go into.
1273 # We used to wipe it out if it existed. Now we request permision if interactive.
1274 for LASTTRACK in $TRACKQUEUE; do :; done
1275 ALBUMFILE="$(mungefilename "$DALBUM")"
1276 ARTISTFILE="$(mungefilename "$DARTIST")"
1277 GENRE=$(mungegenre "$GENRE")
1278 YEAR=${CDYEAR:-$CDYEAR}
1279 if [ "$VARIOUSARTISTS" = "y" ] ; then
1280 PLAYLISTFILE=$(eval echo $VAPLAYLISTFORMAT)
1281 else
1282 PLAYLISTFILE=$(eval echo $PLAYLISTFORMAT)
1283 fi
1284 FINALPLAYLISTDIR=$(dirname "$OUTPUTDIR/$PLAYLISTFILE")
1285 mkdir -p "$FINALPLAYLISTDIR"
1286 if [ -s "$OUTPUTDIR/$PLAYLISTFILE" ]; then
1287 echo -n "Erase, Append to, or Keep the existing playlist file? [e/a/k] (e): " >&2
1288 if [ "$INTERACTIVE" = "y" ]; then
1289 while [ "$DONE" != "y" ]; do
1290 read ERASEPLAYLIST
1291 case $ERASEPLAYLIST in
1292 e|E|a|A|k|K) DONE=y ;;
1293 *) ;;
1294 esac
1295 done
1296 else
1297 echo e >&2
1298 ERASEPLAYLIST=e
1299 fi
1300 # Once we erase the playlist, we use append to create the new one.
1301 [ "$ERASEPLAYLIST" = "e" -o "$ERASEPLAYLIST" = "E" ] && rm -f "$OUTPUTDIR/$PLAYLISTFILE" && ERASEPLAYLIST=a
1302 else
1303 # The playlist does not exist, so we can safelly use append to create the new list
1304 ERASEPLAYLIST=a
1305 fi
1306 if [ "$ERASEPLAYLIST" = "a" -o "$ERASEPLAYLIST" = "A" ]; then
1307 touch "$OUTPUTDIR/$PLAYLISTFILE"
1308 for UTRACKNUM in $TRACKQUEUE
1309 do
1310 # Shares some code with do_move since the filenames have to match
1311 CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
1312 do_getcddbinfo TRACKNAME
1313 splitvarious
1314 TRACKFILE="$(mungefilename "$TRACKNAME")"
1315 ARTISTFILE="$(mungefilename "$TRACKARTIST")"
1316 ALBUMFILE="$(mungefilename "$DALBUM")"
1317 # If we want to start the tracks with a given number, we need to modify the
1318 # TRACKNUM value before evaluation
1319 do_gettracknum
1320 if [ "$VARIOUSARTISTS" = "y" ]; then
1321 OUTPUTFILE=$(eval echo $VAOUTPUTFORMAT)
1322 else
1323 OUTPUTFILE=$(eval echo $OUTPUTFORMAT)
1324 fi
1325 if [ "$VARIOUSARTISTS" = "y" ]; then
1326 if [ "$VAPLAYLISTDATAPREFIX" ] ; then
1327 echo ${VAPLAYLISTDATAPREFIX}$OUTPUTFILE.$OUTPUT >> "$OUTPUTDIR/$PLAYLISTFILE"
1328 else
1329 relpath "$PLAYLISTFILE", "$OUTPUTFILE.$OUTPUT" >> "$OUTPUTDIR/$PLAYLISTFILE"
1330 fi
1331 else
1332 if [ "$PLAYLISTDATAPREFIX" ]; then
1333 echo ${PLAYLISTDATAPREFIX}$OUTPUTFILE.$OUTPUT >> "$OUTPUTDIR/$PLAYLISTFILE"
1334 else
1335 relpath "$PLAYLISTFILE", "$OUTPUTFILE.$OUTPUT" >> "$OUTPUTDIR/$PLAYLISTFILE"
1336 fi
1337 fi
1338 done
1339 fi
1340 ## this will convert the playlist to have CRLF line-endings, if specified
1341 ## (some hardware players insist on CRLF endings)
1342 if [ "$DOSPLAYLIST" = "y" ]; then
1343 awk '{substr("\r",""); printf "%s\r\n", $0}' "$OUTPUTDIR/$PLAYLISTFILE" > "$ABCDETEMPDIR/PLAYLISTFILE.tmp"
1344 # mv -f "$ABCDETEMPDIR/PLAYLISTFILE.tmp" "$OUTPUTDIR/$PLAYLISTFILE"
1345 cat "$ABCDETEMPDIR/PLAYLISTFILE.tmp" | sed 's/\//\\/' > "$OUTPUTDIR/$PLAYLISTFILE"
1346 fi
1347 echo "playlistcomplete" >> "$ABCDETEMPDIR/status"
1348 done
1349 }
1350
1351 # do_discid
1352 # This essentially the start of things
1353 do_discid ()
1354 {
1355 # Query the CD to get the track info, unless the user specified -C
1356 # or we are using some actions which do not need the CDDB data at all
1357 #if [ ! X"$EXPACTIONS" = "X" ]; then
1358 # :
1359 #elif [ -z "$DISCID" ]; then
1360 if [ -z "$DISCID" ]; then
1361 vecho -n "Getting CD track info... "
1362 # In OSX, unmount the disc before a query
1363 if [ "$OSFLAVOUR" = "OSX" ]; then
1364 disktool -u ${CDROM#/dev/}
1365 fi
1366 if [ "$CDROMREADERSYNTAX" = "flac" ] ; then
1367 if $METAFLAC $METAFLACOPTS --export-cuesheet-to=- $CDROM > /dev/null 2>&1 ; then
1368 TRACKINFO=$($METAFLAC $METAFLACOPTS --export-cuesheet-to=- $CDROM | $CUE2DISCID)
1369 else
1370 log error "the input flac file does not contain a cuesheet."
1371 exit 1
1372 fi
1373 else
1374 case "$CDDBMETHOD" in
1375 cddb) TRACKINFO=$($CDDISCID $CDROM) ;;
1376 # FIXME # musicbrainz needs a cleanup
1377 musicbrainz) TRACKINFO=$($MUSICBRAINZ -c $CDROM ) ;;
1378 esac
1379 fi
1380 # Make sure there's a CD in there by checking cd-discid's return code
1381 if [ ! "$?" = "0" ]; then
1382 if [ "$CDROMREADERSYNTAX" = "flac" ] ; then
1383 log error "cuesheet information from the flac file could not be read."
1384 log error "Perhaps the flac file does not contain a cuesheet?."
1385 exit 1
1386 else
1387 log error "CD could not be read. Perhaps there's no CD in the drive?"
1388 exit 1
1389 fi
1390 fi
1391 # In OSX, remount the disc again
1392 if [ "$OSFLAVOUR" = "OSX" ]; then
1393 disktool -m ${CDROM#/dev/}
1394 fi
1395 WEHAVEACD=y
1396 DISCID=$(echo $TRACKINFO | cut -f1 -d' ')
1397 else
1398 TRACKINFO=$(cat "$WAVOUTPUTDIR/abcde.$DISCID/discid")
1399 fi
1400
1401 # Get a full enumeration of tracks, sort it, and put it in the TRACKQUEUE.
1402 # This needs to be done now because a section of the resuming code will need
1403 # it later.
1404
1405 # get the number of digits to pad TRACKNUM with - we'll use this later
1406 # a CD can only hold 99 tracks, but since we support a feature for starting
1407 # numbering the tracks from a given number, we might need to set it as a
1408 # variable for the user to define... or obtain it somehow.
1409 if [ "$PADTRACKS" = "y" ] ; then
1410 TRACKNUMPADDING=2
1411 fi
1412
1413 ABCDETEMPDIR="$WAVOUTPUTDIR/abcde.$(echo $TRACKINFO | cut -f1 -d' ')"
1414 if [ -z "$TRACKQUEUE" ]; then
1415 if [ ! "$STRIPDATATRACKS" = "y" ]; then
1416 case "$CDROMREADERSYNTAX" in
1417 cdparanoia|debug)
1418 if [ "$WEHAVEACD" = "y" ]; then
1419 vecho "Querying the CD for audio tracks..."
1420 CDPARANOIAOUTPUT="$( $CDROMREADER -$CDPARANOIACDROMBUS $CDROM -Q --verbose 2>&1 )"
1421 RET=$?
1422 if [ ! "$RET" = "0" ];then
1423 log warning "something went wrong while querying the CD... Maybe a DATA CD?"
1424 fi
1425 TRACKS="$(echo "$CDPARANOIAOUTPUT" | egrep '^[[:space:]]+[[:digit:]]' | tail -n 1 | get_first | tr -d "." | tr '\n' ' ')"
1426 CDPARANOIAAUDIOTRACKS="$TRACKS"
1427 else
1428 # Previous versions of abcde would store the tracks on a file, instead of the status record.
1429 if [ -f "$ABCDETEMPDIR/cdparanoia-audio-tracks" ]; then
1430 echo cdparanoia-audio-tracks=$( cat "$ABCDETEMPDIR/cdparanoia-audio-tracks" ) >> "$ABCDETEMPDIR/status"
1431 rm -f "$ABCDETEMPDIR/cdparanoia-audio-tracks"
1432 fi
1433 if [ -f "$ABCDETEMPDIR/status" ] && TRACKS=$(checkstatus cdparanoia-audio-tracks); then :; else
1434 TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
1435 fi
1436 fi
1437 ;;
1438 *) TRACKS=$(echo $TRACKINFO | cut -f2 -d' ') ;;
1439 esac
1440 else
1441 TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
1442 fi
1443 if echo "$TRACKS" | grep "[[:digit:]]" > /dev/null 2>&1 ;then :;else
1444 log info "The disc does not contain any tracks. Giving up..."
1445 exit 0
1446 fi
1447 echo -n "Grabbing entire CD - tracks: "
1448 if [ ! "$PADTRACKS" = "y" ] ; then
1449 TRACKNUMPADDING=$(echo -n $TRACKS | wc -c | tr -d ' ')
1450 fi
1451 TRACKS=$(printf "%0.${TRACKNUMPADDING}d" $TRACKS)
1452 X=0
1453 while [ "$X" -ne "$TRACKS" ]
1454 do
1455 X=$(printf "%0.${TRACKNUMPADDING}d" $(expr $X + 1))
1456 TRACKQUEUE=$(echo $TRACKQUEUE $X)
1457 done
1458 echo $TRACKQUEUE
1459 else
1460 TRACKS=$(echo $TRACKINFO | cut -f2 -d' ')
1461 # User-supplied track queue.
1462 # Weed out non-numbers, whitespace, then sort and weed out duplicates
1463 TRACKQUEUE=$(echo $TRACKQUEUE | sed 's-[^0-9 ]--g' | tr ' ' '\n' | grep -v ^$ | sort -n | uniq | tr '\n' ' ' | sed 's- $--g')
1464 # Once cleaned, obtain the highest value in the trackqueue for number padding
1465 for LASTTRACK in $TRACKQUEUE; do :; done
1466 if [ ! "$PADTRACKS" = "y" ] ; then
1467 TRACKNUMPADDING=$(echo -n $LASTTRACK | wc -c | tr -d ' ')
1468 fi
1469 # Now we normalize the trackqueue
1470 for TRACK in $TRACKQUEUE ; do
1471 TRACKNUM=$(printf %0.${TRACKNUMPADDING}d $(expr ${TRACK} + 0 ))
1472 PADTRACKQUEUE=$(echo $PADTRACKQUEUE $TRACKNUM)
1473 done
1474 TRACKQUEUE=$PADTRACKQUEUE
1475 echo Grabbing tracks: "$TRACKQUEUE"
1476 fi
1477
1478 QUEUEDTRACKS=$(echo $TRACKQUEUE | wc -w | tr -d ' ')
1479
1480 # We have the discid, create a temp directory after it to store all the temp
1481 # info
1482
1483 if [ -e "$ABCDETEMPDIR" ]; then
1484 echo -n "abcde: attempting to resume from $ABCDETEMPDIR"
1485 # It already exists, see if it's a directory
1486 if [ ! -d "$ABCDETEMPDIR" ]; then
1487 # This is a file/socket/fifo/device/etc, not a directory
1488 # Complain and exit
1489 echo >&2
1490 echo "abcde: file $ABCDETEMPDIR already exists and does not belong to abcde." >&2
1491 echo "Please investigate, remove it, and rerun abcde." >&2
1492 exit 1
1493 fi
1494 echo -n .
1495 # It's a directory, let's see if it's owned by us
1496 if [ ! -O "$ABCDETEMPDIR" ]; then
1497 # Nope, complain and exit
1498 echo >&2
1499 echo "abcde: directory $ABCDETEMPDIR already exists and is not owned by you." >&2
1500 echo "Please investigate, remove it, and rerun abcde." >&2
1501 exit 1
1502 fi
1503 echo .
1504 # See if it's populated
1505 if [ ! -f "$ABCDETEMPDIR/discid" ]; then
1506 # Wipe and start fresh
1507 echo "abcde: $ABCDETEMPDIR/discid not found. Abcde must remove and recreate" >&2
1508 echo -n "this directory to continue. Continue? [y/n] (n)" >&2
1509 if [ "$INTERACTIVE" = "y" ]; then
1510 read ANSWER
1511 else
1512 echo y >&2
1513 ANSWER=y
1514 fi
1515 if [ "$ANSWER" != "y" ]; then
1516 exit 1
1517 fi
1518 rm -rf "$ABCDETEMPDIR" || exit 1
1519 mkdir -p "$ABCDETEMPDIR"
1520 if [ "$?" -gt "0" ]; then
1521 # Directory already exists or could not be created
1522 echo "abcde: Temp directory $ABCDETEMPDIR could not be created." >&2
1523 exit 1
1524 fi
1525 else
1526 # Everything is fine. Check for ^encodetracklocation-
1527 # and encode-output entries in the status file and
1528 # remove them. These are not relevant across sessions.
1529 if [ -f "$ABCDETEMPDIR/status" ]; then
1530 mv "$ABCDETEMPDIR/status" "$ABCDETEMPDIR/status.old"
1531 grep -v ^encodetracklocation- < "$ABCDETEMPDIR/status.old" \
1532 | grep -v ^encode-output > "$ABCDETEMPDIR/status"
1533 fi
1534 # Remove old error messages
1535 if [ -f "$ABCDETEMPDIR/errors" ]; then
1536 rm -f "$ABCDETEMPDIR/errors"
1537 fi
1538 fi
1539 else
1540 # We are starting from scratch
1541 mkdir -p "$ABCDETEMPDIR"
1542 if [ "$?" -gt "0" ]; then
1543 # Directory already exists or could not be created
1544 echo "abcde: Temp directory $ABCDETEMPDIR could not be created." >&2
1545 exit 1
1546 fi
1547 cat /dev/null > "$ABCDETEMPDIR/status"
1548 # Store the abcde version in the status file.
1549 echo "abcde-version=$VERSION" >> "$ABCDETEMPDIR/status"
1550 fi
1551 if [ X"$MAKECUEFILE" = "Xy" -a X"$WEHAVEACD" = "Xy" ]; then
1552 if checkstatus cuefile > /dev/null 2>&1 ; then :; else
1553 CUEFILE=cue-$(echo "$TRACKINFO" | cut -f1 -d' ').txt
1554 vecho "Creating cue file..."
1555 if $CUEREADER $CUEREADEROPTS > "$ABCDETEMPDIR/$CUEFILE"; then
1556 echo cuefile=$CUEFILE >> "$ABCDETEMPDIR/status"
1557 else
1558 log warning "reading the CUE sheet with mkcue is still considered experimental"
1559 log warning "and there was a problem with the CD reading. abcde will continue,"
1560 log warning "but consider reporting the problem to the abcde author"
1561 fi
1562 fi
1563 fi
1564 # If we got the CDPARANOIA status and it is not recorded, save it now
1565 if [ -n "$CDPARANOIAAUDIOTRACKS" ]; then
1566 if checkstatus cdparanoia-audio-tracks > /dev/null 2>&1; then :; else
1567 echo cdparanoia-audio-tracks=$CDPARANOIAAUDIOTRACKS >> "$ABCDETEMPDIR/status"
1568 fi
1569 fi
1570
1571 # Create the discid file
1572 echo "$TRACKINFO" > "$ABCDETEMPDIR/discid"
1573 if checkstatus cddbmethod > /dev/null 2>&1 ; then :; else
1574 echo "cddbmethod=$CDDBMETHOD" >> "$ABCDETEMPDIR/status"
1575 fi
1576 }
1577
1578 # do_cleancue
1579 # Create a proper CUE file based on the CUE file we created before.
1580 do_cleancue()
1581 {
1582 if CUEFILE_IN="$ABCDETEMPDIR"/$(checkstatus cuefile); then
1583 CUEFILE_OUT=$CUEFILE_IN.out
1584 ### FIXME ### checkstatus cddb
1585 if [ -e "$CDDBDATA" ]; then
1586 vecho "Adding metadata to the cue file..."
1587 # FIXME It doesn't preserve spaces! Why?
1588 # FIXME parse $track into PERFORMER and TITLE - abcde already has code for this?
1589 n=1
1590 echo "PERFORMER \"$DARTIST\"" >> "$CUEFILE_OUT"
1591 echo "TITLE \"$DALBUM\"" >> "$CUEFILE_OUT"
1592 cat "$CUEFILE_IN" | while read line
1593 do
1594 if echo "$line" | grep -q "INDEX"
1595 then
1596 eval track="\$TRACK$n"
1597 n=$(expr $n + 1)
1598 echo "TITLE \"$track\"" >> "$CUEFILE_OUT"
1599 fi
1600 echo "$line" >> "$CUEFILE_OUT"
1601 done
1602 mv "$CUEFILE_OUT" "$CUEFILE_IN"
1603 echo "cleancuefile" >> "$ABCDETEMPDIR/status"
1604 fi
1605 fi
1606 }
1607
1608 # do_cddbparse
1609 # Parses a CDDB file and outputs the title and the track names.
1610 # Variables: CDDBFILE
1611 do_cddbparse ()
1612 {
1613 CDDBPARSEFILE="$1"
1614 # List out disc title/author and contents
1615 if [ "$ONETRACK" = "y" ]; then
1616 vecho "ONETRACK mode selected: displaying only the title of the CD..."
1617 fi
1618 echo "---- $(grep DTITLE "${CDDBPARSEFILE}" | cut '-d=' -f2- | tr -d \\r\\n ) ----"
1619 if [ X"$SHOWCDDBYEAR" = "Xy" ]; then
1620 PARSEDYEAR=$(grep DYEAR "${CDDBPARSEFILE}" | cut '-d=' -f2-)
1621 if [ ! X"$PARSEDYEAR" = "X" ]; then
1622 echo "Year: $PARSEDYEAR"
1623 fi
1624 fi
1625 if [ X"$SHOWCDDBGENRE" = "Xy" ]; then
1626 PARSEDGENRE=$(grep DGENRE "${CDDBPARSEFILE}" | cut '-d=' -f2-)
1627 if [ ! X"$PARSEDGENRE" = "X" ]; then
1628 echo "Genre: $PARSEDGENRE"
1629 fi
1630 fi
1631 if [ ! "$ONETRACK" = "y" ]; then
1632 for TRACK in $(f_seq_row 1 $TRACKS)
1633 do
1634 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "${CDDBPARSEFILE}" | cut -f2- -d= | tr -d \\r\\n)"
1635 done
1636 fi
1637 }
1638
1639 # do_localcddb
1640 # Check for a local CDDB file, and report success
1641 do_localcddb ()
1642 {
1643 if checkstatus cddb-readcomplete && checkstatus cddb-choice >/dev/null; then :; else
1644
1645 CDDBLOCALSTATUS="notfound"
1646 CDDBDISCID=$(echo $TRACKINFO | cut -d' ' -f1)
1647 USELOCALRESP="y"
1648
1649 if [ "$CDDBLOCALRECURSIVE" = "y" ]; then
1650 CDDBLOCALRESULTS="$(find ${CDDBLOCALDIR} -name "${CDDBDISCID}" -type f 2> /dev/null)"
1651 if [ ! "${CDDBLOCALRESULTS}" = "" ]; then
1652 if (( $(echo "${CDDBLOCALRESULTS}" | wc -l) == 1 )); then
1653 CDDBLOCALFILE="${CDDBLOCALRESULTS}"
1654 CDDBLOCALMATCH=single
1655 elif (( $(echo "${CDDBLOCALRESULTS}" | wc -l) > 1 )); then
1656 CDDBLOCALMATCH=multiple
1657 fi
1658 else
1659 CDDBLOCALMATCH=none
1660 fi
1661 elif [ "$CDDBLOCALMATCH" = "none" ] && [ -r "${CDDBLOCALDIR}/${CDDBDISCID}" ]; then
1662 CDDBLOCALFILE="${CDDBLOCALDIR}/${CDDBDISCID}"
1663 CDDBLOCALMATCH=single
1664 else
1665 CDDBLOCALMATCH=none
1666 fi
1667
1668 # If the user has selected to check a local CDDB repo, we proceed with it
1669 case $CDDBLOCALMATCH in
1670 multiple)
1671 echo "Processing multiple matching CDDB entries..." > "$ABCDETEMPDIR/cddblocalchoices"
1672 X=0
1673 echo "$CDDBLOCALRESULTS" | while read RESULT ; do
1674 X=$(expr $X + 1)
1675 # List out disc title/author and contents
1676 CDDBLOCALREAD="$ABCDETEMPDIR/cddblocalread.$X"
1677 cat "$RESULT" > "${CDDBLOCALREAD}"
1678 {
1679 echo -n "#$X: "
1680 do_cddbparse "${CDDBLOCALREAD}"
1681 echo ""
1682 } >> "$ABCDETEMPDIR/cddblocalchoices"
1683 done
1684 CDDBLOCALCHOICES=$( echo "$CDDBLOCALRESULTS" | wc -l )
1685 cat "$ABCDETEMPDIR/cddblocalchoices"
1686 CDDBLOCALCHOICENUM=-1
1687 if [ "$INTERACTIVE" = "y" ]; then
1688 while [ $CDDBLOCALCHOICENUM -lt 0 ] || [ $CDDBLOCALCHOICENUM -gt $CDDBLOCALCHOICES ]; do
1689 echo -n "Locally cached CDDB entries found. Which one would you like to use (0 for none)? [0-$CDDBLOCALCHOICES]: " >&2
1690 read CDDBLOCALCHOICENUM
1691 [ x"$CDDBLOCALCHOICENUM" = "x" ] && CDDBLOCALCHOICENUM="1"
1692 done
1693 else
1694 ### FIXME ###
1695 echo "Selected ..."
1696 CDDBLOCALRESP=y
1697 fi
1698 if [ ! "$CDDBLOCALCHOICENUM" = "0" ]; then
1699 #echo "Using local copy of CDDB data"
1700 echo "# DO NOT ERASE THIS LINE! Added by abcde to imitate cddb output" > "$ABCDETEMPDIR/cddbread.1"
1701 cat "$ABCDETEMPDIR/cddblocalread.$CDDBLOCALCHOICENUM" >> "$ABCDETEMPDIR/cddbread.1"
1702 echo 999 > "$ABCDETEMPDIR/cddbquery" # Assuming 999 isn't used by CDDB
1703 echo cddb-readcomplete >> "$ABCDETEMPDIR/status"
1704 do_cddbparse "$ABCDETEMPDIR/cddbread.1" > "$ABCDETEMPDIR/cddbchoices"
1705 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1706 CDDBLOCALSTATUS="found"
1707 else
1708 #echo "Not using local copy of CDDB data"
1709 CDDBLOCALSTATUS="notfound"
1710 fi
1711 ;;
1712 single)
1713 # List out disc title/author and contents
1714 do_cddbparse "${CDDBLOCALFILE}"
1715 if [ "$CDROMREADERSYNTAX" = "flac" ] ; then
1716 echo -n "Embedded cuesheet entry found, use it? [y/n] (y): " >&2
1717 else
1718 echo -n "Locally cached CDDB entry found, use it? [y/n] (y): " >&2
1719 fi
1720 if [ "$INTERACTIVE" = "y" ]; then
1721 read USELOCALRESP
1722 while [ "$USELOCALRESP" != "y" ] && [ "$USELOCALRESP" != "n" ] && [ "$USELOCALRESP" != "" ] ; do
1723 echo -n 'Invalid selection. Please answer "y" or "n": ' >&2
1724 read USELOCALRESP
1725 done
1726 [ x"$USELOCALRESP" = "x" ] && USELOCALRESP="y"
1727 else
1728 echo "y" >&2
1729 fi
1730 if [ "$USELOCALRESP" = "y" ]; then
1731 #echo "Using local copy of CDDB data"
1732 echo "# DO NOT ERASE THIS LINE! Added by abcde to imitate cddb output" > "$ABCDETEMPDIR/cddbread.1"
1733 cat "${CDDBLOCALFILE}" >> "$ABCDETEMPDIR/cddbread.1"
1734 echo 999 > "$ABCDETEMPDIR/cddbquery" # Assuming 999 isn't used by CDDB
1735 echo cddb-readcomplete >> "$ABCDETEMPDIR/status"
1736 do_cddbparse "${CDDBLOCALFILE}" > "$ABCDETEMPDIR/cddbchoices"
1737 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1738 CDDBLOCALSTATUS="single"
1739 else
1740 #echo "Not using local copy of CDDB data"
1741 CDDBLOCALSTATUS="notfound"
1742 fi
1743 ;;
1744 none)
1745 CDDBLOCALSTATUS="notfound"
1746 ;;
1747 esac
1748 fi
1749 }
1750
1751 do_musicbrainzstat ()
1752 {
1753 :
1754 }
1755
1756 do_musizbrainz ()
1757 {
1758 :
1759 }
1760
1761 # do_cddbstat
1762 do_cddbstat ()
1763 {
1764 # Perform CDDB protocol version check if it hasn't already been done
1765 if checkstatus cddb-statcomplete; then :; else
1766 if [ "$CDDBAVAIL" = "n" ]; then
1767 ERRORCODE=no_query
1768 echo 503 > "$ABCDETEMPDIR/cddbstat"
1769 else
1770 rc=1
1771 CDDBUSER=$(echo $HELLOINFO | cut -f1 -d'@')
1772 CDDBHOST=$(echo $HELLOINFO | cut -f2- -d'@')
1773 while test $rc -eq 1 -a $CDDBPROTO -ge 3; do
1774 vecho "Checking CDDB server status..."
1775 $CDDBTOOL stat $CDDBURL $CDDBUSER $CDDBHOST $CDDBPROTO > "$ABCDETEMPDIR/cddbstat"
1776 RESPONSECODE=$(head -n 1 "$ABCDETEMPDIR/cddbstat" | cut -f1 -d' ')
1777 case "$RESPONSECODE" in
1778 210) # 210 OK, status information follows (until terminating `.')
1779 rc=0;
1780 ;;
1781 501|*) # 501 Illegal CDDB protocol level: <n>.
1782 CDDBPROTO=`expr $CDDBPROTO - 1`
1783 ;;
1784 esac
1785 done
1786 if test $rc -eq 1; then
1787 CDDBAVAIL="n"
1788 fi
1789 fi
1790 echo cddb-statcomplete >> "$ABCDETEMPDIR/status"
1791 fi
1792 }
1793
1794
1795 # do_cddbquery
1796 do_cddbquery ()
1797 {
1798 CDDBDISCID=$(echo $TRACKINFO | cut -d' ' -f1)
1799 CDDBLOCALFILE="${CDDBLOCALDIR}/${CDDBDISCID}"
1800
1801 # Perform CDDB query if it hasn't already been done
1802 if checkstatus cddb-querycomplete; then :; else
1803 if [ "$CDDBAVAIL" = "n" ]; then
1804 ERRORCODE=no_query
1805 echo 503 > "$ABCDETEMPDIR/cddbquery"
1806 # The default CDDBLOCALSTATUS is "notfound"
1807 # This part will be triggered if the user CDDB repo does not
1808 # contain the entry, or if we are not trying to use the repo.
1809 else
1810 vecho "Querying the CDDB server..."
1811 CDDBUSER=$(echo $HELLOINFO | cut -f1 -d'@')
1812 CDDBHOST=$(echo $HELLOINFO | cut -f2- -d'@')
1813 $CDDBTOOL query $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $TRACKINFO > "$ABCDETEMPDIR/cddbquery"
1814 ERRORCODE=$?
1815 case $ERRORCODE in
1816 0) # success
1817 ;;
1818 12|13|14)
1819 # no match found in database,
1820 # wget/fetch error, or user requested not to use CDDB
1821 # Make up an error code (503) that abcde
1822 # will recognize in do_cddbread
1823 # and compensate by making a template
1824 echo 503 > "$ABCDETEMPDIR/cddbquery"
1825 ;;
1826 *) # strange and unknown error
1827 echo ERRORCODE=$ERRORCODE
1828 echo "abcde: $CDDBTOOL returned unknown error code"
1829 ;;
1830 esac
1831 fi
1832 echo cddb-querycomplete >> "$ABCDETEMPDIR/status"
1833 fi
1834 }
1835
1836 # do_cddbread
1837 do_cddbread ()
1838 {
1839 # If it's not to be used, generate a template.
1840 # Then, display it (or them) and let the user choose/edit it
1841 if checkstatus cddb-readcomplete; then :; else
1842 vecho "Obtaining CDDB results..."
1843 # If CDDB is to be used, interpret the query results and read all
1844 # the available entries.
1845 rm -f "$ABCDETEMPDIR/cddbchoices"
1846 CDDBCHOICES=1 # Overridden by multiple matches
1847 RESPONSECODE=$(head -n 1 "$ABCDETEMPDIR/cddbquery" | cut -f1 -d' ')
1848 case "$RESPONSECODE" in
1849 200)
1850 # One exact match, retrieve it
1851 # 200 [section] [discid] [artist] / [title]
1852 if checkstatus cddb-read-1-complete; then :; else
1853 echo -n "Retrieving 1 CDDB match..." >> "$ABCDETEMPDIR/cddbchoices"
1854 $CDDBTOOL read $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $(cut -f2,3 -d' ' "$ABCDETEMPDIR/cddbquery") > "$ABCDETEMPDIR/cddbread.1"
1855 echo "done." >> "$ABCDETEMPDIR/cddbchoices"
1856 echo cddb-read-1-complete >> "$ABCDETEMPDIR/status"
1857 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1858 fi
1859 # List out disc title/author and contents
1860 echo ---- "$(cut '-d ' -f4- "$ABCDETEMPDIR/cddbquery")" ---- >> "$ABCDETEMPDIR/cddbchoices"
1861 for TRACK in $(f_seq_row 1 $TRACKS)
1862 do
1863 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.1" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1864 done
1865 echo >> "$ABCDETEMPDIR/cddbchoices"
1866 ;;
1867 202|403|409|503)
1868 # No match
1869 case "$RESPONSECODE" in
1870 202) echo "No CDDB match." >> "$ABCDETEMPDIR/cddbchoices" ;;
1871 403|409) echo "CDDB entry is corrupt, or the handshake failed." >> "$ABCDETEMPDIR/cddbchoices" ;;
1872 503) echo "CDDB unavailable." >> "$ABCDETEMPDIR/cddbchoices" ;;
1873 esac
1874 $CDDBTOOL template $(cat "$ABCDETEMPDIR/discid") > "$ABCDETEMPDIR/cddbread.0"
1875 # List out disc title/author and contents of template
1876 echo ---- Unknown Artist / Unknown Album ---- >> "$ABCDETEMPDIR/cddbchoices"
1877 UNKNOWNDISK=y
1878 for TRACK in $(f_seq_row 1 $TRACKS)
1879 do
1880 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.0" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1881 done
1882 echo >> "$ABCDETEMPDIR/cddbchoices"
1883 echo cddb-read-0-complete >> "$ABCDETEMPDIR/status"
1884 echo cddb-choice=0 >> "$ABCDETEMPDIR/status"
1885 ;;
1886 210|211)
1887 # Multiple exact, (possibly multiple) inexact matches
1888 IN=
1889 if [ "$RESPONSECODE" = "211" ]; then IN=in; fi
1890 if [ "$(wc -l < "$ABCDETEMPDIR/cddbquery" | tr -d ' ')" -eq 3 ]; then
1891 echo "One ${IN}exact match:" >> "$ABCDETEMPDIR/cddbchoices"
1892 tail -n +2 "$ABCDETEMPDIR/cddbquery" | head -n 1 >> "$ABCDETEMPDIR/cddbchoices"
1893 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1894 else
1895 echo "Multiple ${IN}exact matches:" >> "$ABCDETEMPDIR/cddbchoices"
1896 fi
1897 vecho -n "Retrieving multiple matches... "
1898 grep -v ^[.]$ "$ABCDETEMPDIR/cddbquery" | ( X=0
1899 read DISCINFO # eat top line
1900 while read DISCINFO
1901 do
1902 X=$(expr $X + 1)
1903 if checkstatus cddb-read-$X-complete; then :; else
1904 $CDDBTOOL read $CDDBURL $CDDBPROTO $CDDBUSER $CDDBHOST $(echo $DISCINFO | cut -f1,2 -d' ') > "$ABCDETEMPDIR/cddbread.$X"
1905 echo cddb-read-$X-complete >> "$ABCDETEMPDIR/status"
1906 fi
1907 # List out disc title/author and contents
1908 echo \#$X: ---- "$DISCINFO" ---- >> "$ABCDETEMPDIR/cddbchoices"
1909 for TRACK in $(f_seq_row 1 $TRACKS)
1910 do
1911 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.$X" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1912 done
1913 echo >> "$ABCDETEMPDIR/cddbchoices"
1914 done )
1915 vecho "done."
1916 CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
1917 ;;
1918 999)
1919 # Using local copy.
1920 for TRACK in $(f_seq_row 1 $TRACKS)
1921 do
1922 echo $TRACK: "$(grep ^TTITLE$(expr $TRACK - 1)= "$ABCDETEMPDIR/cddbread.1" | cut -f2- -d= | tr -d \\r\\n)" >> "$ABCDETEMPDIR/cddbchoices"
1923 done
1924 echo >> "$ABCDETEMPDIR/cddbchoices"
1925 echo cddb-read-1-complete >> "$ABCDETEMPDIR/status"
1926 echo cddb-choice=1 >> "$ABCDETEMPDIR/status"
1927 ;;
1928 esac
1929 echo "cddb-readcomplete" >> "$ABCDETEMPDIR/status"
1930 fi
1931 }
1932
1933 # do_cddbedit
1934 do_cddbedit ()
1935 {
1936 if checkstatus cddb-edit >/dev/null; then
1937 CDDBDATA="$ABCDETEMPDIR/cddbread.$(checkstatus cddb-choice)"
1938 VARIOUSARTISTS="$(checkstatus variousartists)"
1939 VARIOUSARTISTSTYLE="$(checkstatus variousartiststyle)"
1940 return 0
1941 fi
1942 if [ "$INTERACTIVE" = "y" ]; then
1943 # We should show the CDDB results both when we are not using the local CDDB repo
1944 # or when we are using it but we could not find a proper match
1945 if [ "$CDDBUSELOCAL" = "y" ] && [ "$CDDBLOCALSTATUS" = "notfound" ] || [ ! "$CDDBUSELOCAL" = "y" ]; then
1946 # Display the $ABCDETEMPDIR/cddbchoices file created above
1947 # Pick a pager so that if the tracks overflow the screen the user can still view everything
1948 if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
1949 CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
1950 CHOICE=$(checkstatus cddb-choice)
1951 if [ -n "$CHOICE" ] ; then
1952 case $CDDBCHOICES in
1953 -1) if head -1 "$ABCDETEMPDIR/cddbquery" | grep -q "^$" ; then
1954 log error "CDDB query failed!"
1955 exit 1
1956 else
1957 cat "$ABCDETEMPDIR/cddbchoices"
1958 fi
1959 ;;
1960 1) cat "$ABCDETEMPDIR/cddbchoices" ;;
1961 *)
1962 echo "Selected: #$CHOICE"
1963 do_cddbparse "$ABCDETEMPDIR/cddbread.$CHOICE"
1964 ;;
1965 esac
1966 else
1967 # The user has a choice to make, display the info in a pager if necessary
1968 if [ $(cat "$ABCDETEMPDIR/cddbchoices" | wc -l) -ge 24 ]; then
1969 page "$ABCDETEMPDIR/cddbchoices"
1970 else
1971 # It's all going to fit in one page, cat it
1972 cat "$ABCDETEMPDIR/cddbchoices" >&2
1973 fi
1974
1975 CDDBCHOICENUM=""
1976 # Setting the choice to an impossible integer to avoid errors in the numeric comparisons
1977 CDCHOICENUM=-1
1978 # I'll take CDDB read #3 for $400, Alex
1979 while [ $CDCHOICENUM -lt 0 ] || [ $CDCHOICENUM -gt $CDDBCHOICES ]; do
1980 echo -n "Which entry would you like abcde to use (0 for none)? [0-$CDDBCHOICES]: " >&2
1981 read CDDBCHOICE
1982 [ X"$CDDBCHOICE" = "X" ] && CDDBCHOICE=1
1983 if echo $CDDBCHOICE | egrep -q "[[:space:]]*[[:digit:]]+,[[:digit:]]+[[:space:]]*" ; then
1984 if [ ! X"$DIFF" = "X" ]; then
1985 PARSECHOICE1=$(echo $CDDBCHOICE | cut -d"," -f1 | xargs printf %d 2>/dev/null)
1986 PARSECHOICE2=$(echo $CDDBCHOICE | cut -d"," -f2 | xargs printf %d 2>/dev/null)
1987 if [ $PARSECHOICE1 -lt 1 ] || [ $PARSECHOICE1 -gt $CDDBCHOICES ] || \
1988 [ $PARSECHOICE2 -lt 1 ] || [ $PARSECHOICE2 -gt $CDDBCHOICES ] || \
1989 [ $PARSECHOICE1 -eq $PARSECHOICE2 ]; then
1990 echo "Invalid diff range. Please select two coma-separated numbers between 1 and $CDDBCHOICES" >&2
1991 else
1992 # We parse the 2 choices to diff, store them in temporary files and diff them.
1993 for PARSECHOICE in $(echo $CDDBCHOICE | tr , \ ); do
1994 do_cddbparse "$ABCDETEMPDIR/cddbread.$PARSECHOICE" > "$ABCDETEMPDIR/cddbread.parsechoice.$PARSECHOICE"
1995 done
1996 echo "Showing diff between choices $PARSECHOICE1 and $PARSECHOICE2..." > "$ABCDETEMPDIR/cddbread.diff"
1997 $DIFF $DIFFOPTS "$ABCDETEMPDIR/cddbread.parsechoice.$PARSECHOICE1" "$ABCDETEMPDIR/cddbread.parsechoice.$PARSECHOICE2" >> "$ABCDETEMPDIR/cddbread.diff"
1998 if [ $(cat "$ABCDETEMPDIR/cddbread.diff" | wc -l) -ge 24 ]; then
1999 page "$ABCDETEMPDIR/cddbread.diff"
2000 else
2001 cat "$ABCDETEMPDIR/cddbread.diff" >&2
2002 fi
2003 fi
2004 else
2005 echo "The diff program was not found in your path. Please choose a number between 0 and $CDDBCHOICES." >&2
2006 fi
2007 elif echo $CDDBCHOICE | egrep -q "[[:space:]]*[[:digit:]]+[[:space:]]*" ; then
2008 # Make sure we get a valid choice
2009 CDCHOICENUM=$(echo $CDDBCHOICE | xargs printf %d 2>/dev/null)
2010 if [ $CDCHOICENUM -lt 0 ] || [ $CDCHOICENUM -gt $CDDBCHOICES ]; then
2011 echo "Invalid selection. Please choose a number between 0 and $CDDBCHOICES." >&2
2012 fi
2013 fi
2014 done
2015 if [ "$CDCHOICENUM" = "0" ]; then
2016 vecho "Creating empty CDDB template..."
2017 UNKNOWNDISK=y
2018 $CDDBTOOL template $(cat "$ABCDETEMPDIR/discid") > "$ABCDETEMPDIR/cddbread.0"
2019 else
2020 echo "Selected: #$CDCHOICENUM ($(grep ^DTITLE= "$ABCDETEMPDIR/cddbread.$CDCHOICENUM" | cut -f2- -d= | tr -d \\r\\n))" >&2
2021 do_cddbparse "$ABCDETEMPDIR/cddbread.$CDCHOICENUM"
2022 fi
2023 echo "cddb-choice=$CDCHOICENUM" >> "$ABCDETEMPDIR/status"
2024 fi
2025 fi
2026 else
2027 # We need some code to show the selected option when local repository is selected and we have found a match
2028 vecho "Using cached CDDB match..." >&2
2029 # Display the $ABCDETEMPDIR/cddbchoices file created above
2030 # Pick a pager so that if the tracks overflow the screen the user can still view everything
2031 if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
2032 CDDBCHOICES=$(expr $(cat "$ABCDETEMPDIR/cddbquery" | wc -l) - 2)
2033 CHOICE=$(checkstatus cddb-choice)
2034 if [ "$USELOCALRESP" = "y" ]; then :; else
2035 if [ -n "$CHOICE" ] ; then
2036 case $CDDBCHOICES in
2037 0)
2038 UNKNOWNDISK=y
2039 echo "Selected template."
2040 ;;
2041 1) cat "$ABCDETEMPDIR/cddbchoices" ;;
2042 *)
2043 echo "Selected: #$CHOICE"
2044 do_cddbparse "$ABCDETEMPDIR/cddbread.$CHOICE"
2045 ;;
2046 esac
2047 fi
2048 fi
2049 fi
2050 fi
2051 else
2052 # We're noninteractive - pick the first choice.
2053 # But in case we run a previous instance and selected a choice, use it.
2054 if [ -r "$ABCDETEMPDIR/cddbchoices" ]; then
2055 # Show the choice if we are not using the locally stored one
2056 # or when the local search failed to find a match.
2057 PREVIOUSCHOICE=$(checkstatus cddb-choice)
2058 if [ "$CDDBUSELOCAL" = "y" ] && [ "$CDDBLOCALSTATUS" = "notfound" ] || [ ! "$CDDBUSELOCAL" = "y" ]; then
2059 #if [ "$PREVIOUSCHOICE" ]; then
2060 cat "$ABCDETEMPDIR/cddbchoices"
2061 #fi
2062 fi
2063 if [ ! -z "$PREVIOUSCHOICE" ] ; then
2064 CDCHOICENUM=$PREVIOUSCHOICE
2065 else
2066 CDCHOICENUM=1
2067 echo "cddb-choice=$CDCHOICENUM" >> "$ABCDETEMPDIR/status"
2068 fi
2069 echo "Selected: #$CDCHOICENUM ($(grep ^DTITLE= "$ABCDETEMPDIR/cddbread.$CDCHOICENUM" | cut -f2- -d= | tr -d \\r\\n))" >&2
2070 fi
2071 fi
2072
2073 # sanity check
2074 if checkstatus cddb-choice >/dev/null; then :; else
2075 echo "abcde: internal error: cddb-choice not recorded." >&2
2076 exit 1
2077 fi
2078 CDDBDATA="$ABCDETEMPDIR/cddbread.$(checkstatus cddb-choice)"
2079 echo -n "Edit selected CDDB data? [y/n] (" >&2
2080 if [ "$INTERACTIVE" = "y" ]; then
2081 if [ "$UNKNOWNDISK" = "y" ]; then
2082 echo -n "y): " >&2
2083 read EDITCDDB
2084 [ "$EDITCDDB" != "n" ] && EDITCDDB=y
2085 else
2086 echo -n "n): " >&2
2087 read EDITCDDB
2088 fi
2089 else
2090 echo "n): n" >&2
2091 EDITCDDB=n
2092 fi
2093 if [ "$EDITCDDB" = "y" ]; then
2094 CDDBDATAMD5SUM=$($MD5SUM "$CDDBDATA" | cut -d " " -f 1);
2095
2096 # Use the debian sensible-editor wrapper to pick the editor that the
2097 # user has requested via their $EDITOR environment variable
2098 if [ -x "/usr/bin/sensible-editor" ]; then
2099 /usr/bin/sensible-editor "$CDDBDATA"
2100 elif [ -n "$EDITOR" ]; then
2101 if [ -x $(which "${EDITOR%%\ *}") ]; then
2102 # That failed, try to load the preferred editor, starting
2103 # with their EDITOR variable
2104 eval $(echo "$EDITOR") \"$CDDBDATA\"
2105 fi
2106 # If that fails, check for a vi
2107 elif which vi >/dev/null 2>&1; then
2108 vi "$CDDBDATA"
2109 elif [ -x /usr/bin/vim ]; then
2110 /usr/bin/vim "$CDDBDATA"
2111 elif [ -x /usr/bin/vi ]; then
2112 /usr/bin/vi "$CDDBDATA"
2113 elif [ -x /bin/vi ]; then
2114 /bin/vi "$CDDBDATA"
2115 # nano should be on all (modern, i.e., sarge) debian systems
2116 elif which nano >/dev/null 2>&1 ; then
2117 nano "$CDDBDATA"
2118 elif [ -x /usr/bin/nano ]; then
2119 /usr/bin/nano "$CDDBDATA"
2120 # mg should be on all OpenBSD systems
2121 elif which mg >/dev/null 2>&1 ; then
2122 mg "$CDDBDATA"
2123 elif [ -x /usr/bin/mg ]; then
2124 /usr/bin/mg "$CDDBDATA"
2125 # bomb out
2126 else
2127 log warning "no editor available. Check your EDITOR environment variable."
2128 fi
2129 # delete editor backup file if it exists
2130 if [ -w "$CDDBDATA~" ]; then
2131 rm -f "$CDDBDATA~"
2132 fi
2133 fi
2134
2135 # Some heuristics first. Look at Disc Title, and if it starts with
2136 # "Various", then we'll assume Various Artists
2137 if [ "$(grep ^DTITLE= "$CDDBDATA" | cut -f2- -d= | egrep -ci '^(various|soundtrack|varios|sonora|ost)')" != "0" ]; then
2138 echo "Looks like a Multi-Artist CD" >&2
2139 VARIOUSARTISTS=y
2140 else
2141 echo -n "Is the CD multi-artist? [y/n] (n): " >&2
2142 if [ "$INTERACTIVE" = "y" ]; then
2143 read VARIOUSARTISTS
2144 else
2145 echo n >&2
2146 VARIOUSARTISTS=n
2147 fi
2148 fi
2149 if [ "$VARIOUSARTISTS" = "y" ] && [ ! "$ONETRACK" = "y" ]; then
2150 # Set a default
2151 DEFAULTSTYLE=1
2152 # Need NUMTRACKS before cddb-tool will return it:
2153 NUMTRACKS=$(egrep '^TTITLE[0-9]+=' "$CDDBDATA" | wc -l)
2154 if [ "$(grep -c "^TTITLE.*\/" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
2155 # More than 1/2 tracks contain a "/", so guess forward
2156 DEFAULTSTYLE=1
2157 elif [ "$(grep -c "^TTITLE.*\-" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
2158 # More than 1/2 contain a "-", so guess forward-dash
2159 DEFAULTSTYLE=2
2160 elif [ "$(grep -c "^TTITLE.*(.*)" "$CDDBDATA")" -gt "$(expr $NUMTRACKS / 2 )" ]; then
2161 # More than 1/2 contain something in parens, so guess trailing-paren
2162 DEFAULTSTYLE=6
2163 fi
2164
2165 echo "1) Artist / Title" >&2
2166 echo "2) Artist - Title" >&2
2167 echo "3) Title / Artist" >&2
2168 echo "4) Title - Artist" >&2
2169 echo "5) Artist: Title" >&2
2170 echo "6) Title (Artist)" >&2
2171 echo "7) This is a single-artist CD" >&2
2172 echo -n "Which style of multiple artist entries is it? [1-7] ($DEFAULTSTYLE): " >&2
2173 if [ "$INTERACTIVE" = "y" ]; then
2174 read VARIOUSARTISTSTYLE
2175 else
2176 echo $DEFAULTSTYLE >&2
2177 VARIOUSARTISTSTYLE=$DEFAULTSTYLE
2178 fi
2179 VARIOUSARTISTSTYLE=$(echo 0$VARIOUSARTISTSTYLE | xargs printf %d)
2180 # If they press Enter, then the default style (0) was chosen
2181 while [ $VARIOUSARTISTSTYLE -lt 0 ] || [ $VARIOUSARTISTSTYLE -gt 7 ]; do
2182 echo "Invalid selection. Please choose a number between 1 and 7."
2183 echo -n "Selection [1-7]: "
2184 read VARIOUSARTISTSTYLE
2185 VARIOUSARTISTSTYLE=$(echo 0$VARIOUSARTISTSTYLE | xargs printf %d)
2186 done
2187 if [ "$VARIOUSARTISTSTYLE" = "0" ]; then
2188 VARIOUSARTISTSTYLE=$DEFAULTSTYLE
2189 fi
2190 vecho "Selected: $VARIOUSARTISTSTYLE"
2191 case "$VARIOUSARTISTSTYLE" in
2192 1) # Artist / Title
2193 VARIOUSARTISTSTYLE=forward
2194 ;;
2195 2) # Artist - Title
2196 VARIOUSARTISTSTYLE=forward-dash
2197 ;;
2198 3) # Title / Artist
2199 VARIOUSARTISTSTYLE=reverse
2200 ;;
2201 4) # Title - Artist
2202 VARIOUSARTISTSTYLE=reverse-dash
2203 ;;
2204 5) # Artist: Title
2205 VARIOUSARTISTSTYLE=colon
2206 ;;
2207 6) # Title (Artist)
2208 VARIOUSARTISTSTYLE=trailing-paren
2209 ;;
2210 7) # Single Artist
2211 VARIOUSARTISTS=n
2212 ;;
2213 esac
2214 fi
2215
2216 echo "variousartists=$VARIOUSARTISTS" >> "$ABCDETEMPDIR/status"
2217 echo "variousartiststyle=$VARIOUSARTISTSTYLE" >> "$ABCDETEMPDIR/status"
2218
2219 if [ "$EDITCDDB" = "y" ] && [ "$UNINTENTIONALLY_ANGER_THE_FREEDB_PEOPLE" = "y" ]; then
2220 if [ "$CDDBDATAMD5SUM" != "" ] && [ "$CDDBDATAMD5SUM" != "$($MD5SUM "$CDDBDATA" | cut -d " " -f 1)" ]; then
2221 # This works but does not have the necessary error checking
2222 # yet. If you are familiar with the CDDB spec
2223 # (see http://www.freedb.org/src/latest/DBFORMAT)
2224 # and can create an error-free entry on your own, then put
2225 # UNINTENTIONALLY_ANGER_THE_FREEDB_PEOPLE=y in your
2226 # abcde.conf to enable it. Put CDDBSUBMIT=email@address in
2227 # your abcde.conf to change the email address submissions are
2228 # sent to.
2229
2230 # submit the modified file, if they want
2231 if [ "$NOSUBMIT" != "y" ]; then
2232 echo -n "Do you want to submit this entry to $CDDBSUBMIT? [y/n] (n): "
2233 read YESNO
2234 while [ "$YESNO" != "y" ] && [ "$YESNO" != "n" ] && [ "$YESNO" != "Y" ] && \
2235 [ "$YESNO" != "N" ] && [ "$YESNO" != "" ]
2236 do
2237 echo -n 'Invalid selection. Please answer "y" or "n": '
2238 read YESNO
2239 done
2240 if [ "$YESNO" = "y" ] || [ "$YESNO" = "Y" ]; then
2241 echo -n "Sending..."
2242 $CDDBTOOL send "$CDDBDATA" $CDDBSUBMIT
2243 echo "done."
2244 fi
2245 fi
2246 fi
2247 fi
2248 ### FIXME ###
2249 # User CDDBLOCALPOLICY to find out if we store the file or not...
2250 # Cache edited CDDB entry in the user's cddb dir
2251 if [ "$CDDBCOPYLOCAL" = "y" ]; then
2252 # Make sure the cache directory exists
2253 mkdir -p $CDDBLOCALDIR
2254 cat "$CDDBDATA" | tail -n $(expr $(cat "$CDDBDATA" | wc -l ) - 1 ) > ${CDDBLOCALDIR}/$(echo "$TRACKINFO" | cut -d' ' -f1)
2255 fi
2256
2257 echo "cddb-edit" >> "$ABCDETEMPDIR/status"
2258 }
2259
2260 # do_cdread [tracknumber]
2261 # do_cdread onetrack [firsttrack] [lasttrack]
2262 #
2263 do_cdread ()
2264 {
2265 # The commands here don't go through run_command because they're never supposed to be silenced
2266 # return codes need to be doublechecked anyway, however
2267 if [ "$1" = "onetrack" ]; then
2268 # FIXME # Add the possibility of grabbing ranges of tracks in onetrack
2269 # FIXME # Until then, we grab the whole CD in one track, no matter what
2270 # the user said
2271 # We need the first and last track for cdda2wav
2272 FIRSTTRACK=$2
2273 LASTTRACK=$(expr $3 + 0)
2274 UTRACKNUM=$FIRSTTRACK
2275 case "$CDROMREADERSYNTAX" in
2276 flac) READTRACKNUMS="$FIRSTTRACK.1-$(($LASTTRACK + 1)).0" ;;
2277 cdparanoia) READTRACKNUMS="$FIRSTTRACK-$LASTTRACK" ;;
2278 cdda2wav) READTRACKNUMS="$FIRSTTRACK+$LASTTRACK" ;;
2279 *) echo "abcde error: $CDROMREADERSYNTAX does not support ONETRACK mode"
2280 exit 1 ;;
2281 esac
2282 else
2283 UTRACKNUM=$1
2284 fi
2285 CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
2286 if [ "$USEPIPES" = "y" ]; then
2287 TEMPARG="PIPERIPPER_$CDROMREADERSYNTAX"
2288 FILEARG="$( eval echo "\$$TEMPARG" )"
2289 REDIR=""
2290 PIPE_MESSAGE="and encoding "
2291 else
2292 WAVDATA="$ABCDETEMPDIR/track$UTRACKNUM.wav"
2293 case "$CDROMREADERSYNTAX" in
2294 ## FIXME ## Find the cases for dagrab and flac, to avoid exceptions
2295 flac)
2296 FILEARG="--output-name=$WAVDATA"
2297 ;;
2298 dagrab)
2299 FILEARG="-f $WAVDATA"
2300 ;;
2301 *)
2302 FILEARG="$WAVDATA"
2303 ;;
2304 esac
2305 REDIR=">&2"
2306 fi
2307 if [ "$1" = "onetrack" ]; then
2308 echo "Grabbing ${PIPE_MESSAGE}tracks $UTRACKNUM - $LASTTRACK as one track ..." >&2
2309 else
2310 if [ -r "$CDDBDATA" ]; then
2311 do_getcddbinfo TRACKNAME
2312 echo "Grabbing ${PIPE_MESSAGE}track $UTRACKNUM: $TRACKNAME..." >&2
2313 else
2314 echo "Grabbing ${PIPE_MESSAGE}track $UTRACKNUM..." >&2
2315 fi
2316 fi
2317 case "$CDROMREADERSYNTAX" in
2318 ### FIXME ### use an exception for flac, since it uses -o
2319 ### FIXME ### Shall we just use -o $FILEARG ??
2320 flac)
2321 # Avoid problems wit math expressions by unpadding the given UTRACKNUM
2322 STRIPTRACKNUM=$(expr $UTRACKNUM + 0)
2323 nice $READNICE $FLAC -d -f --cue=${READTRACKNUMS:-$STRIPTRACKNUM.1-$(($STRIPTRACKNUM + 1)).0} "$FILEARG" "$CDROM" ;;
2324 cdparanoia)
2325 nice $READNICE $CDROMREADER -$CDPARANOIACDROMBUS $CDROM ${READTRACKNUMS:-$UTRACKNUM} "$FILEARG" $REDIR ;;
2326 cdda2wav)
2327 if [ "$OSFLAVOUR" = "OSX" ] ; then
2328 # Hei, we have to unmount the device before running anything like cdda2wav in OSX
2329 disktool -u ${CDROM#/dev/} 0
2330 # Also, in OSX the cdrom device for cdda2wav changes...
2331 CDDA2WAVCDROM="IODVDServices"
2332 elif [ "$OSFLAVOUR" = "FBSD" ] ; then
2333 CDDA2WAVCDROM="$CDROMID"
2334 else
2335 if [ "$CDROMID" = "" ]; then
2336 CDDA2WAVCDROM="$CDROM"
2337 else
2338 CDDA2WAVCDROM="$CDROMID"
2339 fi
2340 fi
2341 nice $READNICE $CDROMREADER -D $CDDA2WAVCDROM -t ${READTRACKNUMS:-$UTRACKNUM} "$FILEARG" $REDIR
2342 ;;
2343 ## FIXME ## We have an exception for dagrab, since it uses -f
2344 ## FIXME ## Shall we just use -f $FILEARG ??
2345 dagrab) nice $READNICE $CDROMREADER -d $CDROM -v $UTRACKNUM "$FILEARG" $REDIR
2346 ;;
2347 cddafs)
2348 # Find the track's mounted path
2349 REALTRACKNUM=$(expr $UTRACKNUM + 0)
2350 FILEPATH=$(mount | grep "$CDROM on" | sed 's/^[^ ]* on \(.*\) (.*/\1/')
2351 FILEPATH=$(find "$FILEPATH" | grep "/$REALTRACKNUM ");
2352 # If the file exists, copy it
2353 if [ -e "$FILEPATH" ] ; then
2354 nice $READNICE $CDROMREADER "$FILEPATH" "$FILEARG" $REDIR
2355 else
2356 false
2357 fi ;;
2358 debug) nice $READNICE $CDROMREADER -$CDPARANOIACDROMBUS $CDROM -w $UTRACKNUM-[:1] "$FILEARG" $REDIR
2359 ;;
2360 esac
2361 RETURN=$?
2362 # If we get some error or we get some missing wav
2363 # (as long as we dont use pipes)
2364 if [ "$RETURN" != "0" -o \( ! -s "$WAVDATA" -a X"$USEPIPES" != "Xy" \) ]; then
2365 # Thank goodness errors is only machine-parseable up to the
2366 # first colon, otherwise this woulda sucked
2367 if [ "$RETURN" = "0" -a ! -s "$WAVDATA" ]; then
2368 RETURN=73 # fake a return code as cdparanoia return 0 also on aborted reads
2369 fi
2370 if [ "$USEPIPES" = "y" ]; then
2371 echo "readencodetrack-$UTRACKNUM: $CDROMREADER returned code $RETURN" >> "$ABCDETEMPDIR/errors"
2372 else
2373 echo "readtrack-$UTRACKNUM: $CDROMREADER returned code $RETURN" >> "$ABCDETEMPDIR/errors"
2374 fi
2375 return $RETURN
2376 else
2377 if [ "$USEPIPES" = "y" ]; then
2378 echo readencodetrack-$UTRACKNUM >> "$ABCDETEMPDIR/status"
2379 else
2380 echo readtrack-$UTRACKNUM >> "$ABCDETEMPDIR/status"
2381 fi
2382 if [ "$1" = "onetrack" ]; then
2383 echo onetrack >> "$ABCDETEMPDIR/status"
2384 fi
2385 fi
2386 }
2387
2388 # do_cdspeed
2389 # No values accepted, only uses env variables
2390 do_cdspeed ()
2391 {
2392 if "$CDSPEED" "$CDSPEEDOPTS" "$CDSPEEDVALUE" >/dev/null ; then
2393 vecho "Setting CD speed to ${CDSPEEDVALUE}x"
2394 else
2395 echo "abcde: unable to set the device speed" >&2
2396 fi
2397 }
2398
2399 # vecho [message]
2400 #
2401 # vecho outputs a message if EXTRAVERBOSE is selected
2402 vecho ()
2403 {
2404 if [ x"$EXTRAVERBOSE" != "x" ]; then
2405 case $1 in
2406 warning) shift ; log warning "$@" ;;
2407 *) echo "$@" ;;
2408 esac
2409 fi
2410 }
2411
2412 # decho [message]
2413 #
2414 # decho outputs a debug message if DEBUG is selected
2415 decho ()
2416 {
2417 if [ x"$DEBUG" != "x" ]; then
2418 if echo $1 | grep -q "^\[" ; then
2419 DEBUGECHO=$(echo "$@" | tr -d '[]')
2420 echo "[DEBUG] $DEBUGECHO: `eval echo \\$${DEBUGECHO}`"
2421 else
2422 echo "[DEBUG] $1"
2423 fi
2424 fi
2425 }
2426
2427 # User-redefinable functions
2428 # Custom filename munging:
2429 mungefilename ()
2430 {
2431 #echo "$@" | sed s,:,\ -,g | tr \ /\* __+ | tr -d \'\"\?\[:cntrl:\]
2432 echo "$@" | sed s,:,\ -,g | tr \ / __ | tr -d \'\"\?\[:cntrl:\]
2433 }
2434
2435 # Custom genre munging:
2436 mungegenre ()
2437 {
2438 echo $CDGENRE | tr "[:upper:]" "[:lower:]"
2439 }
2440
2441 # pre_read
2442 # Empty pre_read function, to be defined in the configuration file.
2443 pre_read ()
2444 {
2445 :
2446 }
2447
2448 # post_read
2449 # Empty post_read function, to be defined in the configuration file.
2450 post_read ()
2451 {
2452 :
2453 }
2454
2455 ###############################################################################
2456 # End of functions
2457 #
2458 # Start of execution
2459 ###############################################################################
2460
2461 # Builtin defaults
2462
2463 # CDDB
2464 # Defaults to FreeDB, but a python musicbrainz can be used
2465 CDDBMETHOD=cddb
2466 CDDBURL="http://freedb.freedb.org/~cddb/cddb.cgi"
2467 CDDBSUBMIT=freedb-submit@freedb.org
2468 CDDBPROTO=5
2469 HELLOINFO="$(whoami)@$(hostname)"
2470 CDDBCOPYLOCAL="n"
2471 CDDBLOCALPOLICY="always"
2472 CDDBLOCALRECURSIVE="y"
2473 CDDBLOCALDIR="$HOME/.cddb"
2474 CDDBUSELOCAL="n"
2475
2476 # List of fields we parse and show during the CDDB parsing...
2477 SHOWCDDBFIELDS="year,genre"
2478
2479 INTERACTIVE=y
2480 #CDROMREADERSYNTAX=cdparanoia
2481 ENCODERSYNTAX=default
2482
2483 MP3ENCODERSYNTAX=default
2484 OGGENCODERSYNTAX=default
2485 FLACENCODERSYNTAX=default
2486 SPEEXENCODERSYNTAX=default
2487 MPPENCODERSYNTAX=default
2488 AACENCODERSYNTAX=default
2489 NORMALIZERSYNTAX=default
2490 CUEREADERSYNTAX=default
2491
2492 OUTPUTFORMAT='${ARTISTFILE}-${ALBUMFILE}/${TRACKNUM}.${TRACKFILE}'
2493 # Use the following VAOUTPUTFORMAT to revert to 2.0.x VA format:
2494 #VAOUTPUTFORMAT=${OUTPUTFORMAT}
2495 VAOUTPUTFORMAT='Various-${ALBUMFILE}/${TRACKNUM}.${ARTISTFILE}-${TRACKFILE}'
2496 ONETRACKOUTPUTFORMAT='${ARTISTFILE}-${ALBUMFILE}/${ALBUMFILE}'
2497 VAONETRACKOUTPUTFORMAT='Various-${ALBUMFILE}/${ALBUMFILE}'
2498 PLAYLISTFORMAT='${ARTISTFILE}-${ALBUMFILE}.${OUTPUT}.m3u'
2499 PLAYLISTDATAPREFIX=''
2500 VAPLAYLISTFORMAT='${ARTISTFILE}-${ALBUMFILE}.${OUTPUT}.m3u'
2501 VAPLAYLISTDATAPREFIX=''
2502 DOSPLAYLIST=n
2503 COMMENT=''
2504 ID3TAGV=2
2505 ENCNICE=10
2506 READNICE=10
2507 DISTMP3NICE=10
2508 VARIOUSARTISTS=n
2509 VARIOUSARTISTSTYLE=forward
2510 KEEPWAVS=n
2511 PADTRACKS=n
2512 NOGAP=n
2513 BATCHNORM=n
2514
2515 # If using scsi devices, cdda2wav needs a CDROMID, instead of a device node
2516 # i.e. CDROMID="1,0,0"
2517 CDROMID=""
2518 # If we are using the IDE bus, we need CDPARANOIACDROMBUS defined as "d"
2519 # If we are using the ide-scsi emulation layer, we need to define a "g"
2520 CDPARANOIACDROMBUS="d"
2521
2522 # program paths - defaults to checking your $PATH
2523 # mp3
2524 LAME=lame
2525 TOOLAME=toolame
2526 GOGO=gogo
2527 BLADEENC=bladeenc
2528 L3ENC=l3enc
2529 XINGMP3ENC=xingmp3enc
2530 MP3ENC=mp3enc
2531 # ogg
2532 VORBIZE=vorbize
2533 OGGENC=oggenc
2534 # flac
2535 FLAC=flac
2536 # speex
2537 SPEEXENC=speexenc
2538 # mpp (Musepack)
2539 MPPENC=mppenc
2540 # m4a
2541 AACENC=faac
2542
2543 ID3=id3
2544 ID3V2=id3v2
2545 EYED3=eyeD3
2546 CDPARANOIA=cdparanoia
2547 CDDA2WAV=cdda2wav
2548 DAGRAB=dagrab
2549 CDDAFS=cp
2550 CDDISCID=cd-discid
2551 CDDBTOOL=cddb-tool
2552 MUSICBRAINZ=musicbrainz-get-tracks
2553 EJECT=eject
2554 MD5SUM=md5sum
2555 DISTMP3=distmp3
2556 VORBISCOMMENT=vorbiscomment
2557 METAFLAC=metaflac
2558 NORMALIZE=normalize-audio
2559 CDSPEED=eject
2560 VORBISGAIN=vorbisgain
2561 MP3GAIN=mp3gain
2562 MPPGAIN=replaygain
2563 MKCUE=mkcue
2564 MKTOC=cdrdao
2565 DIFF=diff
2566 CUE2DISCID=cue2discid
2567
2568 # Options for programs called from abcde
2569 # mp3
2570 LAMEOPTS=
2571 TOOLAMEOPTS=
2572 GOGOOPTS=
2573 BLADEENCOPTS=
2574 L3ENCOPTS=
2575 XINGMP3ENCOPTS=
2576 MP3ENCOPTS=
2577 # ogg
2578 VORBIZEOPTS=
2579 OGGENCOPTS=
2580 # flac
2581 FLACOPTS=
2582 # speex
2583 SPEEXENCOPTS=
2584 # mpc
2585 MPPENCOPTS=
2586 # m4a
2587 AACENCOPTS=
2588
2589 ID3OPTS=
2590 ID3V2OPTS=
2591 CDPARANOIAOPTS=
2592 CDDA2WAVOPTS=
2593 DAGRABOPTS=
2594 CDDAFSOPTS="-f"
2595 CDDBTOOLOPTS=
2596 EJECTOPTS=
2597 DISTMP3OPTS=
2598 NORMALIZEOPTS=
2599 CDSPEEDOPTS="-x"
2600 CDSPEEDVALUE=
2601 MKCUEOPTS=
2602 MKTOCOPTS=""
2603 VORBISCOMMENTOPTS="-R"
2604 METAFLACOPTS="--no-utf8-convert"
2605 DIFFOPTS=
2606
2607 # Default to one process if -j isn't specified
2608 MAXPROCS=1
2609
2610 # List of actions to perform - by default, run to completion
2611 ACTIONS=cddb,read,encode,tag,move,clean
2612
2613 # This option is basicaly for Debian package dependencies:
2614 # List of prefered outputs - by default, run with whatever we have in the path
2615 DEFAULT_OUTPUT_BINARIES=vorbis:oggenc,flac:flac,mp3:lame,mp3:bladeenc,spx:speex
2616
2617 # List of prefered cdromreaders - by default, run whichever we have in the path
2618 DEFAULT_CDROMREADERS="cdparanoia cdda2wav"
2619
2620 # Asume fetch if under FreeBSD. curl is used for Mac OS X. wget is used for Linux/OpenBSD/NetBSD.
2621 # Let's use these checkings to determine the OS flavour, which will be used later
2622 if [ X$(uname) = "XFreeBSD" ] ; then
2623 HTTPGET=fetch
2624 MD5SUM=md5
2625 NEEDCDROMID=y
2626 OSFLAVOUR=FBSD
2627 elif [ X$(uname) = "XDarwin" ] ; then
2628 HTTPGET=curl
2629 OSFLAVOUR=OSX
2630 # We should have disktool in OSX, but let's be sure...
2631 NEEDDISKTOOL=y
2632 CDROMREADERSYNTAX=cddafs
2633 elif [ X$(uname) = "XOpenBSD" ] ; then
2634 HTTPGET=wget
2635 MD5SUM=md5
2636 elif [ X$(uname) = "XNetBSD" ] ; then
2637 HTTPGET=ftp
2638 MD5SUM=md5
2639 else
2640 HTTPGET=wget
2641 fi
2642
2643 # If CDDBAVAIL is set to n, no CDDB read is done
2644 # If USEID3 is set to n, no ID3 tagging is done
2645 CDDBAVAIL=y
2646 USEID3=y
2647 USEID3V2=y
2648
2649 if [ -z "$OUTPUTDIR" ]; then
2650 OUTPUTDIR=$(pwd)
2651 fi
2652
2653 if [ -z "$WAVOUTPUTDIR" ]; then
2654 WAVOUTPUTDIR="$OUTPUTDIR"
2655 fi
2656
2657 # Load system defaults
2658 if [ -r /etc/abcde.conf ]; then
2659 . /etc/abcde.conf
2660 fi
2661 # Load user preference defaults
2662 if [ -r $HOME/.abcde.conf ]; then
2663 . $HOME/.abcde.conf
2664 fi
2665
2666 # By this time, we need some HTTPGETOPTS already defined.
2667 # If the user has defined a non-default HTTPGET method, we should not be empty.
2668
2669 if [ "$HTTPGETOPTS" = "" ] ; then
2670 case $HTTPGET in
2671 wget) HTTPGETOPTS="-q -O -";;
2672 curl) HTTPGETOPTS="-f -s";;
2673 fetch)HTTPGETOPTS="-q -o -";;
2674 ftp) HTTPGETOPTS="-q -o -";;
2675 *) log warning "HTTPGET in non-standard and HTTPGETOPTS are not defined." ;;
2676 esac
2677 fi
2678
2679 # If the CDROM has not been set yet, find a suitable one.
2680 # If this is a devfs system, default to /dev/cdroms/cdrom0
2681 # instead of /dev/cdrom
2682 if [ "$CDROM" = "" ] ; then
2683 if [ -e /dev/cdroms/cdrom0 ]; then
2684 CDROM=/dev/cdroms/cdrom0
2685 elif [ -e /dev/cdrom ]; then
2686 CDROM=/dev/cdrom
2687 elif [ -e /dev/cd0c ]; then
2688 CDROM=/dev/cd0c
2689 elif [ -e /dev/acd0c ]; then
2690 CDROM=/dev/acd0c
2691 elif [ -e /dev/disk1 ]; then
2692 CDROM=/dev/disk1
2693 fi
2694 fi
2695
2696 # Parse command line options
2697 #while getopts 1a:bc:C:d:Dehj:klLmMnNo:pPr:Rs:S:t:T:vVxw:W: opt ; do
2698 while getopts 1a:bBc:C:d:Defghj:klLmMnNo:pPr:s:S:t:T:uvVxw:W:z opt ; do
2699 case "$opt" in
2700 1) ONETRACK=y ;;
2701 a) ACTIONS="$OPTARG" ;;
2702 A) EXPACTIONS="$OPTARG" ;;
2703 b) BATCHNORM=y ;;
2704 B) NOBATCHREPLAYGAIN=y ;;
2705 c) if [ -e "$OPTARG" ] ; then . "$OPTARG" ; else log error "config file \"$OPTARG\" cannot be found." ; exit 1 ; fi ;;
2706 C) DISCID="$( echo ${OPTARG#abcde.} | tr -d /)" ;;
2707 d) CDROM="$OPTARG" ;;
2708 D) set -x ;;
2709 e) ERASEENCODEDSTATUS=y ;;
2710 h) usage; exit ;;
2711 e) ERASEENCODEDSTATUS=y ;;
2712 E) ENCODING="$OPTARG" ;;
2713 f) FORCE=y ;;
2714 g) NOGAP=y ;;
2715 i) INLINETAG=y ;;
2716 j) MAXPROCS="$OPTARG" ;;
2717 k) KEEPWAVS=y ;;
2718 l) LOWDISK=y ;;
2719 L) CDDBUSELOCAL=y ;;
2720 n) CDDBAVAIL=n ;;
2721 N) INTERACTIVE=n ;;
2722 m) DOSPLAYLIST=y ;;
2723 M) MAKECUEFILE=y ;;
2724 o) OUTPUTTYPE="$OPTARG" ;;
2725 p) PADTRACKS=y ;;
2726 P) USEPIPES=y ;;
2727 r) REMOTEHOSTS="$OPTARG" ;;
2728 R) DOREPLAYGAIN=y ;;
2729 s) SHOWCDDBFIELDS="$OPTARG" ;;
2730 S) CDSPEEDVALUE="$OPTARG" ;;
2731 t) STARTTRACKNUMBER="$OPTARG" ;;
2732 T) STARTTRACKNUMBER="$OPTARG" ; STARTTRACKNUMBERTAG="y" ;;
2733 u) CDDBPROTO=6 ;;
2734 v)
2735 echo "This is abcde v$VERSION."
2736 echo "Usage: abcde [options] [tracks]"
2737 echo "abcde -h for extra help"
2738 exit
2739 ;;
2740 V) EXTRAVERBOSE="y" ;;
2741 x) EJECTCD="y" ;;
2742 w) COMMENT="$OPTARG" ;;
2743 W) if echo $OPTARG | grep -q "[[:digit:]]" ; then
2744 STARTTRACKNUMBER="${OPTARG}01" ; STARTTRACKNUMBERTAG="y" ; COMMENT="CD${OPTARG}"
2745 else
2746 log error "argument of -W must be integer"
2747 exit 1
2748 fi
2749 ;;
2750 z) DEBUG=y ; CDROMREADERSYNTAX=debug ; EJECTCD="n" ;;
2751 ?) usage; exit ;;
2752 esac
2753 done
2754
2755 shift $(($OPTIND - 1))
2756
2757 # If the user specified a flac file, then switch to special flac mode
2758 if echo $CDROM | grep -i -q '.flac$'; then
2759 vecho warning "abcde: switching to flac CDROMREADERSYNTAX..."
2760 CDROMREADERSYNTAX=flac
2761 # Added a need on CUE2DISCID until we manage to convert the python script to bash.
2762 NEEDCUE2DISCID=y
2763 NEEDMETAFLAC=y
2764 EJECTCD=n
2765 fi
2766
2767 # If the user provided a DISCID, disable eject
2768 if [ -n "$DISCID" ] || [ "$CDROMREADERSYNTAX" = "flac" ]; then EJECTCD=n ; fi
2769
2770 # Check the available cd rippers in the system, from the ones we know.
2771 if [ "$CDROMREADERSYNTAX" = "" ]; then
2772 for DEFAULT_CDROMREADER in $DEFAULT_CDROMREADERS; do
2773 if [ -x $( which $DEFAULT_CDROMREADER ) ]; then
2774 CDROMREADERSYNTAX=$DEFAULT_CDROMREADER
2775 break
2776 fi
2777 done
2778 if [ "$CDROMREADERSYNTAX" = "" ]; then
2779 log error "no cdreader found in your PATH"
2780 log error "hints: are all dependencies installed? has the \$PATH been modified?"
2781 exit 1
2782 fi
2783 fi
2784
2785 # Decide if we can continue.
2786 if [ "$ONETRACK" = "y" ]; then
2787 # FIXME # remove check as soon as we find out about the other readers
2788 case "$CDROMREADERSYNTAX" in
2789 flac) ;;
2790 cdparanoia) ;;
2791 cdda2wav) ;;
2792 *) log error "$CDROMREADERSYNTAX does not support ONETRACK mode"
2793 exit 1 ;;
2794 esac
2795 if [ "$BATCHNORM" = "y" ]; then
2796 log warning "BATCHNORM mode is not compatible with ONETRACK mode. Disabling..."
2797 BATCHNORM=n
2798 fi
2799 if [ "$NOGAP" = "y" ]; then
2800 log warning "NOGAP mode is not compatible with ONETRACK mode. Disabling..."
2801 NOGAP=n
2802 fi
2803 # It does not matter how many tracks we want. In ONETRACK mode we grab them all
2804 # FIXME # allow ranges of tracks to be selected for onetrack ripping
2805 if [ $# -gt 0 ]; then
2806 log warning "ONETRACK mode selected, grabbing all tracks..."
2807 fi
2808 else
2809 while [ $# -gt 0 ]; do
2810 # Range parsing code courtesy of Vincent Ho
2811 RSTART=$(echo $1 | cut -f1 -d-)
2812 REND=$(echo $1 | cut -f2 -d-)
2813 if [ "$RSTART" = "$REND" ]; then
2814 NEWTRACKS="$RSTART"
2815 else
2816 NEWTRACKS=$(f_seq_line $RSTART $REND)
2817 fi
2818 TRACKQUEUE=$(echo "$TRACKQUEUE" "$NEWTRACKS")
2819 shift
2820 done
2821 fi
2822
2823 # List of valid actions: cddb,read,normalize,encode,tag,move,playlist,clean
2824 # List of experimental actions: retag,transcode
2825
2826 # Determine what actions are to be done from $ACTIONS and set the
2827 # following environment variables for them:
2828 DOCDDB=n
2829 DOREAD=n
2830 DONORMALIZE=n
2831 DOPREPROCESS=n
2832 DOENCODE=n
2833 DOPOSTPROCESS=n
2834 DOTAG=n
2835 DOMOVE=n
2836 DOREPLAYGAIN=n
2837 DOPLAYLIST=n
2838 DOCLEAN=n
2839
2840 for ACTION in $(echo $ACTIONS | tr , \ )
2841 do
2842 case $ACTION in
2843 cddb) DOCDDB=y;;
2844 read) DOREAD=y;;
2845 normalize) DONORMALIZE=y; DOREAD=y;;
2846 # preprocess) DOPREPROCESS=y; DOREAD=y;;
2847 encode) DOENCODE=y; DOREAD=y;;
2848 # postprocess) DOPREPROCESS=y; DOENCODE=y; DOREAD=y;;
2849 tag) DOTAG=y; DOREAD=y; DOENCODE=y; DOCDDB=y;;
2850 move) DOMOVE=y; DOTAG=y; DOREAD=y; DOENCODE=y; DOCDDB=y;;
2851 replaygain) DOCDDB=y; DOREAD=y; DOENCODE=y; DOTAG=y; DOMOVE=y; DOREPLAYGAIN=y;;
2852 playlist) DOCDDB=y; DOPLAYLIST=y;;
2853 clean) DOCLEAN=y;;
2854 esac
2855 done
2856
2857 if [ "$DONORMALIZE" = "y" ] && [ "$DOREPLAYGAIN" = "y" ]; then
2858 # FIXME # should we abort on error or just inform the user?
2859 log warning "selected both normalize and replaygain actions"
2860 fi
2861
2862 for SHOWCDDBFIELD in $(echo $SHOWCDDBFIELDS | tr , \ ); do
2863 case $SHOWCDDBFIELD in
2864 y*|Y*) SHOWCDDBYEAR="y";;
2865 g*|G*) SHOWCDDBGENRE="y";;
2866 *) ;;
2867 esac
2868 done
2869
2870 # Sanity checks:
2871
2872 # At this point a CDROM has to be defined, so we check it exists.
2873 if [ X"$CDROM" != "X" ] ; then
2874 if [ "$CDROMREADERSYNTAX" = "cdda2wav" ] && [ "$NEEDCDROMID" = "y" ] ; then
2875 if [ "$OSFLAVOUR" = "FBSD" ]; then
2876 if ! echo "$CDROMID" | grep "^[0-9],[0-9],[0-9]$" >/dev/null 2>&1 ; then
2877 log error "CDROMID not in the right format for $CDROMREADERSYNTAX"
2878 log error "Use \"cdrecord -scanbus\" to obtain a adecuate ID an set CDROMID accordingly"
2879 exit 1
2880 fi
2881 fi
2882 elif [ ! -e "$CDROM" -a X"$DOREAD" = "Xy" ]; then
2883 log error "CDROM device cannot be found."
2884 exit 1
2885 fi
2886 # avoid processing if we are not going to hit the CDROM.
2887 elif [ X"$DOREAD" = "Xy" ]; then
2888 log error "CDROM has not been defined or cannot be found"
2889 exit 1
2890 fi
2891
2892 # USEPIPES pre-tests, before we get into more serious stuff
2893 # Not compatible with:
2894 # - multiple outputs
2895 # - normalize
2896 # - lowdisk algorithm
2897 # - anything else?
2898 if [ X"$USEPIPES" = "Xy" ]; then
2899 if [ $(echo "$OUTPUTTYPE" | tr , \ | wc -w ) -gt 1 ]; then
2900 log error "Unix pipes not compatible with multiple outputs"
2901 exit 1
2902 fi
2903 if [ X"$DONORMALIZE" = "Xy" ]; then
2904 log error "Unix pipes not compatible with normalizer"
2905 # FIXME # Do we need to exit or shall we just disable the mode?
2906 exit 1
2907 fi
2908 if [ X"$BATCHNORM" = "Xy" ]; then
2909 log error "Unix pipes not compatible with BATCHNORM encoding"
2910 exit 1
2911 fi
2912 if [ X"$NOGAP" = "Xy" ]; then
2913 log error "Unix pipes not compatible with NOGAP encoding"
2914 exit 1
2915 fi
2916 if [ X"$DOENCODE" = "Xn" ]; then
2917 vecho warning "Disabling Unix pipes since we are not encoding!"
2918 USEPIPES=n
2919 fi
2920 if [ X"$LOWDISK" = "Xy" ]; then
2921 log error "Unix pipes not compatible with lowdisk algorithm"
2922 exit 1
2923 fi
2924 fi
2925
2926 # LOWDISK pre-tests, before we get into more problematic stuff
2927 # Not compatible with anything that needs all the files in the hard disc:
2928 # - BATCHNORM
2929 # - NOGAP lame mode
2930 if [ X"$LOWDISK" = "Xy" ]; then
2931 if [ X"$BATCHNORM" = "Xy" ]; then
2932 log error "Unix pipes not compatible with BATCHNORM encoding"
2933 exit 1
2934 fi
2935 if [ X"$NOGAP" = "Xy" ]; then
2936 log error "Unix pipes not compatible with NOGAP encoding"
2937 exit 1
2938 fi
2939 fi
2940
2941 # BATCHNORM pre-tests, before we get into serious problems
2942 # Not compatible with
2943 if [ "$BATCHNORM" = "y" ] && [ "$DONORMALIZE" = "n" ]; then
2944 vecho warning "Disabling BATCHNORM since we are not normalizing!"
2945 BATCHNORM=n
2946 fi
2947
2948 # Check the encoding format from the ones available in the system, if nothing has been configured in the system.
2949 if [ X"$OUTPUTTYPE" = "X" ]; then
2950 for DEFAULT_OUTPUT in $( echo "$DEFAULT_OUTPUT_BINARIES" | tr , \ ); do
2951 DEFAULT_OUTPUT_FORMAT="$(echo $DEFAULT_OUTPUT | cut -d ":" -f 1)"
2952 DEFAULT_OUTPUT_BINARY="$(echo $DEFAULT_OUTPUT | cut -d ":" -f 2)"
2953 if [ -x $(which $DEFAULT_OUTPUT_BINARY) ] ; then
2954 OUTPUTTYPE=$DEFAULT_OUTPUT_FORMAT
2955 vecho "No default output type defined. Autoselecting $OUTPUTTYPE..." >&2
2956 break
2957 fi
2958 done
2959 if [ X"$OUTPUTTYPE" = "X" ]; then
2960 log error "no encoder found in the PATH"
2961 log error "hints: are all dependencies installed? has the \$PATH been modified?"
2962 exit 1
2963 fi
2964 fi
2965
2966 # Decide which CDROM reader we're gonna use
2967 case "$CDROMREADERSYNTAX" in
2968 cdparanoia|debug)
2969 CDROMREADER="$CDPARANOIA"
2970 CDROMREADEROPTS="$CDPARANOIAOPTS"
2971 ;;
2972 cdda2wav)
2973 CDROMREADER="$CDDA2WAV"
2974 CDROMREADEROPTS="$CDDA2WAVOPTS"
2975 ;;
2976 dagrab)
2977 CDROMREADER="$DAGRAB"
2978 CDROMREADEROPTS="$DAGRABOPTS"
2979 ;;
2980 cddafs)
2981 CDROMREADER="$CDDAFS"
2982 CDROMREADEROPTS="$CDDAFSOPTS"
2983 ;;
2984 flac)
2985 CDROMREADER="$FLAC"
2986 CDROMREADEROPTS="$FLACOPTS"
2987 ;;
2988 esac
2989
2990 # There's only one normalize...
2991 case "$NORMALIZERSYNTAX" in
2992 default|normalize)
2993 NORMALIZER="$NORMALIZE"
2994 NORMALIZEROPTS="$NORMALIZEOPTS"
2995 ;;
2996 esac
2997
2998 # Allow -o OUTPUT(1):OPTIONS(1),...,OUTPUT(N):OPTIONS(N) mode of operation
2999 if echo "$OUTPUTTYPE" | grep ":" > /dev/null 2>&1 ; then
3000 for OUTPUT in "$(echo "$OUTPUTTYPE" | tr , \ )"; do
3001 case "$OUTPUT" in
3002 vorbis:*|ogg:*) OGGENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3003 mp3:*) MP3ENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3004 flac:*) FLACENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3005 spx:*) SPEEXENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3006 mpc:*) MPPENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3007 m4a:*) AACENCODEROPTSCLI="$( echo $OUTPUT | cut -d: -f2- )" ;;
3008 esac
3009 done
3010 for OUTPUT in "$(echo "$OUTPUTTYPE" | tr , \ )"; do
3011 TEMPOUTPUT=$( echo "$OUTPUT" | cut -d: -f1 )
3012 TEMPOUTPUTTYPE="${TEMPOUTPUTTYPE:+$TEMPOUTPUTTYPE,}$TEMPOUTPUT"
3013 done
3014 OUTPUTTYPE="$TEMPOUTPUTTYPE"
3015 fi
3016
3017 # If nothing has been specified, use oggenc for oggs and lame for mp3s and flac
3018 # for flacs and speexenc for speex and mppenc for mpps and faac for m4as
3019
3020 # Getting ready for multiple output changes
3021 for OUTPUT in $(echo $OUTPUTTYPE | tr , \ )
3022 do
3023 case $OUTPUT in
3024 vorbis|ogg)
3025 [ "$OGGENCODERSYNTAX" = "default" ] && OGGENCODERSYNTAX=oggenc
3026 [ "$DOTAG" = "y" ] && NEEDCOMMENTER=y
3027 [ "$DOREPLAYGAIN" = "y" ] && NEEDVORBISGAIN=y
3028 OGGOUTPUTCONTAINER=ogg
3029 ;;
3030 mp3)
3031 [ "$MP3ENCODERSYNTAX" = "default" ] && MP3ENCODERSYNTAX=lame
3032 [ "$DOTAG" = "y" ] && NEEDTAGGER=y
3033 [ "$DOREPLAYGAIN" = "y" ] && NEEDMP3GAIN=y
3034 ;;
3035 flac)
3036 [ "$FLACENCODERSYNTAX" = "default" ] && FLACENCODERSYNTAX=flac
3037 [ "$DOTAG" = "y" ] && NEEDMETAFLAC=y
3038 [ "$DOREPLAYGAIN" = "y" ] && NEEDMETAFLAC=y
3039 ;;
3040 spx)
3041 [ "$SPEEXENCODERSYNTAX" = "default" ] && SPEEXENCODERSYNTAX=speexenc
3042 # [ "$DOREPLAYGAIN" = "y" ] &&
3043 ;;
3044 mpc)
3045 [ "$MPPENCODERSYNTAX" = "default" ] && MPPENCODERSYNTAX=mppenc
3046 [ "$DOREPLAYGAIN" = "y" ] && NEEDMPPGAIN=y
3047 ;;
3048 m4a)
3049 [ "$AACENCODERSYNTAX" = "default" ] && AACENCODERSYNTAX=faac
3050 ;;
3051 wav)
3052 if [ "$KEEPWAVS" = "y" ]; then
3053 vecho "Unsetting the KEEPWAVS option, since the resulting wav files were requested..."
3054 fi
3055 KEEPWAVS=move
3056 ;;
3057 *) log error "Invalid OUTPUTTYPE defined"
3058 exit 1
3059 ;;
3060 esac
3061 done
3062
3063 # decide which encoder
3064 case "$MP3ENCODERSYNTAX" in
3065 lame)
3066 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$LAMEOPTS}"
3067 MP3ENCODER="$LAME"
3068 ;;
3069 toolame)
3070 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$TOOLAMEOPTS}"
3071 MP3ENCODER="$TOOLAME"
3072 ;;
3073 gogo)
3074 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$GOGOOPTS}"
3075 MP3ENCODER="$GOGO"
3076 ;;
3077 bladeenc)
3078 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$BLADEENCOPTS}"
3079 MP3ENCODER="$BLADEENC"
3080 ;;
3081 l3enc)
3082 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$L3ENCOPTS}"
3083 MP3ENCODER="$L3ENC"
3084 ;;
3085 xingmp3enc)
3086 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$XINGMP3ENCOPTS}"
3087 MP3ENCODER="$XINGMP3ENC"
3088 ;;
3089 mp3enc)
3090 MP3ENCODEROPTS="${MP3ENCODEROPTSCLI:-$MP3ENCOPTS}"
3091 MP3ENCODER="$MP3ENC"
3092 ;;
3093 esac
3094 case "$OGGENCODERSYNTAX" in
3095 vorbize)
3096 OGGENCODEROPTS="${OGGENCODEROPTSCLI:-$VORBIZEOPTS}"
3097 OGGENCODER="$VORBIZE"
3098 ;;
3099 oggenc)
3100 OGGENCODEROPTS="${OGGENCODEROPTSCLI:-$OGGENCOPTS}"
3101 OGGENCODER="$OGGENC"
3102 ;;
3103 esac
3104 case "$FLACENCODERSYNTAX" in
3105 flac)
3106 FLACENCODEROPTS="${FLACENCODEROPTSCLI:-$FLACOPTS}"
3107 FLACENCODER="$FLAC"
3108 # FLAC streams can be encapsulated on a Ogg transport layer
3109 if echo "$FLACENCODEROPTS" | egrep -q -- "(^| )--ogg($| )" ;then
3110 log error "FLAC on an Ogg container is not yet supported"
3111 log error "due to problem with adding comments to such files"
3112 exit 1
3113 FLACOUTPUTCONTAINER=ogg
3114 else
3115 FLACOUTPUTCONTAINER=flac
3116 fi
3117 ;;
3118 esac
3119 case "$SPEEXENCODERSYNTAX" in
3120 speexenc)
3121 SPEEXENCODEROPTS="${SPEEXENCODEROPTSCLI:-$SPEEXENCOPTS}"
3122 SPEEXENCODER="$SPEEXENC"
3123 ;;
3124 esac
3125 case "$MPPENCODERSYNTAX" in
3126 mppenc)
3127 MPPENCODEROPTS="${MPPENCODEROPTSCLI:-$MPPENCOPTS}"
3128 MPPENCODER="$MPPENC"
3129 ;;
3130 esac
3131 case "$AACENCODERSYNTAX" in
3132 faac)
3133 AACENCODEROPTS="${AACENCODEROPTSCLI:-$AACENCOPTS}"
3134 AACENCODER="$AACENC"
3135 ;;
3136 esac
3137 # and which tagger
3138
3139 if [ "$ID3TAGV" = "1" ]; then
3140 TAGGER="$ID3"
3141 TAGGEROPTS="$ID3OPTS"
3142 else
3143 TAGGER="$ID3V2"
3144 TAGGEROPTS="$ID3V2OPTS"
3145 fi
3146
3147 # Specific for NOGAP is the use of lame. Another encoder fails...
3148 if [ "$NOGAP" = "y" ] && [ ! "$MP3ENCODER" = "lame" ]; then
3149 log warning "the NOGAP option is specific of lame. Deactivating..."
3150 NOGAP=n
3151 fi
3152
3153 # Options for mkcue
3154 case "$CUEREADERSYNTAX" in
3155 default|mkcue)
3156 CUEREADEROPTS="${CDROM}"
3157 CUEREADER="$MKCUE"
3158 ;;
3159 esac
3160
3161 # which information retrieval tool are we using?
3162 case "$CDDBTOOL" in
3163 cddb) ;;
3164 musicbrainz) ;;
3165 esac
3166
3167 # Check if both OGGEOUTPUTCONTAINER and FLACOUTPUTCONTAINER are the same, and differentiante them
3168 if [ X"$OGGOUTPUTCONTAINER" = "Xogg" ] && [ X"$FLACOUTPUTCONTAINER" = "Xogg" ]; then
3169 log error "FLAC on an Ogg container is not yet supported"
3170 log error "due to problem with adding comments to such files"
3171 exit 1
3172 OGGOUTPUTCONTAINER=ogg.ogg
3173 FLACOUTPUTCONTAINER=flac.ogg
3174 vecho warning "modified file endings due to conflicting transport layers in Ogg/Vorbis and Ogg/FLAC"
3175 fi
3176
3177 # Clean up nice options (either use '-n NICELEVEL or -NICELEVEL')
3178
3179 if [ "$ENCNICE" ]; then
3180 ENCNICE="-n $ENCNICE"
3181 fi
3182 if [ "$READNICE" ]; then
3183 READNICE="-n $READNICE"
3184 fi
3185 if [ "$DISTMP3NICE" ]; then
3186 DISTMP3NICE="-n $DISTMP3NICE"
3187 fi
3188
3189 # Don't check for stuff if it's not needed
3190 if [ "$REMOTEHOSTS" ]; then
3191 NEEDDISTMP3=y
3192 fi
3193 if [ "$DONORMALIZE" = "y" ]; then
3194 NEEDNORMALIZER=y
3195 fi
3196 if [ "$EJECTCD" = "y" ]; then
3197 NEEDEJECT=y
3198 fi
3199 if [ ! "$CDDBAVAIL" = "n" ] && [ "$DOCDDB" = "y" ]; then
3200 if [ "$CDDBMETHOD" = "cddb" ]; then
3201 NEEDHTTPGET=y
3202 elif [ "$CDDBMETHOD" = "musicbrainz" ]; then
3203 :
3204 fi
3205 fi
3206 if [ "$MAKECUEFILE" = "y" ]; then
3207 NEEDCUEREADER=y
3208 fi
3209
3210 if [ X"$CDSPEEDVALUE" != "X" ] && [ "$DOREAD" = "y"]; then
3211 case "$CDROMREADERSYNTAX" in
3212 cdparanoia|debug) CDROMREADEROPTS="$CDPARANOIAOPTS -S $CDSPEEDVALUE" ;;
3213 ### FIXME ### translate "cue2discid" from python to bash
3214 flac) NEEDMETAFLAC=y ; NEEDCUE2DISCID=y ; CDSPEEDVALUE="" ;;
3215 *) NEEDCDSPEED=y ;;
3216 esac
3217 fi
3218
3219 ###USEPIPESSUPPORT###
3220
3221 # Rippers with USEPIPE support
3222 # FIXME # Include here all the rippers we can figure out support pipes
3223 PIPERIPPER_cdparanoia="-"
3224 PIPERIPPER_debug="-"
3225 PIPERIPPER_flac="-c "
3226
3227 # Encoders with USEPIPE support
3228 # FIXME # Include here all the encoders we can figure out support pipes
3229 PIPE_lame="-"
3230 PIPE_bladeenc="-"
3231 PIPE_oggenc="-"
3232 PIPE_flac="-"
3233
3234 # Figure out if we can use pipes with the ripper/encoder combination
3235 # exit otherwise
3236 if [ "$USEPIPES" = "y" ]; then
3237 PIPERIPPERSVARCHECK="PIPERIPPER_${CDROMREADERSYNTAX}"
3238 case "$OUTPUT" in
3239 mp3)
3240 PIPEENCODERSVARCHECK="PIPE_$MP3ENCODERSYNTAX" ;;
3241 vorbis|ogg)
3242 PIPEENCODERSVARCHECK="PIPE_$OGGENCODERSYNTAX" ;;
3243 flac)
3244 PIPEENCODERSVARCHECK="PIPE_$FLACENCODERSYNTAX" ;;
3245 spx)
3246 PIPEENCODERSVARCHECK="PIPE_$SPEEXENCODER" ;;
3247 mpc)
3248 PIPEENCODERSVARCHECK="PIPE_$MPPENCODER" ;;
3249 esac
3250 decho "PIPERIPPERSVARCHECK: $( eval echo "\$$PIPERIPPERSVARCHECK" )"
3251 if [ "$( eval echo "\$$PIPERIPPERSVARCHECK" )" = "$" ] || \
3252 [ "$( eval echo "\$$PIPERIPPERSVARCHECK" )" = "" ] ; then
3253 log error "no support for pipes with given ripper"
3254 log error "read the USEPIPES file from the source tarball to get help."
3255 log error "On a Debian system, it is under /usr/share/doc/abcde/USEPIPES.gz"
3256 exit 1;
3257 fi
3258 decho "PIPEENCODERSVARCHECK: $( eval echo "\$$PIPEENCODERSVARCHECK" )"
3259 if [ "$( eval echo "\$$PIPEENCODERSVARCHECK" )" = "$" ] || \
3260 [ "$( eval echo "\$$PIPEENCODERSVARCHECK" )" = "" ] ; then
3261 log error "no support for pipes with given encoder"
3262 log error "read the USEPIPES file from the source tarball to help"
3263 log error "on a Debian system, read /usr/share/doc/abcde/USEPIPES.gz"
3264 exit 1;
3265 fi
3266 fi
3267
3268 # Make sure a buncha things exist
3269 for X in $CDROMREADER $CDDISCID ${NEEDTAGGER+$TAGGER} $MP3ENCODER \
3270 $OGGENCODER $FLACENCODER $SPEEXENCODER $MPPENCODER \
3271 ${NEEDHTTPGET+$HTTPGET} ${NEEDDISTMP3+$DISTMP3} \
3272 ${NEEDCOMMENTER+$VORBISCOMMENT} ${NEEDMETAFLAC+$METAFLAC} \
3273 ${NEEDNORMALIZER+$NORMALIZER} ${NEEDEJECT+$EJECT} \
3274 ${NEEDDISKTOOL+disktool} ${NEEDCDSPEED+$CDSPEED} \
3275 ${NEEDVORBISGAIN+$VORBISGAIN} ${NEEDMP3GAIN+$MP3GAIN} \
3276 ${NEEDMPPGAIN+$MPPGAIN} ${NEEDCUEREADER+$CUEREADER} \
3277 ${NEEDCUE2DISCID+$CUE2DISCID}
3278 do
3279 checkexec "$X"
3280 done
3281
3282 # And last but not least, check if we can diff between files
3283 if [ -x $(which $DIFF) ]; then :; else
3284 vecho warning "Disabling diff since we cannot find it in the \$PATH..."
3285 DIFF=""
3286 fi
3287
3288 ## Now that we have metaflac, check if we need cue2discid
3289 #case $CDROMREADERSYNTAX in
3290 # flac)
3291 # TRACKINFO=$($METAFLAC --show-tag=CDDB $CDROM | cut -d"=" -f2 | egrep "[a-f0-9]{8}")
3292 # if [ "$TRACKINFO" = "" ]; then
3293 # checkexec ${NEEDCUE2DISCID+$CUE2DISCID}
3294 # fi
3295 # ;;
3296 #esac
3297
3298 CDROMREADER="$CDROMREADER $CDROMREADEROPTS"
3299 CDDBTOOL="$CDDBTOOL $CDDBTOOLOPTS"
3300 HTTPGET="$HTTPGET $HTTPGETOPTS"
3301
3302 # Here it used to say:
3303 # One thousand lines in, we can start doing stuff with things
3304 # Well, right now we are at line 3306 ;)
3305
3306 # Export needed things so they can be read in this subshell
3307 export CDDBTOOL ABCDETEMPDIR TRACKQUEUE LOWDISK EJECTCD EJECT EJECTOPTS
3308 export CDROM CDDBDATA REMOTEHOSTS MAXPROCS HTTPGET MD5SUM
3309
3310 if [ "$DOREAD" = "y" ]; then
3311 # User-definable function to set some things. Use it for
3312 # - closing the CD tray with eject -t
3313 # - set the CD speed value with eject -x
3314 vecho -n "Executing customizable pre-read function... "
3315
3316 pre_read # Execute the user-defined pre-read funtion. Close the CD with it.
3317
3318 vecho "done."
3319 fi
3320
3321 case "$CDDBMETHOD" in
3322 cddb)
3323 do_discid # Get ABCDETEMPDIR created and status file initialized
3324 ;;
3325 musicbrainz)
3326 do_musicbrainz
3327 ;;
3328 esac
3329
3330 if [ "$DOCDDB" = "y" ]; then
3331 # start with a sane default:
3332 CDDBLOCALSTATUS=notfound
3333 if [ $CDDBUSELOCAL = "y" ]; then
3334 do_localcddb
3335 fi
3336 if checkstatus cddb-choice > /dev/null; then
3337 :
3338 else
3339 if [ "$CDDBLOCALSTATUS" = "notfound" ] ; then
3340 case "$CDDBMETHOD" in
3341 cddb)
3342 do_cddbstat
3343 do_cddbquery
3344 do_cddbread
3345 ;;
3346 musicbrainz)
3347 do_musicbrainz
3348 ;;
3349 esac
3350 fi
3351 fi
3352 do_cddbedit
3353
3354 eval "$($CDDBTOOL parse "$CDDBDATA")"
3355 fi
3356
3357 # Before reading tracks, we set the speed of the device
3358
3359 if [ X"$CDSPEEDVALUE" != "X" ]; then
3360 case "$CDROMREADERSYNTAX" in
3361 cdparanoia|debug) ;;
3362 flac) ;;
3363 *) do_cdspeed ;;
3364 esac
3365 fi
3366
3367 # Define the first and last track, since we might need them later in several places
3368 FIRSTTRACK=$( get_first $TRACKQUEUE )
3369 LASTTRACK=$( get_last $TRACKQUEUE )
3370
3371 if [ -f "$ABCDETEMPDIR/status" ] && [ X"$ERASEENCODEDSTATUS" = "Xy" ]; then
3372 mv "$ABCDETEMPDIR/status" "$ABCDETEMPDIR/status.old"
3373 grep -v ^encodetracklocation- < "$ABCDETEMPDIR/status.old" \
3374 | grep -v ^encode-output > "$ABCDETEMPDIR/status"
3375 fi
3376
3377 if checkstatus onetrack ; then ONETRACK=y ; fi
3378
3379 if [ "$ONETRACK" = "y" ]; then
3380 # Reuse the CUEFILE in case we created it in a previous run
3381 if CUEFILE=$(checkstatus cuefile); then
3382 IMPORTCUESHEET=y
3383 fi
3384 fi
3385
3386 # Create playlist if needed (backgroundable) and start reading in tracks
3387
3388 (
3389
3390 if [ "$ONETRACK" = "y" ]; then
3391 if [ "$DOPLAYLIST" = "y" ]; then
3392 echo Creating playlist... >&2
3393 do_playlist
3394 fi
3395 fi
3396
3397 # For the lowdisk option, only one program is running at once so the encoder
3398 # can be unsilenced right away.
3399 if [ "$LOWDISK" = "y" ] || [ "$ONETRACK" = "y" ]; then
3400 echo "encode-output=loud" >> "$ABCDETEMPDIR/status"
3401 fi
3402
3403 if [ "$ONETRACK" = "y" ]; then
3404 TRACKS="$FIRSTTRACK"
3405 if [ "$USEPIPES" = "y" ]; then
3406 if checkstatus readencodetrack-$FIRSTTRACK; then :; else
3407 do_cdread onetrack $FIRSTTRACK $LASTTRACK | do_encode $FIRSTTRACK %local0% > /dev/null 2>&1
3408 fi
3409 else
3410 if checkstatus readtrack-$FIRSTTRACK; then :; else
3411 do_cdread onetrack $FIRSTTRACK $LASTTRACK
3412 fi
3413 fi
3414 else
3415 for UTRACKNUM in $TRACKQUEUE
3416 do
3417 if [ "$DOREAD" = "y" ]; then
3418 if [ "$USEPIPES" = "y" ]; then
3419 if checkstatus readencodetrack-$UTRACKNUM; then :; else
3420 # Read, pipe, shut up!
3421 do_cdread $UTRACKNUM | do_encode $UTRACKNUM %local0% > /dev/null 2>&1
3422 fi
3423 else
3424 if checkstatus readtrack-$UTRACKNUM; then :; else
3425 do_cdread $UTRACKNUM
3426 fi
3427 if [ "$?" != "0" ]; then
3428 # CD read failed - don't give the goahead to
3429 # the encoder
3430 echo NO
3431 exit
3432 fi
3433 fi
3434 fi
3435 if [ "$NOGAP" = "y" ] || [ "$BATCHNORM" = "y" ]; then
3436 :
3437 else
3438 # If we are not reading, set the encode output to loud already, so
3439 # that we can see the output of the first track.
3440 if [ "$MAXPROCS" = "1" ] && [ ! "$DOREAD" = "y" ]; then
3441 echo "encode-output=loud" >> "$ABCDETEMPDIR/status"
3442 fi
3443 echo NEXTTRACK # Get the encoder machine churning again
3444 if [ "$DOREAD" = "y" ]; then
3445 if [ "$LOWDISK" = "y" ] && [ "$DOENCODE" = "y" ]; then
3446 until checkstatus encodetrack-$UTRACKNUM
3447 do
3448 if checkerrors encodetrack-$UTRACKNUM; then
3449 break
3450 fi
3451 sleep 2
3452 done
3453 fi
3454 fi
3455 fi
3456 done
3457 fi
3458
3459 # Now that we're done the encoding can be loud again -
3460 # if we're not using SMP.
3461 if [ "$MAXPROCS" = "1" ]; then
3462 echo "encode-output=loud" >> "$ABCDETEMPDIR/status"
3463 fi
3464
3465 # All tracks read, start encoding.
3466 if [ "$NOGAP" = "y" ] || [ "$BATCHNORM" = "y" ] || [ "$ONETRACK" = "y" ]; then
3467 echo NEXTTRACK
3468 fi
3469
3470 # Execute the user-defined post_read funtion before ejecting CD
3471 post_read
3472
3473 # We are now finished with the cdrom - it can be safely ejected. Note that
3474 # abcde will not have completed yet.
3475 if [ "$EJECTCD" = "y" ] && [ -x $(which $EJECT) ]; then
3476 # We check if the disk we are processing is actually the disk inside the
3477 # CD tray. If not, we do not eject the CD, since it might be so that the
3478 # user ejected it manually.
3479 #CURRENTTRACKINFO=$($CDDISCID $CDROM)
3480 #if if [ "$?" != "1" ] && [ "$CURRENTTRACKINFO" = "$TRACKINFO" ] ; then
3481 # More FreeBSD bits.
3482 if [ X"$(uname)" = X"FreeBSD" ] ; then
3483 # FreeBSD eject uses the EJECT environment variable to name the CDROM
3484 # but in this script EJECT is in the envionment and names the program
3485 eject=$EJECT
3486 unset EJECT
3487 # The FreeBSD eject needs "adc0" not "/dev/adc0c"
3488 cd="$(echo $CDROM | sed -e 's=.*/==;s=[a-h]$==;')"
3489 $eject $EJECTOPTS $cd
3490 elif [ X"$(uname)" = X"Darwin" ] ; then
3491 disktool -e ${CDROM#/dev/} 0
3492 else
3493 $EJECT $EJECTOPTS $CDROM
3494 fi
3495 #fi
3496 fi
3497
3498 ) | (
3499
3500 ## Do we need to pre-process
3501 #if [ x"$PREPROCESS" = "x" ] ; then
3502 # cat
3503 #else
3504 # for PRETRACKNUM in $TRACKQUEUE
3505 # do
3506 # read GOAHEAD
3507 # if [ "$GOAHEAD" = "NO" ]; then break; fi
3508 # PREPROCEED=
3509 # until [ $PREPROCEED ]
3510 # do
3511 # if checkstatus readtrack-$PRETRACKNUM; then PREPROCEED=y; break; fi
3512 # # all locations are working, wait and try again later
3513 # if [ ! $PREPROCEED ]; then sleep 3; fi
3514 # done
3515 # ( do_preprocess $PRETRACKNUM
3516 # echo "NEXTTRACK"
3517 # ) &
3518 # done
3519 #fi
3520 #
3521 #) | (
3522
3523 # In BATCHNORM and/or NOGAP modes, we want all tracks to be read first.
3524 #BACK
3525 if [ "$BATCHNORM" = "y" ] || [ "$NOGAP" = "y" ]; then
3526 read GOAHEAD # For blocking - will contain either "NO" or "NEXTTRACK"
3527 if [ "$GOAHEAD" = "NO" ]; then break; fi
3528 for LASTTRACK in $TRACKQUEUE; do :; done
3529 if checkstatus readtrack-$LASTTRACK; then
3530 if [ "$DONORMALIZE" = "y" ] && [ "$BATCHNORM" = "y" ]; then
3531 if checkstatus normalizetrack-$LASTTRACK; then :; else do_batch_normalize; fi
3532 if checkerrors batch-normalize; then exit 1; fi
3533 fi
3534 if [ "$DOENCODE" = "y" ] && [ "$NOGAP" = "y" ]; then
3535 if [ "$DONORMALIZE" = "y" ]; then
3536 for UTRACKNUM in $TRACKQUEUE
3537 do
3538 if checkstatus readtrack-$UTRACKNUM; then
3539 if checkstatus normalizetrack-$UTRACKNUM; then :; else do_normalize $UTRACKNUM; fi
3540 fi
3541 done
3542 fi
3543 if checkstatus encodetrack-$LASTTRACK; then :; else do_nogap_encode; fi
3544 if checkerrors nogap-encode; then exit 1; fi
3545 fi
3546 fi
3547 fi
3548
3549 # If we are using ONETRACK, we can proceed with the normal encoding using just the $FIRSTTRACK as TRACKQUEUE
3550 if [ "$ONETRACK" = "y" ] ; then
3551 TRACKQUEUE="$FIRSTTRACK"
3552 TRACKS="$FIRSTTRACK"
3553 fi
3554
3555 # Do the encoding, including parallelization of remote encoding
3556 # Figure out where each track is going to be encoded
3557 ENCODELOCATIONS="$(echo $REMOTEHOSTS | tr , ' ')"
3558 if [ "$MAXPROCS" != "0" ]; then
3559 for NUM in $(f_seq_row 1 "$MAXPROCS")
3560 do
3561 ENCODELOCATIONS="$ENCODELOCATIONS %local$NUM%"
3562 done
3563 fi
3564 # Strip whitespace
3565 ENCODELOCATIONS=$(echo $ENCODELOCATIONS)
3566 for UTRACKNUM in $TRACKQUEUE
3567 do
3568 # Wait for our cue
3569 read GOAHEAD # For blocking - will contain either "NO" or "NEXTTRACK"
3570 if [ "$GOAHEAD" = "NO" ]; then break; fi
3571 # find out where this track is to be encoded
3572 if [ "$DOENCODE" = "y" -a "$USEPIPES" != "y" ]; then
3573 # Make sure we have a place to encode this, if not, exit stage right
3574 if [ -z "$ENCODELOCATIONS" ]; then
3575 continue
3576 fi
3577 PROCEED=
3578 until [ $PROCEED ]
3579 do
3580 for LOCATION in $ENCODELOCATIONS
3581 do
3582 PREVIOUSTRACK="$(checkstatus encodetracklocation-$LOCATION)"
3583 # check first if a track has ever been assigned to this location
3584 if [ -z "$PREVIOUSTRACK" ]; then PROCEED=y; break; fi
3585 # If it errored out, rebuild $ENCODELOCATIONS without this location in it
3586 if checkerrors encodetrack-$PREVIOUSTRACK; then
3587 for TEMPLOCATION in $ENCODELOCATIONS
3588 do
3589 if [ "$TEMPLOCATION" != "$LOCATION" ]; then
3590 TEMPENCODELOCATIONS="$TEMPENCODELOCATIONS $TEMPLOCATION"
3591 fi
3592 done
3593 ENCODELOCATIONS=$(echo $TEMPENCODELOCATIONS)
3594 ABORT=y
3595 PROCEED=y
3596 break
3597 fi
3598 # We're still here, this location must have been previously assigned,
3599 # and last completed without error - check if it's done with the
3600 # previous track yet
3601 if checkstatus encodetrack-$PREVIOUSTRACK; then PROCEED=y; break; fi
3602 done
3603 # all locations are working, wait and try again later
3604 if [ ! $PROCEED ]; then sleep 3; fi
3605 done
3606 # Record the location we're about to encode the next track at
3607 echo "encodetracklocation-$LOCATION=$UTRACKNUM" >> "$ABCDETEMPDIR/status"
3608 fi
3609 # Don't proceed with the rest of the loop if we can't encode
3610 if [ "$ABORT" ]; then continue; fi
3611 # Set TRACKNUM, TRACKNAME
3612 if [ -e "$CDDBDATA" ]; then
3613 if [ "$ONETRACK" = "y" ]; then
3614 TRACKNAME="$DALBUM"
3615 TRACKNUM="$FIRSTTRACK"
3616 splitvarious
3617 else
3618 TRACKNUM=$UTRACKNUM
3619 CDDBTRACKNUM=$(expr $UTRACKNUM - 1)
3620 do_getcddbinfo TRACKNAME
3621 splitvarious
3622 fi
3623 fi
3624 # You can't encode a file which needs to be normalized before finishing
3625 # You can't tag a file before it's finished encoding -
3626 # thus all of this is backgrounded together
3627 (
3628 if [ "$DONORMALIZE" = "y" ]; then
3629 if checkstatus readtrack-$UTRACKNUM; then
3630 if checkstatus normalizetrack-$UTRACKNUM; then :; else do_normalize $UTRACKNUM; fi
3631 fi
3632 fi
3633 if [ "$DOENCODE" = "y" -a "$USEPIPES" != "y" ]; then
3634 if checkstatus readtrack-$UTRACKNUM; then
3635 #if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION; fi
3636 if [ "$DONORMALIZE" = "y" ]; then
3637 if checkstatus normalizetrack-$UTRACKNUM; then
3638 if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION $OUTPUT; fi
3639 fi
3640 else
3641 if checkstatus encodetrack-$UTRACKNUM; then :; else do_encode $UTRACKNUM $LOCATION $OUTPUT; fi
3642 fi
3643 fi
3644 fi
3645 if [ "$DOTAG" = "y" ]; then
3646 if checkstatus encodetrack-$UTRACKNUM; then
3647 if checkstatus tagtrack-$UTRACKNUM; then :; else do_tag $UTRACKNUM; fi
3648 fi
3649 # Lets tag the cue file
3650 if checkstatus cleancuefile >/dev/null; then :; else
3651 if checkstatus cuefile >/dev/null ; then
3652 do_cleancue
3653 fi
3654 fi
3655 fi
3656 if [ "$DOMOVE" = "y" ]; then
3657 if checkstatus tagtrack-$UTRACKNUM; then
3658 if checkstatus movetrack-$UTRACKNUM; then :; else do_move $UTRACKNUM; fi
3659 fi
3660 fi
3661 ) &
3662 done
3663