Changeset 10 in mp3-find for trunk/lib


Ignore:
Timestamp:
02/02/06 01:51:00 (18 years ago)
Author:
peter
Message:
  • added test suite for the DB backend
  • doc corrections and updates to Find.pm and Base.pm
  • moved create and update database functions from mp3db to DB.pm
  • added "destroy_db" function to DB.pm
  • documented mp3db
  • set version to 0.02
Location:
trunk/lib/MP3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/MP3/Find.pm

    r6 r10  
    99use Carp; 
    1010 
    11 $VERSION = '0.01'; 
     11$VERSION = '0.02'; 
    1212 
    1313@EXPORT = qw(find_mp3s); 
     
    6969is currently not as stable as the Filesystem backend. 
    7070 
     71B<Note the second>: This whole project is still in the alpha stage, so 
     72I can make no guarentees that there won't be significant interface changes 
     73in the next few versions or so. Also, comments about what about the API 
     74rocks (or sucks!) are appreciated. 
     75 
    7176=head1 REQUIRES 
    7277 
  • trunk/lib/MP3/Find/Base.pm

    r7 r10  
    9393=head1 NAME 
    9494 
    95 MP3::Find::Base - Base class for MP3::Find finders 
     95MP3::Find::Base - Base class for MP3::Find backends 
    9696 
    9797=head1 SYNOPSIS 
  • trunk/lib/MP3/Find/DB.pm

    r3 r10  
    55 
    66use base qw(MP3::Find::Base); 
     7use Carp; 
    78 
    89use DBI; 
     
    1112my $sql = SQL::Abstract->new; 
    1213 
     14my @COLUMNS = ( 
     15    [ mtime        => 'INTEGER' ],  # the filesystem mtime, so we can do incremental updates 
     16    [ FILENAME     => 'TEXT' ],  
     17    [ TITLE        => 'TEXT' ],  
     18    [ ARTIST       => 'TEXT' ],  
     19    [ ALBUM        => 'TEXT' ], 
     20    [ YEAR         => 'INTEGER' ],  
     21    [ COMMENT      => 'TEXT' ],  
     22    [ GENRE        => 'TEXT' ],  
     23    [ TRACKNUM     => 'INTEGER' ],  
     24    [ VERSION      => 'NUMERIC' ], 
     25    [ LAYER        => 'INTEGER' ],  
     26    [ STEREO       => 'TEXT' ], 
     27    [ VBR          => 'TEXT' ], 
     28    [ BITRATE      => 'INTEGER' ],  
     29    [ FREQUENCY    => 'INTEGER' ],  
     30    [ SIZE         => 'INTEGER' ],  
     31    [ OFFSET       => 'INTEGER' ],  
     32    [ SECS         => 'INTEGER' ],  
     33    [ MM           => 'INTEGER' ], 
     34    [ SS           => 'INTEGER' ], 
     35    [ MS           => 'INTEGER' ],  
     36    [ TIME         => 'TEXT' ], 
     37    [ COPYRIGHT    => 'TEXT' ],  
     38    [ PADDING      => 'INTEGER' ],  
     39    [ MODE         => 'INTEGER' ], 
     40    [ FRAMES       => 'INTEGER' ],  
     41    [ FRAME_LENGTH => 'INTEGER' ],  
     42    [ VBR_SCALE    => 'INTEGER' ], 
     43); 
     44 
     45 
    1346sub search { 
    1447    my $self = shift; 
    1548    my ($query, $dirs, $sort, $options) = @_; 
    1649     
    17     my $dbh = DBI->connect("dbi:SQLite:dbname=$$options{db_file}", '', ''); 
     50    croak 'Need a database name to search (set "db_file" in the call to find_mp3s)' unless $$options{db_file}; 
     51     
     52    my $dbh = DBI->connect("dbi:SQLite:dbname=$$options{db_file}", '', '', {RaiseError => 1}); 
    1853     
    1954    # use the 'LIKE' operator to ignore case 
     
    4378     
    4479    return @results; 
     80} 
     81 
     82sub create_db { 
     83    my $self = shift; 
     84    my $db_file = shift or croak "Need a name for the database I'm about to create"; 
     85    my $dbh = DBI->connect("dbi:SQLite:dbname=$db_file", '', '', {RaiseError => 1}); 
     86    $dbh->do('CREATE TABLE mp3 (' . join(',', map { "$$_[0] $$_[1]" } @COLUMNS) . ')'); 
     87} 
     88 
     89sub update_db { 
     90    my $self = shift; 
     91    my $db_file = shift or croak "Need the name of the databse to update"; 
     92    my $dirs = shift; 
     93     
     94    my @dirs = ref $dirs eq 'ARRAY' ? @$dirs : ($dirs); 
     95     
     96    my $dbh = DBI->connect("dbi:SQLite:dbname=$db_file", '', '', {RaiseError => 1}); 
     97    my $mtime_sth = $dbh->prepare('SELECT mtime FROM mp3 WHERE FILENAME = ?'); 
     98    my $insert_sth = $dbh->prepare( 
     99        'INSERT INTO mp3 (' .  
     100            join(',', map { $$_[0] } @COLUMNS) . 
     101        ') VALUES (' . 
     102            join(',', map { '?' } @COLUMNS) . 
     103        ')' 
     104    ); 
     105    my $update_sth = $dbh->prepare( 
     106        'UPDATE mp3 SET ' .  
     107            join(',', map { "$$_[0] = ?" } @COLUMNS) .  
     108        ' WHERE FILENAME = ?' 
     109    ); 
     110     
     111    # the number of records added or updated 
     112    my $count = 0; 
     113     
     114    # look for mp3s using the filesystem backend 
     115    require MP3::Find::Filesystem; 
     116    my $finder = MP3::Find::Filesystem->new; 
     117    for my $mp3 ($finder->find_mp3s(dir => \@dirs, no_format => 1)) { 
     118        # see if the file has been modified since it was first put into the db 
     119        $mp3->{mtime} = (stat($mp3->{FILENAME}))[9]; 
     120        $mtime_sth->execute($mp3->{FILENAME}); 
     121        my $records = $mtime_sth->fetchall_arrayref; 
     122         
     123        warn "Multiple records for $$mp3{FILENAME}\n" if @$records > 1; 
     124         
     125        if (@$records == 0) { 
     126            $insert_sth->execute(map { $mp3->{$$_[0]} } @COLUMNS); 
     127            print STDERR "A $$mp3{FILENAME}\n"; 
     128            $count++; 
     129        } elsif ($mp3->{mtime} > $$records[0][0]) { 
     130            # the mp3 file is newer than its record 
     131            $update_sth->execute((map { $mp3->{$$_[0]} } @COLUMNS), $mp3->{FILENAME}); 
     132            print STDERR "U $$mp3{FILENAME}\n"; 
     133            $count++; 
     134        } 
     135    } 
     136     
     137    # as a workaround for the 'closing dbh with active staement handles warning 
     138    # (see http://rt.cpan.org/Ticket/Display.html?id=9643#txn-120724) 
     139    foreach ($mtime_sth, $insert_sth, $update_sth) { 
     140        $_->{Active} = 1; 
     141        $_->finish; 
     142    } 
     143     
     144    return $count; 
     145} 
     146 
     147sub destroy_db { 
     148    my $self = shift; 
     149    my $db_file = shift or croak "Need the name of a database to destory"; 
     150    unlink $db_file; 
    45151} 
    46152 
     
    64170        }, 
    65171        ignore_case => 1, 
    66     ); 
     172        db_file => 'mp3.db', 
     173    ); 
     174     
     175    # you can do things besides just searching the database 
     176     
     177    # create another database 
     178    $finder->create_db('my_mp3s.db'); 
     179     
     180    # update the database from the filesystem 
     181    $finder->update_db('my_mp3s.db', ['/home/peter/mp3', '/home/peter/cds']); 
     182     
     183    # and then blow it away 
     184    $finder->destroy_db('my_mp3s.db'); 
    67185 
    68186=head1 REQUIRES 
     
    121239=back 
    122240 
     241=head1 METHODS 
     242 
     243=head2 create_db 
     244 
     245    $finder->create_db($db_filename); 
     246 
     247Creates a SQLite database in the file named c<$db_filename>. 
     248 
     249=head2 update_db 
     250 
     251    my $count = $finder->update_db($db_filename, \@dirs); 
     252 
     253Searches for all mp3 files in the directories named by C<@dirs> 
     254using L<MP3::Find::Filesystem>, and adds or updates the ID3 info 
     255from those files to the database. If a file already has a record 
     256in the database, then it will only be updated if it has been modified 
     257sinc ethe last time C<update_db> was run. 
     258 
     259=head2 destroy_db 
     260 
     261    $finder->destroy_db($db_filename); 
     262 
     263Permanantly removes the database. 
     264 
    123265=head1 TODO 
    124266 
    125 Move the database/table creation code from F<mp3db> into this 
    126 module. 
    127  
    128267Database maintanence routines (e.g. clear out old entries) 
    129268 
     269Allow the passing of a DSN or an already created C<$dbh> instead 
     270of a SQLite database filename. 
     271 
    130272=head1 SEE ALSO 
    131273 
    132 L<MP3::Find>, L<MP3::Find::DB> 
     274L<MP3::Find>, L<MP3::Find::Filesystem>, L<mp3db> 
    133275 
    134276=head1 AUTHOR 
Note: See TracChangeset for help on using the changeset viewer.