source: flacrip/trunk/lib/Tracks.pm @ 24

Last change on this file since 24 was 24, checked in by peter, 10 years ago
  • converted Tracks from Class::Std to Moose
  • added a has_tracks() method to Tracks
  • Property svn:executable set to *
File size: 3.1 KB
Line 
1package Tracks;
2
3use Moose;
4use Digest::SHA1;
5
6use constant SECTOR_OFFSET => 150;
7
8has tracks => (
9    is      => 'rw',
10    default => sub { [] },
11);
12
13sub _get_tracks_from_cdinfo {   
14    my $device = shift;
15    my @tracks;
16    open my $CD_INFO, 'cd-info -q |' or die "Unable to run cd-info: $!";
17    while (<$CD_INFO>) {
18        next unless /^\s*([0-9]+): \d\d:\d\d:\d\d  (\d{6})/;
19        my ($num, $sector) = ($1, $2);
20        my $track = {
21            number => $num,
22            sector => $sector,
23        };
24        # place leadout track (170) at index 0
25        $num != 170 ? $tracks[$num] = $track : $tracks[0] = $track;
26    }
27    close $CD_INFO;
28
29    return @tracks;
30}
31
32sub _get_tracks_from_cdparanoia {
33    my $device = shift;
34    my @tracks;
35    open my $CDP, 'cdparanoia -d ' . $device . ' -Q 2>&1 |' or die "Unable to run cdparanoia: $!";
36    while (<$CDP>) {
37        if (m{
38            ^\s+(\d+)\.               # track number
39            \s+(\d+)                  # length
40            \s+\[(\d\d:\d\d\.\d\d)\]  # length (MSF)
41            \s+(\d+)                  # start
42            \s+\[(\d\d:\d\d\.\d\d)\]  # start (MSF)
43        }x) {
44            my ($track, $length, $length_msf, $start, $start_msf) = ($1, $2, $3, $4, $5);
45            $start_msf =~ s/\./:/;
46            $tracks[$track] = {
47                number => $track,
48                sector => $start,
49                msf    => $start_msf,
50            };
51        } elsif (m{TOTAL\s+(\d+)}) {
52            my $total = $1;
53            my $leadout = $total + $tracks[1]{sector};
54            $tracks[0] = {
55                number => 170,
56                sector => $leadout,
57            };       
58        }   
59    }
60    close $CDP;
61
62    return @tracks;
63}
64
65sub read_disc {
66    my ($self, $device) = @_;
67    $self->tracks([ _get_tracks_from_cdparanoia($device) ]);
68}
69
70sub has_tracks {
71    my $self = shift;
72    return @{ $self->tracks } > 0;
73}
74
75sub get_mbz_discid {
76    my ($self) = @_;
77
78    my @tracks = @{ $self->tracks };
79
80    return unless @tracks;
81
82    my $sha1 = Digest::SHA1->new;
83
84    $sha1->add(sprintf('%02X', $tracks[1]{number}));
85    $sha1->add(sprintf('%02X', $tracks[-1]{number}));
86    for my $i (0 .. 99) {
87        my $offset = (defined $tracks[$i]{sector} ? ($tracks[$i]{sector} + SECTOR_OFFSET) : 0);
88        $sha1->add(sprintf('%08X', $offset));
89    }
90
91    my $digest = $sha1->b64digest;
92    $digest =~ tr{+/=}{._-};
93    $digest .= '-';  ## why do we need to manually add this?
94
95    return $digest;
96}
97
98
99sub get_cuesheet {
100    my ($self) = @_;
101    my @tracks = @{ $self->tracks };
102    my @cuesheet;
103    push @cuesheet, qq{FILE "cdda.wav" WAVE};
104    for my $i (1 .. @tracks - 1) {
105        my $track = $tracks[$i];
106        push @cuesheet, sprintf('  TRACK %02d AUDIO', $i);
107        if ($i == 1 && $track->{sector} != 0) {
108            push @cuesheet, '    INDEX 00 00:00:00';
109        }
110        push @cuesheet, '    INDEX 01 ' . $track->{msf};
111    }
112    return join('', map { "$_\n" } @cuesheet);
113}
114
115sub get_cdparanoia_span {
116    my ($self) = @_;
117    # use a msf start unless track 1 begins at sector
118    return $self->tracks->[1]{sector} == 0 ? '1-' : '00:00.00-';
119}
120
121# module return
1221;
Note: See TracBrowser for help on using the repository browser.