]>
Commit | Line | Data |
---|---|---|
83d20a45 CS |
1 | # |
2 | # This file is part of Audio::MPD | |
3 | # Copyright (c) 2007 Jerome Quelin, all rights reserved. | |
4 | # | |
5 | # This program is free software; you can redistribute it and/or modify | |
6 | # it under the same terms as Perl itself. | |
7 | # | |
8 | # | |
9 | ||
10 | package Audio::MPD::Collection; | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use Scalar::Util qw[ weaken ]; | |
15 | ||
16 | use base qw[ Class::Accessor::Fast ]; | |
17 | __PACKAGE__->mk_accessors( qw[ _mpd ] ); | |
18 | ||
19 | ||
20 | #our ($VERSION) = '$Rev: 5284 $' =~ /(\d+)/; | |
21 | ||
22 | ||
23 | #-- | |
24 | # Constructor | |
25 | ||
26 | # | |
27 | # my $collection = Audio::MPD::Collection->new( $mpd ); | |
28 | # | |
29 | # This will create the object, holding a back-reference to the Audio::MPD | |
30 | # object itself (for communication purposes). But in order to play safe and | |
31 | # to free the memory in time, this reference is weakened. | |
32 | # | |
33 | # Note that you're not supposed to call this constructor yourself, an | |
34 | # Audio::MPD::Collection is automatically created for you during the creation | |
35 | # of an Audio::MPD object. | |
36 | # | |
37 | sub new { | |
38 | my ($pkg, $mpd) = @_; | |
39 | ||
40 | my $self = { _mpd => $mpd }; | |
41 | weaken( $self->{_mpd} ); | |
42 | bless $self, $pkg; | |
43 | return $self; | |
44 | } | |
45 | ||
46 | ||
47 | #-- | |
48 | # Public methods | |
49 | ||
50 | # -- Collection: retrieving songs & directories | |
51 | ||
52 | # | |
53 | # my @items = $collection->all_items( [$path] ); | |
54 | # | |
55 | # Return *all* AMC::Items (both songs & directories) currently known | |
56 | # by mpd. | |
57 | # | |
58 | # If $path is supplied (relative to mpd root), restrict the retrieval to | |
59 | # songs and dirs in this directory. | |
60 | # | |
61 | sub all_items { | |
62 | my ($self, $path) = @_; | |
63 | $path ||= ''; | |
64 | $path =~ s/"/\\"/g; | |
65 | ||
66 | return $self->_mpd->_cooked_command_as_items( qq[listallinfo "$path"\n] ); | |
67 | } | |
68 | ||
69 | ||
70 | # | |
71 | # my @items = $collection->all_items_simple( [$path] ); | |
72 | # | |
73 | # Return *all* AMC::Items (both songs & directories) currently known | |
74 | # by mpd. | |
75 | # | |
76 | # If $path is supplied (relative to mpd root), restrict the retrieval to | |
77 | # songs and dirs in this directory. | |
78 | # | |
79 | # /!\ Warning: the AMC::Item::Song objects will only have their tag | |
80 | # file filled. Any other tag will be empty, so don't use this sub for any | |
81 | # other thing than a quick scan! | |
82 | # | |
83 | sub all_items_simple { | |
84 | my ($self, $path) = @_; | |
85 | $path ||= ''; | |
86 | $path =~ s/"/\\"/g; | |
87 | ||
88 | return $self->_mpd->_cooked_command_as_items( qq[listall "$path"\n] ); | |
89 | } | |
90 | ||
91 | ||
92 | # | |
93 | # my @items = $collection->items_in_dir( [$path] ); | |
94 | # | |
95 | # Return the items in the given $path. If no $path supplied, do it on mpd's | |
96 | # root directory. | |
97 | # | |
98 | # Note that this sub does not work recusrively on all directories. | |
99 | # | |
100 | sub items_in_dir { | |
101 | my ($self, $path) = @_; | |
102 | $path ||= ''; | |
103 | $path =~ s/"/\\"/g; | |
104 | ||
105 | return $self->_mpd->_cooked_command_as_items( qq[lsinfo "$path"\n] ); | |
106 | } | |
107 | ||
108 | ||
109 | ||
110 | # -- Collection: retrieving the whole collection | |
111 | ||
112 | # | |
113 | # my @songs = $collection->all_songs( [$path] ); | |
114 | # | |
115 | # Return *all* AMC::Item::Songs currently known by mpd. | |
116 | # | |
117 | # If $path is supplied (relative to mpd root), restrict the retrieval to | |
118 | # songs and dirs in this directory. | |
119 | # | |
120 | sub all_songs { | |
121 | my ($self, $path) = @_; | |
122 | return grep { $_->isa('Audio::MPD::Common::Item::Song') } $self->all_items($path); | |
123 | } | |
124 | ||
125 | ||
126 | # | |
127 | # my @albums = $collection->all_albums; | |
128 | # | |
129 | # Return the list of all albums (strings) currently known by mpd. | |
130 | # | |
131 | sub all_albums { | |
132 | my ($self) = @_; | |
133 | return $self->_mpd->_cooked_command_strip_first_field( "list album\n" ); | |
134 | } | |
135 | ||
136 | ||
137 | # | |
138 | # my @artists = $collection->all_artists; | |
139 | # | |
140 | # Return the list of all artists (strings) currently known by mpd. | |
141 | # | |
142 | sub all_artists { | |
143 | my ($self) = @_; | |
144 | return $self->_mpd->_cooked_command_strip_first_field( "list artist\n" ); | |
145 | } | |
146 | ||
147 | ||
148 | # | |
149 | # my @titles = $collection->all_titles; | |
150 | # | |
151 | # Return the list of all titles (strings) currently known by mpd. | |
152 | # | |
153 | sub all_titles { | |
154 | my ($self) = @_; | |
155 | return $self->_mpd->_cooked_command_strip_first_field( "list title\n" ); | |
156 | } | |
157 | ||
158 | ||
159 | # | |
160 | # my @genre = $collection->all_genre; | |
161 | # | |
162 | # Return the list of all genres (strings) currently known by mpd. | |
163 | # | |
164 | sub all_genre { | |
165 | my ($self) = @_; | |
166 | return $self->_mpd->_cooked_command_strip_first_field( "list genre\n" ); | |
167 | } | |
168 | ||
169 | ||
170 | # | |
171 | # my @yers = $collection->all_years; | |
172 | # | |
173 | # Return the list of all years (strings) currently known by mpd. | |
174 | # | |
175 | sub all_years { | |
176 | my ($self) = @_; | |
177 | return $self->_mpd->_cooked_command_strip_first_field( "list date\n" ); | |
178 | } | |
179 | ||
180 | ||
181 | # | |
182 | # my @pathes = $collection->all_pathes; | |
183 | # | |
184 | # Return the list of all pathes (strings) currently known by mpd. | |
185 | # | |
186 | sub all_pathes { | |
187 | my ($self) = @_; | |
188 | return $self->_mpd->_cooked_command_strip_first_field( "list filename\n" ); | |
189 | } | |
190 | ||
191 | ||
192 | # | |
193 | # my @items = $collection->all_playlists; | |
194 | # | |
195 | # Return the list of playlists (strings) currently known by mpd. | |
196 | # | |
197 | sub all_playlists { | |
198 | my ($self) = @_; | |
199 | ||
200 | return | |
201 | map { /^playlist: (.*)$/ ? ($1) : () } | |
202 | $self->_mpd->_send_command( "lsinfo\n" ); | |
203 | } | |
204 | ||
205 | ||
206 | ||
207 | # -- Collection: picking songs | |
208 | ||
209 | # | |
210 | # my $song = $collection->song( $path ); | |
211 | # | |
212 | # Return the AMC::Item::Song which correspond to $path. | |
213 | # | |
214 | sub song { | |
215 | my ($self, $what) = @_; | |
216 | $what =~ s/"/\\"/g; | |
217 | ||
218 | my ($item) = $self->_mpd->_cooked_command_as_items( qq[find filename "$what"\n] ); | |
219 | return $item; | |
220 | } | |
221 | ||
222 | ||
223 | # | |
224 | # my $song = $collection->songs_with_filename_partial( $path ); | |
225 | # | |
226 | # Return the AMC::Item::Songs containing $string in their path. | |
227 | # | |
228 | sub songs_with_filename_partial { | |
229 | my ($self, $what) = @_; | |
230 | $what =~ s/"/\\"/g; | |
231 | ||
232 | return $self->_mpd->_cooked_command_as_items( qq[search filename "$what"\n] ); | |
233 | } | |
234 | ||
235 | ||
236 | # -- Collection: songs, albums & artists relations | |
237 | ||
238 | # | |
239 | # my @albums = $collection->albums_by_artist($artist); | |
240 | # | |
241 | # Return all albums (strings) performed by $artist or where $artist | |
242 | # participated. | |
243 | # | |
244 | sub albums_by_artist { | |
245 | my ($self, $artist) = @_; | |
246 | $artist =~ s/"/\\"/g; | |
247 | return $self->_mpd->_cooked_command_strip_first_field( qq[list album "$artist"\n] ); | |
248 | } | |
249 | ||
250 | ||
251 | # | |
252 | # my @songs = $collection->songs_by_artist( $genre ); | |
253 | # | |
254 | # Return all AMC::Item::Songs performed in $genre. | |
255 | # | |
256 | ||
257 | sub songs_by_genre { | |
258 | my ($self, $what) = @_; | |
259 | $what =~ s/"/\\"/g; | |
260 | ||
261 | return $self->_mpd->_cooked_command_as_items( qq[find genre "$what"\n] ); | |
262 | } | |
263 | ||
264 | ||
265 | sub filenames_by_artist { | |
266 | my ($self, $what) = @_; | |
267 | $what =~ s/"/\\"/g; | |
268 | ||
269 | return $self->_mpd->_cooked_command_as_filename( qq[find artist "$what"\n] ); | |
270 | } | |
271 | ||
272 | ||
273 | sub filenames_by_year { | |
274 | my ($self, $what) = @_; | |
275 | $what =~ s/"/\\"/g; | |
276 | ||
277 | return $self->_mpd->_cooked_command_as_filename( qq[find date "$what"\n] ); | |
278 | } | |
279 | ||
280 | sub filenames_by_genre { | |
281 | my ($self, $what) = @_; | |
282 | $what =~ s/"/\\"/g; | |
283 | ||
284 | return $self->_mpd->_cooked_command_as_filename( qq[find genre "$what"\n] ); | |
285 | } | |
286 | ||
287 | ||
288 | sub filenames_by_album { | |
289 | my ($self, $what) = @_; | |
290 | $what =~ s/"/\\"/g; | |
291 | ||
292 | return $self->_mpd->_cooked_command_as_filename( qq[find album "$what"\n] ); | |
293 | } | |
294 | ||
295 | ||
296 | # | |
297 | # my @songs = $collection->songs_by_artist_partial( $string ); | |
298 | # | |
299 | # Return all AMC::Item::Songs performed by an artist with $string | |
300 | # in her name. | |
301 | # | |
302 | sub songs_by_artist_partial { | |
303 | my ($self, $what) = @_; | |
304 | $what =~ s/"/\\"/g; | |
305 | ||
306 | return $self->_mpd->_cooked_command_as_items( qq[search artist "$what"\n] ); | |
307 | } | |
308 | ||
309 | ||
310 | # | |
311 | # my @songs = $collection->songs_from_album( $album ); | |
312 | # | |
313 | # Return all AMC::Item::Songs appearing in $album. | |
314 | # | |
315 | sub songs_from_album { | |
316 | my ($self, $what) = @_; | |
317 | $what =~ s/"/\\"/g; | |
318 | ||
319 | return $self->_mpd->_cooked_command_as_items( qq[find album "$what"\n] ); | |
320 | } | |
321 | ||
322 | ||
323 | # | |
324 | # my @songs = $collection->songs_from_album_partial( $string ); | |
325 | # | |
326 | # Return all AMC::Item::Songs appearing in album containing $string. | |
327 | # | |
328 | sub songs_from_album_partial { | |
329 | my ($self, $what) = @_; | |
330 | $what =~ s/"/\\"/g; | |
331 | ||
332 | return $self->_mpd->_cooked_command_as_items( qq[search album "$what"\n] ); | |
333 | } | |
334 | ||
335 | ||
336 | # | |
337 | # my @songs = $collection->songs_with_title( $title ); | |
338 | # | |
339 | # Return all AMC::Item::Songs which title is exactly $title. | |
340 | # | |
341 | sub songs_with_title { | |
342 | my ($self, $what) = @_; | |
343 | $what =~ s/"/\\"/g; | |
344 | ||
345 | return $self->_mpd->_cooked_command_as_items( qq[find title "$what"\n] ); | |
346 | } | |
347 | ||
348 | ||
349 | # | |
350 | # my @songs = $collection->songs_with_title_partial( $string ); | |
351 | # | |
352 | # Return all AMC::Item::Songs where $string is part of the title. | |
353 | # | |
354 | sub songs_with_title_partial { | |
355 | my ($self, $what) = @_; | |
356 | $what =~ s/"/\\"/g; | |
357 | ||
358 | return $self->_mpd->_cooked_command_as_items( qq[search title "$what"\n] ); | |
359 | } | |
360 | ||
361 | ||
362 | # my @songs = $collection->songs_with_title_partial_filename( $string ); | |
363 | # | |
364 | # Return all AMC::Item::Songs where $string is part of the title. | |
365 | # | |
366 | sub songs_with_title_partial_filename { | |
367 | my ($self, $what) = @_; | |
368 | $what =~ s/"/\\"/g; | |
369 | ||
370 | ||
371 | return $self->_mpd->_cooked_command_as_filename( qq[search title "$what"\n] ); | |
372 | } | |
373 | ||
374 | # my @songs = $collection->songs_with_artist_partial_filename( $string ); | |
375 | # | |
376 | # Return all AMC::Item::Songs where $string is part of the artist. | |
377 | # | |
378 | sub songs_with_artist_partial_filename { | |
379 | my ($self, $what) = @_; | |
380 | $what =~ s/"/\\"/g; | |
381 | ||
382 | return $self->_mpd->_cooked_command_as_filename( qq[search artist "$what"\n] ); | |
383 | } | |
384 | ||
385 | ||
386 | # my @songs = $collection->songs_with_album_partial_filename( $string ); | |
387 | # | |
388 | # Return all AMC::Item::Songs where $string is part of the album. | |
389 | # | |
390 | sub songs_with_album_partial_filename { | |
391 | my ($self, $what) = @_; | |
392 | $what =~ s/"/\\"/g; | |
393 | ||
394 | return $self->_mpd->_cooked_command_as_filename( qq[search album "$what"\n] ); | |
395 | } | |
396 | ||
397 | ||
398 | 1; | |
399 | ||
400 | __END__ | |
401 | ||
402 | ||
403 | =head1 NAME | |
404 | ||
405 | Audio::MPD::Collection - an object to query MPD's collection | |
406 | ||
407 | ||
408 | =head1 SYNOPSIS | |
409 | ||
410 | my $song = $mpd->collection->random_song; | |
411 | ||
412 | ||
413 | =head1 DESCRIPTION | |
414 | ||
415 | C<Audio::MPD::Collection> is a class meant to access & query MPD's | |
416 | collection. You will be able to use those high-level methods instead | |
417 | of using the low-level methods provided by mpd itself. | |
418 | ||
419 | ||
420 | =head1 PUBLIC METHODS | |
421 | ||
422 | =head2 Constructor | |
423 | ||
424 | =over 4 | |
425 | ||
426 | =item new( $mpd ) | |
427 | ||
428 | This will create the object, holding a back-reference to the C<Audio::MPD> | |
429 | object itself (for communication purposes). But in order to play safe and | |
430 | to free the memory in time, this reference is weakened. | |
431 | ||
432 | Note that you're not supposed to call this constructor yourself, an | |
433 | C<Audio::MPD::Collection> is automatically created for you during the creation | |
434 | of an C<Audio::MPD> object. | |
435 | ||
436 | =back | |
437 | ||
438 | ||
439 | =head2 Retrieving songs & directories | |
440 | ||
441 | =over 4 | |
442 | ||
443 | =item $coll->all_items( [$path] ) | |
444 | ||
445 | Return B<all> C<Audio::MPD::Common::Item>s (both songs & directories) | |
446 | currently known by mpd. | |
447 | ||
448 | If C<$path> is supplied (relative to mpd root), restrict the retrieval to | |
449 | songs and dirs in this directory. | |
450 | ||
451 | ||
452 | =item $coll->all_items_simple( [$path] ) | |
453 | ||
454 | Return B<all> C<Audio::MPD::Common::Item>s (both songs & directories) | |
455 | currently known by mpd. | |
456 | ||
457 | If C<$path> is supplied (relative to mpd root), restrict the retrieval to | |
458 | songs and dirs in this directory. | |
459 | ||
460 | B</!\ Warning>: the C<Audio::MPD::Common::Item::Song> objects will only have | |
461 | their tag file filled. Any other tag will be empty, so don't use this sub for | |
462 | any other thing than a quick scan! | |
463 | ||
464 | ||
465 | =item $coll->items_in_dir( [$path] ) | |
466 | ||
467 | Return the items in the given C<$path>. If no C<$path> supplied, do it on | |
468 | mpd's root directory. | |
469 | ||
470 | Note that this sub does not work recusrively on all directories. | |
471 | ||
472 | ||
473 | =back | |
474 | ||
475 | ||
476 | =head2 Retrieving the whole collection | |
477 | ||
478 | =over 4 | |
479 | ||
480 | =item $coll->all_songs( [$path] ) | |
481 | ||
482 | Return B<all> C<Audio::MPD::Common::Item::Song>s currently known by mpd. | |
483 | ||
484 | If C<$path> is supplied (relative to mpd root), restrict the retrieval to | |
485 | songs and dirs in this directory. | |
486 | ||
487 | ||
488 | =item $coll->all_albums() | |
489 | ||
490 | Return the list of all albums (strings) currently known by mpd. | |
491 | ||
492 | ||
493 | =item $coll->all_artists() | |
494 | ||
495 | Return the list of all artists (strings) currently known by mpd. | |
496 | ||
497 | ||
498 | =item $coll->all_titles() | |
499 | ||
500 | Return the list of all song titles (strings) currently known by mpd. | |
501 | ||
502 | ||
503 | =item $coll->all_pathes() | |
504 | ||
505 | Return the list of all pathes (strings) currently known by mpd. | |
506 | ||
507 | ||
508 | =item $coll->all_playlists() | |
509 | ||
510 | Return the list of all playlists (strings) currently known by mpd. | |
511 | ||
512 | ||
513 | =back | |
514 | ||
515 | ||
516 | =head2 Picking a song | |
517 | ||
518 | =over 4 | |
519 | ||
520 | =item $coll->song( $path ) | |
521 | ||
522 | Return the C<Audio::MPD::Common::Item::Song> which correspond to C<$path>. | |
523 | ||
524 | ||
525 | =item $coll->songs_with_filename_partial( $path ) | |
526 | ||
527 | Return the C<Audio::MPD::Common::Item::Song>s containing $string in their path. | |
528 | ||
529 | ||
530 | =back | |
531 | ||
532 | ||
533 | =head2 Songs, albums & artists relations | |
534 | ||
535 | =over 4 | |
536 | ||
537 | =item $coll->albums_by_artist( $artist ) | |
538 | ||
539 | Return all albums (strings) performed by C<$artist> or where C<$artist> | |
540 | participated. | |
541 | ||
542 | ||
543 | =item $coll->songs_by_artist( $artist ) | |
544 | ||
545 | Return all C<Audio::MPD::Common::Item::Song>s performed by C<$artist>. | |
546 | ||
547 | ||
548 | =item $coll->songs_by_artist_partial( $string ) | |
549 | ||
550 | Return all C<Audio::MPD::Common::Item::Song>s performed by an artist with | |
551 | C<$string> in her name. | |
552 | ||
553 | ||
554 | =item $coll->songs_from_album( $album ) | |
555 | ||
556 | Return all C<Audio::MPD::Common::Item::Song>s appearing in C<$album>. | |
557 | ||
558 | ||
559 | =item $coll->songs_from_album_partial( $string ) | |
560 | ||
561 | Return all C<Audio::MPD::Common::Item::Song>s appearing in album containing C<$string>. | |
562 | ||
563 | ||
564 | =item $coll->songs_with_title( $title ) | |
565 | ||
566 | Return all C<Audio::MPD::Common::Item::Song>s which title is exactly C<$title>. | |
567 | ||
568 | ||
569 | =item $coll->songs_with_title_partial( $string ) | |
570 | ||
571 | Return all C<Audio::MPD::Common::Item::Song>s where C<$string> is part of the title. | |
572 | ||
573 | ||
574 | =back | |
575 | ||
576 | ||
577 | =head1 SEE ALSO | |
578 | ||
579 | L<Audio::MPD> | |
580 | ||
581 | ||
582 | =head1 AUTHOR | |
583 | ||
584 | Jerome Quelin, C<< <jquelin at cpan.org> >> | |
585 | ||
586 | ||
587 | =head1 COPYRIGHT & LICENSE | |
588 | ||
589 | Copyright (c) 2007 Jerome Quelin, all rights reserved. | |
590 | ||
591 | This program is free software; you can redistribute it and/or modify | |
592 | it under the same terms as Perl itself. | |
593 | ||
594 | =cut |