File Coverage

blib/lib/MP3/Find/Base.pm
Criterion Covered Total %
statement 28 43 65.1
branch 6 16 37.5
condition 2 10 20.0
subroutine 5 6 83.3
pod 3 3 100.0
total 44 78 56.4


line stmt bran cond sub pod time code
1             package MP3::Find::Base;
2              
3 2     2   9 use strict;
  2         3  
  2         50  
4 2     2   8 use warnings;
  2         2  
  2         43  
5              
6 2     2   17 use Carp;
  2         4  
  2         1057  
7              
8             my %format_codes = (
9             a => 'ARTIST',
10             t => 'TITLE',
11             b => 'ALBUM',
12             n => 'TRACKNUM',
13             y => 'YEAR',
14             g => 'GENRE',
15             );
16              
17             sub new {
18 2     2 1 23 my $invocant = shift;
19 2   33     15 my $class = ref $invocant || $invocant;
20 2         4 my %options = @_;
21 2         6 my $self = \%options;
22 2         8 bless $self, $class;
23             }
24              
25             sub find_mp3s {
26 4     4 1 1621 my $self = shift;
27 4         13 my %opt = @_;
28            
29 4   33     13 my $dir = $opt{dir} || $ENV{HOME};
30 4 100       15 my @DIRS = ref $dir eq 'ARRAY' ? @$dir : ($dir);
31            
32 4 50       4 my %QUERY = %{ $opt{query} || {} };
  4         29  
33            
34             # array ref for multiple sort fields, but allow
35             # a simple scalar for single values
36 0         0 my @SORT = $opt{sort} ?
37 4 0       14 (ref $opt{sort} eq 'ARRAY' ? @{ $opt{sort} } : ($opt{sort})) :
    50          
38             ();
39            
40 4         10 foreach (keys %QUERY) {
41 0 0       0 if (defined $QUERY{$_}) {
42             # package everything uniformly, so subclasses don't need to unpack it
43 0 0       0 $QUERY{$_} = [ $QUERY{$_} ] unless ref $QUERY{$_} eq 'ARRAY';
44             } else {
45             # so we don't have spurious warnings when trying to match against undef
46 0         0 delete $QUERY{$_};
47             }
48             }
49            
50             # do the search
51 4         19 my @results = $self->search(\%QUERY, \@DIRS, \@SORT, \%opt);
52            
53             # maybe they want the unformatted data
54 4 50       11 return @results if $opt{no_format};
55            
56 4 50       7 if ($opt{printf}) {
57             # printf style output format
58 0         0 foreach (@results) {
59 0         0 my $output = $opt{printf};
60 0         0 for my $code (keys %format_codes) {
61            
62 0         0 while ($output =~ m/%((-\d)?\d*)$code/g) {
63             # field size modifier
64 0   0     0 my $modifier = $1 || '';
65             # figure out the size of the formating code
66 0         0 my $code_size = 2 + length($modifier);
67 0   0     0 my $value = sprintf("%${modifier}s", $_->{$format_codes{$code}} || '');
68 0         0 substr($output, pos($output) - $code_size, $code_size, $value);
69             }
70             }
71             # to allow literal '%'
72 0         0 $output =~ s/%%/%/g;
73 0         0 $_ = $output;
74             }
75             } else {
76             # just the filenames, please
77 4         7 @results = map { $_->{FILENAME} } @results;
  2         7  
78             }
79            
80 4         20 return @results;
81             }
82              
83             sub search {
84 0     0 1   croak "Method 'search' not implemented in " . __PACKAGE__;
85             }
86              
87             # module return
88             1;
89              
90             =head1 NAME
91              
92             MP3::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              
117             This is the base class for the classes that actually do the
118             searching and sorting for L.
119              
120             =head1 METHODS
121              
122             =head2 new
123              
124             Really simple constructor. If you pass it a hash of options, it
125             will hang on to them for you.
126              
127             =head2 search
128              
129             This is the one you should override in your subclass. If you
130             don't, the base class C method will croak.
131              
132             The C method is called by the C method with
133             the following arguments: the finder object, a hashref of query
134             parameters, an arrayref of directories to search, and a hashref
135             of miscellaneous options.
136              
137             The search method should return a list of hashrefs representing
138             the results of the search. Each hashref should have the following
139             keys (all except C are derived from the keys returned
140             by the C and C functions from L):
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              
179             The method that should be called by the program doing the searching.
180              
181             See L for an explanation of the options that can be passed
182             to C.
183              
184             =head1 TODO
185              
186             More format codes? Possibly look into using L
187              
188             =head1 SEE ALSO
189              
190             L, L, L
191              
192             See L for more information about the fields you can
193             search and sort on.
194              
195             =head1 AUTHOR
196              
197             Peter Eichman
198              
199             =head1 COPYRIGHT AND LICENSE
200              
201             Copyright (c) 2006 by Peter Eichman. All rights reserved.
202              
203             This program is free software; you can redistribute it and/or
204             modify it under the same terms as Perl itself.
205              
206             =cut