Audio-MPD-1.120610000755000764000144 011723631714 13423 5ustar00jquelinusers000000000000TODO100644000764000144 152711723631714 14201 0ustar00jquelinusers000000000000Audio-MPD-1.120610no time plan associated - not even an order implied. ** distribution: - sign module using Module::Signature. ** module enhancements - implementing missing methods in am::collection (random, etc.) . artists_matching (yup, no way to have it with mpd's api) . albums_matching (ditto) . random_song / random_songs . songs_by_artist_from_album . songs_by_artist_without_album . songs_without_artist - extending and harmonizing subs in am::playlist (add() should allow multiple arguments, for example) - what about improving am::* to allow for auto-update? ** dialog with mpd - more extensive coverage of supported mpd instruction set. - better communication with mpd (including auto-reconnect). ** mpd scripts: - mpd proxy adding song ratings on-the-fly. - small daemon watching collection dir (inotify) and updating mpd README100644000764000144 47511723631714 14352 0ustar00jquelinusers000000000000Audio-MPD-1.120610 This archive contains the distribution Audio-MPD, version 1.120610: class to talk to MPD (Music Player Daemon) servers This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. AUTHORS100644000764000144 40511723631714 14533 0ustar00jquelinusers000000000000Audio-MPD-1.120610Jerome Quelin Original authors: Tue Abrahamsen (code) Nicholas J Humfrey (doc) With thanks to: msells sbh hannes Dale Francum Laurent Monrouzies Martin Stolle William Pettersson Changes100644000764000144 2776011723631714 15033 0ustar00jquelinusers000000000000Audio-MPD-1.120610Changelog for Audio-MPD 1.120610 2012-03-01 09:31:01 Europe/Paris - fix rt#75436 - mpd-rate and mpd-dynamic should fail gracefully when no song is playing (florian) - fix rt#75437 - fix mpd-rate and mpd-dynamic pod names 1.113280 2011-11-24 15:07:47 Europe/Paris - fix rt#68357 - ipv6 support - fix rt#71201 - url handlers can vary with mpd installation - fix rt#71202 - requiring software mixer for tests - tests for all_genres, artists_by_genre (sebastien nobili) - better namespace for scripts 1.112670 2011-09-24 11:40:44 Europe/Paris - collection: new method all_genres (sebastien nobili) - collection: new method artists_by_genre (sebastien nobili) 1.111200 2011-04-30 10:21:31 Europe/Paris - removing misleading example in pod 1.110560 2011-02-25 15:28:59 Europe/Paris - new command available: outputs 1.102260 2010-08-14 19:21:51 Europe/Paris - new script mpd-rate to rate a song / display current rating 1.100430 2010-02-12 12:51:18 Europe/Paris - WARNING: no more makefile.pl supplied, only a build.pl - sub::exporter no more used internally 1.093170 Fri Nov 13 19:06:54 2009 - removed no more used prereq class::accessor - revamped pod with podweaver - introducing audio::mpd::types - using moosex::has::sugar 1.092950 Thu Oct 22 19:34:35 2009 - module is quite stable now, bumping to 1.yydddn version - migrated to moose - password() method renamed to set_password() - no more vars exported, use 'reuse' and 'once' strings for conntype ** 0.19.10 Wed Oct 21 14:20:09 2009 - update list of static prereqs, not caught by autoprereq - bump min version for test-corpus-audio-mpd 0.19.9 Sun Oct 18 11:49:57 2009 - using test::corpus::audio::mpd for tests (regains mpd 0.15.x compatibility) 0.19.8 Wed Oct 14 18:05:29 2009 - migrated to dist-zilla (transparent for end-user) 0.19.7 Wed Sep 30 16:56:37 2009 - fix #50109 problem with newer class::accessor 0.19.6 Sat Feb 14 13:03:22 CET 2009 - doc update (catched by streamingmeemee) 0.19.5 Mon Jan 5 15:31:29 CET 2009 - updated to match mpd 0.14 behaviour - doc update 0.19.4 Sat Aug 16 10:38:12 CEST 2008 - doc update - listing mpd-dynamic script prereqs as module prereqs 0.19.3 Tue Aug 12 19:04:23 CEST 2008 - version() reports *protocol* version, not real mpd version - fix some tests that failed because of detection method not precise enough (timing issues) 0.19.2 Tue Jun 17 19:24:16 CEST 2008 - mpd-dynamic should lookup ratings with utf8 encoded pathes 0.19.1 Mon Dec 3 18:23:58 CET 2007 - new method all_playlists() (courtesy of Joey Hess) - fix for filenames / playlists beginning with a space (courtesy of Joey Hess) 0.19.0 Thu Nov 29 20:10:18 CET 2007 - changed constructor api: using a hash for options instead of positional paraemters - new conntype param for constructor to change the way connection is handled - MPD_HOST env var supports password@host - mpd-dynamic daemonizes after mpd connection to trap problems ** 0.18.3 Mon Nov 26 12:51:40 CET 2007 - kwalitee/cpants release 0.18.2 Tue Nov 13 20:20:59 CET 2007 - fixing bug 29232 (courtesy of David Bitseff) 0.18.1 Thu May 31 20:57:47 CEST 2007 - fixing mantis bug #556: support for multiple $path in playlist->add 0.18.0 Wed May 30 12:29:11 CEST 2007 - moved to perl license - using common classes outsourced in audio::mpd::common, namely: item*, stats, status and time. - new methods AM::Collection::all_songs() ** 0.17.2 Sun Apr 8 15:35:43 CEST 2007 - introducing AM::Stats for better encapsulation 0.17.1 Sun Apr 8 12:23:53 CEST 2007 - introducing AM::Time for better encapsulation - thus, removed get_time_info() and get_time_format() - test coverage up to 100% \o/ 0.17.0 Fri Apr 6 16:54:07 CEST 2007 - introducing AM::Playlist for better segregation of playlist handling - completed tests to cover all playlist operations, AM is now 95.1% covered ** 0.16.2 Tue Apr 3 19:02:29 CEST 2007 - utf-8 support generalized 0.16.1 Mon Apr 2 18:26:17 CEST 2007 - new internal _cooked_command_*() methods, allowing for better code factorization - and thus, better code coverage (100% achieved for am::collection, 89.3% overall) 0.16.0 Thu Mar 29 19:04:34 CEST 2007 - script to listen your music endlessly: mpd-dynamic ** 0.15.4 Tue Mar 27 18:42:58 CEST 2007 - AM::Test more robust regarding fake mpd startup - AM::Test quicker if no tests performed - new methods in AM::Collection: . songs_with_filename_partial() . songs_by_artist_partial() . songs_from_album_partial() . songs_with_title_partial() 0.15.3 Wed Mar 21 18:08:06 CET 2007 - requiring perl 5.8.x minimum 0.15.2 Tue Mar 20 17:24:59 CET 2007 - fixed bug #25553 (on rt.cpan.org) 0.15.1 Sun Mar 18 19:06:57 CET 2007 - added Readonly as prereq 0.15.0 Sat Mar 17 17:49:50 CET 2007 - implementation of Audio::MPD::Collection: this class will act as the entry point to look up in mpd's collection - thus, following AM methods removed (see AM::Collection for the replacement): . list() . listall() . listallinfo() . lsinfo() . search() . searchadd() - now that AM::Collection is here, AM's test coverage is up to 82.5% \o/ ** 0.14.0 Sat Mar 17 13:29:57 CET 2007 - implementation of Audio::MPD::Item: instead of returning some random hash reference, Audio::MPD now returns AMI objects. - renamed methods: . get_current_song() -> current() . get_song_info() -> song() . get_song_info_from_id() -> songid() . get_title() -> AMI::Song::as_string() . pl_changes() -> pl_changes() - pl_changes() now return an array ref instead of a hash with positions as key - test coverage of Audio::MPD up to 66.5% ** 0.13.5 Thu Mar 8 20:22:32 CET 2007 - get_urlhandlers() renamed to urlhandlers() - seekid() defaults to current song - pod enhancement - test coverage of Audio::MPD up to 36.1% 0.13.4 Tue Mar 6 20:05:21 CET 2007 - new method password() to change mpd password - bug fix in deleteid() (was issuing "delete") and crop() (should be done in reverse order to keep mpd happy) - test coverage of Audio::MPD up to 36.1% 0.13.3 Sun Mar 4 19:30:24 CET 2007 - bug fix on volume() method 0.13.2 Sun Mar 4 10:17:50 CET 2007 - Makefile.PL now uses ExtUtils::MakeMaker instead of perverting Module::Builder - bugfix in play() / playid() - testing Audio::MPD::Status up to 100% - testing Audio::MPD = 24.5% 0.13.1 - status() now returns an Audio::MPD::Status object, for better encapsulation - added dependancy on Class::Accessor 0.13.0 Fri Mar 2 12:55:38 CET 2007 - connection completely reworked to get rid of the most obvious problems note: this does not mean that we're completely clean, but at least it's better than what it was. - is_connected() and close_connection() are no more needed, and thus removed - error handling is now done via die - get_error() is gone - play(), delete(), move(), get_song_info(), seek() & swap() do not accept a third fromid parameter anymore - pause() now toggle pause status if no parameter is sent - renamed methods: . kill_mpd() -> kill() . get_server_version() -> version() . set_fade() -> fade() . set_random() -> random() . set_repeat() -> repeat() . set_volume() -> volume() - new methods: stats(), status() - delete() and deleteid() can take more than one song to delete ** 0.12.4 Thu Jan 25 21:52:05 CET 2007 [JQ] - grouped pod in sections for easier reading - corrected pod typos here and there - added contact information - new tests for pod correctness and pod coverage - added missing pod for 3 subs 0.12.3 (Nicholas J Humfrey) - Added Makefile.PL support 0.12.2 (Nicholas J Humfrey) - Fixed bug in parsing parmeters in pause() 0.12.0-rc7+njh (Nicholas J Humfrey) - Moved $sock and @playlists into object so that you can talk to multiple MPDs in the same script. - Added Module::Build based build/install system - Changed namespace to Audio::MPD so that it can be added to CPAN - Documented class - Changing 'END' handler to 'DESTROY' - Changed <$sock> to $sock->getline - Changed print $sock "foo" to $sock->print("foo") - Corrected pause() so that it didn't use depricated lack of argument - Added optional path parameter to updatedb() 0.12.0-rc7 - better password-handling, including possibility to connect to password@mpdhost (William Pettersson) - made get_time_info work, and added more to the output - made ALLOW_TOGGLE_STATES 1 by default 0.12.0-rc6 - get_song_info() now uses current song, if none is specified - mpc.pl now says that 'seek' is in seconds instead of percentage - Fixed bug in close() - Removed warn() in _get_playlist() - Made MPD.pm more backwards compatible (Martin Stolle) - Added get_current_song_info() (Martin Stolle) - Made internal sub _process_feedback() more robust (Martin Stolle) - Update get_title() to be more flexible (Martin Stolle) 0.12.0-rc5 (No more fires!-release) - Fixed bug in save() (Laurent Monrouzies) - Removed annoying line in set_random() (Dale Francum) - Added get_time_info (Thanks Dale Francum) - Removed 'use Data::Dumper;' from mpc.pl and MPD.pm - Added support for new MPD-functions: 'outputs', 'enableoutputs', 'disableoutputs', 'commands' and 'notcommands' - Fixed bug in get_title() where old title would get returned - Fixed bug where playlist was not updated (hannes) - Added playlist_changes() so clients can update their playlist (hannes) - Updated _get_playlist() (hannes) 0.12.0-rc4 - Old bug where $playlist[0] contained undef removed again :) - crop() function added (removes all songs but the playing) - Fixed some bugs and errorhandling in mpc.pl 0.12.0-rc3 - (almost) total rewrite of module 0.12.0-rc2 - Changed default port to 6600 - Removed UNPAUSE_ON_PLAY setting, as this is now default in MPD - Added urlhandlers() - Fixed seek() - Small bugfixes - Bugfixes in mpc.pl (playlist() and volume()) - Updated ACK-error handling (geterror() changed, seterror() added) - Add 'plchanges'-support in getplaylist() - Added $config{'ALLOW_TOGGLE_STATES'} - Added deleteid() / moveid() / playid() / seekid() / swapid() - Removed deprecated 'unpause-on-play'-code ** 0.10.0-rc1 - No changes 0.10.0-alpha7 - Major speedup. Playlist was fetched way too many times - Another major speedup. Playlist is now only fetched when needed! - Added %config, for changing default behavior - Old $number-- in play() was removed. - Stupid bug where last song was not saved in @playlist removed - Rewrote searchadd() to utilize 'command_list_begin'/'command_list_end' (Much faster now) - Fixed bug where search() didn't return the last song found - Small rewrite in setrepeat() and setrandom() - Typos - Fixed bugs and bugs and bugs and bugs - Added a destructor - Rewrote all pod-documentation - Tabindented all - Removed 'unfinished subs' and 'todo' - Probably more stuff 0.10.0-alpha6 - Changed @playlist syntax ($pl[song-number]{info-to-get} eg. $pl[42]{'file'}) - Removed deprecated getsonginfo() - Moved gettitle() and gettimeformat() to 'Custom subs' - Altered gettitle()'s errorhandling a bit 0.10.0-alpha5 - Made getsonginfo() return a hash instead of an array - Streamlined add()/delete()/move()/swap() - Made (almost) all functions undef on succes and 1 on error. Last error can be retrieved by $self->geterror() - search() now accepts filenames too (thanks sbh) - delete() can take ranges (thanks sbh) - Added the 'Custom functions'-part - Added searchadd() (thanks sbh) - Repaired add() - Added playlist() 0.10.0-alpha4 - Fixed bug where last song on playlist was not present - Made getstatus() call playlistinfo if playlist had changed - Implemented getsonginfo() for returning information from @playlist (Thanks msells) - Added $self->{module_version} - Empties @playlist, when renewing it - A bit of optimizing and cleanup around getplaylist (Thanks msells) 0.10.0-alpha3 - Fixed error in add()-comments - Moved $host and $port parameter to new() - It finally works! 0.10.0-alpha2 - Added nextinfo() and changed lsinfo() and listallinfo() - Changed version-numbering to fit MPD standards ** 0.1 - Initial release LICENSE100644000764000144 4365611723631714 14547 0ustar00jquelinusers000000000000Audio-MPD-1.120610This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2007 by Jerome Quelin. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2007 by Jerome Quelin. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End dist.ini100644000764000144 74411723631714 15135 0ustar00jquelinusers000000000000Audio-MPD-1.120610name = Audio-MPD author = Jerome Quelin license = Perl_5 copyright_holder = Jerome Quelin copyright_year = 2007 ; -- static meta-information [MetaResources] homepage = http://search.cpan.org/dist/Audio-MPD repository = http://github.com/jquelin/audio-mpd x_mailing_list = http://groups.google.com/group/audio-mpd [Prereqs / TestRequires] Test::Corpus::Audio::MPD = 1.113282 ; software mixer, ipv6, genre tag [@Filter] -bundle = @JQUELIN -remove = ReportVersions META.yml100644000764000144 1515311723631714 15002 0ustar00jquelinusers000000000000Audio-MPD-1.120610--- abstract: 'class to talk to MPD (Music Player Daemon) servers' author: - 'Jerome Quelin' build_requires: File::Find: 0 File::Temp: 0 Module::Build: 0.3601 Test::Corpus::Audio::MPD: 1.113282 Test::More: 0.88 configure_requires: Module::Build: 0.3601 dynamic_config: 0 generated_by: 'Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120351' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Audio-MPD provides: Audio::MPD: file: lib/Audio/MPD.pm version: 1.120610 Audio::MPD::Collection: file: lib/Audio/MPD/Collection.pm version: 1.120610 Audio::MPD::Playlist: file: lib/Audio/MPD/Playlist.pm version: 1.120610 Audio::MPD::Types: file: lib/Audio/MPD/Types.pm version: 1.120610 requires: Audio::MPD::Common::Item: 0 Audio::MPD::Common::Output: 0 Audio::MPD::Common::Stats: 0 Audio::MPD::Common::Status: 0 DB_File: 0 Encode: 0 Getopt::Euclid: 0 IO::Socket::IP: 0 Moose: 0 Moose::Util::TypeConstraints: 0 MooseX::Has::Sugar: 0 MooseX::SemiAffordanceAccessor: 0 Proc::Daemon: 0 Time::HiRes: 0 perl: 5.010 strict: 0 warnings: 0 resources: X_mailing_list: http://groups.google.com/group/audio-mpd bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Audio-MPD homepage: http://search.cpan.org/dist/Audio-MPD/ repository: git://github.com/jquelin/audio-mpd.git version: 1.120610 x_Dist_Zilla: plugins: - class: Dist::Zilla::Plugin::MetaResources name: MetaResources version: 4.300009 - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: test type: requires name: TestRequires version: 4.300009 - class: Dist::Zilla::Plugin::AutoVersion name: '@Filter/AutoVersion' version: 4.300009 - class: Dist::Zilla::Plugin::GatherDir name: '@Filter/GatherDir' version: 4.300009 - class: Dist::Zilla::Plugin::CompileTests name: '@Filter/CompileTests' version: 1.112820 - class: Dist::Zilla::Plugin::HasVersionTests name: '@Filter/HasVersionTests' version: 1.101420 - class: Dist::Zilla::Plugin::KwaliteeTests name: '@Filter/KwaliteeTests' version: 2.03 - class: Dist::Zilla::Plugin::MinimumVersionTests name: '@Filter/MinimumVersionTests' version: 2.0.1 - class: Dist::Zilla::Plugin::PodCoverageTests name: '@Filter/PodCoverageTests' version: 4.300009 - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@Filter/PodSyntaxTests' version: 4.300009 - class: Dist::Zilla::Plugin::ReportVersions::Tiny name: '@Filter/ReportVersions::Tiny' version: 1.03 - class: Dist::Zilla::Plugin::PruneCruft name: '@Filter/PruneCruft' version: 4.300009 - class: Dist::Zilla::Plugin::PruneFiles name: '@Filter/PruneFiles' version: 4.300009 - class: Dist::Zilla::Plugin::ManifestSkip name: '@Filter/ManifestSkip' version: 4.300009 - class: Dist::Zilla::Plugin::AutoPrereqs name: '@Filter/AutoPrereqs' version: 4.300009 - class: Dist::Zilla::Plugin::ExtraTests name: '@Filter/ExtraTests' version: 4.300009 - class: Dist::Zilla::Plugin::NextRelease name: '@Filter/NextRelease' version: 4.300009 - class: Dist::Zilla::Plugin::PkgVersion name: '@Filter/PkgVersion' version: 4.300009 - class: Dist::Zilla::Plugin::PodWeaver name: '@Filter/PodWeaver' version: 3.101641 - class: Dist::Zilla::Plugin::Prepender name: '@Filter/Prepender' version: 1.112280 - class: Dist::Zilla::Plugin::ExecDir name: '@Filter/ExecDir' version: 4.300009 - class: Dist::Zilla::Plugin::ShareDir name: '@Filter/ShareDir' version: 4.300009 - class: Dist::Zilla::Plugin::Bugtracker name: '@Filter/Bugtracker' version: 1.111080 - class: Dist::Zilla::Plugin::Homepage name: '@Filter/Homepage' version: 1.101420 - class: Dist::Zilla::Plugin::Repository name: '@Filter/Repository' version: 0.18 - class: Dist::Zilla::Plugin::MetaProvides::Package name: '@Filter/MetaProvides::Package' version: 1.12060501 - class: Dist::Zilla::Plugin::MetaConfig name: '@Filter/MetaConfig' version: 4.300009 - class: Dist::Zilla::Plugin::License name: '@Filter/License' version: 4.300009 - class: Dist::Zilla::Plugin::MetaYAML name: '@Filter/MetaYAML' version: 4.300009 - class: Dist::Zilla::Plugin::MetaJSON name: '@Filter/MetaJSON' version: 4.300009 - class: Dist::Zilla::Plugin::ModuleBuild name: '@Filter/ModuleBuild' version: 4.300009 - class: Dist::Zilla::Plugin::Readme name: '@Filter/Readme' version: 4.300009 - class: Dist::Zilla::Plugin::Manifest name: '@Filter/Manifest' version: 4.300009 - class: Dist::Zilla::Plugin::CheckChangeLog name: '@Filter/CheckChangeLog' version: 0.01 - class: Dist::Zilla::Plugin::Git::Check name: '@Filter/Git::Check' version: 1.113560 - class: Dist::Zilla::Plugin::Git::Commit name: '@Filter/Git::Commit' version: 1.113560 - class: Dist::Zilla::Plugin::Git::CommitBuild name: '@Filter/Git::CommitBuild' version: 1.113560 - class: Dist::Zilla::Plugin::Git::Tag name: '@Filter/TagMaster' version: 1.113560 - class: Dist::Zilla::Plugin::Git::Tag name: '@Filter/TagRelease' version: 1.113560 - class: Dist::Zilla::Plugin::Git::Push name: '@Filter/Git::Push' version: 1.113560 - class: Dist::Zilla::Plugin::UploadToCPAN name: '@Filter/UploadToCPAN' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' version: 4.300009 - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' version: 4.300009 zilla: class: Dist::Zilla::Dist::Builder config: is_trial: 0 version: 4.300009 MANIFEST100644000764000144 105111723631714 14632 0ustar00jquelinusers000000000000Audio-MPD-1.120610AUTHORS Build.PL Changes LICENSE MANIFEST META.json META.yml README TODO bin/mpd-dynamic bin/mpd-rate dist.ini examples/example.pl examples/mpc.pl lib/Audio/MPD.pm lib/Audio/MPD/Collection.pm lib/Audio/MPD/Playlist.pm lib/Audio/MPD/Types.pm t/00-compile.t t/000-report-versions-tiny.t t/20-connection.t t/21-new.t t/22-general.t t/23-output.t t/24-info.t t/25-settings.t t/26-playback.t t/30-collection.t t/40-playlist.t t/release-has-version.t t/release-kwalitee.t t/release-minimum-version.t t/release-pod-coverage.t t/release-pod-syntax.t weaver.ini Build.PL100644000764000144 241011723631714 14775 0ustar00jquelinusers000000000000Audio-MPD-1.120610 use strict; use warnings; use Module::Build 0.3601; my %module_build_args = ( "build_requires" => { "File::Find" => 0, "File::Temp" => 0, "Module::Build" => "0.3601", "Test::Corpus::Audio::MPD" => "1.113282", "Test::More" => "0.88" }, "configure_requires" => { "Module::Build" => "0.3601" }, "dist_abstract" => "class to talk to MPD (Music Player Daemon) servers", "dist_author" => [ "Jerome Quelin" ], "dist_name" => "Audio-MPD", "dist_version" => "1.120610", "license" => "perl", "module_name" => "Audio::MPD", "recommends" => {}, "recursive_test_files" => 1, "requires" => { "Audio::MPD::Common::Item" => 0, "Audio::MPD::Common::Output" => 0, "Audio::MPD::Common::Stats" => 0, "Audio::MPD::Common::Status" => 0, "DB_File" => 0, "Encode" => 0, "Getopt::Euclid" => 0, "IO::Socket::IP" => 0, "Moose" => 0, "Moose::Util::TypeConstraints" => 0, "MooseX::Has::Sugar" => 0, "MooseX::SemiAffordanceAccessor" => 0, "Proc::Daemon" => 0, "Time::HiRes" => 0, "perl" => "5.010", "strict" => 0, "warnings" => 0 }, "script_files" => [ "bin/mpd-dynamic", "bin/mpd-rate" ] ); my $build = Module::Build->new(%module_build_args); $build->create_build_script; META.json100644000764000144 2430511723631714 15151 0ustar00jquelinusers000000000000Audio-MPD-1.120610{ "abstract" : "class to talk to MPD (Music Player Daemon) servers", "author" : [ "Jerome Quelin" ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120351", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Audio-MPD", "prereqs" : { "build" : { "requires" : { "Module::Build" : "0.3601" } }, "configure" : { "requires" : { "Module::Build" : "0.3601" } }, "runtime" : { "requires" : { "Audio::MPD::Common::Item" : "0", "Audio::MPD::Common::Output" : "0", "Audio::MPD::Common::Stats" : "0", "Audio::MPD::Common::Status" : "0", "DB_File" : "0", "Encode" : "0", "Getopt::Euclid" : "0", "IO::Socket::IP" : "0", "Moose" : "0", "Moose::Util::TypeConstraints" : "0", "MooseX::Has::Sugar" : "0", "MooseX::SemiAffordanceAccessor" : "0", "Proc::Daemon" : "0", "Time::HiRes" : "0", "perl" : "5.010", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "File::Find" : "0", "File::Temp" : "0", "Test::Corpus::Audio::MPD" : "1.113282", "Test::More" : "0.88" } } }, "provides" : { "Audio::MPD" : { "file" : "lib/Audio/MPD.pm", "version" : "1.120610" }, "Audio::MPD::Collection" : { "file" : "lib/Audio/MPD/Collection.pm", "version" : "1.120610" }, "Audio::MPD::Playlist" : { "file" : "lib/Audio/MPD/Playlist.pm", "version" : "1.120610" }, "Audio::MPD::Types" : { "file" : "lib/Audio/MPD/Types.pm", "version" : "1.120610" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-audio-mpd at rt.cpan.org", "web" : "http://rt.cpan.org/Public/Dist/Display.html?Name=Audio-MPD" }, "homepage" : "http://search.cpan.org/dist/Audio-MPD/", "repository" : { "type" : "git", "url" : "git://github.com/jquelin/audio-mpd.git", "web" : "http://github.com/jquelin/audio-mpd" }, "x_mailing_list" : "http://groups.google.com/group/audio-mpd" }, "version" : "1.120610", "x_Dist_Zilla" : { "plugins" : [ { "class" : "Dist::Zilla::Plugin::MetaResources", "name" : "MetaResources", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "test", "type" : "requires" } }, "name" : "TestRequires", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::AutoVersion", "name" : "@Filter/AutoVersion", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::GatherDir", "name" : "@Filter/GatherDir", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::CompileTests", "name" : "@Filter/CompileTests", "version" : "1.112820" }, { "class" : "Dist::Zilla::Plugin::HasVersionTests", "name" : "@Filter/HasVersionTests", "version" : "1.101420" }, { "class" : "Dist::Zilla::Plugin::KwaliteeTests", "name" : "@Filter/KwaliteeTests", "version" : "2.03" }, { "class" : "Dist::Zilla::Plugin::MinimumVersionTests", "name" : "@Filter/MinimumVersionTests", "version" : "2.0.1" }, { "class" : "Dist::Zilla::Plugin::PodCoverageTests", "name" : "@Filter/PodCoverageTests", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@Filter/PodSyntaxTests", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::ReportVersions::Tiny", "name" : "@Filter/ReportVersions::Tiny", "version" : "1.03" }, { "class" : "Dist::Zilla::Plugin::PruneCruft", "name" : "@Filter/PruneCruft", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::PruneFiles", "name" : "@Filter/PruneFiles", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::ManifestSkip", "name" : "@Filter/ManifestSkip", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::AutoPrereqs", "name" : "@Filter/AutoPrereqs", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::ExtraTests", "name" : "@Filter/ExtraTests", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::NextRelease", "name" : "@Filter/NextRelease", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::PkgVersion", "name" : "@Filter/PkgVersion", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::PodWeaver", "name" : "@Filter/PodWeaver", "version" : "3.101641" }, { "class" : "Dist::Zilla::Plugin::Prepender", "name" : "@Filter/Prepender", "version" : "1.112280" }, { "class" : "Dist::Zilla::Plugin::ExecDir", "name" : "@Filter/ExecDir", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::ShareDir", "name" : "@Filter/ShareDir", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::Bugtracker", "name" : "@Filter/Bugtracker", "version" : "1.111080" }, { "class" : "Dist::Zilla::Plugin::Homepage", "name" : "@Filter/Homepage", "version" : "1.101420" }, { "class" : "Dist::Zilla::Plugin::Repository", "name" : "@Filter/Repository", "version" : "0.18" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Package", "name" : "@Filter/MetaProvides::Package", "version" : "1.12060501" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@Filter/MetaConfig", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@Filter/License", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@Filter/MetaYAML", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@Filter/MetaJSON", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::ModuleBuild", "name" : "@Filter/ModuleBuild", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::Readme", "name" : "@Filter/Readme", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@Filter/Manifest", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::CheckChangeLog", "name" : "@Filter/CheckChangeLog", "version" : "0.01" }, { "class" : "Dist::Zilla::Plugin::Git::Check", "name" : "@Filter/Git::Check", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "name" : "@Filter/Git::Commit", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::Git::CommitBuild", "name" : "@Filter/Git::CommitBuild", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "name" : "@Filter/TagMaster", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "name" : "@Filter/TagRelease", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "name" : "@Filter/Git::Push", "version" : "1.113560" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@Filter/UploadToCPAN", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", "version" : "4.300009" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", "version" : "4.300009" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { "is_trial" : "0" }, "version" : "4.300009" } } } weaver.ini100644000764000144 261111723631714 15476 0ustar00jquelinusers000000000000Audio-MPD-1.120610[@CorePrep] [Name] [Version] [Region / prelude] [Generic / SYNOPSIS] [Generic / DESCRIPTION] [Generic / OVERVIEW] [Collect / ATTRIBUTES] command = attr [Collect / METHODS] command = method ; audio::mpd [Collect / MPD_CTRL] command = meth_mpd_ctrl header = CONTROLLING THE SERVER [Collect / MPD_OUTPUT] command = meth_mpd_output header = HANDLING VOLUME & OUTPUT [Collect / MPD_INFO] command = meth_mpd_info header = RETRIEVING INFO FROM CURRENT STATE [Collect / MPD_SETTINGS] command = meth_mpd_settings header = ALTERING MPD SETTINGS [Collect / MPD_PLAYBACK] command = meth_mpd_playback header = CONTROLLING PLAYBACK ; audio::mpd::collection [Collect / COLL_SONG] command = meth_coll_song header = RETRIEVING SONGS & DIRECTORIES [Collect / COLL_WHOLE] command = meth_coll_whole header = RETRIEVING THE WHOLE COLLECTION [Collect / COLL_PICK] command = meth_coll_pick header = PICKING A SONG [Collect / COLL_RELATIONS] command = meth_coll_relations header = SONGS, ALBUMS, ARTISTS & GENRES RELATIONS ; audio::mpd::playlist [Collect / PLAY_INFO] command = meth_play_info header = RETRIEVING INFORMATION [Collect / PLAY_ADDRM] command = meth_play_addrm header = ADDING / REMOVING SONGS [Collect / PLAY_ORDER] command = meth_play_order header = CHANGING PLAYLIST ORDER [Collect / PLAY_MGMT] command = meth_play_mgmt header = MANAGING PLAYLISTS [Leftovers] [Region / postlude] [Authors] [Legal] t000755000764000144 011723631714 13607 5ustar00jquelinusers000000000000Audio-MPD-1.12061021-new.t100644000764000144 462511723631714 15154 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 16; my $mpd; # # testing constructor defaults. $mpd = Audio::MPD->new; is( $mpd->host, 'localhost', 'host defaults to localhost' ); is( $mpd->port, 6600, 'port defaults to 6600' ); is( $mpd->password, '', 'password default to empty string' ); isa_ok( $mpd, 'Audio::MPD', 'object creation' ); # # changing fake mpd config to test constructor. my $port = 16600; stop_test_mpd(); customize_test_mpd_configuration($port); start_test_mpd(); # # testing constructor params. $mpd = Audio::MPD->new( host=>'127.0.0.1', port=>$port, password=>'foobar' ); is( $mpd->host, '127.0.0.1', 'host set to param' ); is( $mpd->port, $port, 'port set to param' ); is( $mpd->password, 'foobar', 'password set to param' ); # # testing constructor environment defaults... $ENV{MPD_HOST} = '127.0.0.1'; $ENV{MPD_PORT} = $port; $ENV{MPD_PASSWORD} = 'foobar'; $mpd = Audio::MPD->new; is( $mpd->host, $ENV{MPD_HOST}, 'host default to $ENV{MPD_HOST}' ); is( $mpd->port, $ENV{MPD_PORT}, 'port default to $ENV{MPD_PORT}' ); is( $mpd->password, $ENV{MPD_PASSWORD}, 'password default to $ENV{MPD_PASSWORD}' ); delete $ENV{MPD_HOST}; delete $ENV{MPD_PASSWORD}; $ENV{MPD_HOST} = 'foobar@127.0.0.1'; is( $mpd->host, '127.0.0.1', 'host detected when $ENV{MPD_HOST} is passwd@host' ); is( $mpd->password, 'foobar', 'password detected when $ENV{MPD_HOST} is passwd@host' ); $ENV{MPD_HOST} = 'foobar@127.0.0.1:16600'; is( $mpd->host, '127.0.0.1', 'host detected when $ENV{MPD_HOST} is passwd@host:port' ); is( $mpd->port, 16600, 'port detected when $ENV{MPD_HOST} is passwd@host:port' ); is( $mpd->password, 'foobar', 'password detected when $ENV{MPD_HOST} is passwd@host:port' ); $mpd = Audio::MPD->new; delete $ENV{MPD_HOST}; delete $ENV{MPD_PORT}; # # testing connection type $mpd = Audio::MPD->new( port=>16600, conntype=>'reuse' ); $mpd->ping; $mpd->ping; $mpd->ping; isa_ok( $mpd->_socket, 'IO::Socket', 'socket is created and retained' ); 24-info.t100644000764000144 420511723631714 15313 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 16; my $mpd = Audio::MPD->new; my $song; # # testing stats $mpd->updatedb; $mpd->playlist->add( 'title.ogg' ); $mpd->playlist->add( 'dir1/title-artist-album.ogg' ); $mpd->playlist->add( 'dir1/title-artist.ogg' ); my $stats = $mpd->stats; isa_ok( $stats, 'Audio::MPD::Common::Stats', 'stats() returns an AMC::Stats object' ); is( $stats->artists, 1, 'one artist in the database' ); is( $stats->albums, 1, 'one album in the database' ); is( $stats->songs, 5, '5 songs in the database' ); is( $stats->playtime, 0, 'already played 0 seconds' ); is( $stats->db_playtime, 10, '10 seconds worth of music in the db' ); isnt( $stats->uptime, undef, 'uptime is defined' ); isnt( $stats->db_update, 0, 'database has been updated' ); # # testing status. $mpd->play; $mpd->pause; my $status = $mpd->status; isa_ok( $status, 'Audio::MPD::Common::Status', 'status return an AMC::Status object' ); # # testing current song. $song = $mpd->current; isa_ok( $song, 'Audio::MPD::Common::Item::Song', 'current return an AMC::Item::Song object' ); # # testing song. $song = $mpd->song(1); isa_ok( $song, 'Audio::MPD::Common::Item::Song', 'song() returns an AMC::Item::Song object' ); is( $song->file, 'dir1/title-artist-album.ogg', 'song() returns the wanted song' ); $song = $mpd->song; # default to current song is( $song->file, 'title.ogg', 'song() defaults to current song' ); # # testing songid. $song = $mpd->songid(1); isa_ok( $song, 'Audio::MPD::Common::Item::Song', 'songid() returns an AMC::Item::Song object' ); is( $song->file, 'dir1/title-artist-album.ogg', 'songid() returns the wanted song' ); $song = $mpd->songid; # default to current song is( $song->file, 'title.ogg', 'songid() defaults to current song' ); bin000755000764000144 011723631714 14114 5ustar00jquelinusers000000000000Audio-MPD-1.120610mpd-rate100755000764000144 410611723631714 15714 0ustar00jquelinusers000000000000Audio-MPD-1.120610/bin#!/usr/bin/perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; # PODNAME: mpd-rate; # ABSTRACT: rate your songs for mpd-dynamic use Audio::MPD; use DB_File; use Encode; use Getopt::Euclid qw{ :minimal_keys }; # fetch current song my $playing = Audio::MPD->new->current; unless (defined $playing) { die "Cannot rate current song, as no song currently is playing!"; } my $song = encode( 'utf-8', $playing->file ); # open ratings file my %ratings; tie %ratings, 'DB_File', $ARGV{ratings}, O_RDWR|O_CREAT, oct(666), $DB_HASH or die "$ARGV{ratings}: $!"; # update rating or print it if ( defined $ARGV{rating} ) { $ratings{$song} = $ARGV{rating}; } else { say exists $ratings{$song} ? $ratings{$song} : 0; } untie %ratings; =pod =head1 NAME mpd-rate; - rate your songs for mpd-dynamic =head1 VERSION version 1.120610 =head1 DESCRIPTION This program allows you to rate your songs, to allow mpd-dynamic to use ratings. =head1 USAGE mpd-rate [options] =head1 OPTIONS You can customize the usage of mpd-dynamic with the following options: =over 4 =item -r[atings] The path of a db file with the ratings per song. The keys are the song path (relative to MPD root), and the value is an integer (the rating). Default to C<~/.mpd/ratings.db>. =for Euclid: ratings.type: writable ratings.default: "$ENV{HOME}/.mpd/ratings.db" =item The rating you want to apply to the current song. If not supplied, will print its current rating. =for Euclid: rating.type: integer =item --version =item --usage =item --help =item --man Print the usual program information =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ 23-output.t100644000764000144 341311723631714 15717 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 9; my $mpd = Audio::MPD->new; # # testing absolute volume. my $oldvol = $mpd->status->volume; # saving volume. $mpd->volume(10); # init to sthg that we know $mpd->volume(42); is( $mpd->status->volume, 42, 'setting volume' ); # # testing positive relative volume. $mpd->volume('+9'); is( $mpd->status->volume, 51, 'increasing volume' ); # # testing negative relative volume. $mpd->volume('-4'); is( $mpd->status->volume, 47, 'decreasing volume' ); $mpd->volume($oldvol); # resoring volume. # # testing outputs. my @outputs = $mpd->outputs; is( scalar(@outputs), 1, 'list of outputs' ); my $o = shift @outputs; isa_ok( $o, 'Audio::MPD::Common::Output', "outputs return AMC:Output objects" ); is( $o->id, 0, "AMC:O object: id" ); is( $o->name, "null", "AMC:O object: name" ); # # testing disable_output. $mpd->playlist->add( 'title.ogg' ); $mpd->playlist->add( 'dir1/title-artist-album.ogg' ); $mpd->playlist->add( 'dir1/title-artist.ogg' ); $mpd->play; $mpd->output_disable(0); sleep(1); SKIP: { # FIXME? my $error = $mpd->status->error; skip "detection method doesn't always work - depends on timing", 1 unless defined $error; like( $error, qr/^problems/, 'disabling output' ); } # # testing enable_output. $mpd->output_enable(0); sleep(1); $mpd->play; $mpd->pause; is( $mpd->status->error, undef, 'enabling output' ); 22-general.t100644000764000144 304411723631714 15773 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 7; my $mpd = Audio::MPD->new; # # testing mpd version. SKIP: { my $output = qx{echo | nc -w1 localhost 6600 2>/dev/null}; skip 'need netcat installed', 1 unless $output =~ /^OK .* ([\d.]+)\n/; is( $mpd->version, $1, 'mpd version grabbed during connection' ); } # # testing kill. $mpd->ping; $mpd->kill; sleep 1; # let mpd shut down the socket cleanly eval { $mpd->ping }; like( $@, qr/^Could not create socket:/, 'kill shuts mpd down' ); start_test_mpd(); # # testing password changing. eval { $mpd->set_password('b0rken') }; like( $@, qr/\{password\} incorrect password/, 'changing password' ); eval { $mpd->set_password() }; # default to empty string. is( $@, '', 'no password = empty password' ); # # testing database updating. # uh - what are we supposed to test? that there was no error? eval { $mpd->updatedb }; is( $@, '', 'updating whole collection' ); sleep 1; # let the first update finish. eval { $mpd->updatedb('dir1') }; is( $@, '', 'updating part of collection' ); # # testing urlhandlers. my @handlers = $mpd->urlhandlers; ok( scalar @handlers >= 1, 'at least one url handler supported' ); 00-compile.t100644000764000144 350111723631714 16000 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Test::More; use File::Find; use File::Temp qw{ tempdir }; my @modules; find( sub { return if $File::Find::name !~ /\.pm\z/; my $found = $File::Find::name; $found =~ s{^lib/}{}; $found =~ s{[/\\]}{::}g; $found =~ s/\.pm$//; # nothing to skip push @modules, $found; }, 'lib', ); sub _find_scripts { my $dir = shift @_; my @found_scripts = (); find( sub { return unless -f; my $found = $File::Find::name; # nothing to skip open my $FH, '<', $_ or do { note( "Unable to open $found in ( $! ), skipping" ); return; }; my $shebang = <$FH>; return unless $shebang =~ /^#!.*?\bperl\b\s*$/; push @found_scripts, $found; }, $dir, ); return @found_scripts; } my @scripts; do { push @scripts, _find_scripts($_) if -d $_ } for qw{ bin script scripts }; my $plan = scalar(@modules) + scalar(@scripts); $plan ? (plan tests => $plan) : (plan skip_all => "no tests to run"); { # fake home for cpan-testers # no fake requested ## local $ENV{HOME} = tempdir( CLEANUP => 1 ); like( qx{ $^X -Ilib -e "require $_; print '$_ ok'" }, qr/^\s*$_ ok/s, "$_ loaded ok" ) for sort @modules; SKIP: { eval "use Test::Script 1.05; 1;"; skip "Test::Script needed to test script compilation", scalar(@scripts) if $@; foreach my $file ( @scripts ) { my $script = $file; $script =~ s!.*/!!; script_compiles( $file, "$script script compiles" ); } } } examples000755000764000144 011723631714 15162 5ustar00jquelinusers000000000000Audio-MPD-1.120610mpc.pl100755000764000144 1344311723631714 16466 0ustar00jquelinusers000000000000Audio-MPD-1.120610/examples#!/usr/bin/perl -w # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use Encode; use Audio::MPD; use constant VERSION => '0.10.0'; my $x = Audio::MPD->new('localhost',6600); # mpctime() - For getting the time in the same format as `mpc` writes it sub mpctime { my($psf,$tst) = split /:/, $x->{'time'}; return sprintf("%d:%02d (%d%%)", ($psf / 60), # minutes so far ($psf % 60), # seconds - minutes so far $psf/($tst/100)); # Percent } sub help { print "mpc version: ".VERSION."\n"; print "mpc\t\t\t\tDisplays status\n"; print "mpc add \t\tAdd a song to the current playlist\n"; print "mpc del \t\tRemove a song from the current playlist\n"; print "mpc play \t\tStart playing a (default: 1)\n"; print "mpc next\t\t\tPlay the next song in the current playlist\n"; print "mpc prev\t\t\tPlay the previous song in the current playlist\n"; print "mpc pause\t\t\tPauses the currently playing song\n"; print "mpc stop\t\t\tStop the currently playing song\n"; print "mpc seek <0-100>\t\tSeeks to the position specified in seconds\n"; print "mpc clear\t\t\tClears the current playlist\n"; print "mpc shuffle\t\t\tShuffle the current playlist\n"; print "mpc move \t\tMove song in playlist\n"; print "mpc playlist\t\t\tPrint the current playlist\n"; print "mpc listall []\t\tList all songs in the music dir\n"; print "mpc ls []\t\t\tList the contents of \n"; print "mpc lsplaylists\t\t\tLists currently available playlists\n"; print "mpc load \t\t\tLoad as a playlist\n"; print "mpc save \t\t\tSaves a playlist as \n"; print "mpc rm \t\t\tRemoves a playlist\n"; print "mpc volume [+-]\t\tSets volume to or adjusts by [+-]\n"; print "mpc repeat \t\tToggle repeat mode, or specify state\n"; print "mpc random \t\tToggle random mode, or specify state\n"; #print "mpc search \tSearch for a song\n"; print "mpc crossfade [sec]\t\tSet and display crossfade settings\n"; print "mpc update\t\t\tScans music directory for updates\n"; print "mpc version\t\t\tReports version of MPD\n"; print "For more information about these and other options look man 1 mpc\n"; exit; } # status() - For showing the current status sub status { $x->_get_status; my $repeat = ($x->{repeat} == 1 ? 'on ' : 'off'); # Let's show the repeat-status a bit nicer my $random = ($x->{random} == 1 ? 'on ' : 'off'); # And the same for random if($x->{state} eq 'play' || $x->{state} eq 'pause') { # If MPD is either playing or paused print decode_utf8($x->get_title)."\n"; print "[".($x->{state} eq 'play' ? 'playing' : 'paused')."] #".($x->{song}+1)."/".$x->{playlistlength}."\t".mpctime."\n"; print "volume: ".$x->{volume}."% repeat: ".$repeat." random: ".$random."\n"; } elsif($x->{state} eq 'stop') { # If MPD is stopped, we don't show much print "volume: ".$x->{volume}."% repeat: ".$repeat." random: ".$random."\n"; } exit; } sub play { $x->play($ARGV[1] ? ($ARGV[1]-1) : 0); status; } sub stop { $x->stop(); status; } sub pause { $x->pause(); status; } sub add { if($ARGV[1] || $ARGV[1] eq '') { $x->add($ARGV[1]); } else { while() { chomp; $x->add($_); } } } sub del { if(defined($ARGV[1])) { $x->delete($ARGV[1]-1); } else { help; } } sub next { $x->next(); status; } sub prev { $x->prev(); status; } sub seek { if(defined($ARGV[1])) { $x->seek($ARGV[1]); status; } else { help; } } sub clear { $x->clear(); } sub shuffle { $x->shuffle(); } sub move { if(defined($ARGV[1]) && defined($ARGV[2])) { $x->move($ARGV[1]-1,$ARGV[2]-1); } else { help; } } sub playlist { my $playlist = $x->playlist; for(my $i = 0 ; $i < $x->{playlistlength} ; $i++) { my $title = ($playlist->[$i]{'Artist'} && $playlist->[$i]{'Title'} ? $playlist->[$i]{'Artist'}." - ".$playlist->[$i]{'Title'} : $playlist->[$i]{'file'}); print "#".($i+1).") ".$title."\n"; } } sub listall { my @list = $x->listall($ARGV[1]); foreach my $item (@list) { print "$1\n" if $item =~ /(?:file):\s(.+)/; } } sub ls { foreach my $tmp ($x->lsinfo($ARGV[1])) { my %hash = %{$tmp}; if($hash{'directory'} || $hash{'file'}) { print $hash{'directory'} || $hash{'file'}; print "\n"; } } } sub lsplaylists { #while(my %hash = $x->nextinfo) foreach my $tmp ($x->lsinfo()) { my %hash = %{$tmp}; print $hash{'playlist'}."\n" if $hash{'playlist'}; } } sub load { if(defined($ARGV[1])) { $x->load($ARGV[1]); } else { help; } } sub save { if(defined($ARGV[1])) { $x->save($ARGV[1]); } else { help; } } sub rm { if(defined($ARGV[1])) { $x->rm($ARGV[1]); } else { help; } } sub volume { if(defined($ARGV[1])) { $x->set_volume($ARGV[1]); status; } else { help; } } sub repeat { if(defined($ARGV[1])) { $x->set_repeat($ARGV[1]); status; } else { help; } } sub random { if(defined($ARGV[1])) { $x->set_random($ARGV[1]); status; } else { help; } } sub search { die('No way!') if $ARGV[1] !~ /^(filename|artist|title|album)$/; my @list = $x->search($ARGV[1],$ARGV[2]); foreach my $hash (@list) { my %song = %$hash; print $song{'file'}."\n"; } } sub crossfade { if(defined($ARGV[1])) { $x->set_fade($ARGV[1]); } else { help; } } sub update { $x->updatedb(); } sub version { print "mpd version: ".$x->{version}."\n"; } # main() - Main sub sub main { status if !$ARGV[0]; help if $ARGV[0] !~ /^(add|del|play|next|prev|pause|stop|seek|clear|shuffle|move|playlist|listall|ls|lsplaylists|load|save|rm|volume|repeat|random|search|crossfade|update|version)$/; goto &{ $ARGV[0] }; } # Let's start! main; mpd-dynamic100755000764000144 1350711723631714 16432 0ustar00jquelinusers000000000000Audio-MPD-1.120610/bin#!/usr/bin/perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; # PODNAME: mpd-dynamic # ABSTRACT: a dynamic playlist for mpd use Audio::MPD; use DB_File; use Encode; use Getopt::Euclid qw[ :minimal_keys ]; use Proc::Daemon; use Time::HiRes qw[ usleep ]; # my $song = 0; # song currently playing my $playlist = 0; # playlist version my $mpd = Audio::MPD->new; Proc::Daemon::Init unless $ARGV{debug}; # fetch list of songs known by mpd. my @files = $mpd->collection->all_pathes; die "Please set up mpd's audio collection before running mpd-dynamic" unless @files; while (1) { # endless loop my $status; eval { $status = $mpd->status }; next if $@; # error while peaking status # do playlist and/or current song have changed? next unless $status->playlist > $playlist || defined $status->song && $status->song != $song; debug("checking playlist...\n"); # yup - update playlist & song. $playlist = $status->playlist; $song = $status->song // 0; # keep at most $ARGV{old} songs. if ( $song > $ARGV{old} ) { my $old = $song - $ARGV{old}; debug( "need to remove $old songs\n" ); eval { $mpd->playlist->delete(0) for 1..$old }; } # add at most $ARGV{new} songs. my @pl = $mpd->playlist->as_items; if ( $#pl - $song < $ARGV{new} ) { my $new = $ARGV{new} - ( $#pl - $song ); debug("need to add $new songs\n"); my %ratings; my $istied = tie( %ratings, 'DB_File', $ARGV{ratings}, O_RDONLY ) ? 1 : 0; PICK_ONE: for (1..$new) { my $random = encode('utf-8', $files[ rand @files ]); if ( $istied && exists $ratings{$random} && $ratings{$random} != 0 && $ratings{$random} < $ARGV{min} ) { debug("rating too low: $ratings{$random} [$random]\n"); redo PICK_ONE; } debug("adding [$random]\n"); eval { $mpd->playlist->add( decode('utf-8', $random) ) }; debug("error: $@\n") if $@; } untie %ratings if $istied; } } continue { usleep $ARGV{sleep} * 1000 * 1000; # microseconds } exit; # should not be there... sub debug { return unless $ARGV{debug}; my ($msg) = @_; my ($s,$m,$h) = ( localtime(time) )[0,1,2,3,6]; my $date = sprintf "%02d:%02d:%02d", $h, $m, $s; warn "$date $msg"; } =pod =head1 NAME mpd-dynamic - a dynamic playlist for mpd =head1 VERSION version 1.120610 =head1 DESCRIPTION This program implements a dynamic playlist for MPD, build on top of the L perl module. MPD (music player daemon) is a cool music player, but it lacks a dynamic playlist. A dynamic playlist is a playlist that will change automatically over time. In particular, it will remove already played songs (keeping at most a given number of songs) and add new songs to the playlist so it never fall short of songs. Note that since mpd is a daemon needing no gui to work, C is also a daemon. That is, it will fork and do all its work from the background. This way, you can fire C and C and forget completely about your music (especially since C is a low-resource program): it will just be there! :-) =head1 USAGE mpd-dynamic [options] =head1 OPTIONS =head2 General behaviour You can customize the usage of mpd-dynamic with the following options: =over 4 =item -o[ld] Number of old tracks to keep in the backlog. Defaults to 10. =for Euclid: old.type: integer >= 0 old.default: 10 =item -n[ew] Number of new tracks to keep in the to-be-played playlist. Defaults to 10. =for Euclid: new.type: integer > 0 new.default: 10 =item -s[leep] Time spent sleeping (in seconds) before checking if playlist should be updated. Default to 5 seconds. =for Euclid: sleep.type: number > 0 sleep.default: 5 =item -d[ebug] Run mpd-dynamic in debug mode. In particular, the program will not daemonize itself. Default to false. =item -e[ncoding] Print debug messages with this encoding. Since mpd-dynamic is meant to be a silent daemon, this option will not be used outside of debug mode. Default to C. =for Euclid: encoding.type: string encoding.default: 'utf-8' =item --version =item --usage =item --help =item --man Print the usual program information =back Note however that those flags are optional: since C comes with some sane defaults, you can fire C as is. =head2 Ratings You can also take advantage of ratings if you want. With those options, songs need to have at least a given rating (or no rating yet) to be inserted: this way, you will only listen to your favorite songs! Ratings can be created / updated with C. Note that if you supply a non-existant rating db-file, the rating mechanism will be ignored. The following options control the rating mechanism: =over 4 =item -r[atings] The path of a db file with the ratings per song. The keys are the song path (relative to MPD root), and the value is an integer (the rating). Default to C<~/.mpd/ratings.db>. =for Euclid: ratings.type: readable ratings.default: "$ENV{HOME}/.mpd/ratings.db" =item -m[in[imum]] The minimum rating for a song to be inserted in the playlist. Default to 4. =for Euclid: min.type: integer > 0 min.default: 4 =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ 26-playback.t100644000764000144 511611723631714 16152 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 19; my $mpd = Audio::MPD->new; # # testing play / playid. $mpd->playlist->clear; $mpd->playlist->add( 'title.ogg' ); $mpd->playlist->add( 'dir1/title-artist-album.ogg' ); $mpd->playlist->add( 'dir1/title-artist.ogg' ); $mpd->playlist->add( 'dir2/album.ogg' ); $mpd->play; is( $mpd->status->state, 'play', 'play() starts playback' ); $mpd->play(2); is( $mpd->status->song, 2, 'play() can start playback at a given song' ); $mpd->play(0); $mpd->pause; sleep 1; $mpd->playid; is( $mpd->status->state, 'play', 'playid() starts playback' ); $mpd->playid(1); is( $mpd->status->songid, 1, 'playid() can start playback at a given song' ); # # testing pause. $mpd->pause(1); is( $mpd->status->state, 'pause', 'pause() forces playback pause' ); $mpd->pause(0); is( $mpd->status->state, 'play', 'pause() can force playback resume' ); $mpd->pause; is( $mpd->status->state, 'pause', 'pause() toggles to pause' ); $mpd->pause; is( $mpd->status->state, 'play', 'pause() toggles to play' ); # # testing stop. $mpd->stop; is( $mpd->status->state, 'stop', 'stop() forces full stop' ); # # testing prev / next. $mpd->play(1); $mpd->pause; $mpd->next; is( $mpd->status->song, 2, 'next() changes track to next one' ); $mpd->prev; is( $mpd->status->song, 1, 'prev() changes track to previous one' ); # # testing seek / seekid. SKIP: { skip "detection method doesn't always work - depends on timing", 8; $mpd->pause(1); $mpd->seek( 1, 2 ); is( $mpd->status->song, 2, 'seek() can change the current track' ); is( $mpd->status->time->sofar_secs, 1, 'seek() seeks in the song' ); $mpd->seek; is( $mpd->status->time->sofar_secs, 0, 'seek() defaults to beginning of song' ); $mpd->seek(1); is( $mpd->status->time->sofar_secs, 1, 'seek() defaults to current song ' ); $mpd->seekid( 1, 1 ); is( $mpd->status->songid, 1, 'seekid() can change the current track' ); is( $mpd->status->time->sofar_secs, 1, 'seekid() seeks in the song' ); $mpd->seekid; is( $mpd->status->time->sofar_secs, 0, 'seekid() defaults to beginning of song' ); $mpd->seekid(1); is( $mpd->status->time->sofar_secs, 1, 'seekid() defaults to current song' ); } 25-settings.t100644000764000144 236611723631714 16227 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 10; my $mpd = Audio::MPD->new; # # testing repeat $mpd->repeat(1); is( $mpd->status->repeat, 1, 'enabling repeat mode' ); $mpd->repeat(0); is( $mpd->status->repeat, 0, 'disabling repeat mode' ); $mpd->repeat; is( $mpd->status->repeat, 1, 'toggling repeat mode to on' ); $mpd->repeat; is( $mpd->status->repeat, 0, 'toggling repeat mode to off' ); # # testing random $mpd->random(1); is( $mpd->status->random, 1, 'enabling random mode' ); $mpd->random(0); is( $mpd->status->random, 0, 'disabling random mode' ); $mpd->random; is( $mpd->status->random, 1, 'toggling random mode to on' ); $mpd->random; is( $mpd->status->random, 0, 'toggling random mode to off' ); # # testing fade $mpd->fade(15); is( $mpd->status->xfade, 15, 'enabling fading' ); $mpd->fade; is( $mpd->status->xfade, 0, 'disabling fading by default' ); 40-playlist.t100644000764000144 1023611723631714 16240 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 24; my $mpd = Audio::MPD->new; my ($nb, @items); # # testing collection accessor. my $pl = $mpd->playlist; isa_ok( $pl, 'Audio::MPD::Playlist', 'playlist return an Audio::MPD::Playlist object' ); # # testing playlist retrieval. $pl->add( 'title.ogg', 'dir1/title-artist-album.ogg', 'dir1/title-artist.ogg' ); @items = $pl->as_items; isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'as_items() returns AMC::Item::Song objects' ) for @items; is( $items[0]->title, 'ok-title', 'first song reported first' ); # # testing playlist changes retrieval. @items = $pl->items_changed_since(0); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'items_changed_since() returns AMC::Item::Song objects' ) for @items; is( $items[0]->title, 'ok-title', 'first song reported first' ); # # testing song insertion. $pl->clear; $nb = $mpd->status->playlistlength; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); is( $mpd->status->playlistlength, $nb+3, 'add() songs' ); # # testing song removal. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); $mpd->play(0); # to set songid $mpd->stop; $nb = $mpd->status->playlistlength; $pl->delete( reverse 1..2 ); # reverse otherwise mpd will get it wrong is( $mpd->status->playlistlength, $nb-2, 'delete() songs' ); $nb = $mpd->status->playlistlength; $pl->deleteid( $mpd->status->songid ); is( $mpd->status->playlistlength, $nb-1, 'deleteid() songs' ); # # testing playlist clearing $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); $nb = $mpd->status->playlistlength; $pl->clear; is( $mpd->status->playlistlength, 0, 'clear() leaves 0 songs' ); isnt( $mpd->status->playlistlength, $nb, 'clear() changes playlist length' ); # # testing cropping. $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); $mpd->play(1); # to set song $mpd->stop; $pl->crop; is( $mpd->status->playlistlength, 1, 'crop() leaves only one song' ); # # testing shuffle. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); my $vers = $mpd->status->playlist; $pl->shuffle; is( $mpd->status->playlist, $vers+1, 'shuffle() changes playlist version' ); # # testing swap. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); $pl->swap(0,2); is( ($pl->as_items)[2]->title, 'ok-title', 'swap() changes songs' ); # # testing swapid. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); @items = $pl->as_items; $pl->swapid($items[0]->id,$items[2]->id); is( ($pl->as_items)[2]->title, 'ok-title', 'swapid() changes songs' ); # # testing move. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); $pl->move(0,2); is( ($pl->as_items)[2]->title, 'ok-title', 'move() changes song' ); # # testing moveid. $pl->clear; $pl->add( 'title.ogg' ); $pl->add( 'dir1/title-artist-album.ogg' ); $pl->add( 'dir1/title-artist.ogg' ); @items = $pl->as_items; $pl->moveid($items[0]->id,2); is( ($pl->as_items)[2]->title, 'ok-title', 'moveid() changes song' ); # # testing load. $pl->clear; $pl->load( 'test' ); @items = $pl->as_items; is( scalar @items, 1, 'load() adds songs' ); is( $items[0]->title, 'ok-title', 'load() adds the correct songs' ); # # testing save. my $pdir = playlist_dir(); $pl->clear; $pl->save( 'test-jq' ); ok( -f "$pdir/test-jq.m3u", 'save() creates a playlist' ); # # testing rm. $pl->rm( 'test-jq' ); ok( ! -f "$pdir/test-jq.m3u", 'rm() removes a playlist' ); Audio000755000764000144 011723631714 15153 5ustar00jquelinusers000000000000Audio-MPD-1.120610/libMPD.pm100644000764000144 4537011723631714 16322 0ustar00jquelinusers000000000000Audio-MPD-1.120610/lib/Audio# # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.008; use warnings; use strict; package Audio::MPD; { $Audio::MPD::VERSION = '1.120610'; } # ABSTRACT: class to talk to MPD (Music Player Daemon) servers use Audio::MPD::Common::Item; use Audio::MPD::Common::Stats; use Audio::MPD::Common::Status; use Audio::MPD::Common::Output; use Encode; use IO::Socket::IP; use Moose; use MooseX::Has::Sugar; use MooseX::SemiAffordanceAccessor; use Audio::MPD::Collection; use Audio::MPD::Playlist; use Audio::MPD::Types; has conntype => ( ro, isa=>'CONNTYPE', default=>'once' ); has host => ( ro, lazy_build ); has password => ( rw, lazy_build, trigger=>sub { $_[0]->ping } ); has port => ( ro, lazy_build ); has collection => ( ro, lazy_build, isa=>'Audio::MPD::Collection' ); has playlist => ( ro, lazy_build, isa=>'Audio::MPD::Playlist' ); has version => ( rw ); has _socket => ( rw, isa=>'IO::Socket::IP' ); #-- # initializer & lazy builders sub BUILD { my $self = shift; # create the connection if conntype is set to $REUSE $self->_connect_to_mpd_server if $self->conntype eq 'reuse'; # try to issue a ping to test connection - this can die. $self->ping; } # # my ($passwd, $host, $port) = _parse_env_var(); # # parse MPD_HOST environment variable, and extract its components. the # canonical format of MPD_HOST is passwd@host:port. # sub _parse_env_var { return (undef, undef, undef) unless defined $ENV{MPD_HOST}; return ($1, $2, $3) if $ENV{MPD_HOST} =~ /^([^@]+)\@([^:@]+):(\d+)$/; # passwd@host:port return ($1, $2, undef) if $ENV{MPD_HOST} =~ /^([^@]+)\@([^:@]+)$/; # passwd@host return (undef, $1, $2) if $ENV{MPD_HOST} =~ /^([^:@]+):(\d+)$/; # host:port return (undef, $ENV{MPD_HOST}, undef); } sub _build_host { return ( _parse_env_var() )[1] || 'localhost'; } sub _build_port { return $ENV{MPD_PORT} || ( _parse_env_var() )[2] || 6600; } sub _build_password { return $ENV{MPD_PASSWORD} || ( _parse_env_var() )[0] || ''; } sub _build_collection { Audio::MPD::Collection->new( _mpd => $_[0] ); } sub _build_playlist { Audio::MPD::Playlist ->new( _mpd => $_[0] ); } #-- # Private methods # # $mpd->_connect_to_mpd_server; # # This method connects to the mpd server. It can die on several conditions: # - if the server cannot be reached, # - if it's not an mpd server, # - or if the password is incorrect, # sub _connect_to_mpd_server { my ($self) = @_; # try to connect to mpd. my $socket = IO::Socket::IP->new( PeerAddr => $self->host, PeerPort => $self->port, ) or die "Could not create socket: $!\n"; # parse version information. my $line = $socket->getline; chomp $line; die "Not a mpd server - welcome string was: [$line]\n" if $line !~ /^OK MPD (.+)$/; $self->set_version($1); # send password. if ( $self->password ) { $socket->print( 'password ' . encode('utf-8', $self->password) . "\n" ); $line = $socket->getline; die $line if $line =~ s/^ACK //; } # save socket $self->_set_socket($socket); } # # my @result = $mpd->_send_command( $command ); # # This method is central to the module. It is responsible for interacting with # mpd by sending the $command and reading output - that will be returned as an # array of chomped lines (status line will not be returned). # # This method can die on several conditions: # - if the server cannot be reached, # - if it's not an mpd server, # - if the password is incorrect, # - or if the command is an invalid mpd command. # In the latter case, the mpd error message will be returned. # sub _send_command { my ($self, $command) = @_; $self->_connect_to_mpd_server if $self->conntype eq 'once'; my $socket = $self->_socket; # ok, now we're connected - let's issue the command. $socket->print( encode('utf-8', $command) ); my @output; while (defined ( my $line = $socket->getline ) ) { chomp $line; die $line if $line =~ s/^ACK //; # oops - error. last if $line =~ /^OK/; # end of output. push @output, decode('utf-8', $line); } # close the socket. $socket->close if $self->conntype eq 'once'; return @output; } # # my @items = $mpd->_cooked_command_as_items( $command ); # # Lots of Audio::MPD methods are using _send_command() and then parse the # output as a collection of AMC::Item. This method is meant to factorize # this code, and will parse the raw output of _send_command() in a cooked # list of items. # sub _cooked_command_as_items { my ($self, $command) = @_; my @lines = $self->_send_command($command); my (@items, %param); # parse lines in reverse order since "file:" or "directory:" lines # come first. therefore, let's first store every other parameter, # and the last line will trigger the object creation. # of course, since we want to preserve the playlist order, this means # that we're going to unshift the objects instead of push. foreach my $line (reverse @lines) { my ($k,$v) = split /:\s/, $line, 2; $param{$k} = $v; next unless $k eq 'file' || $k eq 'directory' || $k eq 'playlist'; # last param of item unshift @items, Audio::MPD::Common::Item->new(%param); %param = (); } return @items; } # # my %hash = $mpd->_cooked_command_as_kv( $command ); # # Lots of Audio::MPD methods are using _send_command() and then parse the # output to get a list of key / value (with the colon ":" acting as separator). # This method is meant to factorize this code, and will parse the raw output # of _send_command() in a cooked hash. # sub _cooked_command_as_kv { my ($self, $command) = @_; my %hash = map { split(/:\s/, $_, 2) } $self->_send_command($command); return %hash; } # # my @list = $mpd->_cooked_command_strip_first_field( $command ); # # Lots of Audio::MPD methods are using _send_command() and then parse the # output to remove the first field (with the colon ":" acting as separator). # This method is meant to factorize this code, and will parse the raw output # of _send_command() in a cooked list of strings. # sub _cooked_command_strip_first_field { my ($self, $command) = @_; my @list = map { ( split(/:\s+/, $_, 2) )[1] } $self->_send_command($command); return @list; } #-- # Public methods # -- MPD interaction: general commands sub ping { my ($self) = @_; $self->_send_command( "ping\n" ); } # sub version {} # implemented as an accessor. sub kill { my ($self) = @_; $self->_send_command("kill\n"); } # implemented by password trigger (from moose) sub updatedb { my ($self, $path) = @_; $path ||= ''; $self->_send_command("update $path\n"); } sub urlhandlers { my ($self) = @_; return $self->_cooked_command_strip_first_field("urlhandlers\n"); } # -- MPD interaction: handling volume & output sub volume { my ($self, $volume) = @_; if ($volume =~ /^(-|\+)(\d+)/ ) { my $current = $self->status->volume; $volume = $1 eq '+' ? $current + $2 : $current - $2; } $self->_send_command("setvol $volume\n"); } sub outputs { my ($self) = @_; my @lines = $self->_send_command("outputs\n"); my (@outputs, %param); # parse lines in reverse order since "id" lines come first foreach my $line (reverse @lines) { my ($k,$v) = split /:\s/, $line, 2; $k =~ s/^output//; $param{$k} = $v; next unless $k eq 'id'; # last output param unshift @outputs, Audio::MPD::Common::Output->new(%param); %param = (); } return @outputs; } sub output_enable { my ($self, $output) = @_; $self->_send_command("enableoutput $output\n"); } sub output_disable { my ($self, $output) = @_; $self->_send_command("disableoutput $output\n"); } # -- MPD interaction: retrieving info from current state sub stats { my ($self) = @_; my %kv = $self->_cooked_command_as_kv( "stats\n" ); return Audio::MPD::Common::Stats->new(\%kv); } sub status { my ($self) = @_; my %kv = $self->_cooked_command_as_kv( "status\n" ); my $status = Audio::MPD::Common::Status->new( \%kv ); return $status; } sub current { my ($self) = @_; my ($item) = $self->_cooked_command_as_items("currentsong\n"); return $item; } sub song { my ($self, $song) = @_; return $self->current unless defined $song; my ($item) = $self->_cooked_command_as_items("playlistinfo $song\n"); return $item; } sub songid { my ($self, $songid) = @_; return $self->current unless defined $songid; my ($item) = $self->_cooked_command_as_items("playlistid $songid\n"); return $item; } # -- MPD interaction: altering settings sub repeat { my ($self, $mode) = @_; $mode = not $self->status->repeat unless defined $mode; # toggle if no param $mode = $mode ? 1 : 0; # force integer $self->_send_command("repeat $mode\n"); } sub random { my ($self, $mode) = @_; $mode = not $self->status->random unless defined $mode; # toggle if no param $mode = $mode ? 1 : 0; # force integer $self->_send_command("random $mode\n"); } sub fade { my ($self, $value) = @_; $value ||= 0; $self->_send_command("crossfade $value\n"); } # -- MPD interaction: controlling playback sub play { my ($self, $number) = @_; $number = '' unless defined $number; $self->_send_command("play $number\n"); } sub playid { my ($self, $number) = @_; $number ||= ''; $self->_send_command("playid $number\n"); } sub pause { my ($self, $state) = @_; $state ||= ''; # default is to toggle $self->_send_command("pause $state\n"); } sub stop { my ($self) = @_; $self->_send_command("stop\n"); } sub next { my ($self) = @_; $self->_send_command("next\n"); } sub prev { my($self) = shift; $self->_send_command("previous\n"); } sub seek { my ($self, $time, $song) = @_; $time ||= 0; $time = int $time; $song = $self->status->song if not defined $song; # seek in current song $self->_send_command( "seek $song $time\n" ); } sub seekid { my ($self, $time, $song) = @_; $time ||= 0; $time = int $time; $song = $self->status->songid if not defined $song; # seek in current song $self->_send_command( "seekid $song $time\n" ); } no Moose; __PACKAGE__->meta->make_immutable; 1; =pod =head1 NAME Audio::MPD - class to talk to MPD (Music Player Daemon) servers =head1 VERSION version 1.120610 =head1 SYNOPSIS use Audio::MPD; my $mpd = Audio::MPD->new; $mpd->play; sleep 10; $mpd->next; =head1 DESCRIPTION L gives a clear object-oriented interface for talking to and controlling MPD (Music Player Daemon) servers. A connection to the MPD server is established as soon as a new L object is created. Since mpd is still in 0.x versions, L sticks to latest mpd (0.15 as time of writing) protocol & behaviour, and does B try to maintain backward compatibility. Note that the module will by default connect to mpd before sending any command, and will disconnect after the command has been issued. This scheme is far from optimal, but allows us not to care about timeout disconnections. Because of that, the C command (new in mpd 0.14) is B (and will not) be supported in L. This will be implemented in L. B Note that L is using high-level, blocking sockets. This means that if the mpd server is slow, or hangs for whatever reason, or even crash abruptly, the program will be hung forever in this sub. The L module is way safer - you're advised to use it instead of L. Or you can try to set C to C<$REUSE> (see L constructor for more details), but you would be then on your own to deal with disconnections. =head2 Searching the collection To search the collection, use the C accessor, returning the associated L object. You will then be able to call: $mpd->collection->all_songs; See L documentation for more details on available methods. =head2 Handling the playlist To update the playlist, use the C accessor, returning the associated L object. You will then be able to call: $mpd->playlist->clear; See L documentation for more details on available methods. =head1 ATTRIBUTES =head2 host The hostname where MPD is running. Defaults to environment var C, then to 'localhost'. Note that C can be of the form C (each of C or C<:port> can be omitted). =head2 port The port that MPD server listens to. Defaults to environment var C, then to parsed C (cf above), then to 6600. =head2 password The password to access special MPD functions. Defaults to environment var C, then to parsed C (cf above), then to empty string. =head2 conntype Change how the connection to mpd server is handled. It should be of a C type (cf L). Use either the C string to reuse the same connection or C to open a new connection per command (default). =head1 METHODS =head2 new my $mpd = Audio::MPD->new( \%opts ); This is the constructor for L. One can specify any of the attributes (cf above). =head1 CONTROLLING THE SERVER =head2 ping $mpd->ping; Sends a ping command to the mpd server. =head2 version my $version = $mpd->version; Return mpd's version number as advertised during connection. Note that mpd returns B version when connected. This protocol version can differ from the real mpd version. eg, mpd version 0.13.2 is "speaking" and thus advertising version 0.13.0. =head2 kill $mpd->kill; Send a message to the MPD server telling it to shut down. =head2 set_password $mpd->set_password( [$password] ); Change password used to communicate with MPD server to C<$password>. Empty string is assumed if C<$password> is not supplied. =head2 updatedb $mpd->updatedb( [$path] ); Force mpd to recan its collection. If C<$path> (relative to MPD's music directory) is supplied, MPD will only scan it - otherwise, MPD will rescan its whole collection. =head2 urlhandlers my @handlers = $mpd->urlhandlers; Return an array of supported URL schemes. =head1 HANDLING VOLUME & OUTPUT =head2 volume $mpd->volume( [+][-]$volume ); Sets the audio output volume percentage to absolute C<$volume>. If C<$volume> is prefixed by '+' or '-' then the volume is changed relatively by that value. =head2 outputs my @outputs = $mpd->outputs( ); Return a list of C with all outputs available within MPD. =head2 output_enable $mpd->output_enable( $output ); Enable the specified audio output. C<$output> is the ID of the audio output. =head2 output_disable $mpd->output_disable( $output ); Disable the specified audio output. C<$output> is the ID of the audio output. =head1 RETRIEVING INFO FROM CURRENT STATE =head2 stats my $stats = $mpd->stats; Return an L object with the current statistics of MPD. See the associated pod for more information. =head2 status my $status = $mpd->status; Return an L object with various information on current MPD server settings. See the associated pod for more information. =head2 current my $song = $mpd->current; Return an L representing the song currently playing. =head2 song my $song = $mpd->song( [$song] ); Return an L representing the song number C<$song>. If C<$song> is not supplied, returns the current song. =head2 songid my $song = $mpd->songid( [$songid] ); Return an L representing the song with id C<$songid>. If C<$songid> is not supplied, returns the current song. =head1 ALTERING MPD SETTINGS =head2 repeat $mpd->repeat( [$repeat] ); Set the repeat mode to C<$repeat> (1 or 0). If C<$repeat> is not specified then the repeat mode is toggled. =head2 random $mpd->random( [$random] ); Set the random mode to C<$random> (1 or 0). If C<$random> is not specified then the random mode is toggled. =head2 fade $mpd->fade( [$seconds] ); Enable crossfading and set the duration of crossfade between songs. If C<$seconds> is not specified or $seconds is 0, then crossfading is disabled. =head1 CONTROLLING PLAYBACK =head2 play $mpd->play( [$song] ); Begin playing playlist at song number C<$song>. If no argument supplied, resume playing. =head2 playid $mpd->playid( [$songid] ); Begin playing playlist at song ID C<$songid>. If no argument supplied, resume playing. =head2 pause $mpd->pause( [$state] ); Pause playback. If C<$state> is 0 then the current track is unpaused, if C<$state> is 1 then the current track is paused. Note that if C<$state> is not given, pause state will be toggled. =head2 stop $mpd->stop; Stop playback. =head2 next $mpd->next; Play next song in playlist. =head2 prev $mpd->prev; Play previous song in playlist. =head2 seek $mpd->seek( $time, [$song]); Seek to C<$time> seconds in song number C<$song>. If C<$song> number is not specified then the perl module will try and seek to C<$time> in the current song. =head2 seekid $mpd->seekid( $time, $songid ); Seek to C<$time> seconds in song ID C<$songid>. If C<$song> number is not specified then the perl module will try and seek to C<$time> in the current song. =for Pod::Coverage BUILD =head1 SEE ALSO You can find more information on the mpd project on its homepage at L.wikia.com>. Original code (2005) by Tue Abrahamsen C<< >>, documented in 2006 by Nicholas J. Humfrey C<< >>. You can look for information on this module at: =over 4 =item * Search CPAN L =item * See open / report bugs L =item * Mailing-list L =item * Git repository L =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ 20-connection.t100644000764000144 400211723631714 16506 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 20; my $mpd = Audio::MPD->new; isa_ok($mpd, 'Audio::MPD'); # # testing error during socket creation. eval { Audio::MPD->new(port=>16600) }; like($@, qr/^Could not create socket/, 'error during socket creation'); # # testing connection to a non-mpd server - here, we'll try to connect # to a sendmail server. my $sendmail_running = grep { /:25\s.*LISTEN/ } qx[ netstat -an ]; SKIP: { skip 'need some sendmail server running', 1 unless $sendmail_running; eval { Audio::MPD->new(port=>25) }; like($@, qr/^Not a mpd server - welcome string was:/, 'wrong server'); }; # # testing ipv6 connection my $mpd6 = Audio::MPD->new( host => "::1" ); isa_ok($mpd6, 'Audio::MPD'); # # testing password sending. eval { $mpd->set_password( 'wrong-password' ) }; like($@, qr/\{password\} incorrect password/, 'wrong password'); eval { $mpd->set_password('fulladmin') }; is($@, '', 'correct password sent'); $mpd->set_password(''); # # testing command. eval { $mpd->_send_command( "bad command\n" ); }; like($@, qr/unknown command "bad"/, 'unknown command'); my @output = $mpd->_send_command( "status\n" ); isnt(scalar @output, 0, 'commands return stuff'); # # testing _cooked_command_as_items my @items = $mpd->_cooked_command_as_items( "lsinfo\n" ); isa_ok( $_, 'Audio::MPD::Common::Item', '_cooked_command_as_items return items' ) for @items; # # testing _cooked_command_strip_first_field my @list = $mpd->_cooked_command_strip_first_field( "stats\n" ); unlike( $_, qr/\D/, '_cooked_command_strip_first_field return only 2nd field' ) for @list; # stats return numerical data as second field. 30-collection.t100644000764000144 1475611723631714 16544 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; use Audio::MPD; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 90; my $mpd = Audio::MPD->new; my @list; # # testing collection accessor. my $coll = $mpd->collection; isa_ok( $coll, 'Audio::MPD::Collection', 'collection return an Audio::MPD::Collection object' ); # # testing all_items. @list = $coll->all_items; is( scalar @list, 7, 'all_items return all 7 items' ); isa_ok( $_, 'Audio::MPD::Common::Item', 'all_items return AMCI objects' ) for @list; @list = $coll->all_items( 'dir1' ); is( scalar @list, 3, 'all_items can be restricted to a subdir' ); is( $list[0]->directory, 'dir1', 'all_items return a subdir first' ); is( $list[1]->artist, 'dir1-artist', 'all_items can be restricted to a subdir' ); # # testing all_items_simple. @list = $coll->all_items_simple; is( scalar @list, 7, 'all_items_simple return all 7 items' ); isa_ok( $_, 'Audio::MPD::Common::Item', 'all_items_simple return AMCI objects' ) for @list; @list = $coll->all_items_simple( 'dir1' ); is( scalar @list, 3, 'all_items_simple can be restricted to a subdir' ); is( $list[0]->directory, 'dir1', 'all_items_simple return a subdir first' ); is( $list[1]->artist, undef, 'all_items_simple does not return full tags' ); # # testing items_in_dir. @list = $coll->items_in_dir; is( scalar @list, 5, 'items_in_dir defaults to root' ); isa_ok( $_, 'Audio::MPD::Common::Item', 'items_in_dir return AMCI objects' ) for @list; @list = $coll->items_in_dir( 'dir1' ); is( scalar @list, 2, 'items_in_dir can take a param' ); # # testing all_songs. @list = $coll->all_songs; is( scalar @list, 5, 'all_songs return all 4 songs' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'all_items return AMCIS objects' ) for @list; @list = $coll->all_songs( 'dir1' ); is( scalar @list, 2, 'all_songs can be restricted to a subdir' ); is( $list[0]->artist, 'dir1-artist', 'all_songs can be restricted to a subdir' ); # # testing all_albums. # note: mpd 0.14 also returns empty albums @list = $coll->all_albums; is( scalar @list, 2, 'all_albums return the albums' ); is( $list[1], 'our album', 'all_albums return strings' ); # # testing all_artists. # note: mpd 0.14 also returns empty artists @list = $coll->all_artists; is( scalar @list, 2, 'all_artists return the artists' ); is( $list[0], 'dir1-artist', 'all_artists return strings' ); # # testing all_titles. # note: mpd 0.14 also returns empty titles @list = $coll->all_titles; is( scalar @list, 4, 'all_titles return the titles' ); like( $list[0], qr/-title$/, 'all_titles return strings' ); # # testing all_pathes. @list = $coll->all_pathes; is( scalar @list, 5, 'all_pathes return the pathes' ); like( $list[0], qr/\.ogg$/, 'all_pathes return strings' ); # # testing all_playlists @list = $coll->all_playlists; is( scalar @list, 1, 'all_playlists return the playlists' ); is( $list[0], 'test', 'all_playlists return strings' ); # # testing all_genres. # note: mpd 0.14 also returns empty genres @list = $coll->all_genres; @list = grep (!/^$/, @list); is( scalar @list, 1, 'all_genres return the genres' ); is( $list[0], 'foo-genre', 'all_genres return strings' ); # # testing song. my $path = 'dir1/title-artist-album.ogg'; my $song = $coll->song($path); isa_ok( $song, 'Audio::MPD::Common::Item::Song', 'song return an AMCI::Song object' ); is( $song->file, $path, 'song return the correct song' ); is( $song->title, 'foo-title', 'song return a full AMCI::Song' ); # # testing songs_with_filename_partial. @list = $coll->songs_with_filename_partial('album'); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_with_filename_partial return AMCI::Song objects' ) for @list; like( $list[0]->file, qr/album/, 'songs_with_filename_partial return the correct song' ); # # testing albums_by_artist. # note: mpd 0.14 also returns empty albums @list = $coll->albums_by_artist( 'dir1-artist' ); is( scalar @list, 2, 'albums_by_artist return the album' ); is( $list[1], 'our album', 'albums_by_artist return plain strings' ); # # testing songs_by_artist. @list = $coll->songs_by_artist( 'dir1-artist' ); is( scalar @list, 3, 'songs_by_artist return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_by_artist return AMCI::Songs' ) for @list; is( $list[0]->artist, 'dir1-artist', 'songs_by_artist return correct objects' ); # # testing songs_by_artist_partial. @list = $coll->songs_by_artist_partial( 'artist' ); is( scalar @list, 3, 'songs_by_artist_partial return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_by_artist_partial return AMCI::Songs' ) for @list; like( $list[0]->artist, qr/artist/, 'songs_by_artist_partial return correct objects' ); # # testing songs_from_album. @list = $coll->songs_from_album( 'our album' ); is( scalar @list, 3, 'songs_from_album return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_from_album return AMCI::Songs' ) for @list; is( $list[0]->album, 'our album', 'songs_from_album_partial return correct objects' ); # # testing songs_from_album_partial. @list = $coll->songs_from_album_partial( 'album' ); is( scalar @list, 3, 'songs_from_album_partial return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_from_album_partial return AMCI::Songs' ) for @list; like( $list[0]->album, qr/album/, 'songs_from_album_partial return correct objects' ); # # testing songs_with_title. @list = $coll->songs_with_title( 'ok-title' ); is( scalar @list, 1, 'songs_with_title return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_with_title return AMCI::Songs' ) for @list; is( $list[0]->title, 'ok-title', 'songs_with_title return correct objects' ); # # testing songs_with_title_partial. @list = $coll->songs_with_title_partial( 'title' ); is( scalar @list, 4, 'songs_with_title_partial return all the songs found' ); isa_ok( $_, 'Audio::MPD::Common::Item::Song', 'songs_with_title_partial return AMCI::Songs' ) for @list; like( $list[0]->title, qr/title/, 'songs_with_title_partial return correct objects' ); # # testing artists_by_genre. @list = $coll->artists_by_genre( 'foo-genre' ); is( scalar @list, 1, 'artists_by_genre returns the artist' ); is( $list[0], 'dir1-artist', 'artists_by_genre return plain strings' ); example.pl100644000764000144 273111723631714 17315 0ustar00jquelinusers000000000000Audio-MPD-1.120610/examples#!/usr/bin/perl -w # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use Data::Dumper; use Audio::MPD; ### NOTE! ### # THIS SCRIPT DOES NOT CONTAIN ERRORHANDLING, AND MAY THEREFORE FAIL ON # CERTAIN ACTIONS ############ #my $x = MPD->new('localhost',2100); # Do this for specifing server and/or port. my $x = Audio::MPD->new('localhost', 6601); print "Example: Shows Audio::MPD used to write mpc-like output\n\n"; print($x->get_title,"\n"); print("[".$x->{state}."] #".($x->{song} || 'n/a')."/".$x->{playlistlength}." ".$x->get_time_format."\n"); print("volume: ".$x->{volume}."% repeat: ".$x->{repeat}." random: ".$x->{random}."\n"); print "\n\nExample: Shows list of all files, directories and playlists in a specific directory.\n"; my @array = $x->listallinfo('Misc'); foreach(@array) { print $_->{'file'} || $_->{'directory'} || $_->{'playlist'},"\n"; } print "\n\nExample: Shows how to get information from the playlist. \@playlist is a reference, so don't change it :)\n\n"; my $playlist = $x->playlist; print "Song 1 filename: ".$playlist->[1]{'file'}."\n"; print "Song 2 time: ".$playlist->[2]{'Time'}." seconds\n"; my $foo = $x->get_time_info; print "Current song info: \n"; print "Minutes: ".$foo->{'minutes_so_far'}."\n"; print "Seconds: ".$foo->{'seconds_so_far'}."\n"; release-kwalitee.t100644000764000144 117311723631714 17361 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } # This test is generated by Dist::Zilla::Plugin::Test::Kwalitee use strict; use warnings; use Test::More; # needed to provide plan. eval "use Test::Kwalitee"; plan skip_all => "Test::Kwalitee required for testing kwalitee" if $@; MPD000755000764000144 011723631714 15573 5ustar00jquelinusers000000000000Audio-MPD-1.120610/lib/AudioTypes.pm100644000764000144 215111723631714 17374 0ustar00jquelinusers000000000000Audio-MPD-1.120610/lib/Audio/MPD# # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.008; use warnings; use strict; package Audio::MPD::Types; { $Audio::MPD::Types::VERSION = '1.120610'; } # ABSTRACT: types used in the distribution use Moose::Util::TypeConstraints; enum CONNTYPE => qw{ reuse once }; 1; =pod =head1 NAME Audio::MPD::Types - types used in the distribution =head1 VERSION version 1.120610 =head1 DESCRIPTION This module implements the specific types used by the distribution, and exports them (exporting is done directly by L. Current types defined: =over 4 =item * CONNTYPE - a simple enumeration, allowing only C or C. =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ release-pod-syntax.t100644000764000144 102411723631714 17655 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::Pod 1.41"; plan skip_all => "Test::Pod 1.41 required for testing POD" if $@; all_pod_files_ok(); release-has-version.t100644000764000144 104711723631714 20012 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::HasVersion"; plan skip_all => "Test::HasVersion required for testing version numbers" if $@; all_pm_version_ok(); release-pod-coverage.t100644000764000144 134111723631714 20124 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::Pod::Coverage 1.08"; plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" if $@; eval "use Pod::Coverage::TrustPod"; plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage" if $@; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); Playlist.pm100644000764000144 1461511723631714 20121 0ustar00jquelinusers000000000000Audio-MPD-1.120610/lib/Audio/MPD# # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.008; use warnings; use strict; package Audio::MPD::Playlist; { $Audio::MPD::Playlist::VERSION = '1.120610'; } # ABSTRACT: class to mess MPD's playlist use Moose; use MooseX::Has::Sugar; use MooseX::SemiAffordanceAccessor; has _mpd => ( ro, required, weak_ref ); #-- # Constructor # # my $collection = Audio::MPD::Playlist->new( _mpd => $mpd ); # # This will create the object, holding a back-reference to the Audio::MPD # object itself (for communication purposes). But in order to play safe and # to free the memory in time, this reference is weakened. # # Note that you're not supposed to call this constructor yourself, an # Audio::MPD::Playlist is automatically created for you during the creation # of an Audio::MPD object. # #-- # Public methods # -- Playlist: retrieving information sub as_items { my ($self) = @_; my @list = $self->_mpd->_cooked_command_as_items("playlistinfo\n"); return @list; } sub items_changed_since { my ($self, $plid) = @_; return $self->_mpd->_cooked_command_as_items("plchanges $plid\n"); } # -- Playlist: adding / removing songs sub add { my ($self, @pathes) = @_; my $command = "command_list_begin\n" . join( '', map { my $p=$_; $p=~s/"/\\"/g; qq[add "$p"\n] } @pathes ) . "command_list_end\n"; $self->_mpd->_send_command( $command ); } sub delete { my ($self, @songs) = @_; my $command = "command_list_begin\n" . join( '', map { my $p=$_; $p=~s/"/\\"/g; "delete $p\n" } @songs ) . "command_list_end\n"; $self->_mpd->_send_command( $command ); } sub deleteid { my ($self, @songs) = @_; my $command = "command_list_begin\n" . join( '', map { "deleteid $_\n" } @songs ) . "command_list_end\n"; $self->_mpd->_send_command( $command ); } sub clear { my ($self) = @_; $self->_mpd->_send_command("clear\n"); } sub crop { my ($self) = @_; my $status = $self->_mpd->status; my $cur = $status->song; my $len = $status->playlistlength - 1; # we need to reverse the list, to remove the bigest ids before my $command = "command_list_begin\n" . join( '', map { $_ != $cur ? "delete $_\n" : '' } reverse 0..$len ) . "command_list_end\n"; $self->_mpd->_send_command( $command ); } # -- Playlist: changing playlist order sub shuffle { my ($self) = @_; $self->_mpd->_send_command("shuffle\n"); } sub swap { my ($self, $from, $to) = @_; $self->_mpd->_send_command("swap $from $to\n"); } sub swapid { my ($self, $from, $to) = @_; $self->_mpd->_send_command("swapid $from $to\n"); } sub move { my ($self, $song, $pos) = @_; $self->_mpd->_send_command("move $song $pos\n"); } sub moveid { my ($self, $song, $pos) = @_; $self->_mpd->_send_command("moveid $song $pos\n"); } # -- Playlist: managing playlists sub load { my ($self, $playlist) = @_; $self->_mpd->_send_command( qq[load "$playlist"\n] ); } sub save { my ($self, $playlist) = @_; $self->_mpd->_send_command( qq[save "$playlist"\n] ); } sub rm { my ($self, $playlist) = @_; $self->_mpd->_send_command( qq[rm "$playlist"\n] ); } no Moose; __PACKAGE__->meta->make_immutable; 1; =pod =head1 NAME Audio::MPD::Playlist - class to mess MPD's playlist =head1 VERSION version 1.120610 =head1 SYNOPSIS $mpd->playlist->shuffle; # and lots of other methods =head1 DESCRIPTION L is a class meant to access & update MPD's playlist. Note that you're not supposed to call the constructor yourself, an L is automatically created for you during the creation of an L object - it can then be used with the C accessor. =head1 RETRIEVING INFORMATION =head2 as_items my @items = $pl->as_items; Return an array of Ls, one for each of the songs in the current playlist. =head2 items_changed_since my @items = $pl->items_changed_since( $plversion ); Return a list with all the songs (as L objects) added to the playlist since playlist C<$plversion>. =head1 ADDING / REMOVING SONGS =head2 add $pl->add( $path [, $path [...] ] ); Add the songs identified by C<$path> (relative to MPD's music directory) to the current playlist. No return value. =head2 delete $pl->delete( $song [, $song [...] ] ); Remove the specified C<$song> numbers (starting from 0) from the current playlist. No return value. =head2 deleteid $pl->deleteid( $songid [, $songid [...] ] ); Remove the specified C<$songid>s (as assigned by mpd when inserted in playlist) from the current playlist. No return value. =head2 clear $pl->clear; Remove all the songs from the current playlist. No return value. =head2 crop $pl->crop; Remove all of the songs from the current playlist B the song currently playing. =head1 CHANGING PLAYLIST ORDER =head2 shuffle $pl->shuffle; Shuffle the current playlist. No return value. =head2 swap $pl->swap( $song1, $song2 ); Swap positions of song number C<$song1> and C<$song2> in the current playlist. No return value. =head2 swapid $pl->swapid( $songid1, $songid2 ); Swap the postions of song ID C<$songid1> with song ID C<$songid2> in the current playlist. No return value. =head2 move $pl->move( $song, $newpos ); Move song number C<$song> to the position C<$newpos>. No return value. =head2 moveid $pl->moveid( $songid, $newpos ); Move song ID C<$songid> to the position C<$newpos>. No return value. =head1 MANAGING PLAYLISTS =head2 load $pl->load( $playlist ); Load list of songs from specified C<$playlist> file. No return value. =head2 save $pl->save( $playlist ); Save the current playlist to a file called C<$playlist> in MPD's playlist directory. No return value. =head2 rm $pl->rm( $playlist ); Delete playlist named C<$playlist> from MPD's playlist directory. No return value. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ Collection.pm100644000764000144 2144111723631714 20406 0ustar00jquelinusers000000000000Audio-MPD-1.120610/lib/Audio/MPD# # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.008; use warnings; use strict; package Audio::MPD::Collection; { $Audio::MPD::Collection::VERSION = '1.120610'; } # ABSTRACT: class to query MPD's collection use Moose; use MooseX::Has::Sugar; use MooseX::SemiAffordanceAccessor; has _mpd => ( ro, required, weak_ref ); #-- # Constructor # # my $collection = Audio::MPD::Collection->new( _mpd => $mpd ); # # This will create the object, holding a back-reference to the Audio::MPD # object itself (for communication purposes). But in order to play safe and # to free the memory in time, this reference is weakened. # # Note that you're not supposed to call this constructor yourself, an # Audio::MPD::Collection is automatically created for you during the creation # of an Audio::MPD object. # #-- # Public methods # -- Collection: retrieving songs & directories sub all_items { my ($self, $path) = @_; $path ||= ''; $path =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[listallinfo "$path"\n] ); } sub all_items_simple { my ($self, $path) = @_; $path ||= ''; $path =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[listall "$path"\n] ); } sub items_in_dir { my ($self, $path) = @_; $path ||= ''; $path =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[lsinfo "$path"\n] ); } # -- Collection: retrieving the whole collection sub all_songs { my ($self, $path) = @_; return grep { $_->isa('Audio::MPD::Common::Item::Song') } $self->all_items($path); } sub all_albums { my ($self) = @_; return $self->_mpd->_cooked_command_strip_first_field( "list album\n" ); } sub all_artists { my ($self) = @_; return $self->_mpd->_cooked_command_strip_first_field( "list artist\n" ); } sub all_titles { my ($self) = @_; return $self->_mpd->_cooked_command_strip_first_field( "list title\n" ); } sub all_pathes { my ($self) = @_; return $self->_mpd->_cooked_command_strip_first_field( "list filename\n" ); } sub all_playlists { my ($self) = @_; return map { /^playlist: (.*)$/ ? ($1) : () } $self->_mpd->_send_command( "lsinfo\n" ); } sub all_genres { my ($self) = @_; return $self->_mpd->_cooked_command_strip_first_field( "list genre\n" ); } # -- Collection: picking songs sub song { my ($self, $what) = @_; $what =~ s/"/\\"/g; my ($item) = $self->_mpd->_cooked_command_as_items( qq[find filename "$what"\n] ); return $item; } sub songs_with_filename_partial { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[search filename "$what"\n] ); } # -- Collection: songs, albums, artists & genres relations sub albums_by_artist { my ($self, $artist) = @_; $artist =~ s/"/\\"/g; return $self->_mpd->_cooked_command_strip_first_field( qq[list album "$artist"\n] ); } sub songs_by_artist { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[find artist "$what"\n] ); } sub songs_by_artist_partial { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[search artist "$what"\n] ); } sub songs_from_album { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[find album "$what"\n] ); } sub songs_from_album_partial { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[search album "$what"\n] ); } sub songs_with_title { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[find title "$what"\n] ); } sub songs_with_title_partial { my ($self, $what) = @_; $what =~ s/"/\\"/g; return $self->_mpd->_cooked_command_as_items( qq[search title "$what"\n] ); } sub artists_by_genre { my ($self, $genre) = @_; $genre =~ s/"/\\"/g; return $self->_mpd->_cooked_command_strip_first_field( qq[list artist genre "$genre"\n] ); } no Moose; __PACKAGE__->meta->make_immutable; 1; =pod =head1 NAME Audio::MPD::Collection - class to query MPD's collection =head1 VERSION version 1.120610 =head1 SYNOPSIS my @songs = $mpd->collection->all_songs; # and lots of other methods =head1 DESCRIPTION L is a class meant to access & query MPD's collection. You will be able to use those high-level methods instead of using the low-level methods provided by mpd itself. Note that you're not supposed to call the constructor yourself, an L is automatically created for you during the creation of an L object - it can then be used with the C accessor. =head1 RETRIEVING SONGS & DIRECTORIES =head2 all_items my @items = $coll->all_items( [$path] ); Return B Ls (both songs & directories) currently known by mpd. If C<$path> is supplied (relative to mpd root), restrict the retrieval to songs and dirs in this directory. =head2 all_items_simple my @items = $coll->all_items_simple( [$path] ); Return B Ls (both songs & directories) currently known by mpd. If C<$path> is supplied (relative to mpd root), restrict the retrieval to songs and dirs in this directory. B: the L objects will only have their tag C filled. Any other tag will be empty, so don't use this sub for any other thing than a quick scan! =head2 items_in_dir my @items = $coll->items_in_dir( [$path] ); Return the items in the given C<$path>. If no C<$path> supplied, do it on mpd's root directory. Note that this sub does not work recusrively on all directories. =head1 RETRIEVING THE WHOLE COLLECTION =head2 all_songs my @songs = $coll->all_songs( [$path] ); Return B Ls currently known by mpd. If C<$path> is supplied (relative to mpd root), restrict the retrieval to songs and dirs in this directory. =head2 all_albums my @albums = $coll->all_albums; Return the list of all albums (strings) currently known by mpd. =head2 all_artists my @artists = $coll->all_artists; Return the list of all artists (strings) currently known by mpd. =head2 all_titles my @titles = $coll->all_titles; Return the list of all song titles (strings) currently known by mpd. =head2 all_pathes my @pathes = $coll->all_pathes; Return the list of all pathes (strings) currently known by mpd. =head2 all_playlists my @lists = $coll->all_playlists; Return the list of all playlists (strings) currently known by mpd. =head2 all_genres my @genres = $coll->all_genres; Return the list of all genres (strings) currently known by mpd. =head1 PICKING A SONG =head2 song my $song = $coll->song( $path ); Return the L which correspond to C<$path>. =head2 songs_with_filename_partial my @songs = $coll->songs_with_filename_partial( $string ); Return the Ls containing C<$string> in their path. =head1 SONGS, ALBUMS, ARTISTS & GENRES RELATIONS =head2 albums_by_artist my @albums = $coll->albums_by_artist( $artist ); Return all albums (strings) performed by C<$artist> or where C<$artist> participated. =head2 songs_by_artist my @songs = $coll->songs_by_artist( $artist ); Return all Ls performed by C<$artist>. =head2 songs_by_artist_partial my @songs = $coll->songs_by_artist_partial( $string ); Return all Ls performed by an artist with C<$string> in her name. =head2 songs_from_album my @songs = $coll->songs_from_album( $album ); Return all Ls appearing in C<$album>. =head2 songs_from_album_partial my @songs = $coll->songs_from_album_partial( $string ); Return all Ls appearing in album containing C<$string>. =head2 songs_with_title my @songs = $coll->songs_with_title( $title ); Return all Ls which title is exactly C<$title>. =head2 songs_with_title_partial my @songs = $coll->songs_with_title_partial( $string ); Return all Ls where C<$string> is part of the title. =head2 artists_by_genre my @artists = $coll->artists_by_genre( $genre ); Return all artists (strings) of C<$genre>. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ release-minimum-version.t100644000764000144 110211723631714 20702 0ustar00jquelinusers000000000000Audio-MPD-1.120610/t#!perl # # This file is part of Audio-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::MinimumVersion"; plan skip_all => "Test::MinimumVersion required for testing minimum versions" if $@; all_minimum_version_from_metayml_ok(); 000-report-versions-tiny.t100644000764000144 560111723631714 20575 0ustar00jquelinusers000000000000Audio-MPD-1.120610/tuse strict; use warnings; use Test::More 0.88; # This is a relatively nice way to avoid Test::NoWarnings breaking our # expectations by adding extra tests, without using no_plan. It also helps # avoid any other test module that feels introducing random tests, or even # test plans, is a nice idea. our $success = 0; END { $success && done_testing; } my $v = "\n"; eval { # no excuses! # report our Perl details my $want = '5.010'; my $pv = ($^V || $]); $v .= "perl: $pv (wanted $want) on $^O from $^X\n\n"; }; defined($@) and diag("$@"); # Now, our module version dependencies: sub pmver { my ($module, $wanted) = @_; $wanted = " (want $wanted)"; my $pmver; eval "require $module;"; if ($@) { if ($@ =~ m/Can't locate .* in \@INC/) { $pmver = 'module not found.'; } else { diag("${module}: $@"); $pmver = 'died during require.'; } } else { my $version; eval { $version = $module->VERSION; }; if ($@) { diag("${module}: $@"); $pmver = 'died during VERSION check.'; } elsif (defined $version) { $pmver = "$version"; } else { $pmver = ''; } } # So, we should be good, right? return sprintf('%-45s => %-10s%-15s%s', $module, $pmver, $wanted, "\n"); } eval { $v .= pmver('Audio::MPD::Common::Item','any version') }; eval { $v .= pmver('Audio::MPD::Common::Output','any version') }; eval { $v .= pmver('Audio::MPD::Common::Stats','any version') }; eval { $v .= pmver('Audio::MPD::Common::Status','any version') }; eval { $v .= pmver('DB_File','any version') }; eval { $v .= pmver('Encode','any version') }; eval { $v .= pmver('File::Find','any version') }; eval { $v .= pmver('File::Temp','any version') }; eval { $v .= pmver('Getopt::Euclid','any version') }; eval { $v .= pmver('IO::Socket::IP','any version') }; eval { $v .= pmver('Module::Build','0.3601') }; eval { $v .= pmver('Moose','any version') }; eval { $v .= pmver('Moose::Util::TypeConstraints','any version') }; eval { $v .= pmver('MooseX::Has::Sugar','any version') }; eval { $v .= pmver('MooseX::SemiAffordanceAccessor','any version') }; eval { $v .= pmver('Proc::Daemon','any version') }; eval { $v .= pmver('Test::Corpus::Audio::MPD','1.113282') }; eval { $v .= pmver('Test::More','0.88') }; eval { $v .= pmver('Time::HiRes','any version') }; eval { $v .= pmver('strict','any version') }; eval { $v .= pmver('warnings','any version') }; # All done. $v .= <<'EOT'; Thanks for using my code. I hope it works for you. If not, please try and include this output in the bug report. That will help me reproduce the issue and solve you problem. EOT diag($v); ok(1, "we really didn't test anything, just reporting data"); $success = 1; # Work around another nasty module on CPAN. :/ no warnings 'once'; $Template::Test::NO_FLUSH = 1; exit 0;