source: mp3-find/trunk/lib/MP3/Find/Base.pm @ 1

Last change on this file since 1 was 1, checked in by peter, 18 years ago

Initial import

File size: 5.8 KB
RevLine 
[1]1package MP3::Find::Base;
2
3use strict;
4use warnings;
5
6use vars qw($VERSION);
7use Carp;
8
9$VERSION = '0.01';
10
11my %format_codes = (
12    a => 'ARTIST',
13    t => 'TITLE',
14    b => 'ALBUM',
15    n => 'TRACKNUM',
16    y => 'YEAR',
17    g => 'GENRE',
18);
19
20sub new {
21    my $invocant = shift;
22    my $class = ref $invocant || $invocant;
23    my $self = {};
24    bless $self, $class;
25}
26
27sub find_mp3s {
28    my $self = shift;
29    my %opt = @_;
30   
31    my $dir = $opt{dir} || $ENV{HOME};
32    my @DIRS = ref $dir eq 'ARRAY' ? @$dir : ($dir);
33   
34    my %QUERY = %{ $opt{query} || {} };
35   
36    # array ref for multiple sort fields, but allow
37    # a simple scalar for single values
38    my @SORT = $opt{sort} ? 
39        (ref $opt{sort} eq 'ARRAY' ? @{ $opt{sort} } : ($opt{sort})) :
40        ();
41   
42   
43    foreach (keys %QUERY) {
44        # so we don't have spurious warnings when trying to match against undef
45        delete $QUERY{$_} unless defined $QUERY{$_};
46        # package everything unioformly, so subclasses don't need to unpack
47        $QUERY{$_} = [ $QUERY{$_} ] unless ref $QUERY{$_} eq 'ARRAY';
48    }
49   
50    # do the search
51    my @results = $self->search(\%QUERY, \@DIRS, \@SORT, \%opt);
52   
53    # maybe they want the unformatted data
54    return @results if $opt{no_format};
55   
56    if ($opt{printf}) {
57        # printf style output format
58        foreach (@results) {
59            my $output = $opt{printf};
60            for my $code (keys %format_codes) {
61               
62                while ($output =~ m/%((-\d)?\d*)$code/g) {
63                    # field size modifier
64                    my $modifier = $1 || '';
65                    # figure out the size of the formating code
66                    my $code_size = 2 + length($modifier);
67                    my $value = sprintf("%${modifier}s", $_->{$format_codes{$code}} || '');
68                    substr($output, pos($output) - $code_size, $code_size, $value);
69                }
70            }
71            # to allow literal '%'
72            $output =~ s/%%/%/g;       
73            $_ = $output;
74        }
75    } else {
76        # just the filenames, please
77        @results = map { $_->{FILENAME} } @results;
78    }
79   
80    return @results;
81}
82
83sub search {
84    croak "Method 'search' not implemented in " . __PACKAGE__;
85}
86
87# module return
881;
89
90=head1 NAME
91
92MP3::Find - Search and sort MP3 files based on their ID3 tags
93
94=head1 SYNOPSIS
95
96    use MP3Find;
97   
98    print "$_\n" foreach find_mp3s(
99        dir => '/home/peter/cds',
100        query => {
101            artist => 'ilyaimy',
102            title => 'deep in the am',
103        },
104        ignore_case => 1,
105        match_words => 1,
106        sort => [qw(year album tracknum)],
107        printf => '%2n. %a - %t (%b: %y)',
108    );
109
110=head1 DESCRIPTION
111
112This module allows you to search for MP3 files by their ID3 tags.
113You can ask for the results to be sorted by one or more of those
114tags, and return either the list of filenames (the deault), a
115C<printf>-style formatted string for each file using its ID3 tags,
116or the actual Perl data structure representing the results.
117
118=head1 REQUIRES
119
120L<File::Find>, L<MP3::Info>, L<Scalar::Util>
121
122L<DBI> and L<DBD::SQLite> are needed if you want to have a
123database backend.
124
125=head1 EXPORTS
126
127=head2 find_mp3s
128
129    my @results = find_mp3s(%options);
130
131Takes the following options:
132
133=over
134
135=item C<dir>
136
137Where to start the search. This can either be a single string or
138an arrayref. Defaults to your home directory.
139
140=item C<query>
141
142Hashref of search parameters. Recognized fields are anything that
143L<MP3::Info> knows about. Field names can be given in either upper
144or lower case; C<find_mp3s> will convert them into upper case for
145you. Value may either be strings, which are converted into regular
146exporessions, or may be C<qr[...]> regular expressions already.
147
148=item C<ignore_case>
149
150Ignore case when matching search strings to the ID3 tag values.
151
152=item C<exact_match>
153
154Adds an implicit C<^> and C<$> around each query string.
155
156=item C<sort>
157
158What field or fields to sort the results by. Can either be a single
159scalar field name to sort by, or an arrayref of field names. Again,
160acceptable field names are anything that L<MP3::Info> knows about.
161
162=item C<printf>
163
164By default, C<find_mp3s> just returns the list of filenames. The
165C<printf> option allows you to provide a formatting string to apply
166to the data for each file. The style is roughly similar to Perl's
167C<printf> format strings. The following formatting codes are
168recognized:
169
170    %a - artist
171    %t - title
172    %b - album
173    %n - track number
174    %y - year
175    %g - genre
176    %% - literal '%'
177
178Numeric modifers may be used in the same manner as with C<%s> in
179Perl's C<printf>.
180
181=item C<no_format>
182
183Causes C<find_mp3s> to return an array of hashrefs instead of an array
184of (formatted) strings. Each hashref consists of the key-value pairs
185from C<MP3::Info::get_mp3_tag> and C<MP3::Info::get_mp3_info>, plus
186the key C<FILENAME> (with the obvious value ;-)
187
188    @results = (
189        {
190            FILENAME => ...,
191            TITLE    => ...,
192            ARTIST   => ...,
193            ...
194            SECS     => ...,
195            BITRATE  => ...,
196            ...
197        },
198        ...
199    );
200
201=back
202
203=head1 TODO
204
205More of a structured query would be nice; currently everything
206is and-ed together, and it would be nice to be able to put query
207keys together with a mixture of and and or.
208
209Searching a big directory is slo-o-ow! Investigate some sort of
210caching of results?
211
212The current sorting function is also probably quite inefficient.
213
214=head1 SEE ALSO
215
216See L<MP3::Info> for more information about the fields you can
217search and sort on.
218
219L<File::Find::Rule::MP3Info> is another way to search for MP3
220files based on their ID3 tags.
221
222=head1 AUTHOR
223
224Peter Eichman <peichman@cpan.org>
225
226=head1 COPYRIGHT AND LICENSE
227
228Copyright (c) 2006 by Peter Eichman. All rights reserved.
229
230This program is free software; you can redistribute it and/or
231modify it under the same terms as Perl itself.
232
233=cut
Note: See TracBrowser for help on using the repository browser.