Changeset 29 in mp3-find for trunk/lib/MP3/Find/DB.pm


Ignore:
Timestamp:
05/21/06 05:17:23 (18 years ago)
Author:
peter
Message:
  • factored out 'get_mp3_metadata' function from Filesystem.pm to Util.pm
  • added 'update' function to DB.pm that combines 'update_db' and 'update_file' (for updating just specific files); idea courtesy of Matt Dietrich
  • modified mp3db to let you mix and match files and directories on the command line; now also uses the 'update' function in DB.pm
File:
1 edited

Legend:

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

    r20 r29  
    99use DBI; 
    1010use SQL::Abstract; 
     11 
     12use MP3::Find::Util qw(get_mp3_metadata); 
    1113 
    1214my $sql = SQL::Abstract->new; 
     
    4850}; 
    4951 
     52# TODO: use DSNs instead of SQLite db names 
    5053sub search { 
    5154    my $self = shift; 
     
    8487} 
    8588 
     89# TODO: convert to using DSNs instead of hardcoded SQLite connections 
     90# TODO: extended table for ID3v2 data 
    8691sub create_db { 
    8792    my $self = shift; 
     
    9095    $dbh->do('CREATE TABLE mp3 (' . join(',', map { "$$_[0] $$_[1]" } @COLUMNS) . ')'); 
    9196} 
     97 
     98# this is update_db and update_files (from Matt Dietrich) rolled into one 
     99=head2 update 
     100 
     101    my $count = $finder->update({ 
     102        dsn   => 'dbi:SQLite:dbname=mp3.db', 
     103        files => \@filenames, 
     104        dirs  => [qw(music downloads/mp3)], 
     105    }); 
     106 
     107Compares the files in the C<files> list plus any MP3s found by searching 
     108in C<dirs> to their records in the database pointed to by C<dsn>. If the 
     109files found have been updated since they have been recorded in the database 
     110(or if they are not in the database), they are updated (or added). 
     111 
     112=cut 
     113 
     114sub update { 
     115    my $self = shift; 
     116    my $args = shift; 
     117 
     118    my $dsn   = $args->{dsn} or croak "Need a DSN to connect to"; 
     119    my @dirs  = $args->{dirs} 
     120                    ? ref $args->{dirs} eq 'ARRAY' 
     121                        ? @{ $args->{dirs} } 
     122                        : ($args->{dirs}) 
     123                    : (); 
     124 
     125    my @files  = $args->{files} 
     126                    ? ref $args->{files} eq 'ARRAY'  
     127                        ? @{ $args->{files} } 
     128                        : ($args->{files}) 
     129                    : (); 
     130     
     131    my $status_callback = $self->{status_callback} || $DEFAULT_STATUS_CALLBACK; 
     132 
     133    my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1}); 
     134    my $mtime_sth = $dbh->prepare('SELECT mtime FROM mp3 WHERE FILENAME = ?'); 
     135    my $insert_sth = $dbh->prepare( 
     136        'INSERT INTO mp3 (' .  
     137            join(',', map { $$_[0] } @COLUMNS) . 
     138        ') VALUES (' . 
     139            join(',', map { '?' } @COLUMNS) . 
     140        ')' 
     141    ); 
     142    my $update_sth = $dbh->prepare( 
     143        'UPDATE mp3 SET ' .  
     144            join(',', map { "$$_[0] = ?" } @COLUMNS) .  
     145        ' WHERE FILENAME = ?' 
     146    ); 
     147     
     148    my $count = 0;  # the number of records added or updated 
     149    my @mp3s;       # metadata for mp3s found 
     150 
     151    # look for mp3s using the filesystem backend if we have dirs to search in 
     152    if (@dirs) { 
     153        require MP3::Find::Filesystem; 
     154        my $finder = MP3::Find::Filesystem->new; 
     155        unshift @mp3s, $finder->find_mp3s(dir => \@dirs, no_format => 1); 
     156    } 
     157 
     158    # get the metadata on specific files 
     159    unshift @mp3s, map { get_mp3_metadata({ filename => $_ }) } @files; 
     160 
     161    # check each file against its record in the database 
     162    for my $mp3 (@mp3s) {        
     163        # see if the file has been modified since it was first put into the db 
     164        $mp3->{mtime} = (stat($mp3->{FILENAME}))[9]; 
     165        $mtime_sth->execute($mp3->{FILENAME}); 
     166        my $records = $mtime_sth->fetchall_arrayref; 
     167         
     168        warn "Multiple records for $$mp3{FILENAME}\n" if @$records > 1; 
     169         
     170        if (@$records == 0) { 
     171            # we are adding a record 
     172            $insert_sth->execute(map { $mp3->{$$_[0]} } @COLUMNS); 
     173            $status_callback->(A => $$mp3{FILENAME}); 
     174            $count++; 
     175        } elsif ($mp3->{mtime} > $$records[0][0]) { 
     176            # the mp3 file is newer than its record 
     177            $update_sth->execute((map { $mp3->{$$_[0]} } @COLUMNS), $mp3->{FILENAME}); 
     178            $status_callback->(U => $$mp3{FILENAME}); 
     179            $count++; 
     180        } 
     181    } 
     182     
     183    # SQLite specific code: 
     184    # as a workaround for the 'closing dbh with active staement handles warning 
     185    # (see http://rt.cpan.org/Ticket/Display.html?id=9643#txn-120724) 
     186    foreach ($mtime_sth, $insert_sth, $update_sth) { 
     187        $_->{RaiseError} = 0;  # don't die on error 
     188        $_->{PrintError} = 0;  # ...and don't even say anything 
     189        $_->{Active} = 1; 
     190        $_->finish; 
     191    } 
     192     
     193    return $count; 
     194} 
     195 
     196 
    92197 
    93198sub update_db { 
     
    129234        warn "Multiple records for $$mp3{FILENAME}\n" if @$records > 1; 
    130235         
    131         #TODO: maybe print status updates somewhere else? 
    132236        if (@$records == 0) { 
    133237            $insert_sth->execute(map { $mp3->{$$_[0]} } @COLUMNS); 
     
    154258} 
    155259 
     260# TODO: use DSNs instead of SQLite db names 
    156261sub sync_db { 
    157262    my $self = shift; 
     
    179284} 
    180285 
     286# TODO: use DSNs instead of SQLite db names (this might get funky) 
    181287sub destroy_db { 
    182288    my $self = shift; 
     
    342448Peter Eichman <peichman@cpan.org> 
    343449 
     450=head1 THANKS 
     451 
     452Thanks to Matt Dietrich for suggesting having an option to just  
     453update specific files instead of doing a (longer) full search. 
     454 
    344455=head1 COPYRIGHT AND LICENSE 
    345456 
Note: See TracChangeset for help on using the changeset viewer.