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

Last change on this file since 40 was 40, checked in by peter, 13 years ago

Reversed accidental commit of extra changes in r39

File size: 5.4 KB
Line 
1package MP3::Find::Base;
2
3use strict;
4use warnings;
5
6use Carp;
7
8my %format_codes = (
9    a => 'ARTIST',
10    t => 'TITLE',
11    b => 'ALBUM',
12    n => 'TRACKNUM',
13    y => 'YEAR',
14    g => 'GENRE',
15);
16
17sub new {
18    my $invocant = shift;
19    my $class = ref $invocant || $invocant;
20    my %options = @_;
21    my $self = \%options;
22    bless $self, $class;
23}
24
25sub find_mp3s {
26    my $self = shift;
27    my %opt = @_;
28   
29    my $dir = $opt{dir} || $ENV{HOME};
30    my @DIRS = ref $dir eq 'ARRAY' ? @$dir : ($dir);
31   
32    my %QUERY = %{ $opt{query} || {} };
33   
34    # array ref for multiple sort fields, but allow
35    # a simple scalar for single values
36    my @SORT = $opt{sort} ? 
37        (ref $opt{sort} eq 'ARRAY' ? @{ $opt{sort} } : ($opt{sort})) :
38        ();
39   
40    foreach (keys %QUERY) {
41        if (defined $QUERY{$_}) {
42            # package everything uniformly, so subclasses don't need to unpack it
43            $QUERY{$_} = [ $QUERY{$_} ] unless ref $QUERY{$_} eq 'ARRAY';
44        } else {
45            # so we don't have spurious warnings when trying to match against undef       
46            delete $QUERY{$_};
47        }
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::Base - Base class for MP3::Find backends
93
94=head1 SYNOPSIS
95
96    package MyFinder;
97    use base 'MP3::Find::Base';
98   
99    sub search {
100        my $self = shift;
101        my ($query, $dirs, $sort, $options) = @_;
102       
103        # do something to find and sort the mp3s...
104        my @results = do_something(...);
105       
106        return @results;
107    }
108   
109    package main;
110    my $finder = MyFinder->new;
111   
112    # see MP3::Find for details about %options
113    print "$_\n" foreach $finder->find_mp3s(\%options);       
114
115=head1 DESCRIPTION
116
117This is the base class for the classes that actually do the
118searching and sorting for L<MP3::Find>.
119
120=head1 METHODS
121
122=head2 new
123
124Really simple constructor. If you pass it a hash of options, it
125will hang on to them for you.
126
127=head2 search
128
129This is the one you should override in your subclass. If you
130don't, the base class C<search> method will croak.
131
132The C<search> method is called by the C<find_mp3s> method with
133the following arguments: the finder object, a hashref of query
134parameters, an arrayref of directories to search, and a hashref
135of miscellaneous options.
136
137The search method should return a list of hashrefs representing
138the results of the search. Each hashref should have the following
139keys (all except C<FILENAME> are derived from the keys returned
140by the C<get_mp3tag> and C<get_mp3Info> functions from L<MP3::Info>):
141
142    FILENAME
143   
144    TITLE
145    ARTIST
146    ALBUM
147    YEAR
148    COMMENT
149    GENRE
150    TRACKNUM
151   
152    VERSION         -- MPEG audio version (1, 2, 2.5)
153    LAYER           -- MPEG layer description (1, 2, 3)
154    STEREO          -- boolean for audio is in stereo
155   
156    VBR             -- boolean for variable bitrate
157    BITRATE         -- bitrate in kbps (average for VBR files)
158    FREQUENCY       -- frequency in kHz
159    SIZE            -- bytes in audio stream
160    OFFSET          -- bytes offset that stream begins
161   
162    SECS            -- total seconds
163    MM              -- minutes
164    SS              -- leftover seconds
165    MS              -- leftover milliseconds
166    TIME            -- time in MM:SS
167   
168    COPYRIGHT       -- boolean for audio is copyrighted
169    PADDING         -- boolean for MP3 frames are padded
170    MODE            -- channel mode (0 = stereo, 1 = joint stereo,
171                    -- 2 = dual channel, 3 = single channel)
172    FRAMES          -- approximate number of frames
173    FRAME_LENGTH    -- approximate length of a frame
174    VBR_SCALE       -- VBR scale from VBR header
175
176
177=head2 find_mp3s
178
179The method that should be called by the program doing the searching.
180
181See L<MP3::Find> for an explanation of the options that can be passed
182to C<find_mp3s>.
183
184=head1 TODO
185
186More format codes? Possibly look into using L<String::Format>
187
188=head1 SEE ALSO
189
190L<MP3::Find>, L<MP3::Find::Filesystem>, L<MP3::Find::DB>
191
192See L<MP3::Info> for more information about the fields you can
193search and sort on.
194
195=head1 AUTHOR
196
197Peter Eichman <peichman@cpan.org>
198
199=head1 COPYRIGHT AND LICENSE
200
201Copyright (c) 2006 by Peter Eichman. All rights reserved.
202
203This program is free software; you can redistribute it and/or
204modify it under the same terms as Perl itself.
205
206=cut
Note: See TracBrowser for help on using the repository browser.