CD ripping

Bennett Todd bet at
Fri Jul 9 11:44:35 PDT 2004

<> does indeed rock, and it's got to be the
fastest way for someone who's comfortable in perl and Unix, who
likes console/cmdline apps, but who knows nothing about audio
ripping to get going. It handily embeds a wealth of trivia about how
to invoke cdparanoia/cdda2wav and lame/oggenc/gogo/bladeenc/flac,
and how to use CDDB_get to automate tagging the ripped encoded
tracks and putting them into nicely-named files.

Once I got into the swing of things, I decided I wanted things ever
so slightly different. I wanted the tracks with filenames preceeded
by tracknumbers, instead of the m3u playlist file. I wanted it to be
completely non-interactive; if freedb didn't have CDDB data for the
tracks, rip 'em into names that can later be re-named / re-tagged
but go ahead and rip 'em.

So I wrote my own rip, which I'm calling bentrip. I attach the
current version. If anybody finds it of any use, please let me know
and I'll email you if I end up doing any enhancements or bugfixes. I
_think_ it's close to feature-complete for my tastes right now, but
I've only ripped 3 CDs with it so far, so I may end up banging on it
some more.

Unlike the rip at, this one doesn't know about all the
options and all the rippers and encoders; it doesn't have any
options, it has one set of options with cdparanoia and oggenc
hard-coded. It's bentrip. I'm invoking it as bentrip;eject, then
using uparrow/return after I load the next CD.

-------------- next part --------------
#!/usr/bin/perl -w
use strict;
use CDDB_get;

=head1 NAME

  bentrip --- Bennett's ripper



	or perhaps

  while true;do
      echo -n "Another? "
      read ans


bentrip rips one CD into the current working subdirectory. The
ripping is hardwired, cdparanoia with default options into oggenc
--bitrate 160 (parameters, and indeed the idea and the way to do
this all shamlessly stolen from Gregory J. Smethells' rip, as found
at Details hardwired to Bennett's
preferences. bentrip, unlike Gregory J. Smethells' rip, is
completely and utterly non-interactive; it writes the best it can
and fills in defaults for anything it can't find out.

Aside from system permission problems and the ilke, it only bombs if
CDDB_get::get_cddb fails to produce a CDDB id and a count of tracks.


my $VERSION = "1.0";

my %cd = CDDB_get::get_cddb({
    CDDB_HOST => "",
    CDDB_PORT => 888,
    CDDB_MODE => "http",
    input     => 0,
    HELLO_ID  => "bet\ rip script $VERSION",
    HTTP_PROXY => ($ENV{HTTP_PROXY} or $ENV{http_proxy}),

die "CDDB_get did not acquire cddb id" unless defined $cd{id};
die "Unknown number of tracks" unless defined $cd{tno};
&burn(\%cd, "/dev/cdrom");

sub edit {
    my ($cd) = @_;
    local *_;

    my $id = $cd->{id};
    for (qw(artist title cat)) {
	$cd->{$_} = "unknown $_ $id" unless defined $cd->{$_};
    for my $i (1 .. $cd->{tno}) {
	$cd->{track}[$i-1] = sprintf("track%3d", $i) unless defined $cd->{track}[$i-1];

sub burn {
    my ($cd) = @_;
    local *_;

    my $artist = $cd->{artist}; $artist =~ y/a-zA-Z0-9_-//cds;
    $artist = $cd->{id} unless length $artist;
    -d $artist or mkdir $artist or die;
    my $title = $cd->{title}; $title =~ y/a-zA-Z0-9_-//cds;
    $title = $cd->{id} unless length $title;
    -d "$artist/$title" or mkdir "$artist/$title" or die;
    my ($year, $mon, $day) = (localtime(time))[5,4,3];
    $year += 1900; $mon++;
    my $date = sprintf("$year-%02.2d-%02.2d", $mon, $day);
    $| = 1;
    track: for my $track (1 .. $cd->{tno}) {
	print "Ripping track $track of $cd->{tno}\n";
	my $filename;
	$filename = $cd->{track}[$track-1];
	$filename =~ y/a-zA-Z0-9_-//cds;
	$filename = sprintf("$artist/$title/%03d-$filename.ogg", $track);
	if (-f $filename) {
	    print "No I am not, it is already there\n";
	    next track;
	pipe READER, WRITER or die;
	my $oggpid = fork;
	die unless defined $oggpid;
	if ($oggpid == 0) {
	    close WRITER or die;
	    open STDIN, "<&", \*READER or die;
	    exec "oggenc", "-",
		"--bitrate", 160,
		"-t", $cd->{track}[$track-1],
		"-a", $cd->{artist},
		"-l", $cd->{title},
		"-N", $track,
		"-c", "genre=$cd->{cat}",
		"-c", "encode_date=$date",
		"-c", "cddb_id=$cd->{id}",
		"-o", $filename;
	    die "oggenc did not exec";
	my $cdparanoiapid = fork;
	die unless defined $cdparanoiapid;
	if ($cdparanoiapid == 0) {
	    close READER or die;
	    open STDOUT, ">&", \*WRITER or die;
	    exec "cdparanoia", "-d", "/dev/cdrom", "-q", $track, "-";
	    die "cdparanoia did not exec";
	close READER or die;
	close WRITER or die;
	$SIG{INT} = sub { unlink $filename; die "interrupted, cleaned up $filename" };
	my $waitpid = waitpid $oggpid, 0;
	unlink $filename and die "wacko waitpid ogg" unless $waitpid == $oggpid;
	unlink $filename and die "oggenc roached exit status $?" if $?;
	$waitpid = waitpid $cdparanoiapid, 0;
	unlink $filename and die "wacko waitpid cdparanoia" unless $waitpid == $cdparanoiapid;
	unlink $filename and die "cdparanoia roached exit status $?" if $?;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <>

More information about the lfs-chat mailing list