]> diplodocus.org Git - flac-archive/blob - fa-rip
Need the g (global) flag on that substitution operation.
[flac-archive] / fa-rip
1 #! /usr/bin/env perl
2
3 # $Id$
4 # $URL$
5
6 =head1 NAME
7
8 B<fa-rip> - rip a CD for B<fa-flacd>
9
10 =head1 SYNOPSIS
11
12 B<fa-rip> [B<-d> I<device>] [B<-t> I<track-count>]
13
14 =cut
15
16 use strict;
17 use warnings;
18
19 use Env qw(
20 CDDEV
21 );
22
23 use File::Temp;
24 use Getopt::Long qw(:config gnu_getopt no_ignore_case);
25 use POSIX ':sys_wait_h';
26 use Pod::Usage;
27
28 use MusicBrainz::Client::Simple;
29
30 sub run_or_die {
31 my $command = shift;
32 my $status;
33
34 $status = system($command);
35
36 if (WIFEXITED($status)) {
37 if (($status = WEXITSTATUS($status)) != 0) {
38 die("$command exited with status $status");
39 }
40 } elsif (WIFSIGNALED($status)) {
41 die("$command killed with signal ", WTERMSIG($status));
42 } elsif (WIFSTOPPED($status)) {
43 die("$command stopped with signal ", WSTOPSIG($status));
44 } else {
45 die("Major horkage on system($command): \$? = $? \$! = $!");
46 }
47 }
48
49 sub mkcue {
50 my $device = shift;
51 my $trackcount = shift;
52 my @command;
53
54 push(@command, 'mkcue');
55
56 if (defined($trackcount)) {
57 push(@command, "-t $trackcount");
58 }
59
60 if (defined($device)) {
61 push(@command, $device);
62 }
63
64 push(@command, '> cue');
65 run_or_die(join(' ', @command));
66
67 if (not defined($trackcount)) {
68 open(F, 'cue') or die("open(cue): $!");
69 $trackcount = grep(/TRACK.*AUDIO/, <F>);
70 close(F);
71 }
72
73 return $trackcount;
74 }
75
76 sub tags {
77 my $device = shift;
78 my $trackcount = shift;
79 my $mb;
80 my @results;
81 my $album;
82 my $i;
83 my @tracks;
84 my $name;
85 my $track;
86 my $j;
87
88 if (defined($device)) {
89 $mb = new MusicBrainz::Client::Simple (device=>$device);
90 } else {
91 $mb = new MusicBrainz::Client::Simple;
92 }
93
94 @results = $mb->lookup_cd;
95 if (not $mb->success) {
96 die($mb->get_error);
97 }
98
99 open(F, '>candidate-tags-0') or die("open('>candidate-tags-0'): $!");
100 print(F "$_=\n") for ('ARTIST', 'ALBUM', 'DATE');
101 print(F "TITLE=\n") for 1 .. $trackcount;
102 close(F) or die("close('>candidate-tags-0'): $!");
103
104 for $album (@results) {
105 $i++;
106 open(F, ">candidate-tags-$i") or die("open(>candidate-tags-$i): $!");
107
108 print(F 'ARTIST=', $album->get_artist->get_name, "\n");
109 print(F 'ALBUM=', $album->get_name, "\n");
110
111 # MusicBrainz doesn't have dates yet; these are usually wrong anyway.
112 print(F "DATE=\n");
113
114 @tracks = $album->get_tracks;
115 for $j (1 .. $trackcount) {
116 if ($track = shift(@tracks)) {
117 $name = $track->get_name;
118 } else {
119 $name = '';
120 }
121 print(F "TITLE=$name\n");
122 }
123
124 close(F) or die("close(>candidate-tags-$i): $!");
125 }
126 }
127
128 sub rip {
129 my $device = shift;
130 my $trackcount = shift;
131
132 $device ||= '/dev/cdrom';
133
134 exec('cdparanoia', '-d', $device, "1-$trackcount", 'wav');
135 # exec prints its own error message so just
136 die;
137 }
138
139 MAIN: {
140 my $trackcount;
141 my $help;
142 my $tempdir;
143
144 GetOptions(
145 'device|d=s' => \$CDDEV,
146 'tracks|t=i' => \$trackcount,
147 'help|h|?' => \$help,
148 ) or pod2usage();
149 $help and pod2usage(-exitstatus=>0, -verbose=>1);
150
151 # File::Temp::tempdir calls die on error.
152 $tempdir = File::Temp::tempdir('flac-archive.XXXXXXXXXX');
153 chdir($tempdir) or die("chdir($tempdir): $!");
154
155 $trackcount = mkcue($CDDEV, $trackcount);
156 tags($CDDEV, $trackcount);
157 rip($CDDEV, $trackcount);
158 }
159
160 \f
161 __END__
162
163 =head1 DESCRIPTION
164
165 B<fa-rip> creates a temporary directory for storage of its
166 intermediate files, runs C<mkcue(1)> to create the "cue" file, uses
167 MusicBrainz to generate candidate tags files, and runs
168 C<cdparanoia(1)> to rip the CD to the "wav" file.
169
170 In order for this CD to be processed by B<fa-flacd>, you must create a
171 "tags" file. This is usually done by renaming one of the
172 candidate-tags files and deleting the others. Don't forget to fill in
173 the DATE tag in the selected candidate before renaming it. If
174 B<fa-rip> could not find any tag information from MusicBrainz, you'll
175 have to fill out the candidate-tags-0 template.
176
177 =head1 OPTIONS
178
179 =over 4
180
181 =item B<-d> [B<--device>] I<device>
182
183 Use I<device> as the CD-ROM device, instead of the default
184 "/dev/cdrom" or the environment variable CDDEV.
185
186 =item B<-t> [B<--tracks>] I<track-count>
187
188 Archive only the first I<track-count> tracks. This is handy for
189 ignoring data tracks.
190
191 =back
192
193 =head1 ENVIRONMENT
194
195 =over 4
196
197 =item CDDEV
198
199 B<fa-rip> uses this to rip audio and save the cuesheet for a CD. It
200 makes some effort to check some common device names for FreeBSD,
201 Linux, and NetBSD by default.
202
203 =back
204
205 =head1 AUTHORS
206
207 Written by Eric Gillespie <epg@pretzelnet.org>.
208
209 flac-archive is free software; you may redistribute it and/or modify
210 it under the same terms as Perl itself.
211
212 =cut
213
214 # Local variables:
215 # cperl-indent-level: 4
216 # perl-indent-level: 4
217 # indent-tabs-mode: nil
218 # End:
219
220 # vi: set tabstop=4 expandtab: