The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#
#  CDDB - Read the CDDB entry for an audio CD in your drive
#
#  This module/script gets the CDDB info for an audio cd. You need
#  LINUX, a cdrom drive and an active internet connection in order
#  to do that.
#
#  (c) 2004 Armin Obersteiner <armin@xos.net>
#
#  LICENSE
#
#  This library is released under the same conditions as Perl, that
#  is, either of the following:
#
#  a) the GNU General Public License Version 2 as published by the
#  Free Software Foundation,
#
#  b) the Artistic License.
#

package CDDB_cache;

use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $debug $dir $readonly $grep);

require Exporter;

@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT_OK = qw(
  get_cddb
  get_discids
);
$VERSION = '1.0';

use CDDB_get;
use File::Find;
use Data::Dumper qw(Dumper);

#$debug=1;
$dir="/tmp/xmcd";

my $CD_DEVICE = "/dev/cdrom";

sub get_discids {
  my $cd=shift;

  return CDDB_get::get_discids($cd);
}

my @files;

sub get_cddb {
  my $config=shift;
  my $diskid=shift;

  if($debug) {
    print STDERR "dir: [$dir]  readonly [$readonly]  grep [$grep]\n";
  }

  $config->{multi}=0;
  $CD_DEVICE = $config->{CD_DEVICE} if (defined($config->{CD_DEVICE}));

  my $did=$diskid;
  $did=CDDB_get::get_discids($CD_DEVICE) unless($did);
  #print Dumper($did);
 
  printf STDERR "%08x %08lx\n", $did->[0],  $did->[0] if($debug);
 
  my $sid = sprintf "%08x", $did->[0];
  my $id = sprintf "%08x %d", $did->[0], $did->[1];
  for(0..$did->[1]-1) {
    $id.=" ".$did->[2]->[$_]->{frames};
  }
  $id.=" ".int($did->[2]->[$did->[1]]->{frames}/75);
  print STDERR "id: $id\n" if $debug;

  @files=();
  if($grep) {
    find({ wanted => sub {
      next unless -f $File::Find::name;
      my $tid=`grep -H $sid $File::Find::name`;
      if($tid =~ /\S+/) {
        push @files, $File::Find::name;
      } 
    }, follow=>1}, $dir);
  } else {
    find({ wanted => sub {
      if($_ eq $sid) {
        push @files, $File::Find::name;
      } 
    }, follow=>1}, $dir);
  }
  print STDERR Dumper(\@files) if $debug;

  my $file;
  my $found;

  for(@files) {
    open IN,$_;
    undef $/;
    $file=<IN>;
    close IN;

    my ($fid)=$file =~ /DISCID=(\S+)/i;
    my ($len)=$file =~ /Disc length: (\d+) seconds/i;
    my ($s)=$file =~ /Track frame offsets:\s+(.*)\s+Disc length/si;
    my $t="";
    my @tr=split /#/,$s;
    my $c=0;
    for(@tr) {
      next unless /(\d+)/;
      $c++;
      $t.=" $1";
      last if($c>=$did->[1]);
    }
    my $tid="$fid $c$t $len";

    if($tid eq $id) {
      $found=$_;
      last;
    }
  }

  my $toc=$did->[2];

  my %cd;
  if($found) {
    print STDERR "CDDB_cache: reading from file: $found\n";

    my @lines=split /\n/,$file;
    for(@lines) {
      push @{$cd{raw}},$_."\n";
      #TTITLE0=Bitch (Edit)
      if(/^TTITLE(\d+)\=\s*(.*)/) {
        my $t= $2;
        chomp $t;
        $cd{frames}[$1]=$toc->[$1]->{frames};
        $cd{data}[$1]=$toc->[$1]->{data};
        unless (defined $cd{track}[$1]) {
          $cd{track}[$1]=$t;
        } else {
          $cd{track}[$1]=$cd{track}[$1].$t;
        }
      } elsif(/^DYEAR=\s*(\d+)/) {
        $cd{'year'} = $1;
      } elsif(/^DGENRE=\s*(\S+.*)/) {
        my $t = $1;
        chomp $t;
        $cd{'genre'} = $t;
      }
    }

    $cd{tno}=$#{$cd{track}}+1;
    $cd{frames}[$cd{tno}]=$toc->[$cd{tno}]->{frames};

    $cd{id}=$sid;

    my ($at)=$file=~/DTITLE=(.*?)\n/;
    my ($artist,$title);
    #chop $at if($at =~ /\r/);
    chomp $at;

    if($at =~ /\//) {
      ($artist,$title)= $at =~ /^(.*?)\s\/\s(.*)/;
    } else {
      $artist=$at;
      $title=$at;
    }

    $cd{artist}=$artist;
    $cd{title}=$title;

    my ($cat) = $found =~ /$dir\/(\S+?)\/$sid/;
    $cd{cat}=$cat;

  } else {
    print STDERR "CDDB_cache: reading from network\n";

    %cd=CDDB_get::get_cddb($config,$diskid);
  }

  print STDERR Dumper(\%cd) if $debug;

  unless($readonly || $found) {
    my $file=$dir."/$cd{cat}/$cd{id}";
    my $ddir=$dir."/$cd{cat}";
    mkdir $ddir,0755;   

    open OUT,">$file";
    for(@{$cd{raw}}) {
      print OUT $_;
    }
    close OUT;
  }

  return %cd;
}

1;
__END__