X-Git-Url: https://diplodocus.org/git/flac-archive/blobdiff_plain/890a5921fe12b21fbc65d88a0e59080dc8cc9a5b..d5d85722f4fb0fc6ca61102b397aa51a96bddcc6:/fa-flacd diff --git a/fa-flacd b/fa-flacd index 72c8923..3e9e7cb 100755 --- a/fa-flacd +++ b/fa-flacd @@ -1,18 +1,15 @@ #! /usr/bin/env perl # $Id$ +# $URL$ =head1 NAME -B, B, B - archive CDs to single FLAC files +B - archive CDs to single FLAC files =head1 SYNOPSIS -B [B<-jv>] - -B - -B ID TRACKCOUNT OFFSET [OFFSET ...] LENGTH +B [B<-j> I] [B<-v>] =cut @@ -20,17 +17,16 @@ use strict; use warnings; use File::Basename; -use Getopt::Std; $Getopt::Std::STANDARD_HELP_VERSION = 1; +use Getopt::Long qw(:config gnu_getopt no_ignore_case); use POSIX ':sys_wait_h'; - -our $VERSION = 1; +use Pod::Usage; my $verbose; my @jobs; my @finished; sub verbose { - $verbose and map({ print(STDERR $_) } @_); + $verbose and print(STDERR $_) for @_; } # Return the ARTIST, ALBUM, and DATE followed by a list of all the @@ -41,7 +37,6 @@ sub get_tags { my $value; my $artist; my $album; - my $date; my @tags; verbose("Opening tags file $fn\n"); @@ -58,14 +53,11 @@ sub get_tags { } elsif (/^ALBUM=/) { $album = $value; verbose("ALBUM $album from $fn\n"); - } elsif (/^DATE=/) { - $date = $value; - verbose("DATE $date from $fn\n"); } } - close(TAGS); + close(TAGS) or die("close($fn): $!"); - return ($artist, $album, $date, @tags); + return ($artist, $album, @tags); } # Process the fa-rip output in the directory DIR. @@ -73,15 +65,15 @@ sub flac { my $dir = shift; my $artist; my $album; - my $date; my @tags; + my $outfile; my $status; verbose("Renaming $dir/tags\n"); rename("$dir/tags", "$dir/using-tags") or die("rename($dir/tags, $dir/using-tags): $!"); - ($artist, $album, $date, @tags) = get_tags("$dir/using-tags"); + ($artist, $album, @tags) = get_tags("$dir/using-tags"); verbose("mkdir($artist)\n"); -d $artist or mkdir($artist) or die("mkdir($artist): $!"); @@ -89,38 +81,45 @@ sub flac { verbose("chdir($dir)\n"); chdir($dir) or die("chdir($dir): $!"); + $outfile = "$album"; + $outfile =~ s/\//_/g; + verbose("Running flac\n"); - $status = system('flac', '-o', "../$artist/$album.flac-tmp", + $status = system('flac', '-o', "../$artist/$outfile.flac-tmp", '--delete-input-file', '-V', '--cuesheet', 'cue', '--no-padding', '--best', map({ ('-T', $_) } @tags), 'wav'); - if (WIFEXITED($status) and ($status = WEXITSTATUS($status)) != 0) { - die("flac: $status"); + if (WIFEXITED($status)) { + if (($status = WEXITSTATUS($status)) != 0) { + die("flac exited with status $status"); + } } elsif (WIFSIGNALED($status)) { die("flac killed with signal ", WTERMSIG($status)); } elsif (WIFSTOPPED($status)) { die("flac stopped with signal ", WSTOPSIG($status)); + } else { + die("Major horkage on system(flac): \$? = $? \$! = $!"); } verbose("Cleaning up $dir\n"); unlink('using-tags') or die("unlink(using-tags): $!"); unlink('cue') or die("unlink(cue): $!"); - rename('toc', "../$artist/$album.toc") - or die("rename(toc, ../$artist/$album.toc): $!"); - rename('log', "../$artist/$album.log") - or die("rename(log, ../$artist/$album.log): $!"); + rename('log', "../$artist/$outfile.log") + or die("rename(log, ../$artist/$outfile.log): $!"); chdir('..') or die("chdir(..): $!"); rmdir($dir) or die("rmdir($dir): $!"); - rename("$artist/$album.flac-tmp", "$artist/$album.flac") - or die("rename($artist/$album.flac-tmp, $artist/$album.flac): $!"); + rename("$artist/$outfile.flac-tmp", "$artist/$outfile.flac") + or die("rename($artist/$outfile.flac-tmp, $artist/$outfile.flac): $!"); + + return 0; } sub reaper { my $pid; - while (($pid = waitpid(0, WNOHANG)) > 0) { + while (($pid = waitpid(-1, WNOHANG)) > 0) { push(@finished, [$pid, $?]); } @@ -132,13 +131,12 @@ sub newjob { my $pid; $pid = fork(); - if ($pid == -1) { + if (not defined($pid)) { die("fork: $!"); } elsif ($pid == 0) { $SIG{CHLD} = 'IGNORE'; open(STDERR, ">$dir/log") or die("open(STDERR, >$dir/log): $!"); - flac($dir); - exit(0); + exit(flac($dir)); } verbose("new job $pid for $dir\n"); @@ -152,15 +150,15 @@ sub deljob { my $status; $pid = $finished[$i][0]; - $status = WEXITSTATUS($finished[$i][1]); + $status = $finished[$i][1]; verbose("$pid finished ("); if (WIFEXITED($status)) { - verbose('exited ', WEXITSTATUS($status)); + verbose('exited with status ', WEXITSTATUS($status)); } elsif (WIFSIGNALED($status)) { - verbose('signalled ', WTERMSIG($status)); + verbose('killed with signal ', WTERMSIG($status)); } elsif (WIFSTOPPED($status)) { - verbose('stopped ', WSTOPSIG($status)); + verbose('stopped with signal ', WSTOPSIG($status)); } verbose(")\n"); @@ -195,18 +193,18 @@ sub flacloop { } MAIN: { - my %opts; - - $opts{'j'} = 4; - $opts{'v'} = 0; - if (not getopts('j:v', \%opts)) { - print("usage: flacd [-jN -v]\n"); - exit(2); - } - - $verbose = $opts{'v'}; - - flacloop($opts{'j'}); + my $jobs; + my $help; + + $jobs = 4; + GetOptions( + 'jobs|j=i' => \$jobs, + 'verbose|v' => \$verbose, + 'help|h|?' => \$help, + ) or pod2usage(); + $help and pod2usage(-exitstatus=>0, -verbose=>1); + + flacloop($jobs); } @@ -214,29 +212,23 @@ __END__ =head1 DESCRIPTION -B, B, and B together comprise -B, a system for archiving audio CDs to single FLAC -files. B is the guts of the system. It runs in the -directory where the audio archives are stored, scanning for new CDs to -encode and rename; it never exits. B generates the inputs for -B: the ripped WAV file, Vorbis tags, and a cuesheet. -B is not meant to be run directly; B uses it to -generate the candidate Vorbis tags. - -All three programs expect to be run from the same directory. They use -that directory to manage directories named by artist and by disc ID. -Intermediate files are written to the disc ID directory. B -processes the disc ID directories into per-album files in the artist -directories. - -=head2 FA-FLACD - -B does not exit; it runs until the user kills it. Every 5 -seconds it scans its current directory for directories with a file -called "tags" and creates a processing job for each one. The number -of jobs B attempts to run is controlled by the B<-j> option -and defaults to 4. B will print diagnostic output when the -B<-v> option is given. +B and B together comprise B, a system +for archiving audio CDs to single FLAC files. B is the guts +of the system. It runs in the directory where the audio archives are +stored, scanning for new ripped CDs to encode and rename; it never +exits. B generates the inputs for B: the ripped WAV +file, Vorbis tags, and a cuesheet. + +Both programs expect to be run from the same directory. They use that +directory to manage directories named by artist. Intermediate files +are written to temporary directories here. B processes the +temporary directories into per-album files in the artist directories. + +Every 5 seconds, B scans its current directory for +directories with a file called "tags" and creates a processing job for +each one. The number of jobs B attempts to run is +controlled by the B<-j> option and defaults to 4. B will +print diagnostic output when the B<-v> option is given. A processing job first renames the directory's "tags" file to "using-tags" so that B will not try to start another job for @@ -245,65 +237,30 @@ so a new job will not be started until the user corrects the error condition and renames "using-tags" back to "tags". Next, it encodes the "wav" file to a FLAC file, using the "cue" file for the cuesheet and "using-tags" for Vorbis tags. Any diagnostic output is saved in -the "log" file. Finally, the "cue" and "log" files are moved to the -artist directory (and named by album) and the ID directory is removed. - -=head2 FA-RIP - -B uses L to retrieve the disc ID and track -information. It creates a directory named by ID for storage of its -intermediate files. It passes the L output as -command-line arguments to B in the background. It then uses -L to create the "cue" file in the background. Finally, it -execs > to rip the CD to the "wav" file. +the "log" file. Finally, B moves the "cue" and "log" files +to the artist directory (named by album) and removes the temporary +directory. -In order for this CD to be processed by B, the user must -create a "tags" file. This is usually done by renaming one of the -candidate-tags files and deleting the others. - -=head2 FA-TAGS - -B uses L (from the B package) to -populate candidate-tags files. These are numbered in the order of -entries read from CDDB, e.g. candidate-tags-1, candidate-tags-2, etc. -B also creates candidate-tags-0, which has the correct fields -for this CD (including correct number of TITLE= lines), but with all -fields blank. - -B expects the output of L as command-line -arguments. That is, the disc ID, number of tracks, list of track -offsets, and total length of the CD in seconds. - -=head1 ENVIRONMENT +=head1 OPTIONS =over 4 -=item CDDBURL +=item B<-j> [B<--jobs>] I -B uses this to retrieve candidate Vorbis tags. Defaults to -"http://freedb.freedb.org/~cddb/cddb.cgi". +Run up to I jobs instead of the default 4. -=item CDDEV +=item B<-v> [B<--verbose>] -B uses this to rip audio and save the cuesheet for a CD. It -makes some effort to check some common device names for FreeBSD, -Linux, and NetBSD by default. +Print diagnostic information. =back =head1 AUTHORS -Written by Eric Gillespie . B contains -code from B, which bears the following notice: - -# Copyright (c) 1998-2001 Robert Woodcock -# Copyright (c) 2003-2004 Jesus Climent -# This code is hereby licensed for public consumption under either the -# GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice. +Written by Eric Gillespie . -B is hereby licensed for public consumption under either -the GNU GPL v2 or greater, or Larry Wall's Artistic license - your -choice. +flac-archive is free software; you may redistribute it and/or modify +it under the same terms as Perl itself. =cut