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

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

remove undefined query keys so we don't get warnings when trying to match against 'undef'

File size: 5.4 KB
Line 
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 %options = @_;
24    my $self = \%options;
25    bless $self, $class;
26}
27
28sub find_mp3s {
29    my $self = shift;
30    my %opt = @_;
31   
32    my $dir = $opt{dir} || $ENV{HOME};
33    my @DIRS = ref $dir eq 'ARRAY' ? @$dir : ($dir);
34   
35    my %QUERY = %{ $opt{query} || {} };
36   
37    # array ref for multiple sort fields, but allow
38    # a simple scalar for single values
39    my @SORT = $opt{sort} ? 
40        (ref $opt{sort} eq 'ARRAY' ? @{ $opt{sort} } : ($opt{sort})) :
41        ();
42   
43    foreach (keys %QUERY) {
44        if (defined $QUERY{$_}) {
45            # package everything uniformly, so subclasses don't need to unpack it
46            $QUERY{$_} = [ $QUERY{$_} ] unless ref $QUERY{$_} eq 'ARRAY';
47        } else {
48            # so we don't have spurious warnings when trying to match against undef       
49            delete $QUERY{$_};
50        }
51    }
52   
53    # do the search
54    my @results = $self->search(\%QUERY, \@DIRS, \@SORT, \%opt);
55   
56    # maybe they want the unformatted data
57    return @results if $opt{no_format};
58   
59    if ($opt{printf}) {
60        # printf style output format
61        foreach (@results) {
62            my $output = $opt{printf};
63            for my $code (keys %format_codes) {
64               
65                while ($output =~ m/%((-\d)?\d*)$code/g) {
66                    # field size modifier
67                    my $modifier = $1 || '';
68                    # figure out the size of the formating code
69                    my $code_size = 2 + length($modifier);
70                    my $value = sprintf("%${modifier}s", $_->{$format_codes{$code}} || '');
71                    substr($output, pos($output) - $code_size, $code_size, $value);
72                }
73            }
74            # to allow literal '%'
75            $output =~ s/%%/%/g;       
76            $_ = $output;
77        }
78    } else {
79        # just the filenames, please
80        @results = map { $_->{FILENAME} } @results;
81    }
82   
83    return @results;
84}
85
86sub search {
87    croak "Method 'search' not implemented in " . __PACKAGE__;
88}
89
90# module return
911;
92
93=head1 NAME
94
95MP3::Find::Base - Base class for MP3::Find finders
96
97=head1 SYNOPSIS
98
99    package MyFinder;
100    use base 'MP3::Find::Base';
101   
102    sub search {
103        my $self = shift;
104        my ($query, $dirs, $sort, $options) = @_;
105       
106        # do something to find and sort the mp3s...
107        my @results = do_something(...);
108       
109        return @results;
110    }
111   
112    package main;
113    my $finder = MyFinder->new;
114   
115    # see MP3::Find for details about %options
116    print "$_\n" foreach $finder->find_mp3s(\%options);       
117
118=head1 DESCRIPTION
119
120This is the base class for the classes that actually do the
121searching and sorting for L<MP3::Find>.
122
123=head1 METHODS
124
125=head2 new
126
127Really simple constructor. If you pass it a hash of options, it
128will hang on to them for you.
129
130=head2 search
131
132This is the one you should override in your subclass. If you
133don't, the base class C<search> method will croak.
134
135The C<search> method is called by the C<find_mp3s> method with
136the following arguments: the finder object, a hashref of query
137parameters, an arrayref of directories to search, and a hashref
138of miscellaneous options.
139
140The search method should return a list of hashrefs representing
141the results of the search. Each hashref should have the following
142keys (all except C<FILENAME> are derived from the keys returned
143by the C<get_mp3tag> and C<get_mp3Info> functions from L<MP3::Info>):
144
145    FILENAME
146   
147    TITLE
148    ARTIST
149    ALBUM
150    YEAR
151    COMMENT
152    GENRE
153    TRACKNUM
154   
155    VERSION         -- MPEG audio version (1, 2, 2.5)
156    LAYER           -- MPEG layer description (1, 2, 3)
157    STEREO          -- boolean for audio is in stereo
158   
159    VBR             -- boolean for variable bitrate
160    BITRATE         -- bitrate in kbps (average for VBR files)
161    FREQUENCY       -- frequency in kHz
162    SIZE            -- bytes in audio stream
163    OFFSET          -- bytes offset that stream begins
164   
165    SECS            -- total seconds
166    MM              -- minutes
167    SS              -- leftover seconds
168    MS              -- leftover milliseconds
169    TIME            -- time in MM:SS
170   
171    COPYRIGHT       -- boolean for audio is copyrighted
172    PADDING         -- boolean for MP3 frames are padded
173    MODE            -- channel mode (0 = stereo, 1 = joint stereo,
174                    -- 2 = dual channel, 3 = single channel)
175    FRAMES          -- approximate number of frames
176    FRAME_LENGTH    -- approximate length of a frame
177    VBR_SCALE       -- VBR scale from VBR header
178
179
180=head2 find_mp3s
181
182The method that should be called by the program doing the searching.
183
184See L<MP3::Find> for an explanation of the options that can be passed
185to C<find_mp3s>.
186
187=head1 TODO
188
189More format codes? Possibly look into using L<String::Format>
190
191=head1 SEE ALSO
192
193L<MP3::Find>, L<MP3::Find::Filesystem>, L<MP3::Find::DB>
194
195See L<MP3::Info> for more information about the fields you can
196search and sort on.
197
198=head1 AUTHOR
199
200Peter Eichman <peichman@cpan.org>
201
202=head1 COPYRIGHT AND LICENSE
203
204Copyright (c) 2006 by Peter Eichman. All rights reserved.
205
206This program is free software; you can redistribute it and/or
207modify it under the same terms as Perl itself.
208
209=cut
Note: See TracBrowser for help on using the repository browser.