]> git.donarmstrong.com Git - bin.git/blob - ripit
add common subscriber
[bin.git] / ripit
1 #!/usr/bin/perl
2 ########################################################################
3 #
4 # LICENSE
5 #
6 # Copyright (C) 2005 Felix Suwald
7 #
8 #
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.
13 #
14 #
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.
19 #
20 #
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,
24 # USA.
25 #
26 #
27 ########################################################################
28 #
29 # CODE
30 #
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
42 #               with text
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.
51 #
52 #
53 # Version 3.9.0 - July 14th 2010 - Felix Suwald, thanks for input:
54 #                                  F. Sundermeyer
55 #                                  S. NoĆ©
56 # Version 3.8.1 - November 18th 2009 - Felix Suwald
57 #                                      D. Mader
58 # Version 3.8.0 - September 28th 2009 - Felix Suwald
59 #
60 # Version 3.7.0 - May 6th 2009 - Felix Suwald, thanks for input:
61 #                                C. Blank
62 #                                A. Gillis
63 #                                and to all the bug-reporters!
64 # Version 3.6.0 - June 16th 2007 - Felix Suwald, thanks for input:
65 #                                  C. Blank
66 #                                  G. Edwards
67 #                                  G. Ross
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
80 #
81 #
82 ########################################################################
83 #
84 # User configurable variables:
85 # Keep these values and save your own settings in a config file with
86 # option --save!
87 #
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
101                             # list of encoders.
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.
116 my $quaflac   = 5;          #
117 my $quafaac   = 100;        #
118 my $quamp4als = 0;          #
119 my $quamuse   = 5;          #
120 my $lameopt   = "";         #
121 my $oggencopt = "";         #
122 my $flacopt   = "";         #
123 my $faacopt   = "";         #
124 my $mp4alsopt = "";         #
125 my $museopt   = "";         #
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
157                             # (1 yes, 0 no).
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
163                             # (1 yes, 0 no).
164 my $config    = 1;          # Use config file to read parameters
165                             # (1 yes, 0 no).
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
169                             # (1 yes, 0 no).
170 my $parano    = 1;          # Use paranoia mode in cdparanoia
171                             # (1 yes, 0 no).
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
177                             # (1 yes, 0 no).
178 my $infolog   = "";         # InfoLog
179                             # (filename)
180 my $interaction = 1;        # If 0 do not ask anything, take the 1st
181                             # CDDB entry found or use default names!
182                             # (1 yes, 0 no).
183 my $underscore = 0;         # Use _ instead of spaces in filenames
184                             # (1 yes, 0 no).
185 my $lowercase = 0;          # Lowercase filenames
186                             # (1 yes, 0 no).
187 my $uppercasefirst = 0;     # Uppercase first filenames
188                             # (1 yes, 0 no).
189 my $archive   = 0;          # Save CDDB files in ~/.cddb dir
190                             # (1 yes, 0 no).
191 my $mb        = 0;          # Use the musicbrainz DB instead of freedb
192                             # (1 yes, 0 no).
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
220                             # beginning.
221 my $extend    = 2.0;        # Extend ghost songs by 2 seconds at the
222                             # end.
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).
234 #
235 # New options step 1: Add global variables here above or below in case
236 # they shouldn't be user configurable.
237 #
238 #
239 #
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"';
248 #
249 my @dirtemplate = '"$artist - $album"';
250 my $tracktemplate  = '"$tracknum $trackname"';
251 my $trackoffset = 0;
252 #
253 #
254 # LCDproc settings:
255 #
256 my $lcdhost   = "localhost";
257 my $lcdport   = "13666";
258 my $lcdline1  = "   [initializing]   ";
259 my $lcdline2  = " ripit-lcd-module     ";
260 my $lcdline3  = "          2005 ";
261 my $lcdoline1 = "";
262 my $lcdoline2 = "";
263 my $lcdoline3 = "";
264 my $lcdproc;
265 my $lcdtrackno       = 0;
266 #
267 #
268 #
269 # Normalize settings:
270 #
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";
275 #
276 #
277 ########################################################################
278 #
279 # System variables, no user configurable variables below.
280 #
281 use Encode;                 # Needed for decode_utf8 calls.
282 use Fcntl;                  # Needed for sysopen calls.
283 use File::Copy;
284 use Getopt::Long qw(:config no_ignore_case);
285 use IO::Socket;
286 use strict;
287 #use warnings;
288 #
289 # Initialize paths.
290 #
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) (?).
295 my $hostnam = "";
296 if($ENV{HOSTNAME}) {
297    $hostnam = "$ENV{HOSTNAME}";
298 }
299 elsif($ENV{HOST}) {
300    $hostnam = "$ENV{HOST}";
301 }
302 my $charset = "";
303 if($ENV{G_FILENAME_ENCODING}) {
304    $charset = "$ENV{G_FILENAME_ENCODING}";
305 }
306 else {
307    $charset = "$ENV{LANG}";
308 }
309 if($charset =~ /UTF-8/) {
310    $charset = "UTF-8";
311 }
312 elsif($charset  =~ /ISO-8859-15/) {
313    $charset = "ISO-8859-15";
314 }
315 else {
316    $charset = "ISO-8859-1";
317 }
318 #print ($_,$ENV{$_},"\n") foreach (keys %ENV);
319
320 #
321 # Initialize global variables.
322 #
323 my $version          = "3.9.0";
324 my $album_utf8       = "";
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
334                             # coverart support.
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.
357 my $hiddenflag       = 0;
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
365                             # encoder.
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.
374 #
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.
377 #
378 #
379 # Initialize subroutines without ().
380 #
381 sub ask_subm;
382 sub check_bitrate;
383 sub check_cddev;
384 sub check_chars;
385 sub check_cover;
386 sub check_vbrmode;
387 sub choose_genre;
388 sub copy_cover;
389 sub disp_info;
390 sub extract_comm;
391 sub get_rev;
392 sub get_isrcs;
393 sub init_mod;
394 sub init_var;
395 sub lame_preset;
396 sub main_sub;
397 sub skip_tracks;
398 sub write_cddb;
399 sub merge_wav;
400 sub write_wavhead;
401 #
402 # New options step 3: Do not forget to initialize new subroutines.
403 #
404 #
405 # Define the variables which catch the command line input.
406 # The p stands for passed (from command line).
407 my (
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,
433    $pmbpass,        $pisrc,
434 );
435 #
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.
439 #
440 #
441 ########################################################################
442 #
443 # Get the parameters from the command line.
444 #
445 # available:             E F     jJkK           Q               Y
446 # already used: aAbBcCdDe f gGhiI    lLmMnNoOpPq rRsStTuUvVwWxXy zZ
447 #
448 GetOptions(
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,
490    "halt"                   => \$phalt,
491    "help|h"                 => \$help,
492    "inf=i"                  => \$pinf,
493    "infolog=s"              => \$pinfolog,
494    "interaction|i!"         => \$pinteraction,
495    "isrc=i"                 => \$pisrc,
496    "lcd!"                   => \$plcd,
497    "lcdhost=s"              => \$plcdhost,
498    "lcdport=s"              => \$plcdport,
499    "lowercase|l!"           => \$plowercase,
500    "uppercasefirst!"        => \$puppercasefirst,
501    "local!"                 => \$plocal,
502    "loop=i"                 => \$ploop,
503    "mb!"                    => \$pmb,
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,
511    "multi"                  => \$pmulti,
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,
531    "rip!"                   => \$prip,
532    "ripper|r=s"             => \$pripper,
533    "ripopt=s"               => \$pripopt,
534    "savenew"                => \$psavenew,
535    "save"                   => \$psavepara,
536    "scp"                    => \$pscp,
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,
552    "wav|w!"                 => \$pwav,
553    "disable-paranoia|Z:i"   => \$pparano,
554 )
555 or exit print_usage();
556 #
557 # New options step 5: Add the command line option here.
558 #
559 #
560 ########################################################################
561 #
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!
569 #
570 # New options step 6: force use of command line options if passed.
571 #
572 #
573 # First for the normal options, e. g. options which are never zero.
574 #
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);
596 #
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);
630 #
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;
658 }
659 else {
660    $scsi_cddev = $pcddev if($pcddev);
661 }
662 $span = $pspan if defined $pspan;
663 $trackoffset = $ptrackoffset if defined $ptrackoffset;
664 $verbose = $pverbose if defined $pverbose;
665 $vatag = $pvatag if defined $pvatag;
666 #
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;
688 #
689 ########################################################################
690 #
691 # Preliminary start: print version, read (and write) config file.
692 #
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
695 # by config file.
696 #
697 my $ripdir = $confdir . "/" . $confname if($confdir ne "");
698 # Fallback:
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>;
704    close(CONF);
705    chomp($verbose = join('', grep(s/^verbose=//, @conflines)))
706       unless($pverbose);
707    chomp($infolog = join('', grep(s/^infolog=//, @conflines)))
708       unless($pinfolog);
709 }
710 #
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.
715 if($infolog) {
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";
719 }
720 log_info("RipIT version $version infolog-file.\n");
721 #
722 #
723 # Do some checks before writing a new config file (if wanted):
724 #
725 # First check if arguments of option merge are OK.
726 my @dummy = skip_tracks if($pmerge);
727 #
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.
735 #
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.
738 #
739    $chars = "" if($chars eq "XX" && ($savenew == 1 || $savepara == 1));
740    if($savenew == 1) {
741       $verbose = 3; # Set back to default value.
742       $infolog = ""; # Set back to default value.
743       save_config();
744       print "Saved a new config file!\n\n" if($verbose >= 3);
745    }
746 #
747 # Read the config file.
748 #
749    read_config() if($config == 1);
750    check_enc("lame", "mp3");
751 #   check_enc("faac", "m4a");
752 #
753 # Check if the necessary modules are installed properly.
754 #
755    init_mod;
756 #
757 #
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.
762 #
763 # New options step 7: not mandatory, might be useful.
764 #
765    $copycover = "" unless($copycover);
766    $uppercasefirst = 0 unless($uppercasefirst);
767    $mb = 0 unless($mb);
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);
782 #
783 # Save the config file.
784 #
785    save_config() if($savepara == 1);
786    print "Updated the config file!\n\n"
787       if($verbose >= 3 && $savepara == 1);
788 #
789 # It might be a good to x-check settings from config file because they
790 # can be edited manually.
791 #
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.
797 }
798 #
799 ########################################################################
800 #
801 # MAIN ROUTINE
802 #
803 ########################################################################
804 #
805 if($printver) {
806    print "\n";
807    exit 2;
808 }
809
810 if($verbose >= 2) {
811    print "Process summary:\n", "-" x 16, "\n" unless($help == 1);
812 }
813
814 if($help == 1) {
815    print "\nThis is a shorten man page. Refer to the full manpage ",
816          "for more details.\n";
817    print_help();
818    exit 3;
819 }
820
821 if(!$pcddev) {                 # Check CD dev if none defined.
822    check_cddev;
823 }
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");
829 }
830
831 if($scsi_cddev eq "") {
832    $scsi_cddev = $cddev;
833 }
834
835 if($chars) {
836    check_chars;
837 }
838
839 if($lcd == 1) {
840    init_lcd();
841 }
842
843 if($outputdir eq "") {
844    $outputdir = $homedir;
845    chomp $outputdir;
846 }
847
848 if($outputdir =~ /^\.\//) {
849    $outputdir =~ s/^\./$workdir/;
850 }
851 elsif($outputdir =~ /^\.\s*$/) {
852    $outputdir =~ s/^\./$workdir/;
853 }
854
855 if($outputdir =~ /^~\//) {
856    $outputdir =~ s/^~/$homedir/;
857 }
858
859 if($outputdir =~ /^\$HOME/) {
860    $outputdir =~ s/^\$HOME/$homedir/;
861 }
862
863 # New options step 8: Add a message about selected options if needed.
864
865 if(length($year) > 0 && length($year) != 4 ) {
866    print STDERR "Warning: year should be in 4 digits - $year.\n"
867       if($verbose >= 1);
868 }
869
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";
874 }
875
876 if($fpermission && $verbose >= 2) {
877    $fpermission = sprintf("%04d", $fpermission);
878    print "File permission will be set to $fpermission.\n";
879 }
880
881 if($resume == 1 && $verbose >= 2) {
882    print "Resuming previous session.\n";
883 }
884
885 if($span && $verbose >= 2) {
886    print "Partial wav files will be ripped.\n" unless($span =~ /\d-$/);
887 }
888
889 if($wav == 1 && $verbose >= 2) {
890    print "Wav files will not be deleted.\n";
891 }
892
893 if($normalize == 1 && $verbose >= 2) {
894    print "Normalizeing the CD-tracks.\n";
895 }
896
897 if($book >= 1 && $verbose >= 2) {
898    print "All tracks will be merged into one file and a chapter file written.\n";
899    $pmerge = "1-";
900    $ghost = 0;
901 }
902
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);
906    $ghost = 0;
907    $ghost = 1 if($cdcue == 1);
908 }
909
910 if($cdtoc >= 1 && $verbose >= 2) {
911    print "A toc file will be written.\n";
912 }
913
914 if($inf >= 1 && $verbose >= 2) {
915    print "Inf files will be written for each track.\n";
916 }
917
918 if($ghost == 1) {
919    print "Tracks will be analyzed for ghost songs.\n" if($verbose >= 2);
920 }
921
922 if($utftag == 0 && $verbose >= 2 && "@coder" =~ /0/) {
923    print "Lame-tags will be encoded to ISO8859-1.\n";
924 }
925
926 if($mp3tags[0] && $verbose >= 2 ) {
927    print "Special track tags will be added to mp3 files.\n";
928 }
929
930 if($vatag > 0 && $verbose >= 2 ) {
931    print "Track tags will be analyzed for VA style.\n";
932 }
933
934 if($playlist >= 1 && $verbose >= 2) {
935    print "Playlist (m3u) file will be written.\n";
936 }
937
938 if($md5sum == 1 && $verbose >= 2) {
939    print "MD5SUMs of sound files will be calculated.\n";
940 }
941
942 if($copycover && $verbose >= 2) {
943    print "Copying the cover to encoder directories.\n";
944 }
945
946 if($coverart =~ /1/ && $verbose >= 2) {
947    print "Adding coverart to sound files.\n";
948 }
949
950 if(($mp3gain || $vorbgain || $flacgain || $aacgain || $mpcgain || $wvgain)
951    && $encode == 1 && $verbose >= 2) {
952    print "Adding album gain tags to sound files.\n";
953 }
954
955 if($parano >= 3 && $verbose >= 2 ) {
956    print "Warning: paranoia argument unknown, will use paranoia.\n";
957    $parano = 1;
958 }
959
960 if($halt == 1 && $verbose >= 2) {
961    print "Halting machine when finished.\n";
962 }
963
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);
967 }
968
969 if($loop >= 1) {
970    print "Endless looping and ejection of each CD.\n" if($verbose >= 2);
971    print "\n" if($verbose >= 2);
972    while($loop >= 1) {
973       main_sub;
974       last if($loop == 0);
975       init_var;
976       print "Please insert a new CD!\n" if($verbose >= 1);
977       while( not cd_present() ) {
978          sleep(6);
979       }
980    }
981 }
982 else {
983    print "\n" if($verbose >= 2);
984    main_sub;
985 }
986 exit;
987 #
988 ########################################################################
989 #
990 # Main subroutine.
991 #
992 ########################################################################
993 #
994 sub main_sub {
995    if(@ARGV) {
996       $trackselection = $ARGV[0];
997    }
998
999    if($bitrate ne "off" && $lameflag == 1) {
1000       check_bitrate;
1001    }
1002
1003    if($vbrmode ne "" && $lameflag == 1) {
1004       check_vbrmode;
1005    }
1006
1007    if($preset) {
1008       lame_preset;
1009    }
1010
1011    unless( cd_present() ) {
1012       print "\nPlease insert an audio CD!\n" if($verbose > 0);
1013       while( not cd_present() ) {
1014          check_cddev;
1015          sleep(12);
1016       }
1017    }
1018    if($archive == 1 && $multi == 0) {
1019       get_arch()
1020    }
1021    else {
1022       get_cdinfo() if($mb == 0);
1023       get_mb() if($mb == 1);
1024    }
1025    disp_info;
1026    create_seltrack($trackselection);
1027    ask_subm();
1028    my $answer = create_dirs();
1029
1030    if($answer eq "go") {
1031       if($precmd) {
1032          $precmd =~ s/\$/\\\$/g;
1033          print "Will execute command \"$precmd\".\n" if($verbose >= 3);
1034          log_system("$precmd");
1035       }
1036       if(-f "$copycover" && -s "$copycover") {
1037          copy_cover;
1038       }
1039       elsif($copycover ne "") {
1040          print "\nAlbum cover with path $copycover not found.\n"
1041          if($verbose > 2);
1042          if($interaction == 1) {
1043             check_cover;
1044             copy_cover if(-f "$copycover" && -s "$copycover");
1045          }
1046       }
1047       if($normalize == 1 or $cdcue > 0) {
1048          rip_cd();
1049          norm_cd() if($normalize == 1);
1050          enc_cd();
1051       }
1052       else {
1053          rip_cd();
1054       }
1055    }
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");
1061    }
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");
1066    }
1067
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");
1073    }
1074
1075    return if($answer eq "next" or $answer eq "unknown");
1076
1077    if($loop == 2) {
1078
1079       my $pid = fork();
1080       if (not defined $pid) {
1081          print "\nResources not avilable, will quit.\n";
1082       }
1083       elsif($pid != 0) {
1084          finish_process($pid);
1085       }
1086       else {
1087          # Child: restart process.
1088          return;
1089          # Problem: being recursive, we won't come back! Hello zombie.
1090          exit(0);
1091       }
1092    }
1093    else {
1094       finish_process();
1095    }
1096    $loop = 0 if($loop == 2);
1097    return;
1098 }
1099 #
1100 ########################################################################
1101 #
1102 # SUBROUTINES
1103 #
1104 ########################################################################
1105 #
1106 # New options step 9: Add new code as a subroutine somewhere below,
1107 # the very end might be appropriate.
1108 #
1109 ########################################################################
1110 #
1111 # Check local .cddb directory for cddb files with album, artist, discID
1112 # and track titles.
1113 #
1114 sub get_arch {
1115    # Get cddbid and number of tracks of CD.
1116    my $trackno;
1117    ($cddbid, $trackno) = get_cddbid();
1118
1119    my ($artist, $album);
1120    my @comment = ();
1121
1122    if($pgenre) {
1123       $genre = $pgenre;
1124    }
1125    else {
1126       $genre = "";
1127    }
1128    if($pyear) {
1129       $year = $pyear;
1130    }
1131    else {
1132       $year = "";
1133    }
1134
1135    my $usearch = "x";
1136    my @categs = ();
1137
1138
1139    print "\nChecking for a local DB entry, please wait...\n\n"
1140       if($verbose > 1);
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));
1146    close(CDDB);
1147    my @cddbid = ();
1148    foreach (@categs) {
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));
1153          close(CATEG);
1154          push @cddbid, $_ if($entries[0]);
1155       }
1156       elsif(-f "$homedir/.cddb/$_" && -s "$homedir/.cddb/$_") {
1157          push @cddbid, $_ if($_ =~ /$cddbid/);
1158       }
1159    }
1160    my $count = 1;
1161    my @dirflag = ();
1162    if($cddbid[0]) {
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);
1166       foreach (@cddbid) {
1167          my $openflag = "no";
1168          if(-s "$homedir/.cddb/$_/$cddbid") {
1169             open(LOG, "$homedir/.cddb/$_/$cddbid");
1170             $openflag = "ok";
1171             $dirflag[$count-1] = 1;
1172          }
1173          elsif(-s "$homedir/.cddb/$cddbid") {
1174             open(LOG, "$homedir/.cddb/$cddbid");
1175             $_ = "no category found!";
1176             $openflag = "ok";
1177             $dirflag[$count-1] = 0;
1178          }
1179          if($openflag eq "ok") {
1180             my @loglines = <LOG>;
1181             close(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);
1191             $count++;
1192             $agenre = "";
1193          }
1194       }
1195       print "\n0: Search online DB instead.\n"
1196          if($interaction == 1);
1197       if($interaction == 0) {
1198          $usearch = 1;
1199       }
1200       else {
1201          while($usearch !~ /\d/ || $usearch >= $count) {
1202             print "\nChoose: (1) ";
1203             $usearch = <STDIN>;
1204             chomp $usearch;
1205             $usearch = 1 if($usearch eq "");
1206             print "\n";
1207          }
1208       }
1209    }
1210    else {
1211       get_cdinfo() if($mb == 0);
1212       get_mb() if($mb == 1);
1213       return;
1214    }
1215
1216    if($usearch != 0) {
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",
1225             $ctg, $trackno);
1226       }
1227       elsif($dirflag[$usearch-1] == 0) {
1228          read_entry("$homedir/.cddb/$cddbid", $ctg, $trackno);
1229       }
1230       $categ = $cd{cat} = $cddbid[$usearch-1];
1231    }
1232    else {
1233       get_cdinfo() if($mb == 0);
1234       get_mb() if($mb == 1);
1235       return;
1236    }
1237
1238    if($mb == 1) {
1239       open(DISCID, "discid $scsi_cddev|");
1240       my @response = <DISCID>;
1241       close(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.
1245       if($isrc == 1) {
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);
1255             }
1256          }
1257       }
1258    }
1259 }
1260 ########################################################################
1261 #
1262 # Read the album, artist, discID and track titles from the get_CDDB()
1263 # generated TOC file.
1264 #
1265 sub get_cdinfo {
1266    my $writecddb = shift; # Passed when calling this sub from get_mb.
1267    $writecddb = 0 unless($writecddb);
1268
1269    # Get cddbid and number of tracks of CD.
1270    my $trackno;
1271    ($cddbid, $trackno) = get_cddbid();
1272
1273    my ($artist, $album, %config, $revision);
1274    my ($CDDB_INPUT, $CDDB_MODE, $CDDB_PORT);
1275    my @comment = ();
1276
1277    if($pgenre) {
1278       $genre = $pgenre;
1279    }
1280    else {
1281       $genre = "";
1282    }
1283    if($pyear) {
1284       $year = $pyear;
1285    }
1286    else {
1287       $year = "";
1288    }
1289
1290
1291    #Configure CDDB_get parameters
1292    if($CDDB_HOST eq "freedb2.org") {
1293       $config{CDDB_HOST} = $CDDB_HOST;
1294    }
1295    elsif($CDDB_HOST eq "musicbrainz.org") {
1296       $config{CDDB_HOST} = "freedb." . $CDDB_HOST;
1297    }
1298    else {
1299       $config{CDDB_HOST} = $mirror . "." . $CDDB_HOST;
1300    }
1301    while($transfer !~ /^cddb$|^http$/) {
1302       print "Transfer mode not valid!\n";
1303       print "Enter cddb or http : ";
1304       $transfer = <STDIN>;
1305       chomp $transfer;
1306    }
1307    if($transfer eq "cddb") {
1308       $CDDB_PORT = 8880;
1309       $CDDB_MODE = "cddb";
1310    }
1311    elsif($transfer eq "http") {
1312       $CDDB_PORT = 80;
1313       $CDDB_MODE = "http";
1314    }
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) {
1320       $CDDB_INPUT = 0;
1321    }
1322    else {
1323       $CDDB_INPUT = 1;
1324    }
1325    $config{input} = $CDDB_INPUT;
1326    $config{PROTO_VERSION} = $proto;
1327
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);
1332    if($hid[4]) {
1333       print "There are more than 4 words in the \"HELLO_ID\"!\n",
1334             "The handshake with the freeDB-server will fail!\n\n";
1335    }
1336    $config{HELLO_ID} = $hid;
1337
1338    print "\nChecking for a DB entry \@ $config{CDDB_HOST}...\n"
1339       if($verbose >= 1 && $writecddb != 0);
1340    eval {%cd = get_cddb(\%config);};
1341    if($@) {
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);
1346       $submission = 0;
1347    }
1348    #
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
1357    # $writecddb == 0.
1358    #
1359    if($interaction == 0 && $archive == 1 && defined $cd{title}) {
1360        write_cddb() unless $writecddb == 0;
1361    }
1362
1363    if($multi == 1) {
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");
1369    }
1370 }
1371 ########################################################################
1372 #
1373 # Read the album, artist, discID and track titles from MusicBrainz.
1374 #
1375 sub get_mb {
1376
1377    print "Querying MusicBrainz DB." if($verbose > 2);
1378    my ($cddbid, $trackno, $totaltime) = get_cddbid();
1379
1380
1381    # Using the perl module to retrieve the MB discid.
1382    my $discid = 0;
1383    my $submit_url = 0;
1384    my $disc;
1385    eval{ $disc = new MusicBrainz::DiscID($scsi_cddev);};
1386    if($@) {
1387       # Use the libdiscid command discid to retrieve the MB discid.
1388       open(DISCID, "discid $scsi_cddev|");
1389       my @response = <DISCID>;
1390       close(DISCID);
1391       chomp($discid = join("", grep(s/^DiscID\s*:\s//, @response)));
1392       chomp($submit_url = join("", grep(s/^Submit\svia\s*:\s//, @response)));
1393    }
1394    else {
1395       if($disc->read() == 0) {
1396          print "Error: %s\n", $disc->error_msg();
1397          get_cdinfo();
1398          return;
1399       }
1400       $discid = $disc->id();
1401       $submit_url = $disc->submission_url();
1402    }
1403
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.
1407
1408    print "\nChecking for a DB entry \@ MusicBrainz.org...\n"
1409       if($verbose >= 1);
1410    my $service;
1411    eval {$service = WebService::MusicBrainz::Release->new();};
1412    my $discid_response;
1413    eval {$discid_response = $service->search({ DISCID => $discid });};
1414    if($@){
1415       print "\nMusicBrainz lookup failed... 2nd try in 3s.",
1416             "\nError message is: $@.\n" if($verbose > 3);
1417       sleep 3;
1418       eval {$discid_response = $service->search({ DISCID => $discid });};
1419       if($@){
1420          print "\nMusicBrainz lookup failed! Using freedb instead.",
1421                "\nError message is: $@.\n" if($verbose > 3);
1422          get_cdinfo();
1423          return;
1424       }
1425    }
1426    else {
1427       print "DiscID retrieved.\n" if($verbose > 4);
1428       print "Discid is: $discid.\n" if($verbose > 3);
1429    }
1430    # Print the data for further queries.
1431 #    use Data::Dumper;
1432 #    print Dumper($discid_response);
1433 #    print "*" x 72, "\n\n";
1434 #   exit(1);
1435
1436    my $mbid;
1437    eval {$mbid = $discid_response->release()->id();};
1438    if($@){
1439       print "\nMusicBrainz does not know this discid! Use\n",
1440             "$submit_url for submission!\n" if($verbose > 1);
1441       get_cdinfo();
1442       return;
1443    }
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);
1448    }
1449
1450    my $mbid_response;
1451    eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'artist' });};
1452    if($@){
1453       print "\nMusicBrainz artist lookup failed... 2nd try in 3s.",
1454             "\nError message is: $@.\n" if($verbose > 3);
1455       sleep 3;
1456       eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'artist' });};
1457       if($@){
1458          print "\nMusicBrainz lookup artist failed!",
1459                "\nUsing freedb instead.",
1460                "\nError message is: $@.\n" if($verbose > 3);
1461          get_cdinfo();
1462          return;
1463       }
1464    }
1465    else {
1466       print "MB artist retrieved.\n" if($verbose > 4);
1467    }
1468
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");
1479
1480    # Retrieve the year and barcode:
1481    eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'release-events' });};
1482    if($@){
1483       print "\nMusicBrainz lookup failed... 2nd try in 3s:\n" if($verbose > 3);
1484       sleep 3;
1485       eval {$mbid_response = $service->search({ MBID => $mbid, INC => 'release-events' });};
1486       if($@){
1487          print "\nMusicBrainz lookup failed! Using freedb instead.\n"
1488             if($verbose > 3);
1489          get_cdinfo();
1490          return;
1491       }
1492    }
1493    else {
1494       print "MB release eventrs retrieved.\n" if($verbose > 4);
1495    }
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);
1500    $year = $reldate;
1501    $year =~ s/-.*$// if($year);
1502
1503    # Some people insist in getting a genre, but MB does not supply one.
1504    unless($genre) {
1505       my $save_inter = $interaction;
1506       $interaction = 0;
1507       print "Retrieving a genre from freedb.org.\n" if($verbose > 2);
1508       get_cdinfo(0);
1509       $interaction = $save_inter;
1510       $genre = $cd{genre};
1511       $year = $cd{year} unless($year);
1512    }
1513
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);
1533
1534
1535    # figure out number of disks and possible track offset
1536    eval {
1537        my $ua = LWP::UserAgent->new();
1538        $ua->env_proxy();
1539        $ua->agent("ripit/$version");
1540        my $response = $ua->get("http://musicbrainz.org/ws/2/release/$mbid?inc=media+discids");
1541        use XML::Simple;
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) {
1548                    last;
1549                }
1550                $trackoffset += $medium->{'track-list'}{count};
1551            }
1552        }
1553    };
1554    print STDERR $trackoffset."\n";
1555    print STDERR "discid $discid\n";
1556    print STDERR $@;
1557
1558    # Retrieve the track list.
1559    eval {$mbid_response = $service->search({ DISCID => $discid, INC => 'tracks' });};
1560    if($@){
1561       print "\nMusicBrainz lookup failed...  [$@] 2nd try in 3s:\n";# if($verbose > 3);
1562       sleep 3;
1563       eval {$mbid_response = $service->search({ DISCID => $discid, INC => 'tracks' });};
1564       if($@){
1565          print "\nMusicBrainz lookup failed! Using freedb instead.\n"
1566             if($verbose > 3);
1567          close(TMP);
1568          unlink("$temp_file");
1569          get_cdinfo();
1570          return;
1571       }
1572    }
1573    else {
1574       print "MB track list retrieved.\n" if($verbose > 4);
1575    }
1576    $release = $mbid_response->release();
1577    my $track_list = $release->track_list();
1578    my $mb_trackno = $#{$track_list->tracks()} + 1;
1579
1580    my $i=1;
1581    my $j=0;
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";
1587          $va_flag = 2;
1588          $va_delim = "/";
1589       }
1590       # Normal tracklist style.
1591       else {
1592          print TMP "track $i: $_\n";
1593       }
1594       # For ISRC detection/submission use the track IDs.
1595       push(@idata, $track->id);
1596       $i++;
1597       $j++;
1598    }
1599
1600    close(TOC);
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";
1605       $i++;
1606       $j++;
1607    }
1608    close(TMP);
1609    read_entry("$temp_file", "musicbrainz", $trackno);
1610    unlink("$temp_file");
1611 }
1612 ########################################################################
1613 #
1614 # Display CDDB info.
1615 #
1616 sub disp_info {
1617    my $latinflag = 0;
1618    my $wideflag = 0;
1619    my $utf_latinflag = 0;
1620    my $utf_wideflag = 0;
1621    my ($artist, $album, %config, $revision);
1622    my @comment = ();
1623
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});
1629
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);
1639       $categ = $cd{cat};
1640
1641       # Set the year if it wasn't passed on command line.
1642       unless($year) {
1643          $year = $cd{year} if($cd{year});
1644          $year =~ s/[\015]//g if($year);
1645       }
1646
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);
1651       }
1652
1653       @comment = extract_comm;
1654       $revision = get_rev() unless($cd{discid});
1655       # In case of corrupted (local) DB files.
1656       $revision = "unknown" unless($revision);
1657    }
1658    else {
1659       if($submission == 0) {
1660          print "\nNo CDDB info chosen or found for this CD\n"
1661             if($verbose >= 1);
1662       }
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) {
1667          create_deftrack(1);
1668       }
1669       # ... or ask whether 1) default or 2) manual entries shall be used
1670       # or entered.
1671       else {
1672          create_deftrack(2);
1673       }
1674       $album = $cd{title};
1675       $artist = $cd{artist};
1676       $revision = $cd{revision};
1677    }
1678
1679    if($cd{discid}) {
1680       # We do nothing anymore because we read the data from a file.
1681    }
1682    else {
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!
1690       #
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}});
1695
1696       ($latinflag, $wideflag, $utf_latinflag, $utf_wideflag) =
1697          check_encoding($char_string);
1698
1699       if($utf_latinflag >= $latinflag * 3 && $utf_wideflag == 0 && $wideflag == 0) {
1700          print "\nRare case: Decoding from iso 8859-1 to utf-8?\n"
1701             if($verbose >= 5);
1702          Encode::from_to($artist, 'iso-8859-1', 'UTF-8');
1703          Encode::from_to($album, 'iso-8859-1', 'UTF-8');
1704       }
1705       elsif($wideflag == 0 && $latinflag == 0) {
1706          print "No wide char found, artist is <$artist>.\n"
1707             if($verbose >= 5);
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);
1712       }
1713       elsif($utf_wideflag == 1 && $wideflag == 0) {
1714          print "\nForcing UTF8 case 1:\n"
1715             if($verbose >= 5);
1716          $album =  Encode::decode('UTF-8', $album);
1717          $artist =  Encode::decode('UTF-8', $artist);
1718       }
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"
1721             if($verbose >= 5);
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);
1725       }
1726       elsif($utf_wideflag > 0 && $wideflag >= 0) {
1727          print "\nTrying to force UTF8 case 3: source might be utf8!\n"
1728             if($verbose >= 5);
1729          # Keep it commented for the clean archive Enya case.
1730 #         $album =  Encode::decode('UTF-8', $album);
1731 #         $artist =  Encode::decode('UTF-8', $artist);
1732       }
1733       else {
1734          print "\nDon't know what to do. Is it cp-1252 or iso 8859-1?\n"
1735             if($verbose >= 5);
1736       }
1737    }
1738
1739
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
1745 # hash screwed up?
1746
1747    $album_utf8 = $album;
1748    $artist_utf8 = $artist;
1749
1750    my $genreno = "";
1751    if($genre eq "" && $interaction == 1) {
1752       print "\nPlease enter a valid CDDB genre (or none): ";
1753       $genre = <STDIN>;
1754       chomp $genre;
1755       $cd{genre} = $genre;
1756    }
1757    if($genre) {
1758       $genre =~ s/[\015]//g;
1759       ($genre,$genreno) = check_genre($genre);
1760    }
1761
1762    if($verbose >= 1) {
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);
1767       if($genre) {
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";
1772          }
1773       }
1774       else{
1775          print "ID3-Genre: none\n";
1776       }
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";
1787       }
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($_);
1793          }
1794       }
1795       print "CD length: $totaltime\n";
1796       print "\n";
1797    }
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");
1807
1808    # Read out pregap before calculating track lengths.
1809    my $frames = $toc->[0]->{'frames'};
1810    push @framelist, "$frames";
1811    if($frames > 400) {
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")
1820          if($verbose >= 1);
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)
1826          if($verbose >= 1);
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);
1839    }
1840    my $n = 1;
1841    # Print track information.
1842    foreach (@{$cd{track}}) {
1843       $_ = clean_all($_);
1844       $_ = change_case($_) if($uppercasefirst == 1);
1845
1846       if($cd{discid}) {
1847          # We do nothing anymore because we read the data from a file.
1848       }
1849       else {
1850          if($utf_latinflag >= $latinflag * 3 && $utf_wideflag == 0 && $wideflag == 0) {
1851             Encode::from_to($_, 'iso-8859-1', 'UTF-8');
1852          }
1853          elsif($latinflag == 0 && $wideflag == 0) {
1854             $_ = UTF8_encoding($_);
1855          }
1856          elsif($utf_wideflag == 1 && $wideflag == 0) {
1857             $_ =  Encode::decode('UTF-8', $_);
1858          }
1859       }
1860       push @tracktags, $_;
1861
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, $_)
1874          if($verbose >= 2);
1875       $_ = clean_name($_);
1876       $_ = change_case($_);
1877       $_ =~ s/ /_/g if($underscore == 1);
1878       push @tracklist, $_;
1879       $n++;
1880    }
1881    print "\n\n" if($verbose >= 1);
1882
1883    # Some more error checking.
1884    if($artist eq "") {
1885       die "Error: No artist found!\n";
1886    }
1887    unless($tracklist[0]) {
1888       die "Error: No tracks found!\n";
1889    }
1890
1891    get_isrcs if($isrc == 1 && $mb == 1);
1892
1893    # LCDproc
1894    if($lcd == 1) {
1895       $lcdline1 = $artist . "-" . $album;
1896       $lcdline2 = "R00|00.0%|----------";
1897       $lcdline3 = "E00|00.0%|----------";
1898       ulcd();
1899    }
1900 }
1901 ########################################################################
1902 #
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.
1906 #
1907 sub create_seltrack {
1908    my($tempstr,$intrack);
1909    ($tempstr) = @_;
1910    if($_[0] eq "-") {
1911          die "Invalid track selection \"-\"!\n\n";
1912    }
1913
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) . "-";
1919       }
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 ",
1928                       "on CD.\n\n";
1929                }
1930             }
1931             for(my $i = $outrack[0]; $i <= $outrack[1]; $i++) {
1932                push @seltrack, $i;
1933             }
1934          }
1935          else {
1936             push @seltrack, $intrack;
1937          }
1938       }
1939    }
1940    elsif($tempstr eq '') {
1941       for(my $i = 1; $i <= ($#tracklist + 1); $i++) {
1942          $seltrack[$i - 1] = $i;
1943       }
1944    }
1945    elsif($tempstr =~ /^[0-9]*[0-9]$/) {
1946       $seltrack[0] = $tempstr;
1947    }
1948    else {
1949       die "Track selection invalid!\n";
1950    }
1951
1952    @seltrack = sort {$a <=> $b} @seltrack;
1953
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";
1958       }
1959       elsif($_ == 0) {
1960          shift @seltrack;
1961       }
1962    }
1963 }
1964 ########################################################################
1965 #
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.
1973 #
1974 sub ask_subm {
1975    my $index = 2;
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) ";
1983          $index = <STDIN>;
1984          chomp $index;
1985          if($index eq "") {
1986             $index = 0;
1987          }
1988          print "\n";
1989       }
1990       if($index == 1) {
1991          my $revision = get_rev() unless($cd{discid});
1992          if($revision) {
1993             print "\nPlease change some settings.";
1994             print "\nYou may confirm CDDB settings with \"enter\".\n";
1995             create_deftrack(0);
1996          }
1997          else {
1998             print "\nPlease change some settings.";
1999             print "\nYou may confirm given settings with \"enter\".\n";
2000             create_deftrack(0);
2001          }
2002       }
2003       elsif($index == 0) {
2004          #
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}) {
2008              write_cddb();
2009          }
2010       }
2011       else {
2012          print "Choose 0 or 1!\n";
2013       }
2014    }
2015    if($index == 1) {
2016       pre_subm();
2017    }
2018
2019    # Once the metadata has been altered (optionally), check for
2020    # VA style.
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;
2026    my $n = 0;
2027    if($vatag > 0) {
2028       # We call check_va only to print detected results if verbosity is
2029       # switched on.
2030       my $delim = check_va(1);
2031       if($interaction == 1) {
2032          $index = 9;
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) ";
2037             $index = <STDIN>;
2038             chomp $index;
2039             if($index eq "") {
2040                $index = $vatag;
2041             }
2042             print "\n";
2043             $vatag = $index;
2044          }
2045       }
2046    }
2047    return;
2048 }
2049 ########################################################################
2050 #
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).
2058 #
2059 sub create_dirs {
2060    my $c = -1;
2061
2062    # Get cddbid and number of tracks of CD.
2063    my $trackno;
2064    ($cddbid, $trackno) = get_cddbid();
2065
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");
2071
2072       # Why this? Remember, we have worked a lot with encoding of artist
2073       # and album names!
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);
2084
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);
2090          shift(@words);
2091          foreach (@words) {
2092             $iletter = $_;
2093             $iletter =~ s/\s*(.).*/$1/;
2094             last if($iletter =~ /\w{1}/);
2095          }
2096       }
2097       $iletter = "A" unless($iletter);
2098       $iletter = "\u$iletter" unless($lowercase == 1);
2099
2100       # Take the last dirtemplate for missing ones and for wav.
2101       my $dirindex = $c;
2102       if($suffix eq "wav") {
2103          $dirindex = $#dirtemplate;
2104       }
2105       elsif($c > $#dirtemplate) {
2106          $dirindex = $#dirtemplate;
2107       }
2108
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));
2115       }
2116       # Do the same for the genre.
2117       if(($dirtemplate[$dirindex] =~ /\$genre/ or
2118           $tracktemplate =~ /\$genre/)) {
2119          $genre = "Other" if($genre eq "");
2120          chomp $genre;
2121       }
2122
2123       my $dir;
2124       if(!eval("\$dir = $dirtemplate[$dirindex]")) {
2125          die "Directory template incorrect, caused eval to fail: $!\n";
2126       }
2127
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);
2139
2140       $dir =~ s/\.+$// if($chars =~ /NTFS/);
2141       $dir =~ s/^\///;
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.
2146       #
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.
2154       #
2155       my $cdexistflag = 0;
2156       my $i = 1;
2157       my $nsoundir = $soundir;
2158       my $sfx = "";
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;
2165          $i++;
2166          $cdexistflag = 1;
2167       }
2168       return "next" if($cdexistflag == 1 && $overwrite =~ /^e|q$/);
2169       return "unknown" if($artist =~ /unknown.artist/i && $album =~ /unknown.album/i && $quitnodb == 1);
2170
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!
2175       esc_char($soundir);
2176       $nsoundir = $wavdir if($wavdir =~ /$soundir.\d+/);
2177
2178       if($multi == 1 && $_ eq "wav") {
2179          if($overwrite =~ /^y$/) {
2180             $cdexistflag = 0;
2181             $sfx = "";
2182          }
2183          my $aadir = $dir . $sfx;
2184          if($cdexistflag == 1) {
2185             $i--;
2186             open(SRXY,"$logfile") or
2187                print "Can not open \"$logfile\"!\n";
2188             my @srxylines = <SRXY>;
2189             close(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";
2199             close(SRXY);
2200          }
2201          open(SRXY,">>$logfile")
2202             or print "Can not append to file \"$logfile\"!\n";
2203          print SRXY "\n\nArtist - Album:$aadir";
2204          close(SRXY);
2205       }
2206       $soundir = $nsoundir;
2207       $soundir =~ s;/$;;g;
2208
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
2212       # succeed.
2213       #
2214       # Save machines umask for reset.
2215       my $umask = umask();
2216
2217       # Get the default permission mode.
2218       my $dperm = sprintf("%04o", 0777 & ~umask());
2219
2220       if(!opendir(TESTDIR, $soundir)) {
2221          # Explicitly log soundir creation.
2222          log_info("new-mediadir: $soundir");
2223
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)) {
2228             next if($_ eq " ");
2229             # Should we allow relative paths?
2230             if($_ =~ /^\.{1,2}$/ && $growing_dir eq "") {
2231                $growing_dir .= "$_";
2232             }
2233             else {
2234                $growing_dir .= "/$_";
2235             }
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) {
2242                      chop;
2243                      chop($growing_dir);
2244                   }
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...
2249                   #use File::Path;
2250                   #eval { mkpath($growing_dir) };
2251                   #if($@) {
2252                   #   die "\nRelease directory $growing_dir creation failed : $!\n\n";
2253                   #}
2254                   log_system("mkdir -m $dpermission -p \"$growing_dir\"")
2255                      or die "Can not create directory $growing_dir: $!\n";
2256                   $limit_flag = 255;
2257                }
2258             }
2259          }
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";
2265       }
2266       else {
2267          closedir(TESTDIR);
2268       }
2269
2270       # Reset umask
2271       #umask($umask) if defined $umask;
2272
2273       $sepdir[$c] = $soundir unless($_ eq "wav");
2274       $wavdir = $soundir if($_ eq "wav");
2275       $c++;
2276
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") {
2281          my $exec;
2282          if(!eval("\$exec = $execmd")) {
2283             print "execmd incorrect, caused eval to fail: $!\n";
2284          }
2285          $execmd = $exec;
2286       }
2287       if($precmd && $suffix eq "wav") {
2288          my $prec;
2289          if(!eval("\$prec = $precmd")) {
2290             print "precmd incorrect, caused eval to fail: $!\n";
2291          }
2292          $precmd = $prec;
2293       }
2294       if($coverpath && $suffix eq "wav") {
2295          my $covp;
2296          if(!eval("\$covp = $coverpath")) {
2297             print "coverpath incorrect, caused eval to fail: $!\n";
2298          }
2299          $coverpath = $covp;
2300       }
2301       if($copycover && $suffix eq "wav") {
2302          my $copy;
2303          if(!eval("\$copy = $copycover")) {
2304             print "copycover path incorrect, caused eval to fail: $!\n";
2305          }
2306          $copycover = $copy;
2307       }
2308    }
2309    return("go");
2310 }
2311 ########################################################################
2312 #
2313 # Create the full-path track file name from the tracktemplate variable.
2314 #
2315 sub get_trackname {
2316    my($trnum, $trname, $riptrname, $shortflag);
2317
2318    ($trnum, $trname, $shortflag) = @_;
2319    $shortflag = 0 unless($shortflag);
2320
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;
2333    }
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";
2344       }
2345    }
2346    else {
2347       $trname  = change_case($trname);
2348       $trname =~ s/ /_/g if($underscore == 1);
2349       $riptrname = $trname;
2350    }
2351
2352    if($limit_flag == 255) {
2353       $riptrname = substr($riptrname, 0, 250);
2354    }
2355
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/);
2359    }
2360    return $riptrname;
2361 }
2362 ########################################################################
2363 #
2364 # Rip the CD.
2365 #
2366 sub rip_cd {
2367    my($ripcom, $riptrackname, $riptracktag);
2368    my $startenc = 0;
2369    my $failflag = 0;
2370    my $resumerip = $resume;
2371    my $trackstart = 0;
2372    my $cue_point = 0;
2373    # Cleaning.
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);
2384
2385    # Delete existing md5 files in case of resuming.
2386    if($md5sum == 1 && $resume == 1) {
2387       if($wav == 1) {
2388          my @paths = split(/\//, $wavdir);
2389          my $md5file =  $paths[$#paths] . " - wav" . ".md5";
2390          $md5file =~ s/ /_/g if($underscore == 1);
2391          unlink("$wavdir/$md5file");
2392       }
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");
2398       }
2399    }
2400
2401    # Delete machine.lock files.
2402    if($resume == 1) {
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]);
2406       closedir(DIR);
2407       unlink("$wavdir/$_") foreach (@lockfiles);
2408    }
2409
2410    # Define an array with intervals and the tracks to be skipped.
2411    my @merge = ();
2412    my @skip = ();
2413    if($pmerge) {
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
2422       # track names.
2423       my $concat = " + ";
2424       $concat =~ s/ /_/g if($underscore == 1);
2425       $concat = clean_chars($concat) if($chars);
2426       foreach(@merge) {
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);
2437             $bea[0]++;
2438          }
2439       }
2440    }
2441
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.
2446    my $trackcn;
2447    my $prevtcn = -1;
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);
2453       my $trackno;
2454       # Check if next tracknumber is in the skip array of tracks being
2455       # merged. If so, add a hyphen.
2456       my $increment = 1;
2457       if($skip[0] && ($trackcn + $increment) =~ /^$skip[0]$/) {
2458          $trackno = $trackcn . "-";
2459          shift(@skip);
2460          $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]$/) {
2464            $trackcn++;
2465            shift(@skip);
2466          }
2467          $trackno = $trackno . $trackcn;
2468          $prevtcn = $trackcn;
2469       }
2470       else {
2471          $trackno = $trackcn;
2472       }
2473       push(@printracks, $trackno);
2474    }
2475
2476    if($#seltrack == 0 && $hiddenflag == 0) {
2477       print "Track @printracks will be ripped.\n\n" if($verbose > 0);
2478    }
2479    elsif(!@seltrack && $hiddenflag == 1) {
2480       print "Track 0 will be ripped.\n\n" if($verbose > 0);
2481    }
2482    elsif($pmerge && $pmerge =~ /^0/ && $hiddenflag == 1) {
2483       print "Tracks @printracks will be ripped.\n\n" if($verbose > 0);
2484    }
2485    elsif($hiddenflag == 1) {
2486       print "Tracks 0 @printracks will be ripped.\n\n" if($verbose > 0);
2487    }
2488    else {
2489       print "Tracks @printracks will be ripped.\n\n" if($verbose > 0);
2490    }
2491
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";
2501    close(ERO);
2502    if($multi == 1) {
2503       open(SRXY,">>$logfile")
2504          or print "Can not append to file \"$logfile\"!\n";
2505       print SRXY "\nRipping started: $ripstart";
2506       close(SRXY);
2507    }
2508
2509    # Write a toc-file.
2510    if($cdtoc == 1) {
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";
2531       close(CDTOC);
2532    }
2533
2534    # Start to rip the hidden track if there's one: First check if
2535    # cdparanoia is available.
2536    if($ripper != 1) {
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);
2541          $hiddenflag = 0;
2542       }
2543    }
2544
2545    # Check if the hidden track has been done in a previous session.
2546    my $checknextflag = 0;
2547    if($resumerip) {
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);
2555       }
2556       elsif(-r "$wavdir/$riptrackname.wav") {
2557          $checknextflag = 1;
2558          print "Found $riptrackname.wav.\n" if($verbose >= 1);
2559          md5_sum("$wavdir", "$riptrackname.wav", 0)
2560             if($md5sum == 1 && $wav == 1);
2561       }
2562       else{
2563          for(my $c=0; $c<=$#coder; $c++) {
2564             if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
2565                $checknextflag = 1;
2566                print "Found file $riptrackname.$suffix[$c].\n";
2567             }
2568          }
2569       }
2570       if($checknextflag == 1) {
2571          $riptrackname = "Hidden Track";
2572          unshift(@tracktags, $riptrackname);
2573          unshift(@seltrack, 0);
2574          unshift(@tracklist, $riptrackname);
2575       }
2576    }
2577
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;
2583
2584    # Write header of cue-file.
2585    if($cdcue > 0) {
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";
2590       close(CDCUE);
2591    }
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.
2608       my $endtrackno = 0;
2609       if($pmerge) {
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";
2619          }
2620       }
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);
2631
2632       unless(log_system("$ripcom")) {
2633          if($parano == 2) {
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"
2638                if($verbose > 1);
2639             unless(log_system("$ripcom")) {
2640                # If no success, shift the hidden track stuff out of
2641                # arrays.
2642                $hiddenflag = 0;
2643                shift(@secondlist);
2644                shift(@seltrack);
2645                shift(@tracklist);
2646                shift(@tracktags);
2647             }
2648          }
2649          else {
2650             # If no success, shift the hidden track stuff out of arrays.
2651             $hiddenflag = 0;
2652             shift(@secondlist);
2653             shift(@seltrack);
2654             shift(@tracklist);
2655             shift(@tracktags);
2656          }
2657       }
2658
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";
2667          close(CDTOC);
2668       }
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.
2673       my @times = (0);
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);
2682                }
2683       }
2684       if($hiddenflag == 1) {
2685          rename("$wavdir/$riptrackname.rip",
2686                 "$wavdir/$riptrackname.wav");
2687       }
2688       $ripopt = $saveripopt;
2689    }
2690
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";
2702       close(CDCUE);
2703    }
2704    # End preparation of ripping process.
2705    #
2706    #
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;
2711
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.
2715    my $encline = 0;
2716    $trackcn = 0;
2717
2718    foreach (@tracksel) {
2719       next if($_ == 0); # Skip hidden track.
2720       $trackcn++;
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);
2727
2728
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/) {
2734          $artistag = "";
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;
2743                $artistag = "";
2744             }
2745          }
2746          else {
2747             ($riptracktag, $artistag) = split(/$delim/, $riptracktag);
2748             $artistag =~ s/\)// if($delim =~ /\(/);
2749             $artistag =~ s/^\s*//;
2750             $riptracktag =~ s/\s*$//;
2751          }
2752       }
2753
2754       my $riptrackno = $_;
2755       # If we use option merge, skip a previously merged track:
2756       my $skipflag = 0;
2757       if($pmerge) {
2758          @skip = skip_tracks;
2759          foreach my $skip (@skip) {
2760             $skipflag = 1 if($_ == $skip);
2761          }
2762       }
2763       if(($cdtoc == 1 || $cdcue > 0) && $failflag == 0) {
2764          $cdtocn++;
2765       }
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";
2778          close(CDCUE);
2779       }
2780
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";
2800          close(CDTOC);
2801       }
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...
2813          }
2814       }
2815       # LCDproc
2816       if($lcd == 1) {
2817          my $_lcdtracks = scalar @tracksel;
2818          $lcdtrackno++;
2819          my $lcdperc;
2820          if($_lcdtracks eq $lcdtrackno) {
2821             $lcdperc = "*100";
2822          }
2823          else {
2824             $lcdperc = sprintf("%04.1f", $lcdtrackno/$_lcdtracks*100);
2825          }
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);
2830          ulcd();
2831       }
2832
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)
2837       # > 200 characters.
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 ",
2842                "WAV-file.\n"
2843             if($verbose > 2);
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);
2847       }
2848
2849       # Check for tracks already done if option --resume is on.
2850       $checknextflag = 0;
2851       if($resumerip) {
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) {
2861                $startenc = 1;
2862                open(ENCLOG,">$wavdir/enc.log");
2863                close(ENCLOG);
2864                unless(fork) {
2865                   enc_cd();
2866                }
2867             }
2868          }
2869
2870          if(-r "$wavdir/$riptrackname.rip") {
2871             unlink("$wavdir/$riptrackname.rip");
2872             print "Found $riptrackname.rip.\n" if($verbose >= 1);
2873          }
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);
2877          }
2878          elsif(-r "$wavdir/$riptrackname.wav") {
2879             $checknextflag = 1;
2880             print "Found $riptrackname.wav.\n" if($verbose >= 1);
2881             if($md5sum == 1 && $wav == 1) {
2882                md5_sum("$wavdir", "$riptrackname.wav", 0);
2883             }
2884          }
2885          elsif($wav == 0) {
2886             for(my $c = 0; $c <= $#coder; $c++) {
2887                if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
2888                   $checknextflag = 1;
2889                   print "Found file $riptrackname.$suffix[$c].\n"
2890                      if($verbose >= 1);
2891                }
2892                else {
2893                   $checknextflag = 2;
2894                }
2895                last if($checknextflag == 2);
2896             }
2897          }
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]") {
2911                   $checknextflag = 1;
2912                }
2913                else {
2914                   $checknextflag = 2;
2915                }
2916                last if($checknextflag == 2);
2917             }
2918          }
2919       }
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.
2924       $resumerip = 0;
2925
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.
2932       #
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
2937       # error.log.
2938       # cdda2wav prints errors @ data-track, therefore die!
2939       if($ripper == 0 && $rip == 1) {
2940          if($trackcn == 1) {
2941             $ripopt .= " -r 3" if($parano == 0 && $ripopt !~ /\s-r\s3/);
2942             $ripopt .= " -v" if($verbose >= 2 && $ripopt !~ /\s-v/);
2943          }
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
2954             # wait.
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";
2960             close(ERO);
2961          }
2962          print "\n";
2963       }
2964       elsif($ripper == 1 && $rip == 1) {
2965          if($trackcn == 1) {
2966             $ripopt .= " -Z" if($parano == 0 && $ripopt !~ /\s-Z/);
2967             $ripopt .= " -q" if($verbose < 2 && $ripopt !~ /\s-q/);
2968          }
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).
2972          if($span) {
2973             my @bea = split(/-/, $span);
2974             my $offset = 0;
2975             my $chunk = 0;
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
2986                # size.
2987                if($hiddenflag == 0 && $secondlist[$j - 1] < $chunk) {
2988                   $chunk = 0;
2989                   $bea[1] = " ";
2990                }
2991                elsif($hiddenflag == 1 && $secondlist[$j] < $chunk) {
2992                   $chunk = 0;
2993                   $bea[1] = " ";
2994                }
2995                if($chunk <= 0) {
2996                   $chunk = $secondlist[$j - 1] if($hiddenflag == 0);
2997                   $chunk = $secondlist[$j] if($hiddenflag == 1);
2998                }
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];
3002             }
3003             else {
3004                # Special case: if the chunk of sound is larger than the
3005                # (last) track, use the true track length instead of chunk
3006                # size.
3007                if($hiddenflag == 0 && $secondlist[$_ - 1] < $chunk) {
3008                   $chunk = 0;
3009                   $bea[1] = " ";
3010                }
3011                elsif($hiddenflag == 1 && $secondlist[$_] < $chunk) {
3012                   $chunk = 0;
3013                   $bea[1] = " ";
3014                }
3015                $riptrackno = $riptrackno . $bea[0] . "-" . $riptrackno . $bea[1];
3016                # Variable $chunk is zero if span reaches the end of the
3017                # track.
3018                if($chunk <= 0) {
3019                   $chunk = $secondlist[$_ - 1] if($hiddenflag == 0);
3020                   $chunk = $secondlist[$_] if($hiddenflag == 1);
3021                }
3022                $chunk -= $offset;
3023                $secondlist[$_ - 1] = $chunk if($hiddenflag == 0);
3024                $secondlist[$_] = $chunk if($hiddenflag == 1);
3025             }
3026          }
3027          if($multi == 0) {
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"
3034                   if($verbose > 1);
3035             }
3036             # Make sure $failflag is set to 0 if success.
3037             $failflag = 0;
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:
3048                # don't wait.
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";
3055                   close(ERO);
3056                }
3057                $failflag = $save_failflag + 1;
3058             }
3059             $ripopt = $save_ripopt;
3060          }
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"
3067                   if($verbose > 1);
3068             }
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);
3076             $failflag = 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
3080                   # checktrack.
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";
3088                   close(SRXY);
3089                   # Create error message in CD-directory for encoder:
3090                   # don't wait.
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";
3096                   close(ERO);
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 !";
3111                      close(SRTF);
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";
3120                      close(ERO);
3121                      # Now wait to be terminated by checktrack.
3122                      sleep 360;
3123                      exit;
3124                   }
3125                }
3126                $failflag = $save_failflag + 1;
3127             }
3128             $ripopt = $save_ripopt;
3129          }
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";
3143                close(ERO);
3144                if($multi == 1) {
3145                   # Append error message to file srXY for rip2m to start
3146                   # checktrack.
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";
3154                   close(SRXY);
3155                }
3156                # Misuse of variable failflag, we don't care, it's the
3157                # last track!
3158                $failflag = 3;
3159             }
3160             else {
3161                print "\nRip file $riptrackname.rip not found...\n"
3162                if($verbose > 2);
3163             }
3164          }
3165       }
3166       elsif($ripper == 2 && $rip == 1) {
3167          if($trackcn == 1) {
3168             $ripopt .= " -q" if($verbose <= 1 && $ripopt !~ /\s-q/);
3169          }
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.
3173          if($span) {
3174             my @bea = split(/-/, $span);
3175             my $offset = 0;
3176             my $duration = 0;
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) {
3183                      $duration = 0;
3184                   }
3185                   else {
3186                      $duration = $secondlist[$_ - 1] = $secondlist[$_ - 1] - $secondlist[$j - 1] + $duration - $offset;
3187                   }
3188                }
3189                elsif($hiddenflag == 1) {
3190                   # TODO: Oops, why is the counter reduced?
3191                   if($secondlist[$j - 1] < $duration) {
3192                      $duration = 0;
3193                   }
3194                   else {
3195                      $duration = $secondlist[$_] = $secondlist[$_] - $secondlist[$j] + $duration - $offset;
3196                   }
3197                }
3198             }
3199             else {
3200                if($hiddenflag == 0 && $secondlist[$_ - 1] < $duration) {
3201                   $duration = 0;
3202                }
3203                elsif($hiddenflag == 1 && $secondlist[$_] < $duration) {
3204                   $duration = 0;
3205                }
3206                else {
3207                   $duration -= int($offset);
3208                   $secondlist[$_ - 1] = $duration if($hiddenflag == 0);
3209                   $secondlist[$_] = $duration if($hiddenflag == 1);
3210                }
3211             }
3212             $duration = 0 if($duration < 0);
3213             $offset *= 75;
3214             $ripcom .= "-o $offset ";
3215             $ripcom .= "-d $duration " if($duration > 0);
3216          }
3217          if($multi == 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";
3231                close(ERO);
3232                $failflag++;
3233             }
3234          }
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
3242                # checktrack.
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";
3250                close(SRXY);
3251                # Create error message in CD-directory for encoder:
3252                # don't wait.
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";
3258                close(ERO);
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 !";
3273                   close(SRTF);
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";
3282                   close(ERO);
3283                   # Now wait to be terminated by checktrack.
3284                   sleep 360;
3285                   exit;
3286                }
3287             }
3288          }
3289          print "\n" if($verbose > 1);
3290       }
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]";
3297          }
3298       }
3299       elsif($ripper == 4 && $rip == 1) {
3300          my $cdd_dev = $cddev;
3301          $cdd_dev =~ s/^\/dev\/r//;
3302          $cdd_dev =~ s/c$//;
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]";
3308          }
3309       }
3310       elsif($rip == 1) {
3311          print "No CD Ripper defined.\n";
3312       }
3313
3314       redo if($ripper == 1 && $failflag == 1 && $parano == 2);
3315
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\"");
3320       }
3321
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).
3329       if($ripper == 2) {
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");
3339          }
3340          else {
3341             rename("$wavdir/$riptrackname\_rip.wav",
3342                    "$wavdir/$riptrackname.rip");
3343          }
3344       }
3345       # Check for gaps and silence in tracks.
3346       my @times = (0);
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",
3356                                $cdtocn, @times);
3357                ($cdtocn, $cue_point) =
3358                   rename_chunks($saveriptrackno, "$riptrackname",
3359                                 $cdtocn, $cue_point, $shorten,
3360                                 $artistag, $riptracktag, @times);
3361                }
3362          }
3363       }
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");
3367       #
3368       # Final stuff.
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
3373       # the file name!
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;
3388          }
3389          else {
3390             rename("$wavdir/$riptrackname.rip", "$wavdir/$riptrackname.wav");
3391          }
3392       }
3393       else {
3394          rename("$wavdir/$riptrackname.rip", "$wavdir/$riptrackname.wav");
3395       }
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
3408       # track.
3409       if($inf >= 1 && $failflag < 3) {
3410          $trackstart = write_inf($wavdir, $riptrackname, $artistag,
3411            $albumtag, $riptracktag, $save_cdtocn, $cdtocn, $trackstart);
3412       }
3413       chmod oct($fpermission), "$wavdir/$riptrackname.wav"
3414          if($fpermission);
3415       unlink("$logfile.$riptrackno.txt") if($multi == 1);
3416       $failflag = 0;
3417
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));
3423             chomp $encstart;
3424             if($multi == 1) {
3425                open(SRXY,">>$logfile")
3426                   or print "Can not append to file \"$logfile\"!\n";
3427                print SRXY "\nEncoding started: $encstart";
3428                close(SRXY);
3429             }
3430             $startenc = 1;
3431             open(ENCLOG,">$wavdir/enc.log");
3432             close(ENCLOG);
3433             unless(fork) {
3434                enc_cd();
3435             }
3436          }
3437       }
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>;
3444          close(ENCLOG);
3445          my $lincn = 0;
3446          my @outlines = ();
3447          foreach (@loglines) {
3448             if($verbose >= 3) {
3449                push(@outlines, $_)
3450                   if($lincn >= $encline && $_ !~ /^\n/);
3451             }
3452             elsif($verbose == 1 || $verbose == 2) {
3453                print $_ if($lincn >= $encline && $_ =~ /complete\./);
3454             }
3455             $lincn++;
3456          }
3457          # Compact output.
3458          $encline = $lincn;
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);
3463             }
3464             else {
3465                print "\n", "*" x 47, "\nWaiting for encoder to finish...\n\n";
3466             }
3467             print @outlines if($verbose >= 2);
3468          }
3469       }
3470    }
3471    unlink("$wavdir/enc.log") if(-r "$wavdir/enc.log");
3472
3473    # Hack to tell the child process that we are waiting for it to
3474    # finish.
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";
3480    close(ERR);
3481    if($multi == 1) {
3482       open(SRXY,">>$logfile")
3483          or print "Can not append to file \"$logfile\"!\n";
3484       print SRXY "\nRipping complete: $ripend";
3485       close(SRXY);
3486    }
3487 }
3488 ########################################################################
3489 #
3490 # Normalize the wav.
3491 # Using normalize will disable parallel ripping & encoding.
3492 #
3493 sub norm_cd {
3494
3495    print "Normalizing the wav-files...\n" if($verbose >= 1);
3496    my($escdir, $norm, $normtrackname);
3497    $escdir = $wavdir;
3498    $escdir = esc_char($escdir);
3499
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");
3509       }
3510       # Normalize is picky about certain characters - get them escaped!
3511       $wavname = esc_char($wavname);
3512       $normtrackname .= "$escdir/$wavname.wav" . " \\\n          ";
3513    }
3514    $normtrackname =~ s/\s*$//;
3515    $normtrackname =~ s/\$/\\\$/g;
3516
3517    # Add verbosity:
3518    $normopt .= "q" if($verbose == 0);
3519    $normopt .= "v" if($verbose >= 2 && $normopt !~ /q/);
3520    $normopt .= "vv" if($verbose >= 4 && $normopt !~ /q/);
3521
3522    $norm = "$normcmd $normopt -- $normtrackname";
3523
3524    if(log_system("$norm")) {
3525       log_info("\nNormalizing complete.\n");
3526       print "\nNormalizing complete.\n" if($verbose >= 1);
3527    }
3528    else {
3529       print "\nWarning: normalizing failed.\n";
3530    }
3531 }
3532 ########################################################################
3533 #
3534 # Encode the wav.
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.
3540 #
3541 sub enc_cd {
3542
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.).
3550
3551    # Cleaning.
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);
3562
3563    # Create special variables for Lame-tags because of UTF8 problem.
3564    if($utftag == 0) {
3565       $albumlametag = back_encoding($albumtag);
3566       $commentlametag = back_encoding($commentag);
3567    }
3568    else{
3569       $albumlametag = $albumtag;
3570       $commentlametag = $commentag;
3571    }
3572
3573    # Write header of playlist file.
3574    my $playfile;
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);
3580       }
3581       open(PLST, ">$wavdir/$playfile") or
3582          print "Can't open $wavdir/$playfile! $!\n";
3583       print PLST "#EXTM3U\n";
3584    }
3585
3586    # Read the cdcue file (once) to be copied to the encoder directories.
3587    my @cuelines = ();
3588    if($cdcue > 0) {
3589       open(CUE, "<$wavdir/cd.cue")
3590          or print "Can not read file cue sheet!\n";
3591       @cuelines = <CUE>;
3592       close(CUE);
3593    }
3594
3595    # If using book-option define a chapter file.
3596    my $chapterfile;
3597    if($book >= 1) {
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";
3603       }
3604    }
3605
3606    my $ghostflag = 0;
3607    my $ghostcn = 0;
3608
3609    if($commentag =~ /^discid|cddbid$/) {
3610       if($commentag =~ /^discid$/) {
3611          $commentag = $cd{discid}
3612       }
3613       elsif($commentag =~ /^cddbid$/) {
3614          $commentag = $cd{id};
3615       }
3616       $commentag = "" unless($commentag);
3617       $commentlametag = $commentag;
3618    }
3619
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/);
3624
3625    # Create a coverart array supposing its exactly in the same order as
3626    # encoder array.
3627    my @coverart = ();
3628    if($coverart) {
3629       @coverart = split(/,/, $coverart);
3630    }
3631
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);
3635
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);
3654       $riptrackno = $_;
3655       $tagtrackno = $_ + $trackoffset;
3656       $trackcn++;
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.
3666
3667       $riptrackname = get_trackname($_, $tracklist[$_ - 1]);
3668       $riptrackname = get_trackname($_, $tracklist[$_])
3669          if($hiddenflag == 1);
3670
3671       if($ghostflag >= 1) {
3672          $ghostcn++;
3673          $riptrackname = get_trackname($_, $tracklist[$ghostcn - 1]);
3674          $riptrackname = get_trackname($_, $tracklist[$ghostcn])
3675             if($hiddenflag == 1);
3676       }
3677
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:
3682       my $skipflag = 0;
3683       if($pmerge) {
3684          @skip = skip_tracks;
3685          foreach my $skip (@skip) {
3686             $skipflag = 1 if($_ == $skip);
3687          }
3688          if($book == 1) {
3689             # Search the index number of encoder faac.
3690             my $index = 0;
3691             for(my $c = 0; $c <= $#coder; $c++) {
3692                $index = $c if($coder[$c] == 3);
3693             }
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";
3705             close(CHAP);
3706          }
3707       }
3708       next if($skipflag == 1);
3709       $lastskip = $_;
3710
3711       # LCDproc
3712       if($lcd == 1) {
3713          my $_lcdtracks = scalar @tracksel;
3714          my $_lcdenctrack = $trackcn;
3715          my $lcdperc;
3716          if($_lcdtracks eq $_lcdenctrack) {
3717             $lcdperc = "*100";
3718          }
3719          else {
3720             $lcdperc = sprintf("%04.1f", $_lcdenctrack / $_lcdtracks * 100);
3721          }
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);
3726          ulcd();
3727       }
3728
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);
3735       }
3736
3737       # Split the tracktag into its artist part and track part if
3738       # VA style is used.
3739       if($va_flag > 0 && $tracktag =~ /$delim/) {
3740          $artistag = "";
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;
3749                $artistag = "";
3750             }
3751          }
3752          else {
3753             ($tracktag, $artistag) = split(/$delim/, $tracktag);
3754             $artistag =~ s/\)// if($delim =~ /\(/);
3755             $artistag =~ s/^\s*//;
3756             $tracktag =~ s/\s*$//;
3757          }
3758       }
3759
3760       if($utftag == 0) {
3761          $tracklametag = back_encoding($tracktag);
3762          $artislametag = back_encoding($artistag);
3763       }
3764       else{
3765          $tracklametag = $tracktag;
3766          $artislametag = $artistag;
3767       }
3768       $artistag = clean_all($artist_utf8) if($artistag eq "");
3769
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");
3775       }
3776
3777       # Check for tracks already done.
3778       my $checknextflag = 1;
3779       if($resumenc) {
3780          for(my $c=0; $c<=$#coder; $c++) {
3781             if(! -r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
3782                $checknextflag = 0;
3783             }
3784             else{
3785                print "Found $riptrackname.$suffix[$c]:\n"
3786                   if($verbose >= 1);
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);
3791             }
3792             last if($checknextflag == 0);
3793          }
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"
3800                if($playlist == 1);
3801             print PLST "$riptrackname.suffix\n" if($playlist == 2);
3802             print PLST "Add Ghost Song $_ Here.\n" if($ghost == 1);
3803          }
3804          unlink("$wavdir/$riptrackname.wav")
3805             if($wav == 0 && $sshflag == 0 && $checknextflag == 1);
3806       }
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.
3811       $resumenc = 0;
3812
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;
3819
3820       # We don't need this for ghost songs, as they are done only when
3821       # the (original) last track was successfully ripped.
3822       my $dataflag = 0;
3823       my $xtime = 0;
3824       my $ripsize = 0;
3825       while(! -r "$wavdir/$wavname.wav" && $ghostflag == 0) {
3826          $xtime++;
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!
3831          if($ghost == 1) {
3832             my ($ghost_rtn, $dummy) = split(/\//, $tracktag);
3833             if($ghost_rtn) {
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
3848                # ripping.
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;
3854                      if($utftag == 0) {
3855                         $tracklametag = back_encoding($tracktag);
3856                      }
3857                      else{
3858                         $tracklametag = $tracktag;
3859                      }
3860                }
3861            }
3862          }
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;
3868             #
3869             if(-r "$wavdir/$wavname.rip") {
3870                $ripsize = -s "$wavdir/$wavname.rip";
3871             }
3872             if($multi != 1) {
3873                if($ripsize > $old_ripsize * 1.2) {
3874                   $tlength = $tlength * 1.5;
3875                }
3876                else {
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");
3883                }
3884             }
3885             else {
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;
3894                   }
3895                   else {
3896                      $xtime = 0 unless($riptrackname =~ /00 Hidden Track/);
3897                      open(ERR, ">>$wavdir/error.log");
3898                      print ERR "Ripping ended: 00:00!\n";
3899                      close(ERR);
3900                   }
3901                }
3902                else {
3903                   $xtime = 0 unless($riptrackname =~ /00 Hidden Track/);
3904                   open(ERR, ">>$wavdir/error.log");
3905                   print ERR "Ripping ended: 00:00!\n";
3906                   close(ERR);
3907                }
3908             }
3909          }
3910          sleep 10;
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
3918          # worry.
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>;
3923             close(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)));
3927             if($errtrack) {
3928                $xtime = $tlength + 1;
3929                $dataflag = 1;
3930                if($verbose >= 2) {
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";
3936                      close(ENCLOG);
3937                   }
3938                   else {
3939                      print "\nDid not detect track $errtrack ",
3940                            "($riptrackname.rip), assume ripper ",
3941                            "failure!\n";
3942                   }
3943                }
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";
3949                      close(ENCLOG);
3950                   }
3951                   else {
3952                      print "RipIT will finish the job! ",
3953                            "Check the error.log!\n";
3954                   }
3955                }
3956             }
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 !";
3970                close(SRTF);
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";
3979                close(ERO);
3980                # Now wait to be terminated by checktrack.
3981                sleep 360;
3982                exit;
3983             }
3984          }
3985       }
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>;
4001          close(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");
4013          $ghost = 0;
4014          $ghostflag = 1;
4015          $resumenc = $resume; # Continue to resume ghost songs.
4016       }
4017
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);
4023
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
4029       # unpack function.
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\"");
4035       }
4036
4037       my $delwav = 0;
4038       my $starts = sprintf("%3d", sub {$_[1]*60+$_[0]}->(localtime));
4039
4040       if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
4041          open(ENCLOG, ">>$wavdir/enc.log");
4042          print ENCLOG "\nEncoding \"$riptrackname\"...\n"
4043             if($verbose >= 3);
4044          close(ENCLOG);
4045       }
4046       else {
4047          print "\nEncoding \"$riptrackname\"...\n" if($verbose >= 3);
4048       }
4049
4050       my $covertag;
4051       my $failflag = 0;
4052       # Set the encoder(s) we are going to use.
4053       for(my $c = 0; $c <= $#coder; $c++) {
4054          # Initialization of coverart variables.
4055          $covertag = " ";
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];
4062
4063             # Coverart tagging will be done below because an additional
4064             # module will be used. Don't handle the whole picture-data
4065             # in this command.
4066
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)
4077                   if($verbose >= 3);
4078                print ENCLOG "Lame $lameopt encoding track $trackcn" .
4079                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4080                close(ENCLOG);
4081             }
4082             else {
4083                printf "\n%02d:%02d:%02d: ",
4084                   sub {$_[2], $_[1], $_[0]}->(localtime)
4085                   if($verbose >= 3);
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);
4090             }
4091             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4092          }
4093          elsif($coder[$c] == 1) {
4094             $encodername = "Oggenc";
4095             $oggencopt = $globopt[$c];
4096
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
4100             # in this command.
4101
4102             # http://www.hydrogenaudio.org/forums/lofiversion/index.php/t48386.html
4103
4104             # CLI solutions:
4105             # first: base64 encoding of the image:
4106             #
4107             # perl -MMIME::Base64 -0777 -ne 'print encode_base64($_, "")' < thumb.png > temp
4108             #
4109             # note the double quotes to prevent the newlines.
4110             # Redirect this output to a file.
4111             #
4112             # second: use vorbiscomment to tag the file: (http://darcs.tonywhitmore.co.uk/repos/podcoder/podcoder)
4113             #
4114             # vorbiscomment -a 01.ogg -t "COVERARTMIME=image/png" -t "COVERART=`cat temp`"
4115             #
4116             # and you're done.
4117
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
4121
4122             # Proposals for extending Ogg Vorbis comments
4123             # http://reallylongword.org/vorbiscomment/
4124
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)
4135                   if($verbose >= 3);
4136                print ENCLOG "Oggenc $oggencopt encoding track" .
4137                      " $trackcn of " . ($#tracksel + 1) . "\n"
4138                      if($verbose >= 3);
4139                close(ENCLOG);
4140             }
4141             else {
4142                printf "\n%02d:%02d:%02d: ",
4143                   sub {$_[2], $_[1], $_[0]}->(localtime)
4144                   if($verbose >= 3);
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);
4149             }
4150             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4151          }
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\"";
4162             }
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\" \\
4168              $covertag \\
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)
4175                   if($verbose >= 3);
4176                print ENCLOG "Flac $flacopt encoding track $trackcn" .
4177                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4178                close(ENCLOG);
4179             }
4180             else {
4181                printf "\n%02d:%02d:%02d: ",
4182                   sub {$_[2], $_[1], $_[0]}->(localtime)
4183                   if($verbose >= 3);
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);
4188             }
4189             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4190             my $flacopt = $save_flacopt if($resume);
4191          }
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\"";
4197             }
4198             $enc = "faac $faacopt -w --title \"$tracktag\" \\
4199              --artist \"$artistag\" --album \"$albumtag\" \\
4200              --year \"$year\" --genre \"$genre_tag\" --track $tagtrackno \\
4201              --comment \"$commentag\" \\
4202              $covertag \\
4203              -o \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\" \\
4204              \"$wavdir/$riptrackname.wav\" \\
4205              > /dev/null 2>&1";
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)
4210                   if($verbose >= 3);
4211                print ENCLOG "Faac $faacopt encoding track $trackcn" .
4212                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4213                close(ENCLOG);
4214             }
4215             else {
4216                printf "\n%02d:%02d:%02d: ",
4217                   sub {$_[2], $_[1], $_[0]}->(localtime)
4218                   if($verbose >= 3);
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);
4223             }
4224             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4225          }
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\" \\
4232              > /dev/null 2>&1 \\
4233              ";
4234             # Only add tags if MP4 container is set up, use artwork for
4235             # coverart.
4236             my $mp4suffix = $suffix[$c];
4237             if($mp4alsopt =~ /MP4/) {
4238                $mp4suffix = "mp4";
4239                if($coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4240                   $covertag = "-P \"$coverpath\"";
4241                }
4242                $enc .= " && mp4tags -s \"$tracktag\" -a \"$artistag\" \\
4243                 -A \"$albumtag\" -y \"$year\" -g \"$genre_tag\" \\
4244                 -t $tagtrackno -c \"$commentag\" -e RipIT -E mp4als \\
4245                 $covertag \\
4246                 \"$sepdir[$c]/$riptrackname.$suffix[$c]_enc\"";
4247             }
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)
4252                   if($verbose >= 3);
4253                print ENCLOG "Mp4als $mp4alsopt encoding track $trackcn" .
4254                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4255                close(ENCLOG);
4256             }
4257             else {
4258                printf "\n%02d:%02d:%02d: ",
4259                   sub {$_[2], $_[1], $_[0]}->(localtime)
4260                   if($verbose >= 3);
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);
4265             }
4266             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4267          }
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
4273             # track...
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)
4283                   if($verbose >= 3);
4284                print ENCLOG "Mppenc $museopt encoding track $trackcn" .
4285                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4286                close(ENCLOG);
4287             }
4288             else {
4289                printf "\n%02d:%02d:%02d: ",
4290                   sub {$_[2], $_[1], $_[0]}->(localtime)
4291                   if($verbose >= 3);
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);
4296             }
4297             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4298          }
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\"";
4307             }
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\" \\
4313              $covertag \\
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)
4320                   if($verbose >= 3);
4321                print ENCLOG "Wavpack $wavpacopt encoding track $trackcn" .
4322                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4323                close(ENCLOG);
4324             }
4325             else {
4326                printf "\n%02d:%02d:%02d: ",
4327                   sub {$_[2], $_[1], $_[0]}->(localtime)
4328                   if($verbose >= 3);
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);
4333             }
4334             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4335          }
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!
4345             #
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!
4349             #
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
4353             #
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\'";
4361 #            }
4362             $enc = "ffmpeg -i \"$wavdir/$riptrackname.wav\" \\
4363              $ffmpegopt \\
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\" \\
4368              $covertag \\
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]\"";
4375                }
4376             }
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)
4381                   if($verbose >= 3);
4382                print ENCLOG "ffmpeg $ffmpegopt encoding track $trackcn" .
4383                      " of " . ($#tracksel + 1) . "\n" if($verbose >= 3);
4384                close(ENCLOG);
4385             }
4386             else {
4387                printf "\n%02d:%02d:%02d: ",
4388                   sub {$_[2], $_[1], $_[0]}->(localtime)
4389                   if($verbose >= 3);
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);
4394             }
4395             log_info("new-mediafile: $sepdir[$c]/${riptrackname}.$suffix[$c]");
4396          }
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>;
4408                close(ERR);
4409                my @ripcomplete = grep(/^$ripmsg/, @errlines);
4410                $ripcomplete = 1 if(@ripcomplete);
4411             }
4412          }
4413
4414          $enc =~ s/\$/\\\$/g;
4415          # Finally, do the job of encoding.
4416          if($sshflag == 1) {
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.
4422             push(@md5tracks,
4423                  "$sepdir[$c];#;$riptrackname.$suffix[$c]");
4424             my @waitracks;
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 "");
4432                   }
4433                   # Add coverart if it is a mp3 or ogg.
4434                   if($donetrack =~ /mp3$/ && -f "$coverpath" && -s "$coverpath") {
4435                      mp3_cover("$sepdir/$donetrack", "$coverpath");
4436                   }
4437                   elsif($donetrack =~ /ogg$/ && -f "$coverpath" && -s "$coverpath") {
4438                      ogg_cover("$sepdir/$donetrack", "$coverpath");
4439                   }
4440                }
4441                # Only add files to array @md5tracks if coverart shall be
4442                # added.
4443                else {
4444                   push(@waitracks, "$sepdir;#;$donetrack") if($coder[$c] <= 1 && $coverart[$c] == 1);
4445                }
4446             }
4447             @md5tracks = @waitracks;
4448          }
4449          else {
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>;
4456                      close(ERR);
4457                      my @ripcomplete = grep(/^$ripmsg/, @errlines);
4458                      $ripcomplete = 1 if(@ripcomplete);
4459                   }
4460                }
4461                if($coder[$c] == 4 && $mp4alsopt =~ /MP4/) {
4462                   rename("$sepdir[$c]/$riptrackname.$suffix[$c]_enc",
4463                          "$sepdir[$c]/$riptrackname.mp4");
4464                }
4465                elsif($coder[$c] == 5) {
4466                   rename("$sepdir[$c]/$riptrackname\_enc.$suffix[$c]",
4467                          "$sepdir[$c]/$riptrackname.$suffix[$c]");
4468                }
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");
4475                   }
4476                }
4477                else {
4478                   rename("$sepdir[$c]/$riptrackname.$suffix[$c]_enc",
4479                          "$sepdir[$c]/$riptrackname.$suffix[$c]");
4480                }
4481                # Add special mp3 tags.
4482                if(@mp3tags && $coder[$c] == 0) {
4483                   mp3_tags("$sepdir[$c]/$riptrackname.$suffix[$c]") if($mp3tags[0] ne "");
4484                }
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");
4488                }
4489                elsif($coder[$c] == 1 && $coverart[$c] == 1 && -f "$coverpath" && -s "$coverpath") {
4490                   ogg_cover("$sepdir[$c]/$riptrackname.$suffix[$c]", "$coverpath");
4491                }
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);
4497                   close(ENCLOG);
4498                }
4499                else {
4500                   print "Encoding of \"$riptrackname.$suffix[$c]\" " .
4501                         "complete.\n" if($verbose >= 1);
4502                }
4503             }
4504             else {
4505                print "Encoder $encodername failed on $tracklist[$_ - 1]\n",
4506                      "of disc in device $cddev.\n",
4507                      "Error message says: $?\n";
4508                $failflag = 1;
4509                if($multi == 1) {
4510                   # Print error message to file srXY.Z.txt, checktrack
4511                   # will grep for string "encoder failed" and kill the
4512                   # CD immediately!
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 $? !";
4518                   close(SRTF);
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";
4527                   close(ERO);
4528                   # Wait to be terminated by checktrack.
4529                   sleep 360;
4530                }
4531             }
4532             sleep 1;
4533          }
4534          # Copy the cdcue file (once) to the directory of the encoded
4535          # files.
4536          if($cdcue > 0) {
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) {
4543                chomp;
4544                s/\.wav/.$suffix[$c]/;
4545                s/\sWAVE/ $cue_suffix/;
4546                print CUE "$_\n";
4547             }
4548             close(CUE);
4549          }
4550       }
4551       # Calculate time in seconds when encoding ended and total time
4552       # encoder needed.
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);
4559
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
4567       # any track.
4568       # TODO:
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],",
4583                         "$tracktag\n"
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"
4588                if($playlist == 1);
4589             print PLST "GS$_:$riptrackname.suffix\n" if($playlist == 2);
4590          }
4591          else {
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>;
4596                close(GHOST);
4597                my @seclines = grep(s/^Array secondlist: //, @errlines);
4598                @secondlist = split(/ /, $seclines[$#seclines]);
4599                chomp($_) foreach(@secondlist);
4600             }
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"
4606                if($playlist == 1);
4607             print PLST "$riptrackname.suffix\n" if($playlist == 2);
4608             print PLST "Add Ghost Song $_ Here.\n"
4609                if($ghost == 1 || $ghostflag == 1);
4610          }
4611       }
4612       last if($cdcue > 0);
4613    }
4614
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
4620    # to del_erlog!
4621
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);
4627    close(ERR);
4628    close(PLST);
4629    exit unless($normalize == 1 or $cdcue > 0);
4630 }
4631 ########################################################################
4632 #
4633 # Finish the M3U file used by players such as Amarok, Noatun, X11Amp...
4634 #
4635 sub create_m3u {
4636    my $playfile;
4637    my @mp3s = ();
4638
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);
4645
4646    $playfile = "$artist" . " - " . "$album" . ".m3u";
4647    $playfile =~ s/ /_/g if($underscore == 1);
4648    if($limit_flag == 255) {
4649       $playfile = substr($playfile, 0, 240);
4650    }
4651
4652    # Prevent warnings in some rare cases if no tracks have been ripped.
4653    return unless(-r "$wavdir/$playfile");
4654
4655    open(PLST, "<$wavdir/$playfile")
4656       or print "Can not open file $wavdir/$playfile!\n";
4657    my @playlines = <PLST>;
4658    close(PLST);
4659    my @ghosts = grep(/^GS\d+:/, @playlines);
4660
4661    unlink("$wavdir/$playfile");
4662
4663    my @playlist = ();
4664    foreach (@playlines) {
4665       next if($_ =~ /^GS\d+:/ || $_ =~ /^$/);
4666       $_ =~ s/^Add Ghost Song (\d+) Here.$/$1/;
4667       chomp $_;
4668       if($_ =~ /^\d+$/) {
4669          foreach my $ghostsong (@ghosts) {
4670             if($ghostsong =~ s/^GS$_\://) { # Why not as a 1-liner?
4671                $ghostsong =~ s/^GS$_\://;
4672                chomp $ghostsong;
4673                push @playlist, $ghostsong;
4674             }
4675          }
4676       }
4677       else {
4678          push @playlist, $_;
4679       }
4680    }
4681
4682    my $nplayfile;
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.
4690       if($#coder != 0) {
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";
4699       }
4700       else {
4701          $nplayfile = $playfile;
4702          open(PLST, ">$sepdir[$c]/$nplayfile") or
4703             print "Can't open $sepdir[$c]/$nplayfile! $!\n";
4704       }
4705       print PLST "$_\n" foreach(@mp3s);
4706       close(PLST);
4707       chmod oct($fpermission), "$sepdir[$c]/$nplayfile"
4708          if($fpermission);
4709    }
4710    # Recreate the wav-playlist if wavs aren't deleted.
4711    if($wav == 1) {
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);
4724       close(PLST);
4725       chmod oct($fpermission), "$wavdir/$nplayfile"
4726          if($fpermission);
4727    }
4728 }
4729 ########################################################################
4730 #
4731 # Create a default or manual track list.
4732 #
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);
4739
4740    my $tracks = substr($cddbid, 6);
4741    $tracks = hex($tracks);
4742
4743    $album = clean_all($album_utf8) if(defined $cd{title});
4744    $artist = clean_all($artist_utf8) if(defined $cd{artist});
4745
4746    # Preselect answer if no interaction requested.
4747    $index = 1 if($interaction == 0);
4748
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) ";
4753       $index = <STDIN>;
4754       chomp $index;
4755       $index = 0 unless($index);
4756       print "\n";
4757    }
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.
4762    if($index == 1) {
4763       $artist = "Unknown Artist";
4764       $album = "Unknown Album";
4765       %cd = (
4766          artist => $artist,
4767          title => $album,
4768          cat => $categ,
4769          genre => $genre,
4770          id => $cddbid,
4771          revision => 0,
4772          year => $year,
4773       );
4774       while($i < $tracks) {
4775          $j = $i + 1;
4776          $j = "0" . $j if($j < 10);
4777          $cd{track}[$i] = "Track " . "$j";
4778          ++$i;
4779       }
4780       $cddbsubmission = 0;
4781    }
4782    # Create manual tracklist.
4783    elsif($index == 0) {
4784       # In case of CDDB resubmission
4785       if(defined $cd{artist}) {
4786          print "\n   Artist ($artist): ";
4787       }
4788       # In case of manual CDDB entry.
4789       else {
4790          print "\n   Artist : ";
4791       }
4792       $artist = <STDIN>;
4793       chomp $artist;
4794       # If CDDB entry confirmed, take it.
4795       if(defined $cd{artist} && $artist eq "") {
4796          $artist = $artist_utf8;
4797       }
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;
4803       }
4804       if($artist eq "") {
4805          $artist = "Unknown Artist";
4806          $cddbsubmission = 0;
4807       }
4808       if(defined $cd{title}) {
4809          print "\n   Album ($album): ";
4810       }
4811       else {
4812          print "\n   Album : ";
4813       }
4814       $album = <STDIN>;
4815       chomp $album;
4816       while($year !~ /^\d{4}$/) {
4817          if(defined $cd{year}) {
4818             print "\n   Year ($year): ";
4819          }
4820          else {
4821             print "\n   year : ";
4822          }
4823          $year = <STDIN>;
4824          chomp $year;
4825          last if($year eq "");
4826       }
4827       # If CDDB entry confirmed, take it.
4828       if(defined $cd{title} && $album eq "") {
4829          $album = $album_utf8;
4830       }
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;
4836       }
4837       if($album eq "") {
4838          $album = "Unknown Album";
4839          $cddbsubmission = 0;
4840       }
4841       %cd = (
4842          artist => $artist,
4843          title => $album,
4844          cat => $categ,
4845          genre => $genre,
4846          id => $cddbid,
4847          revision => 0,
4848          year => $year,
4849       ) unless(defined $cd{title});
4850       print "\n";
4851       $i = 1;
4852       while($i <= $tracks) {
4853          if(defined $cd{track}[$i-1]) {
4854             printf("   Track %02d (%s): ", $i, $tracktags[$i-1]);
4855          }
4856          else {
4857             printf("   Track %02d: ", $i);
4858          }
4859          my $tracktag = <STDIN>;
4860          chomp $tracktag;
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;
4872          }
4873          elsif(!$cd{track}[$i-1] && $track eq "") {
4874             $track = "Track " . sprintf("%02d", $i);
4875             $cddbsubmission = 0;
4876          }
4877          # Fill the "empty" array @{$cd{track}}.
4878          push(@{$cd{track}}, "$track");
4879          $i++;
4880       }
4881       print "\n";
4882    }
4883    else {
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";
4887    }
4888    return;
4889 }
4890 ########################################################################
4891 #
4892 # Read the CD and generate a TOC with DiscID, track frames and total
4893 # length. Then prepare CDDB-submission with entries from @tracklist.
4894 #
4895 sub pre_subm {
4896    my($check,$i,$ans,$genreno,$line,$oldcat,$subject) = (0,0);
4897
4898    my $tracks = $#framelist;
4899    my $totals = int($framelist[$#framelist] / 75);
4900
4901    my $album = clean_all($album_utf8);
4902    my $artist = clean_all($artist_utf8);
4903
4904    my $revision = get_rev() unless($cd{discid});
4905    if($revision) {
4906       # TODO: if submission fails, set revision back.
4907       $revision++;
4908       print "Revision is set to $revision.\n" if($verbose > 4);
4909    }
4910    elsif(defined $cd{revsision}) {
4911       $revision = $cd{revision};
4912    }
4913    else {
4914       $revision = 0;
4915    }
4916
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";
4922       $revision = 0;
4923    }
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);
4927    }
4928    if(!$year) {
4929       while($year !~ /^\d{4}$| / || !$year ) {
4930       print "\nPlease enter the year (or none): ";
4931       $year = <STDIN>;
4932       chomp $year;
4933       $cd{year} = $year;
4934       last if(!$year);
4935       $cddbsubmission = 1;
4936       }
4937    }
4938    if($cd{year}) {
4939       $cddbsubmission = 1 unless($year eq $cd{year});
4940    }
4941    else {
4942       $cddbsubmission = 1;
4943    }
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.
4946    $oldcat = $categ;
4947    if($cd{cat} && $categ) {
4948       $categ = get_answ("CDDB category",$categ);
4949    }
4950
4951    my @categ = ();
4952    my @categories = (
4953       "blues",  "classical", "country", "data",
4954       "folk",   "jazz",      "misc",    "newage",
4955       "reggae", "rock",      "soundtrack"
4956    );
4957
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?",
4963                " [y/n] (y) ";
4964       $ans = <STDIN>;
4965       chomp $ans;
4966       if($ans eq "") {
4967          $ans = "y";
4968       }
4969       if($ans =~ /^y/) {
4970          print "\n\nAvailable categories:\n";
4971          foreach (@categories) {
4972             my $templines = "";
4973             my $source = "http://www.freedb.org/freedb/" .
4974                           $_ . "/" . $cddbid;
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???
4979             if($templines) {
4980                push @categ, $_;
4981             }
4982             else {
4983                print "   $_\n"
4984             }
4985          }
4986          if($categ[10]) {
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;
4993          }
4994
4995          # Check if the $categ variable is correct.
4996          while($categ !~ m/^blues$|^classical$|^country$|^data$|^folk$|
4997                           |^jazz$|^newage$|^reggae$|^rock$|^soundtrack$|
4998                           |^misc$/ ) {
4999             print "\nPlease choose one of the available CDDB categories: "
5000                if($categ[10]);
5001             print "\nPlease choose one of the categories: "
5002                unless($categ[10]);
5003             $categ = <STDIN>;
5004             chomp $categ;
5005          }
5006          $cddbsubmission = 1 unless($categ eq $cd{cat});
5007       }
5008    }
5009    elsif($cd{discid}) {
5010       $categ = "musicbrainz";
5011    }
5012    # If one changes category for a new submission, set Revision to 0.
5013    if($oldcat ne $categ && defined $cd{cat}) {
5014       $revision = 0;
5015    }
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'});
5022    }
5023    # Do not to ask if genre had been passed from command line.
5024    unless($pgenre) {
5025       $genre = get_answ("genre",$genre);
5026    }
5027    unless($genre) {
5028       print "\nPlease enter a valid CDDB genre (or none): ";
5029       $genre = <STDIN>;
5030       chomp $genre;
5031       $cd{genre} = $genre;
5032       # Allow to submit no genre! Else check it!
5033       if($genre) {
5034          $genre =~ s/[\015]//g;
5035          ($genre,$genreno) = check_genre($genre);
5036       }
5037    }
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);
5042
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";
5048    $i = 0;
5049    foreach (@framelist) {
5050       print TOC "# $_\n" if($i < $#framelist);
5051       $i++;
5052    }
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);
5063    }
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";
5071    print TOC "#\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";
5077    }
5078    elsif($genre eq "" && defined $categ) {
5079       print TOC "DGENRE=$categ\n";
5080    }
5081    $i = 0;
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";
5086       ++$i;
5087    }
5088
5089    my @comment = extract_comm;
5090    my $commentest = "@comment";
5091    if($commentest) {
5092       $ans = "x";
5093       $check = 0;
5094       print "Confirm (Enter), delete or edit each comment line ";
5095       print "(c/d/e)!\n";
5096       foreach (@comment) {
5097          chomp($_);
5098          s/\n//g;
5099          next if($_ eq "");
5100          while($ans !~ /^c|^d|^e/) {
5101             print "$_ (c/d/e): ";
5102             $ans = <STDIN>;
5103             chomp $ans;
5104             if($ans eq "") {
5105                $ans = "c";
5106             }
5107          }
5108          if($ans =~ /^c/ || $ans eq "") {
5109             print TOC "EXTD=$_\\n\n";
5110             $check = 1;
5111          }
5112          elsif($ans =~ /^e/) {
5113             print "Enter a different line: \n";
5114             my $ans = <STDIN>;
5115             chomp $ans;
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;
5120             $check = 1;
5121          }
5122          else {
5123             # Don't print the line.
5124             $cddbsubmission = 1;
5125          }
5126          $ans = "x";
5127       }
5128       $line = "a";
5129       while(defined $line) {
5130          print "Do you want to add a line? (Enter for none or type!): ";
5131          $line = <STDIN>;
5132          chomp $line;
5133          $cddbsubmission = 1 if($line ne "");
5134          last if(!$line);
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";
5138          $check = 1;
5139       }
5140       # If all lines have been deleted, add an empty EXTD line!
5141       if($check == 0) {
5142          print TOC "EXTD=\n";
5143       }
5144    }
5145    # If there are no comments, ask to add some.
5146    elsif(!$comment[0]) {
5147       $line = "a";
5148       my $linecn = 0;
5149       while(defined $line) {
5150          print "Please enter a comment line (or none): ";
5151          $line = <STDIN>;
5152          chomp $line;
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);
5158          $linecn++;
5159          # This line has to be written, so break the
5160          # while loop here and not before, as above.
5161          last if(!$line);
5162       }
5163    }
5164    else {
5165       print TOC "EXTD=\n";
5166    }
5167
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) {
5172       chomp($_);
5173       s/\n//g;
5174       s/[\015]//g;
5175    }
5176    $ans = get_answ('Track comment','existing ones');
5177    if($ans eq "") {
5178       $i = 0;
5179       while($i < $tracks) {
5180          my $track;
5181          if($trackcom[$i]) {
5182             printf("   Track comment %02d (%s):", $i+1, $trackcom[$i]);
5183          }
5184          else {
5185             printf("   Track comment %02d: ", $i+1);
5186          }
5187          $track = <STDIN>;
5188          chomp $track;
5189          substr($track, 230, 0, "\nEXTT$i=") if(length($track) > 250);
5190          substr($track, 460, 0, "\nEXTT$i=") if(length($track) > 500);
5191
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";
5195          }
5196          elsif(defined $trackcom[$i] && $track ne "") {
5197             print TOC "EXTT$i=$track\n";
5198             $cddbsubmission = 1;
5199          }
5200          elsif($track ne "") {
5201             print TOC "EXTT$i=$track\n";
5202             $cddbsubmission = 1;
5203          }
5204          else {
5205             print TOC "EXTT$i=\n";
5206          }
5207          $i++;
5208       }
5209    }
5210    elsif(@trackcom) {
5211       $i = 0;
5212       foreach (@tracklist) {
5213          print TOC "EXTT$i=$trackcom[$i]\n";
5214          ++$i;
5215       }
5216    }
5217    else {
5218       $i = 0;
5219       foreach (@tracklist) {
5220          print TOC "EXTT$i=\n";
5221          ++$i;
5222       }
5223    }
5224
5225    # Extract the playorder line.
5226    my @playorder = grep(/^PLAYORDER=/, @{$cd{raw}});
5227    @playorder = grep(s/^PLAYORDER=//, @playorder);
5228    if(@playorder) {
5229       my $playorder = $playorder[0];
5230       chomp $playorder;
5231       print TOC "PLAYORDER=$playorder\n";
5232    }
5233    else {
5234       print TOC "PLAYORDER=\n";
5235    }
5236    close(TOC);
5237    # Copy the *edited* CDDB file if variable set to the ~/.cddb/
5238    # directory.
5239    if($archive == 1 && $cddbsubmission != 2) {
5240       log_system("mkdir -m 0755 -p \"$homedir/.cddb/$categ\"")
5241          or print
5242          "Can not create directory \"$homedir/.cddb/$categ\": $!\n";
5243       log_system(
5244          "cp \"$homedir/cddb.toc\" \"$homedir/.cddb/$categ/$cddbid\""
5245          )
5246          or print
5247          "Can not copy cddb.toc to directory ",
5248          "\"$homedir/.cddb/$categ/$cddbid\": $!\n";
5249       print "Saved file $cddbid in \"$homedir/.cddb/$categ/\"";
5250    }
5251    print "\n";
5252    # If no connection to the internet do not submit.
5253    if($submission == 0) {
5254       $cddbsubmission = 0;
5255    }
5256    # If we came from MB do not submit.
5257    elsif($cd{discid}) {
5258       $cddbsubmission = 0;
5259    }
5260
5261    if($cddbsubmission == 1) {
5262       my $ans = "x";
5263       while($ans !~ /^y$|^n$/) {
5264          print "Do you really want to submit your data to freeDB.org?",
5265                " [y/n] (y) ";
5266          $ans = <STDIN>;
5267          chomp $ans;
5268          if($ans eq "") {
5269             $ans = "y";
5270          }
5271       }
5272       if($ans =~ /^y/) {
5273          $cddbsubmission = 1;
5274       }
5275       else{
5276          $cddbsubmission = 0;
5277       }
5278    }
5279    if($cddbsubmission == 1) {
5280       while($mailad !~ /.@.+[.]./) {
5281          print "\nReady for submission, enter a valid return ";
5282          print "e-mail address: ";
5283          $mailad = <STDIN>;
5284          chomp $mailad;
5285       }
5286
5287       open TOC, "cat \"$homedir/cddb.toc\" |"
5288          or die "Can not open file $homedir/cddb.toc $!\n";
5289       my @lines = <TOC>;
5290       close(TOC);
5291
5292       $subject = "cddb " . $categ . " " . $cddbid;
5293       open(MAIL, "|/usr/sbin/sendmail -t -r $mailad")
5294          or print "/usr/sbin/sendmail not installed? $!\n";
5295
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";
5303       foreach (@lines) {
5304          print MAIL $_;
5305       }
5306       close(MAIL);
5307       print "Mail exit status not zero: $?" if($?);
5308       print "CDDB entry submitted.\n\n" unless($?);
5309       unlink("$homedir/cddb.toc");
5310    }
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";
5317       sleep (4);
5318    }
5319    else {
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";
5324    }
5325 }
5326 ########################################################################
5327 #
5328 # Check if genre is correct.
5329 #
5330 sub check_genre {
5331    my $genre = $_[0];
5332    my $genreno = "";
5333    my $genrenoflag = 1;
5334
5335    $genre = "  " if($genre eq "");
5336
5337    # If Lame is not used, don't die if ID3v2-tag is not compliant.
5338    if($lameflag == 0) {
5339       unless(log_system(
5340          "lame --genre-list 2>&1 | grep -i \" $genre\$\" > /dev/null ")) {
5341          print "Genre $genre is not ID3v2 compliant!\n"
5342             if($verbose >= 1);
5343          print "Continuing anyway!\n\n" if($verbose >= 1);
5344          chomp($genreno = "not ID3v2 compliant!\n");
5345       }
5346       return ($genre,$genreno);
5347    }
5348
5349    # If Lame is not installed, don't loop for ever.
5350    if($lameflag == -1) {
5351       chomp($genreno = "Unknown.\n");
5352       return ($genre,$genreno);
5353    }
5354
5355    # Check if (similar) genre exists. Enter a new one with interaction,
5356    # or take the default one.
5357    while(!log_system(
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): ";
5363          $genre = <STDIN>;
5364          chomp $genre;
5365          $cd{genre} = $genre;
5366       }
5367       else {
5368          print "Genre \"Other\" will be used instead!\n"
5369             if($verbose >= 1);
5370          $genre = "12 Other";
5371       }
5372    }
5373
5374    if($genre eq "") {
5375       return;
5376    }
5377    elsif($genre =~ /^\d+$/) {
5378       chomp($genre = `lame --genre-list 2>&1 | grep -i \' $genre \'`);
5379    }
5380    else {
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);
5399          my ($i,$j) = (0,1);
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
5403             # different.
5404             foreach (@list) {
5405                printf(" %2d: $_ \n",$j);
5406                $j++;
5407             }
5408             $j--;
5409             print "\nChoose [1-$j]: ";
5410             $i = <STDIN>;
5411             chomp $i;
5412             $j = 1;
5413          }
5414          chomp($genre = $list[$i-1]);
5415       }
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 "");
5419          $genre =~ s/\n.*//;
5420       }
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) {
5425          $genre = $ogenre;
5426          $genrenoflag = 0;
5427       }
5428       chomp $genre;
5429    }
5430
5431    # Extract genre-number.
5432    if($genre ne "" && $genrenoflag == 1) {
5433       $genre =~ s/^\s*//;
5434       my @genre = split(/ /, $genre);
5435       $genreno = shift(@genre);
5436       $genre = "@genre";
5437    }
5438    return ($genre,$genreno);
5439 }
5440 ########################################################################
5441 #
5442 # Check mirrors. Need to be tested from time to time, which ones are up.
5443 #
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
5455 #
5456 #
5457 sub check_host {
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: ";
5464       $mirror = <STDIN>;
5465       chomp $mirror;
5466    }
5467 }
5468 ########################################################################
5469 #
5470 # Answer to question.
5471 #
5472 sub get_answ {
5473    my $ans = "x";
5474    while($ans !~ /^y|^n/) {
5475       print "Do you want to enter a different ".$_[0]." than ".$_[1];
5476       print "? [y/n], (n): ";
5477       $ans = <STDIN>;
5478       chomp $ans;
5479       if($ans eq "") {
5480          $ans = "n";
5481       }
5482    }
5483    if($ans =~ /^y/) {
5484       return "";
5485    }
5486    return $_[1];
5487 }
5488 ########################################################################
5489 #
5490 # Check quality passed from command line for lame, oggenc, flac, faac.
5491 #
5492 sub check_quality {
5493    #
5494    # Prevent warnings.
5495    @pquality = defined unless(@pquality);
5496    #
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!
5500    #
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));
5507    }
5508    elsif("@quality" eq "5 3 5 100 0 5") {
5509       return;
5510    }
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>;
5520       close(CONF);
5521       @pcoder = grep(s/^coder=//, @conflines) unless(@pcoder);
5522       chomp @pcoder;
5523       if($pcoder[0] =~ /^\d/) {
5524          @coder = split(/,/, join(',',@pcoder));
5525       }
5526    }
5527
5528    # Actually check only those qualities needed, i.e. for chosen
5529    # encoders.
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]"
5533    # instead!
5534    my $corrflag = 0;
5535    $qualame = "";
5536    $qualoggenc = "";
5537    $quaflac = "";
5538    $quafaac = "";
5539    $quamp4als = "";
5540    $quamuse = "";
5541    for(my $c=0; $c<=$#coder; $c++) {
5542       if($coder[$c] == 0 && !defined($quality[$c])) {
5543          $quality[$c] = 5; # prevent warnings.
5544       }
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),",
5550                   " [0-9]: ";
5551             $quality[$c] = <STDIN>;
5552             chomp $quality[$c];
5553          }
5554          $qualame .= ";" . $quality[$c];
5555       }
5556       elsif($coder[$c] == 0 && $quality[$c] eq "off") {
5557          $qualame .= ";" . $quality[$c];
5558       }
5559       # Done with lame, do the other encoders.
5560       if($coder[$c] == 1 && !defined($quality[$c])) {
5561          $quality[$c] = 3; # prevent warnings.
5562       }
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),",
5568                   " [1-10]: ";
5569             $quality[$c] = <STDIN>;
5570             chomp $quality[$c];
5571          }
5572          $qualoggenc .= "," . $quality[$c];
5573       }
5574       elsif($coder[$c] == 1 && $quality[$c] eq "off") {
5575          $qualoggenc .= "," . $quality[$c];
5576       }
5577       if($coder[$c] == 2 && !defined($quality[$c])) {
5578          $quality[$c] = 5; # prevent warnings.
5579       }
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 ",
5584                   "for Flac!",
5585                   "\nPlease enter a different compression level ",
5586                   "(0 = lowest), [0-8]: ";
5587             $quality[$c] = <STDIN>;
5588             chomp $quality[$c];
5589          }
5590          $quaflac = $quaflac . "," . $quality[$c];
5591       }
5592       elsif($coder[$c] == 2 && $quality[$c] eq "off") {
5593          $quaflac .= "," . $quality[$c];
5594       }
5595       if($coder[$c] == 3 && !defined($quality[$c])) {
5596          $quality[$c] = 100; # prevent warnings.
5597       }
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), ",
5603                   "[10-500]: ";
5604             $quality[$c] = <STDIN>;
5605             chomp $quality[$c];
5606          }
5607          $quafaac .= "," . $quality[$c];
5608       }
5609       elsif($coder[$c] == 3 && $quality[$c] eq "off") {
5610          $quafaac .= "," . $quality[$c];
5611       }
5612       if($coder[$c] == 4 && !defined($quality[$c])) {
5613          $quality[$c] = 0; # prevent warnings.
5614       }
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];
5619       }
5620       elsif($coder[$c] == 4 && $quality[$c] eq "off") {
5621          $quamp4als .= "," . $quality[$c];
5622       }
5623       if($coder[$c] == 5 && !defined($quality[$c])) {
5624          $quality[$c] = 5; # prevent warnings.
5625       }
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), ",
5631                   "[0-10]: ";
5632             $quality[$c] = <STDIN>;
5633             chomp $quality[$c];
5634          }
5635          $quamuse .= "," . $quality[$c];
5636       }
5637       elsif($coder[$c] == 5 && $quality[$c] eq "off") {
5638          $quamuse .= "," . $quality[$c];
5639       }
5640       if($coder[$c] == 6 && !defined($quality[$c])) {
5641          $quality[$c] = " "; # prevent warnings.
5642       }
5643       if($coder[$c] == 7 && !defined($quality[$c])) {
5644          $quality[$c] = " "; # prevent warnings.
5645       }
5646    }
5647    $qualame =~ s/^,//;
5648    $qualoggenc =~ s/^,//;
5649    $quaflac =~ s/^,//;
5650    $quafaac =~ s/^,//;
5651    $quamuse =~ 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.
5663    if($pquality[0]) {
5664       my $pquality = join(',', @quality);
5665       $pquality =~ s/(,\s)*$//;
5666       @pquality = ();
5667       $pquality[0] = $pquality;
5668    }
5669 }
5670 ########################################################################
5671 #
5672 # Check bitrate for Lame only if vbr is wanted.
5673 #
5674 sub check_vbrmode {
5675    while($vbrmode ne "new" && $vbrmode ne "old") {
5676       print "\nFor vbr using Lame choose *new* or *old*! (new): ";
5677       $vbrmode = <STDIN>;
5678       chomp $vbrmode;
5679       $vbrmode = "new" if($vbrmode eq "");
5680    }
5681 }
5682 ########################################################################
5683 #
5684 # Check preset for Lame only.
5685 #
5686 sub lame_preset {
5687    if($vbrmode eq "new") {
5688       $preset = "fast " . $preset;
5689    }
5690 }
5691 ########################################################################
5692 #
5693 # Check if there is an other than $cddev which has a CD if no --device
5694 # option was given.
5695 #
5696 sub check_cddev {
5697    # Try to get a list of possible CD devices.
5698    open(DEV, "/etc/fstab");
5699    my @dev = <DEV>;
5700    close(DEV);
5701    @dev = grep(/^\s*\/dev/, @dev);
5702    @dev = grep(!/^\s*\/dev\/[f|h]d/, @dev);
5703    @dev = grep(!/sd/, @dev);
5704    my @devlist = ();
5705    foreach (@dev) {
5706       my @line = split(/\s/, $_);
5707       chomp $line[0];
5708       push(@devlist, $line[0]) unless($line[0] =~ /by-id/);
5709    }
5710    # First check some default addresses.
5711    if(open(CD, "$cddev")) {
5712       $cddev = $cddev;
5713       close(CD);
5714    }
5715    elsif(open(CD, "/dev/cdrecorder")) {
5716       $cddev = "/dev/cdrecorder";
5717       close(CD);
5718    }
5719    elsif(open(CD, "/dev/dvd")) {
5720       $cddev = "/dev/dvd";
5721       close(CD);
5722    }
5723    elsif(open(CD, "/dev/sr0")) {
5724       $cddev = "/dev/sr0";
5725       close(CD);
5726    }
5727    elsif(open(CD, "/dev/sr1")) {
5728       $cddev = "/dev/sr1";
5729       close(CD);
5730    }
5731    else {
5732       foreach (@devlist) {
5733          if(open(CD, "$_")) {
5734             $cddev = $_;
5735             chomp $cddev;
5736             close(CD);
5737          }
5738          else {
5739             $cddev = "";
5740          }
5741       }
5742    }
5743    # On a notebook, the tray can't be closed automatically!
5744    # Print error message and retry detection.
5745    if($cddev eq "") {
5746       print "Is there a CD and the tray of the device closed?\n";
5747       print "Pausing 12 seconds.\n";
5748       sleep(12);
5749       foreach (@devlist) {
5750          if(open(CD, "$_")) {
5751             $cddev = $_;
5752             chomp $cddev;
5753             close(CD);
5754          }
5755       }
5756    }
5757    if($cddev eq "") {
5758       print "Could not detect CD device! The default /dev/cdrom ";
5759       print "device will be used.\n";
5760       $cddev = "/dev/cdrom";
5761    }
5762    return;
5763 }
5764 ########################################################################
5765 #
5766 # Check bitrate if bitrate is not zero.
5767 #
5768 sub check_bitrate {
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";
5775       $bitrate = <STDIN>;
5776       chomp $bitrate;
5777       if($bitrate eq "") {
5778          $bitrate = 128;
5779       }
5780    }
5781 }
5782 ########################################################################
5783 #
5784 # Check protocol level for CDDB query.
5785 #
5786 sub check_proto {
5787    while($proto > 6) {
5788       print "Protocol level for CDDB query should be less-equal 6!\n";
5789       print "Enter an other value for protocol level (6): ";
5790       $proto =  <STDIN>;
5791       chomp $proto;
5792       $proto = 6 if($proto eq "");
5793    }
5794 }
5795 ########################################################################
5796 #
5797 # Check and clean the coder array.
5798 #
5799 sub check_coder {
5800
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);
5804
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!
5808    if(@pcoder) {
5809       @coder = split(/,/, join(',', @pcoder));
5810    }
5811    else {
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));
5816    }
5817
5818    my @ffmpegsuf = ();
5819    if($ffmpegsuffix) {
5820       @ffmpegsuf = split(/,/, $ffmpegsuffix);
5821    }
5822
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!
5831       }
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;
5845       }
5846    }
5847    # Use comma separated string to write the encoder array to the
5848    # config file!
5849    $wcoder = join(',', @coder);
5850 }
5851 ########################################################################
5852 #
5853 # Over or re-write the config file (depends on option savenew or save).
5854 #
5855 # New options step 10: Add description of new option to config file.
5856 #
5857 sub save_config {
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";
5866    print CONF "
5867 #####
5868 #
5869 # RipIT $version configuration file.
5870 #
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 .
5874
5875
5876 #####
5877 #
5878 # Ripping device & path.
5879 #
5880
5881 # cddevice: Define ripping device if other than /dev/cdrom.
5882 # Default: /dev/cdrom
5883
5884 cddevice=$cddev
5885
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
5889 # be used.
5890 # Example: /dev/sr18
5891 # Default: not set
5892
5893 scsidevice=$scsi_cddev
5894
5895 # output: Path for audio files. If not set, \$HOME will be used.
5896 # Default: not set
5897
5898 output=$outputdir
5899
5900 # directory permissions: Permissions for directories.
5901 # Default: 0755
5902
5903 dpermission=$dpermission
5904
5905 # file permissions: Permissions for sound and log files.
5906 # If not set, uses the default system settings.
5907 # Default: not set
5908
5909 fpermission=$fpermission
5910
5911
5912 #####
5913 #
5914 # Ripping options.
5915 #
5916
5917 # ripper: select CD ripper
5918 # 0 - dagrab
5919 # 1 - cdparanoia
5920 # 2 - cdda2wav
5921 # 3 - tosha
5922 # 4 - cdd
5923 # Default: cdparanoia
5924
5925 ripper=$ripper
5926
5927 # ripopt: User definable options for the CD ripper.
5928 # Default: not set
5929
5930 ripopt=$ripopt
5931
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
5935 # Default: not set
5936
5937 span=$span
5938
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
5944
5945 paranoia=$parano
5946
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
5950 # Default: off
5951
5952 ghost=$ghost
5953
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.
5959 # Default: 2.0
5960
5961 prepend=$prepend
5962
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.
5967 # Default: 2.0
5968
5969 extend=$extend
5970
5971 # resume: Resume a previously started session.
5972 # Possible values: 0 - off, 1 - on
5973 # Default: off
5974
5975 resume=$resume
5976
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
5982 # switched on.
5983 # Possible values: n - off, y - on,
5984 #                  q - quit, e - quit and force ejection
5985 # Default: off
5986
5987 overwrite=$overwrite
5988
5989
5990 #####
5991 #
5992 # Encoding options
5993 #
5994
5995 # encode: Encode the wavs.
5996 # Possible values: 0 - off, 1 - on
5997 # Default: on
5998
5999 encode=$encode
6000
6001 # coder: Select encoders for audio files:
6002 # 0 - Lame (mp3)
6003 # 1 - Oggenc (ogg)
6004 # 2 - Flac (flac)
6005 # 3 - Faac (m4a)
6006 # 4 - mp4als (als or mp4)
6007 # 5 - Musepack (mpc)
6008 # 6 - Wavpack (wv)
6009 # 7 - ffmpeg
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
6012 # Default: Lame
6013
6014 coder=$wcoder
6015
6016 ###
6017 #
6018 # lame (mp3) encoder options
6019 #
6020
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
6026 # 9: lowest 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.
6031 # Default: 5
6032
6033 qualame=$qualame
6034
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
6038 # Default: not set
6039
6040 lameopt=$lameopt
6041
6042 # vbrmode: Enable variable bitrate for lame encoder.
6043 # Possible values: \"old\" or \"new\"
6044 # Default: not set
6045
6046 vbrmode=$vbrmode
6047
6048 # bitrate: Sets bitrate for lame encoder.
6049 # Possible values: 32...320, off
6050 # Should be set to \"off\" if vbr is used
6051 # Default: 128
6052
6053 bitrate=$bitrate
6054
6055 # maxrate: Sets maximum bitrate for lame (when using vbr) and oggenc.
6056 # Possible values: 0 - off, 32...320
6057 # Default: 0
6058
6059 maxrate=$maxrate
6060
6061 # preset: Use lame presets. To set the \"fast\" switch, use --vbrmode new.
6062 # Possible values: medium, standard, extreme, insane
6063 #
6064 # medium: 160kbps
6065 # standard: 192kbps
6066 # extreme: 256kbps
6067 # insane: 320kbps
6068 #
6069 # Default: not set
6070
6071 preset=$wpreset
6072
6073 ###
6074 #
6075 # oggenc (ogg) encoder options
6076 #
6077
6078 # qualoggenc: Sets audio quality for oggenc.
6079 # Possible values: 1..10, off
6080 # 1: lowest quality
6081 # 10: highest quality
6082 # Can be set to \"off\"
6083 # Default: 3
6084
6085 qualoggenc=$qualoggenc
6086
6087 # oggencopt: Additional options for oggenc,
6088 # use a comma separated list if encoder is used several times.
6089 # Default: not set
6090
6091 oggencopt=$oggencopt
6092
6093 ###
6094 #
6095 # flac (lossless) encoder options
6096 #
6097
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\"
6103 # Default: 5
6104
6105 quaflac=$quaflac
6106
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.
6115 # Default: not set
6116
6117 flacopt=$flacopt
6118
6119 ###
6120 #
6121 # faac (m4a) encoder options
6122 #
6123
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\"
6129 # Default: 100
6130
6131 quafaac=$quafaac
6132
6133 # faacopt: Additional options for faac encoder,
6134 # comma separated list if encoder is used several times.
6135 # Default: not set
6136
6137 faacopt=$faacopt
6138
6139 ###
6140 #
6141 # mp4als (als or mp4) encoder options
6142 #
6143
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.
6147 # Default: 0
6148
6149 quamp4als=$quamp4als
6150
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.
6155 # Default: not set
6156
6157 mp4alsopt=$mp4alsopt
6158
6159 ###
6160 #
6161 # Musepack (mpc) encoder options
6162 #
6163
6164 # musenc: The encoder name on the command line
6165 # Possible values: any
6166 # Example: musenc=mppenc for older versions
6167 # Default: mpcenc
6168
6169 musenc=$musenc
6170
6171 # quamuse: Sets audio quality for Musepack encoder
6172 # Possible values: 0...10, off
6173 # 0: lowest quality
6174 # 10: highest quality
6175 # Can be set to \"off\"
6176 # Default: 5
6177
6178 quamuse=$quamuse
6179
6180 # museopt: Additional options for Musepack encoder,
6181 # use a comma separated list if encoder is used several times.
6182 # Default: not set
6183
6184 museopt=$museopt
6185
6186 ###
6187 #
6188 # Wavpack (wv) encoder options
6189 #
6190
6191 # wavpacopt: Additional options for Wavpack encoder,
6192 # use a comma separated list if encoder is used several times.
6193 # Example: -b320chy
6194 # Default: -y
6195
6196 wavpacopt=$wavpacopt
6197
6198 ###
6199 #
6200 #ffmpeg encoder options
6201 #
6202
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
6206 # Default: off
6207
6208 ffmpegopt=$ffmpegopt
6209
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
6213 # Default: off
6214
6215 ffmpegsuffix=$ffmpegsuffix
6216
6217
6218 #####
6219 #
6220 # Trackname and directory template
6221 #
6222
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:
6227 # \$album
6228 # \$artist
6229 # \$iletter
6230 # \$genre
6231 # \$quality
6232 # \$suffix
6233 # \$trackname
6234 # \$tracknum
6235 # \$year
6236 # \$trackno
6237 #
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
6244 # of the release.
6245 #
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=...).
6249 #
6250 # Example:
6251 # dirtemplate=\"\$suffix/hard_path/\$iletter/\$artist/\$year - \$album\"
6252 #
6253 # The double quotes (\") are mandatory!
6254 # Default: \"\$artist - \$album\"
6255 \n";
6256    print CONF "dirtemplate=$_\n" foreach(@dirtemplate);
6257    print CONF "
6258 # tracktemplate: Template for track names
6259 # \"tracktemplate\" is used similarly to \"dirtemplate\"
6260 # Default:  \"\$tracknum \$trackname\"
6261
6262 tracktemplate=$tracktemplate
6263
6264 # trackoffset: Add an offset to the track counter (\$tracknum)
6265 # Possible values: any integer
6266 # Default: 0
6267
6268 trackoffset=$trackoffset
6269
6270 # infolog: Log certain operations to file
6271 # (e.g. system calls, creation of dirs/files)
6272 # Possible values: filename (full path, no ~ here!)
6273 # Default: not set
6274
6275 infolog=$infolog
6276
6277 # lowercase: Convert filenames to lowercase
6278 # Possible values: 0 - off, 1 - on
6279 # Default: off
6280
6281 lowercase=$lowercase
6282
6283 # uppercasefirst: Convert filenames and tags to uppercase first,
6284 # not recommended. To be used on the command line only if CDDB entry
6285 # is in uppercase.
6286 # Possible values: 0 - off, 1 - on
6287 # Default: off
6288
6289 uppercasefirst=$uppercasefirst
6290
6291 # underscore: Replace blanks in filenames with underscores
6292 # Possible values: 0 - off, 1 - on
6293 # Default: off
6294
6295 underscore=$underscore
6296
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
6306 # directories.
6307 #
6308 # No need to escape the special characters here in the config file.
6309 # Possible values: HFS, NTFS, none, any (?)
6310 # Default: not set
6311
6312 chars=$chars
6313
6314 # playlist: Create m3u playlist with or without the full path
6315 # in the filename.
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)
6320
6321 playlist=$playlist
6322
6323
6324 #####
6325 #
6326 # Audio file tagging
6327 #
6328
6329 # year-tag: State a year (mp3, m4a) or a date (ogg, flac) tag.
6330 # Possible values: integer
6331 # Default: not set
6332
6333 year=$year
6334
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\"
6338 # or \"discid\".
6339 # Possible values: discid, cddbid or any string
6340 # Default: not set
6341
6342 comment=$commentag
6343
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
6350 # Default: not set
6351 \n";
6352    if(@mp3tags) {
6353       foreach(@mp3tags) {
6354          print CONF "mp3tags=$_\n";
6355       }
6356    }
6357    else {
6358       print CONF "mp3tags=\n";
6359    }
6360    print CONF "
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
6366 # Default: on
6367
6368 utftag=$utftag
6369
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.
6375 # Example: 1,0,0,1
6376 # Possible values: 0 - off, 1 - on
6377 # Default: off
6378
6379 coverart=$coverart
6380
6381 # coverpath: Path where the cover can be found.
6382 # Example: ../thumb.png
6383 # Possible values: string, none
6384 # Default: none
6385
6386 coverpath=$coverpath
6387
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
6392 # Default: off
6393
6394 copycover=$copycover
6395
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).
6407 # Example: 5
6408 # Possible values: 0 - off, 1, 2, 3, 4, 5, 6, 7, 8
6409 # Default: off
6410
6411 vatag=$vatag
6412
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
6418
6419 vastring=$vastring
6420
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
6424 # Default: not set
6425
6426 mp3gain=$mp3gain
6427
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
6431 # Default: not set
6432
6433 vorbgain=$vorbgain
6434
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
6438 # Default: not set
6439
6440 flacgain=$flacgain
6441
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
6445 # Default: not set
6446
6447 aacgain=$aacgain
6448
6449 # mpcgain: Add album gain tags to mpc files using the appropriate
6450 # command with options and arguments but without infiles.
6451 # Example: mpcgain
6452 # Default: not set
6453
6454 mpcgain=$mpcgain
6455
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
6459 # Default: not set
6460
6461 wvgain=$wvgain
6462
6463
6464 #####
6465 #
6466 # CDDB options
6467 #
6468
6469 # mb: Access MusicBrainz DB via WebService::MusicBrainz module instead
6470 # of the http protocol (see below).
6471 # Possible values: 0 - off, 1 - on
6472 # Default: off
6473
6474 mb=$mb
6475
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
6480 # mirror.
6481 # E.g. default server is freedb.freedb.org
6482 # Default: freedb.org
6483
6484 CDDBHOST=$CDDB_HOST
6485
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
6491 # Default: freedb
6492
6493 mirror=$mirror
6494
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
6498 # mode http.
6499 # Default: cddb
6500
6501 transfer=$transfer
6502
6503 # proto: Set CDDP protocol level
6504 # Possible values: 5, 6
6505 # Protocol level 6 supports Unicode (UTF-8)
6506 # Default: 6
6507
6508 proto=$proto
6509
6510 # proxy: Address of http-proxy, if needed.
6511 # Default: not set
6512
6513 proxy=$proxy
6514
6515 # mailad: Mail address for cddb submissions.
6516 # Possible values: Valid user email address for submitting cddb entries
6517 # Default: not set
6518
6519 mailad=$mailad
6520
6521 # archive: Read and save cddb data on local machine.
6522 # Possible values: 0 - off, 1 - on
6523 # Default: off
6524
6525 archive=$archive
6526
6527 # submission: Submit new or edited cddb entries to freeCDDB.
6528 # Possible values: 0 - off, 1 - on
6529 # Default: on
6530
6531 submission=$submission
6532
6533 # interaction: Turns on or off user interaction in cddb dialog and
6534 # everywhere else.
6535 # Possible values: 0 - off, 1 - on
6536 # Default: on
6537
6538 interaction=$interaction
6539
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
6544 # Default: off
6545
6546 isrc=$isrc
6547
6548 # mbname: login name to Musicbrainz.org
6549 # Possible values: string
6550 # Default: not set
6551
6552 mbname=$mbname
6553
6554 # mbpass: password to Musicbrainz.org
6555 # Possible values: string
6556 # Default: not set
6557
6558 mbpass=$mbpass
6559
6560
6561 #####
6562 #
6563 # LCD options
6564 #
6565
6566 # lcd: Use lcdproc to display status on LCD
6567 # Possible values: 0 - off, 1 - on
6568 # Default: off
6569
6570 lcd=$lcd
6571
6572 # lcdhost: Specify the lcdproc host
6573 # Default: localhost
6574
6575 lcdhost=$lcdhost
6576
6577 # lcdport: Specify port number for $lcdhost
6578 # Default: 13666
6579
6580 lcdport=$lcdport
6581
6582
6583 #####
6584 #
6585 # Distributed ripping options
6586 #
6587
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
6592 # machine names.
6593 # Default: not set
6594
6595 sshlist=$wsshlist
6596
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
6600 # Default: off
6601
6602 scp=$scp
6603
6604 # local: Turn off encoding on local machine, e.g. use only remote
6605 # machines.
6606 # Possible values: 0 - off, 1 - on
6607 # Example: local=0 (off) turns off encoding on the
6608 # local machine
6609 # Default: on
6610
6611 local=$local
6612
6613
6614 #####
6615 #
6616 # Misc. options
6617 #
6618
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
6624
6625 verbose=$verbose
6626
6627 # eject: Eject cd after finishing encoding.
6628 # Possible values: 0 - off, 1 - on
6629 # Default: off
6630
6631 eject=$eject
6632
6633 # ejectcmd: Command used to eject and close CD tray.
6634 # Possible values: string
6635 # Example: /usr/sbin/cdcontrol for FreeBSD
6636 # Default: eject
6637
6638 ejectcmd=$ejectcmd
6639
6640 # ejectopt: Options to command used to eject or close CD.
6641 # Possible values: string or \"{cddev}\" to design the CD
6642 # device.
6643 # Note: Don't use options -t / close or eject,
6644 #       RipIT knows when to eject or load the tray
6645 # Default: {cddev}
6646
6647 ejectopt=$ejectopt
6648
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
6654 # Default: off
6655
6656 quitnodb=$quitnodb
6657
6658 # execmd: Execute a command when done with ripping. Quote the command
6659 # if needed.
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
6662 # if available.
6663 # Possible values: none - off, string - on
6664 # Example: execmd=\"add_db -a \\\"\$artist\\\" -r \\\"\$album\\\"\"
6665 # Default: off
6666
6667 execmd=$execmd
6668
6669 # precmd: Execute a command before starting to rip. Quote the command
6670 # if needed.
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
6673 # if available.
6674 # Possible values: none - off, string - on
6675 # Example: precmd=\"get_cover -a \\\"\$artist\\\" -r \\\"\$album\\\" -o \\\"\$wavdir\\\" -t \\\"\$trackno\\\"\"
6676 # Default: off
6677
6678 precmd=$precmd
6679
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
6685 # Default: off
6686
6687 book=$book
6688
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
6695 # Default: off
6696
6697 loop=$loop
6698
6699 # halt: Powers off machine after finishing encoding.
6700 # Possible values: 0 - off, 1 - on
6701 # Default: off
6702
6703 halt=$halt
6704
6705 # nice: Sets \"nice\" value for the encoding process.
6706 # Possible values: 0..19 for normal users,
6707 #                  -20..19 for user \"root\"
6708 # Default: 0
6709
6710 nice=$nice
6711
6712 # nicerip: Sets \"nice\" value for the ripping process.
6713 # Possible values: 0..19 for normal users,
6714 #                  -20..19 for user \"root\"
6715 # Default: 0
6716
6717 nicerip=$nicerip
6718
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
6723 # Default: 1
6724
6725 threads=$wthreads
6726
6727 # md5sum: Create file with md5sums for each type of sound files.
6728 # Possible values: 0 - off, 1 - on
6729 # Default: off
6730
6731 md5sum=$md5sum
6732
6733 # wav: Don't delete wave-files after encoding.
6734 # Possible values: 0 - off, 1 - on
6735 # Default: off
6736
6737 wav=$wav
6738
6739 # normalize: Normalizes the wave-files to a given dB-value
6740 # (default: -12dB)
6741 # See http://normalize.nongnu.org for details.
6742 # Possible values: 0 - off, 1 - on
6743 # Default: off
6744
6745 normalize=$normalize
6746
6747 # normcmd: Command to be used to normalize.
6748 # Possible values: string
6749 # Example: normalize-audio (when using Debian)
6750 # Default: normalize
6751
6752 normcmd=$normcmd
6753
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
6760 #                               maintained
6761 #                  -m         : Mix mode - all track are normalized to
6762 #                               the same loudness
6763 #                  -v         : Verbose operation
6764 #                  -q         : Quiet operation
6765 # For further options see normalize documentation.
6766 # Default: -b
6767 # The -v option will be added by default according to RipITs verbosity
6768
6769 normopt=$normopt
6770
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
6774 # Default: off
6775
6776 cdtoc=$cdtoc
6777
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
6781 # Default: off
6782
6783 inf=$inf
6784
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.
6788 # Default: off
6789
6790 cdcue=$cdcue
6791 \n";
6792    close(CONF);
6793 }
6794 ########################################################################
6795 #
6796 # Read the config file, take the parameters only if NOT yet defined!
6797 #
6798 # New options step 11: Read the new options from config file. Replicate
6799 # one of the 2-liners starting with chomp.
6800 #
6801 sub read_config {
6802    $ripdir = $confdir . "/" . $confname if($confdir ne "");
6803    # Fallback:
6804    $ripdir = $homedir . "/.ripit/config" unless(-r "$ripdir");
6805    $ripdir = "/etc/ripit/config" unless(-r "$ripdir");
6806    if(-r "$ripdir") {
6807       open(CONF, "$ripdir") or
6808       print "Can not read config file in $ripdir: $!\n";
6809       my @conflines = <CONF>;
6810       close(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);
6815       chomp $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";
6820          # TODO:
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);
6826          sleep(3);
6827       }
6828       elsif($version ne $confver) {
6829          grep(s/^chars=[01]\s*$/chars=/, @conflines);
6830       }
6831       chomp($archive = join(' ', grep(s/^archive=//, @conflines)))
6832          unless defined $parchive;
6833       chomp($bitrate = join(' ', grep(s/^bitrate=//, @conflines)))
6834          unless($pbitrate);
6835       chomp($book = join(' ', grep(s/^book=//, @conflines)))
6836          unless($pbook);
6837       chomp($maxrate = join(' ', grep(s/^maxrate=//, @conflines)))
6838          unless($pmaxrate);
6839       chomp($cddev = join(' ', grep(s/^cddevice=//, @conflines)))
6840          unless($pcddev);
6841       chomp($scsi_cddev = join(' ', grep(s/^scsidevice=//, @conflines)))
6842          unless($pscsi_cddev);
6843       chomp($cdtoc = join('', grep(s/^cdtoc=//, @conflines)))
6844          unless($pcdtoc);
6845       chomp($cdcue = join('', grep(s/^cdcue=//, @conflines)))
6846          unless($pcdcue);
6847       chomp($chars = join('', grep(s/^chars=//, @conflines)))
6848          if($chars eq "XX");
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);
6857       chomp $wcoder;
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)))
6882          unless($phalt);
6883       chomp($inf = join('', grep(s/^inf=//, @conflines)))
6884          unless($pinf);
6885       chomp($infolog = join('', grep(s/^infolog=//, @conflines)))
6886          unless($pinfolog);
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)))
6894          unless($plcdhost);
6895       chomp($lcdport = join('', grep(s/^lcdport=//, @conflines)))
6896          unless($plcdport);
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)))
6906          unless($pmailad);
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)))
6914          unless($pmd5sum);
6915       chomp($mirror = join('', grep(s/^mirror=//, @conflines)))
6916          unless($pmirror);
6917       @mp3tags = grep(s/^mp3tags=//, @conflines)
6918          unless($pmp3tags[0]);
6919       chomp $_ foreach(@mp3tags);
6920       chomp($musenc = join('', grep(s/^musenc=//, @conflines)))
6921          unless($pmusenc);
6922       chomp($normalize = join('', grep(s/^normalize=//, @conflines)))
6923          unless defined $pnormalize;
6924       chomp($normcmd = join('', grep(s/^normcmd=//, @conflines)))
6925          unless($pnormcmd);
6926       chomp($normopt = join('', grep(s/^normopt=//, @conflines)))
6927          unless($pnormopt);
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)))
6943          unless($ppreset);
6944       # NOTE: we have to fill the w_RITE_preset variable!
6945       $wpreset = $preset unless($ppreset);
6946       chomp $preset;
6947       chomp $wpreset;
6948       chomp($proto = join('', grep(s/^proto=//, @conflines)))
6949          unless($pproto);
6950       chomp($proxy = join('', grep(s/^proxy=//, @conflines)))
6951          unless($pproxy);
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];
6982                shift(@qualame);
6983             }
6984             if($coder[$c] == 1) {
6985                $quality[$c] = $qualoggenc[0];
6986                shift(@qualoggenc);
6987             }
6988             if($coder[$c] == 2) {
6989                $quality[$c] = $quaflac[0];
6990                shift(@quaflac);
6991             }
6992             if($coder[$c] == 3) {
6993                $quality[$c] = $quafaac[0];
6994                shift(@quafaac);
6995             }
6996             if($coder[$c] == 4) {
6997                $quality[$c] = $quamp4als[0];
6998                shift(@quamp4als);
6999             }
7000             if($coder[$c] == 5) {
7001                $quality[$c] = $quamuse[0];
7002                shift(@quamuse);
7003             }
7004          }
7005       }
7006       chomp($faacopt = join('', grep(s/^faacopt=//, @conflines)))
7007          unless($pfaacopt);
7008       chomp($flacopt = join('', grep(s/^flacopt=//, @conflines)))
7009          unless($pflacopt);
7010       chomp($lameopt = join('', grep(s/^lameopt=//, @conflines)))
7011          unless($plameopt);
7012       chomp($mp4alsopt = join('', grep(s/^mp4alsopt=//, @conflines)))
7013          unless($pmp4alsopt);
7014       chomp($museopt = join('', grep(s/^museopt=//, @conflines)))
7015          unless($pmuseopt);
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)))
7021          unless($paacgain);
7022       chomp($flacgain = join('', grep(s/^flacgain=//, @conflines)))
7023          unless($pflacgain);
7024       chomp($mp3gain = join('', grep(s/^mp3gain=//, @conflines)))
7025          unless($pmp3gain);
7026       chomp($mpcgain = join('', grep(s/^mpcgain=//, @conflines)))
7027          unless($pmpcgain);
7028       chomp($vorbgain = join('', grep(s/^vorbgain=//, @conflines)))
7029          unless($pvorbgain);
7030       chomp($wvgain = join('', grep(s/^wvgain=//, @conflines)))
7031          unless($pwvgain);
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)))
7037          unless($pcoverart);
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]);
7051       chomp @clist;
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]);
7055       chomp @rlist;
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)))
7065          unless($ptransfer);
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)))
7079          unless($pvbrmode);
7080       chomp($year = join('', grep(s/^year=//, @conflines)))
7081          unless($pyear);
7082       chomp($wav = join('', grep(s/^wav=//, @conflines)))
7083          unless defined $pwav;
7084    }
7085    else {
7086       print "\nNo config file found! Use option --save to create one.\n"
7087          if($verbose >= 2);
7088    }
7089 }
7090 ########################################################################
7091 #
7092 # Encode to utf-8 with UTF8 flag.
7093 #
7094 sub UTF8_encoding {
7095    my $string = shift;
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);
7112    return($string);
7113 }
7114 ########################################################################
7115 #
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.
7119 #
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
7127 #
7128 sub back_encoding {
7129    my $string = shift;
7130    my $utf_string = $string;
7131    if(utf8::is_utf8($string)) {
7132       print "The \$string is already in utf8, do nothing!\n"
7133       if($verbose >= 5);
7134    }
7135    else {
7136       $utf_string = Encode::decode('UTF-8', $utf_string, Encode::FB_QUIET);
7137    }
7138    my @utf_points = unpack("U0U*", "$utf_string"); # Perl 5.10
7139    print "\nutf_points:\n@utf_points\n" if($verbose >= 5);
7140    my $latinflag = 0;
7141    my $wideflag = 0;
7142    foreach (@utf_points) {
7143       $wideflag = 1 if($_ > 255);
7144       $latinflag++ if($_ > 128 && $_ < 256);
7145    }
7146
7147    # It works with Rƶyksopp archive and freeCDDB entry.
7148    my @char_points = unpack("U0U*", "$string");
7149
7150
7151    @char_points = @utf_points if($wideflag == 1);
7152
7153    return $string if($string eq "");
7154    my $decoded = "";
7155    foreach (@char_points) {
7156       if($_ > 255) {
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);
7162          my $smallflag = 0;
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;
7172       }
7173       else {
7174          $decoded .= chr($_);
7175       }
7176    }
7177
7178    if($cd{discid}) {
7179       # Special condition for MB data. Please do not ask why.
7180       if($wideflag == 0 && $latinflag == 0) {
7181       # Original.
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');
7186       }
7187       elsif($wideflag == 0) {
7188          Encode::from_to($decoded, 'utf-8', 'ISO-8859-15');
7189       }
7190    }
7191    elsif($wideflag == 0) {
7192       Encode::from_to($decoded, 'utf-8', 'ISO-8859-15');
7193    }
7194    return $decoded;
7195 }
7196 ########################################################################
7197 #
7198 # Check the preset options.
7199 #
7200 sub check_preset {
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): ";
7206          $preset = <STDIN>;
7207          chomp $preset;
7208          if($preset eq "") {
7209             $preset = "standard";
7210          }
7211       }
7212    }
7213    else {
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";
7219          $preset = <STDIN>;
7220          chomp $preset;
7221          if($preset eq "") {
7222             $preset = 128;
7223          }
7224       }
7225    }
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);
7230    $wpreset = $preset;
7231 }
7232 ########################################################################
7233 #
7234 # Check sshlist of remote machines and create a hash.
7235 #
7236 sub check_sshlist {
7237    if(@psshlist) {
7238       @sshlist = split(/,/, join(',', @psshlist));
7239    }
7240    if(@pthreads) {
7241       @threads = split(/,/, join(',', @pthreads));
7242    }
7243    $wthreads = join(',', @threads);
7244    if(@sshlist || $threads[0] > 1) {
7245       $sshflag = 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);
7250       my $threadscn = 1;
7251       foreach (@sshlist) {
7252          $threads[$threadscn] = 1 unless($threads[$threadscn]);
7253          $sshlist{$_} = $threads[$threadscn];
7254          $threadscn++;
7255       }
7256    }
7257    else {
7258       $sshflag = 0;
7259    }
7260 }
7261 ########################################################################
7262 #
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.
7270 #
7271 sub enc_ssh {
7272    my $machine;
7273    my @codwav = ();
7274    my $delwav = $_[0];
7275    my $enccom = $_[1];
7276    my $ripnam = $_[2];
7277    my $sepdir = $_[3];
7278    my $suffix = $_[4];
7279    my $old_wavdir = $wavdir;
7280    my $old_sepdir = $sepdir;
7281    my $old_ripnam = $ripnam;
7282    my $esc_name;
7283    my $esc_dir;
7284    my $threadscn;
7285
7286    $sshflag = 2;
7287    while ($sshflag == 2) {
7288       # Start on the local machine first.
7289       $threadscn = 1;
7290       for($threadscn = 1; $threadscn <= $threads[0]; $threadscn++) {
7291          if(! -r "$wavdir/local.lock_$threadscn") {
7292             if($local == 1) {
7293                $sshflag = 1;
7294                $machine = "local";
7295                push @codwav, "$ripnam";
7296             }
7297          }
7298          last if($sshflag == 1);
7299       }
7300       last if($sshflag == 1);
7301       $threadscn = 1;
7302       foreach $_ (keys %sshlist) {
7303          $machine = $_; # Why this?
7304          for($threadscn = 1; $threadscn <= $sshlist{$_}; $threadscn++) {
7305             if(! -r "$wavdir/$machine.lock_$threadscn") {
7306                $sshflag = 1;
7307             }
7308             # Prepare array @codwav with all tracknames in, which are
7309             # still in progress, i. e. either being ripped or encoded.
7310             else {
7311                open(LOCK, "$wavdir/$machine.lock_$threadscn");
7312                my @locklines = <LOCK>;
7313                close(LOCK);
7314                if($locklines[0]) {
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);
7320                }
7321             }
7322             last if($sshflag == 1);
7323          }
7324          last if($sshflag == 1);
7325       }
7326       last if($sshflag == 1);
7327       sleep 3;
7328    }
7329
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$/);
7336       close(ENCLOG);
7337    }
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$/);
7343    }
7344    open(LOCKF, ">$wavdir/$machine.lock_$threadscn");
7345    print LOCKF "$sepdir/$ripnam.$suffix\n";
7346    close(LOCKF);
7347
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 . "'";
7355       if($scp) {
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\\\"");
7364          # *Copy* the File:
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);
7371          close(LOCK);
7372          my $wavflag = 0;
7373          # Open each lock-file, read the content, increase counter if
7374          # the same wavname is found. Again: it will be found at least
7375          # once.
7376          foreach(@boxes) {
7377             open(LOCKF, "$old_wavdir/$_") or
7378                print "Can't open $old_wavdir/$_: $!\n";
7379             my @content = <LOCKF>;
7380             close(LOCKF);
7381             $wavflag++ if("@content" =~ /$ripnam/);
7382          }
7383          $ripnam = esc_char($ripnam);
7384          log_system("scp $wavdir/$ripnam.wav \\
7385            $machine:\"$wavdir/$ripnam.wav\" > /dev/null 2>&1")
7386            if($wavflag <= 1);
7387       }
7388    }
7389    else {
7390       # On the local machine escape at least the dollar sign.
7391       $ripnam =~ s/\$/\\\$/g;
7392       $sepdir =~ s/\$/\\\$/g;
7393    }
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\" ";
7407       }
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\" ";
7413             # TODO:
7414             # Copy correction file! Not yet supported.
7415       }
7416       else {
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\" ";
7421       }
7422    }
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));
7428    }
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));
7434          # TODO:
7435          # Copy correction file! Not yet supported.
7436    }
7437    else {
7438       $enccom = $enccom . " && \\
7439                 mv \"$sepdir/$ripnam.$suffix\_enc\" \\
7440                 \"$sepdir/$ripnam.$suffix\""
7441          if($machine eq "local" || ($machine !~ /^local$/ && !$scp));
7442    }
7443    $enccom = $enccom . " && \\
7444              rm \"$old_wavdir/$machine.lock_$threadscn\" &";
7445
7446    # A huge hack only not to interfere with the ripper output.
7447    if($verbose >= 4) {
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>;
7454          close(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";
7461             close(ENCLOG);
7462          }
7463          else {
7464             print "\nExecuting command on machine $machine and tring",
7465                   " to encode \n$ripnam.$suffix\_enc.\n";
7466          }
7467       }
7468       else {
7469          print "\nExecuting command on machine $machine and tring",
7470                " to encode \n$ripnam.$suffix\_enc.\n";
7471       }
7472    }
7473    log_system("$enccom");
7474    sleep 2; # Don't mess up with possible error-msgs from remote hosts.
7475
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
7485    # @delname.
7486    if($delwav == 1) {
7487       push @delname, "$ripnam";
7488       my $delflag = 0;
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.");
7495             shift(@delname);
7496             # Prevent endless loop if array is empty.
7497             $delflag = 1 if(!$delwav[0]);
7498          }
7499          else {
7500             $delflag = 1;
7501          }
7502       }
7503    }
7504 }
7505 ########################################################################
7506 #
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.
7511 #
7512 sub del_wav {
7513    my $waitflag = 1;
7514    sleep 3;
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) {
7519       sleep 3;
7520       opendir(DIR, "$wavdir");
7521       my @locks = readdir(DIR);
7522       closedir(DIR);
7523       @locks = grep { /\.lock_\d+$/ } @locks;
7524       $waitflag++ if(! @locks);
7525       $waitflag = 0 if(@locks);
7526    }
7527    if($wav == 0) {
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);
7533       closedir(DIR);
7534       @wavs = grep { /\.wav$/ } @wavs;
7535       foreach (@wavs) {
7536          unlink("$wavdir/$_");
7537          log_info("File $wavdir/$_ deleted.");
7538       }
7539    }
7540    if($scp) {
7541       foreach my $machine (keys %sshlist) {
7542          next if($machine =~ /local/);
7543          foreach my $deldir (@sepdir, $wavdir) {
7544             my $dd = $deldir;
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");
7548          }
7549       }
7550    }
7551 }
7552 ########################################################################
7553 #
7554 # LCDproc subroutines, all credits to Max Kaesbauer. For comments and
7555 # questions contact max [dot] kaesbauer [at] gmail [dot] com.
7556 #
7557
7558 # print
7559
7560 sub plcd {
7561    my ($data) = @_;
7562    print $lcdproc $data."\n";
7563    my $res = <$lcdproc>;
7564 }
7565
7566 # update
7567
7568 sub ulcd {
7569    if($lcdoline1 ne $lcdline1) {
7570       $lcdoline1 = $lcdline1;
7571       plcd("widget_set ripitlcd line1 1 2 {$lcdline1}");
7572        }
7573    if($lcdoline2 ne $lcdline2) {
7574       $lcdoline2 = $lcdline2;
7575       plcd("widget_set ripitlcd line2 1 3 {$lcdline2}");
7576    }
7577    if($lcdoline3 ne $lcdline3) {
7578       $lcdoline3 = $lcdline3;
7579       plcd("widget_set ripitlcd line3 1 4 {$lcdline3}");
7580    }
7581 }
7582
7583 # init
7584
7585 sub init_lcd {
7586    $lcdproc = IO::Socket::INET->new(
7587       Proto     => "tcp",
7588       PeerAddr  => $lcdhost,
7589       PeerPort  => $lcdport,
7590    ) || die "Can not connect to LCDproc port\n";
7591    $lcdproc->autoflush(1);
7592    sleep 1;
7593
7594    print $lcdproc "Hello\n";
7595    my @lcd_specs = split(/ /,<$lcdproc>);
7596    my %screen;
7597
7598    $screen{wid} = $lcd_specs[7];
7599    $screen{hgt} = $lcd_specs[9];
7600    $screen{cellwid} = $lcd_specs[11];
7601    $screen{cellhgt} = $lcd_specs[13];
7602
7603    $screen{pixwid} = $screen{wid}*$screen{cellwid};
7604    $screen{pixhgt} = $screen{hgt}*$screen{cellhgt};
7605
7606    fcntl($lcdproc, F_SETFL, O_NONBLOCK);
7607
7608    plcd("client_set name {ripit.pl}");
7609    plcd("screen_add ripitlcd");
7610    plcd("screen_set ripitlcd name {ripitlcd}");
7611
7612    plcd("widget_add ripitlcd title title");
7613    plcd("widget_set ripitlcd title {RipIT $version}");
7614
7615    plcd("widget_add ripitlcd line1 string");
7616    plcd("widget_add ripitlcd line2 string");
7617    plcd("widget_add ripitlcd line3 string");
7618 }
7619 ########################################################################
7620 #
7621 # Read the CDDB on the local machine.
7622 #
7623 sub read_entry {
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>;
7629    close(LOG);
7630    %cd = ();
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);
7647    }
7648    else {
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);
7658       chomp $artist;
7659       chomp $album;
7660       $categ = $_[1];
7661       unless($genre) {
7662          chomp($genre = join('', grep(s/^DGENRE=//, @cddblines)));
7663          $genre =~ s/[\015]//g;
7664       }
7665       unless($year) {
7666          chomp($year = join('', grep(s/^DYEAR=//, @cddblines)));
7667          $year =~ s/[\015]//g;
7668       }
7669       unless($discid) {
7670          chomp($discid = join('', grep(s/^MBID=//, @cddblines)));
7671          $discid =~ s/[\015]//g;
7672       }
7673       $trackno = $_[2];
7674    }
7675    $cd{artist} = $artist;
7676    $cd{title} = $album;
7677    $cd{cat} = $categ;
7678    $cd{genre} = $genre;
7679    $cd{id} = $cddbid;
7680    $cd{discid} = $discid;
7681    $cd{asin} = $asin;
7682    $cd{year} = $year;
7683    $cd{barcode} = $barcode;
7684    $cd{language} = $language;
7685    $cd{reldate} = $reldate;
7686
7687    my $i = 1;
7688    my $j = 0;
7689    while($i <= $trackno) {
7690       my @track = ();
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;
7697       chomp $track;
7698       $cd{track}[$j] = $track;
7699       $i++;
7700       $j++;
7701    }
7702 }
7703 ########################################################################
7704 #
7705 # Delete error.log if there is no track-comment in!
7706 #
7707 sub del_erlog {
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>;
7712       close(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);
7716       if(@md5tracks) {
7717          foreach (@md5tracks) {
7718             my ($sepdir, $donetrack) = split(/;#;/, $_);
7719             chomp $donetrack;
7720             # Add special mp3 tags.
7721             if(@mp3tags && $donetrack =~ /mp3$/) {
7722                mp3_tags("$sepdir/$donetrack") if($mp3tags[0] ne "");
7723             }
7724             # Add coverart if it is a mp3 or ogg.
7725             if($donetrack =~ /mp3$/ && -f "$coverpath" && -s "$coverpath") {
7726                mp3_cover("$sepdir/$donetrack", "$coverpath");
7727             }
7728             elsif($donetrack =~ /ogg$/ && -f "$coverpath" && -s "$coverpath") {
7729                ogg_cover("$sepdir/$donetrack", "$coverpath");
7730             }
7731          }
7732       }
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"
7738          if($verbose > 2);
7739          if($mp3gain && $suffix[$c] =~ /mp3/) {
7740             log_system("$mp3gain \"$sepdir[$c]/\"*.$suffix[$c]");
7741          }
7742          elsif($vorbgain && $suffix[$c] =~ /ogg/) {
7743             log_system("$vorbgain \"$sepdir[$c]/\"*.$suffix[$c]");
7744          }
7745          elsif($flacgain && $suffix[$c] =~ /flac/) {
7746             log_system("$flacgain \"$sepdir[$c]/\"*.$suffix[$c]");
7747          }
7748          elsif($aacgain && $suffix[$c] =~ /m4a|mp4/) {
7749             log_system("$aacgain \"$sepdir[$c]/\"*.$suffix[$c]");
7750          }
7751          elsif($mpcgain && $suffix[$c] =~ /mpc/) {
7752             log_system("$mpcgain \"$sepdir[$c]/\"*.$suffix[$c]");
7753          }
7754          elsif($wvgain && $suffix[$c] =~ /wv/) {
7755             log_system("$wvgain \"$sepdir[$c]/\"*.$suffix[$c]");
7756          }
7757          else {
7758             print "\nNo album gain command found for $suffix[$c].\n"
7759             if($verbose > 5);
7760          }
7761       }
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);
7770       my $riptrackname;
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]"
7779                if($fpermission);
7780             # Generate md5sum of files.
7781             if($md5sum == 1) {
7782                if(-r "$sepdir[$c]/$riptrackname.$suffix[$c]") {
7783                   md5_sum("$sepdir[$c]",
7784                      "$riptrackname.$suffix[$c]", 1);
7785                }
7786             }
7787          }
7788          last if($cdcue > 0);
7789       }
7790
7791
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);
7797             close(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]);
7802             if($_ eq $wavdir) {
7803                chmod oct($fpermission), "$_/$md5files[0]" if($wav == 1);
7804             }
7805             else {
7806                chmod oct($fpermission), "$_/$md5files[0]";
7807             }
7808          }
7809       }
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");
7814       }
7815       elsif($fpermission) {
7816          chmod oct($fpermission), "$wavdir/error.log";
7817       }
7818       if($ghost == 1&& -r "$wavdir/ghost.log") {
7819          unlink("$wavdir/ghost.log");
7820       }
7821       if($wav == 0 && $wavdir ne $homedir) {
7822          # I don't like the -p option.
7823          log_system("rmdir -p \"$wavdir\" 2> /dev/null");
7824       }
7825    }
7826 }
7827 ########################################################################
7828 #
7829 # Escape special characters when using scp.
7830 #
7831 sub esc_char {
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;
7841    $_[0] =~ s/ /\\ /g;
7842    return $_[0];
7843 }
7844 ########################################################################
7845 #
7846 # Calculate how much time ripping and encoding needed.
7847 #
7848 sub cal_times {
7849    my $encend = `date \'+%R\'`;
7850    chomp $encend;
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>;
7855    close(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;
7868
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]);
7874
7875    my $enctime = "@enctime";
7876    chomp $enctime;
7877    if($encode == 1) {
7878       @enctime = split(/ /, $enctime);
7879       $enctime[0] = 0 unless(@enctime);
7880       $enctime = int($enctime[0]/60);
7881    }
7882    else {
7883       $enctime = 0;
7884    }
7885    return ($riptime,$enctime,$encend,$blanktrks,$ghostrks,$splitrks);
7886 }
7887 ########################################################################
7888 #
7889 # Thanks to mjb: log info to file.
7890 #
7891 sub log_info {
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";
7897    close(SYSLOG);
7898 }
7899 ########################################################################
7900 #
7901 # Thanks to mjb and Stefan Wartens improvements:
7902 # log_system used throughout in place of system() calls.
7903 #
7904 sub log_system {
7905    my $P_command = shift;
7906    if($verbose > 3) {
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>;
7916             close(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";
7922                close(ENCLOG);
7923             }
7924             else {
7925                print "system: $P_command\n\n";
7926             }
7927          }
7928       }
7929       else {
7930          print "system: $P_command\n\n";
7931       }
7932    }
7933
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/);
7937
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/) {
7942       my $pid = 0;
7943       # This is probably dangerous, very dangerous because of zombies...
7944       $SIG{CHLD} = 'IGNORE';
7945       unless($pid = fork) {
7946          exec($P_command);
7947          exit;
7948       }
7949       # ... but we check and wait for $pid to finish in subroutine.
7950       my $result = check_ripper($P_command, $pid);
7951       waitpid($pid, 0);
7952       $SIG{CHLD} = 'DEFAULT';
7953       return $result;
7954    }
7955    else {
7956       system($P_command);
7957    }
7958
7959    # system() returns several pieces of information about the launched
7960    # subprocess squeezed into a 16-bit integer:
7961    #
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
7968    #
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)
7972
7973    # Subprocess has been executed successfully.
7974    return 1 if $? == 0;
7975
7976    # Subprocess was killed by SIGINT (CTRL-C). Exit RipIT.
7977    die "\n\nRipit caught a SIGINT.\n" if(( $? & 127) == 2);
7978
7979    # Subprocess could not be executed or failed.
7980    return 0;
7981 }
7982 ########################################################################
7983 #
7984 # Special characters in cd.toc file won't be written correctly by
7985 # cdrdao, so change them to octal!
7986 #
7987 # Thanks to pancho horrillo:
7988 # http://perldoc.perl.org/perluniintro.html#Displaying-Unicode-As-Text
7989 #
7990 sub oct_char {
7991    $_[0] = join '',
7992                map { $_ > 191
7993                      ? sprintf '\%o', $_
7994                      : chr $_
7995                } unpack("C0U*", "$_[0]");
7996 }
7997 ########################################################################
7998 #
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.
8003 #
8004 sub cd_present {
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;
8010    }
8011    elsif($os =~ /BSD/i) {
8012       $CDROMREADTOCHDR = 0x40046304;
8013    }
8014    my $tochdr = "";
8015    my $err = ioctl(CD, $CDROMREADTOCHDR, $tochdr);
8016    close(CD);
8017    return $err;
8018 }
8019 ########################################################################
8020 #
8021 # A hack to reinitialize global variables before starting a new loop.
8022 #
8023 sub init_var {
8024    $categ            = "";
8025    $cddbid           = 0;
8026    @framelist        = ();
8027    @secondlist       = ();
8028    @tracklist        = ();
8029    @tracktags        = ();
8030    @seltrack         = ();
8031    @tracksel         = ();
8032    %cd               = ();
8033    $cddbsubmission   = 2;
8034    $hiddenflag       = 0;
8035    $wavdir           = "";
8036    @sepdir           = ();
8037 }
8038 ########################################################################
8039 #
8040 # Get the revision number of the CDDB entry.
8041 #
8042 sub get_rev {
8043    my @revision = grep(/^\#\sRevision:\s/, @{$cd{raw}});
8044    my $revision = join('', grep(s/^\#\sRevision:\s//, @revision));
8045    chomp $revision if($revision);
8046    return $revision;
8047 }
8048 ########################################################################
8049 #
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"'
8052 #
8053 sub change_case {
8054 #   use encoding "utf8"; # This will break every single non ascii char!
8055    if($lowercase == 1 or $uppercasefirst == 1) {
8056       $_[0] = lc($_[0]);
8057       $_[0] =~ tr/[ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏ]/[Ć Ć”Ć¢Ć£Ć¤Ć„Ć¦Ć§ĆØĆ©ĆŖƫƬƭƮĆÆ]/;
8058       $_[0] =~ tr/[ƐƑƒƓƔƕƖƘƙƚƛƜƝƞ]/[Ć°Ć±Ć²Ć³Ć“ĆµĆ¶ĆøĆ¹ĆŗĆ»Ć¼Ć½Ć¾]/;
8059    }
8060    if($uppercasefirst == 1) {
8061       # s/(\w+)/\u\L$1/g; # Does not work with non ascii chars...
8062       my @words = split(/ /, $_[0]);
8063       foreach (@words) {
8064          s/(\w+)/\u\L$1/g; # Ensure ucfirst within brackets etc.
8065          $_ = "\u$_";
8066          $_ =~ tr/^[Ć Ć”Ć¢Ć£Ć¤Ć„Ć¦Ć§ĆØĆ©ĆŖƫƬƭƮĆÆ]/[ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏ]/;
8067          $_ =~ tr/^[Ć°Ć±Ć²Ć³Ć“ĆµĆ¶ĆøĆ¹ĆŗĆ»Ć¼Ć½Ć¾]/[ƐƑƒƓƔƕƖƘƙƚƛƜƝƞ]/;
8068       }
8069       $_[0] = join(' ', @words);
8070    }
8071    return $_[0];
8072 }
8073 ########################################################################
8074 #
8075 # Strip dodgey chars I. This will be done for file names and tags.
8076 #
8077 # TODO: Do we really have to erase all of them? Maybe we should keep
8078 # some for the tags...
8079 #
8080 sub clean_all {
8081    $_[0] =~ s/[;><"\015]//g;
8082    $_[0] =~ s/\`/\'/g;
8083    $_[0] =~ s/Ā“/\'/g;
8084    $_[0] =~ s/\s+/ /g;
8085    return $_[0];
8086 }
8087 ########################################################################
8088 #
8089 # Strip dodgey chars II. This will only be done for file names.
8090 #
8091 sub clean_name {
8092    $_[0] =~ s/[*]//g;
8093    $_[0] =~ s/\// - /g;
8094    $_[0] =~ s/\s+/ /g;
8095    return $_[0];
8096 }
8097 ########################################################################
8098 #
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!
8105 #
8106 sub clean_chars {
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;
8119    $_[0] =~ s/\s+/ /g;
8120    $_[0] =~ s/\s$//;
8121    return $_[0];
8122 }
8123 ########################################################################
8124 #
8125 # Put all chars in brackets and escape some.
8126 #
8127 sub check_chars {
8128    $chars =~ s/\\/\\\\/;
8129    $chars =~ s/-/\\-/;
8130    $chars =~ s/]/\\]/;
8131    $chars =~ s/\s/\\s/;
8132    $chars = "[" . $chars . "]" unless($chars =~ /HFS|NTFS|off/);
8133 }
8134 ########################################################################
8135 #
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
8141 # end of each line!
8142 #
8143 sub extract_comm {
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) {
8150       chomp $_;
8151       $_ =~ s/^\s+//g;
8152    }
8153    return (@comment);
8154 }
8155 ########################################################################
8156 #
8157 # Display a help page and exit.
8158 #
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.
8161 #
8162 sub print_help {
8163    print <<END
8164
8165 SYNOPSIS:
8166    ripit [options]
8167
8168 OPTIONS:
8169  [track_selection]
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.
8182               Default: not set.
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.
8193  -r, --ripper number
8194               0 dagrab, 1 cdparanoia, 2 cdda2wav, 3 tosha, 4 cdd,
8195               default: 1.
8196  --ripopt options
8197               Additional options for specific ripper. Default: not set.
8198  --nicerip value
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.
8211  --extend seconds
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.
8215  --prepend seconds
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.
8219  -c, --coder encoder
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
8222               each encoder.
8223               The same encoder may be stated more than once. Adapt
8224               --dirtemplate in this case, see below. Default: 0.
8225  --musenc name
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
8233               Same as above.
8234  --lameopt    Lame-options
8235               Same as above.
8236  --museopt    Musepack-options
8237               Same as above.
8238  --mp4alsopt  mp4als-options
8239               Same as above.
8240  --oggencopt  Oggenc-options
8241               Same as above.
8242  --wavpacopt  Wavpack-options
8243               Same as above.
8244  --ffmpegopt  ffmpeg-options
8245               Same as above.
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
8254               5,3,5,100,0,5.
8255  -v, --vbrmode mode
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.
8259  -b, --bitrate rate
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.
8263  -B, --maxrate rate
8264               maxrate (Bitrate) for Lame using --vbrmode is equal to the
8265               -B option for Lame or the -M option for Oggenc,
8266               default: 0.
8267  -S, --preset mode
8268               Use the preset switch when encoding with Lame. With option
8269               --vbrmode new --preset fast will be used. Default: off.
8270  -W, --chars [list]
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.
8275               Default: off.
8276  --comment comment
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.
8281  -g, --genre genre
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.
8285  -y, --year year
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.
8298 --coverart list
8299               Add coverart to the sound files. Comma separated list
8300               according to option coder with values 0 (no) or 1 (yes),
8301               default 0.
8302 --coverpath path
8303               Path to the coverart picture to be included in the
8304               metadata of the sound files, default: not set.
8305 --copycover path
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.
8309 --mp3tags FRAME=Tag
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.
8314 --vatag number
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.
8320 --vastring string
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.
8324               metflac.
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.
8330  --sshlist list
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,
8335               default: off.
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.
8339  --mbname login
8340               Give MB login name to submitt ISRCs to the database. Saved
8341               in plain when using a config, default not set.
8342  --mbpass password
8343               Give MB password to submitt ISRCs to the database. Saved
8344               in plain when using a config, default not set.
8345  --isrc number
8346               Enable ISRC detection and submission to MB (1 yes, 0 no);
8347               default: 0
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.
8351  -m, --mirror mirror
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
8357  -P, --proxy address
8358               The http proxy to use when accessing the cddb server.  The
8359               CDDB protocol must be http! Default: not set.
8360  -t, --transfer mode
8361               Transfer mode, cddb or http, will set default port to 8880
8362               or 80 (for http), default: cddb.
8363  -n, --nice value
8364               Set niceness of encoding process, default: not set.
8365  -a, --archive
8366               Read and save CDDB files in  \$HOME/.cddb/\"category\"
8367               directory. Default: off.
8368  -e, --eject  Ejects the CD when finished, default off.
8369  --ejectcmd cmd
8370               Command to use for ejecting CD (see --eject), default:
8371               eject.
8372  --ejectopt options
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.
8377  -s, --submission
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.
8382  -M, --mail address
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.
8389  -i, --interaction
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.
8395  --infolog file
8396               Log operations (system calls,  file/directory creation) to
8397               file, given with full path; default: not set.
8398  -l, --lowercase
8399               Lowercase filenames, default: off.
8400  -u, --underscore
8401               Use underscores _ instead of spaces in filenames, default:
8402               off.
8403  --uppercasefirst
8404               Uppercase first characters of each word in filenames and
8405               tags, default: off.
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.
8408               Default: on.
8409  --encode     Prevent encoding (generate only wavs) with --noencode.
8410               Default: on.
8411  -w, --wav    Keep the wav files after encoding instead of deleting them
8412               default: off.
8413  -N, --normalize
8414               Normalizes the wav-files to a given dB-value (default:
8415               -12dB). Default: off.
8416  --normcmd    Command to use for normalizing, default: normalize.
8417  -z, --normopt
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.
8422  --cdtoc n
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.
8425  --cdcue n
8426               n=1: Create a cue file to burn the wavs with cd-text,
8427               default: 0 - off.
8428  --inf n
8429               n=1: Creat inf files for each track to burn the wavs with
8430               cd-text using wodim or cdrecord (in dao mode),
8431               default: 0 - off.
8432  -h, --help   Print this and exit.
8433  -V, --version
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
8438               (5). Default 3
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.
8446  -A, --book number
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
8451  --loop number
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.
8456  --quitnodb value
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.
8466               Default: not set.
8467  --threads number
8468               Comma separated list of numbers giving maximum of allowed
8469               encoders to run at the same time, default: 1.
8470  --execmd command
8471               State a command to be executed when ripit finshed. Make
8472               sure to escape the command if needed. Default: not set.
8473  --precmd command
8474               State a command to be executed when ripping starts. Make
8475               sure to escape the command if needed. Default: not set.
8476
8477
8478 SEE ALSO
8479        ripit(1), cdparanoia(1), lame(1), oggenc(1), flac(1),
8480        normalize(1), cdda2wav(1).
8481
8482 AUTHORS
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.
8488
8489 DATE
8490        14 July 2010
8491
8492 END
8493 }
8494 ########################################################################
8495 #
8496 # Display available options and exit!
8497 #
8498 # New options step 13: Add the new options to the short help/error msg.
8499 #
8500 sub print_usage {
8501    print <<END
8502
8503 Usage:
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]
8540
8541
8542 For general usage information see the manpage or type:
8543        ripit --help | less
8544 or try to run
8545        ripit
8546 without any options.
8547
8548 END
8549 }
8550 ########################################################################
8551 #
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.
8556 #
8557 sub skip_tracks {
8558    my @merge = split(/,/, $pmerge);
8559    foreach (@merge) {
8560       # Split each interval into a BeginEndArray.
8561       my @bea = split(/-|\+/, $_);
8562       my $i = $bea[0] + 1;
8563       # Missing separator in command line argument?
8564       if($#bea > 1) {
8565          print "\nStrange interval in argument of option merge ($_)!",
8566                "\nIs there a comma missing?\n\n";
8567          exit;
8568       }
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]);
8575       }
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";
8581             exit;
8582          }
8583       }
8584       while($i <= $bea[$#bea]) {
8585          push(@skip, $i);
8586          $i++;
8587       }
8588    }
8589    return(@skip);
8590 }
8591 ########################################################################
8592 #
8593 # Read the header of the wav file yet still called $trn.rip.
8594 #
8595 sub get_wavhead {
8596    my $trn = shift;
8597    my $prn = shift;
8598    open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8599    binmode(IN);
8600    my $H = {};
8601    $H->{header_size} = 44;
8602    my $wavheader;
8603    print "Can not read full WAV header!\n"
8604       if($H->{header_size} != read(IN, $wavheader, $H->{header_size}));
8605    close(IN);
8606
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},
8612     $H->{data_size}
8613    ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
8614
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);
8619       print "\n";
8620    }
8621    return($wavheader, $H);
8622 }
8623 ########################################################################
8624 #
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.
8632 #
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.
8645 #
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!)
8654 #
8655 #
8656 # Testreport (CDs with correctly split ghost songs):
8657 #
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
8690 #
8691 # Deleted blank tracks:
8692 #
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
8696 #
8697 #
8698 sub get_chunks {
8699    my ($tcn, $trn) = @_;
8700    my @times = ();
8701    $trn = $trn . ".rip";
8702    my ($wavheader, $H) = get_wavhead("$trn", 0);
8703
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!
8733
8734    my $bindata;
8735    my $bytecn = 0;
8736    my $silencecn = 0;
8737    my $chunkcn = 0;
8738    my $chunksize = 0.1; # Chunk size in seconds.
8739    my $chunkbyte = $H->{byte_per_sec} * $chunksize;
8740    my $chunklen = 0;
8741    my $leadinflag = 0;
8742    my $startsnd = 0;
8743    my $soundflag = 0;
8744    my $deltathre = $H->{byte_per_sec} * $chunksize;
8745    my $totalthre = 0;
8746    my $trimcn = 0;
8747    my $weight = 1;
8748    my $maxthresh = $deltathre * 8 * 0.7;
8749
8750    open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8751    binmode(IN);
8752    seek(IN, 44, 0);
8753    while(read(IN, $bindata, $chunkbyte)) {
8754       $chunkcn++;
8755       my $thresh = unpack('%32b*', $bindata);
8756       $totalthre += $thresh / 1000 if($thresh < $maxthresh * 1.1 );
8757       $weight++
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
8763       # not.
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
8777          # precise values.
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};
8785             # Otherwise:
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!
8790             if($chunklen < 4) {
8791                $chunklen = 0;
8792             }
8793             else {
8794                push(@times, "$startsnd $chunklen");
8795                # Prevent re-entering a duplicate last entry outside of
8796                # the loop.
8797                $startsnd = 0;
8798             }
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!
8802             $soundflag = 1;
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);
8807          }
8808          # We will stay in this condition, until...
8809       }
8810       else {
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) /
8817                             $H->{byte_per_sec};
8818             }
8819             elsif($startsnd == 0) {
8820                $startsnd = $bytecn / $H->{byte_per_sec};
8821             }
8822             $soundflag = 0;
8823          }
8824          $trimcn = 0;
8825          $silencecn = 0;
8826       }
8827       $bytecn += $chunkbyte;
8828    }
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);
8838
8839    my $tracklen = int(($framelist[$tcn] - $framelist[$tcn - 1]) / 7.5);
8840    $tracklen = int($framelist[$tcn] / 7.5) if($tcn == 0);
8841    $tracklen /= 10;
8842
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) {
8846       $chunkcn = 0;
8847       $totalthre = 0;
8848       open(IN, "< $wavdir/$trn") or print "Can't open $trn: $!\n";
8849       binmode(IN);
8850       seek(IN, 44, 0);
8851       while(read(IN, $bindata, 2)) {
8852          $chunkcn++;
8853          my $thresh = unpack('%32b*', $bindata);
8854          $thresh = 0 if($thresh >= 14);
8855          $totalthre += $thresh;
8856       }
8857       $totalthre = $totalthre * 4 / $chunkcn;
8858    }
8859
8860    if($totalthre < 200) {
8861       unlink("$wavdir/$trn") or print "Can't delete $trn: $!\n";
8862       if($verbose >= 1) {
8863          print "\n\nRipIT found blank track $trn\n",
8864                "and decided to delete it.\n\n";
8865       }
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";
8869       close(ERO);
8870       log_info("blank track deleted: $wavdir/$trn");
8871       $times[0] = "blank";
8872       return(@times);
8873    }
8874
8875    if($verbose >= 2) {
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)");
8882       foreach(@times) {
8883          my @interval = split(/ /, $_);
8884          printf("%5.1f %9.1f\n", $interval[0], $interval[1]);
8885          log_info("@interval");
8886       }
8887    }
8888    return(@times);
8889 }
8890 ########################################################################
8891 #
8892 # Split the wav into chunks of sound and rename all of them to
8893 # "Ghost Song $counter.wav".
8894 #
8895 sub split_chunks {
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);
8901    my $bindata;
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;
8905    my $chunkcn = 0;
8906    # Save the tracklength of the original track to be compared with the
8907    # chunks of sound.
8908    my $tracklen = int($H->{data_size} / $H->{byte_per_sec} * 10);
8909    $tracklen /= 10;
8910    # Let the other processes know, if the track has been shorten or not.
8911    my $shorten = 0;
8912
8913    my $times_cn = 0;
8914    foreach(@times) {
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;
8922       }
8923       else{
8924          $interval[1] += $interval[0];
8925          $interval[0] = 0;
8926       }
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
8930       # extend command.
8931       if($interval[0] + $interval[1] > $tracklen) {
8932          $interval[1] = $tracklen - $interval[0];
8933       }
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] ||
8937           $interval[1] < 3) {
8938          print "Track $tcn not splitted.\n\n" if($verbose >= 1);
8939          log_info("Track $tcn not splitted.");
8940
8941          # Merge track into album-track if $cdcue == 1.
8942          merge_wav($trn, $chunkbyte, $album) if($cdcue == 1);
8943          return($shorten, @times);
8944       }
8945
8946       # Update the times array.
8947       $times[$times_cn] = "$interval[0] $interval[1]";
8948       $times_cn++;
8949       # Modify the @times array.
8950       $_ = "$interval[0] $interval[1]";
8951
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.
8956       if($chunkcn == 0) {
8957          $secondlist[$tcn - 1] = int($interval[1]) if($hiddenflag == 0);
8958          $secondlist[$tcn] = int($interval[1]) if($hiddenflag == 1);
8959       }
8960       else {
8961          push(@secondlist, int($interval[1]));
8962       }
8963
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);
8969       }
8970       if($chunkcn == 0) {
8971          log_info("Splitting \"$trn\" into " . ($#times + 1) . " chunk.")
8972             if($#times == 0);
8973          log_info("Splitting \"$trn\" into " . ($#times + 1) . " chunks.")
8974             unless($#times == 0);
8975       }
8976       if($verbose >= 4) {
8977          print "\n\nUsing these values for chunk $chunkcn:\n";
8978          printf("%5.1f %5.1f\n", $interval[0], $interval[1]);
8979       }
8980       log_info("\nUsing these values for chunk $chunkcn:");
8981       log_info("@interval");
8982
8983       # Prepare the filename for output.
8984       my $outr = "Ghost Song $chunkcn";
8985       $outr = get_trackname($tcn, $outr) . ".rip";
8986
8987       if($cdcue == 1) {
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";
8995       }
8996       else {
8997          open(OUT, "> $wavdir/$outr");
8998       }
8999       binmode(OUT);
9000
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};
9004
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});
9010
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!
9017       my $loopcn = 0;
9018       # Initialization:
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},
9023        $H->{data_size}
9024       ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
9025
9026       while($loopcn < 10 and $H->{data_size} ne $interval[1]) {
9027          if($verbose >= 5) {
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);
9034             print "\n";
9035          }
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);
9042          log_info("\n");
9043
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;
9047
9048          substr($wavheader, 4, 4) = pack("V", $H->{file_size_8});
9049          substr($wavheader, 40, 4) = pack("V", $H->{data_size});
9050
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},
9055           $H->{data_size}
9056          ) = unpack("a4Va4a4VvvVVvva4V", $wavheader);
9057
9058          $loopcn++;
9059       }
9060
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");
9070             if($chunkcn == 0) {
9071                $secondlist[$tcn - 1] = $interval[1] if($hiddenflag == 0);
9072                $secondlist[$tcn] = $interval[1] if($hiddenflag == 1);
9073             }
9074             else {
9075                pop(@secondlist);
9076             }
9077          }
9078          else {
9079             print "\nTrying to continue anyway.\n";
9080             log_info("\nTrying to continue anyway.\n");
9081          }
9082       }
9083       return($shorten, @times) if($loopcn >= 9 && $wcoder =~ /2/);
9084
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);
9089       log_info("\n");
9090       if($verbose >= 5) {
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);
9094          print "\n";
9095       }
9096
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";
9100       binmode(IN);
9101       print "Seeking to: ${interval[0]}B, starting from 0B.\n"
9102          if($verbose >= 4);
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";
9106
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.
9121          my $pos = tell(IN);
9122          if($pos !~ /[02468]$/) {
9123             print "After chunkbyte = <$chunkbyte> reached pos <$pos>.\n"
9124                if($verbose >= 5);
9125             log_info("After chunkbyte = <$chunkbyte> reached pos <$pos>.\n");
9126             # Move one byte!
9127             read(IN, my $dummybyte, 1);
9128             $pos = tell(IN);
9129             print "After 1 byte read reached pos <$pos>.\n"
9130                if($verbose >= 5);
9131          }
9132          print OUT $bindata;
9133       }
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,
9137                "B large.");
9138       log_info("Remember, steps in the size of $chunkbyte B are used.");
9139       close(OUT);
9140       write_wavhead("$wavdir/$album.wav") if($cdcue == 1);
9141       $chunkcn++;
9142    }
9143    close(IN);
9144    open(ERO,">>$wavdir/error.log")
9145       or print "Can not append to file ",
9146                "\"$wavdir/error.log\"!\n";
9147    if($#times == 0) {
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";
9151       $shorten = 1;
9152    }
9153    else {
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";
9157       $shorten = 1;
9158    }
9159    close(ERO);
9160    return($shorten, @times);
9161 }
9162 ########################################################################
9163 #
9164 # Rename the chunks called "XY Ghost Song $chunkcn" to the appropriate
9165 # file name according to the track-template.
9166 #
9167 sub rename_chunks {
9168
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
9174    # songs.
9175
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.
9184
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!)
9188
9189    my ($tcn, $trn, $cdtocn, $cue_point, $shorten, $artistag, $trt, @times) = @_;
9190    my $chunkcn = 0;
9191    my $ghostflag = 0;
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");
9197
9198    # Writing the toc file in case $cdtoc == 1.
9199    if($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";
9212          close(CDTOC);
9213    }
9214    # Writing the cue file in case $cdcue == 1.
9215    if($cdcue > 0) {
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";
9225       close(CDCUE);
9226    }
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;
9231    if($shorten == 0) {
9232       $chunk_length = $framelist[$tcn] - $framelist[$tcn - 1] if($hiddenflag == 0);
9233       $chunk_length = $framelist[$tcn] - $framelist[$tcn] if($hiddenflag == 1);
9234    }
9235    $cue_point += $chunk_length;
9236
9237    # If only one chunk has been trimmed, we are done, array @times is
9238    # empty now.
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.
9248    my $gcn = $tcn;
9249    $ghostflag = 1 if($tcn == $#framelist);
9250    $ghostflag = 1 if($hiddenflag == 1 && $tcn == $#framelist - 1);
9251    $gcn++ if($ghostflag == 1);
9252    $chunkcn++;
9253    foreach (@times) {
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
9257       # a slash.
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.
9264          if($chunkcn == 1) {
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.
9276             if($cdtoc == 1) {
9277                open(CDTOC, "<$wavdir/cd.toc")
9278                   or print "Can not read file cd.toc!\n";
9279                my @toclines = <CDTOC>;
9280                close(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:/);
9285                   print CDTOC $_;
9286                }
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";
9298                close(CDTOC);
9299             }
9300             # The cdcue needs to be hacked too, because the track length
9301             # is different if the track has been splitted.
9302             if($cdcue > 0) {
9303                open(CDCUE, "<$wavdir/cd.cue")
9304                   or print "Can not read file cd.cue!\n";
9305                my @cuelines = <CDCUE>;
9306                close(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);
9310                my $track_flag = 0;
9311                foreach (@cuelines) {
9312                   if($track_flag == 1) {
9313                      print "   TITLE \"$prev_trt\"\n";
9314                      print CDCUE "   TITLE \"$prev_trt\"\n";
9315                      $track_flag = 0;
9316                   }
9317                   else {
9318                      print $_;
9319                      print CDCUE $_;
9320                   }
9321                   $track_flag = 1 if(/^TRACK\s$cuetrackno\sAUDIO/);
9322                }
9323                close(CDCUE);
9324             }
9325          }
9326       }
9327       else {
9328          # The name for the tags will be with originating track name as
9329          # prefix.
9330          $trt = $trt . " - Ghost Song" if($#times == 0);
9331          $trt = $trt . " - Ghost Song $chunkcn" if($#times > 0);
9332       }
9333       # The actual track name will be slightly different.
9334       $trn = $trt;
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) {
9350          $cdtocn++;
9351       }
9352       if($cdtoc == 1) {
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";
9365          close(CDTOC);
9366       }
9367       if($cdcue > 0) {
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";
9377          close(CDCUE);
9378       }
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"
9384          if($verbose > 5);
9385       $gcn++ if($ghostflag == 1);
9386       $chunkcn++;
9387    }
9388    print "\n\n" if($verbose >= 2);
9389    log_info("\n");
9390
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);
9399    close(GHOST);
9400    return($cdtocn, $cue_point);
9401 }
9402 ########################################################################
9403 #
9404 # Check if the necessary modules are available.
9405 #
9406 sub init_mod {
9407    print "\n" if($verbose >= 1);
9408
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
9413    # encoder.
9414    my $mp3art = 0;
9415    my $oggart = 0;
9416    my $wvpart = 0;
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);
9423       }
9424    }
9425
9426    eval { require CDDB_get };
9427    if($@) {
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";
9435       exit 0;
9436    }
9437    $@ = ();
9438    eval { require LWP::Simple };
9439    if($@) {
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";
9447       sleep 2;
9448    }
9449    $@ = ();
9450    eval { require Digest::MD5 } if($md5sum == 1);
9451    if($@) {
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";
9456       exit 0;
9457    }
9458    $@ = ();
9459    eval { require Unicode::UCD } if($utftag == 0);
9460    if($@) {
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";
9465       exit 0;
9466    }
9467    $@ = ();
9468    eval { require MP3::Tag } if($mp3art == 1 && $lameflag == 1);
9469    if($@) {
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";
9474       exit 0;
9475    }
9476    $@ = ();
9477    eval { require MIME::Base64 } if($oggart == 1 && $oggflag == 1);
9478    if($@) {
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";
9483       exit 0;
9484    }
9485
9486    eval { require WebService::MusicBrainz::Release } if($mb == 1);
9487    if($@) {
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";
9493       exit 0;
9494    }
9495
9496    eval { require MusicBrainz::DiscID } if($mb == 1);
9497    if($@) {
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";
9501 #      exit 0;
9502    }
9503
9504    if($wvpart == 1) {
9505       open(WAVPAK, "wavpack 2>&1|");
9506       my @response = <WAVPAK>;
9507       close(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);
9514       }
9515    }
9516
9517    if($multi == 1) {
9518       eval "use Color::Output";
9519       if($@) {print "\nColor::Output not installed!\n"};
9520       eval "Color::Output::Init";
9521    }
9522
9523    print "\n\n" if($verbose >= 1);
9524 }
9525 ########################################################################
9526 #
9527 # Check if lame is installed.
9528 #
9529 sub check_enc {
9530    my ($enc, $suf) = @_;
9531    unless(log_system("$enc --version > /dev/null 2>&1")) {
9532       $enc = "\u$enc";
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";
9536          my $ans = "x";
9537          while($ans !~ /^[yn]$/i) {
9538             print "Do you want to try oggenc? [y/n] (y) ";
9539             $ans = <STDIN>;
9540             chomp $ans;
9541             $ans = "y" if($ans eq "");
9542          }
9543          if($ans eq "y") {
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/);
9549             }
9550             else {
9551                $coders =~ s/0//g if($enc =~ /Lame/);
9552                $coders =~ s/3//g if($enc =~ /Faac/);
9553             }
9554             if($pcoders !~ /1/) {
9555                $pcoders =~ s/0/1/g if($enc =~ /Lame/);
9556                $pcoders =~ s/3/1/g if($enc =~ /Faac/);;
9557             }
9558             else {
9559                $pcoders =~ s/0//g if($enc =~ /Lame/);
9560                $pcoders =~ s/3//g if($enc =~ /Faac/);
9561             }
9562             $lameflag = -1;
9563             @coder = split(/ /, $coders);
9564             @pcoder = split(/ /, $pcoders);
9565          }
9566          else {
9567             print "\n",
9568                   "Install $enc or choose another encoder with option",
9569                   "\n",
9570                   "-c 1 for oggenc, -c 2 for flac, -c 3 for faac,",
9571                   "\n",
9572                   "-c 4 for mp4als, -c 5 for Musepack,",
9573                   "\n",
9574                   "-c 6 for Wavpack or -c 7 for ffmpeg.",
9575                   "\n\n",
9576                   "Type ripit --help or check the manpage for info.",
9577                   "\n\n";
9578             exit;
9579          }
9580       }
9581       else {
9582          $lameflag = -1;
9583       }
9584    }
9585 }
9586 ########################################################################
9587 #
9588 # Create MD5sum file of sound files.
9589 #
9590 sub md5_sum {
9591    my $sepdir = shift;
9592    my $filename = shift;
9593    my $ripcomplete = shift;
9594    my $suffix = $filename;
9595    $suffix =~ s/^.*\.//;
9596    chomp($filename);
9597    chomp($suffix);
9598
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);
9603
9604    return unless(-r "$sepdir/$filename");
9605
9606    open(SND, "< $sepdir/$filename") or
9607       print "Can not open $sepdir/$filename: $!\n";
9608    binmode(SND);
9609    if($verbose >= 4) {
9610       if(-r "$wavdir/enc.log" && $ripcomplete == 0) {
9611          open(ENCLOG, ">>$wavdir/enc.log");
9612          print ENCLOG "\n\nCalculating MD5-sum for $filename...";
9613          close(ENCLOG);
9614       }
9615       else {
9616          print "\nCalculating MD5-sum for $filename...";
9617       }
9618    }
9619    my $md5 = Digest::MD5->new->addfile(*SND)->hexdigest;
9620    close(SND);
9621    if($verbose >= 4) {
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";
9625          close(ENCLOG);
9626       }
9627       else {
9628          print "\nThe MD5-sum for $filename is: $md5.\n";
9629       }
9630    }
9631    open(MD5SUM,">>$sepdir/$md5file")
9632       or print "Can not append to file \"$sepdir/$md5file\"!\n";
9633    print MD5SUM "$md5 *$filename\n";
9634    close(MD5SUM);
9635 }
9636 ########################################################################
9637 #
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
9643 # @globopt.
9644 #
9645 sub check_options {
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) {
9664          if($preset) {
9665             $lameopt[0] .= " --preset $preset";
9666          }
9667          else {
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);
9675          }
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/;
9680          }
9681          $lameopt[0] =~ s/^\s*//;
9682          push(@globopt, $lameopt[0]);
9683          shift(@lameopt);
9684       }
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]);
9690          shift(@oggencopt);
9691       }
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]);
9696          shift(@flacopt);
9697       }
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]);
9702          shift(@faacopt);
9703       }
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]);
9708          shift(@mp4alsopt);
9709       }
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]);
9714          shift(@museopt);
9715       }
9716       elsif($coder[$c] == 6) {
9717          push(@globopt, $wavpacopt[0]);
9718          shift(@wavpacopt);
9719       }
9720       elsif($coder[$c] == 7) {
9721          push(@globopt, $ffmpegopt[0]);
9722          shift(@ffmpegopt);
9723       }
9724    }
9725 }
9726 ########################################################################
9727 #
9728 # Check ripper (cdparanoia) and calculate a timeout according to track
9729 # length.
9730 #
9731 sub check_ripper {
9732    my $P_command = shift;
9733    my $pid = 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));
9746    my $cn = 0;
9747    while(kill 0, $pid) {
9748       if($cn > $tlength) {
9749          unless(kill 9, $pid) {
9750             warn "\nProcess $pid already finished!\n";
9751          }
9752          return 0;
9753       }
9754       sleep 3;
9755       $cn += 3;
9756    }
9757    return 1;
9758 }
9759 ########################################################################
9760 #
9761 # Check distribution.
9762 #
9763 sub check_distro {
9764    $distro = "debian" if(-f "/etc/debian_version");
9765 }
9766 ########################################################################
9767 #
9768 # Get discid and number of tracks of inserted disc.
9769 #
9770 sub get_cddbid {
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);
9777 }
9778 ########################################################################
9779 #
9780 # Analyze string build from CDDB data for latin and wide chars.
9781 #
9782 sub check_encoding {
9783    my $char_string = shift;
9784    my $utf_string = $char_string;
9785    my $latinflag = 0;
9786    my $wideflag = 0;
9787    my $utf_latinflag = 0;
9788    my $utf_wideflag = 0;
9789
9790    if($cd{discid}) {
9791       # We do nothing for the moment.
9792       # $char_string = decode("iso-8859-15", $char_string);
9793    }
9794    else {
9795       $utf_string = Encode::decode('UTF-8', $utf_string, Encode::FB_QUIET);
9796    }
9797
9798    my @char_points = ();
9799    my @utf_points = ();
9800
9801    # Prevent warning:
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");
9806    }
9807    # @utf_points = unpack("C0U*", "$datb"); # Perl 5.8
9808    @utf_points = unpack("U0U*", "$utf_string"); # Perl 5.10
9809
9810
9811    foreach (@char_points) {
9812 #      print "$_ " if($verbose >= 5);
9813       $latinflag++ if($_ > 128 && $_ < 256);
9814       $wideflag++ if($_ > 255);
9815    }
9816
9817    foreach (@utf_points) {
9818 #      print "$_ " if($verbose >= 5);
9819       $utf_latinflag++ if($_ > 128 && $_ < 256);
9820       $utf_wideflag++ if($_ > 255);
9821    }
9822
9823    return($latinflag, $wideflag, $utf_latinflag, $utf_wideflag);
9824 }
9825 ########################################################################
9826 #
9827 # Transform length of span in seconds. Argument has hh:mm:ss.ff format.
9828 #
9829 sub span_length {
9830    my $time = shift;
9831    my @time = split(/:/, $time);
9832    my $factor = 60;
9833    $time = pop(@time);
9834    # Cut off frames (sectors).
9835    my $frames = 0;
9836    ($time, $frames) = split(/\./, $time) if($time =~ /\./);
9837    # Round the value of frames.
9838    $time++ if($frames > 37);
9839    while ($time[0]) {
9840       $time += pop(@time) * $factor;
9841       $factor += 60;
9842    }
9843    return($time);
9844 }
9845 ########################################################################
9846 #
9847 # Transform length of span from frames to hh:mm:ss.ff format.
9848 # Thanks to perlmonks.
9849 #
9850 sub chapter_length {
9851    my $f = shift;
9852
9853    my $s = int($f / 75);
9854
9855    return sprintf("%s%02d", "00:00:", $s) if($s < 60);
9856
9857    my $m = $s / 60;
9858    $s = $s % 60;
9859    return sprintf("%s%02d:%02d", "00:", $m, $s) if($m < 60);
9860
9861    my $h = $m / 60;
9862    $m %= 60;
9863    return sprintf("%02d:%02d:%02d", $h, $m, $s) if($h < 24);
9864
9865    my $d = $h / 24;
9866    $h %= 24;
9867    return sprintf("%d:%02d:%02d:%02d", $d, $h, $m, $s);
9868 }
9869 ########################################################################
9870 #
9871 # Finish process.
9872 #
9873 sub finish_process {
9874
9875    if($sshflag == 1) {
9876       del_wav();
9877    }
9878    else {
9879       wait;
9880    }
9881
9882    if($playlist >= 1 && $encode == 1) {
9883       create_m3u();
9884    }
9885
9886    my ($riptime, $enctime, $encend, $blanktrks, $ghostrks, $splitrks)
9887       = cal_times();
9888    del_erlog();
9889
9890    if(-r "$wavdir/error.log" && $blanktrks eq "") {
9891       if($verbose >= 1) {
9892          print "\nCD may NOT be complete! Check the error.log \n",
9893                "in $wavdir!\n";
9894       }
9895       elsif($verbose >= 3) {
9896          print "\nRipping needed $riptime min and encoding needed ",
9897                "$enctime min.\n\n";
9898       }
9899    }
9900    else {
9901       if($verbose >= 1) {
9902          if($ghost == 1) {
9903             if($blanktrks) {
9904                print "\nCD may NOT be complete! Check the error.log \n",
9905                     "in $wavdir!\n";
9906                print "Blank track deleted: $blanktrks!\n"
9907                    if($blanktrks !~ /and/);
9908                print "Blank tracks deleted: $blanktrks!\n"
9909                    if($blanktrks =~ /and/);
9910             }
9911             else {
9912                printf "\n%02d:%02d:%02d: ",
9913                   sub {$_[2], $_[1], $_[0]}->(localtime);
9914                print "All complete!\n";
9915             }
9916             if($ghostrks) {
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/);
9921             }
9922             else {
9923                print "No ghost songs found!\n";
9924             }
9925             if($splitrks) {
9926                print "Track $splitrks trimmed!\n"
9927                   if($splitrks !~ /and/);
9928                print "Tracks $splitrks trimmed!\n"
9929                   if($splitrks =~ /and/);
9930             }
9931             else {
9932               print "No tracks trimmed!\n" unless($splitrks);
9933             }
9934          }
9935          else {
9936             print "\nAll complete!\n";
9937          }
9938          print "Ripping needed $riptime min and ";
9939          print "encoding needed $enctime min.\n\n";
9940       }
9941    }
9942
9943    log_info("\nRipping needed $riptime minutes.");
9944    log_info("Encoding needed $enctime minutes.");
9945
9946    if($lcd == 1) {                 # lcdproc
9947       $lcdline1 = " ";
9948       $lcdline2 = "   RipIT finished   ";
9949       $lcdline3 = " ";
9950       ulcd();
9951       close($lcdproc) or print "close: $!";
9952    }
9953
9954    if($multi == 1) {
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);
9966       close(SRXY);
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";
9973       close(SUCC);
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);
9985    }
9986
9987    if($execmd) {
9988       $execmd =~ s/\$/\\\$/g;
9989       print "Will execute command \"$execmd\".\n" if($verbose >= 3);
9990       log_system("$execmd");
9991    }
9992
9993    if($halt == 1 && $verbose >= 1) {
9994       print "\nShutdown...\n";
9995       log_system("shutdown -h now");
9996    }
9997
9998    log_info("*" x 72, "\n");
9999    print "\n";
10000    print "Please insert a new CD!\n\n" if($loop == 2);
10001    return;
10002 }
10003 ########################################################################
10004 #
10005 # Write inf files for each track.
10006 #
10007 sub write_inf {
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;
10016
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));
10022
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";
10033       }
10034       else {
10035          print INF "Albumperformer=\t'$artistag'\n";
10036       }
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";
10053       close(INF);
10054       $nofghosts--;
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);
10060          $riptrackno++;
10061       }
10062    }
10063    return($trackstart);
10064 }
10065 ########################################################################
10066 #
10067 # Write coverart to mp3 files.
10068 #
10069 sub mp3_cover {
10070    my($snd_file, $coverpath) = @_;
10071    my $mp3 = MP3::Tag->new($snd_file);
10072    $mp3->get_tags;
10073    my $id3v2 = exists $mp3->{'ID3v2'}
10074          ? $mp3->{'ID3v2'}
10075          : $mp3->new_tag('ID3v2');
10076    my $type = $coverpath;
10077    $type =~ s/.*\.(gif|jpg|jpeg|png)$/$1/;
10078    $type =~ s/jpeg/jpg/;
10079
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";
10085    binmode(PIC);
10086    my $data = do { local($/); <PIC> };
10087    $id3v2->add_frame('APIC', "image/$type", 3, 'Cover Image', $data);
10088    $id3v2->write_tag;
10089    close(PIC);
10090    $mp3->close;
10091    return;
10092 }
10093 ########################################################################
10094 #
10095 # Write special tags to mp3 files.
10096 #
10097 sub mp3_tags {
10098    my($snd_file) = shift;
10099    my $mp3 = MP3::Tag->new($snd_file);
10100    $mp3->get_tags;
10101    my $id3v2 = exists $mp3->{'ID3v2'}
10102          ? $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.");
10108    }
10109    $id3v2->write_tag;
10110    $mp3->close;
10111    return;
10112 }
10113 ########################################################################
10114 #
10115 # Write coverart to ogg files.
10116 #
10117 sub ogg_cover {
10118    use MIME::Base64 qw(encode_base64);
10119    my($snd_file, $coverpath) = @_;
10120    my $type = $coverpath;
10121    $type =~ s/.*\.(gif|jpg|png)$/$1/;
10122
10123    open(PIC, "$coverpath")
10124       or print "Cannot open file $coverpath: $!\n\n";
10125    my $data = do { local($/); encode_base64(<PIC>, '') };
10126    close(PIC);
10127
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");
10132    return;
10133 }
10134 ########################################################################
10135 #
10136 # Write the CDDB entry to ~/.cddb/category if there is not already
10137 # an entry present.
10138 #
10139 sub write_cddb {
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}}) {
10148            print TOC $_;
10149        }
10150     }
10151     close TOC;
10152     $archive = 0;
10153 }
10154 ########################################################################
10155 #
10156 # Merge the wav files if $cdcue == 1.
10157 #
10158 sub merge_wav {
10159    my ($trn, $chunkbyte, $album) = @_;
10160    open(IN, "< $wavdir/$trn.rip") or
10161    print "Can't open $trn.rip: $!\n";
10162    binmode(IN);
10163    # Only skip the header in case the base file already exists.
10164    if(-r "$wavdir/$album.wav") {
10165       seek(IN, 44, 0) or
10166          print "\nCould not seek beyond header in file IN: $!\n";
10167    }
10168    open(OUT, ">> $wavdir/$album.wav");
10169    binmode(OUT);
10170
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;
10175    }
10176    close(IN);
10177    close(OUT);
10178
10179    # Rewrite the header of the merged file $album.wav.
10180    write_wavhead("$wavdir/$album.wav");
10181
10182    return;
10183 }
10184 ########################################################################
10185 #
10186 # Rewrite the wav header.
10187 #
10188 sub write_wavhead {
10189    my $file = shift;
10190    if(!sysopen(WAV, $file, O_RDWR | O_CREAT, 0755)) {
10191       print "\nCan not to open $file: $!\n";
10192       return;
10193    }
10194    my $buffer;
10195    my $nread = sysread(WAV, $buffer, 44);
10196    if($nread != 44 || length($buffer) != 44) {
10197       print "\nWAV-header length problem in file $file.\n";
10198       close(WAV);
10199       return;
10200    }
10201
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);
10206    if($verbose > 5) {
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";
10212    }
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));
10221    close(WAV);
10222    return;
10223 }
10224 ########################################################################
10225 #
10226 # Check all tracks for VA-style.
10227 #
10228 sub check_va {
10229    my $prt_msg = shift;
10230    my $delim = "";
10231    my $delim_colon = 0;
10232    my $delim_hyphen = 0;
10233    my $delim_slash = 0;
10234    my $delim_parenthesis = 0;
10235    my $n = 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) {
10240       my $tn = $_ - 1;
10241       $delim_colon++ if($tracktags[$tn] =~ /:/);
10242       $delim_hyphen++ if($tracktags[$tn] =~ /-/);
10243       $delim_slash++ if($tracktags[$tn] =~ /\//);
10244       $delim_parenthesis++ if($tracktags[$tn] =~ /\(.*\)/);
10245       $n++;
10246    }
10247
10248    my $artist = clean_all($cd{artist});
10249
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)) {
10253       $va_flag = 1;
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);
10257    }
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)) {
10261       $va_flag = 1;
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);
10265    }
10266    elsif($vatag >= 5 and
10267      ($delim_colon == $n or $delim_hyphen == $n or
10268       $delim_slash == $n or $delim_parenthesis == $n)) {
10269       $va_flag = 1;
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);
10273    }
10274    elsif($vatag >= 7 and
10275      ($delim_colon > 0 or $delim_hyphen > 0 or $delim_slash > 0 or
10276       $delim_parenthesis > 0)) {
10277       $va_flag = 1;
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);
10281    }
10282    else {
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);
10287    }
10288    print "\n" if($verbose > 2 and $prt_msg == 1);
10289    return($delim) if($va_flag == 0);
10290
10291    if($va_flag == 2) {
10292       $va_flag = 1;
10293       $delim = "/";
10294    }
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) {
10299       $delim = "/";
10300    }
10301    elsif($delim_colon >= $delim_hyphen and
10302       $delim_colon >= $delim_parenthesis and
10303       $delim_colon >= $delim_slash) {
10304       $delim = ":";
10305    }
10306    elsif($delim_hyphen >= $delim_colon and
10307          $delim_hyphen >= $delim_slash and
10308          $delim_hyphen >= $delim_parenthesis) {
10309       $delim = "-";
10310    }
10311    elsif($delim_parenthesis >= $delim_colon and
10312          $delim_parenthesis >= $delim_slash and
10313          $delim_parenthesis >= $delim_hyphen) {
10314       $delim = "(";
10315    }
10316    else {
10317       $delim = "/";
10318    }
10319    return($delim);
10320 }
10321 ########################################################################
10322 #
10323 # Copy image file from destination path to directories of encoded sound
10324 # files.
10325 #
10326 sub copy_cover {
10327    for(my $c=0; $c<=$#coder; $c++) {
10328       copy("$copycover", "$sepdir[$c]")
10329       or print "Copying file to $sepdir[$c] failed: $!\n";
10330    }
10331 }
10332 ########################################################################
10333 #
10334 # Check album cover in path variable copycover.
10335 #
10336 sub check_cover {
10337    my $ans;
10338    unless(-s $copycover) {
10339       while($copycover !~ /^[yn]$/i) {
10340          print "\nImage file $copycover is not a valid file. Continue? [y/n] (y) ";
10341          $ans = <STDIN>;
10342          chomp $ans;
10343          $ans = "y" if($ans eq "");
10344          last if($ans =~ /y/i);
10345          die "Aborting\n" if($ans =~ /n/i);
10346       }
10347    }
10348 }
10349 ########################################################################
10350 #
10351 # Read in ISRCs using Icedax and submit them if detected using code from
10352 # Nicholas Humfrey <njh@aelius.com>.
10353 #
10354 sub get_isrcs {
10355    print "\nReading ISRC..." if($verbose > 2);
10356    my $icedax = `which icedax`;
10357    chomp($icedax);
10358    if($mbname ne "" and $mbpass ne "" and $icedax ne "") {
10359       my $mcn = undef;
10360       @isrcs = ();
10361       open(ICEDAX, "icedax -D $scsi_cddev -g -H -J -Q -v trackid 2>&1 |")
10362       or print "\nFailed to run icedax command: $!\n";
10363       while(<ICEDAX>) {
10364          chomp;
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));
10367             $isrc =~ s/\W//g;
10368             $isrcs[$num] = $isrc;
10369          }
10370          elsif(/Media catalog number: (.+)/i) {
10371             $mcn = $1;
10372          }
10373       }
10374       close(ICEDAX);
10375
10376       my $diflag = 1; # Suppose all ISRCs found are different.
10377       # Now preparing ISRC data array to post to MB server.
10378       my @isrcdata = ();
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)
10386             if($verbose > 3);
10387             push(@isrcdata, "isrc=" . $trackid . '%20' . $isrcno);
10388          }
10389          # Test if subsequent (all) ISRCs are different.
10390          if($i > 0) {
10391             $isrcno = $i unless($isrcno);
10392             $diflag = 0 if($isrcs[$i-1] && $isrcno eq $isrcs[$i-1]);
10393          }
10394       }
10395       print "\n\n" if($verbose > 3);
10396
10397       # Check that we have something to submit
10398       if(scalar(@isrcdata) < 1) {
10399          print "\nNo valid ISRCs to submit." if($verbose > 2);
10400          sleep 1;
10401       }
10402       elsif($diflag == 0) {
10403          print "\nIdentical ISRCs for different tracks detected.",
10404                "\nNo submission in this case.\n" if($verbose > 2);
10405          sleep 1;
10406       }
10407       else {
10408          # Send to Musicbrainz.
10409          if($mbname ne "" and $mbpass ne "") {
10410             my $ua = LWP::UserAgent->new;
10411             $ua->timeout(10);
10412             $ua->env_proxy;
10413             $ua->credentials( 'musicbrainz.org:80', 'musicbrainz.org', "$mbname", "$mbpass" );
10414
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');
10418
10419             my $response = $ua->request($request);
10420             print "\nISRC submission to MB " . $response->status_line. "\n" if($verbose > 2);
10421          }
10422          else {
10423             print "\nNo ISRC submission to MB.\n" if($verbose > 2);
10424          }
10425       }
10426    }
10427    return;
10428 }