2 ########################################################################
6 # Copyright (C) 2005 Felix Suwald
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or (at
12 # your option) any later version.
15 # This program is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 # General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
27 ########################################################################
31 # ripit.pl - Rips audio CD and encodes files, following steps can be
32 # performed (unsorted list):
33 # 1) Query CDDB data for album/artist/track info
34 # 2) Rip the audio files from the CD
35 # 3) Encode the wav files
36 # 4) ID3 tag the encoded files
37 # 5) Extract possible hidden tracks
38 # 6) Optional: Create a playlist (M3U) file.
39 # 7) Optional: Prepares and sends a CDDB submission.
40 # 8) Optional: saves the CDDB file
41 # 9) Optional: creates a toc (cue) file to burn a CD in DAO
43 # 10) Optional: analyze the wavs for gaps and splits them into
44 # chunks and/or trim lead-in/out (experimental)
45 # 11) Optional: merges wavs for gapless encoding
46 # 12) Optional: normalizes the wavs before encoding.
47 # 13) Optional: adds coverart to tags of sound files and
48 # copies albumcover to encoding directories.
49 # 14) Optional: calculates album gain for sound files.
50 # 15) Optional: creates a md5sum for each type of sound files.
53 # Version 3.9.0 - July 14th 2010 - Felix Suwald, thanks for input:
56 # Version 3.8.1 - November 18th 2009 - Felix Suwald
58 # Version 3.8.0 - September 28th 2009 - Felix Suwald
60 # Version 3.7.0 - May 6th 2009 - Felix Suwald, thanks for input:
63 # and to all the bug-reporters!
64 # Version 3.6.0 - June 16th 2007 - Felix Suwald, thanks for input:
68 # Version 3.5.0 - June 6th 2006 - Felix Suwald, credits to
69 # E. Riesebieter (deb-package)
70 # C. Walter (normalize option)
71 # S. Warten (general support & loop)
72 # S. Warten (signal handling)
73 # Version 3.4 - December 3rd 2005 - Felix Suwald, credits to
74 # M. Bright (infolog file)
75 # M. Kaesbauer (lcdproc) and
76 # C. Walter (config file).
77 # Version 2.5 - November 13th 2004 - Felix Suwald
78 # Version 2.2 - October 18th 2003 - Mads Martin Joergensen
79 # Version 1.0 - February 16th 1999 - Simon Quinn
82 ########################################################################
84 # User configurable variables:
85 # Keep these values and save your own settings in a config file with
88 my $cddev = "/dev/cdrom";# Path of CD device.
89 my $scsi_cddev = ""; # Path of CD device for non audio commands.
90 my $outputdir = ""; # Where the sound should go to.
91 my $ripopt = ""; # Options for audio CD ripper.
92 my $span = ""; # Options for track spans.
93 my $ripper = 1; # 0 - dagrab, 1 - cdparanoia,
94 # 2 - cdda2wav, 3 - tosha, 4 - cdd.
95 my @coder = (0); # 0 - Lame, 1 - Oggenc, 2 - Flac,
96 # 3 - Faac, 4 - mp4als, 5 - Musepack,
97 # 6 - Wavpack, 7 - ffmpeg,
98 # comma separated list.
99 my $coverart = 0; # Add cover metadata, (1 yes, 0 no),
100 # comma separated list in same order as
102 my $coverpath = ""; # Path to cover to be added to sound files.
103 my $copycover = ""; # Path to album cover source.
104 my $bitrate = 128; # Bitrate for lame, if --vbrmode used,
105 # bitrate is equal to the -b option.
106 my $maxrate = 0; # Bitrate for lame using --vbrmode,
107 # maxrate is equal to the -B option.
108 my @quality = (5,3,5,100,0,5);# Quality for lame in vbr mode (0-9), best
109 # quality = 0, quality for oggenc (1-10),
110 # best = 10; or compression level for Flac
111 # (0-8), lowest = 0, quality for Faac
112 # (10-500), best = 500, no values for
113 # Wavpack and ffmpeg.
114 my $qualame = 5; # Same as above, more intuitive. Use quotes
115 my $qualoggenc= 3; # if values shall be comma separated lists.
121 my $oggencopt = ""; #
124 my $mp4alsopt = ""; #
126 my $wavpacopt = "-y"; #
127 my $ffmpegopt = ""; #
128 my $ffmpegsuffix = ""; # The suffix of the encoder used
129 my $musenc = "mpcenc"; # The default Musepack encoder.
130 my $mp3gain = ""; # The mp3 album gain command with options.
131 my $vorbgain = ""; # The vorbis album gain command with options.
132 my $flacgain = ""; # The flac album gain command with options.
133 my $aacgain = ""; # The aac album gain command with options.
134 my $mpcgain = ""; # The mpc album gain command with options.
135 my $wvgain = ""; # The wv album gain command with options.
136 my $lcd = 0; # Use lcdproc (1 yes, 0 no).
137 my $chars = "XX"; # Exclude special chars in file names.
138 my $verbose = 3; # Normal output: 3, no output: 0, minimal
139 # output: 1, normal without encoder msgs: 2,
140 # normal: 3, verbose: 4, extremely verbose: 5
141 my $commentag = ""; # Comment ID3 tag.
142 my $genre = ""; # Genre of Audio CD for ID3 tag.
143 my $year = ""; # Year of Audio CD for ID3 tag.
144 my @mp3tags = (); # Add special mp3 tag.
145 my $utftag = 1; # Keep Lame-tags in utf or decode them to
146 # ISO8895-1 (1 yes, 0 no).
147 my $vatag = 0; # Detect VA style for tagging (1 yes, 0 no,
148 # 2 backward style (trackname / artist)).
149 my $vastring = "\\bVA\\b|Variou*s|Various Artists";
150 my $eject = 0; # Eject the CD when done (1 yes, 0 no).
151 my $ejectcmd = "eject"; # Command to use for eject
152 my $ejectopt = "{cddev}"; # Options to above
153 my $quitnodb = 0; # Quit if no CDDB entry found (1 yes, 0 no).
154 my $overwrite = "n"; # Overwrite existing directory / rip
155 # (n no, y yes, e eject if directory exists)
156 my $halt = 0; # Shutdown machine when finished
158 my $nice = 0; # Set nice for encoding process.
159 my $nicerip = 0; # Set nice for ripping process.
160 my $savenew = 0; # Saved passed parameters to new config
161 # file (1 yes, 0 no).
162 my $savepara = 0; # Save parameters passed in config file
164 my $config = 1; # Use config file to read parameters
166 my $confdir = ""; # Full path to the users config file.
167 my $confname = "config"; # File name of config file.
168 my $submission= 1; # Send CDDB submission
170 my $parano = 1; # Use paranoia mode in cdparanoia
172 my $playlist = 1; # Do create the m3u playlist file
173 # (1 yes, 0 no, 2 no full path in filename).
174 my $book = 0; # Merge all tracks into a single file and
175 # write a chapter file (1 yes, 0 no).
176 my $resume = 0; # Resume a previously started session
178 my $infolog = ""; # InfoLog
180 my $interaction = 1; # If 0 do not ask anything, take the 1st
181 # CDDB entry found or use default names!
183 my $underscore = 0; # Use _ instead of spaces in filenames
185 my $lowercase = 0; # Lowercase filenames
187 my $uppercasefirst = 0; # Uppercase first filenames
189 my $archive = 0; # Save CDDB files in ~/.cddb dir
191 my $mb = 0; # Use the musicbrainz DB instead of freedb
193 my $mirror = "freedb"; # The host (a freedb mirror) that
194 # shall be used instead of freedb.
195 my $transfer = "cddb"; # Transfer mode, cddb or http, will set
196 # default port to 8880 or 80 (for http).
197 my $vbrmode = ""; # Variable bitrate, only used with lame,
198 # (new or old), see lame-manpage.
199 my $proto = 6; # CDDB protocol level for CDDB query.
200 my $proxy = ""; # Set proxy.
201 my $CDDB_HOST = "freedb.org"; # Set cddb host
202 my $mailad = ""; # Users return e-mail address.
203 my @threads = 1; # Number of encoding processes for each box
204 my @sshlist = (); # List of remote machines.
205 my $scp = 0; # Use scp to access files (1 yes, 0 no).
206 my $local = 1; # Encode on locale machine (1 yes, 0 no).
207 my $wav = 0; # Keep the wav files (1 yes, 0 no).
208 my $encode = 1; # Encode the wav files (1 yes, 0 no).
209 my $rip = 1; # Rip the CD files (1 yes, 0 no).
210 my $cdcue = 0; # Create a cue-file for what? (1 yes, 0 no).
211 my $cdtoc = 0; # Create a cd.toc for CDRDAO (1 yes, 0 no).
212 my $inf = 0; # Create inf files for wodim (1 yes, 0 no).
213 my $loop = 0; # Restart ripit as soon as the previous CD
214 # is done. This option will force ejection!
215 # (1 yes, 0 no, 2 immediate restart after
216 # ripping, experimental, use with caution!).
217 my $ghost = 0; # Check and extract ghost songs from all
218 # tracks (1 yes, 0 no).
219 my $prepend = 2.0; # Extend ghost songs by 2 seconds at the
221 my $extend = 2.0; # Extend ghost songs by 2 seconds at the
223 my $dpermission = "0755"; # Directory permissions.
224 my $fpermission = ""; # Audio and text file permissions.
225 my $md5sum = 0; # Generate MD5 sums for every sound file
226 # not deleted (1 yes, 0 no).
227 my @suffix = (); # Array of suffixes according to coders.
228 my $execmd = ""; # Execute a command when done.
229 my $precmd = ""; # Execute a command before ripping.
230 my $multi = 0; # Not yet official. Do not use!
231 my $mbname = ""; # Musicbrainz login name.
232 my $mbpass = ""; # Musicbrainz password for ISRC submission.
233 my $isrc = 0; # Detect ISRC with icedax (1 yes, 0 no).
235 # New options step 1: Add global variables here above or below in case
236 # they shouldn't be user configurable.
240 # Directory and track template variables:
241 # Contains the format the track names will be written as.
242 # The '" and "' are important and must surround the template.
243 # Example variables to use are: $tracknum, $album, $artist, $genre,
244 # $trackname or $year.
245 # E.g. example setting of $tracktemplate produces a trackname of
246 # "07 The Game - Swandive" .
247 # $tracktemplate = '"$tracknum $trackname - $artist"';
249 my @dirtemplate = '"$artist - $album"';
250 my $tracktemplate = '"$tracknum $trackname"';
256 my $lcdhost = "localhost";
257 my $lcdport = "13666";
258 my $lcdline1 = " [initializing] ";
259 my $lcdline2 = " ripit-lcd-module ";
260 my $lcdline3 = " 2005 ";
269 # Normalize settings:
271 my $normalize = 0; # normalize CD, needs 'normalize' in $path.
272 my $normcmd = "normalize"; # This might differ for other distros.
273 my $normopt = "-b"; # Additional options for normalize.
274 my $subdir = "Unsorted";
277 ########################################################################
279 # System variables, no user configurable variables below.
281 use Encode; # Needed for decode_utf8 calls.
282 use Fcntl; # Needed for sysopen calls.
284 use Getopt::Long qw(:config no_ignore_case);
291 my $homedir = "$ENV{HOME}";
292 my $workdir = "$ENV{PWD}";
293 my $usename = "$ENV{USER}";
294 # The hostname is not so important and not available on Ubuntu(s) (?).
297 $hostnam = "$ENV{HOSTNAME}";
300 $hostnam = "$ENV{HOST}";
303 if($ENV{G_FILENAME_ENCODING}) {
304 $charset = "$ENV{G_FILENAME_ENCODING}";
307 $charset = "$ENV{LANG}";
309 if($charset =~ /UTF-8/) {
312 elsif($charset =~ /ISO-8859-15/) {
313 $charset = "ISO-8859-15";
316 $charset = "ISO-8859-1";
318 #print ($_,$ENV{$_},"\n") foreach (keys %ENV);
321 # Initialize global variables.
323 my $version = "3.9.0";
325 my $artist_utf8 = "";
326 my $distro = ""; # Linux distribution
327 my $categ = ""; # CDDB category
328 my $cddbid = 0; # Needed in several subroutines
329 my $lameflag = 0; # Flag to check if lame is used, some users
330 # are not aware that lame is needed for mp3!
331 my $oggflag = 0; # Flag to check if oggenc is used. Needed to
332 # load modules if coverart for ogg is used.
333 my $wvpflag = 0; # Flag to check wavpack version and its
335 my $trackselection = ""; # Passed from command line
336 my @tracksel = (); # Array of all track numbers, including
337 # those not explicitly stated.
338 my @seltrack = (); # Array of all track numbers, including
339 # those not explicitly stated and ghost
340 # songs found by ripper needed by encoder.
341 my @framelist = (); # Needed in several subroutines
342 my @secondlist = (); # Needed in several subroutines
343 my @tracklist = (); # Needed in several subroutines
344 my @tracktags = (); # Needed in several subroutines
345 my %cd = (); # HoH of all CD-data.
346 my $cddbsubmission = 2; # If zero then data for CDDB submission is
347 # incorrect, if 1: submission OK, if 2: CDDB
348 # entry not changed (edited)
349 my $wpreset = ""; # Preset written into config file.
350 my $wcoder = ""; # Use a comma separated string to write the
351 # coder-array into the config file.
352 my $wthreads = ""; # Use a comma separated string to write the
353 # threads-array into the config file.
354 my $wsshlist = ""; # As above for the list of remote machines.
355 my $sshflag = 0; # Ssh encoding OK if sshflag == 1.
356 my %sshlist = (); # Hash of remote machines.
358 my $logfile = ""; # Used with not *to-use* option --multi.
359 my $help = 0; # Print help and exit if 1.
360 my $printver = 0; # Print version and exit if 1.
361 my @delname = (); # List of tracknames being processed, i.e.
362 # ready for deletion.
363 my @skip = (); # List of merged tracks.
364 my @globopt = (); # All encoder options sorted according to
366 my @sepdir = (); # Array of sound directories sorted
367 # according to encoder.
368 my $wavdir = ""; # (Default) directory for sound.
369 my $limit_flag = 0; # Directory and file length flag.
370 my $va_flag = 0; # VA style flag.
371 my $va_delim = "/"; # VA style delimiter.
372 my @isrcs = (); # ISRC array.
373 my @idata = (); # Array for the MB track IDs.
375 # New options step 2: Add global variables here in case they shouldn't
376 # be user configurable; additional modules can be added right below.
379 # Initialize subroutines without ().
402 # New options step 3: Do not forget to initialize new subroutines.
405 # Define the variables which catch the command line input.
406 # The p stands for passed (from command line).
408 $parchive, $pbitrate, $pmaxrate, $PCDDB_HOST,
409 $pcddev, $pcdtoc, @pcoder, $pcommentag,
410 $pconfig, @pdirtemplate, $ptracktemplate, $peject,
411 $pencode, $pfaacopt, $pflacopt, $plameopt,
412 $poggencopt, $pgenre, $phalt, $pinfolog,
413 $pinteraction, $plcdhost, $plcdport, $plcd,
414 $plocal, $ploop, $plowercase, $pmirror,
415 $pmailad, $pmulti, $pnice, $pnormalize,
416 $pnormopt, $poutputdir, $pparano, $pplaylist,
417 $ppreset, $pproto, $pproxy, @pquality,
418 $pripopt, $prip, $pripper, $psavenew,
419 $psavepara, $pscp, @psshlist, $psubdir,
420 $psubmission, $ptransfer, $punderscore, $putftag,
421 $pvbrmode, $pverbose, $pwav, $pyear,
422 $presume, $pmerge, $pghost, $pprepend,
423 $pextend, $pejectopt, $pejectcmd, $pdpermission,
424 $pfpermission, $pmd5sum, $pnicerip, @pthreads,
425 $pnormcmd, $pmb, $puppercasefirst, $pexecmd,
426 $pspan, $poverwrite, $pquitnodb, $pbook,
427 $pmusenc, $pmp4alsopt, $pmuseopt, $pinf,
428 $pscsi_cddev, $pwavpacopt, $pffmpegopt, $pffmpegsuffix,
429 $pprecmd, $pcoverart, $pcoverpath, $pcdcue,
430 $pvatag, $pvastring, $pmp3gain, $pvorbgain,
431 $pflacgain, $paacgain, $pmpcgain, $pwvgain,
432 @pmp3tags, $pcopycover, $ptrackoffset, $pmbname,
436 # New options step 4: For distinction of variables passed on the command
437 # line and other from the configuration file, introduce for each new
438 # option the variable name prefixed with 'p'; 'p' stands for passed.
441 ########################################################################
443 # Get the parameters from the command line.
445 # available: E F jJkK Q Y
446 # already used: aAbBcCdDe f gGhiI lLmMnNoOpPq rRsStTuUvVwWxXy zZ
449 "archive|a!" => \$parchive,
450 "bitrate|b=s" => \$pbitrate,
451 "book|A=i" => \$pbook,
452 "maxrate|B=i" => \$pmaxrate,
453 "chars|W:s" => \$chars,
454 "cddbserver|C=s" => \$PCDDB_HOST,
455 "cdcue=i" => \$pcdcue,
456 "cdtoc=i" => \$pcdtoc,
457 "config!" => \$pconfig,
458 "coder|c=s" => \@pcoder,
459 "coverart=s" => \$pcoverart,
460 "coverpath=s" => \$pcoverpath,
461 "copycover=s" => \$pcopycover,
462 "comment=s" => \$pcommentag,
463 "threads=s" => \@pthreads,
464 "device|d=s" => \$pcddev,
465 "dirtemplate|D=s" => \@pdirtemplate,
466 "eject|e!" => \$peject,
467 "ejectcmd=s" => \$pejectcmd,
468 "ejectopt=s" => \$pejectopt,
469 "encode!" => \$pencode,
470 "execmd|X=s" => \$pexecmd,
471 "extend=f" => \$pextend,
472 "faacopt=s" => \$pfaacopt,
473 "flacopt=s" => \$pflacopt,
474 "lameopt=s" => \$plameopt,
475 "oggencopt=s" => \$poggencopt,
476 "mp4alsopt=s" => \$pmp4alsopt,
477 "musenc=s" => \$pmusenc,
478 "museopt=s" => \$pmuseopt,
479 "wavpacopt=s" => \$pwavpacopt,
480 "ffmpegopt=s" => \$pffmpegopt,
481 "ffmpegsuffix=s" => \$pffmpegsuffix,
482 "mp3gain=s" => \$pmp3gain,
483 "vorbgain=s" => \$pvorbgain,
484 "flacgain=s" => \$pflacgain,
485 "aacgain=s" => \$paacgain,
486 "mpcgain=s" => \$pmpcgain,
487 "wvgain=s" => \$pwvgain,
488 "genre|g=s" => \$pgenre,
489 "ghost|G!" => \$pghost,
493 "infolog=s" => \$pinfolog,
494 "interaction|i!" => \$pinteraction,
497 "lcdhost=s" => \$plcdhost,
498 "lcdport=s" => \$plcdport,
499 "lowercase|l!" => \$plowercase,
500 "uppercasefirst!" => \$puppercasefirst,
501 "local!" => \$plocal,
504 "md5sum!" => \$pmd5sum,
505 "merge=s" => \$pmerge,
506 "mirror|m=s" => \$pmirror,
507 "mail|M=s" => \$pmailad,
508 "mbname=s" => \$pmbname,
509 "mbpass=s" => \$pmbpass,
510 "mp3tags=s" => \@pmp3tags,
512 "nice|n=s" => \$pnice,
513 "nicerip=s" => \$pnicerip,
514 "normalize|N!" => \$pnormalize,
515 "normcmd=s" => \$pnormcmd,
516 "normopt|z=s" => \$pnormopt,
517 "subdir=s" => \$psubdir,
518 "outputdir|o=s" => \$poutputdir,
519 "overwrite|O=s" => \$poverwrite,
520 "dpermission=s" => \$pdpermission,
521 "fpermission=s" => \$pfpermission,
522 "playlist|p:s" => \$pplaylist,
523 "precmd=s" => \$pprecmd,
524 "prepend=f" => \$pprepend,
525 "preset|S=s" => \$ppreset,
526 "proxy|P=s" => \$pproxy,
527 "protocol|L=i" => \$pproto,
528 "quality|q=s" => \@pquality,
529 "quitnodb=i" => \$pquitnodb,
530 "resume|R" => \$presume,
532 "ripper|r=s" => \$pripper,
533 "ripopt=s" => \$pripopt,
534 "savenew" => \$psavenew,
535 "save" => \$psavepara,
537 "scsidevice=s" => \$pscsi_cddev,
538 "sshlist=s" => \@psshlist,
539 "span|I=s" => \$pspan,
540 "submission|s!" => \$psubmission,
541 "tracktemplate|T=s" => \$ptracktemplate,
542 "trackoffset=i" => \$ptrackoffset,
543 "transfer|t=s" => \$ptransfer,
544 "underscore|u!" => \$punderscore,
545 "utftag|U!" => \$putftag,
546 "vatag=i" => \$pvatag,
547 "vastring=s" => \$pvastring,
548 "vbrmode|v=s" => \$pvbrmode,
549 "verbose|x=i" => \$pverbose,
550 "version|V" => \$printver,
551 "year|y=i" => \$pyear,
553 "disable-paranoia|Z:i" => \$pparano,
555 or exit print_usage();
557 # New options step 5: Add the command line option here.
560 ########################################################################
562 # Evaluate the command line parameters if passed. We need to do it this
563 # way, because passed options have to be saved (in case user wants to
564 # save them in the config file) before config file is read to prevent
565 # overriding passed options with options from config file. The passed
566 # options shall be stronger than the config file options!
567 # Problems arise with options that can be zero. Because a usual if-test
568 # can not distinguish between zero or undef, use the defined-test!
570 # New options step 6: force use of command line options if passed.
573 # First for the normal options, e. g. options which are never zero.
575 # The check of array @coder will be done in the subroutine!
576 $faacopt = $pfaacopt if($pfaacopt);
577 $flacopt = $pflacopt if($pflacopt);
578 $lameopt = $plameopt if($plameopt);
579 $oggencopt = $poggencopt if($poggencopt);
580 $mp4alsopt = $pmp4alsopt if($pmp4alsopt);
581 $musenc = $pmusenc if($pmusenc);
582 $museopt = $pmuseopt if($pmuseopt);
583 $wavpacopt = $pwavpacopt if($pwavpacopt);
584 $ffmpegopt = $pffmpegopt if($pffmpegopt);
585 $ffmpegsuffix = $pffmpegsuffix if($pffmpegsuffix);
586 $oggencopt = " " unless($oggencopt); # Oops, only to prevent warnings...
587 $mp3gain = $pmp3gain if($pmp3gain);
588 $vorbgain = $pvorbgain if($pvorbgain);
589 $flacgain = $pflacgain if($pflacgain);
590 $aacgain = $paacgain if($paacgain);
591 $mpcgain = $pmpcgain if($pmpcgain);
592 $wvgain = $pwvgain if($pwvgain);
593 $CDDB_HOST = $PCDDB_HOST if($PCDDB_HOST);
594 $cddev = $pcddev if($pcddev);
595 $overwrite = $poverwrite if($poverwrite);
597 # Get the default "no-argument" values.
598 # Note, that subroutine clean_all already purges ;><" and \015.
599 $chars = "NTFS" if($chars eq "");
600 $chars = "" if($chars eq "off");
601 $commentag = $pcommentag if($pcommentag);
602 $copycover = $pcopycover if($pcopycover);
603 @dirtemplate = @pdirtemplate if($pdirtemplate[0]);
604 $tracktemplate = $ptracktemplate if($ptracktemplate);
605 $execmd = $pexecmd if($pexecmd);
606 $precmd = $pprecmd if($pprecmd);
607 $halt = $phalt if($phalt);
608 $infolog = $pinfolog if($pinfolog);
609 $lcdhost = $plcdhost if($plcdhost);
610 $lcdport = $plcdport if($plcdport);
611 $mailad = $pmailad if($pmailad);
612 $mbname = $pmbname if($pmbname);
613 $mbpass = $pmbpass if($pmbpass);
614 @mp3tags = @pmp3tags if($pmp3tags[0]);
615 $mirror = $pmirror if($pmirror);
616 $normcmd = $pnormcmd if($pnormcmd);
617 $normopt = $pnormopt if($pnormopt);
618 $outputdir = $poutputdir if($poutputdir);
619 my $preset = $ppreset if($ppreset);
620 $ripopt = $pripopt if($pripopt);
621 $dpermission = $pdpermission if($pdpermission);
622 $fpermission = $pfpermission if($pfpermission);
623 $proto = $pproto if($pproto);
624 $proxy = $pproxy if($pproxy);
625 # Check for variable $psshlist will be done in the subroutine!
626 # Check for variable $pthreads will be done in the subroutine!
627 $transfer = $ptransfer if($ptransfer);
628 $vbrmode = $pvbrmode if($pvbrmode);
629 $year = $pyear if($pyear);
631 # Options which might be zero.
632 $bitrate = $pbitrate if($pbitrate);
633 $book = $pbook if($pbook);
634 $cdcue = $pcdcue if defined $pcdcue;
635 $cdtoc = $pcdtoc if defined $pcdtoc;
636 $coverart = $pcoverart if defined $pcoverart;
637 $extend = $pextend if defined $pextend;
638 $genre = $pgenre if defined $pgenre;
639 $inf = $pinf if defined $pinf;
640 $isrc = $pisrc if defined $pisrc;
641 $loop = $ploop if defined $ploop;
642 $md5sum = $pmd5sum if defined $pmd5sum;
643 $maxrate = $pmaxrate if defined $pmaxrate;
644 $nice = $pnice if defined $pnice;
645 $nicerip = $pnicerip if defined $pnicerip;
646 $parano = $pparano if defined $pparano;
647 $playlist = $pplaylist if defined $pplaylist;
648 $playlist = 1 if($playlist eq "");
649 $prepend = $pprepend if defined $pprepend;
650 $quitnodb = $pquitnodb if defined $pquitnodb;
651 $resume = $presume if defined $presume;
652 $ripper = $pripper if defined $pripper;
653 $savepara = $psavepara if defined $psavepara;
654 $savenew = $psavenew if defined $psavenew;
655 $scp = $pscp if defined $pscp;
656 if(defined $pscsi_cddev) {
657 $scsi_cddev = $pscsi_cddev;
660 $scsi_cddev = $pcddev if($pcddev);
662 $span = $pspan if defined $pspan;
663 $trackoffset = $ptrackoffset if defined $ptrackoffset;
664 $verbose = $pverbose if defined $pverbose;
665 $vatag = $pvatag if defined $pvatag;
667 # And for the negatable options.
668 $archive = $parchive if defined $parchive;
669 $config = $pconfig if defined $pconfig;
670 $encode = $pencode if defined $pencode;
671 $eject = $peject if defined $peject;
672 $ejectcmd = $pejectcmd if defined $pejectcmd;
673 $ejectopt = $pejectopt if defined $pejectopt;
674 $ghost = $pghost if defined $pghost;
675 $interaction = $pinteraction if defined $pinteraction;
676 $lcd = $plcd if defined $plcd;
677 $local = $plocal if defined $plocal;
678 $lowercase = $plowercase if defined $plowercase;
679 $mb = $pmb if defined $pmb;
680 $uppercasefirst = $puppercasefirst if defined $puppercasefirst;
681 $multi = $pmulti if defined $pmulti;
682 $normalize = $pnormalize if defined $pnormalize;
683 $rip = $prip if defined $prip;
684 $submission = $psubmission if defined $psubmission;
685 $underscore = $punderscore if defined $punderscore;
686 $utftag = $putftag if defined $putftag;
687 $wav = $pwav if defined $pwav;
689 ########################################################################
691 # Preliminary start: print version, read (and write) config file.
693 # To have the version printed first of all other (warning-) messages,
694 # find out if verbosity is set off or not, either by command line or
697 my $ripdir = $confdir . "/" . $confname if($confdir ne "");
699 $ripdir = $homedir . "/.ripit/config" unless(-r "$ripdir");
700 $ripdir = "/etc/ripit/config" unless(-r "$ripdir");
701 if(-r "$ripdir" && $config == 1) {
702 open(CONF, "$ripdir") || print "Can not read config file!\n";
703 my @conflines = <CONF>;
705 chomp($verbose = join('', grep(s/^verbose=//, @conflines)))
707 chomp($infolog = join('', grep(s/^infolog=//, @conflines)))
711 print "\n\n\nRipIT version $version.\n" if($verbose >= 1);
712 # Preliminary creation of the infolog path.
713 # No log_system call here because this would try to write to the infolog
714 # file not yet created.
716 my($log_path, $filename) = $infolog =~ m/(.*\/)(.*)$/;
717 system("mkdir -m 0755 -p \"$log_path\"") and
718 print "Can not create directory \"$log_path\": $!\n";
720 log_info("RipIT version $version infolog-file.\n");
723 # Do some checks before writing a new config file (if wanted):
725 # First check if arguments of option merge are OK.
726 my @dummy = skip_tracks if($pmerge);
728 # Then the options that will be written to the config file.
729 if($help ne 1 && $printver ne 1) {
730 check_coder(); # Check encoder array.
731 check_quality(); # Check if quality is valid.
732 check_proto(); # Check if protocol level is valid.
733 check_sshlist(); # Check list of remote machines.
734 check_preset() if($preset); # Check preset settings.
736 # To be able to save a new config file we have to write it before
737 # reading the parameters not yet passed from the config file.
739 $chars = "" if($chars eq "XX" && ($savenew == 1 || $savepara == 1));
741 $verbose = 3; # Set back to default value.
742 $infolog = ""; # Set back to default value.
744 print "Saved a new config file!\n\n" if($verbose >= 3);
747 # Read the config file.
749 read_config() if($config == 1);
750 check_enc("lame", "mp3");
751 # check_enc("faac", "m4a");
753 # Check if the necessary modules are installed properly.
758 # Security check for new options: give them default value if empty.
759 # This can happen, if the config file is not yet up-to date.
760 # This will go away again in version 4.0. This is also done to prevent
761 # warnings. And to avoid problems when updating from versions like 3.3.
763 # New options step 7: not mandatory, might be useful.
765 $copycover = "" unless($copycover);
766 $uppercasefirst = 0 unless($uppercasefirst);
768 $execmd = "" unless($execmd);
769 $precmd = "" unless($precmd);
770 $overwrite = "n" unless($overwrite);
771 $quitnodb = 0 unless($quitnodb);
772 $book = 0 unless($book);
773 $cdcue = 0 unless($cdcue);
774 $inf = 0 unless($inf);
775 $isrc = 0 unless($isrc);
776 $resume = 0 unless($resume);
777 $musenc = "mpcenc" unless($musenc);
778 $quamp4als = 0 unless($quamp4als);
779 $quamuse = 5 unless($quamuse);
780 $trackoffset = 0 unless($trackoffset);
781 $vatag = 0 unless($vatag);
783 # Save the config file.
785 save_config() if($savepara == 1);
786 print "Updated the config file!\n\n"
787 if($verbose >= 3 && $savepara == 1);
789 # It might be a good to x-check settings from config file because they
790 # can be edited manually.
792 check_coder(); # Check it again for lame cbr vs vbr.
793 check_quality(); # Check it again if quality is valid.
794 check_sshlist(); # Check it again to create the hash.
795 check_options(); # Sort the options according to the encoder.
796 check_distro(); # Check for the distribution used.
799 ########################################################################
803 ########################################################################
811 print "Process summary:\n", "-" x 16, "\n" unless($help == 1);
815 print "\nThis is a shorten man page. Refer to the full manpage ",
816 "for more details.\n";
821 if(!$pcddev) { # Check CD dev if none defined.
824 else { # Close the tray.
825 my $closeopt = $cddev if($ejectopt eq '{cddev}');
826 $closeopt = "-t " . $closeopt if($ejectcmd =~ /^eject$/);
827 $closeopt = $closeopt . " close" if($ejectcmd =~ /cdcontrol/);
828 log_system("$ejectcmd $closeopt > /dev/null 2>&1");
831 if($scsi_cddev eq "") {
832 $scsi_cddev = $cddev;
843 if($outputdir eq "") {
844 $outputdir = $homedir;
848 if($outputdir =~ /^\.\//) {
849 $outputdir =~ s/^\./$workdir/;
851 elsif($outputdir =~ /^\.\s*$/) {
852 $outputdir =~ s/^\./$workdir/;
855 if($outputdir =~ /^~\//) {
856 $outputdir =~ s/^~/$homedir/;
859 if($outputdir =~ /^\$HOME/) {
860 $outputdir =~ s/^\$HOME/$homedir/;
863 # New options step 8: Add a message about selected options if needed.
865 if(length($year) > 0 && length($year) != 4 ) {
866 print STDERR "Warning: year should be in 4 digits - $year.\n"
870 if($pdpermission && $verbose >= 2) {
871 # Print this message only, if a dpermission has been passed on CL.
872 $dpermission = sprintf("%04d", $dpermission);
873 print "Directory permission will be set to $dpermission.\n";
876 if($fpermission && $verbose >= 2) {
877 $fpermission = sprintf("%04d", $fpermission);
878 print "File permission will be set to $fpermission.\n";
881 if($resume == 1 && $verbose >= 2) {
882 print "Resuming previous session.\n";
885 if($span && $verbose >= 2) {
886 print "Partial wav files will be ripped.\n" unless($span =~ /\d-$/);
889 if($wav == 1 && $verbose >= 2) {
890 print "Wav files will not be deleted.\n";
893 if($normalize == 1 && $verbose >= 2) {
894 print "Normalizeing the CD-tracks.\n";
897 if($book >= 1 && $verbose >= 2) {
898 print "All tracks will be merged into one file and a chapter file written.\n";
903 if($cdcue > 0 && $verbose >= 2) {
904 print "All tracks will be merged into one file and a cue-file written.\n";
905 $pmerge = "1-" if($cdcue == 2);
907 $ghost = 1 if($cdcue == 1);
910 if($cdtoc >= 1 && $verbose >= 2) {
911 print "A toc file will be written.\n";
914 if($inf >= 1 && $verbose >= 2) {
915 print "Inf files will be written for each track.\n";
919 print "Tracks will be analyzed for ghost songs.\n" if($verbose >= 2);
922 if($utftag == 0 && $verbose >= 2 && "@coder" =~ /0/) {
923 print "Lame-tags will be encoded to ISO8859-1.\n";
926 if($mp3tags[0] && $verbose >= 2 ) {
927 print "Special track tags will be added to mp3 files.\n";
930 if($vatag > 0 && $verbose >= 2 ) {
931 print "Track tags will be analyzed for VA style.\n";
934 if($playlist >= 1 && $verbose >= 2) {
935 print "Playlist (m3u) file will be written.\n";
938 if($md5sum == 1 && $verbose >= 2) {
939 print "MD5SUMs of sound files will be calculated.\n";
942 if($copycover && $verbose >= 2) {
943 print "Copying the cover to encoder directories.\n";
946 if($coverart =~ /1/ && $verbose >= 2) {
947 print "Adding coverart to sound files.\n";
950 if(($mp3gain || $vorbgain || $flacgain || $aacgain || $mpcgain || $wvgain)
951 && $encode == 1 && $verbose >= 2) {
952 print "Adding album gain tags to sound files.\n";
955 if($parano >= 3 && $verbose >= 2 ) {
956 print "Warning: paranoia argument unknown, will use paranoia.\n";
960 if($halt == 1 && $verbose >= 2) {
961 print "Halting machine when finished.\n";
964 if($eject == 1 || $loop >= 1) {
965 print "CD will be ejected when finished.\n" if($verbose >= 2);
966 $ejectcmd = "eject -v" if($ejectcmd =~ /eject/ && $verbose >= 4);
970 print "Endless looping and ejection of each CD.\n" if($verbose >= 2);
971 print "\n" if($verbose >= 2);
976 print "Please insert a new CD!\n" if($verbose >= 1);
977 while( not cd_present() ) {
983 print "\n" if($verbose >= 2);
988 ########################################################################
992 ########################################################################
996 $trackselection = $ARGV[0];
999 if($bitrate ne "off" && $lameflag == 1) {
1003 if($vbrmode ne "" && $lameflag == 1) {
1011 unless( cd_present() ) {
1012 print "\nPlease insert an audio CD!\n" if($verbose > 0);
1013 while( not cd_present() ) {
1018 if($archive == 1 && $multi == 0) {
1022 get_cdinfo() if($mb == 0);
1023 get_mb() if($mb == 1);
1026 create_seltrack($trackselection);
1028 my $answer = create_dirs();
1030 if($answer eq "go") {
1032 $precmd =~ s/\$/\\\$/g;
1033 print "Will execute command \"$precmd\".\n" if($verbose >= 3);
1034 log_system("$precmd");
1036 if(-f "$copycover" && -s "$copycover") {
1039 elsif($copycover ne "") {
1040 print "\nAlbum cover with path $copycover not found.\n"
1042 if($interaction == 1) {
1044 copy_cover if(-f "$copycover" && -s "$copycover");
1047 if($normalize == 1 or $cdcue > 0) {
1049 norm_cd() if($normalize == 1);
1056 elsif($answer eq "next") {
1057 print "\nRelease $cd{artist} - $cd{title} already done, ",
1058 "giving up.\n" if($verbose > 0);
1059 log_info("Directory already present, giving up.");
1060 log_info("*" x 72, "\n");
1062 elsif($answer eq "unknown") {
1063 print "\nRelease unknown, giving up.\n" if($verbose > 0);
1064 log_info("Release unknown, giving up.");
1065 log_info("*" x 72, "\n");
1068 if($eject == 1 or $loop >= 1
1069 or $overwrite eq "e" and $answer eq "next") {
1070 my $ejectopt = $cddev if($ejectopt eq '{cddev}');
1071 $ejectopt = $ejectopt . " eject" if($ejectcmd =~ /cdcontrol/);
1072 log_system("$ejectcmd $ejectopt");
1075 return if($answer eq "next" or $answer eq "unknown");
1080 if (not defined $pid) {
1081 print "\nResources not avilable, will quit.\n";
1084 finish_process($pid);
1087 # Child: restart process.
1089 # Problem: being recursive, we won't come back! Hello zombie.
1096 $loop = 0 if($loop == 2);
1100 ########################################################################
1104 ########################################################################
1106 # New options step 9: Add new code as a subroutine somewhere below,
1107 # the very end might be appropriate.
1109 ########################################################################
1111 # Check local .cddb directory for cddb files with album, artist, discID
1115 # Get cddbid and number of tracks of CD.
1117 ($cddbid, $trackno) = get_cddbid();
1119 my ($artist, $album);
1139 print "\nChecking for a local DB entry, please wait...\n\n"
1141 log_system("mkdir -m 0755 -p $homedir/.cddb")
1142 or print "Can not create directory $homedir/.cddb: $!\n";
1143 opendir(CDDB, "$homedir/.cddb/")
1144 or print "Can not read in $homedir/.cddb: $!\n";
1145 @categs = grep(/\w/i, readdir(CDDB));
1149 if(-d "$homedir/.cddb/$_") {
1150 opendir(CATEG, "$homedir/.cddb/$_")
1151 or print "Can not read in $homedir/.cddb: $!\n";
1152 my @entries = grep(/$cddbid$/, readdir(CATEG));
1154 push @cddbid, $_ if($entries[0]);
1156 elsif(-f "$homedir/.cddb/$_" && -s "$homedir/.cddb/$_") {
1157 push @cddbid, $_ if($_ =~ /$cddbid/);
1163 print "Found local entry $cddbid in $homedir/.cddb !\n"
1164 if($interaction == 1);
1165 print "This CD could be:\n\n" if($interaction == 1);
1167 my $openflag = "no";
1168 if(-s "$homedir/.cddb/$_/$cddbid") {
1169 open(LOG, "$homedir/.cddb/$_/$cddbid");
1171 $dirflag[$count-1] = 1;
1173 elsif(-s "$homedir/.cddb/$cddbid") {
1174 open(LOG, "$homedir/.cddb/$cddbid");
1175 $_ = "no category found!";
1177 $dirflag[$count-1] = 0;
1179 if($openflag eq "ok") {
1180 my @loglines = <LOG>;
1182 # Here we should test if @loglines is a good entry!
1183 # If there are empty files, we get warnings!
1184 chomp(my $artist = join(' ', grep(s/^DTITLE=//, @loglines)));
1185 $artist = clean_all($artist);
1186 chomp(my $agenre = join(' ', grep(s/^DGENRE=//, @loglines)));
1187 $agenre =~ s/[\015]//g;
1188 $agenre = "none" unless($agenre);
1189 print "$count: $artist (genre: $agenre, category: $_)\n"
1190 if($interaction == 1);
1195 print "\n0: Search online DB instead.\n"
1196 if($interaction == 1);
1197 if($interaction == 0) {
1201 while($usearch !~ /\d/ || $usearch >= $count) {
1202 print "\nChoose: (1) ";
1205 $usearch = 1 if($usearch eq "");
1211 get_cdinfo() if($mb == 0);
1212 get_mb() if($mb == 1);
1217 # We use "musicbrainz" as key when reading entry if coming from
1218 # MB section (below). So if we have a ~/.cddb/musicbrainz
1219 # directory this will give problems, use word "archive" for the
1220 # category name instead.
1221 my $ctg = $cddbid[$usearch-1];
1222 $ctg = "archive" if($ctg =~ /musicbrainz/);
1223 if($dirflag[$usearch-1] == 1) {
1224 read_entry("$homedir/.cddb/$cddbid[$usearch-1]/$cddbid",
1227 elsif($dirflag[$usearch-1] == 0) {
1228 read_entry("$homedir/.cddb/$cddbid", $ctg, $trackno);
1230 $categ = $cd{cat} = $cddbid[$usearch-1];
1233 get_cdinfo() if($mb == 0);
1234 get_mb() if($mb == 1);
1239 open(DISCID, "discid $scsi_cddev|");
1240 my @response = <DISCID>;
1242 chomp($cd{discid} = join("", grep(s/^DiscID\s*:\s//, @response)));
1243 # Fill up the track->id array in case we want to submit ISRCs, but
1244 # only if ripit found one single match.
1246 my $ws = WebService::MusicBrainz::Release->new();
1247 my $result = $ws->search({ DISCID => $cd{discid} });
1248 my @releases = @{$result->release_list->releases};
1249 if(scalar(@releases) == 1) {
1250 my $release = $releases[0];
1251 my @tracks = @{$release->track_list->tracks};
1252 for(my $i = 0; $i < scalar(@tracks); $i++) {
1253 my $track = $tracks[$i];
1254 push(@idata, $track->id);
1260 ########################################################################
1262 # Read the album, artist, discID and track titles from the get_CDDB()
1263 # generated TOC file.
1266 my $writecddb = shift; # Passed when calling this sub from get_mb.
1267 $writecddb = 0 unless($writecddb);
1269 # Get cddbid and number of tracks of CD.
1271 ($cddbid, $trackno) = get_cddbid();
1273 my ($artist, $album, %config, $revision);
1274 my ($CDDB_INPUT, $CDDB_MODE, $CDDB_PORT);
1291 #Configure CDDB_get parameters
1292 if($CDDB_HOST eq "freedb2.org") {
1293 $config{CDDB_HOST} = $CDDB_HOST;
1295 elsif($CDDB_HOST eq "musicbrainz.org") {
1296 $config{CDDB_HOST} = "freedb." . $CDDB_HOST;
1299 $config{CDDB_HOST} = $mirror . "." . $CDDB_HOST;
1301 while($transfer !~ /^cddb$|^http$/) {
1302 print "Transfer mode not valid!\n";
1303 print "Enter cddb or http : ";
1304 $transfer = <STDIN>;
1307 if($transfer eq "cddb") {
1309 $CDDB_MODE = "cddb";
1311 elsif($transfer eq "http") {
1313 $CDDB_MODE = "http";
1315 $config{CDDB_MODE} = $CDDB_MODE;
1316 $config{CDDB_PORT} = $CDDB_PORT;
1317 $config{CD_DEVICE} = $scsi_cddev;
1318 $config{HTTP_PROXY}= $proxy if($proxy);
1319 if($interaction == 0) {
1325 $config{input} = $CDDB_INPUT;
1326 $config{PROTO_VERSION} = $proto;
1328 # Change to whatever, but be aware to enter exactly 4 words!
1329 # E.g. username hostname clientname version
1330 my $hid = "RipIT www.suwald.com/ripit/ripit.html RipIT $version";
1331 my @hid = split(/ /, $hid);
1333 print "There are more than 4 words in the \"HELLO_ID\"!\n",
1334 "The handshake with the freeDB-server will fail!\n\n";
1336 $config{HELLO_ID} = $hid;
1338 print "\nChecking for a DB entry \@ $config{CDDB_HOST}...\n"
1339 if($verbose >= 1 && $writecddb != 0);
1340 eval {%cd = get_cddb(\%config);};
1342 $@ =~ s/db:\s/db:\n/;
1343 $@ =~ s/at\s\//at\n\//;
1344 print "No connection to internet? The error message is:\n",
1345 "$@\n" if($verbose >= 1);
1349 # Thanks to Frank Sundermeyer
1350 # If wanting to write the CDDB data (archive=1) but having set
1351 # interaction=0, the CDDB data will not get modified, so it
1352 # is safe to write it now.
1353 # But this routine is also called from get_mb (for getting a genre)
1354 # with $interaction temporarily set to 0. We call it with a parameter
1355 # set to zero (0) when calling it from get_mb. This parameter is
1356 # saved to $writecddb. Therefore do not write the entry if
1359 if($interaction == 0 && $archive == 1 && defined $cd{title}) {
1360 write_cddb() unless $writecddb == 0;
1364 my $cddevno = $cddev;
1365 $cddevno =~ s/\/dev\///;
1366 $cddevno =~ s/(\d)/0$1/ unless($cddevno =~ /\d\d/);
1367 $logfile = $outputdir . "/" . $cddevno;
1368 read_entry($logfile, "multi");
1371 ########################################################################
1373 # Read the album, artist, discID and track titles from MusicBrainz.
1377 print "Querying MusicBrainz DB." if($verbose > 2);
1378 my ($cddbid, $trackno, $totaltime) = get_cddbid();
1381 # Using the perl module to retrieve the MB discid.
1385 eval{ $disc = new MusicBrainz::DiscID($scsi_cddev);};
1387 # Use the libdiscid command discid to retrieve the MB discid.
1388 open(DISCID, "discid $scsi_cddev|");
1389 my @response = <DISCID>;
1391 chomp($discid = join("", grep(s/^DiscID\s*:\s//, @response)));
1392 chomp($submit_url = join("", grep(s/^Submit\svia\s*:\s//, @response)));
1395 if($disc->read() == 0) {
1396 print "Error: %s\n", $disc->error_msg();
1400 $discid = $disc->id();
1401 $submit_url = $disc->submission_url();
1404 # Get the xml contents of that file, parse the MB-ID and do another
1405 # lookup at http://musicbrainz.org/ws/1/release/MBID, parse this data
1406 # again and you're done.
1408 print "\nChecking for a DB entry \@ MusicBrainz.org...\n"
1411 eval {$service = WebService::MusicBrainz::Release->new();};
1412 my $discid_response;
1413 eval {$discid_response = $service->search({ DISCID => $discid });};
1415 print "\nMusicBrainz lookup failed... 2nd try in 3s.",
1416 "\nError message is: $@.\n" if($verbose > 3);
1418 eval {$discid_response = $service->search({ DISCID => $discid });};
1420 print "\nMusicBrainz lookup failed! Using freedb instead.",
1421 "\nError message is: $@.\n" if($verbose > 3);
1427 print "DiscID retrieved.\n" if($verbose > 4);
1428 print "Discid is: $discid.\n" if($verbose > 3);
1430 # Print the data for further queries.
1432 # print Dumper($discid_response);
1433 # print "*" x 72, "\n\n";
1437 eval {$mbid = $discid_response->release()->id();};
1439 print "\nMusicBrainz does not know this discid! Use\n",
1440 "$submit_url for submission!\n" if($verbose > 1);
1444 # This should not happen.
1445 elsif($mbid eq "") {
1446 print "\nNo discid $discid found at MusicBrainz! Use\n",
1447 "$submit_url for submission!\n" if($verbose > 1);
1451 eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'artist' });};
1453 print "\nMusicBrainz artist lookup failed... 2nd try in 3s.",
1454 "\nError message is: $@.\n" if($verbose > 3);
1456 eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'artist' });};
1458 print "\nMusicBrainz lookup artist failed!",
1459 "\nUsing freedb instead.",
1460 "\nError message is: $@.\n" if($verbose > 3);
1466 print "MB artist retrieved.\n" if($verbose > 4);
1469 my $release = $mbid_response->release();
1470 my $artist = $release->artist()->name();
1471 my $album = $release->title();
1472 my $asin = $release->asin();
1473 my $language = $release->text_rep_language();
1474 $artist =~ s/^The\s+// unless($artist =~ /^The\sThe/);
1475 $language = "English" unless($language);
1476 $language = "English" if($language eq "ENG");
1477 $language = "French" if($language eq "FRA");
1478 $language = "German" if($language eq "DEU");
1480 # Retrieve the year and barcode:
1481 eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'release-events' });};
1483 print "\nMusicBrainz lookup failed... 2nd try in 3s:\n" if($verbose > 3);
1485 eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'release-events' });};
1487 print "\nMusicBrainz lookup failed! Using freedb instead.\n"
1494 print "MB release eventrs retrieved.\n" if($verbose > 4);
1496 $release = $mbid_response->release();
1497 my $content = $release->release_event_list();
1498 my $reldate = ${$content->events()}[0]->date() if($content);
1499 my $barcode = ${$content->events()}[0]->barcode() if($content);
1501 $year =~ s/-.*$// if($year);
1503 # Some people insist in getting a genre, but MB does not supply one.
1505 my $save_inter = $interaction;
1507 print "Retrieving a genre from freedb.org.\n" if($verbose > 2);
1509 $interaction = $save_inter;
1510 $genre = $cd{genre};
1511 $year = $cd{year} unless($year);
1514 # Why this? Actually, I don't know. Thought that in the 21st
1515 # century there should be no UTF-8 problem anymore... But getting
1516 # e.g. tracknames with pure ascii in one track, latin chars in an
1517 # other track and even true wide chars in a third one will totally
1518 # mess up encoder tags and even the file names used by the ripper.
1519 my $temp_file = "/tmp/ripit-MB-$$\.txt";
1520 open(TMP, '>:utf8', "$temp_file") or print "$temp_file $!";
1521 print TMP "artist: $artist\n";
1522 print TMP "album: $album\n";
1523 print TMP "genre: $genre\n" if($genre);
1524 print TMP "category: musicbrainz\n";
1525 print TMP "cddbid: $cddbid\n";
1526 print TMP "discid: $discid\n";
1527 print TMP "asin: $asin\n" if($asin);
1528 print TMP "year: $year\n" if($year);
1529 print TMP "trackno: $trackno\n";
1530 print TMP "language: $language\n";
1531 print TMP "reldate: $reldate\n" if($reldate);
1532 print TMP "barcode: $barcode\n" if($barcode);
1535 # figure out number of disks and possible track offset
1537 my $ua = LWP::UserAgent->new();
1539 $ua->agent("ripit/$version");
1540 my $response = $ua->get("http://musicbrainz.org/ws/2/release/$mbid?inc=media+discids");
1542 my $xml = XMLin($response->content());
1543 if ($xml->{release}{'medium-list'}{count} > 1) {
1544 for my $medium (@{$xml->{release}{'medium-list'}{medium}}) {
1545 if (exists $medium->{'disc-list'}{disc}{$discid} or
1546 exists $medium->{'disc-list'}{disc}{id} and
1547 $medium->{'disc-list'}{disc}{id} eq $discid) {
1550 $trackoffset += $medium->{'track-list'}{count};
1554 print STDERR $trackoffset."\n";
1555 print STDERR "discid $discid\n";
1558 # Retrieve the track list.
1559 eval {$mbid_response = $service->search({ DISCID => $discid, INC => 'tracks' });};
1561 print "\nMusicBrainz lookup failed... [$@] 2nd try in 3s:\n";# if($verbose > 3);
1563 eval {$mbid_response = $service->search({ DISCID => $discid, INC => 'tracks' });};
1565 print "\nMusicBrainz lookup failed! Using freedb instead.\n"
1568 unlink("$temp_file");
1574 print "MB track list retrieved.\n" if($verbose > 4);
1576 $release = $mbid_response->release();
1577 my $track_list = $release->track_list();
1578 my $mb_trackno = $#{$track_list->tracks()} + 1;
1582 foreach my $track (@{$track_list->tracks()}) {
1583 $_ = $track->title();
1584 # Various artist style
1585 if($track->artist) {
1586 print TMP "track $i: ", $track->artist->name(), " / $_\n";
1590 # Normal tracklist style.
1592 print TMP "track $i: $_\n";
1594 # For ISRC detection/submission use the track IDs.
1595 push(@idata, $track->id);
1601 # MusicBrainz does not state data tracks. Let's continue to fill up
1602 # the tracklist in the %cd-hash.
1603 while($i <= ($trackno)) {
1604 print TMP "track $i: data\n";
1609 read_entry("$temp_file", "musicbrainz", $trackno);
1610 unlink("$temp_file");
1612 ########################################################################
1614 # Display CDDB info.
1619 my $utf_latinflag = 0;
1620 my $utf_wideflag = 0;
1621 my ($artist, $album, %config, $revision);
1624 CDDB_get->import( qw( get_cddb get_discids ) );
1625 my $cd = get_discids($scsi_cddev);
1626 my ($id, $trackno, $toc) = ($cd->[0], $cd->[1], $cd->[2]);
1627 my $cddbid = sprintf("%08x", $id);
1628 my $totaltime = sprintf("%02d:%02d",$toc->[$trackno]->{min},$toc->[$trackno]->{sec});
1630 if(defined $cd{title}) {
1631 $album = clean_all($cd{title});
1632 $artist = clean_all($cd{artist});
1633 # Remember: use of lowercase was supposed for file names only,
1634 # tags should not be lowercase (what for?). But option
1635 # ucfirst is useful if DB entry is in uppercase only, and tags
1636 # in uppercase are rather ugly.
1637 $album = change_case($cd{title}) if($uppercasefirst == 1);
1638 $artist = change_case($cd{artist}) if($uppercasefirst == 1);
1641 # Set the year if it wasn't passed on command line.
1643 $year = $cd{year} if($cd{year});
1644 $year =~ s/[\015]//g if($year);
1647 # Set the genre if it wasn't passed on command line.
1648 if(!defined $pgenre && defined $cd{genre}) {
1649 $genre = $cd{genre};
1650 $genre =~ s/[\015]//g if($genre);
1653 @comment = extract_comm;
1654 $revision = get_rev() unless($cd{discid});
1655 # In case of corrupted (local) DB files.
1656 $revision = "unknown" unless($revision);
1659 if($submission == 0) {
1660 print "\nNo CDDB info chosen or found for this CD\n"
1663 # Set submission OK, will be set to 0 if default names are used.
1664 $cddbsubmission = 1;
1665 # Don't ask for default settings, use them ...
1666 if($interaction == 0) {
1669 # ... or ask whether 1) default or 2) manual entries shall be used
1674 $album = $cd{title};
1675 $artist = $cd{artist};
1676 $revision = $cd{revision};
1680 # We do nothing anymore because we read the data from a file.
1683 # The strings from archive files should be OK, because the files
1684 # should be written in the corresponding encoding. Only strings
1685 # from CDDB_get must be treated.
1686 # But still, this gives the error:
1687 # Cannot decode string with wide characters at
1688 # /usr/lib/perl5/5.8.8/i586-linux-threads-multi/Encode.pm line 186.
1689 # So do it here to be sure to analyze manually entered data!
1691 # Create a string with the DB data to be analyzed for true UTF-8
1692 # (wide) characters.
1693 my $char_string = $cd{title} . $cd{artist};
1694 $char_string .= $_ foreach (@{$cd{track}});
1696 ($latinflag, $wideflag, $utf_latinflag, $utf_wideflag) =
1697 check_encoding($char_string);
1699 if($utf_latinflag >= $latinflag * 3 && $utf_wideflag == 0 && $wideflag == 0) {
1700 print "\nRare case: Decoding from iso 8859-1 to utf-8?\n"
1702 Encode::from_to($artist, 'iso-8859-1', 'UTF-8');
1703 Encode::from_to($album, 'iso-8859-1', 'UTF-8');
1705 elsif($wideflag == 0 && $latinflag == 0) {
1706 print "No wide char found, artist is <$artist>.\n"
1708 print "No latin char found, artist is <$artist>.\n"
1709 if($verbose >= 5 && $latinflag == 0);
1710 $album = UTF8_encoding($album);
1711 $artist = UTF8_encoding($artist);
1713 elsif($utf_wideflag == 1 && $wideflag == 0) {
1714 print "\nForcing UTF8 case 1:\n"
1716 $album = Encode::decode('UTF-8', $album);
1717 $artist = Encode::decode('UTF-8', $artist);
1719 elsif($utf_latinflag % 2 == 0 && $latinflag % 2 == 0 && $utf_wideflag == 0 && $wideflag == 0) {
1720 print "\nTrying to force UTF8 case 2: source might be utf8!\n"
1722 # Keep it commented for the archive and online Rƶyksopp case.
1723 # $album = Encode::decode('UTF-8', $album);
1724 # $artist = Encode::decode('UTF-8', $artist);
1726 elsif($utf_wideflag > 0 && $wideflag >= 0) {
1727 print "\nTrying to force UTF8 case 3: source might be utf8!\n"
1729 # Keep it commented for the clean archive Enya case.
1730 # $album = Encode::decode('UTF-8', $album);
1731 # $artist = Encode::decode('UTF-8', $artist);
1734 print "\nDon't know what to do. Is it cp-1252 or iso 8859-1?\n"
1740 # Resetting the album and artist in the %cd-hash will screw up all the
1741 # track titles (e.g. Bang Bang). Can you believe it? Change album and
1742 # artist and tracknames will blow up. That's life, that's Perl.
1743 # Again: we need a save copy of the string as it is now! What is wrong
1744 # changing an entry of a hash? Why are all other entries of that
1747 $album_utf8 = $album;
1748 $artist_utf8 = $artist;
1751 if($genre eq "" && $interaction == 1) {
1752 print "\nPlease enter a valid CDDB genre (or none): ";
1755 $cd{genre} = $genre;
1758 $genre =~ s/[\015]//g;
1759 ($genre,$genreno) = check_genre($genre);
1763 print "\n", "-" x 17, "\nCDDB and tag Info", "\n", "-" x 17, "\n";
1764 print "Artist: $artist_utf8\n";
1765 print "Album: $album_utf8\n";
1766 print "Category: $categ\n" if($verbose >= 2);
1768 print "ID3-Genre: $genre ($genreno)\n" if($lameflag >= 0);
1769 print "Genre-tag: $genre\n" if($lameflag == -1);
1770 if(lc($genre) ne lc($cd{'genre'})) {
1771 print "CDDB-Genre: $cd{genre}\n";
1775 print "ID3-Genre: none\n";
1777 print "ASIN: $cd{asin}\n" if($cd{asin});
1778 print "Barcode: $cd{barcode}\n" if($cd{barcode});
1779 print "Language: $cd{language}\n" if($cd{language});
1780 print "Release date: $cd{reldate}\n" if($cd{reldate});
1781 print "Year: $year\n" if($year);
1782 print "Revision: $revision\n" if($verbose >= 2);
1783 # It happens, that the ID from CDDB is NOT identical to the ID
1784 # calculated from the frames of the inserted CD...
1785 if($cddbid ne $cd{id} && defined $cd{id} ) {
1786 print "CDDB id: $cd{id}\n";
1788 print "CD id: $cddbid\n";
1789 print "Discid: $cd{discid}\n" if($cd{discid});
1790 if(@comment && $verbose >= 2) {
1791 foreach (@comment) {
1792 print "Comment: $_\n" if($_);
1795 print "CD length: $totaltime\n";
1798 log_info("\nArtist: $artist");
1799 log_info("Album: $album");
1800 log_info("ID3-Genre: $genre ($genreno)") if($genre);
1801 log_info("ID3-Genre: none") unless($genre);
1802 log_info("Category: $categ");
1803 log_info("ASIN: $cd{asin}") if($cd{asin});
1804 log_info("CD id: $cddbid");
1805 log_info("MB id: $cd{discid}") if($cd{discid} && $cd{discid} ne $cddbid);
1806 log_info("CD length: $totaltime\n");
1808 # Read out pregap before calculating track lengths.
1809 my $frames = $toc->[0]->{'frames'};
1810 push @framelist, "$frames";
1812 my $second = int($frames/75);
1813 my $frame = $frames - $second * 75;
1814 my $minute = int($second/60);
1815 $second -= $minute * 60;
1816 printf("%s %02d:%02d %s %d %s\n",
1817 "There might be a hidden track", $minute, $second,
1818 "long,\nbecause offset of track 01 has", $frames,
1819 "frames\nintstead of typically 150 (equals 2 seconds).\n")
1821 my $riptrackname = "Hidden Track";
1822 $riptrackname = change_case($riptrackname);
1823 $riptrackname =~ s/ /_/g if($underscore == 1);
1824 printf("%s: [%02d:%02d.%02d] %s\n",
1825 "00", $minute, $second, $frame, $riptrackname)
1827 $second = int($frames/75);
1828 $hiddenflag = 1 if($trackselection eq ""
1829 || $trackselection =~ /^0/
1830 || $trackselection =~ /\D0/);
1831 # We can't add this track to seltrack and framelist, because this
1832 # would break (re-) submission of CDDB.
1833 # Note: seltrack is not yet defined... But we start to fill the
1834 # @secondlist array (yet empty) with track lengths in seconds.
1835 # TODO: push the pregap seconds to the list in any case, then we
1836 # don't need to differentiate between the case hiddenflag == 1 or
1837 # hiddenflag == 0 while choosing tracknames.
1838 push @secondlist, "$second" if($hiddenflag == 1);
1841 # Print track information.
1842 foreach (@{$cd{track}}) {
1844 $_ = change_case($_) if($uppercasefirst == 1);
1847 # We do nothing anymore because we read the data from a file.
1850 if($utf_latinflag >= $latinflag * 3 && $utf_wideflag == 0 && $wideflag == 0) {
1851 Encode::from_to($_, 'iso-8859-1', 'UTF-8');
1853 elsif($latinflag == 0 && $wideflag == 0) {
1854 $_ = UTF8_encoding($_);
1856 elsif($utf_wideflag == 1 && $wideflag == 0) {
1857 $_ = Encode::decode('UTF-8', $_);
1860 push @tracktags, $_;
1862 # Get frames and total time.
1863 my $frames = $toc->[$n]->{'frames'};
1864 push @framelist, "$frames";
1865 $frames = $frames - $framelist[$n - 1];
1866 my $second = int($frames / 75);
1867 push @secondlist, "$second";
1868 my $frame = $frames - $second * 75;
1869 my $minute = int($second / 60);
1870 $second -= $minute * 60;
1871 $_ = clean_chars($_) if($chars);
1872 printf("%02d: [%02d:%02d.%02d] %s\n",
1873 $n + $trackoffset, $minute, $second, $frame, $_)
1875 $_ = clean_name($_);
1876 $_ = change_case($_);
1877 $_ =~ s/ /_/g if($underscore == 1);
1878 push @tracklist, $_;
1881 print "\n\n" if($verbose >= 1);
1883 # Some more error checking.
1885 die "Error: No artist found!\n";
1887 unless($tracklist[0]) {
1888 die "Error: No tracks found!\n";
1891 get_isrcs if($isrc == 1 && $mb == 1);
1895 $lcdline1 = $artist . "-" . $album;
1896 $lcdline2 = "R00|00.0%|----------";
1897 $lcdline3 = "E00|00.0%|----------";
1901 ########################################################################
1903 # Create the track selection from the parameters passed on the command-
1904 # line, i. e. create an array with all track numbers including those not
1905 # explicitly stated at the command line.
1907 sub create_seltrack {
1908 my($tempstr,$intrack);
1911 die "Invalid track selection \"-\"!\n\n";
1914 if(($tempstr =~ /,/) || ($tempstr =~ /\-/)) {
1915 my @intrack = split(/,/ , $tempstr);
1916 # If last character is a , add an other item with a -
1917 if($tempstr =~ /,$/) {
1918 push @intrack, ($intrack[$#intrack]+1) . "-";
1920 foreach $intrack (@intrack) {
1921 if($intrack =~ /\-/) {
1922 my @outrack = split(/-/ , $intrack);
1923 # If last character is a -, add last track to $outrack
1924 if($#outrack == 0) {
1925 $outrack[1] = $#tracklist + 1;
1926 if($outrack[0] > ($#tracklist + 1)) {
1927 die "Track selection higher than number of tracks ",
1931 for(my $i = $outrack[0]; $i <= $outrack[1]; $i++) {
1936 push @seltrack, $intrack;
1940 elsif($tempstr eq '') {
1941 for(my $i = 1; $i <= ($#tracklist + 1); $i++) {
1942 $seltrack[$i - 1] = $i;
1945 elsif($tempstr =~ /^[0-9]*[0-9]$/) {
1946 $seltrack[0] = $tempstr;
1949 die "Track selection invalid!\n";
1952 @seltrack = sort {$a <=> $b} @seltrack;
1954 # Check the validity of the track selection.
1955 foreach (@seltrack) {
1956 if($_ > ($#tracklist + 1)) {
1957 die "Track selection higher than number of tracks on CD.\n\n";
1964 ########################################################################
1966 # Ask if CDDB submission shall be done. Either because one might change
1967 # some settings a last time before writing to directories and files (if
1968 # there was not DB entry and operator entered all by hand) or because
1969 # DB entry has some typos! Also x-check for VA-style and let operator
1970 # change settings according to metadata retrieved (in case interaction
1971 # is on) and finally submit ISRCs to MusicBrainz if login info available
1972 # and the ISRCs are OK.
1976 unless($cddbsubmission == 0 || $interaction == 0) {
1977 while($index !~ /^[0-1]$/) {
1978 print "\nDo you want to edit or submit the CDDB entry?";
1979 print "\nTo confirm each question type Enter.\n\n";
1980 print "1: Yes, and I know about the naming-rules of ";
1981 print "freedb.org!\n\n";
1982 print "0: No\n\nChoose [0-1]: (0) ";
1991 my $revision = get_rev() unless($cd{discid});
1993 print "\nPlease change some settings.";
1994 print "\nYou may confirm CDDB settings with \"enter\".\n";
1998 print "\nPlease change some settings.";
1999 print "\nYou may confirm given settings with \"enter\".\n";
2003 elsif($index == 0) {
2005 # CDDB data does not get modified, write the existing data to
2006 # the local CDDB if wanted.
2007 if($archive == 1 && defined $cd{title}) {
2012 print "Choose 0 or 1!\n";
2019 # Once the metadata has been altered (optionally), check for
2021 # Delimeters to be checked for various artists style.
2022 my $delim_colon = 0;
2023 my $delim_hyphen = 0;
2024 my $delim_slash = 0;
2025 my $delim_parenthesis = 0;
2028 # We call check_va only to print detected results if verbosity is
2030 my $delim = check_va(1);
2031 if($interaction == 1) {
2033 while($index !~ /^[0-8]$/) {
2034 print "\nDo you want to change option --vatag to alter";
2035 print "\ndetection of compilation style?";
2036 print "\n\nChoose [0-8]: ($vatag) ";
2049 ########################################################################
2051 # Create the directory where the sound files shall go.
2052 # Directory created will be: /outputdir/$dirtemplate[$c] .
2053 # We first check the wavdir and set the counter $c for the encoder
2054 # depending arrays @sepdir, @suffix, @globopt to -1. In this way,
2055 # directory names will not be suffixed with a counter if they shall be
2056 # the same for wavs and encoded files (condition $soundir ne $wavdir and
2057 # the exception handling below).
2062 # Get cddbid and number of tracks of CD.
2064 ($cddbid, $trackno) = get_cddbid();
2066 foreach("wav", @coder) {
2067 my $suffix = $suffix[$c] if(defined $suffix[$c]);
2068 $suffix = "wav" if($_ eq "wav");
2069 my $quality = $globopt[$c] if(defined $globopt[$c]);
2070 $quality = "" if($_ eq "wav");
2072 # Why this? Remember, we have worked a lot with encoding of artist
2074 my $album = clean_all($album_utf8);
2075 my $artist = clean_all($artist_utf8);
2076 $album = clean_name($album);
2077 $artist = clean_name($artist);
2078 $album = clean_chars($album) if($chars);
2079 $artist = clean_chars($artist) if($chars);
2080 $artist = change_case($artist);
2081 $album = change_case($album);
2082 $album =~ s/ /_/g if($underscore == 1);
2083 $artist =~ s/ /_/g if($underscore == 1);
2085 # Define variable for initial letter of artist.
2086 my $iletter = $artist;
2087 $iletter =~ s/\s*(.).*/$1/;
2088 if($iletter =~ /\d/) {
2089 my @words = split(/ /, $artist);
2093 $iletter =~ s/\s*(.).*/$1/;
2094 last if($iletter =~ /\w{1}/);
2097 $iletter = "A" unless($iletter);
2098 $iletter = "\u$iletter" unless($lowercase == 1);
2100 # Take the last dirtemplate for missing ones and for wav.
2102 if($suffix eq "wav") {
2103 $dirindex = $#dirtemplate;
2105 elsif($c > $#dirtemplate) {
2106 $dirindex = $#dirtemplate;
2109 # Check and create the full path where the files will go.
2110 # Check the dirtemplate and use the actual year as default if
2111 # $year is in the template and none is given!
2112 if(($dirtemplate[$dirindex] =~ /\$year/ or
2113 $tracktemplate =~ /\$year/) && !$year) {
2114 $year = sprintf("%04d", sub {$_[5]+1900}->(localtime));
2116 # Do the same for the genre.
2117 if(($dirtemplate[$dirindex] =~ /\$genre/ or
2118 $tracktemplate =~ /\$genre/)) {
2119 $genre = "Other" if($genre eq "");
2124 if(!eval("\$dir = $dirtemplate[$dirindex]")) {
2125 die "Directory template incorrect, caused eval to fail: $!\n";
2128 $dir =~ s,\s-\s/,/,g; # Do this in any case, even if all chars are
2129 $dir =~ s,\s-\s$,,g; # allowed.
2130 $dir =~ s,\s+/,/,g; # Do this in any case, even if all chars are
2131 $dir =~ s,\s+, ,g; # allowed.
2132 $dir =~ s,\s-\s-\s*, ,g;
2133 # Change case again only if lowercase wanted! Else we will get
2134 # lower case of special dirtemplates like: $iletter/$artist: here
2135 # artist would be converted to lowercase, since we check for words!
2136 $dir = change_case($dir) if($lowercase == 1);
2137 $dir = clean_chars($dir) if($chars);
2138 $dir =~ s/ /_/g if($underscore == 1);
2140 $dir =~ s/\.+$// if($chars =~ /NTFS/);
2142 my $soundir = $outputdir . "/" . $dir if($outputdir !~ /\/$/);
2143 $soundir = $outputdir . $dir if($outputdir =~ /\/$/);
2144 # Check if the soundir already exists, if it does, try "soundir i"
2145 # with i an integer until it works, unless option resume is given.
2147 # TODO: What if two identical named discs shall be done, but with
2148 # different number of tracks (different track names will be too
2149 # difficult to distinguish!)? Maybe we should test here the number
2150 # of tracks in an existing directory with same name...
2151 # E.g. Nouvelle Vague: Bande Ć part, EU version, US version,
2152 # LTD. Ed, initial release version... all have the same name but
2153 # different track names/numbers.
2155 my $cdexistflag = 0;
2157 my $nsoundir = $soundir;
2159 while(defined(opendir(TESTDIR, $nsoundir)) &&
2160 $rip == 1 && $resume == 0 && $soundir ne $wavdir) {
2161 $sfx = " " . $i if($underscore == 0);
2162 $sfx = "_" . $i if($underscore == 1);
2163 $sfx = clean_chars($sfx) if($chars);
2164 $nsoundir = $soundir . $sfx;
2168 return "next" if($cdexistflag == 1 && $overwrite =~ /^e|q$/);
2169 return "unknown" if($artist =~ /unknown.artist/i && $album =~ /unknown.album/i && $quitnodb == 1);
2171 $nsoundir = $soundir if($overwrite eq "y");
2172 # Exception handling: if the $wavdir is identical to the
2173 # $nsoundir apart from a suffixed counter, use the $wavdir as
2174 # $soundir instead of the incremented $nsoundir!
2176 $nsoundir = $wavdir if($wavdir =~ /$soundir.\d+/);
2178 if($multi == 1 && $_ eq "wav") {
2179 if($overwrite =~ /^y$/) {
2183 my $aadir = $dir . $sfx;
2184 if($cdexistflag == 1) {
2186 open(SRXY,"$logfile") or
2187 print "Can not open \"$logfile\"!\n";
2188 my @srxylines = <SRXY>;
2190 chomp(my $orig_album = join(' ', grep(/^album:\s/, @srxylines)));
2191 grep(s/^album:\s(.*)$/album: $1 $i/, @srxylines)
2192 if($underscore == 0);
2193 grep(s/^album:\s(.*)$/album: $1_$i/, @srxylines)
2194 if($underscore == 1);
2195 open(SRXY,">$logfile")
2196 or print "Can not write to file \"$logfile\"!\n";
2197 print SRXY @srxylines;
2198 print SRXY "Original-$orig_album\n";
2201 open(SRXY,">>$logfile")
2202 or print "Can not append to file \"$logfile\"!\n";
2203 print SRXY "\n\nArtist - Album:$aadir";
2206 $soundir = $nsoundir;
2207 $soundir =~ s;/$;;g;
2209 # Problem: multi level directory creation should set permission to
2210 # each directory level. I thought the easiest way would be to
2211 # alter permissions using umask and then set it back. I did not
2214 # Save machines umask for reset.
2215 my $umask = umask();
2217 # Get the default permission mode.
2218 my $dperm = sprintf("%04o", 0777 & ~umask());
2220 if(!opendir(TESTDIR, $soundir)) {
2221 # Explicitly log soundir creation.
2222 log_info("new-mediadir: $soundir");
2224 # The so called Holzhacker-Method: create dir level by level.
2225 # TODO: Let me know the good way to do it, thanks.
2226 my $growing_dir = "";
2227 foreach (split(/\//, $soundir)) {
2229 # Should we allow relative paths?
2230 if($_ =~ /^\.{1,2}$/ && $growing_dir eq "") {
2231 $growing_dir .= "$_";
2234 $growing_dir .= "/$_";
2236 $growing_dir =~ s;//;/;g;
2237 if(!opendir(TESTDIR, $growing_dir)) {
2238 log_system("mkdir -m $dpermission -p \"$growing_dir\"");
2239 if (! -d "$growing_dir") {
2240 print "\nWill try to trim length of directory.\n" if($verbose > 4);
2241 while(length($_) > 250) {
2245 # Again problems with umask... not comprehensive.
2246 # eval { mkpath($growing_dir, {mode => $dpermission,}) };
2247 # Actually, why should I use mkpath if it is not
2248 # recommended to be used with eval...
2250 #eval { mkpath($growing_dir) };
2252 # die "\nRelease directory $growing_dir creation failed : $!\n\n";
2254 log_system("mkdir -m $dpermission -p \"$growing_dir\"")
2255 or die "Can not create directory $growing_dir: $!\n";
2260 # In case $growing_dir needed to be shorten.
2261 $soundir = $growing_dir;
2262 # Do it again for security reasons.
2263 log_system("mkdir -m $dpermission -p \"$soundir\"")
2264 or die "Can not create directory $soundir: $!\n";
2271 #umask($umask) if defined $umask;
2273 $sepdir[$c] = $soundir unless($_ eq "wav");
2274 $wavdir = $soundir if($_ eq "wav");
2277 # This might not be the best place to set up the pre- and exe-
2278 # command and the coverpath but this is where most variables are
2279 # available. The same goes for the copycover variable.
2280 if($execmd && $suffix eq "wav") {
2282 if(!eval("\$exec = $execmd")) {
2283 print "execmd incorrect, caused eval to fail: $!\n";
2287 if($precmd && $suffix eq "wav") {
2289 if(!eval("\$prec = $precmd")) {
2290 print "precmd incorrect, caused eval to fail: $!\n";
2294 if($coverpath && $suffix eq "wav") {
2296 if(!eval("\$covp = $coverpath")) {
2297 print "coverpath incorrect, caused eval to fail: $!\n";
2301 if($copycover && $suffix eq "wav") {
2303 if(!eval("\$copy = $copycover")) {
2304 print "copycover path incorrect, caused eval to fail: $!\n";
2311 ########################################################################
2313 # Create the full-path track file name from the tracktemplate variable.
2316 my($trnum, $trname, $riptrname, $shortflag);
2318 ($trnum, $trname, $shortflag) = @_;
2319 $shortflag = 0 unless($shortflag);
2321 my $album = clean_all($album_utf8);
2322 my $artist = clean_all($artist_utf8);
2323 $album = clean_name($album);
2324 $artist = clean_name($artist);
2325 $album = clean_chars($album) if($chars);
2326 $artist = clean_chars($artist) if($chars);
2327 $album =~ s/ /_/g if($underscore == 1);
2328 $artist =~ s/ /_/g if($underscore == 1);
2329 # Create the full file name from the track template, unless
2330 # the disk is unknown.
2331 if($trname =~ /short/ && $shortflag =~ /short/) {
2332 $riptrname = $trname;
2334 elsif(defined $cd{title}) {
2335 # We do not need to lowercase the tracktemplate because all
2336 # variables are already lowercase!
2337 $tracktemplate =~ s/ /\\_/g if($underscore == 1);
2338 # We have to update tracknum and trackname because they're
2339 # evaluated by the tracktemplate!
2340 my $tracknum = sprintf("%02d", $trnum + $trackoffset);
2341 my $trackname = $trname;
2342 if(!eval("\$riptrname = $tracktemplate")) {
2343 die "\nTrack Template incorrect, caused eval to fail: $!.\n";
2347 $trname = change_case($trname);
2348 $trname =~ s/ /_/g if($underscore == 1);
2349 $riptrname = $trname;
2352 if($limit_flag == 255) {
2353 $riptrname = substr($riptrname, 0, 250);
2356 # No counters if option book or cdcue is used:
2357 if($book == 1 or $cdcue > 0) {
2358 $riptrname =~ s/^\d+[\s|_]// if($tracktemplate =~ /^\$tracknum/);
2362 ########################################################################
2367 my($ripcom, $riptrackname, $riptracktag);
2370 my $resumerip = $resume;
2374 my $albumtag = clean_all($album_utf8);
2375 my $artistag = clean_all($artist_utf8);
2376 my $album = $albumtag;
2377 $album = clean_name($album);
2378 my $artist = $artistag;
2379 $artist = clean_name($artist);
2380 $album = clean_chars($album) if($chars);
2381 $artist = clean_chars($artist) if($chars);
2382 $album =~ s/ /_/g if($underscore == 1);
2383 $artist =~ s/ /_/g if($underscore == 1);
2385 # Delete existing md5 files in case of resuming.
2386 if($md5sum == 1 && $resume == 1) {
2388 my @paths = split(/\//, $wavdir);
2389 my $md5file = $paths[$#paths] . " - wav" . ".md5";
2390 $md5file =~ s/ /_/g if($underscore == 1);
2391 unlink("$wavdir/$md5file");
2393 for(my $c = 0; $c <= $#coder; $c++) {
2394 my @paths = split(/\//, $sepdir[$c]);
2395 my $md5file = $paths[$#paths] . " - " . $suffix[$c] . ".md5";
2396 $md5file =~ s/ /_/g if($underscore == 1);
2397 unlink("$sepdir[$c]/$md5file");
2401 # Delete machine.lock files.
2403 opendir (DIR, "$wavdir") or print "Can't open $wavdir $!\n";
2404 my @lockfiles = grep(/\.lock_\d+$/, readdir(DIR));
2405 @lockfiles = grep(/\.lock$/, readdir(DIR)) unless($lockfiles[0]);
2407 unlink("$wavdir/$_") foreach (@lockfiles);
2410 # Define an array with intervals and the tracks to be skipped.
2414 # If hidden track supposed, try to merge it too in case operator
2415 # wants a book or a cdcue.
2416 $pmerge = "0-" if($hiddenflag == 1 && ($book == 1 || $cdcue == 2));
2417 @skip = skip_tracks;
2418 @merge = split(/,/, $pmerge);
2419 # If merge is used, we need to calculate the true track length for
2420 # the playlist file. And it would be nice, if the filename
2421 # reflects "missing" tracks. Define a string to concatenate the
2424 $concat =~ s/ /_/g if($underscore == 1);
2425 $concat = clean_chars($concat) if($chars);
2427 my @bea = split(/-|\+/, $_);
2428 my $beg = $bea[0] - 1;
2429 $beg = 0 if($beg < 0); # If nerds want to merge hidden tracks.
2430 while($bea[0] < $bea[1]) {
2431 $secondlist[$beg] += $secondlist[$bea[0]];
2432 # Don't merge all track names if option book or cdcue is used.
2433 $tracklist[$beg] = $tracklist[$beg] . $concat .
2434 $tracklist[$bea[0]] unless($book == 1 or $cdcue == 2);
2435 $tracktags[$beg] = $tracktags[$beg] . " + " .
2436 $tracktags[$bea[0]] unless($book == 1 or $cdcue == 2);
2442 # Display info which tracks are going to be ripped. Because of option
2443 # merge we have to work hard to make it look nice:
2444 @tracksel = @seltrack; # Use a copy of @seltrack to work with.
2445 my @printracks; # A new array in nice print format.
2448 # Add the hidden track to @tracksel if a nerd wants it to merge, i.e.
2449 # operator entered it in the merge argument.
2450 unshift(@tracksel, 0) if($pmerge && $pmerge =~ /^0/ && $hiddenflag == 1);
2451 foreach $trackcn (@tracksel) {
2452 next if($trackcn <= $prevtcn);
2454 # Check if next tracknumber is in the skip array of tracks being
2455 # merged. If so, add a hyphen.
2457 if($skip[0] && ($trackcn + $increment) =~ /^$skip[0]$/) {
2458 $trackno = $trackcn . "-";
2461 # Is the next tracknumber the last of the interval of merged
2462 # tracks? If not, continue to increase the tracknumber.
2463 while($skip[0] && ($trackcn + $increment) =~ /^$skip[0]$/) {
2467 $trackno = $trackno . $trackcn;
2468 $prevtcn = $trackcn;
2471 $trackno = $trackcn;
2473 push(@printracks, $trackno);
2476 if($#seltrack == 0 && $hiddenflag == 0) {
2477 print "Track @printracks will be ripped.\n\n" if($verbose > 0);
2479 elsif(!@seltrack && $hiddenflag == 1) {
2480 print "Track 0 will be ripped.\n\n" if($verbose > 0);
2482 elsif($pmerge && $pmerge =~ /^0/ && $hiddenflag == 1) {
2483 print "Tracks @printracks will be ripped.\n\n" if($verbose > 0);
2485 elsif($hiddenflag == 1) {
2486 print "Tracks 0 @printracks will be ripped.\n\n" if($verbose > 0);
2489 print "Tracks @printracks will be ripped.\n\n" if($verbose > 0);
2492 # Prevent failure if hald occupies drive.
2493 sleep 6 if($loop == 2);
2494 # Get the time when ripping started, and save it in the error.log.
2495 my $ripstart = sprintf("%02d:%02d", sub {$_[2], $_[1]}->(localtime));
2496 my $date = sprintf("%04d-%02d-%02d",
2497 sub {$_[5]+1900, $_[4]+1, $_[3]}->(localtime));
2498 open(ERO,">$wavdir/error.log")
2499 or print "Can not append to file \"$wavdir/error.log\"!\n";
2500 print ERO "Ripping started: $ripstart\n";
2503 open(SRXY,">>$logfile")
2504 or print "Can not append to file \"$logfile\"!\n";
2505 print SRXY "\nRipping started: $ripstart";
2511 my $cdtocartis = $artistag;
2512 oct_char($cdtocartis);
2513 my $cdtocalbum = $albumtag;
2514 oct_char($cdtocalbum);
2515 open(CDTOC ,">$wavdir/cd.toc")
2516 or print "Can not write to file \"$wavdir/cd.toc\"!\n";
2517 print CDTOC "CD_DA\n//Ripit $version cd.toc file generated ",
2518 "$date at $ripstart.",
2519 "\n//Use command >cdrdao scanbus< to detect device.",
2520 "\n//Assume the device found is: 1,0,0 : _NEC ",
2521 " then use e. g. command",
2522 "\n//>cdrdao write --device 1,0,0 ",
2523 "--speed 4 cd.toc< to burn the CD.",
2524 "\n//Note: Not all CD (DVD) burners are able to burn",
2525 " CD-text!\n//Test your device!";
2526 print CDTOC "\n\n//CD Text:\nCD_TEXT{LANGUAGE_MAP {0 : EN}\n\t";
2527 print CDTOC "LANGUAGE 0 {\n\t\tTITLE \"$cdtocalbum\"\n\t\t";
2528 print CDTOC "PERFORMER \"$cdtocartis\"\n";
2529 # print CDTOC "\t\tGENRE \"$genreno\"\n" if($genreno);
2530 print CDTOC "\t\tDISC_ID \"$cddbid\"\n\t}\n}\n";
2534 # Start to rip the hidden track if there's one: First check if
2535 # cdparanoia is available.
2537 unless(log_system("cdparanoia -V")) {
2538 print "Cdparanoia not installed? Can't rip the hidden track ";
2539 print "without cdparanoia!\n"
2540 if($hiddenflag == 1);
2545 # Check if the hidden track has been done in a previous session.
2546 my $checknextflag = 0;
2548 $riptrackname = "Hidden Track";
2549 $riptrackname = change_case($riptrackname);
2550 $riptrackname =~ s/ /_/g if($underscore == 1);
2551 $riptrackname = get_trackname(0, $riptrackname);
2552 if(-r "$wavdir/$riptrackname.rip") {
2553 unlink("$wavdir/$riptrackname.rip");
2554 print "Found $riptrackname.rip.\n" if($verbose >= 1);
2556 elsif(-r "$wavdir/$riptrackname.wav") {
2558 print "Found $riptrackname.wav.\n" if($verbose >= 1);
2559 md5_sum("$wavdir", "$riptrackname.wav", 0)
2560 if($md5sum == 1 && $wav == 1);
2563 for(my $c=0; $c<=$#coder; $c++) {
2564 if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
2566 print "Found file $riptrackname.$suffix[$c].\n";
2570 if($checknextflag == 1) {
2571 $riptrackname = "Hidden Track";
2572 unshift(@tracktags, $riptrackname);
2573 unshift(@seltrack, 0);
2574 unshift(@tracklist, $riptrackname);
2578 # Define some counters:
2579 # Because cdtoc is written in different subroutines, define a counter
2580 # for each track written into the toc file. This way, ghost songs are
2581 # sorted in the toc file, while they aren't in the @seltrack array.
2582 my $cdtocn = 0 + $trackoffset;
2584 # Write header of cue-file.
2586 open(CDCUE ,">$wavdir/cd.cue")
2587 or print "Can not write to file \"$wavdir/cd.cue\"!\n";
2588 print CDCUE "TITLE \"$albumtag\"\nPERFORMER \"$artistag\"\n",
2589 "FILE \"$wavdir/$album.wav\" WAVE\n";
2592 # Process a possible hidden (first) track.
2593 if($hiddenflag == 1 && $checknextflag == 0) {
2594 $riptrackname = "Hidden Track";
2595 unshift @tracktags, $riptrackname;
2596 my $cdtocname = $riptrackname;
2597 $riptrackname = change_case($riptrackname);
2598 $riptrackname =~ s/ /_/g if($underscore == 1);
2599 unshift @seltrack, 0;
2600 unshift @tracklist, $riptrackname;
2601 $riptrackname = get_trackname(0, $tracklist[0]);
2602 # If a cuefile shall be created, use album for the track name.
2603 $riptrackname = $album if($book == 1 or $cdcue == 2);
2604 my $start_point = "[00:00]";
2605 # What if the operator wants to merge a hidden track with the 1st
2606 # and so on tracks? Calculate the number of the last track to be
2607 # merged with the hidden track.
2610 my @bea = split(/-|\+/, $merge[0]);
2611 # Hm, always confused. Should we use defined here to enter the
2612 # condition in case $bea[0] is defined, but zero?
2613 #if($bea[0] && $bea[0] == 0) {
2614 if(defined $bea[0] && $bea[0] == 0) {
2615 $endtrackno = $bea[1];
2616 $endtrackno =~ s/^0.//;
2617 $endtrackno++ unless($endtrackno == $seltrack[$#seltrack]);
2618 $start_point .= "-$endtrackno";
2621 # Assemble the command for cdparanoia to rip the hidden track.
2622 my $saveripopt = $ripopt;
2623 $ripopt .= " -Z" if($parano == 0);
2624 $ripopt .= " -q" if($verbose <= 1 && $ripopt !~ /\s-q/);
2625 $ripcom = "cdparanoia $ripopt -d $cddev $start_point \\
2626 \"$wavdir/$riptrackname.rip\"";
2627 printf "\n%02d:%02d:%02d: ", sub {$_[2], $_[1], $_[0]}->(localtime)
2628 if($verbose >= 1 && $rip == 1);
2629 print "Ripping \"$riptrackname\"...\n"
2630 if($verbose >= 1 && $rip == 1);
2632 unless(log_system("$ripcom")) {
2634 $ripopt = $ripopt . " -Z" if($parano == 2);
2635 $ripcom = "cdparanoia $ripopt -d $cddev $start_point \\
2636 \"$wavdir/$riptrackname.rip\"";
2637 print "\n\nTrying again without paranoia.\n"
2639 unless(log_system("$ripcom")) {
2640 # If no success, shift the hidden track stuff out of
2650 # If no success, shift the hidden track stuff out of arrays.
2659 # Write to the toc file.
2660 if($cdtoc == 1 && $hiddenflag == 1) {
2661 open(CDTOC ,">>$wavdir/cd.toc")
2662 or print "Can not append to file \"$wavdir/cd.toc\"!\n";
2663 print CDTOC "\n//Track 0:\nTRACK AUDIO\nTWO_CHANNEL_AUDIO\n";
2664 print CDTOC "CD_TEXT {LANGUAGE 0 {\n\t\tTITLE \"$cdtocname\"";
2665 print CDTOC "\n\t\tPERFORMER \"$artistag\"\n\t}\n}\n";
2666 print CDTOC "FILE \"$riptrackname.wav\" 0\n";
2669 # Check the hidden track for gaps. We do not care about option
2670 # merge... should we? Yes, we should. If option merge has been
2671 # chosen for this track, splitting is not allowed, while
2672 # extracting one chunk of sound may be desired.
2674 if($ghost == 1 && $hiddenflag == 1) {
2675 @times = get_chunks(0, $riptrackname);
2676 unless($times[0] eq "blank") {
2677 (my $shorten, @times) =
2678 split_chunks(0, "$riptrackname", 0, @times);
2679 ($cdtocn, $cue_point) =
2680 rename_chunks(0, "$riptrackname", 0, $cue_point,
2681 $shorten, $artistag, $riptrackname, @times);
2684 if($hiddenflag == 1) {
2685 rename("$wavdir/$riptrackname.rip",
2686 "$wavdir/$riptrackname.wav");
2688 $ripopt = $saveripopt;
2691 # If ripping did not fail (on whatever track of the whole disc),
2692 # write the hidden track info to the cue file.
2693 if($cdcue == 2 && $hiddenflag == 1) {
2694 my $points = chapter_length($framelist[1] - $framelist[0]);
2695 $points =~ /\.\d+$/;
2696 open(CDCUE ,">>$wavdir/cd.cue")
2697 or print "Can not append to file \"$wavdir/cd.cue\"!\n";
2698 print CDCUE "TRACK 01 AUDIO\n",
2699 " TITLE \"Hidden Track\"\n",
2700 " PERFORMER \"$artistag\"\n",
2701 " INDEX 01 $points\n";
2704 # End preparation of ripping process.
2707 # Start ripping each track. Note that we have to skip a possible
2708 # hidden track. To prevent reripping ghost songs pushed into the
2709 # @seltrack array, make a copy which will not be altered.
2710 @tracksel = @seltrack;
2712 # Encoder messages are printed into a file which will be read by the
2713 # ripper to prevent splitting ripper-messages. Lines already printed
2714 # will not be printed again, use counter $encline.
2718 foreach (@tracksel) {
2719 next if($_ == 0); # Skip hidden track.
2721 $riptrackname = get_trackname($_, $tracklist[$_ - 1]);
2722 $riptrackname = get_trackname($_, $tracklist[$_])
2723 if($hiddenflag == 1);
2724 $riptrackname = $album if($book == 1 or $cdcue == 2);
2725 $riptracktag = $tracktags[$_ - 1];
2726 $riptracktag = $tracktags[$_] if($hiddenflag == 1);
2729 # Split the tracktag into its artist part and track part if
2730 # VA style is used, no messages to be printed.
2731 my $delim = check_va(0);
2732 $delim = quotemeta($delim);
2733 if($va_flag > 0 && $riptracktag =~ /$delim/) {
2735 if($vatag % 2 == 1) {
2736 ($artistag, $riptracktag) = split(/$delim/, $riptracktag);
2737 $riptracktag =~ s/\)// if($delim =~ /\(/);
2738 $riptracktag =~ s/^\s*//;
2739 $artistag =~ s/\s*$//;
2740 # If artistag got all info, rather use it as tracktag...
2741 if($riptracktag eq "") {
2742 $riptracktag = $artistag;
2747 ($riptracktag, $artistag) = split(/$delim/, $riptracktag);
2748 $artistag =~ s/\)// if($delim =~ /\(/);
2749 $artistag =~ s/^\s*//;
2750 $riptracktag =~ s/\s*$//;
2754 my $riptrackno = $_;
2755 # If we use option merge, skip a previously merged track:
2758 @skip = skip_tracks;
2759 foreach my $skip (@skip) {
2760 $skipflag = 1 if($_ == $skip);
2763 if(($cdtoc == 1 || $cdcue > 0) && $failflag == 0) {
2766 # Don't write the cue entry again in case ripper failed with
2767 # paranoia and retries ripping without.
2768 if($cdcue == 2 && $failflag == 0) {
2769 my $points = chapter_length($framelist[$_ - 1] - $framelist[0]);
2770 $points =~ /\.\d+$/;
2771 my $cuetrackno = sprintf("%02d", $cdtocn);
2772 open(CDCUE ,">>$wavdir/cd.cue")
2773 or print "Can not append to file \"$wavdir/cd.cue\"!\n";
2774 print CDCUE "TRACK $cuetrackno AUDIO\n",
2775 " TITLE \"$riptracktag\"\n",
2776 " PERFORMER \"$artistag\"\n",
2777 " INDEX 01 $points\n";
2781 print "\nSkip track $_, it has been merged into previous one.\n"
2782 if($verbose >=1 && $skipflag == 1);
2783 next if($skipflag == 1);
2784 # Write the toc entry only if wav present, don't write it again in
2785 # case ripper failed with paranoia and retries ripping without.
2786 # In case we check for ghost songs, these might be deleted, so
2787 # don't write the toc file here.
2788 if($cdtoc == 1 && $failflag == 0 && $ghost == 0) {
2789 my $cdtoctitle = $riptracktag;
2790 oct_char($cdtoctitle);
2791 my $cdtocartis = $artistag;
2792 oct_char($cdtocartis);
2793 open(CDTOC, ">>$wavdir/cd.toc")
2794 or print "Can not append to file \"$wavdir/cd.toc\"!\n";
2795 print CDTOC "\n//Track $cdtocn:\nTRACK AUDIO\n";
2796 print CDTOC "TWO_CHANNEL_AUDIO\nCD_TEXT {LANGUAGE 0 {\n\t\t";
2797 print CDTOC "TITLE \"$cdtoctitle\"\n\t\t";
2798 print CDTOC "PERFORMER \"$cdtocartis\"\n\t}\n}\n";
2799 print CDTOC "FILE \"$riptrackname.wav\" 0\n";
2802 # Remember: $riptrackno is the track number passed to the encoder.
2803 # If we want to merge, we substitute it with the interval, with a
2804 # hyphen for cdparanoia and a plus sign for cdda2wav.
2805 my $saveriptrackno = $riptrackno;
2806 if($pmerge && $merge[0]) {
2807 my @bea = split(/-|\+/, $merge[0]);
2808 if($bea[0] && $riptrackno == $bea[0]) {
2809 $riptrackno = shift(@merge);
2810 $riptrackno =~ s/-/\+/ if($ripper == 2);
2811 $riptrackno =~ s/\+/-/ if($ripper == 1);
2812 # TODO: check for dagrab and sox...
2817 my $_lcdtracks = scalar @tracksel;
2820 if($_lcdtracks eq $lcdtrackno) {
2824 $lcdperc = sprintf("%04.1f", $lcdtrackno/$_lcdtracks*100);
2826 $lcdline2 =~ s/\|\d\d.\d/\|$lcdperc/;
2827 my $lcdtracknoF = sprintf("%02d", $lcdtrackno);
2828 $lcdline2 =~ s/\r\d\d/\r$lcdtracknoF/;
2829 substr($lcdline2,10,10) = substr($riptrackname,3,13);
2833 # There is a problem with too long file names, encountered e. g.
2834 # with some classical CDs. Cdparanoia cuts the length of the file
2835 # name, cdda2wav too... but how should RipIT know? Therefore use
2836 # a shorter track name if total length (including the full path)
2838 my $rip_wavdir = $wavdir;
2839 if(length($riptrackname) + length($wavdir) > 200) {
2840 print "Warning: output trackname is longer than 200 chars,\n",
2841 "RipIT will use a temporary output name to for the ",
2844 $riptrackname = get_trackname($_, $_ . "short", "short");
2845 # We still have problems in case total path is too long:
2846 $rip_wavdir = "/tmp" if(length($riptrackname) + length($wavdir) > 250);
2849 # Check for tracks already done if option --resume is on.
2852 if($normalize == 0 and $cdcue == 0) {
2853 # Start the encoder in the background, but only once.
2854 # We do it already here, because:
2855 # i) if all wavs are done, the encoding process at the end
2856 # of this subroutine will not be started at all!
2857 # ii) why should we wait for the first missing wav, if
2858 # other wavs are already here and encoding could start
2859 # (continue) right away?
2860 if($startenc == 0 && $encode == 1) {
2862 open(ENCLOG,">$wavdir/enc.log");
2870 if(-r "$wavdir/$riptrackname.rip") {
2871 unlink("$wavdir/$riptrackname.rip");
2872 print "Found $riptrackname.rip.\n" if($verbose >= 1);
2874 elsif(-r "$wavdir/$riptrackname\_rip.wav" && $ripper == 2) {
2875 unlink("$wavdir/$riptrackname\_rip.wav");
2876 print "Found $riptrackname\_rip.wav.\n" if($verbose >= 1);
2878 elsif(-r "$wavdir/$riptrackname.wav") {
2880 print "Found $riptrackname.wav.\n" if($verbose >= 1);
2881 if($md5sum == 1 && $wav == 1) {
2882 md5_sum("$wavdir", "$riptrackname.wav", 0);
2886 for(my $c = 0; $c <= $#coder; $c++) {
2887 if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
2889 print "Found file $riptrackname.$suffix[$c].\n"
2895 last if($checknextflag == 2);
2898 # Cdda2wav is somehow unpleasant. It dies not quick enough with
2899 # ^+c. I. e. even if a track has not been ripped to the end,
2900 # the *.rip file will become a *.wav. So we have to check for
2901 # completely encoded files and assume, that for not encoded
2902 # files, there is no fully ripped file. OK, perhaps it would be
2903 # better to check for the last *.wav file and rerip only that
2904 # one. But on a modern machine, the encoder won't be far from
2905 # catching up the ripper, so deleting all *.wavs for missing
2906 # encoded files won't hurt, because cdda2wav is quite fast,
2907 # ripping those tracks again doesn't cost a lot of time.
2908 if($ripper == 2 && $checknextflag == 1) {
2909 for(my $c = 0; $c <= $#coder; $c++) {
2910 if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
2916 last if($checknextflag == 2);
2920 # Skip that track, i.e. restart the foreach-loop of tracks if a
2921 # wav file or other (mp3, ogg, flac, m4a) was found.
2922 next if($checknextflag == 1);
2923 # Don't resume anymore if we came until here.
2926 # Now do the job of ripping:
2927 printf "\n%02d:%02d:%02d: ", sub {$_[2], $_[1], $_[0]}->(localtime)
2928 if($verbose >= 1 && $rip == 1);
2929 print "Ripping \"$riptrackname\"...\n"
2930 if($verbose >= 1 && $rip == 1);
2931 # Choose the cdaudio ripper to use.
2933 # TODO: Check behaviour of all rippers on data tracks.
2934 # Choose to use print instead of die if ripper stops itself!
2935 # Dagrab fails @ data-track, so don't die and create an error.log,
2936 # cdparanoia fails @ data-track, so don't die and create an
2938 # cdda2wav prints errors @ data-track, therefore die!
2939 if($ripper == 0 && $rip == 1) {
2941 $ripopt .= " -r 3" if($parano == 0 && $ripopt !~ /\s-r\s3/);
2942 $ripopt .= " -v" if($verbose >= 2 && $ripopt !~ /\s-v/);
2944 $ripcom = "(dagrab $ripopt -d $cddev \\
2945 -f \"$rip_wavdir/$riptrackname.rip\" \\
2946 $riptrackno 3>&1 1>&2 2>&3 \\
2947 | tee -a \"$wavdir/error.log\") 3>&1 1>&2 2>&3 ";
2948 $ripcom =~ s/\$/\\\$/g;
2949 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
2950 unless(log_system("$ripcom")) {
2951 print "Dagrab detected some read errors on ",
2952 "$tracklist[$_ - 1]\n\n";
2953 # Create error message in CD-directory for encoder: don't
2955 open(ERO,">>$wavdir/error.log")
2956 or print "Can not append to file ",
2957 "\"$wavdir/error.log\"!\n";
2958 print ERO "Dagrab detected some read errors at $riptrackno";
2959 print ERO " on CD $artist - $album, do not worry!\n";
2964 elsif($ripper == 1 && $rip == 1) {
2966 $ripopt .= " -Z" if($parano == 0 && $ripopt !~ /\s-Z/);
2967 $ripopt .= " -q" if($verbose < 2 && $ripopt !~ /\s-q/);
2969 # Introduce the span argument into the tracknumber, adjust the
2970 # tracknumber suffix according to cdparanoia and recalculate
2971 # the track length (used in the playlist file).
2973 my @bea = split(/-/, $span);
2976 $offset = span_length($bea[0]) if($bea[0]);
2977 $chunk = span_length($bea[1]) if($bea[1]);
2978 $bea[0] = "0.0" unless($bea[0]);
2979 $bea[1] = " " unless($bea[1]);
2980 $bea[0] = "[" . $bea[0] . "]" if($bea[0] =~ /\d+/);
2981 $bea[1] = "[" . $bea[1] . "]" if($bea[1] =~ /\d+/);
2982 if($riptrackno =~ /-/) {
2983 my($i, $j) = split(/-/, $riptrackno);
2984 # Special case: if the chunk of sound is larger than the
2985 # (last) track, use the true track length instead of chunk
2987 if($hiddenflag == 0 && $secondlist[$j - 1] < $chunk) {
2991 elsif($hiddenflag == 1 && $secondlist[$j] < $chunk) {
2996 $chunk = $secondlist[$j - 1] if($hiddenflag == 0);
2997 $chunk = $secondlist[$j] if($hiddenflag == 1);
2999 $secondlist[$_ - 1] = $secondlist[$_ - 1] - $secondlist[$j - 1] + $chunk - $offset if($hiddenflag == 0);
3000 $secondlist[$_] = $secondlist[$_] - $secondlist[$j] + $chunk - $offset if($hiddenflag == 1);
3001 $riptrackno = $i . $bea[0] . "-" . $j . $bea[1];
3004 # Special case: if the chunk of sound is larger than the
3005 # (last) track, use the true track length instead of chunk
3007 if($hiddenflag == 0 && $secondlist[$_ - 1] < $chunk) {
3011 elsif($hiddenflag == 1 && $secondlist[$_] < $chunk) {
3015 $riptrackno = $riptrackno . $bea[0] . "-" . $riptrackno . $bea[1];
3016 # Variable $chunk is zero if span reaches the end of the
3019 $chunk = $secondlist[$_ - 1] if($hiddenflag == 0);
3020 $chunk = $secondlist[$_] if($hiddenflag == 1);
3023 $secondlist[$_ - 1] = $chunk if($hiddenflag == 0);
3024 $secondlist[$_] = $chunk if($hiddenflag == 1);
3028 # Handle special paranoia mode for single failed tracks.
3029 my $save_ripopt = $ripopt;
3030 my $save_failflag = $failflag;
3031 if($parano == 2 && $failflag == 1) {
3032 $ripopt = $ripopt . " -Z" if($parano == 2);
3033 print "\n\nTrying again without paranoia.\n"
3036 # Make sure $failflag is set to 0 if success.
3038 $ripcom = "cdparanoia -d $cddev $riptrackno $ripopt \\
3039 \"$rip_wavdir/$riptrackname.rip\"";
3040 $ripcom =~ s/\$/\\\$/g;
3041 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3042 unless(log_system("$ripcom")) {
3043 print "cdparanoia failed on track ", $_,
3044 " $tracklist[$_ - 1]\n\n" if($hiddenflag == 0);
3045 print "cdparanoia failed on track ", $_,
3046 " $tracklist[$_]\n\n" if($hiddenflag == 1);
3047 # Create error message in CD-directory for encoder:
3049 if($parano == 2 && $save_failflag == 1 || $parano < 2 ) {
3050 open(ERO,">>$wavdir/error.log")
3051 or print "Can not append to file ",
3052 "\"$wavdir/error.log\"!\n";
3053 print ERO "Track $saveriptrackno on CD $artist - $album ";
3054 print ERO "failed!\n";
3057 $failflag = $save_failflag + 1;
3059 $ripopt = $save_ripopt;
3061 elsif($multi == 1) {
3062 my $save_ripopt = $ripopt;
3063 my $save_failflag = $failflag;
3064 if($parano == 2 && $failflag == 1) {
3065 $ripopt .= " -Z" if($parano == 2);
3066 print "\n\nTrying again without paranoia.\n"
3069 $ripcom = "cdparanoia -d $cddev $riptrackno $ripopt \\
3070 \"$rip_wavdir/$riptrackname.rip\"";
3071 # Log the ripping output only when using paranoia!
3072 $ripcom .= " 2>> \"$logfile.$saveriptrackno.txt\""
3073 if($parano == 2 && $failflag == 1 || $parano < 2 );
3074 $ripcom =~ s/\$/\\\$/g;
3075 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3077 unless(log_system("$ripcom")) {
3078 if($parano == 2 && $save_failflag == 1 || $parano < 2 ) {
3079 # Append error message to file srXY for rip2m to start
3081 open(SRXY,">>$logfile")
3082 or print "Can not append to file \"$logfile\"!\n";
3083 print SRXY "\ncdparanoia failed on $tracklist[$_ - 1] "
3084 if($hiddenflag == 0);
3085 print SRXY "\ncdparanoia failed on $tracklist[$_] "
3086 if($hiddenflag == 1);
3087 print SRXY "in device $logfile";
3089 # Create error message in CD-directory for encoder:
3091 open(ERO,">>$wavdir/error.log")
3092 or print "Can not append to file ",
3093 "\"$wavdir/error.log\"!\n";
3094 print ERO "Track $saveriptrackno on CD $artist - $album ";
3095 print ERO "failed!\n";
3097 # Kill failed CD only if it is not the last track. Last
3098 # track may be data/video track.
3099 # I.e. print error message to file srXY.Z.txt, checktrack
3100 # will grep for string
3101 # "cdparanoia failed" and kill the CD immediately!
3102 if($riptrackno != $tracksel[$#tracksel]) {
3103 open(SRTF,">>$logfile.$saveriptrackno.txt")
3104 or print "Can not append to file ",
3105 "\"$logfile.$saveriptrackno.txt\"!\n";
3106 print SRTF "cdparanoia failed on $tracklist[$_ - 1]"
3107 if($hiddenflag == 0);
3108 print SRTF "cdparanoia failed on $tracklist[$_ - 1]"
3109 if($hiddenflag == 1);
3110 print SRTF "\nin device $logfile, error !";
3112 # Create on the fly error message in log-directory.
3113 my $devnam = $cddev;
3114 $devnam =~ s/.*dev.//;
3115 open(ERO,">>$outputdir/failed.log")
3116 or print "Can not append to file ",
3117 "\"$outputdir/failed.log\"!\n";
3118 print ERO "$artist;$album;$genre;$categ;$cddbid;";
3119 print ERO "$devnam;$hostnam; Cdparanoia failure!\n";
3121 # Now wait to be terminated by checktrack.
3126 $failflag = $save_failflag + 1;
3128 $ripopt = $save_ripopt;
3130 # This is an awkward workaround introduced because of the
3131 # enhanced --paranoia option. Failures on data tracks are not
3132 # captured anymore. Force update of error.log for encoder.
3133 # Remember, because of option --span $riptrackno can be a
3134 # string. Use $saveriptrackno instead.
3135 if(! -f "$rip_wavdir/$riptrackname.rip") {
3136 if($saveriptrackno == $tracksel[$#tracksel] &&
3137 $riptrackname =~ /data|video/i) {
3138 open(ERO,">>$wavdir/error.log")
3139 or print "Can not append to file ",
3140 "\"$wavdir/error.log\"!\n";
3141 print ERO "Track $saveriptrackno on CD $artist - $album ";
3142 print ERO "failed!\n";
3145 # Append error message to file srXY for rip2m to start
3147 open(SRXY,">>$logfile")
3148 or print "Can not append to file \"$logfile\"!\n";
3149 print SRXY "\ncdparanoia failed on $tracklist[$_ - 1] "
3150 if($hiddenflag == 0);
3151 print SRXY "\ncdparanoia failed on $tracklist[$_] "
3152 if($hiddenflag == 1);
3153 print SRXY "in device $logfile";
3156 # Misuse of variable failflag, we don't care, it's the
3161 print "\nRip file $riptrackname.rip not found...\n"
3166 elsif($ripper == 2 && $rip == 1) {
3168 $ripopt .= " -q" if($verbose <= 1 && $ripopt !~ /\s-q/);
3170 $ripcom = "cdda2wav -D $cddev -H $ripopt ";
3171 # Introduce the span argument into the tracknumber and recalculate the track
3172 # length (used in the playlist file). We use $duration instead of $chunk in the cdparanoia part above.
3174 my @bea = split(/-/, $span);
3177 $offset = span_length($bea[0]) if($bea[0]);
3178 $duration = span_length($bea[1]) if($bea[1]);
3179 if($riptrackno =~ /\+/) {
3180 my($i, $j) = split(/\+/, $riptrackno);
3181 if($hiddenflag == 0) {
3182 if($secondlist[$j - 1] < $duration) {
3186 $duration = $secondlist[$_ - 1] = $secondlist[$_ - 1] - $secondlist[$j - 1] + $duration - $offset;
3189 elsif($hiddenflag == 1) {
3190 # TODO: Oops, why is the counter reduced?
3191 if($secondlist[$j - 1] < $duration) {
3195 $duration = $secondlist[$_] = $secondlist[$_] - $secondlist[$j] + $duration - $offset;
3200 if($hiddenflag == 0 && $secondlist[$_ - 1] < $duration) {
3203 elsif($hiddenflag == 1 && $secondlist[$_] < $duration) {
3207 $duration -= int($offset);
3208 $secondlist[$_ - 1] = $duration if($hiddenflag == 0);
3209 $secondlist[$_] = $duration if($hiddenflag == 1);
3212 $duration = 0 if($duration < 0);
3214 $ripcom .= "-o $offset ";
3215 $ripcom .= "-d $duration " if($duration > 0);
3218 $ripcom .= "-t $riptrackno \"$rip_wavdir/$riptrackname\_rip\"";
3219 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3220 $ripcom =~ s/\$/\\\$/g;
3221 unless(log_system("$ripcom")) {
3222 print "cdda2wav failed on <$tracklist[$_ - 1]>.\n"
3223 if($hiddenflag == 0);
3224 print "cdda2wav failed on <$tracklist[$_]>.\n"
3225 if($hiddenflag == 1);
3226 open(ERO,">>$wavdir/error.log")
3227 or print "Can not append to file ",
3228 "\"$wavdir/error.log\"!\n";
3229 print ERO "Track $saveriptrackno on CD $artist - $album ";
3230 print ERO "failed!\n";
3235 elsif($multi == 1) {
3236 $ripcom = "-t $riptrackno \"$rip_wavdir/$riptrackname\_rip\" \\
3237 2>> \"$logfile.$saveriptrackno.txt\"";
3238 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3239 $ripcom =~ s/\$/\\\$/g;
3240 unless(log_system("$ripcom")) {
3241 # Append error message to file srXY for rip2m to start
3243 open(SRXY,">>$logfile")
3244 or print "Can not append to file \"$logfile\"!\n";
3245 print SRXY "\ncdda2wav failed on $tracklist[$_ - 1] in "
3246 if($hiddenflag == 0);
3247 print SRXY "\ncdda2wav failed on $tracklist[$_] in "
3248 if($hiddenflag == 1);
3249 print SRXY "device $logfile";
3251 # Create error message in CD-directory for encoder:
3253 open(ERO,">>$wavdir/error.log")
3254 or print "Can not append to file ",
3255 "\"$wavdir/error.log\"!\n";
3256 print ERO "Track $saveriptrackno on CD $artist - $album ";
3257 print ERO "failed!\n";
3259 # Kill failed CD only if it is not the last track.
3260 # Last track may be data/video track.
3261 # I.e. print error message to file srXY.Z.txt, checktrack
3262 # will grep for string
3263 # "cdparanoia failed" and kill the CD immediately!
3264 if($riptrackno != $tracksel[$#tracksel]) {
3265 open(SRTF,">>$logfile.$saveriptrackno.txt")
3266 or print "Can not append to file ",
3267 "\"$logfile.$saveriptrackno.txt\"!\n";
3268 print SRTF "cdda2wav failed on $tracklist[$_ - 1]\n"
3269 if($hiddenflag == 0);
3270 print SRTF "cdda2wav failed on $tracklist[$_]\n"
3271 if($hiddenflag == 1);
3272 print SRTF "in device $logfile, error !";
3274 # Create on the fly error message in log-directory.
3275 my $devnam = $cddev;
3276 $devnam =~ s/.*dev.//;
3277 open(ERO,">>$outputdir/failed.log")
3278 or print "Can not append to file ",
3279 "\"$outputdir/failed.log\"!\n";
3280 print ERO "$artist;$album;$genre;$categ;$cddbid;";
3281 print ERO "$devnam;$hostnam; Cdda2wav failure!\n";
3283 # Now wait to be terminated by checktrack.
3289 print "\n" if($verbose > 1);
3291 elsif($ripper == 3 && $rip == 1) {
3292 $ripcom = "tosha -d $cddev -f wav -t $riptrackno \\
3293 -o \"$rip_wavdir/$riptrackname.rip\"";
3294 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3295 unless(log_system("$ripcom")) {
3296 die "tosha failed on $tracklist[$_ - 1]";
3299 elsif($ripper == 4 && $rip == 1) {
3300 my $cdd_dev = $cddev;
3301 $cdd_dev =~ s/^\/dev\/r//;
3303 $ripcom = "cdd -t $riptrackno -q -f $cdd_dev - 2> /dev/null \\
3304 | sox -t cdr -x - \"$rip_wavdir/$riptrackname.wav\"";
3305 $ripcom = "nice -n $nicerip " . $ripcom if($nicerip != 0);
3306 unless(log_system("$ripcom")) {
3307 die "cdd failed on $tracklist[$_ - 1]";
3311 print "No CD Ripper defined.\n";
3314 redo if($ripper == 1 && $failflag == 1 && $parano == 2);
3316 # If we had problems in case total path is too long (note: the
3317 # riptrackname is still the short one).
3318 if(length($riptrackname) + length($wavdir) > 250) {
3319 log_system("cd \"$wavdir\" && mv \"/tmp/$riptrackname.rip\" \"$riptrackname.rip\"");
3322 # Cdda2wav output is not easy to handle. Everything beyond a last
3323 # period . has been erased. Example: riptrackname is something
3324 # like "never ending...", then we assign cdda2wav in the above
3325 # section to rip a file called: "never ending..._rip", but
3326 # cdda2wav misbehaves and the file is called "never ending...".
3327 # Therefore we rename the ripped file to the standard name
3328 # riptrackname.rip first (if cdda2wav was used).
3330 if($riptrackname =~ /\./) {
3331 # But split is too clever! If a trackname ends with "bla..."
3332 # all points get lost, so we've to add a word at the end!
3333 my $cddatrackname = $riptrackname . "end";
3334 my @riptrackname = split(/\./, $cddatrackname);
3335 delete($riptrackname[$#riptrackname]);
3336 $cddatrackname = join('.',@riptrackname);
3337 rename("$wavdir/$cddatrackname.wav",
3338 "$wavdir/$riptrackname.rip");
3341 rename("$wavdir/$riptrackname\_rip.wav",
3342 "$wavdir/$riptrackname.rip");
3345 # Check for gaps and silence in tracks.
3347 my $save_cdtocn = $cdtocn;
3348 if(-r "$wavdir/$riptrackname.rip") {
3349 # Remember: $saveriptrackno is the single track number, whereas
3350 # $riptrackno may hold an interval if option merge is used.
3351 if($ghost == 1 && $failflag == 0) {
3352 @times = get_chunks($saveriptrackno, $riptrackname);
3353 unless($times[0] eq "blank") {
3354 (my $shorten, @times) =
3355 split_chunks($saveriptrackno, "$riptrackname",
3357 ($cdtocn, $cue_point) =
3358 rename_chunks($saveriptrackno, "$riptrackname",
3359 $cdtocn, $cue_point, $shorten,
3360 $artistag, $riptracktag, @times);
3364 # A blank track has been deleted.
3365 $cdtocn-- if(($cdtoc == 1 || $cdcue > 0) && $times[0] eq "blank");
3366 next if($times[0] eq "blank");
3369 # Rename rip file to a wav for encoder so that it will be picked
3370 # up by the encoder background process.
3371 # If the track has been splited into chunks, check if the filename
3372 # holds information about the ghost song. If so, don't use it in
3374 if($save_cdtocn < $cdtocn) {
3375 if($riptracktag =~ /\//) {
3376 my ($wavname, $dummy) = split(/\//, $riptracktag);
3377 $wavname =~ s/^\s+|\s+$//;
3378 # The new riptracktag is needed for inf files.
3379 $riptracktag = $wavname;
3380 $wavname = clean_all($wavname);
3381 $wavname = clean_name($wavname);
3382 $wavname = clean_chars($wavname) if($chars);
3383 $wavname = change_case($wavname);
3384 $wavname =~ s/ /_/g if($underscore == 1);
3385 $wavname = get_trackname($saveriptrackno, $wavname);
3386 rename("$wavdir/$riptrackname.rip", "$wavdir/$wavname.wav");
3387 $riptrackname = $wavname;
3390 rename("$wavdir/$riptrackname.rip", "$wavdir/$riptrackname.wav");
3394 rename("$wavdir/$riptrackname.rip", "$wavdir/$riptrackname.wav");
3396 # Delete the "single-track" wav if cdcue is used. The track is
3397 # already merged, no need to keep it.
3398 unlink("$wavdir/$riptrackname.wav")
3399 if($sshflag == 0 && $cdcue > 0);
3400 md5_sum("$wavdir", "$riptrackname.wav", 0)
3401 if($md5sum == 1 && $normalize == 0 &&
3402 $wav == 1 && $failflag == 0);
3403 # Writing inf files for cdburning.
3404 # We use the $save_cdtocn counter as track counter instead of the
3405 # $riptrackno because $riptrackno might hold a span argument and
3406 # does not reflect the exact number of tracks created.
3407 # Use failflag == 3 to prevent writing inf file for failed data
3409 if($inf >= 1 && $failflag < 3) {
3410 $trackstart = write_inf($wavdir, $riptrackname, $artistag,
3411 $albumtag, $riptracktag, $save_cdtocn, $cdtocn, $trackstart);
3413 chmod oct($fpermission), "$wavdir/$riptrackname.wav"
3415 unlink("$logfile.$riptrackno.txt") if($multi == 1);
3418 if($normalize == 0 and $cdcue == 0) {
3419 # Start the encoder in the background, but only once.
3420 if($startenc == 0 && $encode == 1) {
3421 my $encstart = sprintf("%02d:%02d",
3422 sub {$_[2], $_[1]}->(localtime));
3425 open(SRXY,">>$logfile")
3426 or print "Can not append to file \"$logfile\"!\n";
3427 print SRXY "\nEncoding started: $encstart";
3431 open(ENCLOG,">$wavdir/enc.log");
3438 # Print encoder messages saved in enc.log not to spoil the
3439 # ripper output. Maybe it would be better to test existence of the
3440 # file instead of testing all these conditions.
3441 if($encode == 1 && $normalize == 0 && $cdcue == 0) {
3442 open(ENCLOG, "< $wavdir/enc.log");
3443 my @loglines = <ENCLOG>;
3447 foreach (@loglines) {
3450 if($lincn >= $encline && $_ !~ /^\n/);
3452 elsif($verbose == 1 || $verbose == 2) {
3453 print $_ if($lincn >= $encline && $_ =~ /complete\./);
3459 if($outlines[0] && $verbose >= 1) {
3460 if($trackcn <= $#tracksel) {
3461 push(@outlines, "*" x 47, "\n") if($verbose >= 3);
3462 unshift(@outlines, "*" x 15, " Encoder reports ", "*" x 15, "\n") if($verbose >= 3);
3465 print "\n", "*" x 47, "\nWaiting for encoder to finish...\n\n";
3467 print @outlines if($verbose >= 2);
3471 unlink("$wavdir/enc.log") if(-r "$wavdir/enc.log");
3473 # Hack to tell the child process that we are waiting for it to
3475 my $ripend = sprintf("%02d:%02d", sub {$_[2], $_[1]}->(localtime));
3476 open(ERR, ">>$wavdir/error.log")
3477 or print "Can not append to file error.log!\n";
3478 print ERR "The audio CD ripper reports: all done!\n";
3479 print ERR "Ripping ended: $ripend\n";
3482 open(SRXY,">>$logfile")
3483 or print "Can not append to file \"$logfile\"!\n";
3484 print SRXY "\nRipping complete: $ripend";
3488 ########################################################################
3490 # Normalize the wav.
3491 # Using normalize will disable parallel ripping & encoding.
3495 print "Normalizing the wav-files...\n" if($verbose >= 1);
3496 my($escdir, $norm, $normtrackname);
3498 $escdir = esc_char($escdir);
3500 # Generate filelist to be processed:
3501 foreach (@seltrack) {
3502 my $riptrackname = get_trackname($_, $tracklist[$_ - 1]);
3503 $riptrackname = get_trackname($_, $tracklist[$_])
3504 if($hiddenflag == 1);
3505 # If the file name was too long for ripper, look for special name.
3506 my $wavname = $riptrackname;
3507 if(length($riptrackname) + length($wavdir) > 200) {
3508 $wavname = get_trackname($_, $_."short", "short");
3510 # Normalize is picky about certain characters - get them escaped!
3511 $wavname = esc_char($wavname);
3512 $normtrackname .= "$escdir/$wavname.wav" . " \\\n ";
3514 $normtrackname =~ s/\s*$//;
3515 $normtrackname =~ s/\$/\\\$/g;
3518 $normopt .= "q" if($verbose == 0);
3519 $normopt .= "v" if($verbose >= 2 && $normopt !~ /q/);
3520 $normopt .= "vv" if($verbose >= 4 && $normopt !~ /q/);
3522 $norm = "$normcmd $normopt -- $normtrackname";
3524 if(log_system("$norm")) {
3525 log_info("\nNormalizing complete.\n");
3526 print "\nNormalizing complete.\n" if($verbose >= 1);
3529 print "\nWarning: normalizing failed.\n";
3532 ########################################################################
3535 # This runs as a separate process from the main program which
3536 # allows it to continuously encode as the ripping is being done.
3537 # The encoder will also wait for the ripped wav in-case the encoder
3538 # is faster than the CDROM. In fact it will be waited 3 times the length
3539 # of the track to be encoded.
3543 my ($enc, $riptrackno, $riptrackname, $suffix, $tagtrackno);
3544 my ($albumlametag, $artislametag, $commentlametag, $tracklametag);
3545 my ($ripcomplete, $trackcn, $totalencs) = (0, 0, 0);
3546 my $lastskip = $tracksel[0];
3547 my $resumenc = $resume;
3548 my $encodername = "";
3549 my @md5tracks = (); # List of tracks to be re-taged (coverart etc.).
3552 my $albumtag = clean_all($album_utf8);
3553 my $artistag = clean_all($artist_utf8);
3554 my $album = $albumtag;
3555 my $artist = $artistag;
3556 $album = clean_name($album);
3557 $artist = clean_name($artist);
3558 $album = clean_chars($album) if($chars);
3559 $artist = clean_chars($artist) if($chars);
3560 $album =~ s/ /_/g if($underscore == 1);
3561 $artist =~ s/ /_/g if($underscore == 1);
3563 # Create special variables for Lame-tags because of UTF8 problem.
3565 $albumlametag = back_encoding($albumtag);
3566 $commentlametag = back_encoding($commentag);
3569 $albumlametag = $albumtag;
3570 $commentlametag = $commentag;
3573 # Write header of playlist file.
3575 if($playlist >= 1) {
3576 $playfile = "$artist" . " - " . "$album" . ".m3u";
3577 $playfile =~ s/ /_/g if($underscore == 1);
3578 if($limit_flag == 255) {
3579 $playfile = substr($playfile, 0, 250);
3581 open(PLST, ">$wavdir/$playfile") or
3582 print "Can't open $wavdir/$playfile! $!\n";
3583 print PLST "#EXTM3U\n";
3586 # Read the cdcue file (once) to be copied to the encoder directories.
3589 open(CUE, "<$wavdir/cd.cue")
3590 or print "Can not read file cue sheet!\n";
3595 # If using book-option define a chapter file.
3598 $chapterfile = "$artist" . " - " . "$album" . ".chapters.txt";
3599 $chapterfile =~ s/ /_/g if($underscore == 1);
3600 if($limit_flag == 255) {
3601 $chapterfile = substr($chapterfile, 0, 235);
3602 $chapterfile .= ".chapters.txt";
3609 if($commentag =~ /^discid|cddbid$/) {
3610 if($commentag =~ /^discid$/) {
3611 $commentag = $cd{discid}
3613 elsif($commentag =~ /^cddbid$/) {
3614 $commentag = $cd{id};
3616 $commentag = "" unless($commentag);
3617 $commentlametag = $commentag;
3620 # Prevent using genre "other" if genre is not lame compliant but
3621 # other encoders than Lame are used:
3622 my $genre_tag = $genre;
3623 $genre_tag = $cd{genre} if($genre =~ /Other/ && $cd{genre} !~ /Other/);
3625 # Create a coverart array supposing its exactly in the same order as
3629 @coverart = split(/,/, $coverart);
3632 # Loop all tracknames for a last VA style detection needed for
3633 # tagging the files. Note that nothing is known about ghost songs.
3634 my $delim = check_va(0);
3636 # Start encoding each track.
3637 foreach (@tracksel) {
3638 # A lot of hacking for ghost songs. Remember, array @tracksel is
3639 # the original one, without ghost songs as long as we did not get
3640 # to the end. Once all tracks are done, this array will be
3641 # updated if ghost songs were found by the ripper.
3642 # Now: if only one track in the middle of the album has been
3643 # selected, problems occur if this track has ghost songs. Why?
3644 # Because the updated array @tracksel will be e.g. 4 4 4 4 if the
3645 # track 4 has 3 ghost songs. But the track-list and tag-list
3646 # arrays have all tracknames of the whole CD, so after track
3647 # number 4 will come track number 5! Therefor no track
3648 # "04 name of track 5" will be found and the encoder fails!
3649 # To prevent this: Once all (selected) tracks are done, we have to
3650 # set the $ghostcn to the total number of tracks of the CD to
3651 # access names of ghost songs added to the list by the ripper.
3652 $ghostflag = 2 if($ghostflag == 1 && $riptrackno >= $_);
3653 $ghostcn = $#{$cd{track}} + 1 if($ghostflag == 0);
3655 $tagtrackno = $_ + $trackoffset;
3657 # A new problem araises if the track names of ghost (and original)
3658 # songs are changed (if the track name with ghost song has a
3659 # slash in). In this case, the resume option and the part that
3660 # waits for the ripped files to appear will fail. In this case we
3661 # need to check ghost.log. But the ghost.log is not yet present if
3662 # ripper is still ripping that file (the resume function in the
3663 # ripper process failed for the same reason). So we don't care
3664 # here and want the resume function fail again. An additional test
3665 # will be done in the waiting part below.
3667 $riptrackname = get_trackname($_, $tracklist[$_ - 1]);
3668 $riptrackname = get_trackname($_, $tracklist[$_])
3669 if($hiddenflag == 1);
3671 if($ghostflag >= 1) {
3673 $riptrackname = get_trackname($_, $tracklist[$ghostcn - 1]);
3674 $riptrackname = get_trackname($_, $tracklist[$ghostcn])
3675 if($hiddenflag == 1);
3678 # Once the file is ripped and merged, it is called $album, no
3679 # matter if $cdcue == 1 or 2.
3680 $riptrackname = $album if($book == 1 or $cdcue > 0);
3681 # If we want to merge, skip a previously merged track:
3684 @skip = skip_tracks;
3685 foreach my $skip (@skip) {
3686 $skipflag = 1 if($_ == $skip);
3689 # Search the index number of encoder faac.
3691 for(my $c = 0; $c <= $#coder; $c++) {
3692 $index = $c if($coder[$c] == 3);
3694 # Write the *.chapter.txt file.
3695 open(CHAP, ">>$sepdir[$index]/$chapterfile") or
3696 print "Can't open $sepdir[$index]/$chapterfile! $!\n";
3697 # Use timestamps, not the true track lengths. Where are the
3698 # specifications, please?
3699 my $points = chapter_length($framelist[$_ - 1] - $framelist[0]);
3700 my $chapname = $tracktags[$_ - 1];
3701 # Remember: merge writes all merged tracknames into the
3702 # first track of an interval.
3703 $chapname =~ s/\s\+\s.*$// if($_ == 1);
3704 print CHAP "$points $chapname\n";
3708 next if($skipflag == 1);
3713 my $_lcdtracks = scalar @tracksel;
3714 my $_lcdenctrack = $trackcn;
3716 if($_lcdtracks eq $_lcdenctrack) {
3720 $lcdperc = sprintf("%04.1f", $_lcdenctrack / $_lcdtracks * 100);
3722 $lcdline3 =~ s/\|\d\d.\d/\|$lcdperc/;
3723 my $_lcdenctrackF = sprintf("%02d", $_lcdenctrack);
3724 $lcdline3 =~ s/\E\d\d/\E$_lcdenctrackF/;
3725 substr($lcdline3, 10, 10) = substr($riptrackname, 3, 13);
3729 # Adjust encoding of tracktag for Lame.
3730 my $tracktag = $tracktags[$_ - 1];
3731 $tracktag = $tracktags[$_] if($hiddenflag == 1);
3732 if($ghostflag >= 1) {
3733 $tracktag = $tracktags[$ghostcn - 1];
3734 $tracktag = $tracktags[$ghostcn] if($hiddenflag == 1);
3737 # Split the tracktag into its artist part and track part if
3739 if($va_flag > 0 && $tracktag =~ /$delim/) {
3741 if($vatag % 2 == 1) {
3742 ($artistag, $tracktag) = split(/$delim/, $tracktag);
3743 $tracktag =~ s/\)// if($delim =~ /\(/);
3744 $tracktag =~ s/^\s*//;
3745 $artistag =~ s/\s*$//;
3746 # If artistag got all info, rather use it as tracktag...
3747 if($tracktag eq "") {
3748 $tracktag = $artistag;
3753 ($tracktag, $artistag) = split(/$delim/, $tracktag);
3754 $artistag =~ s/\)// if($delim =~ /\(/);
3755 $artistag =~ s/^\s*//;
3756 $tracktag =~ s/\s*$//;
3761 $tracklametag = back_encoding($tracktag);
3762 $artislametag = back_encoding($artistag);
3765 $tracklametag = $tracktag;
3766 $artislametag = $artistag;
3768 $artistag = clean_all($artist_utf8) if($artistag eq "");
3770 $tracktag = $album if($cdcue > 0);
3771 # If the file name was too long for ripper, look for special name.
3772 my $wavname = $riptrackname;
3773 if(length($riptrackname) + length($wavdir) > 200) {
3774 $wavname = get_trackname($_, $_."short", "short");
3777 # Check for tracks already done.
3778 my $checknextflag = 1;
3780 for(my $c=0; $c<=$#coder; $c++) {
3781 if(! -r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
3785 print "Found $riptrackname.$suffix[$c]:\n"
3787 print "Will calculate and write md5sum for:\n"
3788 if($verbose >= 4 && $md5sum == 1);
3789 print "$sepdir[$c], $riptrackname.$suffix[$c]\n"
3790 if($verbose >= 4 && $md5sum == 1);
3792 last if($checknextflag == 0);
3794 if($checknextflag == 1 && $playlist >= 1) {
3795 print PLST "#EXTINF:$secondlist[$_ - 1],$tracktag\n"
3796 if($hiddenflag == 0);
3797 print PLST "#EXTINF:$secondlist[$_],$tracktag\n"
3798 if($hiddenflag == 1);
3799 print PLST "Sepdir/$riptrackname.suffix\n"
3801 print PLST "$riptrackname.suffix\n" if($playlist == 2);
3802 print PLST "Add Ghost Song $_ Here.\n" if($ghost == 1);
3804 unlink("$wavdir/$riptrackname.wav")
3805 if($wav == 0 && $sshflag == 0 && $checknextflag == 1);
3807 # Skip that track, i. e. restart the foreach-loop of tracks if a
3808 # compressed file (mp3, ogg, ma4, flac) was found.
3809 next if($resumenc && $checknextflag == 1);
3810 # Don't resume anymore, if we came until here.
3813 # Keep looping until the wav file appears, i.e. wait for
3814 # ripper timeout. Timeout is 3 times the length of track
3815 # to rip/encode. Then leave that one and finish the job!
3816 my $slength = $secondlist[$_ - 1];
3817 my $mlength = (int($slength / 60) + 1) * 3;
3818 my $tlength = (int($slength / 10) + 6) * 3;
3820 # We don't need this for ghost songs, as they are done only when
3821 # the (original) last track was successfully ripped.
3825 while(! -r "$wavdir/$wavname.wav" && $ghostflag == 0) {
3827 last if($xtime > $tlength);
3828 # There might be a ghost song with an other name. If ripping
3829 # is done, ghost.log would help, but the ghost.log file
3830 # might not be present yet!
3832 my ($ghost_rtn, $dummy) = split(/\//, $tracktag);
3834 $ghost_rtn =~ s/^\s+|\s+$//;
3835 my $ghost_trt = $ghost_rtn;
3836 $ghost_rtn = clean_all($ghost_rtn);
3837 $ghost_rtn = clean_name($ghost_rtn);
3838 $ghost_rtn = clean_chars($ghost_rtn) if($chars);
3839 $ghost_rtn = change_case($ghost_rtn);
3840 $ghost_rtn =~ s/ /_/g if($underscore == 1);
3841 $ghost_rtn = get_trackname($riptrackno, $ghost_rtn);
3842 # Rename the riptrackname to wavname to exit the
3843 # while-loop. Do it only when the wav appeared and the
3844 # rip file disappeared in case it's the last track and
3845 # the following check of ghost.log is mandatory. Else
3846 # we would leave this loop and possibly read an old
3847 # ghost.log not yet updated, because ripper is still
3849 if(!-r "$wavdir/$wavname.rip" and
3850 !-r "$wavdir/$ghost_rtn.rip" and
3851 -r "$wavdir/$ghost_rtn.wav") {
3852 $wavname = $riptrackname = $ghost_rtn;
3853 $tracktag = $ghost_trt;
3855 $tracklametag = back_encoding($tracktag);
3858 $tracklametag = $tracktag;
3863 # Condition 1: Too long waiting for the track!
3864 if($xtime >= $tlength) {
3865 # If the rip file has been found, give a chance to
3866 # continue if the rip-file increases in size.
3867 my $old_ripsize = $ripsize;
3869 if(-r "$wavdir/$wavname.rip") {
3870 $ripsize = -s "$wavdir/$wavname.rip";
3873 if($ripsize > $old_ripsize * 1.2) {
3874 $tlength = $tlength * 1.5;
3877 print "Encoder waited $mlength minutes for file\n";
3878 print "$riptrackname.wav to appear, now giving up!\n";
3879 print "with $artist - $album in device $cddev\n";
3880 log_info("Encoder waited $mlength minutes for file");
3881 log_info("$riptrackname.wav to appear, now giving up!");
3882 log_info("with $artist - $album in device $cddev");
3886 print "Encoder waited $mlength minutes for file\n";
3887 print "$riptrackname.wav to appear\n";
3888 print "with $artist - $album in device $cddev.\n";
3889 # If the rip file has been found, give a chance to
3890 # continue if the rip-file increases in size.
3891 if(-r "$wavdir/$wavname.rip") {
3892 if($ripsize > $old_ripsize * 1.2) {
3893 $tlength = $tlength * 1.5;
3896 $xtime = 0 unless($riptrackname =~ /00 Hidden Track/);
3897 open(ERR, ">>$wavdir/error.log");
3898 print ERR "Ripping ended: 00:00!\n";
3903 $xtime = 0 unless($riptrackname =~ /00 Hidden Track/);
3904 open(ERR, ">>$wavdir/error.log");
3905 print ERR "Ripping ended: 00:00!\n";
3911 # Condition 2: Check the error log!
3912 # If at this moment the ripper did not start with
3913 # the riptrackname.rip, assume it was a data track!
3914 # If cdparanoia failed on a data track, there will
3915 # be an entry in the error.log.
3916 # If dagrab gave error messages, but the wav file
3917 # was created, we won't get to this point, so don't
3919 if(-r "$wavdir/error.log") {
3920 open(ERR, "$wavdir/error.log")
3921 or print "Encoder can't read $wavdir/error.log!\n";
3922 my @errlines = <ERR>;
3924 # Note that the ripper wrote the $savetrackno into the
3925 # errorlog, we check for $riptrackno not $tagtrackno.
3926 chomp(my $errtrack = join(' ', grep(/^Track $riptrackno /, @errlines)));
3928 $xtime = $tlength + 1;
3931 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
3932 open(ENCLOG, ">>$wavdir/enc.log");
3933 print ENCLOG "\nDid not detect track $errtrack ",
3934 "($riptrackname.rip),\n assume ",
3935 "ripper failure!\n";
3939 print "\nDid not detect track $errtrack ",
3940 "($riptrackname.rip), assume ripper ",
3944 if($verbose >= 2 && $sshflag == 0) {
3945 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
3946 open(ENCLOG, ">>$wavdir/enc.log");
3947 print ENCLOG "\nRipIT will finish the job! ",
3948 "Check the error.log!\n";
3952 print "RipIT will finish the job! ",
3953 "Check the error.log!\n";
3957 chomp(my $rip_ended = join(' ', grep(/^Ripping\sended:\s\d\d:\d\d/, @errlines)));
3958 if($rip_ended and $xtime == 0 and $multi == 1) {
3959 print "Ripper reported having ripped all wavs.\n";
3960 print "There is a problem with $riptrackname.wav.\n";
3961 print "with $artist - $album in device $cddev.\n";
3962 open(SRTF,">>$logfile.$riptrackno.txt")
3963 or print "Can not append to file ",
3964 "\"$logfile.$riptrackno.txt\"!\n";
3965 print SRTF "cdparanoia failed on $tracklist[$_ - 1]"
3966 if($hiddenflag == 0);
3967 print SRTF "cdparanoia failed on $tracklist[$_ - 1]"
3968 if($hiddenflag == 1);
3969 print SRTF "\nin device $logfile, error !";
3971 # Create on the fly error message in log-directory.
3972 my $devnam = $cddev;
3973 $devnam =~ s/.*dev.//;
3974 open(ERO,">>$outputdir/failed.log")
3975 or print "Can not append to file ",
3976 "\"$outputdir/failed.log\"!\n";
3977 print ERO "$artist;$album;$genre;$categ;$cddbid;";
3978 print ERO "$devnam;$hostnam; Cdparanoia failure!\n";
3980 # Now wait to be terminated by checktrack.
3986 # This is an other hack to update the track-arrays modified by the
3987 # ripper if ghost songs were found. Is there another way to
3988 # communicate with the parent process?
3989 # This loop was supposed to be at the end of this sub-routine,
3990 # but we need it here in case of data tracks. The encoder would
3991 # stop here after a data track and fail to encode previously found
3992 # ghost songs because @tracksel has not yet been updated.
3993 # This loop was supposed to come right after the next part
3994 # checking for presence of wav-files. But we need it here in case
3995 # of ghost songs where the original track gets a new name.
3996 if($ghost == 1 && $_ == $tracksel[$#tracksel]
3997 && -r "$wavdir/ghost.log") {
3998 open(GHOST, "<$wavdir/ghost.log")
3999 or print "Can not read file ghost.log!\n";
4000 my @errlines = <GHOST>;
4002 my @selines = grep(s/^Array seltrack: //, @errlines);
4003 @tracksel = split(/ /, $selines[$#selines]);
4004 chomp($_) foreach(@tracksel);
4005 my @seclines = grep(s/^Array secondlist: //, @errlines);
4006 @secondlist = split(/ /, $seclines[$#seclines]);
4007 chomp($_) foreach(@secondlist);
4008 @tracklist = grep(s/^Array tracklist: //, @errlines);
4009 chomp($_) foreach(@tracklist);
4010 @tracktags = grep(s/^Array tracktags: //, @errlines);
4011 chomp($_) foreach(@tracktags);
4012 unlink("$wavdir/ghost.log");
4015 $resumenc = $resume; # Continue to resume ghost songs.
4018 # Jump to the next track if wav wasn't found. Note that the
4019 # $tlength does not exist for additional ghost songs, so don't
4020 # test this condition when encoding ghost songs, furthermore we
4021 # assume that ghost songs are present as soon as one was found.
4022 next if($ghostflag == 0 && $xtime >= $tlength || $dataflag == 1);
4024 # It seems that we need to rename long filenames in a subshell,
4025 # because the rename function does not work if the full path is
4026 # even longer. NOTE: There is a problem with UTF8, when special
4027 # characters are true wide characters... Too many of them, and
4028 # it will fail again. Maybe one should check the length with the
4030 if(length($riptrackname) + length($wavdir) > 200) {
4031 $riptrackname = substr($riptrackname, 0, 200);
4032 $riptrackname =~ s/\s*$//;
4033 # rename("\"$wavdir/$wavname.wav\"","\"$wavdir/$riptrackname.wav\"");
4034 log_system("cd \"$wavdir\" && mv \"$wavname.wav\" \"$riptrackname.wav\"");
4038 my $starts = sprintf("%3d", sub {$_[1]*60+$_[0]}->(localtime));
4040 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4041 open(ENCLOG, ">>$wavdir/enc.log");
4042 print ENCLOG "\nEncoding \"$riptrackname\"...\n"
4047 print "\nEncoding \"$riptrackname\"...\n" if($verbose >= 3);
4052 # Set the encoder(s) we are going to use.
4053 for(my $c = 0; $c <= $#coder; $c++) {
4054 # Initialization of coverart variables.
4056 $coverart[$c] = 0 unless($coverart[$c]);
4057 # Get the command for the encoder to use!
4058 $genre = "" unless($genre);
4059 if($coder[$c] == 0) {
4060 $encodername = "Lame";
4061 $lameopt = $globopt[$c];
4063 # Coverart tagging will be done below because an additional
4064 # module will be used. Don't handle the whole picture-data
4067 $enc = "lame $lameopt -S --tt \"$tracklametag\" \\
4068 --ta \"$artislametag\" --tl \"$albumlametag\" \\
4069 --ty \"$year\" --tg \"$genre\" --tn $tagtrackno \\
4070 --tc \"$commentlametag\" --add-id3v2 \\
4071 \"$wavdir/$riptrackname.wav\" \\
4072 \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\"";
4073 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4074 open(ENCLOG, ">>$wavdir/enc.log");
4075 printf ENCLOG "\n%02d:%02d:%02d: ",
4076 sub {$_[2], $_[1], $_[0]}->(localtime)
4078 print ENCLOG "Lame $lameopt encoding track $trackcn" .
4079 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4083 printf "\n%02d:%02d:%02d: ",
4084 sub {$_[2], $_[1], $_[0]}->(localtime)
4086 print "Lame $lameopt encoding track $trackcn of " .
4087 ($#tracksel + 1) if($verbose >= 3);
4088 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4089 print "\n" if($verbose >= 3);
4091 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4093 elsif($coder[$c] == 1) {
4094 $encodername = "Oggenc";
4095 $oggencopt = $globopt[$c];
4097 # Some info about coverart tagging.
4098 # This will happen below, after encoding, because we use
4099 # vorbiscomment. Don't handle the whole picture-data
4102 # http://www.hydrogenaudio.org/forums/lofiversion/index.php/t48386.html
4105 # first: base64 encoding of the image:
4107 # perl -MMIME::Base64 -0777 -ne 'print encode_base64($_, "")' < thumb.png > temp
4109 # note the double quotes to prevent the newlines.
4110 # Redirect this output to a file.
4112 # second: use vorbiscomment to tag the file: (http://darcs.tonywhitmore.co.uk/repos/podcoder/podcoder)
4114 # vorbiscomment -a 01.ogg -t "COVERARTMIME=image/png" -t "COVERART=`cat temp`"
4118 # Use of METADATA_BLOCK_PICTURE
4119 # http://wiki.xiph.org/index.php/VorbisComment
4120 # http://lists.xiph.org/pipermail/vorbis-dev/2009-April/019853.html
4122 # Proposals for extending Ogg Vorbis comments
4123 # http://reallylongword.org/vorbiscomment/
4125 $enc = "oggenc $oggencopt -Q -t \"$tracktag\" \\
4126 -a \"$artistag\" -l \"$albumtag\" \\
4127 -d \"$year\" -G \"$genre_tag\" \\
4128 -N $tagtrackno -c \"DESCRIPTION=$commentag\" \\
4129 -o \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\" \\
4130 \"$wavdir/$riptrackname.wav\"";
4131 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4132 open(ENCLOG, ">>$wavdir/enc.log");
4133 printf ENCLOG "\n%02d:%02d:%02d: ",
4134 sub {$_[2], $_[1], $_[0]}->(localtime)
4136 print ENCLOG "Oggenc $oggencopt encoding track" .
4137 " $trackcn of " . ($#tracksel + 1) . "\n"
4142 printf "\n%02d:%02d:%02d: ",
4143 sub {$_[2], $_[1], $_[0]}->(localtime)
4145 print "Oggenc $oggencopt encoding track $trackcn of " .
4146 ($#tracksel + 1) if($verbose >= 3);
4147 print " merged tracks" if($verbose >= 3 && $cdcue > 0);
4148 print ".\n" if($verbose >= 3);
4150 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4152 elsif($coder[$c] == 2) {
4153 $encodername = "Flac";
4154 $flacopt = $globopt[$c];
4155 my $save_flacopt = $flacopt;
4156 $flacopt .= " -f" if($resume);
4157 # Don't know if the COMPILATION-tag is supported but it
4158 # should not harm at all.
4159 $flacopt .= " --tag=COMPILATION=1" if($va_flag > 0);
4160 if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4161 $covertag = "--picture=\"$coverpath\"";
4163 $enc = "flac $flacopt -s --tag=TITLE=\"$tracktag\" \\
4164 --tag=ARTIST=\"$artistag\" --tag=ALBUM=\"$albumtag\" \\
4165 --tag=DATE=\"$year\" --tag=TRACKNUMBER=\"$tagtrackno\" \\
4166 --tag=GENRE=\"$genre_tag\" --tag=CATEGORY=\"$categ\" \\
4167 --tag=DESCRIPTION=\"$commentag\" --tag=CDID=\"$cddbid\" \\
4169 -o \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\" \\
4170 \"$wavdir/$riptrackname.wav\"";
4171 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4172 open(ENCLOG, ">>$wavdir/enc.log");
4173 printf ENCLOG "%02d:%02d:%02d: ",
4174 sub {$_[2], $_[1], $_[0]}->(localtime)
4176 print ENCLOG "Flac $flacopt encoding track $trackcn" .
4177 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4181 printf "\n%02d:%02d:%02d: ",
4182 sub {$_[2], $_[1], $_[0]}->(localtime)
4184 print "Flac $flacopt encoding track $trackcn of " .
4185 ($#tracksel + 1) if($verbose >= 3);
4186 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4187 print "\n" if($verbose >= 3);
4189 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4190 my $flacopt = $save_flacopt if($resume);
4192 elsif($coder[$c] == 3) {
4193 $encodername = "Faac";
4194 $faacopt = $globopt[$c];
4195 if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4196 $covertag = "--cover-art \"$coverpath\"";
4198 $enc = "faac $faacopt -w --title \"$tracktag\" \\
4199 --artist \"$artistag\" --album \"$albumtag\" \\
4200 --year \"$year\" --genre \"$genre_tag\" --track $tagtrackno \\
4201 --comment \"$commentag\" \\
4203 -o \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\" \\
4204 \"$wavdir/$riptrackname.wav\" \\
4206 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4207 open(ENCLOG, ">>$wavdir/enc.log");
4208 printf ENCLOG "\n%02d:%02d:%02d: ",
4209 sub {$_[2], $_[1], $_[0]}->(localtime)
4211 print ENCLOG "Faac $faacopt encoding track $trackcn" .
4212 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4216 printf "\n%02d:%02d:%02d: ",
4217 sub {$_[2], $_[1], $_[0]}->(localtime)
4219 print "Faac $faacopt encoding track $trackcn of " .
4220 ($#tracksel + 1) if($verbose >= 3);
4221 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4222 print "\n" if($verbose >= 3);
4224 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4226 elsif($coder[$c] == 4) {
4227 $encodername = "mp4als";
4228 $mp4alsopt = $globopt[$c];
4229 $enc = "mp4als $mp4alsopt \\
4230 \"$wavdir/$riptrackname.wav\" \\
4231 \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\" \\
4234 # Only add tags if MP4 container is set up, use artwork for
4236 my $mp4suffix = $suffix[$c];
4237 if($mp4alsopt =~ /MP4/) {
4239 if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4240 $covertag = "-P \"$coverpath\"";
4242 $enc .= " && mp4tags -s \"$tracktag\" -a \"$artistag\" \\
4243 -A \"$albumtag\" -y \"$year\" -g \"$genre_tag\" \\
4244 -t $tagtrackno -c \"$commentag\" -e RipIT -E mp4als \\
4246 \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\"";
4248 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4249 open(ENCLOG, ">>$wavdir/enc.log");
4250 printf ENCLOG "\n%02d:%02d:%02d: ",
4251 sub {$_[2], $_[1], $_[0]}->(localtime)
4253 print ENCLOG "Mp4als $mp4alsopt encoding track $trackcn" .
4254 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4258 printf "\n%02d:%02d:%02d: ",
4259 sub {$_[2], $_[1], $_[0]}->(localtime)
4261 print "Mp4als $mp4alsopt encoding track $trackcn of " .
4262 ($#tracksel + 1) if($verbose >= 3);
4263 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4264 print "\n" if($verbose >= 3);
4266 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4268 elsif($coder[$c] == 5) {
4269 $encodername = "Musepack";
4270 $museopt = $globopt[$c];
4271 # Musepack seems not to support coverart, the developper
4272 # probably assumes that coverart has nothing to do with a
4274 $enc = "$musenc --silent $museopt --title \"$tracktag\" \\
4275 --artist \"$artistag\" --album \"$albumtag\" \\
4276 --year \"$year\" --genre \"$genre_tag\" --track $tagtrackno --comment \"$commentag\" \\
4277 \"$wavdir/$riptrackname.wav\" \\
4278 \"$sepdir[$c]/$riptrackname\_enc.$suffix[$c]\"";
4279 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4280 open(ENCLOG, ">>$wavdir/enc.log");
4281 printf ENCLOG "\n%02d:%02d:%02d: ",
4282 sub {$_[2], $_[1], $_[0]}->(localtime)
4284 print ENCLOG "Mppenc $museopt encoding track $trackcn" .
4285 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4289 printf "\n%02d:%02d:%02d: ",
4290 sub {$_[2], $_[1], $_[0]}->(localtime)
4292 print "Mppenc $museopt encoding track $trackcn of " .
4293 ($#tracksel + 1) if($verbose >= 3);
4294 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4295 print "\n" if($verbose >= 3);
4297 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4299 elsif($coder[$c] == 6) {
4300 $encodername = "wavpack";
4301 $wavpacopt = $globopt[$c];
4302 # Use command wvunpack -ss filename.wv to check if the cover
4303 # art is present or not. See:
4304 # www.hydrogenaudio.org/forums/index.php?showtopic=74828
4305 if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4306 $covertag = "--write-binary-tag \"Cover Art (Front)=\@$coverpath\"";
4308 $enc = "wavpack $wavpacopt -q \\
4309 -w \"Title=$tracktag\" \\
4310 -w \'Artist=$artistag\' -w \"Album=$albumtag\" \\
4311 -w \"Year=$year\" -w \"Genre=$genre_tag\" \\
4312 -w \"Track=$tagtrackno\" -w \"Comment=$commentag\" \\
4314 \"$wavdir/$riptrackname.wav\" \\
4315 -o \"$sepdir[$c]/$riptrackname\_enc\"";
4316 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4317 open(ENCLOG, ">>$wavdir/enc.log");
4318 printf ENCLOG "\n%02d:%02d:%02d: ",
4319 sub {$_[2], $_[1], $_[0]}->(localtime)
4321 print ENCLOG "Wavpack $wavpacopt encoding track $trackcn" .
4322 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4326 printf "\n%02d:%02d:%02d: ",
4327 sub {$_[2], $_[1], $_[0]}->(localtime)
4329 print "Wavpack $wavpacopt encoding track $trackcn of " .
4330 ($#tracksel + 1) if($verbose >= 3);
4331 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4332 print "\n" if($verbose >= 3);
4334 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4336 elsif($coder[$c] == 7) {
4337 $encodername = "ffmpeg";
4338 # Trying to solve the tag problem of tagging with ffmpeg in
4339 # general and within alac files in special:
4340 # First, I tried to use ffmpeg and the -map_meta_tag option:
4341 # ffmpeg -i 05\ I\ Beg\ For\ You.flac -acodec alac \\
4342 # 05\ I\ Beg\ For\ You.m4a -map_meta_data outfile:infile
4343 # Note: do not replace outfile:infile by the file names, use
4344 # the command as stated!
4346 # OK, this works and we see, that the four character code
4347 # used in the m4a tags are "ART" and "wrt". So, what we need
4348 # is author to access these tags!
4350 # http://archives.free.net.ph/message/20090925.222527.f3078d30.en.html
4351 # http://atomicparsley.sourceforge.net/mpeg-4files.html
4352 # http://code.google.com/p/mp4v2/wiki/iTunesMetadata
4354 $ffmpegopt = $globopt[$c];
4355 $ffmpegopt .= " -y" if($overwrite eq "y");
4356 $ffmpegopt .= " -metadata compilation=1 " if($va_flag > 0 and $ffmpegopt =~ /alac/i);
4357 # Not yet supported... at least I don't know how to use the
4358 # -atag fourcc/tag option.
4359 # if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4360 # $covertag = "-metadata artwork=\'$coverpath\'";
4362 $enc = "ffmpeg -i \"$wavdir/$riptrackname.wav\" \\
4364 -metadata author=\"$artistag\" -metadata album=\"$albumtag\" \\
4365 -metadata title=\"$tracktag\" -metadata genre=\"$genre_tag\" \\
4366 -metadata day=\"$year\" -metadata comment=\"$commentag\" \\
4367 -metadata track=\"$tagtrackno\" \\
4369 \"$sepdir[$c]/$riptrackname.$suffix[$c]\" > /dev/null 2>&1";
4370 # Only add artwork for coverart if alac is present.
4371 if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4372 if($ffmpegopt =~ /alac/) {
4373 $enc .= " && mp4art -q --add \"$coverpath\" \\
4374 \"$sepdir[$c]/$riptrackname.$suffix[$c]\"";
4377 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4378 open(ENCLOG, ">>$wavdir/enc.log");
4379 printf ENCLOG "\n%02d:%02d:%02d: ",
4380 sub {$_[2], $_[1], $_[0]}->(localtime)
4382 print ENCLOG "ffmpeg $ffmpegopt encoding track $trackcn" .
4383 " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4387 printf "\n%02d:%02d:%02d: ",
4388 sub {$_[2], $_[1], $_[0]}->(localtime)
4390 print "ffmpeg $ffmpegopt encoding track $trackcn of " .
4391 ($#tracksel + 1) if($verbose >= 3);
4392 print " merged tracks." if($verbose >= 3 && $cdcue > 0);
4393 print "\n" if($verbose >= 3);
4395 log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4397 # Set "last encoding of track" - flag.
4398 $delwav = 1 if($wav == 0 && $c == $#coder);
4399 # Set nice if wished.
4400 $enc = "nice -n $nice " . $enc if($nice != 0);
4401 # Make the output look nice, don't mess the messages!
4402 my $ripmsg = "The audio CD ripper reports: all done!";
4403 if($ripcomplete == 0 ) {
4404 if(-r "$wavdir/error.log") {
4405 open(ERR, "$wavdir/error.log")
4406 or print "Can not open file error.log!\n";
4407 my @errlines = <ERR>;
4409 my @ripcomplete = grep(/^$ripmsg/, @errlines);
4410 $ripcomplete = 1 if(@ripcomplete);
4414 $enc =~ s/\$/\\\$/g;
4415 # Finally, do the job of encoding.
4417 enc_ssh($delwav,$enc,$riptrackname,$sepdir[$c],$suffix[$c]);
4418 # Calculation of md5sum has been moved to the end, we still
4419 # use the process to check the files already done to add
4420 # coverart. Files not yet encoded will need to be post-
4421 # processed in del_erlog subroutine.
4423 "$sepdir[$c];#;$riptrackname.$suffix[$c]");
4425 foreach my $md5tr (@md5tracks) {
4426 my ($sepdir, $donetrack) = split(/;#;/, $md5tr);
4427 # Proceede only if file appeared.
4428 if(-f "$sepdir/$donetrack") {
4429 # Add special mp3 tags.
4430 if(@mp3tags && $donetrack =~ /mp3$/) {
4431 mp3_tags("$sepdir/$donetrack") if($mp3tags[0] ne "");
4433 # Add coverart if it is a mp3 or ogg.
4434 if($donetrack =~ /mp3$/ && -f "$coverpath" && -s "$coverpath") {
4435 mp3_cover("$sepdir/$donetrack", "$coverpath");
4437 elsif($donetrack =~ /ogg$/ && -f "$coverpath" && -s "$coverpath") {
4438 ogg_cover("$sepdir/$donetrack", "$coverpath");
4441 # Only add files to array @md5tracks if coverart shall be
4444 push(@waitracks, "$sepdir;#;$donetrack") if($coder[$c] <= 1 && $coverart[$c] == 1);
4447 @md5tracks = @waitracks;
4450 if(log_system("$enc")) {
4451 if($ripcomplete == 0) {
4452 if(-r "$wavdir/error.log") {
4453 open(ERR, "$wavdir/error.log")
4454 or print "Can open file error.log!\n";
4455 my @errlines = <ERR>;
4457 my @ripcomplete = grep(/^$ripmsg/, @errlines);
4458 $ripcomplete = 1 if(@ripcomplete);
4461 if($coder[$c] == 4 && $mp4alsopt =~ /MP4/) {
4462 rename("$sepdir[$c]/$riptrackname.$suffix[$c]_enc",
4463 "$sepdir[$c]/$riptrackname.mp4");
4465 elsif($coder[$c] == 5) {
4466 rename("$sepdir[$c]/$riptrackname\_enc.$suffix[$c]",
4467 "$sepdir[$c]/$riptrackname.$suffix[$c]");
4469 elsif($coder[$c] == 6) {
4470 rename("$sepdir[$c]/$riptrackname\_enc.$suffix[$c]",
4471 "$sepdir[$c]/$riptrackname.$suffix[$c]");
4472 if(-r "$sepdir[$c]/$riptrackname\_enc.wvc") {
4473 rename("$sepdir[$c]/$riptrackname\_enc.wvc",
4474 "$sepdir[$c]/$riptrackname.wvc");
4478 rename("$sepdir[$c]/$riptrackname.$suffix[$c]_enc",
4479 "$sepdir[$c]/$riptrackname.$suffix[$c]");
4481 # Add special mp3 tags.
4482 if(@mp3tags && $coder[$c] == 0) {
4483 mp3_tags("$sepdir[$c]/$riptrackname.$suffix[$c]") if($mp3tags[0] ne "");
4485 # Add coverart if it is a mp3 or ogg.
4486 if($coder[$c] == 0 && $coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4487 mp3_cover("$sepdir[$c]/$riptrackname.$suffix[$c]", "$coverpath");
4489 elsif($coder[$c] == 1 && $coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4490 ogg_cover("$sepdir[$c]/$riptrackname.$suffix[$c]", "$coverpath");
4492 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4493 open(ENCLOG, ">>$wavdir/enc.log");
4494 print ENCLOG "Encoding of " .
4495 "\"$riptrackname.$suffix[$c]\" " .
4496 "complete.\n" if($verbose >= 1);
4500 print "Encoding of \"$riptrackname.$suffix[$c]\" " .
4501 "complete.\n" if($verbose >= 1);
4505 print "Encoder $encodername failed on $tracklist[$_ - 1]\n",
4506 "of disc in device $cddev.\n",
4507 "Error message says: $?\n";
4510 # Print error message to file srXY.Z.txt, checktrack
4511 # will grep for string "encoder failed" and kill the
4513 open(SRTF,">>$logfile.$riptrackno.txt")
4514 or print "Can not append to file ",
4515 "\"$logfile.$riptrackno.txt\"!\n";
4516 print SRTF "\nencoder failed on $tracklist[$_ - 1] ";
4517 print SRTF "in device $cddev, error $? !";
4519 # Create on the fly error message in log-directory.
4520 my $devnam = $cddev;
4521 $devnam =~ s/.*dev.//;
4522 open(ERO, ">>$outputdir/failed.log")
4523 or print "Can not append to file ",
4524 "\"$outputdir/failed.log\"!\n";
4525 print ERO "$artist;$album;$genre;$categ;$cddbid;";
4526 print ERO "$devnam;$hostnam; Encoder failure!\n";
4528 # Wait to be terminated by checktrack.
4534 # Copy the cdcue file (once) to the directory of the encoded
4537 my $cue_suffix = $suffix[$c];
4538 $cue_suffix =~ tr/a-z/A-Z/;
4539 open(CUE, ">$sepdir[$c]/$album.cue")
4540 or print "Can not append to file ",
4541 "\"$sepdir[$c]/$album.cue\"!\n";
4542 foreach (@cuelines) {
4544 s/\.wav/.$suffix[$c]/;
4545 s/\sWAVE/ $cue_suffix/;
4551 # Calculate time in seconds when encoding ended and total time
4553 my $endsec = sprintf("%3d", sub {$_[1]*60+$_[0]}->(localtime));
4554 $endsec += 60 while($endsec <= $starts);
4555 $totalencs = $totalencs + $endsec - $starts;
4556 # Delete the wav if not wanted.
4557 unlink("$wavdir/$riptrackname.wav")
4558 if($delwav == 1 && $sshflag == 0);
4560 # Write the playlist file. This is somehow tricky, if ghost songs
4561 # may appear. To ensure the files in the right order, introduce
4562 # placeholders for possible ghost songs.
4563 # The problem is that the secondlist with the true track lengths
4564 # will only be updated when the last track has been encoded (the
4565 # last track except ghost songs). But we need the true length
4566 # right now. So, if $ghost == 1, check for the ghost.log file at
4569 # An other buggy behaviour: if the last encoder of a list fails,
4570 # failflag will prevent writing playlist files, although encoding
4571 # was successful for all other encoders (but the last one).
4572 # Would it be better to write the playlist file in any case?
4573 if($failflag == 0 && $playlist >= 1) {
4574 # Ghost songs follow after the last track, but $ghostflag was
4575 # set to 1 just before last track is encoded. Therefore set
4576 # $ghostflag to 2 after the last track has been done and
4577 # inserted in the playlist file as a regular file (below),
4578 # and insert sound files as ghost songs only when $ghostflag is
4579 # 2. If only the last song has been split into chunks and
4580 # the counter increased, continue to insert as regular file.
4581 if($ghostflag == 2) {
4582 print PLST "GS$_:#EXTINF:$secondlist[$ghostcn - 1],",
4584 if($hiddenflag == 0);
4585 print PLST "GS$_:#EXTINF:$secondlist[$ghostcn],$tracktag\n"
4586 if($hiddenflag == 1);
4587 print PLST "GS$_:Sepdir/$riptrackname.suffix\n"
4589 print PLST "GS$_:$riptrackname.suffix\n" if($playlist == 2);
4592 if($ghost == 1 && -r "$wavdir/ghost.log") {
4593 open(GHOST, "<$wavdir/ghost.log")
4594 or print "Can not read file ghost.log!\n";
4595 my @errlines = <GHOST>;
4597 my @seclines = grep(s/^Array secondlist: //, @errlines);
4598 @secondlist = split(/ /, $seclines[$#seclines]);
4599 chomp($_) foreach(@secondlist);
4601 print PLST "#EXTINF:$secondlist[$_ - 1],$tracktag\n"
4602 if($hiddenflag == 0);
4603 print PLST "#EXTINF:$secondlist[$_],$tracktag\n"
4604 if($hiddenflag == 1);
4605 print PLST "Sepdir/$riptrackname.suffix\n"
4607 print PLST "$riptrackname.suffix\n" if($playlist == 2);
4608 print PLST "Add Ghost Song $_ Here.\n"
4609 if($ghost == 1 || $ghostflag == 1);
4612 last if($cdcue > 0);
4615 print "\n" if($verbose > 2);
4616 # Only add albumgain and md5sum calculation if all tracks are done,
4617 # this might not be the case when running with more than one thread
4618 # or using remote process. In the later case, we need to add coverart
4619 # and album gain before calculating md5sums, so: move all this stuff
4622 # Tell the mother process the encoding time.
4623 open(ERR, ">>$wavdir/error.log")
4624 or print "Can not append to file error.log!\n";
4625 print ERR "Encoding needed $totalencs seconds!\n";
4626 print ERR "md5: $_\n" foreach(@md5tracks);
4629 exit unless($normalize == 1 or $cdcue > 0);
4631 ########################################################################
4633 # Finish the M3U file used by players such as Amarok, Noatun, X11Amp...
4639 my $album = clean_all($album_utf8);
4640 my $artist = clean_all($artist_utf8);
4641 $album = clean_name($album);
4642 $artist = clean_name($artist);
4643 $album = clean_chars($album) if($chars);
4644 $artist = clean_chars($artist) if($chars);
4646 $playfile = "$artist" . " - " . "$album" . ".m3u";
4647 $playfile =~ s/ /_/g if($underscore == 1);
4648 if($limit_flag == 255) {
4649 $playfile = substr($playfile, 0, 240);
4652 # Prevent warnings in some rare cases if no tracks have been ripped.
4653 return unless(-r "$wavdir/$playfile");
4655 open(PLST, "<$wavdir/$playfile")
4656 or print "Can not open file $wavdir/$playfile!\n";
4657 my @playlines = <PLST>;
4659 my @ghosts = grep(/^GS\d+:/, @playlines);
4661 unlink("$wavdir/$playfile");
4664 foreach (@playlines) {
4665 next if($_ =~ /^GS\d+:/ || $_ =~ /^$/);
4666 $_ =~ s/^Add Ghost Song (\d+) Here.$/$1/;
4669 foreach my $ghostsong (@ghosts) {
4670 if($ghostsong =~ s/^GS$_\://) { # Why not as a 1-liner?
4671 $ghostsong =~ s/^GS$_\://;
4673 push @playlist, $ghostsong;
4683 for(my $c = 0; $c <= $#coder; $c++) {
4684 my @mp3s = @playlist;
4685 $_ =~ s/\.suffix$/.$suffix[$c]/i foreach (@mp3s);
4686 $_ =~ s/^Sepdir/$sepdir[$c]/ foreach (@mp3s);
4687 # Extension of playlist-file only needed when more than one
4688 # encoder selected. Using separate dirs, this would not be
4689 # necessary, but who says we use them? We keep the extension.
4691 $nplayfile = $playfile;
4692 $nplayfile = change_case($nplayfile);
4693 $nplayfile =~ s/\.m3u$/ - $suffix[$c].m3u/
4694 if($underscore == 0);
4695 $nplayfile =~ s/\.m3u$/_-_$suffix[$c].m3u/
4696 if($underscore == 1);
4697 open(PLST, ">$sepdir[$c]/$nplayfile") or
4698 print "Can't open $sepdir[$c]/$nplayfile! $!\n";
4701 $nplayfile = $playfile;
4702 open(PLST, ">$sepdir[$c]/$nplayfile") or
4703 print "Can't open $sepdir[$c]/$nplayfile! $!\n";
4705 print PLST "$_\n" foreach(@mp3s);
4707 chmod oct($fpermission), "$sepdir[$c]/$nplayfile"
4710 # Recreate the wav-playlist if wavs aren't deleted.
4712 my @mp3s = @playlist;
4713 $_ =~ s/\.suffix$/\.wav/i foreach (@mp3s);
4714 $_ =~ s/^Sepdir/$wavdir/ foreach (@mp3s);
4715 $nplayfile = $playfile;
4716 $nplayfile = change_case($nplayfile);
4717 $nplayfile =~ s/\.m3u$/ - wav\.m3u/
4718 if($underscore == 0);
4719 $nplayfile =~ s/\.m3u$/_-_wav\.m3u/
4720 if($underscore == 1);
4721 open(PLST, ">$wavdir/$nplayfile") or
4722 print "Can't open $wavdir/$nplayfile! $!\n";
4723 print PLST "$_\n" foreach(@mp3s);
4725 chmod oct($fpermission), "$wavdir/$nplayfile"
4729 ########################################################################
4731 # Create a default or manual track list.
4733 sub create_deftrack {
4734 # Let operator chose to use default names or enter them manually.
4735 # Do not ask if we come form CDDB submission, i.e. index == 0,
4736 # or if $interaction == 0, then $index == 1.
4737 my ($i, $j, $index) = (0,1,@_);
4738 my ($album, $artist);
4740 my $tracks = substr($cddbid, 6);
4741 $tracks = hex($tracks);
4743 $album = clean_all($album_utf8) if(defined $cd{title});
4744 $artist = clean_all($artist_utf8) if(defined $cd{artist});
4746 # Preselect answer if no interaction requested.
4747 $index = 1 if($interaction == 0);
4749 while($index !~ /^[0-1]$/ ) {
4750 print "\nThis CD shall be labeled with:\n\n";
4751 print "1: Default Album, Artist and Tracknames\n\n";
4752 print "0: Manual input\n\nChoose [0-1]: (0) ";
4755 $index = 0 unless($index);
4758 # Create default tracklist and cd-hash.
4759 # NOTE: here we define an additional key: revision, which does not
4760 # exist if %cd is filled by CDDB_get. If this key exists we know
4761 # that it is a new entry.
4763 $artist = "Unknown Artist";
4764 $album = "Unknown Album";
4774 while($i < $tracks) {
4776 $j = "0" . $j if($j < 10);
4777 $cd{track}[$i] = "Track " . "$j";
4780 $cddbsubmission = 0;
4782 # Create manual tracklist.
4783 elsif($index == 0) {
4784 # In case of CDDB resubmission
4785 if(defined $cd{artist}) {
4786 print "\n Artist ($artist): ";
4788 # In case of manual CDDB entry.
4790 print "\n Artist : ";
4794 # If CDDB entry confirmed, take it.
4795 if(defined $cd{artist} && $artist eq "") {
4796 $artist = $artist_utf8;
4798 # If CDDB entry CHANGED, submission OK.
4799 elsif(defined $cd{artist} && $artist ne "") {
4800 $cddbsubmission = 1;
4801 $cd{artist} = $artist;
4802 $artist_utf8 = $artist;
4805 $artist = "Unknown Artist";
4806 $cddbsubmission = 0;
4808 if(defined $cd{title}) {
4809 print "\n Album ($album): ";
4812 print "\n Album : ";
4816 while($year !~ /^\d{4}$/) {
4817 if(defined $cd{year}) {
4818 print "\n Year ($year): ";
4825 last if($year eq "");
4827 # If CDDB entry confirmed, take it.
4828 if(defined $cd{title} && $album eq "") {
4829 $album = $album_utf8;
4831 # If CDDB entry CHANGED, submission OK.
4832 elsif(defined $cd{title} && $album ne "") {
4833 $cddbsubmission = 1;
4834 $cd{title} = $album;
4835 $album_utf8 = $album;
4838 $album = "Unknown Album";
4839 $cddbsubmission = 0;
4849 ) unless(defined $cd{title});
4852 while($i <= $tracks) {
4853 if(defined $cd{track}[$i-1]) {
4854 printf(" Track %02d (%s): ", $i, $tracktags[$i-1]);
4857 printf(" Track %02d: ", $i);
4859 my $tracktag = <STDIN>;
4861 $tracktag = clean_all($tracktag);
4862 my $track = $tracktag;
4863 $track = clean_name($track);
4864 $track = clean_chars($track) if($chars);
4865 $track = change_case($track);
4866 $track =~ s/ /_/g if($underscore == 1);
4867 # If CDDB entry confirmed, take and replace it in tracklist.
4868 if(defined $cd{track}[$i-1] && $track ne "") {
4869 splice @tracklist, $i-1, 1, $track;
4870 splice @tracktags, $i-1, 1, $tracktag;
4871 $cddbsubmission = 1;
4873 elsif(!$cd{track}[$i-1] && $track eq "") {
4874 $track = "Track " . sprintf("%02d", $i);
4875 $cddbsubmission = 0;
4877 # Fill the "empty" array @{$cd{track}}.
4878 push(@{$cd{track}}, "$track");
4884 # I don't like die, but I don't like if-loops without else.
4885 # This should not happen because of previous while-loop!
4886 die "Choose 0 or 1!\n\n";
4890 ########################################################################
4892 # Read the CD and generate a TOC with DiscID, track frames and total
4893 # length. Then prepare CDDB-submission with entries from @tracklist.
4896 my($check,$i,$ans,$genreno,$line,$oldcat,$subject) = (0,0);
4898 my $tracks = $#framelist;
4899 my $totals = int($framelist[$#framelist] / 75);
4901 my $album = clean_all($album_utf8);
4902 my $artist = clean_all($artist_utf8);
4904 my $revision = get_rev() unless($cd{discid});
4906 # TODO: if submission fails, set revision back.
4908 print "Revision is set to $revision.\n" if($verbose > 4);
4910 elsif(defined $cd{revsision}) {
4911 $revision = $cd{revision};
4917 # Check for CDDB ID vs CD ID problems.
4918 if($cddbid ne $cd{id} && defined $cd{id}) {
4919 print "\nObsolet warning: CDID ($cddbid) is not identical to ";
4920 print "CDDB entry ($cd{id})!";
4921 print "\nYou might get a collision error. Try anyway!\n";
4924 # Questioning to change CDDB entries and ask to fill missing fields.
4925 if(defined $cd{year} && $year ne "") {
4926 $year = get_answ("year",$year);
4929 while($year !~ /^\d{4}$| / || !$year ) {
4930 print "\nPlease enter the year (or none): ";
4935 $cddbsubmission = 1;
4939 $cddbsubmission = 1 unless($year eq $cd{year});
4942 $cddbsubmission = 1;
4944 # Ask if CDDB category shall be changed and check if done;
4945 # $categ will be an empty string if user wants to change it.
4947 if($cd{cat} && $categ) {
4948 $categ = get_answ("CDDB category",$categ);
4953 "blues", "classical", "country", "data",
4954 "folk", "jazz", "misc", "newage",
4955 "reggae", "rock", "soundtrack"
4958 # If data is from musicbrainz, don't ask to check category and simply
4959 # prepare a CD-DB file with category musicbrainz. User will have to
4960 # find a unused category and submit the entry manually.
4961 if(!$categ && !$cd{discid} && $submission != 0) {
4962 print "Shall Ripit check for available categories?",
4970 print "\n\nAvailable categories:\n";
4971 foreach (@categories) {
4973 my $source = "http://www.freedb.org/freedb/" .
4975 $templines = LWP::Simple::get($source);
4976 # Question: what is wrong that I need to put a \n in the print
4977 # command to force perl to print right away, and not to print
4978 # the whole bunch only when the foreach-loop is done???
4987 print "\nAll 11 categories are used, bad luck!";
4988 print "\nSave the file locally with --archive!\n";
4989 print "\nUse one of the following categories:";
4990 print "\nblues, classical, country, data, folk";
4991 print "\njazz, misc, newage, reggae, rock, soundtrack\n";
4992 $cddbsubmission = 0;
4995 # Check if the $categ variable is correct.
4996 while($categ !~ m/^blues$|^classical$|^country$|^data$|^folk$|
4997 |^jazz$|^newage$|^reggae$|^rock$|^soundtrack$|
4999 print "\nPlease choose one of the available CDDB categories: "
5001 print "\nPlease choose one of the categories: "
5006 $cddbsubmission = 1 unless($categ eq $cd{cat});
5009 elsif($cd{discid}) {
5010 $categ = "musicbrainz";
5012 # If one changes category for a new submission, set Revision to 0.
5013 if($oldcat ne $categ && defined $cd{cat}) {
5016 # Remind the user if genre is not ID3v2 compliant even if Lame is
5017 # not used! Reason: There should be no garbage genres in the DB.
5018 # If Lame is used, genre has already been checked!
5019 if($lameflag != 1 && defined $genre) {
5020 ($genre,$genreno) = check_genre($genre);
5021 $cddbsubmission = 1 unless($genre eq $cd{'genre'});
5023 # Do not to ask if genre had been passed from command line.
5025 $genre = get_answ("genre",$genre);
5028 print "\nPlease enter a valid CDDB genre (or none): ";
5031 $cd{genre} = $genre;
5032 # Allow to submit no genre! Else check it!
5034 $genre =~ s/[\015]//g;
5035 ($genre,$genreno) = check_genre($genre);
5038 $cddbsubmission = 1 unless($genre eq $cd{'genre'});
5039 my $dtitle = $artist . " / " . $album;
5040 substr($dtitle, 230, 0, "\nDTITLE=") if(length($dtitle) > 250);
5041 substr($dtitle, 460, 0, "\nDTITLE=") if(length($dtitle) > 500);
5043 # Start writing the CDDB submission.
5044 open(TOC, ">$homedir/cddb.toc")
5045 or print "Can not write to cddb.toc $!\n";
5046 print TOC "# xmcd CD database generated by RipIT\n#\n",
5047 "# Track frame offsets:\n";
5049 foreach (@framelist) {
5050 print TOC "# $_\n" if($i < $#framelist);
5053 print TOC "#\n# Disc length: $totals seconds\n#\n";
5054 if(!$cd{discid} && $archive == 1) {
5055 my $source = "http://www.freedb.org/freedb/" . $categ . "/" . $cddbid;
5056 print "Will try to get <$source>.\n";
5057 my $templines = LWP::Simple::get($source);
5058 my @templines = split(/\n/, $templines);
5059 chomp($revision = join('', grep(s/^\s*#\sRevision:\s(\d+)/$1/, @templines)));
5060 $revision++ if($revision =~ /^\d+/);
5061 $revision = 0 unless($revision =~ /^\d+/);
5062 print "\nRevision number set to $revision.\n" if($verbose >= 4);
5064 print TOC "# Revision: $revision\n";
5065 my $time = sprintf("%02d:%02d", sub {$_[2], $_[1]}->(localtime));
5066 my $date = sprintf("%04d-%02d-%02d",
5067 sub {$_[5]+1900, $_[4]+1, $_[3]}->(localtime));
5068 $date = $date . " at " . $time;
5069 print TOC "# Submitted via: RipIT $version ";
5070 print TOC "www.suwald.com/ripit/ripit.html on $date\n";
5072 print TOC "DISCID=$cddbid\n";
5073 print TOC "DTITLE=$dtitle\n";
5074 print TOC "DYEAR=$year\n";
5075 if(defined $genre) {
5076 print TOC "DGENRE=$genre\n";
5078 elsif($genre eq "" && defined $categ) {
5079 print TOC "DGENRE=$categ\n";
5082 foreach (@tracktags) {
5083 substr($_, 230, 0, "\nTTITLE$i=") if(length($_) > 250);
5084 substr($_, 460, 0, "\nTTITLE$i=") if(length($_) > 500);
5085 print TOC "TTITLE$i=$_\n";
5089 my @comment = extract_comm;
5090 my $commentest = "@comment";
5094 print "Confirm (Enter), delete or edit each comment line ";
5096 foreach (@comment) {
5100 while($ans !~ /^c|^d|^e/) {
5101 print "$_ (c/d/e): ";
5108 if($ans =~ /^c/ || $ans eq "") {
5109 print TOC "EXTD=$_\\n\n";
5112 elsif($ans =~ /^e/) {
5113 print "Enter a different line: \n";
5116 substr($ans, 230, 0, "\nEXTD=") if(length($ans) > 250);
5117 substr($ans, 460, 0, "\nEXTD=") if(length($ans) > 500);
5118 print TOC "EXTD=$ans\\n\n";
5119 $cddbsubmission = 1;
5123 # Don't print the line.
5124 $cddbsubmission = 1;
5129 while(defined $line) {
5130 print "Do you want to add a line? (Enter for none or type!): ";
5133 $cddbsubmission = 1 if($line ne "");
5135 substr($line, 230, 0, "\nEXTD=") if(length($line) > 250);
5136 substr($line, 460, 0, "\nEXTD=") if(length($line) > 500);
5137 print TOC "EXTD=$line\\n\n";
5140 # If all lines have been deleted, add an empty EXTD line!
5142 print TOC "EXTD=\n";
5145 # If there are no comments, ask to add some.
5146 elsif(!$comment[0]) {
5149 while(defined $line) {
5150 print "Please enter a comment line (or none): ";
5153 $cddbsubmission = 1 if($line ne "");
5154 substr($line, 230, 0, "\nEXTD=") if(length($line) > 250);
5155 substr($line, 460, 0, "\nEXTD=") if(length($line) > 500);
5156 print TOC "EXTD=$line\n" if($linecn == 0);
5157 print TOC "EXTD=\\n$line\n" if($linecn != 0);
5159 # This line has to be written, so break the
5160 # while loop here and not before, as above.
5165 print TOC "EXTD=\n";
5168 # Extract the track comment lines EXTT.
5169 my @trackcom = grep(/^EXTT\d+=/, @{$cd{raw}});
5170 @trackcom = grep(s/^EXTT\d+=//, @trackcom);
5171 foreach (@trackcom) {
5176 $ans = get_answ('Track comment','existing ones');
5179 while($i < $tracks) {
5182 printf(" Track comment %02d (%s):", $i+1, $trackcom[$i]);
5185 printf(" Track comment %02d: ", $i+1);
5189 substr($track, 230, 0, "\nEXTT$i=") if(length($track) > 250);
5190 substr($track, 460, 0, "\nEXTT$i=") if(length($track) > 500);
5192 # If CDDB entry confirmed, take and replace it in tracklist.
5193 if(defined $trackcom[$i] && $track eq "") {
5194 print TOC "EXTT$i=$trackcom[$i]\n";
5196 elsif(defined $trackcom[$i] && $track ne "") {
5197 print TOC "EXTT$i=$track\n";
5198 $cddbsubmission = 1;
5200 elsif($track ne "") {
5201 print TOC "EXTT$i=$track\n";
5202 $cddbsubmission = 1;
5205 print TOC "EXTT$i=\n";
5212 foreach (@tracklist) {
5213 print TOC "EXTT$i=$trackcom[$i]\n";
5219 foreach (@tracklist) {
5220 print TOC "EXTT$i=\n";
5225 # Extract the playorder line.
5226 my @playorder = grep(/^PLAYORDER=/, @{$cd{raw}});
5227 @playorder = grep(s/^PLAYORDER=//, @playorder);
5229 my $playorder = $playorder[0];
5231 print TOC "PLAYORDER=$playorder\n";
5234 print TOC "PLAYORDER=\n";
5237 # Copy the *edited* CDDB file if variable set to the ~/.cddb/
5239 if($archive == 1 && $cddbsubmission != 2) {
5240 log_system("mkdir -m 0755 -p \"$homedir/.cddb/$categ\"")
5242 "Can not create directory \"$homedir/.cddb/$categ\": $!\n";
5244 "cp \"$homedir/cddb.toc\" \"$homedir/.cddb/$categ/$cddbid\""
5247 "Can not copy cddb.toc to directory ",
5248 "\"$homedir/.cddb/$categ/$cddbid\": $!\n";
5249 print "Saved file $cddbid in \"$homedir/.cddb/$categ/\"";
5252 # If no connection to the internet do not submit.
5253 if($submission == 0) {
5254 $cddbsubmission = 0;
5256 # If we came from MB do not submit.
5257 elsif($cd{discid}) {
5258 $cddbsubmission = 0;
5261 if($cddbsubmission == 1) {
5263 while($ans !~ /^y$|^n$/) {
5264 print "Do you really want to submit your data to freeDB.org?",
5273 $cddbsubmission = 1;
5276 $cddbsubmission = 0;
5279 if($cddbsubmission == 1) {
5280 while($mailad !~ /.@.+[.]./) {
5281 print "\nReady for submission, enter a valid return ";
5282 print "e-mail address: ";
5287 open TOC, "cat \"$homedir/cddb.toc\" |"
5288 or die "Can not open file $homedir/cddb.toc $!\n";
5292 $subject = "cddb " . $categ . " " . $cddbid;
5293 open(MAIL, "|/usr/sbin/sendmail -t -r $mailad")
5294 or print "/usr/sbin/sendmail not installed? $!\n";
5296 # Generate the mail-header and add the toc-lines.
5297 print MAIL "From: $mailad\n";
5298 print MAIL "To: freedb-submit\@freedb.org\n";
5299 # print MAIL "To: test-submit\@freedb.org\n";
5300 print MAIL "Subject: $subject\n";
5301 print MAIL "MIME-Version: 1.0\n";
5302 print MAIL "Content-Type: text/plain; charset=$charset\n";
5307 print "Mail exit status not zero: $?" if($?);
5308 print "CDDB entry submitted.\n\n" unless($?);
5309 unlink("$homedir/cddb.toc");
5311 elsif($cddbsubmission == 2) {
5312 print "\n CDDB entry created and saved in \$HOME, but not send, ";
5313 print "because no changes";
5314 print "\n were made! Please edit and send it manually to ";
5315 print "freedb-submit\@freedb.org";
5316 print "\n with subject: cddb $categ $cddbid\n\n";
5320 print "\n CDDB entry saved in your home directory, but not send,";
5321 print "\n please edit it and send it manually to:";
5322 print "\n freedb-submit\@freedb.org with subject:";
5323 print "\n cddb $categ $cddbid\n\n";
5326 ########################################################################
5328 # Check if genre is correct.
5333 my $genrenoflag = 1;
5335 $genre = " " if($genre eq "");
5337 # If Lame is not used, don't die if ID3v2-tag is not compliant.
5338 if($lameflag == 0) {
5340 "lame --genre-list 2>&1 | grep -i \" $genre\$\" > /dev/null ")) {
5341 print "Genre $genre is not ID3v2 compliant!\n"
5343 print "Continuing anyway!\n\n" if($verbose >= 1);
5344 chomp($genreno = "not ID3v2 compliant!\n");
5346 return ($genre,$genreno);
5349 # If Lame is not installed, don't loop for ever.
5350 if($lameflag == -1) {
5351 chomp($genreno = "Unknown.\n");
5352 return ($genre,$genreno);
5355 # Check if (similar) genre exists. Enter a new one with interaction,
5356 # or take the default one.
5358 "lame --genre-list 2>&1 | grep -i \"$genre\" > /dev/null ")) {
5359 print "Genre $genre is not ID3v2 compliant!\n" if($verbose >= 1);
5360 if($interaction == 1) {
5361 print "Use \"lame --genre-list\" to get a list!\n";
5362 print "\nPlease enter a valid CDDB genre (or none): ";
5365 $cd{genre} = $genre;
5368 print "Genre \"Other\" will be used instead!\n"
5370 $genre = "12 Other";
5377 elsif($genre =~ /^\d+$/) {
5378 chomp($genre = `lame --genre-list 2>&1 | grep -i \' $genre \'`);
5381 # First we want to be sure that the genre from the DB, which might
5382 # be "wrong", e.g. wave (instead of Darkwave or New Wave) or synth
5383 # instead of Synthpop, will be correct. Put the DB genre to ogenre
5384 # and get a new right-spelled genre... Note, we might get several
5385 # possibilities, e.g. genre is Pop, then we get a bunch of
5386 # "pop-like" genres!
5387 # There will be a line break, if multiple possibilities found.
5388 my $ogenre = $genre;
5389 chomp($genre = `lame --genre-list 2>&1 | grep -i \'$genre\'`);
5390 # Second we want THE original genre, if it precisely exists.
5391 chomp(my $testgenre = `lame --genre-list 2>&1 | grep -i \'\^... $ogenre\$\'`);
5392 $genre = $testgenre if($testgenre);
5393 # If we still have several genres:
5394 # Either let the operator choose, or if no interaction, take
5395 # default genre: "12 Other".
5396 if($genre =~ /\n/ && $interaction == 1) {
5397 print "More than one genre possibility found!\n";
5398 my @list = split(/\n/,$genre);
5400 while($i > $#list+1 || $i == 0) {
5401 # TODO: Here we should add the possibility to choose none!
5402 # Or perhaps to go back and choose something completely
5405 printf(" %2d: $_ \n",$j);
5409 print "\nChoose [1-$j]: ";
5414 chomp($genre = $list[$i-1]);
5416 # OK, no interaction! Take the first or default genre!
5417 elsif($genre =~ /\n/ && $interaction != 1 && $lameflag == 1) {
5418 $genre = "12 Other" if($genre eq "");
5421 # OK, the genre is not Lame compliant, and we do not care about,
5422 # because Lame is not used. Set the genre-number-flag to 0 to
5423 # prevent genre-number-extracting at the end of the subroutine.
5424 elsif($lameflag != 1) {
5431 # Extract genre-number.
5432 if($genre ne "" && $genrenoflag == 1) {
5434 my @genre = split(/ /, $genre);
5435 $genreno = shift(@genre);
5438 return ($genre,$genreno);
5440 ########################################################################
5442 # Check mirrors. Need to be tested from time to time, which ones are up.
5444 # http://at.freedb.org:80/~cddb/cddb.cgi working
5445 # http://au.freedb.org:80/~cddb/cddb.cgi not working
5446 # http://ca.freedb.org:80/~cddb/cddb.cgi working
5447 # http://ca2.freedb.org:80/~cddb/cddb.cgi working
5448 # http://de.freedb.org:80/~cddb/cddb.cgi working
5449 # http://es.freedb.org:80/~cddb/cddb.cgi working
5450 # http://fi.freedb.org:80/~cddb/cddb.cgi working
5451 # http://freedb.freedb.org:80/~cddb/cddb.cgi not working
5452 # http://ru.freedb.org:80/~cddb/cddb.cgi working
5453 # http://uk.freedb.org:80/~cddb/cddb.cgi working
5454 # http://us.freedb.org:80/~cddb/cddb.cgi not working
5458 # while($mirror !~ m/^freedb$|^at$|^au$|^ca$|^es$|^fi$|
5459 # |^fr$|^jp$|^jp2$|^ru$|^uk$|^uk2$|^us$/) {
5460 while($mirror !~ m/^freedb$|^at$|^au$|^bg$|^ca$|^es$|^fi$|
5461 |^lu$|^no$|^uk$|^us$/) {
5462 print "host mirror ($mirror) not valid!\nenter freedb, ",
5463 "at, au, ca, es, fi, fr, jp, jp2, ru, uk, uk2 or us: ";
5468 ########################################################################
5470 # Answer to question.
5474 while($ans !~ /^y|^n/) {
5475 print "Do you want to enter a different ".$_[0]." than ".$_[1];
5476 print "? [y/n], (n): ";
5488 ########################################################################
5490 # Check quality passed from command line for lame, oggenc, flac, faac.
5495 @pquality = defined unless(@pquality);
5497 # Remember, if the quality is defined via -q/--quality switch
5498 # on the command line, the array consists of a comma separated
5499 # string in the first entry only!
5501 if($pquality[0] =~ /\d/) {
5502 # Why this joining and splitting? Because the whole string is in
5503 # $quality[0]! But why joining? Because we can come from CLI! In
5504 # this case we need to make it identical to the way it comes from
5505 # config file, i.e. as comma separated string in the first entry.
5506 @quality = split(/,/, join(',', @pquality));
5508 elsif("@quality" eq "5 3 5 100 0 5") {
5511 # If no coder-array has been passed, we do not know to which encoder
5512 # each quality-entry belongs to. NOTE, we've not yet read the config.
5513 # So we need to read the config file to check if there is a unusual
5514 # order of encoders. In this way, this subroutine will ask the
5515 # correct questions and not mess up the encoders if qualities are
5516 # wrong, supposing the operator is aware about an unusual order!
5517 if(!@pcoder && -r "$ripdir") {
5518 open(CONF, "$ripdir");
5519 my @conflines = <CONF>;
5521 @pcoder = grep(s/^coder=//, @conflines) unless(@pcoder);
5523 if($pcoder[0] =~ /^\d/) {
5524 @coder = split(/,/, join(',',@pcoder));
5528 # Actually check only those qualities needed, i.e. for chosen
5530 # NOTE again: the $qualame etc. variables hold the string needed for
5531 # the config, it might be a comma separated string. When passing
5532 # commands, we should not use them, but things like "$quality[$c]"
5541 for(my $c=0; $c<=$#coder; $c++) {
5542 if($coder[$c] == 0 && !defined($quality[$c])) {
5543 $quality[$c] = 5; # prevent warnings.
5545 elsif($coder[$c] == 0 && $quality[$c] ne "off") {
5546 $quality[$c] = 5 unless($quality[$c] =~ /\d/);
5547 while($quality[$c] > 9) {
5548 print "\nThe quality $quality[$c] is not valid for Lame!",
5549 "\nPlease enter a different quality (0 = best),",
5551 $quality[$c] = <STDIN>;
5554 $qualame .= ";" . $quality[$c];
5556 elsif($coder[$c] == 0 && $quality[$c] eq "off") {
5557 $qualame .= ";" . $quality[$c];
5559 # Done with lame, do the other encoders.
5560 if($coder[$c] == 1 && !defined($quality[$c])) {
5561 $quality[$c] = 3; # prevent warnings.
5563 elsif($coder[$c] == 1 && $quality[$c] ne "off") {
5564 $quality[$c] = 3 unless($quality[$c] =~ /\d/);
5565 while($quality[$c] > 10 || $quality[$c] == 0) {
5566 print "\nThe quality $quality[$c] is not valid for Oggenc!",
5567 "\nPlease enter a different quality (10 = best),",
5569 $quality[$c] = <STDIN>;
5572 $qualoggenc .= "," . $quality[$c];
5574 elsif($coder[$c] == 1 && $quality[$c] eq "off") {
5575 $qualoggenc .= "," . $quality[$c];
5577 if($coder[$c] == 2 && !defined($quality[$c])) {
5578 $quality[$c] = 5; # prevent warnings.
5580 elsif($coder[$c] == 2 && $quality[$c] ne "off") {
5581 $quality[$c] = 5 unless($quality[$c] =~ /\d/);
5582 while($quality[$c] > 8) {
5583 print "\nThe compression level $quality[$c] is not valid ",
5585 "\nPlease enter a different compression level ",
5586 "(0 = lowest), [0-8]: ";
5587 $quality[$c] = <STDIN>;
5590 $quaflac = $quaflac . "," . $quality[$c];
5592 elsif($coder[$c] == 2 && $quality[$c] eq "off") {
5593 $quaflac .= "," . $quality[$c];
5595 if($coder[$c] == 3 && !defined($quality[$c])) {
5596 $quality[$c] = 100; # prevent warnings.
5598 elsif($coder[$c] == 3 && $quality[$c] ne "off") {
5599 $quality[$c] = 100 unless($quality[$c] =~ /\d/);
5600 while($quality[$c] > 500 || $quality[$c] < 10) {
5601 print "\nThe quality $quality[$c] is not valid for Faac!",
5602 "\nPlease enter a different quality (500 = max), ",
5604 $quality[$c] = <STDIN>;
5607 $quafaac .= "," . $quality[$c];
5609 elsif($coder[$c] == 3 && $quality[$c] eq "off") {
5610 $quafaac .= "," . $quality[$c];
5612 if($coder[$c] == 4 && !defined($quality[$c])) {
5613 $quality[$c] = 0; # prevent warnings.
5615 elsif($coder[$c] == 4 && $quality[$c] ne "off") {
5616 $quality[$c] = 0 unless($quality[$c] =~ /\d/);
5617 # Any info about mp4als "qualities", i. e. compression levels?
5618 $quamp4als .= "," . $quality[$c];
5620 elsif($coder[$c] == 4 && $quality[$c] eq "off") {
5621 $quamp4als .= "," . $quality[$c];
5623 if($coder[$c] == 5 && !defined($quality[$c])) {
5624 $quality[$c] = 5; # prevent warnings.
5626 elsif($coder[$c] == 5 && $quality[$c] ne "off") {
5627 $quality[$c] = 5 unless($quality[$c] =~ /\d/);
5628 while($quality[$c] > 10 || $quality[$c] < 0) {
5629 print "\nThe quality $quality[$c] is not valid for $musenc!",
5630 "\nPlease enter a different quality (10 = max), ",
5632 $quality[$c] = <STDIN>;
5635 $quamuse .= "," . $quality[$c];
5637 elsif($coder[$c] == 5 && $quality[$c] eq "off") {
5638 $quamuse .= "," . $quality[$c];
5640 if($coder[$c] == 6 && !defined($quality[$c])) {
5641 $quality[$c] = " "; # prevent warnings.
5643 if($coder[$c] == 7 && !defined($quality[$c])) {
5644 $quality[$c] = " "; # prevent warnings.
5648 $qualoggenc =~ s/^,//;
5652 # Small problem if only option --savenew is used, with no other
5653 # option at all. Then, qualame has default value (because Lame is
5654 # default encoder), but all other qualities are empty!
5655 $qualoggenc = 3 unless($qualoggenc);
5656 $quaflac = 5 unless($quaflac);
5657 $quafaac = 100 unless($quafaac);
5658 $quamp4als = 0 unless($quamp4als);
5659 $quamuse = 5 unless($quamuse);
5660 # NOTE: corrections have been done on quality array, not pquality.
5661 # If pquality was passed, we need to apply corrections and save it
5662 # the same way as if it had been passed on command line.
5664 my $pquality = join(',', @quality);
5665 $pquality =~ s/(,\s)*$//;
5667 $pquality[0] = $pquality;
5670 ########################################################################
5672 # Check bitrate for Lame only if vbr is wanted.
5675 while($vbrmode ne "new" && $vbrmode ne "old") {
5676 print "\nFor vbr using Lame choose *new* or *old*! (new): ";
5679 $vbrmode = "new" if($vbrmode eq "");
5682 ########################################################################
5684 # Check preset for Lame only.
5687 if($vbrmode eq "new") {
5688 $preset = "fast " . $preset;
5691 ########################################################################
5693 # Check if there is an other than $cddev which has a CD if no --device
5697 # Try to get a list of possible CD devices.
5698 open(DEV, "/etc/fstab");
5701 @dev = grep(/^\s*\/dev/, @dev);
5702 @dev = grep(!/^\s*\/dev\/[f|h]d/, @dev);
5703 @dev = grep(!/sd/, @dev);
5706 my @line = split(/\s/, $_);
5708 push(@devlist, $line[0]) unless($line[0] =~ /by-id/);
5710 # First check some default addresses.
5711 if(open(CD, "$cddev")) {
5715 elsif(open(CD, "/dev/cdrecorder")) {
5716 $cddev = "/dev/cdrecorder";
5719 elsif(open(CD, "/dev/dvd")) {
5720 $cddev = "/dev/dvd";
5723 elsif(open(CD, "/dev/sr0")) {
5724 $cddev = "/dev/sr0";
5727 elsif(open(CD, "/dev/sr1")) {
5728 $cddev = "/dev/sr1";
5732 foreach (@devlist) {
5733 if(open(CD, "$_")) {
5743 # On a notebook, the tray can't be closed automatically!
5744 # Print error message and retry detection.
5746 print "Is there a CD and the tray of the device closed?\n";
5747 print "Pausing 12 seconds.\n";
5749 foreach (@devlist) {
5750 if(open(CD, "$_")) {
5758 print "Could not detect CD device! The default /dev/cdrom ";
5759 print "device will be used.\n";
5760 $cddev = "/dev/cdrom";
5764 ########################################################################
5766 # Check bitrate if bitrate is not zero.
5769 while($bitrate !~ m/^32$|^40$|^48$|^56$|^64$|^80$|^96$|^112$|^128$|
5770 |^160$|^192$|^224$|^256$|^320$|^off$/) {
5771 print "\nBitrate should be one of the following numbers or ";
5772 print "\"off\"! Please Enter";
5773 print "\n32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, ";
5774 print "256 or 320: (128) \n";
5777 if($bitrate eq "") {
5782 ########################################################################
5784 # Check protocol level for CDDB query.
5788 print "Protocol level for CDDB query should be less-equal 6!\n";
5789 print "Enter an other value for protocol level (6): ";
5792 $proto = 6 if($proto eq "");
5795 ########################################################################
5797 # Check and clean the coder array.
5801 # Reset $lameflag set by past invocation of check_coder() except if
5802 # lame is not installed ($lameflag == -1).
5803 $lameflag = 0 if($lameflag > 0);
5805 # Create encoder array if passed or read from config file.
5806 # Remember, if we come from reading the config file, the array
5807 # consists of a comma separated string in the first entry only!
5809 @coder = split(/,/, join(',', @pcoder));
5812 # This can happen because this subroutine is called before config
5813 # file is read! So @pcoder can be empty and @coder will be filled
5814 # with default value for Lame. Do we need this?
5815 @coder = split(/,/, join(',', @coder));
5820 @ffmpegsuf = split(/,/, $ffmpegsuffix);
5823 # Check if there is an entry > 7.
5824 for(my $c = 0; $c <= $#coder; $c++) {
5825 if($coder[$c] > 7) {
5826 die "Encoder number $coder[$c] does not yet exist, ",
5827 "please enter\n0 for Lame, 1 for Oggenc, 2 for Flac ",
5828 "3 for Faac,\n 4 for mp4als, 5 for Musepack, ",
5829 "6 for Wavpack or 7 for ffmpeg!\n\n";
5830 # TODO: splice that entry out, don't die!
5832 $lameflag = 1 if($coder[$c] == 0);
5833 $oggflag = 1 if($coder[$c] == 1);
5834 $wvpflag = 1 if($coder[$c] == 6);
5835 $suffix[$c] = "mp3" if($coder[$c] == 0);
5836 $suffix[$c] = "ogg" if($coder[$c] == 1);
5837 $suffix[$c] = "flac" if($coder[$c] == 2);
5838 $suffix[$c] = "m4a" if($coder[$c] == 3);
5839 $suffix[$c] = "m4b" if($coder[$c] == 3 && $book == 1);
5840 $suffix[$c] = "als" if($coder[$c] == 4);
5841 $suffix[$c] = "mpc" if($coder[$c] == 5);
5842 $suffix[$c] = "wv" if($coder[$c] == 6);
5843 if($coder[$c] == 7) {
5844 $suffix[$c] = shift @ffmpegsuf;
5847 # Use comma separated string to write the encoder array to the
5849 $wcoder = join(',', @coder);
5851 ########################################################################
5853 # Over or re-write the config file (depends on option savenew or save).
5855 # New options step 10: Add description of new option to config file.
5858 $confdir = "$homedir/.ripit" if($confdir eq "");
5859 log_system("mkdir -m 0755 -p $confdir")
5860 or die "Can not create directory $confdir: $!\n";
5861 # Remember: $ripdir is the full path including config file name.
5862 rename("$confdir/$confname","$confdir/$confname.old")
5863 if(-r "$confdir/$confname");
5864 open(CONF, "> $confdir/$confname")
5865 or die "Can not write to $confdir/$confname: $!\n";
5869 # RipIT $version configuration file.
5871 # For further information on ripit configuration / parameters
5872 # and examples see the manpage or the README provided with ripit
5873 # or type ripit --help .
5878 # Ripping device & path.
5881 # cddevice: Define ripping device if other than /dev/cdrom.
5882 # Default: /dev/cdrom
5886 # scsidevice: Device name for special devices if the non ripping
5887 # commands should be executed on a different device node. This might
5888 # be useful for some old SCSI devices. If not set the cddevice will
5890 # Example: /dev/sr18
5893 scsidevice=$scsi_cddev
5895 # output: Path for audio files. If not set, \$HOME will be used.
5900 # directory permissions: Permissions for directories.
5903 dpermission=$dpermission
5905 # file permissions: Permissions for sound and log files.
5906 # If not set, uses the default system settings.
5909 fpermission=$fpermission
5917 # ripper: select CD ripper
5923 # Default: cdparanoia
5927 # ripopt: User definable options for the CD ripper.
5932 # span: Rip only part of a single track or the merged track-interval.
5933 # Possible values: any in the format hh:mm:ss.ff-hh:mm:ss.ff
5934 # Example: rip first 30s of each track: 0-30
5939 # paranoia: Turn \"paranoia\" on or off for dagrab and cdparanoia.
5940 # Possible values: 0 - no paranoia, 1 - use paranoia
5941 # 2 - switch paranoia off if ripping fails on one
5942 # track and retry this track without paranoia
5943 # Default: 1 - use paranoia
5947 # ghost: Analyze the wavs for possible gaps, split the wav into
5948 # chunks of sound and delete blank tracks.
5949 # Possible values: 0 - off, 1 - on
5954 # prepend: Enlarge the the chunk of sound by a number of
5955 # seconds at the beginning (if possible).
5956 # Possible values: any positive number and zero; precision in
5957 # tenths of seconds. Be aware of low numbers, especially when
5958 # using option cdcue.
5963 # extend: Enlarge the the chunk of sound by a number of
5964 # seconds at the end (if possible).
5965 # Possible values: any positive number and zero; precision in
5966 # tenths of seconds. Be aware of low numbers.
5971 # resume: Resume a previously started session.
5972 # Possible values: 0 - off, 1 - on
5977 # overwrite: Default behaviour of Ripit is not to overwrite existing
5978 # directories, a suffix will be added if directory name exists.
5979 # Use option overwrite to prevent this and either overwrite a previous
5980 # rip or force Ripit to quit or even eject the disc. If ejection is
5981 # chosen, the disc will be ejected even if option eject has not been
5983 # Possible values: n - off, y - on,
5984 # q - quit, e - quit and force ejection
5987 overwrite=$overwrite
5995 # encode: Encode the wavs.
5996 # Possible values: 0 - off, 1 - on
6001 # coder: Select encoders for audio files:
6006 # 4 - mp4als (als or mp4)
6007 # 5 - Musepack (mpc)
6010 # Multiple encoders can be selected by giving a comma separated list
6011 # Example: coder=0,0,1,2 encodes CD twice to mp3, ogg and flac files
6018 # lame (mp3) encoder options
6021 # qualame: Sets audio quality for lame encoder in cbr (lame-option -q)
6022 # and vbr (lame-option -V) mode, comma separated list if encoder is
6023 # used several times.
6024 # Possible values: 0...9, off
6025 # 0: highest quality
6027 # Can be set to \"off\" if all options are passed to --lameopt.
6028 # Example: qualame=off,off
6029 # Note: default value is the same for cbr and vbr,
6030 # although vbr-default should be 4.
6035 # lameopt: Additional options for lame encoder,
6036 # use a comma separated list if encoder is used several times.
6037 # Example: lameopt=-b 128,--preset extreme
6042 # vbrmode: Enable variable bitrate for lame encoder.
6043 # Possible values: \"old\" or \"new\"
6048 # bitrate: Sets bitrate for lame encoder.
6049 # Possible values: 32...320, off
6050 # Should be set to \"off\" if vbr is used
6055 # maxrate: Sets maximum bitrate for lame (when using vbr) and oggenc.
6056 # Possible values: 0 - off, 32...320
6061 # preset: Use lame presets. To set the \"fast\" switch, use --vbrmode new.
6062 # Possible values: medium, standard, extreme, insane
6075 # oggenc (ogg) encoder options
6078 # qualoggenc: Sets audio quality for oggenc.
6079 # Possible values: 1..10, off
6081 # 10: highest quality
6082 # Can be set to \"off\"
6085 qualoggenc=$qualoggenc
6087 # oggencopt: Additional options for oggenc,
6088 # use a comma separated list if encoder is used several times.
6091 oggencopt=$oggencopt
6095 # flac (lossless) encoder options
6098 # quaflac: Sets audio compression for flac encoder
6099 # Possible values: 0...8, off
6100 # 0: lowest compression
6101 # 8: highest compression
6102 # Can be set to \"off\"
6107 # flacopt: Additional options for flac encoder,
6108 # use a comma separated list if encoder is used several times.
6109 # Example of single encoder:
6110 # flacopt=--padding=8212 --replay-gain
6111 # Example of multiple encoder:
6112 # flacopt=--padding=8212 --replay-gain,--padding=8212
6113 # Note: If using the --replay-gain option the padding option
6114 # is recommended, otherwise all padding might be lost.
6121 # faac (m4a) encoder options
6124 # quafaac: Sets audio quality for faac encoder
6125 # Possible values: 10...500, off
6126 # 10: lowest quality
6127 # 500: highest quality
6128 # Can be set to \"off\"
6133 # faacopt: Additional options for faac encoder,
6134 # comma separated list if encoder is used several times.
6141 # mp4als (als or mp4) encoder options
6144 # quamp4als: Set audio compression level for mp4als.
6145 # Note: Options that influence compression and speed
6146 # should be used in the mp4als options below.
6149 quamp4als=$quamp4als
6151 # mp4alsopt: Additional options for mp4als encoder,
6152 # comma separated list if encoder is used several times.
6153 # Example: -MP4 to allow tagging, mandatory.
6154 # Example: -a -o30 for faster speed.
6157 mp4alsopt=$mp4alsopt
6161 # Musepack (mpc) encoder options
6164 # musenc: The encoder name on the command line
6165 # Possible values: any
6166 # Example: musenc=mppenc for older versions
6171 # quamuse: Sets audio quality for Musepack encoder
6172 # Possible values: 0...10, off
6174 # 10: highest quality
6175 # Can be set to \"off\"
6180 # museopt: Additional options for Musepack encoder,
6181 # use a comma separated list if encoder is used several times.
6188 # Wavpack (wv) encoder options
6191 # wavpacopt: Additional options for Wavpack encoder,
6192 # use a comma separated list if encoder is used several times.
6196 wavpacopt=$wavpacopt
6200 #ffmpeg encoder options
6203 # ffmpegopt: Additional options for ffmpeg,
6204 # use a comma separated list if encoder is used several times.
6205 # Example if ffmpeg is used twice: -acodec alac,-acodec wmav2
6208 ffmpegopt=$ffmpegopt
6210 # ffmpegsuffix: Suffix to be used for ffmpeg,
6211 # use a comma separated list if encoder is used several times.
6212 # Example if ffmpeg is used twice: m4a,wma
6215 ffmpegsuffix=$ffmpegsuffix
6220 # Trackname and directory template
6223 # dirtemplate: Template for directory structure
6224 # The template can be created using any legal
6225 # character, including slashes (/) for multi-level
6226 # directory-trees, and the following variables:
6238 # The variable \$iletter is the initial letter of
6239 # the artist variable, the \$quality is the quality
6240 # according to the encoding format defined by \$suffix.
6241 # The variable \$quality reflects the encoder options,
6242 # not the arguments of option --quality which may be set
6243 # to off. The variable \$trackno is the total number of tracks
6246 # dirtemplate is an array, for each encoder a different
6247 # dirtemplate may be defined (i. e. for each encoder state
6248 # a line starting with dirtemplate=...).
6251 # dirtemplate=\"\$suffix/hard_path/\$iletter/\$artist/\$year - \$album\"
6253 # The double quotes (\") are mandatory!
6254 # Default: \"\$artist - \$album\"
6256 print CONF "dirtemplate=$_\n" foreach(@dirtemplate);
6258 # tracktemplate: Template for track names
6259 # \"tracktemplate\" is used similarly to \"dirtemplate\"
6260 # Default: \"\$tracknum \$trackname\"
6262 tracktemplate=$tracktemplate
6264 # trackoffset: Add an offset to the track counter (\$tracknum)
6265 # Possible values: any integer
6268 trackoffset=$trackoffset
6270 # infolog: Log certain operations to file
6271 # (e.g. system calls, creation of dirs/files)
6272 # Possible values: filename (full path, no ~ here!)
6277 # lowercase: Convert filenames to lowercase
6278 # Possible values: 0 - off, 1 - on
6281 lowercase=$lowercase
6283 # uppercasefirst: Convert filenames and tags to uppercase first,
6284 # not recommended. To be used on the command line only if CDDB entry
6286 # Possible values: 0 - off, 1 - on
6289 uppercasefirst=$uppercasefirst
6291 # underscore: Replace blanks in filenames with underscores
6292 # Possible values: 0 - off, 1 - on
6295 underscore=$underscore
6297 # chars: Exclude special characters in file names and path.
6298 # Note: following characters will always be purged:
6299 # ; > < \" and \\015 .
6300 # Side note: if calling this option on the command line without
6301 # argument, following characters will be purged: |\\:*?\$ plus
6302 # blanks and periods at beginning and end of file names and directories.
6303 # This is identical to the word NTFS passed as argument to the command
6304 # line or stated here in the config file. The word HFS will purge colons
6305 # only plus blanks and periods at beginning of file names and
6308 # No need to escape the special characters here in the config file.
6309 # Possible values: HFS, NTFS, none, any (?)
6314 # playlist: Create m3u playlist with or without the full path
6316 # Possible values: 0 - off,
6317 # 1 - on with full path
6318 # 2 - on with no path (filename only)
6319 # Default: on (with full path)
6326 # Audio file tagging
6329 # year-tag: State a year (mp3, m4a) or a date (ogg, flac) tag.
6330 # Possible values: integer
6335 # comment-tag: State a comment (mp3, m4a, mpc) or a
6336 # description (ogg, flac) tag. To write the cddbid used for freedb
6337 # or the MusicBrainz discid into the comment, use the word \"cddbid\"
6339 # Possible values: discid, cddbid or any string
6344 # mp3tags: Additional tags for mp3 not passed by the encoder.
6345 # Example: Force a unofficial compilation frame when using within
6346 # a certain player: TCMP=1
6347 # Note: option is an array, for each additional frame/tag to be added
6348 # state the option once.
6349 # Possible values: none, any
6354 print CONF "mp3tags=$_\n";
6358 print CONF "mp3tags=\n";
6361 # utftag: Use Lame-tags in UTF-8 or convert them
6362 # (but not the filenames) from Unicode to ISO8859-1.
6363 # Use when your mp3-audio player doesn't support Unicode tags.
6364 # Recommended with Lame.
6365 # Possible values: 0 - off, 1 - on
6370 # coverart: Add cover image to metadata of encoded file if possible.
6371 # Note: The cover must be available when encoding starts, one might
6372 # want to use option --precmd to execute a script for downloading and
6373 # preparing a cover. Argument is a list in same order as encoders with
6374 # values 0 (no coverart) or 1 (add coverart) for each encoder.
6376 # Possible values: 0 - off, 1 - on
6381 # coverpath: Path where the cover can be found.
6382 # Example: ../thumb.png
6383 # Possible values: string, none
6386 coverpath=$coverpath
6388 # copycover: Copy a cover (or any other file) to all
6389 # directories containing encoded files. Useful e.g. when using Amarok.
6390 # Example: \"\$wavdir/cover.jpg\"
6391 # Possible values: none - off, absolute path to image
6394 copycover=$copycover
6396 # vatag: Analyze tracknames for \"various artists\" style and split
6397 # the metadata in case one of the delimiters (colon, hyphen, slash or
6398 # parenthesis) are found. Use unpair numbers for the scheme
6399 # \"artist ? tracktitle\" and pair numbers in the opposite case.
6400 # The artist will be compared to the argument of option --vastring
6401 # (see below). If the artist must be like vastring and each track have a
6402 # delimiter, use 1 (2), if the artist must be like vastring while only
6403 # some tracks contain the delimiter, use 3 (4), if no restrictions
6404 # apply for the artist but all tracknames must have a delimiter, use
6405 # 5 (6) and finally, if only a few tracks contain a delimiter to be
6406 # used as splitting point, set vatag to 7 (8).
6408 # Possible values: 0 - off, 1, 2, 3, 4, 5, 6, 7, 8
6413 # vastring: the string (regular expression) that defines the
6414 # \"various artists\" style
6415 # Example: Varios|VA
6416 # Possible values: string, none
6417 # Default: \\bVA\\b|Variou*s|Various\\sArtists
6421 # mp3gain: Add album gain tags to mp3 files using the appropriate
6422 # command with options and arguments but without infiles.
6423 # Example: mp3gain -a -c -q -s i
6428 # vorbgain: Add album gain tags to ogg files using the appropriate
6429 # command with options and arguments but without infiles.
6430 # Example: vorbisgain -a -q
6435 # flacgain: Add album gain tags to flac files using the appropriate
6436 # command with options and arguments but without infiles.
6437 # Example: metaflac --add-replay-gain
6442 # aacgain: Add album gain tags to mp4 or m4a files using the appropriate
6443 # command with options and arguments but without infiles.
6444 # Example: aacgain -a -c -q
6449 # mpcgain: Add album gain tags to mpc files using the appropriate
6450 # command with options and arguments but without infiles.
6456 # wvgain: Add album gain tags to wv files using the appropriate
6457 # command with options and arguments but without infiles.
6458 # Example: wvgain -a -q
6469 # mb: Access MusicBrainz DB via WebService::MusicBrainz module instead
6470 # of the http protocol (see below).
6471 # Possible values: 0 - off, 1 - on
6476 # CDDBHOST: Specifies the CDDB server
6477 # Possible values: freedb.org, freedb2.org or musicbrainz.org
6478 # Note: Full name of the server used is \$mirror.\$CDDBHOST, except for
6479 # freedb2.org (no mirror) and musicbrainz.org has freedb as default
6481 # E.g. default server is freedb.freedb.org
6482 # Default: freedb.org
6486 # mirror: Selects freedb mirror
6487 # Possible values: \"freedb\" or any freedb mirrors
6488 # See www.freedb.org for mirror list
6489 # Note: Full name of the server used is \$mirror.\$CDDBHOST
6490 # E.g., default server is freedb.freedb.org
6495 # transfer: Set transfer mode for cddb queries
6496 # Possible values: cddb, http
6497 # Note: CDDB servers freedb2.org and musicbrainz.org may need transfer
6503 # proto: Set CDDP protocol level
6504 # Possible values: 5, 6
6505 # Protocol level 6 supports Unicode (UTF-8)
6510 # proxy: Address of http-proxy, if needed.
6515 # mailad: Mail address for cddb submissions.
6516 # Possible values: Valid user email address for submitting cddb entries
6521 # archive: Read and save cddb data on local machine.
6522 # Possible values: 0 - off, 1 - on
6527 # submission: Submit new or edited cddb entries to freeCDDB.
6528 # Possible values: 0 - off, 1 - on
6531 submission=$submission
6533 # interaction: Turns on or off user interaction in cddb dialog and
6535 # Possible values: 0 - off, 1 - on
6538 interaction=$interaction
6540 # isrc: detect track iscrs using icedax and submit them to Musicbrainz
6541 # if login info is provided. Please check if the device in use is
6542 # able to read correct ISRCs and submit them if found.
6543 # Possible values: 0 - off, 1 - on
6548 # mbname: login name to Musicbrainz.org
6549 # Possible values: string
6554 # mbpass: password to Musicbrainz.org
6555 # Possible values: string
6566 # lcd: Use lcdproc to display status on LCD
6567 # Possible values: 0 - off, 1 - on
6572 # lcdhost: Specify the lcdproc host
6573 # Default: localhost
6577 # lcdport: Specify port number for $lcdhost
6585 # Distributed ripping options
6588 # sshlist: Comma separated list of remote machines ripit shall use
6589 # for encoding. The output path must be the same for all machines.
6590 # Specify the login (login\@machine) only if not the
6591 # same for the remote machine. Else just state the
6597 # scp: Copy files to encode to the remote machine.
6598 # Use if the fs can not be accessed on the remote machines
6599 # Possible values: 0 - off, 1 - on
6604 # local: Turn off encoding on local machine, e.g. use only remote
6606 # Possible values: 0 - off, 1 - on
6607 # Example: local=0 (off) turns off encoding on the
6619 # verbosity: Run silent (do not output comments, status etc.) (0), with
6620 # minimal (1), normal without encoder msgs (2), normal (3), verbose (4)
6621 # or extremely verbose (5).
6622 # Possible values: 0...5
6623 # Default: 3 - normal
6627 # eject: Eject cd after finishing encoding.
6628 # Possible values: 0 - off, 1 - on
6633 # ejectcmd: Command used to eject and close CD tray.
6634 # Possible values: string
6635 # Example: /usr/sbin/cdcontrol for FreeBSD
6640 # ejectopt: Options to command used to eject or close CD.
6641 # Possible values: string or \"{cddev}\" to design the CD
6643 # Note: Don't use options -t / close or eject,
6644 # RipIT knows when to eject or load the tray
6649 # quitnodb: Give up CD if no CDDB entry found.
6650 # Useful if option --loop or --nointeraction are on.
6651 # Default behaviour is to let operator enter data or to use default
6652 # artist, album and track names.
6653 # Possible values: 0 - off, 1 - on
6658 # execmd: Execute a command when done with ripping. Quote the command
6660 # Note: The same variables as in the dirtemplate can be used. When
6661 # using MusicBrainz one might want to use \$cd{asin} to get the ASIN
6663 # Possible values: none - off, string - on
6664 # Example: execmd=\"add_db -a \\\"\$artist\\\" -r \\\"\$album\\\"\"
6669 # precmd: Execute a command before starting to rip. Quote the command
6671 # Note: The same variables as in the dirtemplate can be used. When
6672 # using MusicBrainz one might want to use \$cd{asin} to get the ASIN
6674 # Possible values: none - off, string - on
6675 # Example: precmd=\"get_cover -a \\\"\$artist\\\" -r \\\"\$album\\\" -o \\\"\$wavdir\\\" -t \\\"\$trackno\\\"\"
6680 # book: Create an audiobook, i. e. merge all tracks into one single
6681 # file, option --ghost will be switched off and file suffix will be
6682 # m4b. Make sure to use encoder faac, ripit will not check that.
6683 # A chapter file will be written for chapter marks.
6684 # Possible values: 0 - off, 1 - on
6689 # loop: Continue with a new CD when the previous one is done.
6690 # Option --eject will be forced. To start ripping process immediately
6691 # after ejection of previous disc, use experimental argument 2. Ripit
6692 # will restart as child process, one might see the prompt and it will
6693 # be necessary to manually terminate the process! Use with caution!
6694 # Possible values: 0 - off, 1 - on, 2 - immediate restart, experimental
6699 # halt: Powers off machine after finishing encoding.
6700 # Possible values: 0 - off, 1 - on
6705 # nice: Sets \"nice\" value for the encoding process.
6706 # Possible values: 0..19 for normal users,
6707 # -20..19 for user \"root\"
6712 # nicerip: Sets \"nice\" value for the ripping process.
6713 # Possible values: 0..19 for normal users,
6714 # -20..19 for user \"root\"
6719 # threads: Comma separated list of numbers giving maximum
6720 # of allowed encoder processes to run at the same time
6721 # (on each machine when using sshlist).
6722 # Possible values: comma separated integers
6727 # md5sum: Create file with md5sums for each type of sound files.
6728 # Possible values: 0 - off, 1 - on
6733 # wav: Don't delete wave-files after encoding.
6734 # Possible values: 0 - off, 1 - on
6739 # normalize: Normalizes the wave-files to a given dB-value
6741 # See http://normalize.nongnu.org for details.
6742 # Possible values: 0 - off, 1 - on
6745 normalize=$normalize
6747 # normcmd: Command to be used to normalize.
6748 # Possible values: string
6749 # Example: normalize-audio (when using Debian)
6750 # Default: normalize
6754 # normopt: Options to pass to normalize
6755 # Possible values: -a -nndB : Normalize to -nn dB, default is -12dB,
6756 # Value range: All values <= 0dB
6757 # Example : normalize -a -20dB *.wav
6758 # -b : Batch mode - loudness differences
6759 # between individual tracks of a CD are
6761 # -m : Mix mode - all track are normalized to
6763 # -v : Verbose operation
6764 # -q : Quiet operation
6765 # For further options see normalize documentation.
6767 # The -v option will be added by default according to RipITs verbosity
6771 # cdtoc: Create a toc file to burn the wavs with
6772 # cd-text using cdrdao or cdrecord (in dao mode).
6773 # Possible values: 0 - off, 1 - on
6778 # inf: Create inf files to burn the wavs with
6779 # cd-text using wodim or cdrecord (in dao mode).
6780 # Possible values: 0 - off, 1 - on
6785 # cdcue: Create a cue file to burn the wavs with cd-text.
6786 # Possible values: 0 - off, 1 - on, 2 - on (experimental fallback)
6787 # Note: Use value 2 only if for whatever reason value 1 should fail.
6794 ########################################################################
6796 # Read the config file, take the parameters only if NOT yet defined!
6798 # New options step 11: Read the new options from config file. Replicate
6799 # one of the 2-liners starting with chomp.
6802 $ripdir = $confdir . "/" . $confname if($confdir ne "");
6804 $ripdir = $homedir . "/.ripit/config" unless(-r "$ripdir");
6805 $ripdir = "/etc/ripit/config" unless(-r "$ripdir");
6807 open(CONF, "$ripdir") or
6808 print "Can not read config file in $ripdir: $!\n";
6809 my @conflines = <CONF>;
6811 my @confver = grep(s/^# RipIT //, @conflines);
6812 @confver = split(/ /, $confver[0]) if($confver[0] =~ /^\d/);
6813 my $confver = $confver[0] if($confver[0] =~ /^\d/);
6814 $confver = 0 unless($confver);
6816 if($version ne $confver && $savepara == 0) {
6817 $verbose = 3 if($verbose <= 1);
6818 print "\nPlease update your config-file with option --save";
6819 print "\nto ensure correct settings! Pausing 3 seconds!\n\n";
6821 # In older configs the option var was either set to zero or
6822 # one. In the case one wanted to replace characters, ignore
6823 # for simplicity! User should update! This line and the elsif
6824 # part below will go away with version 3.8.0.
6825 grep(s/^chars=[01]\s*$/chars=/, @conflines);
6828 elsif($version ne $confver) {
6829 grep(s/^chars=[01]\s*$/chars=/, @conflines);
6831 chomp($archive = join(' ', grep(s/^archive=//, @conflines)))
6832 unless defined $parchive;
6833 chomp($bitrate = join(' ', grep(s/^bitrate=//, @conflines)))
6835 chomp($book = join(' ', grep(s/^book=//, @conflines)))
6837 chomp($maxrate = join(' ', grep(s/^maxrate=//, @conflines)))
6839 chomp($cddev = join(' ', grep(s/^cddevice=//, @conflines)))
6841 chomp($scsi_cddev = join(' ', grep(s/^scsidevice=//, @conflines)))
6842 unless($pscsi_cddev);
6843 chomp($cdtoc = join('', grep(s/^cdtoc=//, @conflines)))
6845 chomp($cdcue = join('', grep(s/^cdcue=//, @conflines)))
6847 chomp($chars = join('', grep(s/^chars=//, @conflines)))
6849 chomp($commentag = join('', grep(s/^comment=//, @conflines)))
6850 unless($pcommentag);
6851 chomp($CDDB_HOST = join('', grep(s/^CDDBHOST=//, @conflines)))
6852 unless($PCDDB_HOST);
6853 @pcoder = grep(s/^coder=//, @conflines) unless(@pcoder);
6854 # NOTE: all coders are in array entry $pcoder[0]!
6855 # NOTE: we have to fill the wcoder (w=write) variable!
6856 $wcoder = $pcoder[0] if(@pcoder);
6858 @dirtemplate = grep(s/^dirtemplate=//, @conflines)
6859 unless($pdirtemplate[0]);
6860 chomp $_ foreach(@dirtemplate);
6861 chomp($dpermission = join('', grep(s/^dpermission=//, @conflines)))
6862 unless($pdpermission);
6863 chomp($eject = join('', grep(s/^eject=//, @conflines)))
6864 unless defined $peject;
6865 chomp($ejectcmd = join('', grep(s/^ejectcmd=//, @conflines)))
6866 unless defined $pejectcmd;
6867 chomp($ejectopt = join('', grep(s/^ejectopt=//, @conflines)))
6868 unless defined $pejectopt;
6869 chomp($encode = join('', grep(s/^encode=//, @conflines)))
6870 unless defined $pencode;
6871 chomp($extend = join('', grep(s/^extend=//, @conflines)))
6872 unless defined $pextend;
6873 chomp($execmd = join('', grep(s/^execmd=//, @conflines)))
6874 unless defined $pexecmd;
6875 chomp($precmd = join('', grep(s/^precmd=//, @conflines)))
6876 unless defined $pprecmd;
6877 chomp($fpermission = join('', grep(s/^fpermission=//, @conflines)))
6878 unless($pfpermission);
6879 chomp($ghost = join('', grep(s/^ghost=//, @conflines)))
6880 unless defined $pghost;
6881 chomp($halt = join('', grep(s/^halt=//, @conflines)))
6883 chomp($inf = join('', grep(s/^inf=//, @conflines)))
6885 chomp($infolog = join('', grep(s/^infolog=//, @conflines)))
6887 chomp($interaction = join('', grep(s/^interaction=//, @conflines)))
6888 unless defined $pinteraction;
6889 chomp($isrc = join('', grep(s/^isrc=//, @conflines)))
6890 unless defined $pisrc;
6891 chomp($lcd = join('', grep(s/^lcd=//, @conflines)))
6892 unless defined $plcd;
6893 chomp($lcdhost = join('', grep(s/^lcdhost=//, @conflines)))
6895 chomp($lcdport = join('', grep(s/^lcdport=//, @conflines)))
6897 chomp($local = join('', grep(s/^local=//, @conflines)))
6898 unless defined $plocal;
6899 chomp($loop = join('', grep(s/^loop=//, @conflines)))
6900 unless defined $ploop;
6901 chomp($lowercase = join('', grep(s/^lowercase=//, @conflines)))
6902 unless defined $plowercase;
6903 chomp($uppercasefirst = join('', grep(s/^uppercasefirst=//, @conflines)))
6904 unless defined $puppercasefirst;
6905 chomp($mailad = join('', grep(s/^mailad=//, @conflines)))
6907 chomp($mb = join('', grep(s/^mb=//, @conflines)))
6908 unless defined $pmb;
6909 chomp($mbname = join('', grep(s/^mbname=//, @conflines)))
6910 unless defined $pmbname;
6911 chomp($mbpass = join('', grep(s/^mbpass=//, @conflines)))
6912 unless defined $pmbpass;
6913 chomp($md5sum = join('', grep(s/^md5sum=//, @conflines)))
6915 chomp($mirror = join('', grep(s/^mirror=//, @conflines)))
6917 @mp3tags = grep(s/^mp3tags=//, @conflines)
6918 unless($pmp3tags[0]);
6919 chomp $_ foreach(@mp3tags);
6920 chomp($musenc = join('', grep(s/^musenc=//, @conflines)))
6922 chomp($normalize = join('', grep(s/^normalize=//, @conflines)))
6923 unless defined $pnormalize;
6924 chomp($normcmd = join('', grep(s/^normcmd=//, @conflines)))
6926 chomp($normopt = join('', grep(s/^normopt=//, @conflines)))
6928 chomp($nice = join('', grep(s/^nice=//, @conflines)))
6929 unless defined $pnice;
6930 chomp($nicerip = join('', grep(s/^nicerip=//, @conflines)))
6931 unless defined $pnicerip;
6932 chomp($outputdir = join('', grep(s/^output=//, @conflines)))
6933 unless($poutputdir);
6934 chomp($overwrite = join('', grep(s/^overwrite=//, @conflines)))
6935 unless($poverwrite);
6936 chomp($parano = join('', grep(s/^paranoia=//, @conflines)))
6937 unless defined $pparano;
6938 chomp($playlist = join('', grep(s/^playlist=//, @conflines)))
6939 unless defined $pplaylist;
6940 chomp($prepend = join('', grep(s/^prepend=//, @conflines)))
6941 unless defined $pprepend;
6942 chomp($preset = join('', grep(s/^preset=//, @conflines)))
6944 # NOTE: we have to fill the w_RITE_preset variable!
6945 $wpreset = $preset unless($ppreset);
6948 chomp($proto = join('', grep(s/^proto=//, @conflines)))
6950 chomp($proxy = join('', grep(s/^proxy=//, @conflines)))
6952 my @quafaac = grep(s/^quafaac=//, @conflines) unless($pquality[0]);
6953 chomp($quafaac = $quafaac[0]) unless($pquality[0]);
6954 my @quaflac = grep(s/^quaflac=//, @conflines) unless($pquality[0]);
6955 chomp($quaflac = $quaflac[0]) unless($pquality[0]);
6956 my @qualame = grep(s/^qualame=//, @conflines) unless($pquality[0]);
6957 chomp($qualame = $qualame[0]) unless($pquality[0]);
6958 my @qualoggenc = grep(s/^qualoggenc=//, @conflines)
6959 unless($pquality[0]);
6960 chomp($qualoggenc = $qualoggenc[0]) unless($pquality[0]);
6961 my @quamp4als = grep(s/^quamp4als=//, @conflines)
6962 unless($pquality[0]);
6963 chomp($quamp4als = $quamp4als[0]) unless($pquality[0]);
6964 my @quamuse = grep(s/^quamuse=//, @conflines)
6965 unless($pquality[0]);
6966 chomp($quamuse = $quamuse[0]) unless($pquality[0]);
6967 # I don't really like this. I don't like the variables qualame etc
6968 # too and wanted to get rid of them. Not possible anymore. We need
6969 # them because they hold a comma separated string necessary to
6970 # write to the config file...
6971 unless($pquality[0]) {
6972 @qualame = split(/,/, $qualame);
6973 @qualoggenc = split(/,/, $qualoggenc);
6974 @quaflac = split(/,/, $quaflac);
6975 @quafaac = split(/,/, $quafaac);
6976 @quamp4als = split(/,/, $quamp4als);
6977 @quamuse = split(/,/, $quamuse);
6978 @coder = split(/,/, join(',',@pcoder));
6979 for(my $c=0; $c<=$#coder; $c++) {
6980 if($coder[$c] == 0) {
6981 $quality[$c] = $qualame[0];
6984 if($coder[$c] == 1) {
6985 $quality[$c] = $qualoggenc[0];
6988 if($coder[$c] == 2) {
6989 $quality[$c] = $quaflac[0];
6992 if($coder[$c] == 3) {
6993 $quality[$c] = $quafaac[0];
6996 if($coder[$c] == 4) {
6997 $quality[$c] = $quamp4als[0];
7000 if($coder[$c] == 5) {
7001 $quality[$c] = $quamuse[0];
7006 chomp($faacopt = join('', grep(s/^faacopt=//, @conflines)))
7008 chomp($flacopt = join('', grep(s/^flacopt=//, @conflines)))
7010 chomp($lameopt = join('', grep(s/^lameopt=//, @conflines)))
7012 chomp($mp4alsopt = join('', grep(s/^mp4alsopt=//, @conflines)))
7013 unless($pmp4alsopt);
7014 chomp($museopt = join('', grep(s/^museopt=//, @conflines)))
7016 chomp($oggencopt = join('', grep(s/^oggencopt=//, @conflines)))
7017 unless($poggencopt);
7018 chomp($wavpacopt = join('', grep(s/^wavpacopt=//, @conflines)))
7019 unless($pwavpacopt);
7020 chomp($aacgain = join('', grep(s/^aacgain=//, @conflines)))
7022 chomp($flacgain = join('', grep(s/^flacgain=//, @conflines)))
7024 chomp($mp3gain = join('', grep(s/^mp3gain=//, @conflines)))
7026 chomp($mpcgain = join('', grep(s/^mpcgain=//, @conflines)))
7028 chomp($vorbgain = join('', grep(s/^vorbgain=//, @conflines)))
7030 chomp($wvgain = join('', grep(s/^wvgain=//, @conflines)))
7032 chomp($ffmpegopt = join('', grep(s/^ffmpegopt=//, @conflines)))
7033 unless($pffmpegopt);
7034 chomp($ffmpegsuffix = join('', grep(s/^ffmpegsuffix=//, @conflines)))
7035 unless($pffmpegsuffix);
7036 chomp($coverart = join('', grep(s/^coverart=//, @conflines)))
7038 chomp($coverpath = join('', grep(s/^coverpath=//, @conflines)))
7039 unless($pcoverpath);
7040 chomp($copycover = join('', grep(s/^copycover=//, @conflines)))
7041 unless($pcopycover);
7042 chomp($quitnodb = join('', grep(s/^quitnodb=//, @conflines)))
7043 unless defined $pquitnodb;
7044 chomp($ripper = join('', grep(s/^ripper=//, @conflines)))
7045 unless defined $pripper;
7046 chomp($resume = join('', grep(s/^resume=//, @conflines)))
7047 unless defined $presume;
7048 chomp($ripopt = join('', grep(s/^ripopt=//, @conflines)))
7049 unless defined $pripopt;
7050 my @clist = grep(s/^threads=//, @conflines) unless($pthreads[0]);
7052 # NOTE: all threads numbers are in array entry $clist[0]!
7053 @threads = split(/,/, join(',',@clist));
7054 my @rlist = grep(s/^sshlist=//, @conflines) unless($psshlist[0]);
7056 # NOTE: all machine names are in array entry $rlist[0]!
7057 @sshlist = split(/,/, join(',',@rlist));
7058 chomp($scp = join('', grep(s/^scp=//, @conflines)))
7059 unless defined $pscp;
7060 chomp($span = join('', grep(s/^span=//, @conflines)))
7061 unless defined $pspan;
7062 chomp($submission = join('', grep(s/^submission=//, @conflines)))
7063 unless defined $psubmission;
7064 chomp($transfer = join('', grep(s/^transfer=//, @conflines)))
7066 chomp($tracktemplate = join('', grep(s/^tracktemplate=//, @conflines)))
7067 unless($ptracktemplate);
7068 chomp($trackoffset = join('', grep(s/^trackoffset=//, @conflines)))
7069 unless($ptrackoffset);
7070 chomp($underscore = join('', grep(s/^underscore=//, @conflines)))
7071 unless defined $punderscore;
7072 chomp($utftag = join('', grep(s/^utftag=//, @conflines)))
7073 unless defined $putftag;
7074 chomp($vatag = join('', grep(s/^vatag=//, @conflines)))
7075 unless defined $pvatag;
7076 chomp($vastring = join('', grep(s/^vastring=//, @conflines)))
7077 unless defined $pvastring;
7078 chomp($vbrmode = join('', grep(s/^vbrmode=//, @conflines)))
7080 chomp($year = join('', grep(s/^year=//, @conflines)))
7082 chomp($wav = join('', grep(s/^wav=//, @conflines)))
7083 unless defined $pwav;
7086 print "\nNo config file found! Use option --save to create one.\n"
7090 ########################################################################
7092 # Encode to utf-8 with UTF8 flag.
7096 # We are still at point zero: is it Latin-1 or UTF-8? Let's decode
7097 # without fear, it will work because no wide chars are in!
7098 my @c_points = unpack("C0U*", "$string");
7099 my $d_string = decode_utf8($string, Encode::FB_QUIET);
7100 Encode::from_to($d_string, 'utf8', 'UTF-8');
7101 my @d_points = unpack("C0U*", "$d_string");
7102 # This is one possible test, compare the number of bytes. If
7103 # a wide character is in, then there are less bytes after
7104 # Encode::from_to. E.g. the string DĆ
Āµ will become Dŵr, but
7105 # Ćrger will be ļæ½ger and by chance has the same number of
7106 # bytes -- and unicode points look like: 65533 114 103 101 114.
7107 print "@c_points\n==\n@d_points.\n" if($verbose >= 5);
7108 # In album - artist part we have == !
7109 # $string = $d_string unless(@c_points == @d_points);
7110 # In track part we have > ! Why?
7111 $string = $d_string unless(@c_points > @d_points);
7114 ########################################################################
7116 # Change encoding of tags back to iso-8859-1. Again: this is only needed
7117 # when using lame to create mp3s. Tagging works for all other
7118 # encoders and encodings.
7120 # Test CDs where option --noutf should work:
7121 # Bang Bang: Je t'aime... 10: SacrĆ© cÅur
7122 # Distain!: [Li:quĆd]: 3: Summer 84
7123 # Enya: The Celts: 10: Triad: St. Patrick CĆŗ Chulainn Oisin
7124 # Enya: The Celts: 14: Dan y Dŵr
7125 # Rƶyksopp: Junior: 5: Rƶyksopp Forever
7126 # Žofka: Bad Girls: 1: Woho
7130 my $utf_string = $string;
7131 if(utf8::is_utf8($string)) {
7132 print "The \$string is already in utf8, do nothing!\n"
7136 $utf_string = Encode::decode('UTF-8', $utf_string, Encode::FB_QUIET);
7138 my @utf_points = unpack("U0U*", "$utf_string"); # Perl 5.10
7139 print "\nutf_points:\n@utf_points\n" if($verbose >= 5);
7142 foreach (@utf_points) {
7143 $wideflag = 1 if($_ > 255);
7144 $latinflag++ if($_ > 128 && $_ < 256);
7147 # It works with Rƶyksopp archive and freeCDDB entry.
7148 my @char_points = unpack("U0U*", "$string");
7151 @char_points = @utf_points if($wideflag == 1);
7153 return $string if($string eq "");
7155 foreach (@char_points) {
7157 print "\"Wide\" char detected: $_.\n" if($verbose >= 5);
7158 use Unicode::UCD 'charinfo';
7159 my $charinfo = charinfo(sprintf("0x%X", $_));
7160 my $letter = $charinfo->{name};
7161 print "The charinfo is <$letter>.\n" if($verbose >= 5);
7163 $smallflag = 1 if($letter =~ /SMALL\sLETTER/);
7164 $smallflag = 1 if($letter =~ /SMALL\sLIGATURE/);
7165 $letter =~ s/^.*LETTER\s(\w+)\s.*/$1/;
7166 $letter =~ s/^.*LIGATURE\s(\w+)(\.|\s)*.*/$1/;
7167 $letter = "\L$letter" if($smallflag == 1);
7168 # Rather do nothing than print rubbish (string with words):
7169 $letter = $_ if($letter =~ /\s/);
7170 print "New letter will be: $letter.\n" if($verbose >= 5);
7171 $decoded .= $letter;
7174 $decoded .= chr($_);
7179 # Special condition for MB data. Please do not ask why.
7180 if($wideflag == 0 && $latinflag == 0) {
7182 # Encode::from_to($decoded, 'utf-8', 'iso-8859-15');
7183 # But we come here in every case because we want the discid to be
7184 # present (in comment tags), but come from archive, not from MB.
7185 Encode::from_to($decoded, 'UTF8', 'iso-8859-15');
7187 elsif($wideflag == 0) {
7188 Encode::from_to($decoded, 'utf-8', 'ISO-8859-15');
7191 elsif($wideflag == 0) {
7192 Encode::from_to($decoded, 'utf-8', 'ISO-8859-15');
7196 ########################################################################
7198 # Check the preset options.
7201 if($preset !~ /^\d/) {
7202 while($preset !~ /^insane$|^extreme$|^standard$|^medium$/) {
7203 print "\nPreset should be one of the following words! Please";
7204 print " Enter \ninsane (320\@CBR), extreme (256), standard";
7205 print " (192) or medium (160), (standard): ";
7209 $preset = "standard";
7214 while($preset !~ m/^32$|^40$|^48$|^56$|^64$|^80$|^96$|^112$|^128$|
7215 |^160$|^192$|^224$|^256$|^320$/) {
7216 print "\nPreset should be one of the following numbers!",
7217 " Please Enter \n32, 40, 48, 56, 64, 80, 96, 112, 128,",
7218 " 160, 192, 224, 256 or 320, (128):\n";
7226 $preset = "medium" if($preset =~ /\d+/ && $preset == 160);
7227 $preset = "standard" if($preset =~ /\d+/ && $preset == 192);
7228 $preset = "extreme" if($preset =~ /\d+/ && $preset == 256);
7229 $preset = "insane" if($preset =~ /\d+/ && $preset == 320);
7232 ########################################################################
7234 # Check sshlist of remote machines and create a hash.
7238 @sshlist = split(/,/, join(',', @psshlist));
7241 @threads = split(/,/, join(',', @pthreads));
7243 $wthreads = join(',', @threads);
7244 if(@sshlist || $threads[0] > 1) {
7246 $wsshlist = join(',', @sshlist);
7247 # Create a hash with all machines and the number of encoding
7248 # processes each machine is able to handle.
7249 $sshlist{'local'} = $threads[0] if($local == 1);
7251 foreach (@sshlist) {
7252 $threads[$threadscn] = 1 unless($threads[$threadscn]);
7253 $sshlist{$_} = $threads[$threadscn];
7261 ########################################################################
7263 # Dispatcher for encoding on remote machines. If there are no .lock
7264 # files, a ssh command will be passed, else the dispatcher waits until
7265 # an already passed ssh command terminates and removes the lock file.
7266 # The dispatcher checks all machines all 6 seconds until a machine is
7267 # available. If option --scp is used, the dispatcher will not start an
7268 # other job while copying. In this situation, it looks like nothing
7269 # would happen, but it's only during scp.
7279 my $old_wavdir = $wavdir;
7280 my $old_sepdir = $sepdir;
7281 my $old_ripnam = $ripnam;
7287 while ($sshflag == 2) {
7288 # Start on the local machine first.
7290 for($threadscn = 1; $threadscn <= $threads[0]; $threadscn++) {
7291 if(! -r "$wavdir/local.lock_$threadscn") {
7295 push @codwav, "$ripnam";
7298 last if($sshflag == 1);
7300 last if($sshflag == 1);
7302 foreach $_ (keys %sshlist) {
7303 $machine = $_; # Why this?
7304 for($threadscn = 1; $threadscn <= $sshlist{$_}; $threadscn++) {
7305 if(! -r "$wavdir/$machine.lock_$threadscn") {
7308 # Prepare array @codwav with all tracknames in, which are
7309 # still in progress, i. e. either being ripped or encoded.
7311 open(LOCK, "$wavdir/$machine.lock_$threadscn");
7312 my @locklines = <LOCK>;
7315 chomp(my $locklines = $locklines[0]);
7316 # Push trackname into array only if not yet present.
7317 my @presence = grep(/$locklines/, @codwav);
7318 my $presence = $presence[0];
7319 push @codwav, "$locklines" if(!$presence);
7322 last if($sshflag == 1);
7324 last if($sshflag == 1);
7326 last if($sshflag == 1);
7330 if(-r "$wavdir/enc.log" && $verbose >= 3) {
7331 open(ENCLOG, ">>$wavdir/enc.log");
7332 print ENCLOG "...on machine $machine.\n"
7333 if($#threads > 1 || $machine !~ /^local$/);
7334 print ENCLOG "Executing scp command to $machine.\n"
7335 if($scp && $machine !~ /^local$/);
7338 elsif($verbose >= 3) {
7339 print "...on machine $machine.\n"
7340 if($#threads > 1 || $machine !~ /^local$/);
7341 print ENCLOG "Executing scp command to $machine.\n"
7342 if($scp && $machine !~ /^local$/);
7344 open(LOCKF, ">$wavdir/$machine.lock_$threadscn");
7345 print LOCKF "$sepdir/$ripnam.$suffix\n";
7348 # We need more quotes for the commands (faac,flac,lame,ogg)
7349 # passed to the remote machine. NOTE: But now pay attention
7350 # to single quotes in tags. Quote them outside of single quotes!
7351 # TODO: Please tell me how to quote leading periods, thanks!!!
7352 if($machine !~ /^local$/) {
7353 $enccom =~ s/'/'\\''/g;
7354 $enccom = "ssh " . $machine . " '" . $enccom . "'";
7356 # *Create* the directory:
7357 # Quote the double quotes with a backslash when using ssh!
7358 $sepdir = esc_char($sepdir);
7359 $wavdir = esc_char($wavdir);
7360 log_info("new-outputdir: $sepdir on $machine created.");
7361 log_system("ssh $machine mkdir -p \\\"$sepdir\\\"");
7362 log_info("new-outputdir: $wavdir on $machine created.");
7363 log_system("ssh $machine mkdir -p \\\"$wavdir\\\"");
7365 # Don't overwrite destination file, it will confuse running
7366 # encoders! Do it the hard way! First get all lock-file-names
7367 # of that machine. There will be at least one, created above!
7368 opendir(LOCK, "$old_wavdir") or
7369 print "Can not read in $old_wavdir: $!\n";
7370 my @boxes = grep {/^$machine/i} readdir(LOCK);
7373 # Open each lock-file, read the content, increase counter if
7374 # the same wavname is found. Again: it will be found at least
7377 open(LOCKF, "$old_wavdir/$_") or
7378 print "Can't open $old_wavdir/$_: $!\n";
7379 my @content = <LOCKF>;
7381 $wavflag++ if("@content" =~ /$ripnam/);
7383 $ripnam = esc_char($ripnam);
7384 log_system("scp $wavdir/$ripnam.wav \\
7385 $machine:\"$wavdir/$ripnam.wav\" > /dev/null 2>&1")
7390 # On the local machine escape at least the dollar sign.
7391 $ripnam =~ s/\$/\\\$/g;
7392 $sepdir =~ s/\$/\\\$/g;
7394 $enccom = $enccom . " > /dev/null";
7395 # Because Lame comes with the "Can't get "TERM" environment string"
7396 # error message, I decided to switch off all error output. This is
7397 # not good, if ssh errors appear, then RipIT may hang with a message
7398 # "Checking for lock files". If this happens, switch to verbosity 4
7399 # or higher and look what's going on.
7400 $enccom = $enccom . " 2> /dev/null" if($verbose <= 3);
7401 if($machine !~ /^local$/ && $scp) {
7402 if($suffix eq "mpc") {
7403 $enccom = $enccom . " && \\
7404 scp $machine:\"$sepdir/$ripnam\_enc.$suffix\" \\
7405 $sepdir/$ripnam.$suffix > /dev/null 2>&1 && \\
7406 ssh $machine rm \"$sepdir/$ripnam\_enc.$suffix\" ";
7408 elsif($suffix eq "wv") {
7409 $enccom = $enccom . " && \\
7410 scp $machine:\"$sepdir/$ripnam\_enc.$suffix\" \\
7411 $sepdir/$ripnam.$suffix > /dev/null 2>&1 && \\
7412 ssh $machine rm \"$sepdir/$ripnam\_enc.$suffix\" ";
7414 # Copy correction file! Not yet supported.
7417 $enccom = $enccom . " && \\
7418 scp $machine:\"$sepdir/$ripnam.$suffix\_enc\" \\
7419 $sepdir/$ripnam.$suffix > /dev/null 2>&1 && \\
7420 ssh $machine rm \"$sepdir/$ripnam.$suffix\_enc\" ";
7423 if($suffix eq "mpc") {
7424 $enccom = $enccom . " && \\
7425 mv \"$sepdir/$ripnam\_enc.$suffix\" \\
7426 \"$sepdir/$ripnam.$suffix\""
7427 if($machine eq "local" || ($machine !~ /^local$/ && !$scp));
7429 elsif($suffix eq "wv") {
7430 $enccom = $enccom . " && \\
7431 mv \"$sepdir/$ripnam\_enc.$suffix\" \\
7432 \"$sepdir/$ripnam.$suffix\""
7433 if($machine eq "local" || ($machine !~ /^local$/ && !$scp));
7435 # Copy correction file! Not yet supported.
7438 $enccom = $enccom . " && \\
7439 mv \"$sepdir/$ripnam.$suffix\_enc\" \\
7440 \"$sepdir/$ripnam.$suffix\""
7441 if($machine eq "local" || ($machine !~ /^local$/ && !$scp));
7443 $enccom = $enccom . " && \\
7444 rm \"$old_wavdir/$machine.lock_$threadscn\" &";
7446 # A huge hack only not to interfere with the ripper output.
7448 my $ripmsg = "The audio CD ripper reports: all done!";
7449 my $ripcomplete = 0;
7450 if(-r "$wavdir/error.log") {
7451 open(ERR, "$wavdir/error.log")
7452 or print "Can not open file error.log!\n";
7453 my @errlines = <ERR>;
7455 my @ripcomplete = grep(/^$ripmsg/, @errlines);
7456 $ripcomplete = 1 if(@ripcomplete);
7457 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
7458 open(ENCLOG, ">>$wavdir/enc.log");
7459 print ENCLOG "\n\nExecuting command on machine $machine",
7460 " and trying to encode \n$ripnam.$suffix\_enc.\n";
7464 print "\nExecuting command on machine $machine and tring",
7465 " to encode \n$ripnam.$suffix\_enc.\n";
7469 print "\nExecuting command on machine $machine and tring",
7470 " to encode \n$ripnam.$suffix\_enc.\n";
7473 log_system("$enccom");
7474 sleep 2; # Don't mess up with possible error-msgs from remote hosts.
7476 $wavdir = $old_wavdir;
7477 $sepdir = $old_sepdir;
7478 $ripnam = $old_ripnam;
7479 # Delete the wav only if all encodings of this track are done!
7480 # When the (last) encoding of a track started, its name is pushed
7481 # into the array @delname. Then the first (oldest) entry of the same
7482 # array (@delname) will be compared to the @codwav array. If this
7483 # entry is still present in the codewav-array, nothing happens, else
7484 # the wav file will be deleted and the trackname shifted out of the
7487 push @delname, "$ripnam";
7489 while ($delflag == 0) {
7490 my $delname = $delname[0];
7491 my @delwav = grep(/$delname/, @codwav);
7492 if(!$delwav[0] && $#delname > 1) {
7493 unlink("$wavdir/$delname.wav");
7494 log_info("File $wavdir/$delname.wav deleted.");
7496 # Prevent endless loop if array is empty.
7497 $delflag = 1 if(!$delwav[0]);
7505 ########################################################################
7507 # Delete wavs if sshlist was used. TODO: Improve code for following
7508 # situation: if no .lock files are found, but the encoder did not yet
7509 # finish, don't delete the wavs. Do it only after 3*4 seconds timeout
7510 # with no .lock file.
7515 printf "\n%02d:%02d:%02d: ",
7516 sub {$_[2], $_[1], $_[0]}->(localtime) if($verbose > 1);
7517 print "Checking for remaining lock files.\n" if($verbose > 1);
7518 while ($waitflag <= 3) {
7520 opendir(DIR, "$wavdir");
7521 my @locks = readdir(DIR);
7523 @locks = grep { /\.lock_\d+$/ } @locks;
7524 $waitflag++ if(! @locks);
7525 $waitflag = 0 if(@locks);
7528 printf "\n%02d:%02d:%02d: ",
7529 sub {$_[2], $_[1], $_[0]}->(localtime) if($verbose > 1);
7530 print "Deleting the wavs...\n" if($verbose > 1);
7531 opendir(DIR, "$wavdir");
7532 my @wavs = readdir(DIR);
7534 @wavs = grep { /\.wav$/ } @wavs;
7536 unlink("$wavdir/$_");
7537 log_info("File $wavdir/$_ deleted.");
7541 foreach my $machine (keys %sshlist) {
7542 next if($machine =~ /local/);
7543 foreach my $deldir (@sepdir, $wavdir) {
7545 $dd = esc_char($dd);
7546 log_system("ssh $machine rm \"$dd/*.wav\" 2> /dev/null");
7547 log_system("ssh $machine rmdir -p \"$dd\" 2> /dev/null");
7552 ########################################################################
7554 # LCDproc subroutines, all credits to Max Kaesbauer. For comments and
7555 # questions contact max [dot] kaesbauer [at] gmail [dot] com.
7562 print $lcdproc $data."\n";
7563 my $res = <$lcdproc>;
7569 if($lcdoline1 ne $lcdline1) {
7570 $lcdoline1 = $lcdline1;
7571 plcd("widget_set ripitlcd line1 1 2 {$lcdline1}");
7573 if($lcdoline2 ne $lcdline2) {
7574 $lcdoline2 = $lcdline2;
7575 plcd("widget_set ripitlcd line2 1 3 {$lcdline2}");
7577 if($lcdoline3 ne $lcdline3) {
7578 $lcdoline3 = $lcdline3;
7579 plcd("widget_set ripitlcd line3 1 4 {$lcdline3}");
7586 $lcdproc = IO::Socket::INET->new(
7588 PeerAddr => $lcdhost,
7589 PeerPort => $lcdport,
7590 ) || die "Can not connect to LCDproc port\n";
7591 $lcdproc->autoflush(1);
7594 print $lcdproc "Hello\n";
7595 my @lcd_specs = split(/ /,<$lcdproc>);
7598 $screen{wid} = $lcd_specs[7];
7599 $screen{hgt} = $lcd_specs[9];
7600 $screen{cellwid} = $lcd_specs[11];
7601 $screen{cellhgt} = $lcd_specs[13];
7603 $screen{pixwid} = $screen{wid}*$screen{cellwid};
7604 $screen{pixhgt} = $screen{hgt}*$screen{cellhgt};
7606 fcntl($lcdproc, F_SETFL, O_NONBLOCK);
7608 plcd("client_set name {ripit.pl}");
7609 plcd("screen_add ripitlcd");
7610 plcd("screen_set ripitlcd name {ripitlcd}");
7612 plcd("widget_add ripitlcd title title");
7613 plcd("widget_set ripitlcd title {RipIT $version}");
7615 plcd("widget_add ripitlcd line1 string");
7616 plcd("widget_add ripitlcd line2 string");
7617 plcd("widget_add ripitlcd line3 string");
7619 ########################################################################
7621 # Read the CDDB on the local machine.
7624 my ($album, $artist, $trackno, $asin, $discid, $barcode,
7625 $language, $reldate);
7626 my $logfile = $_[0];
7627 open(LOG, "<$logfile") || print "Can't open $logfile\n";
7628 my @cddblines = <LOG>;
7631 # Note that long lines may be split into several lines
7632 # all starting with the same keyword, e.g. DTITLE.
7633 if($_[1] eq "musicbrainz" or $multi == 1) {
7634 chomp($artist = join('', grep(s/^artist:\s//i, @cddblines)));
7635 chomp($album = join('', grep(s/^album:\s//i, @cddblines)));
7636 chomp($categ = join('', grep(s/^category:\s//i, @cddblines)));
7637 chomp($genre = join('', grep(s/^genre:\s//i, @cddblines)));
7638 chomp($year = join('', grep(s/^year:\s//i, @cddblines)));
7639 chomp($cddbid = join('', grep(s/^cddbid:\s//i, @cddblines)));
7640 chomp($discid = join('', grep(s/^discid:\s//i, @cddblines)));
7641 chomp($asin = join('', grep(s/^asin:\s//i, @cddblines)));
7642 chomp($barcode = join('', grep(s/^barcode:\s//i, @cddblines)));
7643 chomp($language = join('', grep(s/^language:\s//i, @cddblines)));
7644 chomp($reldate = join('', grep(s/^reldate:\s//i, @cddblines)));
7645 chomp($trackno = join('', grep(s/^trackno:\s//i, @cddblines)));
7646 $trackno = $_[2] unless($trackno);
7649 $cd{raw} = \@cddblines;
7650 chomp($artist = join(' / ', grep(s/^DTITLE=//g, @cddblines)));
7651 $artist =~ s/[\015]//g;
7652 $artist =~ s/\n\s\/\s//g;
7653 # Artist is just the first part before first occurrence of
7654 # the slash (/), album gets all the rest!
7655 my @disctitle = split(/\s\/\s/, $artist);
7656 $artist = shift(@disctitle);
7657 $album = join(' / ', @disctitle);
7662 chomp($genre = join('', grep(s/^DGENRE=//, @cddblines)));
7663 $genre =~ s/[\015]//g;
7666 chomp($year = join('', grep(s/^DYEAR=//, @cddblines)));
7667 $year =~ s/[\015]//g;
7670 chomp($discid = join('', grep(s/^MBID=//, @cddblines)));
7671 $discid =~ s/[\015]//g;
7675 $cd{artist} = $artist;
7676 $cd{title} = $album;
7678 $cd{genre} = $genre;
7680 $cd{discid} = $discid;
7683 $cd{barcode} = $barcode;
7684 $cd{language} = $language;
7685 $cd{reldate} = $reldate;
7689 while($i <= $trackno) {
7691 @track = grep(s/^TTITLE$j=//, @cddblines) if($multi == 0);
7692 @track = grep(s/^track\s$i:\s//i, @cddblines)
7693 if($_[1] eq "musicbrainz" or $multi == 1);
7694 my $track = join(' ', @track);
7695 $track =~ s/[\015]//g;
7696 $track =~ s/\n\s\/\s//g;
7698 $cd{track}[$j] = $track;
7703 ########################################################################
7705 # Delete error.log if there is no track-comment in!
7708 if(-r "$wavdir/error.log") {
7709 open(ERR, "$wavdir/error.log")
7710 or print "Fatal: $wavdir/error.log disappeared!\n";
7711 my @errlines = <ERR>;
7713 # Add missing coverart to files previously not done because of
7714 # option thread or sshlist.
7715 my @md5tracks = grep(s/^md5: //, @errlines) if($md5sum == 1);
7717 foreach (@md5tracks) {
7718 my ($sepdir, $donetrack) = split(/;#;/, $_);
7720 # Add special mp3 tags.
7721 if(@mp3tags && $donetrack =~ /mp3$/) {
7722 mp3_tags("$sepdir/$donetrack") if($mp3tags[0] ne "");
7724 # Add coverart if it is a mp3 or ogg.
7725 if($donetrack =~ /mp3$/ && -f "$coverpath" && -s "$coverpath") {
7726 mp3_cover("$sepdir/$donetrack", "$coverpath");
7728 elsif($donetrack =~ /ogg$/ && -f "$coverpath" && -s "$coverpath") {
7729 ogg_cover("$sepdir/$donetrack", "$coverpath");
7733 # Add album-gain once all files are present.
7734 for(my $c = 0; $c <= $#coder; $c++) {
7735 printf "\n%02d:%02d:%02d: ",
7736 sub {$_[2], $_[1], $_[0]}->(localtime) if($verbose > 2);
7737 print "Starting with album gain detection for $suffix[$c]-files.\n"
7739 if($mp3gain && $suffix[$c] =~ /mp3/) {
7740 log_system("$mp3gain \"$sepdir[$c]/\"*.$suffix[$c]");
7742 elsif($vorbgain && $suffix[$c] =~ /ogg/) {
7743 log_system("$vorbgain \"$sepdir[$c]/\"*.$suffix[$c]");
7745 elsif($flacgain && $suffix[$c] =~ /flac/) {
7746 log_system("$flacgain \"$sepdir[$c]/\"*.$suffix[$c]");
7748 elsif($aacgain && $suffix[$c] =~ /m4a|mp4/) {
7749 log_system("$aacgain \"$sepdir[$c]/\"*.$suffix[$c]");
7751 elsif($mpcgain && $suffix[$c] =~ /mpc/) {
7752 log_system("$mpcgain \"$sepdir[$c]/\"*.$suffix[$c]");
7754 elsif($wvgain && $suffix[$c] =~ /wv/) {
7755 log_system("$wvgain \"$sepdir[$c]/\"*.$suffix[$c]");
7758 print "\nNo album gain command found for $suffix[$c].\n"
7762 # Now, once all tagging is done, continue with md5sum calculation.
7763 printf "\n\n%02d:%02d:%02d: ",
7764 sub {$_[2], $_[1], $_[0]}->(localtime)
7765 if($verbose > 2 && $md5sum == 1);
7766 print "Starting with md5sum calculation.\n"
7767 if($verbose > 2 && $md5sum == 1);
7768 # Final sound file stuff
7769 my $album = clean_all($album_utf8);
7771 foreach (@tracksel) {
7772 $riptrackname = get_trackname($_, $tracklist[$_ - 1]);
7773 $riptrackname = get_trackname($_, $tracklist[$_])
7774 if($hiddenflag == 1);
7775 $riptrackname = $album if($book == 1 or $cdcue > 0);
7776 for(my $c = 0; $c <= $#coder; $c++) {
7777 chmod oct($fpermission),
7778 "$sepdir[$c]/$riptrackname.$suffix[$c]"
7780 # Generate md5sum of files.
7782 if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
7783 md5_sum("$sepdir[$c]",
7784 "$riptrackname.$suffix[$c]", 1);
7788 last if($cdcue > 0);
7792 # Change file permissions for md5 files.
7793 if($fpermission && $md5sum == 1){
7794 foreach(@sepdir, $wavdir) {
7795 opendir(MD5, "$_") or print "Can not read in $_: $!\n";
7796 my @md5files = grep {/\.md5$/i} readdir(MD5);
7798 # Security check: if encoder not installed, but directory
7799 # created, then no md5sum-file will be found and the
7800 # directory instead of the file gets the permissions.
7801 next unless($md5files[0]);
7803 chmod oct($fpermission), "$_/$md5files[0]" if($wav == 1);
7806 chmod oct($fpermission), "$_/$md5files[0]";
7810 chmod oct($fpermission), "$wavdir/cd.toc" if($fpermission);
7811 my @ulink = grep(/^Track /, @errlines);
7812 if(!@ulink && $multi == 0) {
7813 unlink("$wavdir/error.log");
7815 elsif($fpermission) {
7816 chmod oct($fpermission), "$wavdir/error.log";
7818 if($ghost == 1&& -r "$wavdir/ghost.log") {
7819 unlink("$wavdir/ghost.log");
7821 if($wav == 0 && $wavdir ne $homedir) {
7822 # I don't like the -p option.
7823 log_system("rmdir -p \"$wavdir\" 2> /dev/null");
7827 ########################################################################
7829 # Escape special characters when using scp.
7832 $_[0] =~ s/\(/\\\(/g;
7833 $_[0] =~ s/\)/\\\)/g;
7834 $_[0] =~ s/\[/\\\[/g;
7835 $_[0] =~ s/\]/\\\]/g;
7836 $_[0] =~ s/\&/\\\&/g;
7837 $_[0] =~ s/\!/\\\!/g;
7838 $_[0] =~ s/\?/\\\?/g;
7839 $_[0] =~ s/\'/\\\'/g;
7840 $_[0] =~ s/\$/\\\$/g;
7844 ########################################################################
7846 # Calculate how much time ripping and encoding needed.
7849 my $encend = `date \'+%R\'`;
7851 # Read times from the file $wavdir/error.log.
7852 open(ERR, "$wavdir/error.log")
7853 or print "Can't calculate time, $wavdir/error.log disappeared!\n";
7854 my @errlines = <ERR>;
7856 my @enctime = grep(s/^Encoding needed //, @errlines);
7857 my @ripstart = grep(s/^Ripping started: //, @errlines);
7858 my @ripend = grep(s/^Ripping ended: //, @errlines);
7859 chomp(my $blanktrks = join(', ', grep(s/^Blankflag = //, @errlines)));
7860 chomp(my $ghostrks = join(', ', grep(s/^Ghostflag = //, @errlines)));
7861 chomp(my $splitrks = join(', ', grep(s/^Splitflag = //, @errlines)));
7862 $blanktrks =~ s/\n//g;
7863 $ghostrks =~ s/\n//g;
7864 $splitrks =~ s/\n//g;
7865 $blanktrks =~ s/,\s(\d+)$/ and $1/g;
7866 $ghostrks =~ s/,\s(\d+)$/ and $1/g;
7867 $splitrks =~ s/,\s(\d+)$/ and $1/g;
7869 @ripstart = split(/:/, $ripstart[0]);
7870 @ripend = split(/:/, $ripend[0]);
7871 $ripend[0] += 24 if($ripend[0] < $ripstart[0]);
7872 my $riptime = ($ripend[0] * 60 + $ripend[1]) -
7873 ($ripstart[0] * 60 + $ripstart[1]);
7875 my $enctime = "@enctime";
7878 @enctime = split(/ /, $enctime);
7879 $enctime[0] = 0 unless(@enctime);
7880 $enctime = int($enctime[0]/60);
7885 return ($riptime,$enctime,$encend,$blanktrks,$ghostrks,$splitrks);
7887 ########################################################################
7889 # Thanks to mjb: log info to file.
7892 if(!defined($infolog)) { return; }
7893 elsif($infolog eq "") { return; }
7894 open(SYSLOG, ">>$infolog") or
7895 print "Can't open info log file <$infolog>.\n";
7896 print SYSLOG "@_\n";
7899 ########################################################################
7901 # Thanks to mjb and Stefan Wartens improvements:
7902 # log_system used throughout in place of system() calls.
7905 my $P_command = shift;
7907 # A huge hack only not to interfer with the ripper output.
7908 if($P_command =~ /faac|flac|lame|machine|mpc|mp4als|oggenc/ &&
7909 $P_command !~ /cdparanoia|cdda2wav|dagrab|icedax|vorbiscomment/) {
7910 my $ripmsg = "The audio CD ripper reports: all done!";
7911 my $ripcomplete = 0;
7912 if(-r "$wavdir/error.log") {
7913 open(ERR, "$wavdir/error.log")
7914 or print "Can not open file error.log!\n";
7915 my @errlines = <ERR>;
7917 my @ripcomplete = grep(/^$ripmsg/, @errlines);
7918 $ripcomplete = 1 if(@ripcomplete);
7919 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
7920 open(ENCLOG, ">>$wavdir/enc.log");
7921 print ENCLOG "\n$P_command\n\n";
7925 print "system: $P_command\n\n";
7930 print "system: $P_command\n\n";
7934 # Log the system command to logfile unless it's the coverart command
7935 # for vorbiscomment with the whole binary picture data.
7936 log_info("system: $P_command") unless($P_command =~ /vorbiscomment/);
7938 # Start a watch process to check progress of ripped tracks.
7939 if($parano == 2 && $P_command =~ /^cdparano/
7940 && $P_command !~ /-Z/
7941 && $P_command !~ /-V/) {
7943 # This is probably dangerous, very dangerous because of zombies...
7944 $SIG{CHLD} = 'IGNORE';
7945 unless($pid = fork) {
7949 # ... but we check and wait for $pid to finish in subroutine.
7950 my $result = check_ripper($P_command, $pid);
7952 $SIG{CHLD} = 'DEFAULT';
7959 # system() returns several pieces of information about the launched
7960 # subprocess squeezed into a 16-bit integer:
7962 # 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
7963 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
7964 # | | | | | | | | | | | | | | | | | [ $? ]
7965 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
7966 # \_____________________/ \/ \__________________/
7967 # exit code core signal number
7969 # To get the exit code, use ($? >> 8)
7970 # To get the signal number, use ($? & 127)
7971 # To get the dumped core flag, use ($? & 128)
7973 # Subprocess has been executed successfully.
7974 return 1 if $? == 0;
7976 # Subprocess was killed by SIGINT (CTRL-C). Exit RipIT.
7977 die "\n\nRipit caught a SIGINT.\n" if(( $? & 127) == 2);
7979 # Subprocess could not be executed or failed.
7982 ########################################################################
7984 # Special characters in cd.toc file won't be written correctly by
7985 # cdrdao, so change them to octal!
7987 # Thanks to pancho horrillo:
7988 # http://perldoc.perl.org/perluniintro.html#Displaying-Unicode-As-Text
7995 } unpack("C0U*", "$_[0]");
7997 ########################################################################
7999 # Check if there is a CD in the CD device. If a CD is present, start
8000 # process. If not, wait until operator inserts a CD, i.e. come back!
8001 # Problem: when used with option loop, the CD already done should not
8002 # be reread again. In this case, don't close the tray automatically.
8005 sysopen(CD, $scsi_cddev, O_RDONLY | O_NONBLOCK) or return;
8006 my $os = `uname -s`;
8007 my $CDROMREADTOCHDR = 0x5305; # Linux
8008 if($os eq "SunOS") {
8009 $CDROMREADTOCHDR = 0x49b;
8011 elsif($os =~ /BSD/i) {
8012 $CDROMREADTOCHDR = 0x40046304;
8015 my $err = ioctl(CD, $CDROMREADTOCHDR, $tochdr);
8019 ########################################################################
8021 # A hack to reinitialize global variables before starting a new loop.
8033 $cddbsubmission = 2;
8038 ########################################################################
8040 # Get the revision number of the CDDB entry.
8043 my @revision = grep(/^\#\sRevision:\s/, @{$cd{raw}});
8044 my $revision = join('', grep(s/^\#\sRevision:\s//, @revision));
8045 chomp $revision if($revision);
8048 ########################################################################
8050 # Change case to lowercase and uppercase first if wanted. Test command:
8051 # perl -e '$string="gLabber (live/mix:radio edit [perl re-mix])"; $string=~s/(\w+)/\u\L$1/g; print "\nString is: $string\n"'
8054 # use encoding "utf8"; # This will break every single non ascii char!
8055 if($lowercase == 1 or $uppercasefirst == 1) {
8057 $_[0] =~ tr/[ĆĆĆĆĆĆ
ĆĆĆĆĆĆĆĆĆĆ]/[Ć Ć”Ć¢Ć£Ć¤Ć„Ć¦Ć§ĆØĆ©ĆŖƫƬĆĆ®ĆÆ]/;
8058 $_[0] =~ tr/[ĆĆĆĆĆĆĆĆĆĆĆĆĆĆ]/[Ć°Ć±Ć²Ć³Ć“ĆµĆ¶ĆøĆ¹ĆŗĆ»Ć¼Ć½Ć¾]/;
8060 if($uppercasefirst == 1) {
8061 # s/(\w+)/\u\L$1/g; # Does not work with non ascii chars...
8062 my @words = split(/ /, $_[0]);
8064 s/(\w+)/\u\L$1/g; # Ensure ucfirst within brackets etc.
8066 $_ =~ tr/^[Ć Ć”Ć¢Ć£Ć¤Ć„Ć¦Ć§ĆØĆ©ĆŖƫƬĆĆ®ĆÆ]/[ĆĆĆĆĆĆ
ĆĆĆĆĆĆĆĆĆĆ]/;
8067 $_ =~ tr/^[Ć°Ć±Ć²Ć³Ć“ĆµĆ¶ĆøĆ¹ĆŗĆ»Ć¼Ć½Ć¾]/[ĆĆĆĆĆĆĆĆĆĆĆĆĆĆ]/;
8069 $_[0] = join(' ', @words);
8073 ########################################################################
8075 # Strip dodgey chars I. This will be done for file names and tags.
8077 # TODO: Do we really have to erase all of them? Maybe we should keep
8078 # some for the tags...
8081 $_[0] =~ s/[;><"\015]//g;
8087 ########################################################################
8089 # Strip dodgey chars II. This will only be done for file names.
8093 $_[0] =~ s/\// - /g;
8097 ########################################################################
8099 # Strip dodgey chars III. This will optionally be done for file names
8100 # and paths. Remember the default chars to be erased are: |\:*?$ plus
8101 # blanks and periods at begin and end of file names and directories.
8102 # But the ending periods problem is not done here, because
8103 # it should only affect directories, not files which have a suffix
8104 # anyway! See subroutine create_dirs!
8107 # Delete beginning blanks in directory names.
8108 $_[0] =~ s,/\s+,/,g if($chars =~ /NTFS/);
8109 # Delete beginning blanks in file names.
8110 $_[0] =~ s/^\s+//g if($chars =~ /NTFS/);
8111 # Delete beginning periods in directory names.
8112 $_[0] =~ s,/\.+,/,g if($chars =~ /HFS|NTFS/);
8113 # Delete beginning perods in file names.
8114 $_[0] =~ s/^\.+//g if($chars =~ /HFS|NTFS/);
8115 my $purged_chars = $chars;
8116 $purged_chars = ":" if($chars =~ /HFS/);
8117 $purged_chars = "[|\\\\:*?\$]" if($chars =~ /NTFS/);
8118 $_[0] =~ s/$purged_chars//g;
8123 ########################################################################
8125 # Put all chars in brackets and escape some.
8128 $chars =~ s/\\/\\\\/;
8131 $chars =~ s/\s/\\s/;
8132 $chars = "[" . $chars . "]" unless($chars =~ /HFS|NTFS|off/);
8134 ########################################################################
8136 # Extract the CDDB comment lines starting with EXTD=.
8137 # NOTE: Each EXTD line my have \n's, but two EXTD lines do NOT
8138 # mean that there's a linebreak in between! So, what we have to do
8139 # is, put all comment lines into a string and split the string
8140 # according to the explicitly \n's (i.e. use \\n).and add a \n at the
8144 my @comment = grep(/^EXTD=/, @{$cd{raw}});
8145 @comment = grep(s/^EXTD=//, @comment);
8146 my $line = "@comment";
8147 $line =~ s/[\015]//g;
8148 @comment = split(/\\n/, $line);
8149 foreach (@comment) {
8155 ########################################################################
8157 # Display a help page and exit.
8159 # New options step 12: Add a short explanation for option --help and do
8160 # not forget to update the manpage ripit.1 to be checked with option -l.
8170 If not specified, all tracks will be ripped. Type a number
8171 or a selection of tracks using numbers separated by commas
8172 or hyphens, default: not set.
8173 -I, --span number-number
8174 Give a span or interval to rip only a part of the track.
8175 The cdparanoia notation is used in the format hh:mm:ss.ff
8176 without brackets. The hyphen is mandatory.
8177 --merge ordered list of comma separated intervals
8178 Place a hyphen or a + between first and last tracknumber
8179 to be merged, default: not set.
8180 -o, --outputdir directory
8181 Where the sound should go. If not set, \$HOME will be used.
8183 --dpermission number
8184 Define directory permissions, default: 0755.
8185 --fpermission number
8186 Define permissions of sound and log files, default: not
8187 set, i.e. depending on the system settings.
8188 -d, --device cddevice
8189 Path of audio CD device, default: /dev/cdrom.
8190 --scsidevice cddevice
8191 Devicename for a different device node of cddevice
8192 where non ripping commands shall be executed.
8194 0 dagrab, 1 cdparanoia, 2 cdda2wav, 3 tosha, 4 cdd,
8197 Additional options for specific ripper. Default: not set.
8199 Set niceness of ripping process, default: 0.
8200 -Z, --disable-paranoia [number]
8201 When using dagrab, the number of retries will be set to 3,
8202 with cdparanoia this option is equal to the -Z option of
8203 cdparanoia. Usefull for faster ripping but not recommended.
8204 Use no argument or 1 to swith paranoia off or 2 if failed
8205 tracks should be done again without paranoia (only one
8206 retry). Default: off (i.e. paranoia on).
8207 -G, --ghost Analyze wav and split into possible chunks of sound or try
8208 to trim lead-in/out. This may override option merge!
8209 Delete blank tracks if only silence ("zero bytes") are
8210 found. Experimental! Default: off.
8212 Enlarge splitted chunk by number of seconds if possible,
8213 or track may be trimmed if value is small (e.g. 0.2), use
8214 with caution! default: 2.0.
8216 Enlarge splitted chunk by number of seconds if possible,
8217 or track may be trimmed if value is small (e.g. 0.2), use
8218 with caution! Default: 2.0.
8220 0 Lame, 1 Oggenc, 2 Flac, 3 Faac, 4 mp4als, 5 Musepack,
8221 6 Wavpack, 7 ffmpge, a comma separated list or use -c for
8223 The same encoder may be stated more than once. Adapt
8224 --dirtemplate in this case, see below. Default: 0.
8226 Pass the command line name of Musepack encoder, e. g.
8227 mppenc. Default: mpcenc.
8228 --faacopt Faac-options
8229 Pass other options to the encoder, quote them with double
8230 quotes if needed; comma separated list if same enocder
8231 is used more than once. Default: not set.
8232 --flacopt Flac-options
8234 --lameopt Lame-options
8236 --museopt Musepack-options
8238 --mp4alsopt mp4als-options
8240 --oggencopt Oggenc-options
8242 --wavpacopt Wavpack-options
8244 --ffmpegopt ffmpeg-options
8246 --ffmpegsuffix suffix
8247 Suffix of the choosen encoder in ffmpeg, a comma sparated
8248 list; default: not set.
8249 -q, --quality quality
8250 A comma separated list of values or the word \"off\", passed
8251 in the same order as the list of encoders! If no encoders
8252 passed, follow the order of the config file! No quality
8253 for wavpack and ffmpeg, use options instead. Default
8256 Variable bitrate, only used with Lame, mode is new or old,
8257 see Lame manpage. The Lame-option quality will be changed
8258 to -V instead of -q if vbr-mode is used; default: not set.
8260 Encode \"mp3\" at this bitrate for Lame. If option --vbrmode
8261 used, bitrate is equal to the -b option, so one might want
8262 to set it \"off\", default: 128.
8264 maxrate (Bitrate) for Lame using --vbrmode is equal to the
8265 -B option for Lame or the -M option for Oggenc,
8268 Use the preset switch when encoding with Lame. With option
8269 --vbrmode new --preset fast will be used. Default: off.
8271 Exclude special characters and (ending!) periods in file
8272 names and path. The argument is optional. Following
8273 characters will be erased, if no argument is stated:
8274 |\\:*?\$ else only ending periods and all passed ones.
8277 Specify a comment tag (mp3, m4a), or a description tag for
8278 (ogg, flac). To write the cddbid used for freedb
8279 or the MusicBrainz discid into the comment, use the word
8280 \"cddbid\" or \"discid\". Default: not set.
8282 Specify (and override CDDB) genre, must be a valid ID3-
8283 genre name if using Lame, can (but shouldn't) be anything
8284 if using other encoders, default: not set.
8286 Specify (and override CDDB) year tag (mp3, m4a), or a date
8287 tag (ogg, flac), default: not set.
8288 -D, --dirtemplate '\" foo \$parameters \"'
8289 Use single and double quotes to pass the parameters of the
8290 templates. More than one --dirtemplate may be stated, or
8291 use variables \$quality and \$suffix. See manpage for more
8292 info. Default: '\"\$artist - \$album\"'
8293 -T, --tracktemplate '\"foo \$parameters\"'
8294 See above. Only one tracktemplate can be stated. Default:
8295 '"\$tracknum \$trackname"'.
8296 --trackoffset number
8297 Use an offset to be added to \$tracknum, default 0.
8299 Add coverart to the sound files. Comma separated list
8300 according to option coder with values 0 (no) or 1 (yes),
8303 Path to the coverart picture to be included in the
8304 metadata of the sound files, default: not set.
8306 Copy an image (may also be any other file) to all
8307 directories containing encoded files.
8308 Value: absolute path to file. Default: not set.
8310 Additional frames to be added to the mp3 file if encoder
8311 does not support the frame or if some unofficial FRAMEs
8312 shall be used. More than one --mp3tags can be used if
8313 several tags shall be added. Default: not set.
8315 Analyze tracknames for "various artists" style and split
8316 the metadata in case one of the delimiters (colon, hyphen,
8317 slash or parenthesis) are found. Use unpair numbers for
8318 the scheme "artist ? tracktitle" and pair numbers in the
8319 opposite case. Default: not set.
8321 A string (regular expression) that defines the "various
8322 artists" style, default: \bVA\b|Variou*s|Various\\sArtists
8323 --flacgain Flacgain command with options but no filenames, e.g.
8325 --mp3gain mp3gain command with options but no filenames.
8326 --mpcgain mpdgain command with options but no filenames.
8327 --aacgain aacgain command with options but no filenames.
8328 --vorbgain vorbisgain command with options but no filenames.
8329 --wvgain wvgain command with options but no filenames.
8331 Comma separated list of remote machines where RipIT should
8332 encode. Default: not set.
8333 --scp If the filesystem can not be accessed on the remote
8334 machines, copy the wavs to the remote machines,
8336 --local Only used with option --sshlist; if all encodings shall be
8337 done on remote machines, use --nolocal, default: on.
8338 --mb Use musicbrainz instead of freedb, default: off.
8340 Give MB login name to submitt ISRCs to the database. Saved
8341 in plain when using a config, default not set.
8343 Give MB password to submitt ISRCs to the database. Saved
8344 in plain when using a config, default not set.
8346 Enable ISRC detection and submission to MB (1 yes, 0 no);
8348 -C, --cddbserver server
8349 CDDB server, default freedb.org. Note, the full address is
8350 \"mirror\".freedb.org, i. e. default is freedb.freedb.org.
8352 Choose \"freedb\" or one of the possible freedb
8353 mirrors, default: freedb.
8354 -L, --protocol level
8355 CDDB protocol level for CDDB query. Level 6 supports UTF-8
8356 and level 5 not. Default: 6
8358 The http proxy to use when accessing the cddb server. The
8359 CDDB protocol must be http! Default: not set.
8361 Transfer mode, cddb or http, will set default port to 8880
8362 or 80 (for http), default: cddb.
8364 Set niceness of encoding process, default: not set.
8366 Read and save CDDB files in \$HOME/.cddb/\"category\"
8367 directory. Default: off.
8368 -e, --eject Ejects the CD when finished, default off.
8370 Command to use for ejecting CD (see --eject), default:
8373 Arguments to the ejecting CD command (see --ejectcmd),
8374 default: path of CD device.
8375 --halt Powers off the machine when finished if the configuration
8376 supports it, default: off.
8378 Specify --nosubmission if the computer is offline and the
8379 created file cddb.toc shall be saved in the home directory
8380 instead of being submitted. With option --archive it will
8381 also be saved in the \$HOME/.cddb directory. Default: on.
8383 Users return email address, needed for submitting an entry
8384 to freedb.org. Default: not set.
8385 -p, --playlist number
8386 Create a m3u playlist file with full paths in filenames.
8387 For filenames without paths use --playlist 2. To prevent
8388 playlist creation, use: --playlist 0. Default: 1 - on.
8390 Specify --nointeraction if ripit shall take the first CDDB
8391 entry found and rip without any questioning. Default: on.
8392 --lcd Use lcdproc to display status, default: on.
8393 --lcdhost Specify the lcdproc host, default: localhost.
8394 --lcdport Specify the lcdport, default: 13666.
8396 Log operations (system calls, file/directory creation) to
8397 file, given with full path; default: not set.
8399 Lowercase filenames, default: off.
8401 Use underscores _ instead of spaces in filenames, default:
8404 Uppercase first characters of each word in filenames and
8406 -U, --utftag If negated decodes Lame-tags to ISO8859-1. Default: off.
8407 --rip Rip the CD, to be used as --norip if wavs are present.
8409 --encode Prevent encoding (generate only wavs) with --noencode.
8411 -w, --wav Keep the wav files after encoding instead of deleting them
8414 Normalizes the wav-files to a given dB-value (default:
8415 -12dB). Default: off.
8416 --normcmd Command to use for normalizing, default: normalize.
8418 Options to pass to normalize. For further options see
8419 normalize documentation (http://normalize.nongnu.org).
8420 Keeping the default value of -12dB is recommended.
8421 Default: -b. Option v will be set according to verbosity.
8423 n=1: Create a toc file to burn the wavs with cd-text using
8424 cdrdao or cdrecord (in dao mode), default: 0 - off.
8426 n=1: Create a cue file to burn the wavs with cd-text,
8429 n=1: Creat inf files for each track to burn the wavs with
8430 cd-text using wodim or cdrecord (in dao mode),
8432 -h, --help Print this and exit.
8434 Print version and exit.
8435 -x, --verbose number
8436 Run silent (0), with minimal (1), normal without encoder
8437 messages (2), normal (3), verbose (4) or extremely verbose
8439 --config Read parameters from config file or specify --noconfig to
8440 prevent reading it; default: on.
8441 --save Add parameters passed on command line to config file. This
8442 options does not overwrite other settings. An existing
8443 config file will be saved as config.old. Default: off.
8444 --savenew Save all parameters passed on command line to a new config
8445 file, backup an existing file to config.old. Default: off.
8447 Create an audiobook, i. e. merge all tracks into one sinlge
8448 file, option --ghost will be switched off and file suffix
8449 will be m4b. Make sure to use encoder faac. A chapter file
8450 will be written for chapter marks. Default: off
8452 Continue to ripp and encode as soon as the previous CD has
8453 finished. This option forces ejection of the CD. Set
8454 number to 2 for immediate restart of ripping process,
8455 experimental. Default off.
8457 Give up CD if no CDDB entry found.
8458 Possible values: 0 - off, 1 - on, default: off
8459 --resume Resume a previously started session. Default: not set.
8460 - O, --overwrite argument
8461 Overwrite existing rip (y), quit if directory exists (q)
8462 or force ejection of disc if directory exists (e). Default
8463 off (n), do not overwrite existing directories, use a
8464 directory name with a suffix instead.
8465 --md5sum Create a MD5-sum file for each type of sound files.
8468 Comma separated list of numbers giving maximum of allowed
8469 encoders to run at the same time, default: 1.
8471 State a command to be executed when ripit finshed. Make
8472 sure to escape the command if needed. Default: not set.
8474 State a command to be executed when ripping starts. Make
8475 sure to escape the command if needed. Default: not set.
8479 ripit(1), cdparanoia(1), lame(1), oggenc(1), flac(1),
8480 normalize(1), cdda2wav(1).
8483 RipIT is now maintained by Felix Suwald, please send bugs, wishes
8484 comments to ripit _[at]_ suwald _[dot]_ com. For bugs, wishes and
8485 comments about lcdproc, contact max.kaesbauer [at] gmail[dot]com.
8486 Former maintainer: Mads Martin Joergensen; RipIT was originally
8487 developed by Simon Quinn.
8494 ########################################################################
8496 # Display available options and exit!
8498 # New options step 13: Add the new options to the short help/error msg.
8504 ripit [--device|d cd-device] [--scsidevice path] [--outputdir|o path]
8505 [--dirtemplate '\"\$parameters\"'] [--chars|W [list]]
8506 [--tracktemplate '\"\$parameters\"'] [--trackoffset number]
8507 [--dpermission number] [--fpermission number]
8508 [--overwrite argument] [--resume|R]
8509 [--rip] [--ripper|r cdripper] [--ripopt ripper-options]
8510 [--nicerip number] [--disable-paranoia|Z] [--wav|w]
8511 [--ghost|G] [--extend seconds] [--prepend seconds]
8512 [--quitnodb value] [--encode] [--coder|c encoders] [--musenc cmd]
8513 [--faacopt options] [--flacopt options] [--oggencopt options]
8514 [--lameopt options] [--mp4alsopt options] [--museopt options]
8515 [--wavpacopt options] [--ffmpegopt options] [--ffmpegsuffix suffix]
8516 [--quality qualities-list] [--bitrate|b rate]
8517 [--maxrate|B rate] [--vbrmode|v old or new] [--preset|S mode]
8518 [--vatag number] [--vastring string or regular expression]
8519 [--comment id3-comment] [--genre|g genre-tag] [--year|y year-tag]
8520 [--mp3gain| cmd options] [--vorbgain| cmd options]
8521 [--flacgain| cmd options] [--aacgain| cmd options]
8522 [--mpcgain| cmd options] [--wvgain| cmd options]
8523 [--utftag|U] [--lowercase|l] [--underscore|u] [--uppercasefirst]
8524 [--coverart list] [--coverpath path] [--copycover path]
8525 [--mp3tags frame-tag=string] [--proxy|P path] [--mb]
8526 [--mbname MB-login] [--mbpass MB-password] [--isrc number]
8527 [--cddbserver|C server] [--mirror|m mirror] [--protocol|L level]
8528 [--transfer|t cddb or http] [--submission|s] [--mail|M address]
8529 [--eject|e] [--ejectcmd command] [--ejectopt options for command]
8530 [--lcd] [--lcdhost host] [--lcdport port]
8531 [--config] [--save] [--savenew]
8532 [--sshlist remote hosts] [--local] [--scp] [--threads numbers]
8533 [--archive|a] [--playlist|p number] [--infolog path] [--md5sum]
8534 [--cdtoc number] [--inf number] [--cdcue number]
8535 [--loop number] [--verbose|x number]
8536 [--normalize|N] [--normcmd] [--normopt|z options]
8537 [--interaction|i] [--nice|n adjustment] [--halt]
8538 [--help|h] [--version|V] [--precmd cmd] [--execmd|X cmd]
8539 [--book|A number] [--merge list] [--span|I span] [track_selection]
8542 For general usage information see the manpage or type:
8546 without any options.
8550 ########################################################################
8552 # Define the tracks to be skipped, change the passed values of the form
8553 # 2+3,5-7 to an array @skip with 3,6,7. Note that we use the untouched
8554 # variable $pmerge to determine the tracks to be skipped.
8555 # In the same time, the intervals have to be tested if valid.
8558 my @merge = split(/,/, $pmerge);
8560 # Split each interval into a BeginEndArray.
8561 my @bea = split(/-|\+/, $_);
8562 my $i = $bea[0] + 1;
8563 # Missing separator in command line argument?
8565 print "\nStrange interval in argument of option merge ($_)!",
8566 "\nIs there a comma missing?\n\n";
8569 # Operator forgot to give last track or wanted the whole CD to be
8570 # merged. But don't add zeros if we come here from the initial
8571 # argument check when the CD-data is still unknown.
8572 if($#tracklist >= 0) {
8573 $pmerge .= $#tracklist + 1 unless($bea[1]);
8574 $bea[1] = $#tracklist + 1 unless($bea[1]);
8576 # Track number larger than number of tracks on CD?
8577 if($#tracklist > 0) {
8578 if($bea[0] > $#tracklist + 1 || $bea[1] > $#tracklist + 1) {
8579 print "\nWrong interval in argument of option merge ($_)!",
8580 "\nHigher track number than tracks on CD?\n\n";
8584 while($i <= $bea[$#bea]) {
8591 ########################################################################
8593 # Read the header of the wav file yet still called $trn.rip.
8598 open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8601 $H->{header_size} = 44;
8603 print "Can not read full WAV header!\n"
8604 if($H->{header_size} != read(IN, $wavheader, $H->{header_size}));
8607 # Unpack the wav header and fill all values into a hashref.
8608 ($H->{RIFF_header}, $H->{file_size_8}, $H->{WAV_header},
8609 $H->{FMT_header}, $H->{WAV_chunk_size}, $H->{WAV_type},
8610 $H->{channels}, $H->{sample_rate}, $H->{byte_per_sec},
8611 $H->{block_align}, $H->{bit_per_sample}, $H->{data_header},
8613 ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
8615 $H->{sample_size} = ($H->{channels} * $H->{bit_per_sample})>>3;
8616 if($verbose >= 4 && $prn == 1) {
8617 print "\nThe wav header has following entries:\n";
8618 print "$_ \t -> $H->{$_} \n" foreach (keys %$H);
8621 return($wavheader, $H);
8623 ########################################################################
8625 # Analyze the wav for chunks and gaps. Fill an array @times with two
8626 # blank separated numbers in each entry. These two numbers are the
8627 # time in seconds of the starting point of sound and the duration of
8628 # that chunk. This is important because this number will be used to seek
8629 # to that point of sound from the beginning of the file, not form the
8630 # end point of the previous cycle. For each chunk we start to seek from
8631 # zero; this is not a large time loss, seeking is fast.
8633 # There were weeks of testing to manage Audio::FindChunks-0.03, gave up!
8634 # The behaviour seems inconsistent. For example: ripping all tracks of
8635 # the CD: Lamb - What Sound gave *no* gaps. When ripping only the last
8636 # track, gaps were immediately detected.
8637 # First, changing the sec_per_chunk value gave better results, but
8638 # suddenly no gaps at all were found. The threshold stayed at zero.
8639 # So then I introduced a loop where the sec_per_chunk increases from
8640 # 0.1 - 0.8 in steps of 0.1, and in the same time, the threshold from
8641 # 0.1 in steps of 0.2 only if the resulting threshold is less than 100.
8642 # You say that this is ugly? No, it is extremely ugly. And all this
8643 # because there might be a caching problem in Audio::FindChunks-0.03?
8644 # Then, testing on a 64bit machine was a drawback, no gaps at all.
8646 # So I gave up this sophisticated and "fully documented" PM, and coded a
8647 # few lines to solve the problem. This code might not be useful to
8648 # split manually recorded vinyl, but the results for ripped CDs are
8649 # much more precise than with the PM. Of course, I can test only on a
8650 # limited range of CDs, and I have no classical or Death-Metal to test.
8651 # But for the following CDs (and hundreds of CDs with no gaps -->
8652 # thousands of tracks and not one was erroneously split) this
8653 # snippet works. (See below for explanation!)
8656 # Testreport (CDs with correctly split ghost songs):
8658 # OK: 2raumwohnung: in wirklich: 11
8659 # OK: A Camp: Colonia: 12
8660 # OK: Archive: Londonium: 13
8661 # OK: Archive: Take My Head: 10
8662 # OK: Aromabar: 1!: 15 (2 ghost songs!)
8663 # OK: Autour de Lucie: L'ƩchappƩe belle: 11
8664 # OK: Camille: Sac des filles: 11
8665 # OK: Camille: Le fil: 15 (Ghost song without zero-gap... not splitted!)
8666 # OK: Cibelle: Cibelle: 11
8667 # OK: Dining Rooms: Experiments In Ambient Soul: 13
8668 # OK: Distain!: [li:quĆd]: 11
8669 # OK: Falco: Out of the Dark: 9+1 renamed
8670 # OK: Helena: NĆ©e dans la nature: 11
8671 # OK: Imogen Heap: Ellipse (disc 2): Half Life (instr.):13+1 reanmed
8672 # OK: Jay-Jay Johanson: Antenna: 10
8673 # OK: Laika: Sound Of The Satellites: 12
8674 # OK: Lamb: Debut: 10
8675 # OK: Lamb: Fear Of Fours: 00 Hidden Track
8676 # OK: Lamb: What Sound: 10
8677 # OK: Little Boots: Hands: 12+1 renamed
8678 # OK: Lunik: Preparing To Leave: 11
8679 # OK: Lunik: Weather: 11
8680 # OK: MĆ£ozinha: Aerosferas: 11
8681 # OK: Massive Attack: 100th Window: 09
8682 # OK: Moby: Last Night : 14
8683 # OK: Moloko: Do You Like My Tight Sweater?: 17+1
8684 # OK: Olive: Trickle: 12
8685 # OK: Rightous Men: Disconnected: 11
8686 # OK: Samia Farah: Samia Farah: 12
8687 # OK: Saint Etienne: Heart Failed [In The Back Of A Taxi] (CD1): 03
8688 # OK: Stereo Total: Musique Automatique 15
8689 # OK: Yoshinori Sunahara: Pan Am: 09
8691 # Deleted blank tracks:
8693 # OK: 22 Pistepirkko: Ralley of Love: 0 (hidden track - copy protection)
8694 # OK: NPG: New Power Soul: all blank tracks
8695 # OK: Dave Matthews Band: Under the Table and Dreaming: all blank tracks
8699 my ($tcn, $trn) = @_;
8701 $trn = $trn . ".rip";
8702 my ($wavheader, $H) = get_wavhead("$trn", 0);
8704 # How do I analyze the chunks? I calculate a threshold value called
8705 # $thresh of the actual chunk by summing up its binary values - perl is
8706 # so cool! Then this value is used to calculate a kind of mean value
8707 # with the previous one --> $deltathre, but only at every 5th value, to
8708 # cancel short fluctuations. If the actual $thresh value lies
8709 # within a small range compared to the deltathre, a weight (counter)
8710 # will be increased and deltathre will be raised to cancel (not so)
8711 # short peak changes (not only) at the end of a track (gap).
8712 # Silence is defined as (not so) significant drop of the $thresh value
8713 # compared to the $deltathre one. Use an upper cut-off value $maxthresh
8714 # (70% of maximum value) to allow deltathre to grow (quickly) in the
8715 # beginning but prevent to bailing out immediately. During the track, a
8716 # weight will help to prevent the same. If the silence lasts more than
8717 # 4 seconds, the detected startsound and duration values will be pushed
8718 # into the @times array. In version 3.7.0 additionally a $trimcn is
8719 # introduced, to enable RipIT to trim tracks at beginning and end. This
8720 # can now be done, if the --extend and --prepend options are set to 0,
8721 # not recommended. If the lead-in/out and gaps are really zero, the
8722 # $trimcn will correct the values pushed into @times which correspond to
8723 # the time points where volume is below the thresh value, but not yet
8724 # zero. With these values a --prepend or --extend of 0 would cut off a
8725 # few fractions of seconds. This may still happen, if the lead-in/out
8726 # and/or gap is not really zero. How should RipIT know about silence?
8727 # If lead-in/out and gaps are zero, $trimcn will slightly enlarge the
8728 # chunks of sound and trimming should not cut away sound, hopefully.
8729 # As far as I understand, the unpack function returns the number of bits
8730 # set -- in a bit vector. Using this value, I stress that we deal with
8731 # bits and not bytes for the variables $thresh and $maxthresh. Therefore
8732 # $maxthresh is multiplied by 8!
8738 my $chunksize = 0.1; # Chunk size in seconds.
8739 my $chunkbyte = $H->{byte_per_sec} * $chunksize;
8744 my $deltathre = $H->{byte_per_sec} * $chunksize;
8748 my $maxthresh = $deltathre * 8 * 0.7;
8750 open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8753 while(read(IN, $bindata, $chunkbyte)) {
8755 my $thresh = unpack('%32b*', $bindata);
8756 $totalthre += $thresh / 1000 if($thresh < $maxthresh * 1.1 );
8758 if($thresh > 0.8 * $deltathre && $thresh < 1.1 * $deltathre);
8759 $deltathre = ($deltathre * $weight + $thresh) / (1 + $weight)
8760 if($thresh > 0.8 * $deltathre && $thresh < $maxthresh &&
8761 $chunkcn =~ /[05]$/);
8762 # According to the $thresh value, decide whether it is sound or
8764 # The if-condition itself is a little more tricky. We have to
8765 # force this condition at beginning, even if there is no silence!
8766 # Why this? If there is a lead-in with immediate sound but very
8767 # short interruptions, the switch of $soundflag = 1 will be the
8768 # reason that the startsnd will increase, although it shouldn't,
8769 # it should stay at 0.0, but will become 0.1 or similar in this
8770 # case! In this way, if the interuptions are short (< 4s) nothing
8771 # will happen, and the fact that $startsnd will not set back to
8772 # zero until a true gap will be found, $startsnd will not be
8773 # recalculated in the else-part.
8774 if($thresh < 0.8 * $deltathre || $bytecn == 0) {
8775 $silencecn += $chunkbyte;
8776 # If thesh is zero, use an other counter to calculate more
8778 $trimcn += $chunkbyte if($thresh == 0);
8779 $leadinflag = 1 if($thresh == 0 && $bytecn == 0);
8780 # If the gap is 4 seconds long, save values in array @times, or
8781 # to detect lead-ins shorter than 4s, set the $soundflag to 1.
8782 if($silencecn == $H->{byte_per_sec} * 4 ||
8783 $bytecn < $H->{byte_per_sec} * 4) {
8784 $chunklen = ($bytecn - $silencecn) / $H->{byte_per_sec};
8786 $chunklen = ($bytecn - $trimcn) / $H->{byte_per_sec}
8787 if($trimcn < $silencecn && $trimcn > 0);
8788 $chunklen -= $startsnd;
8789 # The chunk of sound must be longer than 4.0 seconds!
8794 push(@times, "$startsnd $chunklen");
8795 # Prevent re-entering a duplicate last entry outside of
8799 # Chunk of sound has been detected. Doing this here and not
8800 # just above where $starsnd is set to zero, will enable
8801 # detection of short lead-ins!
8803 # From now on we are in silence!
8804 # Set $trimcn to $silencecn to detect another difference
8805 # at the end of the gap, if the gap consists of zeros.
8806 $trimcn = $silencecn if($bytecn > $H->{byte_per_sec} * 4);
8808 # We will stay in this condition, until...
8811 # ... sound is detected (again)!
8812 # If we get here the first time, save the $startsound time.
8813 if($soundflag == 1 && $startsnd == 0) {
8814 if($trimcn < $silencecn &&
8815 $trimcn > (0.8 * $silencecn)) {
8816 $startsnd = ($bytecn - $silencecn + $trimcn) /
8819 elsif($startsnd == 0) {
8820 $startsnd = $bytecn / $H->{byte_per_sec};
8827 $bytecn += $chunkbyte;
8829 # Calculations for the last (only) chunk of sound.
8830 $chunklen = ($bytecn - $silencecn) / $H->{byte_per_sec};
8831 # Otherwise (slightly different condition than above):
8832 $chunklen = ($bytecn - $trimcn) / $H->{byte_per_sec}
8833 if($trimcn < $silencecn);
8834 $chunklen -= $startsnd;
8835 push(@times, "$startsnd $chunklen") unless($startsnd == 0);
8836 push(@times, "$startsnd $chunklen") unless(@times);
8837 $times[0] =~ s/^0.1/0/ if($startsnd == 0.1 && $leadinflag == 0);
8839 my $tracklen = int(($framelist[$tcn] - $framelist[$tcn - 1]) / 7.5);
8840 $tracklen = int($framelist[$tcn] / 7.5) if($tcn == 0);
8843 # I don't like it, but it might be OK to delete very short tracks
8844 # if their content is blank.
8845 if(-s "$wavdir/$trn" < 200000 && $totalthre >= 200) {
8848 open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8851 while(read(IN, $bindata, 2)) {
8853 my $thresh = unpack('%32b*', $bindata);
8854 $thresh = 0 if($thresh >= 14);
8855 $totalthre += $thresh;
8857 $totalthre = $totalthre * 4 / $chunkcn;
8860 if($totalthre < 200) {
8861 unlink("$wavdir/$trn") or print "Can't delete $trn: $!\n";
8863 print "\n\nRipIT found blank track $trn\n",
8864 "and decided to delete it.\n\n";
8866 open(ERO,">>$wavdir/error.log")
8867 or print "Can not append to file $wavdir/error.log\"!\n";
8868 print ERO "Blankflag = $tcn\nTrack $tcn on CD failed!\n";
8870 log_info("blank track deleted: $wavdir/$trn");
8871 $times[0] = "blank";
8876 printf "\n%02d:%02d:%02d: ",
8877 sub {$_[2], $_[1], $_[0]}->(localtime);
8878 print "RipIT found following chunks for track\n",
8879 "$trn (${tracklen}s long):\nstart duration (in seconds)\n";
8880 log_info("\nRipIT found following chunks for track:");
8881 log_info("$trn (${tracklen}s long):\nstart duration (in seconds)");
8883 my @interval = split(/ /, $_);
8884 printf("%5.1f %9.1f\n", $interval[0], $interval[1]);
8885 log_info("@interval");
8890 ########################################################################
8892 # Split the wav into chunks of sound and rename all of them to
8893 # "Ghost Song $counter.wav".
8896 my ($tcn, $trn, $cdtocn, @times) = @_;
8897 my $album = clean_all($album_utf8);
8898 $album = clean_name($album);
8899 $album = clean_chars($album) if($chars);
8900 $album =~ s/ /_/g if($underscore == 1);
8902 my ($wavheader, $H) = get_wavhead("$trn.rip", 1);
8903 my $chunksize = 0.1; # Chunk size in seconds.
8904 my $chunkbyte = $H->{byte_per_sec} * $chunksize;
8906 # Save the tracklength of the original track to be compared with the
8908 my $tracklen = int($H->{data_size} / $H->{byte_per_sec} * 10);
8910 # Let the other processes know, if the track has been shorten or not.
8915 # Remember: each entry of @times has the form: "start duration"
8916 # where start is the beginning of sound in seconds, and duration
8917 # the time in seconds.
8918 my @interval = split(/ /, $_);
8919 if($interval[0] >= $prepend) {
8920 $interval[0] -= $prepend;
8921 $interval[1] += $prepend;
8924 $interval[1] += $interval[0];
8927 # Extend the interval, this might result in a too long interval.
8928 $interval[1] += $extend;
8929 # Don't allow too long end-times, this can happen with the above
8931 if($interval[0] + $interval[1] > $tracklen) {
8932 $interval[1] = $tracklen - $interval[0];
8934 # Don't split if interval is larger than tracklength from cdtoc.
8935 # Use a threshold of $extend + $prepend. Reasonable?
8936 if(($tracklen - $extend - $prepend) <= $interval[1] ||
8938 print "Track $tcn not splitted.\n\n" if($verbose >= 1);
8939 log_info("Track $tcn not splitted.");
8941 # Merge track into album-track if $cdcue == 1.
8942 merge_wav($trn, $chunkbyte, $album) if($cdcue == 1);
8943 return($shorten, @times);
8946 # Update the times array.
8947 $times[$times_cn] = "$interval[0] $interval[1]";
8949 # Modify the @times array.
8950 $_ = "$interval[0] $interval[1]";
8952 # Use array @secondlist to save new track lengths to allow the
8953 # ripper (!) process to write correct playlist files. The array
8954 # will be printed to ghost.log for encoder process in the "next"
8955 # subroutine called rename_chunks, see below.
8957 $secondlist[$tcn - 1] = int($interval[1]) if($hiddenflag == 0);
8958 $secondlist[$tcn] = int($interval[1]) if($hiddenflag == 1);
8961 push(@secondlist, int($interval[1]));
8964 # Print info message about what is going on (only once):
8965 if($verbose >= 2 && $chunkcn == 0) {
8966 print "Splitting \"$trn\" into " . ($#times + 1) . " chunk";
8967 print ".\n" if($#times == 0);
8968 print "s.\n" unless($#times == 0);
8971 log_info("Splitting \"$trn\" into " . ($#times + 1) . " chunk.")
8973 log_info("Splitting \"$trn\" into " . ($#times + 1) . " chunks.")
8974 unless($#times == 0);
8977 print "\n\nUsing these values for chunk $chunkcn:\n";
8978 printf("%5.1f %5.1f\n", $interval[0], $interval[1]);
8980 log_info("\nUsing these values for chunk $chunkcn:");
8981 log_info("@interval");
8983 # Prepare the filename for output.
8984 my $outr = "Ghost Song $chunkcn";
8985 $outr = get_trackname($tcn, $outr) . ".rip";
8988 my $file_size = -s "$wavdir/$album.wav";
8989 print "\nAppending $outr to album.wav, yet $file_size B large",
8990 ".\n" if($verbose > 4);
8991 log_info("\nAppending $outr to album.wav, yet $file_size B large.\n");
8992 open(OUT, ">> $wavdir/$album.wav")
8993 or print "Can not append to file ",
8994 "\"$wavdir/$album.wav\"!\n";
8997 open(OUT, "> $wavdir/$outr");
9001 # From now on count in bytes instead of seconds.
9002 $interval[0] = $interval[0] * $H->{byte_per_sec} + 44;
9003 $interval[1] = $interval[1] * $H->{byte_per_sec};
9005 # Edit header according to size of the chunk.
9006 $H->{data_size} = $interval[1];
9007 $H->{file_size_8} = $H->{data_size} + 36;
9008 substr($wavheader, 4, 4) = pack("V", $H->{file_size_8});
9009 substr($wavheader, 40, 4) = pack("V", $H->{data_size});
9011 # This is nuts, don't know why this happens, but the chunk sizes
9012 # in the RIFF header are sometimes one byte smaller leading to an
9013 # unpaired number. This causes flac to fail on splitted tracks!
9014 # So let's do it the ugly way: add 1 byte and rewrite the header.
9015 # What goes wrong in the above substr command or elsewhere?
9016 # If someone finds out, please let me know!
9019 ($H->{RIFF_header}, $H->{file_size_8}, $H->{WAV_header},
9020 $H->{FMT_header}, $H->{WAV_chunk_size}, $H->{WAV_type},
9021 $H->{channels}, $H->{sample_rate}, $H->{byte_per_sec},
9022 $H->{block_align}, $H->{bit_per_sample}, $H->{data_header},
9024 ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
9026 while($loopcn < 10 and $H->{data_size} ne $interval[1]) {
9028 print "\nFatal error, unpair chunk sizes detected\n",
9029 "in new header of ghost track part $chunkcn:\n",
9030 "\$H->{data_size} is $H->{data_size} ",
9031 "instead of chunk length = $interval[1]!\n",
9032 "The new wav header has following entries:\n";
9033 print "$_ \t -> $H->{$_} \n" foreach(keys %$H);
9036 log_info("\nFatal error, unpair chunk sizes detected\n",
9037 "in new header of ghost track part $chunkcn:\n",
9038 "\$H->{data_size} is $H->{data_size} ",
9039 "instead of chunk length = $interval[1]!\n",
9040 "The new wav header has following entries:");
9041 log_info("$_ \t -> $H->{$_}") foreach(keys %$H);
9044 $H->{data_size} = 2 * $interval[1] - $H->{data_size};
9045 # $H->{data_size} = $interval[1] + 1;
9046 $H->{file_size_8} = $H->{data_size} + 36;
9048 substr($wavheader, 4, 4) = pack("V", $H->{file_size_8});
9049 substr($wavheader, 40, 4) = pack("V", $H->{data_size});
9051 ($H->{RIFF_header}, $H->{file_size_8}, $H->{WAV_header},
9052 $H->{FMT_header}, $H->{WAV_chunk_size}, $H->{WAV_type},
9053 $H->{channels}, $H->{sample_rate}, $H->{byte_per_sec},
9054 $H->{block_align}, $H->{bit_per_sample}, $H->{data_header},
9056 ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
9061 if($loopcn >= 9 && $verbose >= 3) {
9062 print "\nMajor problem writing the wav header.";
9063 log_info("\nMajor problem writing the wav header.");
9064 if($wcoder =~ /2/) {
9065 print "\nWon't split this track because Flac will fail.";
9066 log_info("\nWon't split this track because Flac will fail.");
9067 # Reset the @times array.
9068 @interval = (0, $tracklen);
9069 @times = ("0 $tracklen");
9071 $secondlist[$tcn - 1] = $interval[1] if($hiddenflag == 0);
9072 $secondlist[$tcn] = $interval[1] if($hiddenflag == 1);
9079 print "\nTrying to continue anyway.\n";
9080 log_info("\nTrying to continue anyway.\n");
9083 return($shorten, @times) if($loopcn >= 9 && $wcoder =~ /2/);
9085 syswrite(OUT, $wavheader, 44) if($cdcue == 0);
9086 log_info("The length of data is $interval[1].");
9087 log_info("The final wav header has following entries:");
9088 log_info("$_ \t -> $H->{$_}") foreach(keys %$H);
9091 print "The length of data is $interval[1].\nThe final wav",
9092 "header of chunk $chunkcn has following entries:\n";
9093 print "$_ \t -> $H->{$_} \n" foreach (keys %$H);
9097 # Seek from beginning of file to start of sound of chunk.
9098 open(IN, "< $wavdir/$trn.rip") or
9099 print "Can't open $trn.rip: $!\n";
9101 print "Seeking to: ${interval[0]}B, starting from 0B.\n"
9103 log_info("Seeking to: ${interval[0]}B, starting from 0B.");
9104 seek(IN, $interval[0], 0) or
9105 print "\nCould not seek in file IN: $!\n";
9107 # I don't know if it is good to read so many bytes a time, but it
9108 # is faster than reading byte by byte.
9109 my $start_snd = $interval[0];
9110 $interval[1] = $interval[1] + $interval[0];
9111 while(read(IN, $bindata, $chunkbyte) &&
9112 $interval[0] < $interval[1] - 1) {
9113 $interval[0] += $chunkbyte;
9114 # Before we write the data, check it, because it happens that
9115 # seek does not seek to a pair number, starting to read an
9116 # unpair (right-channel) byte. In this case, the wav will sound
9117 # like pure noise, and adding or deleting a single byte right
9118 # after the header will heal the wav.
9119 # The amount of data in the read $bindata seems OK, only the
9120 # position is wrong.
9122 if($pos !~ /[02468]$/) {
9123 print "After chunkbyte = <$chunkbyte> reached pos <$pos>.\n"
9125 log_info("After chunkbyte = <$chunkbyte> reached pos <$pos>.\n");
9127 read(IN, my $dummybyte, 1);
9129 print "After 1 byte read reached pos <$pos>.\n"
9134 print "This chunk should be ", $interval[0] - $start_snd,
9135 "B large.\n" if($verbose >= 5);
9136 log_info("This chunk should be ", $interval[0] - $start_snd,
9138 log_info("Remember, steps in the size of $chunkbyte B are used.");
9140 write_wavhead("$wavdir/$album.wav") if($cdcue == 1);
9144 open(ERO,">>$wavdir/error.log")
9145 or print "Can not append to file ",
9146 "\"$wavdir/error.log\"!\n";
9148 print "Track $tcn successfully trimmed.\n\n" if($verbose >= 1);
9149 log_info("Track $tcn successfully trimmed.\n\n");
9150 print ERO "Splitflag = $tcn\n";
9154 print "Track $tcn successfully splitted.\n\n" if($verbose >= 1);
9155 log_info("Track $tcn successfully splitted.\n\n");
9156 print ERO "Ghostflag = $tcn\n";
9160 return($shorten, @times);
9162 ########################################################################
9164 # Rename the chunks called "XY Ghost Song $chunkcn" to the appropriate
9165 # file name according to the track-template.
9169 # The ripper uses a copy of the initial @seltrack array, called
9170 # @tracksel. Ghost songs will be added in @seltrack, but not in array
9171 # @tracksel. This means: the ripper will behave as usual, and not
9172 # care about additional songs. Note that splitted songs are of course
9173 # already ripped, so we do not need to notify the ripper about ghost
9176 # If there is only one chunk, this chunk gets the true trackname.
9177 # If there are more than one chunk, the first chunk gets the true
9178 # track name; this might be wrong, but who knows? If there are only
9179 # two chunks, the second will get the suffix Ghost Song without a
9180 # counter. If the track name holds a slash, the track name will be
9181 # splitted, the first part will be used for the actual track, the
9182 # second part for the ghost song. If there are more than two chunks,
9183 # a counter will be added.
9185 # Another problem is with data tracks. Then the track-counter will
9186 # not increase for ghost songs, as we expect for ghost songs that
9187 # appear in the last track, sad. (See below!)
9189 my ($tcn, $trn, $cdtocn, $cue_point, $shorten, $artistag, $trt, @times) = @_;
9192 my $outr = "Ghost Song $chunkcn";
9193 $outr = get_trackname($tcn, $outr) . ".rip";
9194 # The first track must be renamed to the *.rip file because the
9195 # ripper will rename it to wav!
9196 rename("$wavdir/$outr", "$wavdir/$trn.rip");
9198 # Writing the toc file in case $cdtoc == 1.
9200 my $cdtocartis = $artistag;
9201 oct_char($cdtocartis);
9202 my $cdtoctitle = $trt;
9203 $cdtoctitle = clean_name($cdtoctitle);
9204 oct_char($cdtoctitle);
9205 open(CDTOC, ">>$wavdir/cd.toc")
9206 or print "Can not append to file \"$wavdir/cd.toc\"!\n";
9207 print CDTOC "\n//Track $cdtocn:\nTRACK AUDIO\n";
9208 print CDTOC "TWO_CHANNEL_AUDIO\nCD_TEXT {LANGUAGE 0 {\n\t\t";
9209 print CDTOC "TITLE \"$cdtoctitle\"\n\t\t";
9210 print CDTOC "PERFORMER \"$cdtocartis\"\n\t}\n}\n";
9211 print CDTOC "FILE \"$trn.wav\" 0\n";
9214 # Writing the cue file in case $cdcue == 1.
9216 my $points = chapter_length($cue_point);
9217 $points =~ /\.\d+$/;
9218 my $cuetrackno = sprintf("%02d", $cdtocn);
9219 open(CDCUE ,">>$wavdir/cd.cue")
9220 or print "Can not append to file \"$wavdir/cd.cue\"!\n";
9221 print CDCUE "TRACK $cuetrackno AUDIO\n",
9222 " TITLE \"$trn\"\n",
9223 " PERFORMER \"$artistag\"\n",
9224 " INDEX 01 $points\n";
9227 # Calculate length of track for next cue point.
9228 my $interval = shift(@times);
9229 my ($start, $chunk_length) = split(/ /, $interval);
9230 $chunk_length *= 75;
9232 $chunk_length = $framelist[$tcn] - $framelist[$tcn - 1] if($hiddenflag == 0);
9233 $chunk_length = $framelist[$tcn] - $framelist[$tcn] if($hiddenflag == 1);
9235 $cue_point += $chunk_length;
9237 # If only one chunk has been trimmed, we are done, array @times is
9239 # If there are two or more chunks, proceed and hack all necessary
9240 # arrays needed for the encoder. They will be written in the
9241 # ghost.log file. Note that with only one ghost song no counter is
9242 # needed in the filename. The suffix can now be wav instead of rip.
9243 # TODO: check if final trackname already exists.
9244 # So, the trackname of a new ghost song shall have the same leading
9245 # tracknumber to identify its origin, except if it comes from
9246 # the last track, then the leading number may increase! Define a new
9247 # ghost counter $gcn.
9249 $ghostflag = 1 if($tcn == $#framelist);
9250 $ghostflag = 1 if($hiddenflag == 1 && $tcn == $#framelist - 1);
9251 $gcn++ if($ghostflag == 1);
9254 my $trt = $tracktags[$tcn - 1];
9255 $trt = $tracktags[$tcn] if($hiddenflag == 1);
9256 # Some tracks with ghost songs contain the ghost song name after
9258 my @ghostnames = split(/\//, $trt);
9259 if($ghostnames[$chunkcn]) {
9260 $trt = $ghostnames[$chunkcn];
9261 $trt =~ s/^\s+|\s+$//;
9262 # We need to update the track-arrays as the first track will
9263 # get only its name without the ghost songs name.
9265 my $prev_trt = $ghostnames[0];
9266 $prev_trt =~ s/^\s+|\s+$//;
9267 $tracktags[$#tracktags] = $prev_trt;
9268 my $prev_trn = $prev_trt;
9269 $prev_trn = clean_all($prev_trn);
9270 $prev_trn = clean_name($prev_trn);
9271 $prev_trn = clean_chars($prev_trn) if($chars);
9272 $prev_trn = change_case($prev_trn);
9273 $prev_trn =~ s/ /_/g if($underscore == 1);
9274 $tracklist[$#tracklist] = $prev_trn;
9275 # The cdtoc needs to be hacked too.
9277 open(CDTOC, "<$wavdir/cd.toc")
9278 or print "Can not read file cd.toc!\n";
9279 my @toclines = <CDTOC>;
9281 open(CDTOC, ">$wavdir/cd.toc")
9282 or print "Can not append to file \"$wavdir/cd.toc\"!\n";
9283 foreach (@toclines) {
9284 last if(/\/\/Track\s$cdtocn:/);
9287 my $cdtocartis = $artistag;
9288 oct_char($cdtocartis);
9289 my $cdtoctitle = $prev_trt;
9290 $cdtoctitle = clean_name($cdtoctitle);
9291 oct_char($cdtoctitle);
9292 $prev_trn = get_trackname($tcn, $prev_trn);
9293 print CDTOC "\n//Track $cdtocn:\nTRACK AUDIO\n";
9294 print CDTOC "TWO_CHANNEL_AUDIO\nCD_TEXT {LANGUAGE 0 {\n\t\t";
9295 print CDTOC "TITLE \"$cdtoctitle\"\n\t\t";
9296 print CDTOC "PERFORMER \"$cdtocartis\"\n\t}\n}\n";
9297 print CDTOC "FILE \"$prev_trn.wav\" 0\n";
9300 # The cdcue needs to be hacked too, because the track length
9301 # is different if the track has been splitted.
9303 open(CDCUE, "<$wavdir/cd.cue")
9304 or print "Can not read file cd.cue!\n";
9305 my @cuelines = <CDCUE>;
9307 open(CDCUE, ">$wavdir/cd.cue")
9308 or print "Can not append to file \"$wavdir/cd.cue\"!\n";
9309 my $cuetrackno = sprintf("%02d", $cdtocn);
9311 foreach (@cuelines) {
9312 if($track_flag == 1) {
9313 print " TITLE \"$prev_trt\"\n";
9314 print CDCUE " TITLE \"$prev_trt\"\n";
9321 $track_flag = 1 if(/^TRACK\s$cuetrackno\sAUDIO/);
9328 # The name for the tags will be with originating track name as
9330 $trt = $trt . " - Ghost Song" if($#times == 0);
9331 $trt = $trt . " - Ghost Song $chunkcn" if($#times > 0);
9333 # The actual track name will be slightly different.
9335 $trn = clean_all($trn);
9336 $trn = clean_name($trn);
9337 $trn = clean_chars($trn) if($chars);
9338 $trn = change_case($trn);
9339 $trn =~ s/ /_/g if($underscore == 1);
9340 push(@seltrack, $gcn);
9341 push(@tracklist, $trn);
9342 push(@tracktags, "$trt");
9343 # Remember: $outr is the output track name of the splitted wav.
9344 $outr = "Ghost Song $chunkcn";
9345 $outr = get_trackname($tcn, $outr) . ".rip";
9346 $trn = get_trackname($gcn, $trn);
9347 rename("$wavdir/$outr", "$wavdir/$trn.wav");
9348 md5_sum("$wavdir", "$trn.wav", 0) if($md5sum == 1 && $wav == 1);
9349 if($cdtoc == 1 || $cdcue > 0) {
9353 my $cdtocartis = $artistag;
9354 oct_char($cdtocartis);
9355 my $cdtoctitle = $trt;
9356 $cdtoctitle = clean_name($cdtoctitle);
9357 oct_char($cdtoctitle);
9358 open(CDTOC, ">>$wavdir/cd.toc")
9359 or print "Can not append to file \"$wavdir/cd.toc\"!\n";
9360 print CDTOC "\n//Track $cdtocn:\nTRACK AUDIO\n";
9361 print CDTOC "TWO_CHANNEL_AUDIO\nCD_TEXT {LANGUAGE 0 {\n\t\t";
9362 print CDTOC "TITLE \"$cdtoctitle\"\n\t\t";
9363 print CDTOC "PERFORMER \"$cdtocartis\"\n\t}\n}\n";
9364 print CDTOC "FILE \"$trn.wav\" 0\n";
9368 my $points = chapter_length($cue_point);
9369 $points =~ /\.\d+$/;
9370 my $cuetrackno = sprintf("%02d", $cdtocn);
9371 open(CDCUE ,">>$wavdir/cd.cue")
9372 or print "Can not append to file \"$wavdir/cd.cue\"!\n";
9373 print CDCUE "TRACK $cuetrackno AUDIO\n",
9374 " TITLE \"$trt\"\n",
9375 " PERFORMER \"$artistag\"\n",
9376 " INDEX 01 $points\n";
9379 # Calculate length of track for next cue point.
9380 my ($start, $chunk_length) = split(/ /, $_);
9381 $cue_point += $chunk_length * 75;
9382 print "\nNext cue_point based on interval: $cue_point.\n",
9383 "This is: ", chapter_length($cue_point), ".\n"
9385 $gcn++ if($ghostflag == 1);
9388 print "\n\n" if($verbose >= 2);
9391 # Is there another way to communicate with the encoder process (child
9392 # precess) than writing log files?
9393 open(GHOST, ">$wavdir/ghost.log")
9394 or print "Can not append to file ghost.log!\n";
9395 print GHOST "Array seltrack: @seltrack\n";
9396 print GHOST "Array secondlist: @secondlist\n";
9397 print GHOST "Array tracklist: $_\n" foreach(@tracklist);
9398 print GHOST "Array tracktags: $_\n" foreach(@tracktags);
9400 return($cdtocn, $cue_point);
9402 ########################################################################
9404 # Check if the necessary modules are available.
9407 print "\n" if($verbose >= 1);
9409 # We need to know if coverart is added to mp3 or ogg because those
9410 # encoders can't handle picture tags. The pictures are added after
9411 # encoding process using an additional module.
9412 # Create a coverart array supposing its exactly in the same order as
9417 if($coverart && ($lameflag == 1 || $oggflag == 1 || $wvpflag == 1)) {
9418 my @coverart = split(/,/, $coverart);
9419 for(my $c = 0; $c <= $#coder; $c++) {
9420 $mp3art = 1 if($coder[$c] == 0 && $coverart[$c] > 0);
9421 $oggart = 1 if($coder[$c] == 1 && $coverart[$c] > 0);
9422 $wvpart = 1 if($coder[$c] == 6 && $coverart[$c] > 0);
9426 eval { require CDDB_get };
9428 print "\nPerl module CDDB_get not found. Needed for",
9429 "\nchecking the CD-ID and retrieving the CDDB",
9430 "\nentry from freeDB.org!",
9431 "\nPlease install CDDB_get from your closest",
9432 "\nCPAN mirror before trying again.",
9433 "\nInstall by hand or e.g. type as root:",
9434 "\nperl -MCPAN -e 'install CDDB_get'\n\n";
9438 eval { require LWP::Simple };
9440 print "\nPerl module LWP::Simple not found. Needed for",
9441 "\nchecking free categories before submitting CDDB",
9442 "\nentries to freeDB.org!",
9443 "\nPlease install LWP::Simple and dependencies ",
9444 "\nfrom your closest CPAN mirror or submission will fail.",
9445 "\nInstall by hand or e.g. type as root:",
9446 "\nperl -MCPAN -e 'install LWP::Simple'\n\n";
9450 eval { require Digest::MD5 } if($md5sum == 1);
9452 print "\nPlease install Digest::MD5 and dependencies",
9453 "\nfrom your closest CPAN mirror before trying again with",
9454 "\noption --md5sum. Install by hand or e.g. type as root:",
9455 "\nperl -MCPAN -e 'install Digest::MD5'\n\n";
9459 eval { require Unicode::UCD } if($utftag == 0);
9461 print "\nPlease install Unicode::UCD and dependencies",
9462 "\nfrom your closest CPAN mirror before trying again with",
9463 "\noption --noutftag. Install by hand or e.g. type as root:",
9464 "\nperl -MCPAN -e 'install Unicode::UCD'\n\n";
9468 eval { require MP3::Tag } if($mp3art == 1 && $lameflag == 1);
9470 print "\nPlease install MP3::Tag and dependencies",
9471 "\nfrom your closest CPAN mirror before trying again with",
9472 "\noption --coverart. Install by hand or e.g. type as root:",
9473 "\nperl -MCPAN -e 'install MP3::Tag'\n\n";
9477 eval { require MIME::Base64 } if($oggart == 1 && $oggflag == 1);
9479 print "\nPlease install MIME::Base64 and dependencies",
9480 "\nfrom your closest CPAN mirror before trying again with",
9481 "\noption --coverart. Install by hand or e.g. type as root:",
9482 "\nperl -MCPAN -e 'install MIME::Base64'\n\n";
9486 eval { require WebService::MusicBrainz::Release } if($mb == 1);
9488 print "\nPlease install WebService::MusicBrainz and dependencies",
9489 "\nfrom your closest CPAN mirror before trying again with",
9490 "\noption --mb. Install by hand because using (as root:",
9491 "\nperl -MCPAN -e 'install WebService::MusicBrainz'",
9492 "\nmigth fail.\n\n";
9496 eval { require MusicBrainz::DiscID } if($mb == 1);
9498 print "\nPlease install MusicBrainz::DiscID and dependencies",
9499 "\nfrom your closest CPAN mirror; e.g. type as root:",
9500 "\nperl -MCPAN -e 'install MusicBrainz::DiscID'\n\n";
9505 open(WAVPAK, "wavpack 2>&1|");
9506 my @response = <WAVPAK>;
9508 chomp(my $wvpver = join('', grep(s/.*Linux\sVersion\s//, @response)));
9509 $wvpver =~ s/(\d+\.\d).*/$1/;
9510 if($wvpver <= 4.5) {
9511 print "\n\nWarning:\nThere is a newer version of wavpack ",
9512 "with coverart support.\nThis version of wavpack does ",
9513 "not write binary-tags.\n\n" if($verbose > 0);
9518 eval "use Color::Output";
9519 if($@) {print "\nColor::Output not installed!\n"};
9520 eval "Color::Output::Init";
9523 print "\n\n" if($verbose >= 1);
9525 ########################################################################
9527 # Check if lame is installed.
9530 my ($enc, $suf) = @_;
9531 unless(log_system("$enc --version > /dev/null 2>&1")) {
9533 if(!@pcoder && "@coder" =~ /0/ || "@pcoder" =~ /0/) {
9534 print "\n$enc not found (needed to encode $suf)!",
9535 "\nUse oggenc instead (to generate ogg)?\n";
9537 while($ans !~ /^[yn]$/i) {
9538 print "Do you want to try oggenc? [y/n] (y) ";
9541 $ans = "y" if($ans eq "");
9544 my $coders = "@coder";
9545 my $pcoders = "@pcoder";
9546 if($coders !~ /1/) {
9547 $coders =~ s/0/1/g if($enc =~ /Lame/);
9548 $coders =~ s/3/1/g if($enc =~ /Faac/);
9551 $coders =~ s/0//g if($enc =~ /Lame/);
9552 $coders =~ s/3//g if($enc =~ /Faac/);
9554 if($pcoders !~ /1/) {
9555 $pcoders =~ s/0/1/g if($enc =~ /Lame/);
9556 $pcoders =~ s/3/1/g if($enc =~ /Faac/);;
9559 $pcoders =~ s/0//g if($enc =~ /Lame/);
9560 $pcoders =~ s/3//g if($enc =~ /Faac/);
9563 @coder = split(/ /, $coders);
9564 @pcoder = split(/ /, $pcoders);
9568 "Install $enc or choose another encoder with option",
9570 "-c 1 for oggenc, -c 2 for flac, -c 3 for faac,",
9572 "-c 4 for mp4als, -c 5 for Musepack,",
9574 "-c 6 for Wavpack or -c 7 for ffmpeg.",
9576 "Type ripit --help or check the manpage for info.",
9586 ########################################################################
9588 # Create MD5sum file of sound files.
9592 my $filename = shift;
9593 my $ripcomplete = shift;
9594 my $suffix = $filename;
9595 $suffix =~ s/^.*\.//;
9599 # What name should the md5 file get?
9600 my @paths = split(/\//, $sepdir);
9601 my $md5file = $paths[$#paths] . " - " . $suffix . ".md5";
9602 $md5file =~ s/ /_/g if($underscore == 1);
9604 return unless(-r "$sepdir/$filename");
9606 open(SND, "< $sepdir/$filename") or
9607 print "Can not open $sepdir/$filename: $!\n";
9610 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
9611 open(ENCLOG, ">>$wavdir/enc.log");
9612 print ENCLOG "\n\nCalculating MD5-sum for $filename...";
9616 print "\nCalculating MD5-sum for $filename...";
9619 my $md5 = Digest::MD5->new->addfile(*SND)->hexdigest;
9622 if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
9623 open(ENCLOG, ">>$wavdir/enc.log");
9624 print ENCLOG "\nThe MD5-sum for $filename is: $md5.\n\n";
9628 print "\nThe MD5-sum for $filename is: $md5.\n";
9631 open(MD5SUM,">>$sepdir/$md5file")
9632 or print "Can not append to file \"$sepdir/$md5file\"!\n";
9633 print MD5SUM "$md5 *$filename\n";
9636 ########################################################################
9638 # Sort the options and fill the globopt array according to the encoder.
9639 # Remember, the list of options for one encoder stated several times is
9640 # separated by commas. The *opt arrays below will have only one
9641 # entry, if the corresponding encoder has been stated only once. If one
9642 # needs to find globopt in the code, search for "$globopt[" and not for
9646 my @flacopt = split(/,/, $flacopt);
9647 my @lameopt = split(/,/, $lameopt);
9648 my @oggencopt = split(/,/, $oggencopt);
9649 my @faacopt = split(/,/, $faacopt);
9650 my @mp4alsopt = split(/,/, $mp4alsopt);
9651 my @museopt = split(/,/, $museopt);
9652 my @wavpacopt = split(/,/, $wavpacopt);
9653 my @ffmpegopt = split(/,/, $ffmpegopt);
9654 $faacopt[0] = " " unless($faacopt[0]);
9655 $flacopt[0] = " " unless($flacopt[0]);
9656 $lameopt[0] = " " unless($lameopt[0]);
9657 $mp4alsopt[0] = " " unless($mp4alsopt[0]);
9658 $museopt[0] = " " unless($museopt[0]);
9659 $oggencopt[0] = " " unless($oggencopt[0]);
9660 $wavpacopt[0] = " " unless($wavpacopt[0]);
9661 $ffmpegopt[0] = " " unless($ffmpegopt[0]);
9662 for(my $c=0; $c<=$#coder; $c++) {
9663 if($coder[$c] == 0) {
9665 $lameopt[0] .= " --preset $preset";
9668 $lameopt[0] .= " --vbr-$vbrmode" if($vbrmode);
9669 $lameopt[0] .= " -b $bitrate" if($bitrate ne "off");
9670 $lameopt[0] .= " -B $maxrate" if($maxrate != 0);
9671 $lameopt[0] .= " -V $quality[$c]"
9672 if($qualame ne "off" && $vbrmode);
9673 $lameopt[0] .= " -q $quality[$c]"
9674 if($quality[$c] ne "off" && !$vbrmode);
9676 # Nice output of Lame-encoder messages.
9677 if($quality[$c] eq "off" && $lameopt[0] =~ /\s*-q\s\d\s*/) {
9678 $quality[$c] = $lameopt[0];
9679 $quality[$c] =~ s/^.*-q\s(\d).*$/$1/;
9681 $lameopt[0] =~ s/^\s*//;
9682 push(@globopt, $lameopt[0]);
9685 elsif($coder[$c] == 1) {
9686 $oggencopt[0] .= " -q $quality[$c]" if($quality[$c] ne "off");
9687 $oggencopt[0] .= " -M $maxrate" if($maxrate != 0);
9688 $oggencopt[0] =~ s/^\s*//;
9689 push(@globopt, $oggencopt[0]);
9692 elsif($coder[$c] == 2) {
9693 $flacopt[0] .= " -$quality[$c]" if($quality[$c] ne "off");
9694 $flacopt[0] =~ s/^\s*//;
9695 push(@globopt, $flacopt[0]);
9698 elsif($coder[$c] == 3) {
9699 $faacopt[0] .= " -q $quality[$c]" if($quality[$c] ne "off");
9700 $faacopt[0] =~ s/^\s*//;
9701 push(@globopt, $faacopt[0]);
9704 elsif($coder[$c] == 4) {
9705 $mp4alsopt[0] .= " -q $quality[$c]" if($quality[$c] ne "off");
9706 $mp4alsopt[0] =~ s/^\s*//;
9707 push(@globopt, $mp4alsopt[0]);
9710 elsif($coder[$c] == 5) {
9711 $museopt[0] .= " --quality $quality[$c]" if($quality[$c] ne "off");
9712 $museopt[0] =~ s/^\s*//;
9713 push(@globopt, $museopt[0]);
9716 elsif($coder[$c] == 6) {
9717 push(@globopt, $wavpacopt[0]);
9720 elsif($coder[$c] == 7) {
9721 push(@globopt, $ffmpegopt[0]);
9726 ########################################################################
9728 # Check ripper (cdparanoia) and calculate a timeout according to track
9732 my $P_command = shift;
9734 my @commands = split(/ /, $P_command);
9735 my $riptrackno = $commands[3];
9736 # Remember, $riptrackno might hold an span (interval) format.
9737 $riptrackno =~ s/\[.*$//;
9738 $riptrackno =~ s/-.*$//;
9739 # The $P_command is slightly different in case of hidden tracks.
9740 # Prevent warning when $riptrackno holds the device path instead of
9741 # the hidden track number.
9742 $riptrackno = 0 if($hiddenflag == 1 && $riptrackno !~ /^\d+$/);
9743 my $tlength = $secondlist[$riptrackno - 1];
9744 $tlength = $secondlist[$riptrackno] if($hiddenflag == 1);
9745 $tlength = int(exp(- $tlength / 2000) * ($tlength + 20));
9747 while(kill 0, $pid) {
9748 if($cn > $tlength) {
9749 unless(kill 9, $pid) {
9750 warn "\nProcess $pid already finished!\n";
9759 ########################################################################
9761 # Check distribution.
9764 $distro = "debian" if(-f "/etc/debian_version");
9766 ########################################################################
9768 # Get discid and number of tracks of inserted disc.
9771 CDDB_get->import( qw( get_cddb get_discids ) );
9772 my $cd = get_discids($scsi_cddev);
9773 my ($id, $tracks, $toc) = ($cd->[0], $cd->[1], $cd->[2]);
9774 $cddbid = sprintf("%08x", $id);
9775 my $totaltime = sprintf("%02d:%02d",$toc->[$tracks]->{min},$toc->[$tracks]->{sec});
9776 return($cddbid, $tracks, $totaltime);
9778 ########################################################################
9780 # Analyze string build from CDDB data for latin and wide chars.
9782 sub check_encoding {
9783 my $char_string = shift;
9784 my $utf_string = $char_string;
9787 my $utf_latinflag = 0;
9788 my $utf_wideflag = 0;
9791 # We do nothing for the moment.
9792 # $char_string = decode("iso-8859-15", $char_string);
9795 $utf_string = Encode::decode('UTF-8', $utf_string, Encode::FB_QUIET);
9798 my @char_points = ();
9799 my @utf_points = ();
9802 # Malformed UTF-8 character (unexpected non-continuation byte 0x74,
9803 # immediately after start byte 0xe1) in unpack.
9804 if(!utf8::is_utf8($char_string)) {
9805 @char_points = unpack("C0U*", "$char_string");
9807 # @utf_points = unpack("C0U*", "$datb"); # Perl 5.8
9808 @utf_points = unpack("U0U*", "$utf_string"); # Perl 5.10
9811 foreach (@char_points) {
9812 # print "$_ " if($verbose >= 5);
9813 $latinflag++ if($_ > 128 && $_ < 256);
9814 $wideflag++ if($_ > 255);
9817 foreach (@utf_points) {
9818 # print "$_ " if($verbose >= 5);
9819 $utf_latinflag++ if($_ > 128 && $_ < 256);
9820 $utf_wideflag++ if($_ > 255);
9823 return($latinflag, $wideflag, $utf_latinflag, $utf_wideflag);
9825 ########################################################################
9827 # Transform length of span in seconds. Argument has hh:mm:ss.ff format.
9831 my @time = split(/:/, $time);
9834 # Cut off frames (sectors).
9836 ($time, $frames) = split(/\./, $time) if($time =~ /\./);
9837 # Round the value of frames.
9838 $time++ if($frames > 37);
9840 $time += pop(@time) * $factor;
9845 ########################################################################
9847 # Transform length of span from frames to hh:mm:ss.ff format.
9848 # Thanks to perlmonks.
9850 sub chapter_length {
9853 my $s = int($f / 75);
9855 return sprintf("%s%02d", "00:00:", $s) if($s < 60);
9859 return sprintf("%s%02d:%02d", "00:", $m, $s) if($m < 60);
9863 return sprintf("%02d:%02d:%02d", $h, $m, $s) if($h < 24);
9867 return sprintf("%d:%02d:%02d:%02d", $d, $h, $m, $s);
9869 ########################################################################
9873 sub finish_process {
9882 if($playlist >= 1 && $encode == 1) {
9886 my ($riptime, $enctime, $encend, $blanktrks, $ghostrks, $splitrks)
9890 if(-r "$wavdir/error.log" && $blanktrks eq "") {
9892 print "\nCD may NOT be complete! Check the error.log \n",
9895 elsif($verbose >= 3) {
9896 print "\nRipping needed $riptime min and encoding needed ",
9897 "$enctime min.\n\n";
9904 print "\nCD may NOT be complete! Check the error.log \n",
9906 print "Blank track deleted: $blanktrks!\n"
9907 if($blanktrks !~ /and/);
9908 print "Blank tracks deleted: $blanktrks!\n"
9909 if($blanktrks =~ /and/);
9912 printf "\n%02d:%02d:%02d: ",
9913 sub {$_[2], $_[1], $_[0]}->(localtime);
9914 print "All complete!\n";
9917 print "Ghost song found in track $ghostrks!\n"
9918 if($ghostrks !~ /and/);
9919 print "Ghost songs found in tracks $ghostrks!\n"
9920 if($ghostrks =~ /and/);
9923 print "No ghost songs found!\n";
9926 print "Track $splitrks trimmed!\n"
9927 if($splitrks !~ /and/);
9928 print "Tracks $splitrks trimmed!\n"
9929 if($splitrks =~ /and/);
9932 print "No tracks trimmed!\n" unless($splitrks);
9936 print "\nAll complete!\n";
9938 print "Ripping needed $riptime min and ";
9939 print "encoding needed $enctime min.\n\n";
9943 log_info("\nRipping needed $riptime minutes.");
9944 log_info("Encoding needed $enctime minutes.");
9946 if($lcd == 1) { # lcdproc
9948 $lcdline2 = " RipIT finished ";
9951 close($lcdproc) or print "close: $!";
9955 open(SRXY,">>$logfile")
9956 or print "Can not append to file \"$logfile\"!\n";
9957 print SRXY "\nEncoding ended: $encend";
9958 print SRXY "\nRipping needed: $riptime min.";
9959 print SRXY "\nEncoding needed: $enctime min.";
9960 print SRXY "\nGhost song(s) found in tracks $ghostrks!\n"
9961 if($ghostrks && $ghost == 1);
9962 print SRXY "\nTrack(s) $splitrks trimmed!\n"
9963 if($splitrks && $ghost == 1);
9964 print SRXY "\nTrack(s) $blanktrks deleted!\n"
9965 if($blanktrks && $ghost == 1);
9967 my $cddevno = $cddev;
9968 $cddevno =~ s/\/dev\///;
9969 open(SUCC,">>$outputdir/done.log")
9970 or print "Can not append to file \"$outputdir/succes.log\"!\n";
9971 print SUCC "$cd{artist};$cd{title};$genre;$categ;$cddbid;";
9972 print SUCC "$cddevno;$hostnam;$riptime;$enctime\n";
9974 $cddev =~ s/\/dev\//device /;
9975 $cddev = $cddev . " " unless($cddev =~ /\d\d$/);
9976 my $time = sprintf("%02d:%02d", sub {$_[2], $_[1]}->(localtime));
9977 cprint("\x037Encoding done $time in $cddev with:\x030");
9978 cprint("\x037\n$cd{artist} - $cd{title}.\x030");
9979 cprint("\x033\nGhost song(s) found in tracks $ghostrks!\x030")
9980 if($ghostrks =~ /1/ && $ghost == 1);
9981 cprint("\x033\nTrack(s) $splitrks trimmed!\x030")
9982 if($splitrks =~ /1/ && $ghost == 1);
9983 cprint("\x033\nTrack(s) $blanktrks deleted!\x030")
9984 if($blanktrks =~ /1/ && $ghost == 1);
9988 $execmd =~ s/\$/\\\$/g;
9989 print "Will execute command \"$execmd\".\n" if($verbose >= 3);
9990 log_system("$execmd");
9993 if($halt == 1 && $verbose >= 1) {
9994 print "\nShutdown...\n";
9995 log_system("shutdown -h now");
9998 log_info("*" x 72, "\n");
10000 print "Please insert a new CD!\n\n" if($loop == 2);
10003 ########################################################################
10005 # Write inf files for each track.
10008 my $wavdir = shift;
10009 my $riptrackname = shift;
10010 my $artistag = shift;
10011 my $albumtag = shift;
10012 my $tracktag = shift;
10013 my $riptrackno = shift;
10014 my $nofghosts = shift;
10015 my $trackstart = shift;
10017 $nofghosts = $nofghosts - $riptrackno + 1;
10018 my $ripstart = sprintf("%02d:%02d:%02d",
10019 sub {$_[2], $_[1], $_[0]}->(localtime));
10020 my $date = sprintf("%04d-%02d-%02d",
10021 sub {$_[5]+1900, $_[4]+1, $_[3]}->(localtime));
10023 while ($nofghosts > 0) {
10024 open(INF,">$wavdir/$riptrackname.inf");
10025 print INF "# Wave-info file created by ripit $version on ",
10026 "$date at $ripstart.\n# To burn the wav files use e.g.",
10027 " command:\n# wodim dev=/dev/scd0 -v -eject -pad -dao ",
10028 "-useinfo -text *.wav\n#\n";
10029 print INF "CDINDEX_DISCID=\t'$cd{discid}'\n" if($cd{discid});
10030 print INF "CDDB_DISCID=\t$cddbid\n#\n";
10031 if($va_flag == 1) {
10032 print INF "Albumperformer=\t'$artist_utf8'\n";
10035 print INF "Albumperformer=\t'$artistag'\n";
10037 print INF "Performer=\t'$artistag'\n";
10038 print INF "Albumtitle=\t'$albumtag'\n";
10039 print INF "Tracktitle=\t'$tracktag'\n";
10040 print INF "Tracknumber=\t$riptrackno\n";
10041 print INF "Trackstart=\t$trackstart\n";
10042 my $length = -s "$wavdir/$riptrackname.wav";
10043 $length = int(($length - 44) / 2352);
10044 print INF "# track length in sectors (1/75 seconds each), rest samples\n";
10045 print INF "Tracklength=\t'", $length, ", 0'\n";
10046 $trackstart += $length;
10047 print INF "Pre-emphasis=\tno\n";
10048 print INF "Channels=\t2\n";
10049 print INF "Endianess=\tlittle\n";
10050 print INF "# index list\n";
10051 print INF "Index=\t0\n";
10052 print INF "Index0=\t-1\n";
10055 if($nofghosts > 0) {
10056 my $gcn = $seltrack[$#seltrack - $nofghosts];
10057 my $trn = $tracklist[$gcn];
10058 $tracktag = $tracktags[$gcn];
10059 $riptrackname = get_trackname($gcn + 1, $trn);
10063 return($trackstart);
10065 ########################################################################
10067 # Write coverart to mp3 files.
10070 my($snd_file, $coverpath) = @_;
10071 my $mp3 = MP3::Tag->new($snd_file);
10073 my $id3v2 = exists $mp3->{'ID3v2'}
10075 : $mp3->new_tag('ID3v2');
10076 my $type = $coverpath;
10077 $type =~ s/.*\.(gif|jpg|jpeg|png)$/$1/;
10078 $type =~ s/jpeg/jpg/;
10080 print "Adding a $type to $snd_file.\n\n" if($verbose > 4);
10081 log_info("\nAdding a $type to $snd_file.");
10082 # Read coverart into $data.
10083 open(PIC, "< $coverpath" )
10084 or print "Cannot open file $coverpath: $!\n\n";
10086 my $data = do { local($/); <PIC> };
10087 $id3v2->add_frame('APIC', "image/$type", 3, 'Cover Image', $data);
10093 ########################################################################
10095 # Write special tags to mp3 files.
10098 my($snd_file) = shift;
10099 my $mp3 = MP3::Tag->new($snd_file);
10101 my $id3v2 = exists $mp3->{'ID3v2'}
10103 : $mp3->new_tag('ID3v2');
10104 foreach (@mp3tags) {
10105 my ($frame, $content) = split(/=/, $_);
10106 $id3v2->add_frame($frame, $content);
10107 log_info("\nAdding $frame=$content to $snd_file.");
10113 ########################################################################
10115 # Write coverart to ogg files.
10118 use MIME::Base64 qw(encode_base64);
10119 my($snd_file, $coverpath) = @_;
10120 my $type = $coverpath;
10121 $type =~ s/.*\.(gif|jpg|png)$/$1/;
10123 open(PIC, "$coverpath")
10124 or print "Cannot open file $coverpath: $!\n\n";
10125 my $data = do { local($/); encode_base64(<PIC>, '') };
10128 print "Adding a $type to $snd_file.\n\n" if($verbose > 4);
10129 log_info("\nAdding a $type to $snd_file.");
10130 # print "\n\nvorbiscomment -a $snd_file -t COVERARTMIME=image/$type -t COVERART=$data\n\n";
10131 log_system("vorbiscomment -a \"$snd_file\" -t COVERARTMIME=image/$type -t COVERART=$data");
10134 ########################################################################
10136 # Write the CDDB entry to ~/.cddb/category if there is not already
10137 # an entry present.
10140 chomp($categ = $cd{cat});
10141 log_system("mkdir -m 0755 -p $homedir/.cddb/$categ/")
10142 or print "Can not create directory $homedir/.cddb/$categ: $!\n";
10143 $cddbid =~ s/,.*$// if($cddbid =~ /,/);
10144 if(! -f "$homedir/.cddb/$categ/$cddbid") {
10145 open(TOC, "> $homedir/.cddb/$categ/$cddbid")
10146 or print "Can not write to $homedir/.cddb/$categ/$cddbid: $!\n";
10147 foreach (@{$cd{raw}}) {
10154 ########################################################################
10156 # Merge the wav files if $cdcue == 1.
10159 my ($trn, $chunkbyte, $album) = @_;
10160 open(IN, "< $wavdir/$trn.rip") or
10161 print "Can't open $trn.rip: $!\n";
10163 # Only skip the header in case the base file already exists.
10164 if(-r "$wavdir/$album.wav") {
10166 print "\nCould not seek beyond header in file IN: $!\n";
10168 open(OUT, ">> $wavdir/$album.wav");
10171 # I don't know if it is good to read so many bytes a time, but it
10172 # is faster than reading byte by byte.
10173 while(read(IN, my $bindata, $chunkbyte)) {
10174 print OUT $bindata;
10179 # Rewrite the header of the merged file $album.wav.
10180 write_wavhead("$wavdir/$album.wav");
10184 ########################################################################
10186 # Rewrite the wav header.
10188 sub write_wavhead {
10190 if(!sysopen(WAV, $file, O_RDWR | O_CREAT, 0755)) {
10191 print "\nCan not to open $file: $!\n";
10195 my $nread = sysread(WAV, $buffer, 44);
10196 if($nread != 44 || length($buffer) != 44) {
10197 print "\nWAV-header length problem in file $file.\n";
10202 my $main_template = "a4 V a4 a4 V a16 a4 V";
10203 my($riff_header, $file_size_8, $wav_header, $fmt_header,
10204 $fmt_length, $fmt_data,$data_header,$data_size) =
10205 unpack($main_template, $buffer);
10207 print "RIFF chunk descriptor is: $riff_header\n",
10208 "RIFF chunk length is: $file_size_8\n",
10209 "WAVE format is: $wav_header\n",
10210 "FMT subchunk is: $fmt_header\n",
10211 "FMT subchunk length is: $fmt_length\n";
10213 my $file_length = -s "$file";
10214 $file_size_8 = $file_length - 8;
10215 $data_size = $file_length - 44;
10216 $buffer = pack($main_template, $riff_header, $file_size_8,
10217 $wav_header, $fmt_header, $fmt_length, $fmt_data,
10218 $data_header, $data_size);
10219 sysseek(WAV, 0, 0);
10220 syswrite(WAV, $buffer, length($buffer));
10224 ########################################################################
10226 # Check all tracks for VA-style.
10229 my $prt_msg = shift;
10231 my $delim_colon = 0;
10232 my $delim_hyphen = 0;
10233 my $delim_slash = 0;
10234 my $delim_parenthesis = 0;
10236 # Don't use @tracktags because operator might not want to rip the
10237 # whole CD. VA-style detection will fail if number of selected tracks
10238 # are compared to the total number of tracks!
10239 foreach (@seltrack) {
10241 $delim_colon++ if($tracktags[$tn] =~ /:/);
10242 $delim_hyphen++ if($tracktags[$tn] =~ /-/);
10243 $delim_slash++ if($tracktags[$tn] =~ /\//);
10244 $delim_parenthesis++ if($tracktags[$tn] =~ /\(.*\)/);
10248 my $artist = clean_all($cd{artist});
10250 if($vatag >= 1 and $artist =~ /$vastring/i and
10251 ($delim_colon == $n or $delim_hyphen == $n or
10252 $delim_slash == $n or $delim_parenthesis == $n)) {
10254 print "\nVarious Artists CDDB detected, track artist will be ",
10255 "used for each track tag.\n"
10256 if($verbose > 2 and $prt_msg == 1);
10258 elsif($vatag >= 3 and $artist =~ /$vastring/i and
10259 ($delim_colon > 0 or $delim_hyphen > 0 or $delim_slash > 0 or
10260 $delim_parenthesis > 0)) {
10262 print "\nVarious Artists CDDB detected, track artist will be ",
10263 "used for some track tags.\n"
10264 if($verbose > 2 and $prt_msg == 1);
10266 elsif($vatag >= 5 and
10267 ($delim_colon == $n or $delim_hyphen == $n or
10268 $delim_slash == $n or $delim_parenthesis == $n)) {
10270 print "\nMultiple artists data detected, track artist will be",
10271 " used for each track tag.\n"
10272 if($verbose > 2 and $prt_msg == 1);
10274 elsif($vatag >= 7 and
10275 ($delim_colon > 0 or $delim_hyphen > 0 or $delim_slash > 0 or
10276 $delim_parenthesis > 0)) {
10278 print "\nMultiple artists data detected, track artist will be",
10279 " used for some track tags.\n"
10280 if($verbose > 2 and $prt_msg == 1);
10283 $va_flag = 0 unless($va_flag == 2);
10284 print "\nNo Various Artists DB detected, album artist will be",
10285 " used for each track tag.\n"
10286 if($verbose > 2 and $va_flag == 0 and $prt_msg == 1);
10288 print "\n" if($verbose > 2 and $prt_msg == 1);
10289 return($delim) if($va_flag == 0);
10291 if($va_flag == 2) {
10295 # Give slashes highest priority and set default to slashes too.
10296 if($delim_slash >= $delim_colon and
10297 $delim_slash >= $delim_hyphen and
10298 $delim_slash >= $delim_parenthesis) {
10301 elsif($delim_colon >= $delim_hyphen and
10302 $delim_colon >= $delim_parenthesis and
10303 $delim_colon >= $delim_slash) {
10306 elsif($delim_hyphen >= $delim_colon and
10307 $delim_hyphen >= $delim_slash and
10308 $delim_hyphen >= $delim_parenthesis) {
10311 elsif($delim_parenthesis >= $delim_colon and
10312 $delim_parenthesis >= $delim_slash and
10313 $delim_parenthesis >= $delim_hyphen) {
10321 ########################################################################
10323 # Copy image file from destination path to directories of encoded sound
10327 for(my $c=0; $c<=$#coder; $c++) {
10328 copy("$copycover", "$sepdir[$c]")
10329 or print "Copying file to $sepdir[$c] failed: $!\n";
10332 ########################################################################
10334 # Check album cover in path variable copycover.
10338 unless(-s $copycover) {
10339 while($copycover !~ /^[yn]$/i) {
10340 print "\nImage file $copycover is not a valid file. Continue? [y/n] (y) ";
10343 $ans = "y" if($ans eq "");
10344 last if($ans =~ /y/i);
10345 die "Aborting\n" if($ans =~ /n/i);
10349 ########################################################################
10351 # Read in ISRCs using Icedax and submit them if detected using code from
10352 # Nicholas Humfrey <njh@aelius.com>.
10355 print "\nReading ISRC..." if($verbose > 2);
10356 my $icedax = `which icedax`;
10358 if($mbname ne "" and $mbpass ne "" and $icedax ne "") {
10361 open(ICEDAX, "icedax -D $scsi_cddev -g -H -J -Q -v trackid 2>&1 |")
10362 or print "\nFailed to run icedax command: $!\n";
10365 if(/T:\s+(\d+)\s+ISRC:\s+([A-Z]{2}-?\w{3}-?\d{2}-?\d{5})$/) {
10366 my ($num, $isrc) = ($1-1, uc($2));
10368 $isrcs[$num] = $isrc;
10370 elsif(/Media catalog number: (.+)/i) {
10376 my $diflag = 1; # Suppose all ISRCs found are different.
10377 # Now preparing ISRC data array to post to MB server.
10379 print "MCN: " . $mcn . "\n" if ($mcn && $verbose > 3);
10380 for(my $i = 0; $i < scalar(@isrcs); $i++) {
10381 my $isrcno = $isrcs[$i];
10382 my $trackid = $idata[$i];
10383 next unless($trackid);
10384 if(defined $isrcno && $isrcno ne '' && $isrcno !~ /^0+$/) {
10385 printf("\nTrack %2.2d: %s %s", $i + 1, $isrcno || '', $trackid)
10387 push(@isrcdata, "isrc=" . $trackid . '%20' . $isrcno);
10389 # Test if subsequent (all) ISRCs are different.
10391 $isrcno = $i unless($isrcno);
10392 $diflag = 0 if($isrcs[$i-1] && $isrcno eq $isrcs[$i-1]);
10395 print "\n\n" if($verbose > 3);
10397 # Check that we have something to submit
10398 if(scalar(@isrcdata) < 1) {
10399 print "\nNo valid ISRCs to submit." if($verbose > 2);
10402 elsif($diflag == 0) {
10403 print "\nIdentical ISRCs for different tracks detected.",
10404 "\nNo submission in this case.\n" if($verbose > 2);
10408 # Send to Musicbrainz.
10409 if($mbname ne "" and $mbpass ne "") {
10410 my $ua = LWP::UserAgent->new;
10413 $ua->credentials( 'musicbrainz.org:80', 'musicbrainz.org', "$mbname", "$mbpass" );
10415 my $request = HTTP::Request->new( 'POST', 'http://musicbrainz.org/ws/1/track/' );
10416 $request->content(join('&', @isrcdata));
10417 $request->content_type('application/x-www-form-urlencoded');
10419 my $response = $ua->request($request);
10420 print "\nISRC submission to MB " . $response->status_line. "\n" if($verbose > 2);
10423 print "\nNo ISRC submission to MB.\n" if($verbose > 2);