pax_global_header00006660000000000000000000000064115560425440014520gustar00rootroot0000000000000052 comment=72db1e36ea62eb9d1f510ab0cd15666915071e0a cplay-1.50/000077500000000000000000000000001155604254400125555ustar00rootroot00000000000000cplay-1.50/AUTHORS000066400000000000000000000010241155604254400136220ustar00rootroot00000000000000cplay was originally written by Ulf Betlehem. The current main contact for support, patches etc. is Tomi Pieviläinen . Other contributors include: Tom Adams Yoann AUBINEAU Charl P. Botha Chmouel Boudjnah Adrian C. Ricardo Niederberger Cabral Jesus Climent Jason M. Felice Jay Felice Samium Gromoff Väinö Järvelä Georg Lehner Jean-Nicolas Kuttler Daniel Michalik Martin Michlmayr Gergely Nagy Patrice Neff Antoine Reilles Peter Samuelson Gerald Stieglbauer Christian Storgaard Toni Timonen Moshe Zadka cplay-1.50/ChangeLog000066400000000000000000000440201155604254400143270ustar00rootroot000000000000002011-04-27 Tomi Pieviläinen *** 1.50 released *** * cplay: - fix insecure /tmp handling (DB#255768, DB#324913) (Peter Samuelson) - fix shell crashing (DB#375060) - UTF-8 support (DB#279000) - debug logging - mutagen support (with ogg/flac metadata and fix to DB#413738) - file recognition with magic (based on Jesus Climent) - mplayer support with equalizer and speed support (Tom Adams, Daniel Michalik) - preliminary ALSA mixer support (Tom Adams) - bugfixes (many authors) * cnq: New executable to enque tracks to cplay (Tom Adams, fixes DB#226167) 2006-05-09 Ulf Betlehem *** 1.50pre7 *** * cplay: - work-around backspace problem (shrizza) - shell crash work-around 2005-11-10 Ulf Betlehem *** 1.50pre6 *** * cplay: - share filedescriptors (Antoine Reilles) 2005-10-21 Ulf Betlehem *** 1.50pre5 *** Over a year since last pre-release! I will probably have broken more things than I have fixed, but here goes: * cplay: - fixed URL bug on command line (Georg Lehner) - replaced deprecated apply() - one-line scrolling - continue after errors during recursive add - added FrameOffsetPlayerMpp - handle_command a bit differently 2004-07-25 Ulf Betlehem *** 1.50pre4 *** * cplay: - ogg123 now handles .flac and .spx - require either ID3 or ogg modules for viewing metadata 2004-02-09 Ulf Betlehem *** 1.50pre3 *** * cplay: - replaced volup and voldown FIFOControl commands with one "volume set|cue|toggle N" command - removed inc_volume and dec_volume wrappers - added FIFOControl command "empty" (delete playlist) * lircrc: - volup, voldown => volume command 2004-02-07 Ulf Betlehem *** 1.50pre2 *** * po/pt_BR.po: - new file (Ricardo Niederberger Cabral) * cplay: - allow shell from playlist - user definable macros (for example MACRO['d'] = '!rm "$@"\n') - new remote control commands: macro , add * README: - documented macros and shell positional arguments 2004-02-07 Ulf Betlehem *** 1.50pre1 *** * cplay: - user definable macros (for example MACRO['d'] = '!rm "$@"\n') - new remote control commands: macro , add * README: - documented macros and shell positional arguments 2004-02-05 Ulf Betlehem * README: - mkfifo /var/tmp/cplay_control (Ricardo Niederberger Cabral) 2004-01-07 Ulf Betlehem * po/Makefile, Makefile: - SHELL = /bin/bash (Murphy) 2003-12-05 Ulf Betlehem *** 1.49 released *** * README, cplay.1: - document restricted mode 2003-11-08 Ulf Betlehem *** 1.49pre4 *** * cplay: - restricted mode (suggested by Yoann AUBINEAU) - connect player stdin to a pipe - removed sleep(1) if player exec failed - combined pause/unpause -> toggle_pause - no parse_buf() if stopped or seeking - removed --no-tty-control from madplay (stdin no longer tty) - reduced codesize 2003-11-06 Ulf Betlehem * cplay: - use 'm' for bookmarking instead of 'b' - minor code clean-up - modified help page 2003-11-02 Ulf Betlehem *** 1.49pre3 *** * cplay.list: - ESP Package Manager support (http://www.easysw.com/epm/) * cplay: - removed excessive update() from get_bookmark() - rewritten delete and move commands for speed 2003-11-01 Ulf Betlehem * cplay: - move active status support from ListEntry to PlaylistEntry 2003-10-04 Ulf Betlehem * cplayrc: - removed execute permissions 2003-10-01 Ulf Betlehem * cplay: - possible bugfix for increasing CPU usage 2003-10-01 Ulf Betlehem *** 1.49pre2 *** * cplay: - possible bugfix for increasing CPU usage 2003-09-28 Ulf Betlehem * cplay: - use curses.KEY_ENTER for xwsh (wave++) 2003-09-13 Ulf Betlehem *** 1.49pre1 *** * cplay: - support and prefer ossaudiodev (dorphell) 2003-09-01 Ulf Betlehem * cplay: - fixed playlist identification for 1.48 (Jean-Nicolas Kuttler) 2003-08-28 Ulf Betlehem * Makefile: - cplayrc generation * cplay.1: - execute both /etc/cplayrc and ~/.cplayrc - ignore /etc/cplayrc if ~/.cplayrc exists - speex - xmp * README: - speex - ~/.cplayrc 2003-08-26 Ulf Betlehem *** 1.48 released *** * cplay: - xmp regexp (Yuri D'Elia) - URL support in mpg123 regexp (Martin Michlmayr) - rudimentary /etc/cplayrc support (Toni Timonen) * cplay.1: - xmp, play and cplayrc references * cplayrc: - new file 2003-08-20 Ulf Betlehem * cplay(1.48pre1): - discontinue python1.5 support - mixer/volume control using python-oss module - horizontal scrolling with < and > - show tail (was head) of long input lines - import random instead of whrandom - minor progress parsing modification - NoOffsetPlayer simply counts seconds (Martin Michlmayr) - TimeOffsetPlayer with full madplay support - added partial xmp and play (sox) support 2003-08-17 Ulf Betlehem * po/hu.po: - new file (Gergely Nagy) * po/pl.po: - new file (Perry) - fixed help text not showing * po/da.po: - new file (Christian Storgaard) - specified charset/encoding 2003-05-13 Ulf Betlehem * cplay: - display "Adding tagged files" instead of a separate message for each file (Martin Michlmayr) - avoid error-messages when interrupting cplay when started via xargs (Moshe Zadka) 2003-04-13 Ulf Betlehem *** 1.47 released *** * README: - mp3info and ogginfo modules are both required * TODO: *** empty log message *** * cplay.1: - mention help window - shell command and positional parameters - document control_fifo in FILES section - BUGS section 2003-04-11 Ulf Betlehem * cplay(1.47rc4): - removed "quit silently" command-line option (use Q instead) - fixed missing ": " for isearch-prompt - always add absolute paths to playlist (args and stdin) 2003-04-10 Ulf Betlehem * cplay(1.47rc3): - uses glob.glob() instead of fnmatch.filter() 2003-04-08 Ulf Betlehem * cplay(1.47rc2): - bugfix * cplay(1.47rc1): - status and title now use viewpoints (l) - hide cursor after shell command - help window updates 2003-04-07 Ulf Betlehem * cplay(1.47pre5): - '!' shell command with positional args - TAB completion - kill word/line with C-w/C-u - invert tags command 'i' - removed hide partial pathnames feature - renamed 'X' from [manual] to [stop] - bookmarks - fixed .. -> ../ - actually chdir in filelist - fixed seek/stop/pause crash - minor code cleanup 2003-03-02 Ulf Betlehem * cplay(1.47pre4): - X toggles manual/automatic playlist advancement (Väinö Järvelä) - C-s C-s now remembers previous isearch string - minor code cleanup here and there - absolute seeking with C-a and ^ for bof, C-e and $ for eof - HelpWindow includes "Undocumented commands" - seeking now yield similar results when stopped and paused - fixed byteorder issues with mixer on different architectures? 2003-02-09 Ulf Betlehem * cplay(1.47pre3): - The "Quit? (y/N)" prompt no longer requires Enter. - The number of dirs to hide can be adjusted with < and > for the pathname viewpoint. However, this might still change. - Sorting is now done according to viewpoint, which means that 'S' no longer toggles sorting methods. - Minor help window updates. 2003-01-30 Ulf Betlehem * cplay(1.47pre2): - command line option to quit silently without confirmation - isearch speedup (suggested by Eric Max Francis) - viewpoint speedup 2003-01-25 Ulf Betlehem * cplay(1.47pre1): - added os.path.exists check to get_tag() 2002-12-16 Ulf Betlehem * lircrc: - new file (Pugo) * cplay: - documented @ command - get_tag improvement (Martin Michlmayr) * cplay.1: - combined v and V options into one. 2002-12-16 Ulf Betlehem *** 1.46 released *** * cplay: - documented @ command - get_tag improvement (Martin Michlmayr) * cplay.1: - combined v and V options into one. 2002-12-04 Ulf Betlehem * cplay (1.46rc1): - includes latest version of Martin's get_tag 2002-11-30 Ulf Betlehem * cplay (1.46pre9): - alternative metadata support through get_tag (Martin Michlmayr) - misc refactoring: TagListWindow, PlaylistEntry, etc. - scrollable Help Window - fixed keybinding for toggle counter mode - new @ command that jumps to the active playlist entry - removed V command and option, v toggles MASTER/PCM instead - removed custom normpath 2002-11-08 Ulf Betlehem * cplay.1: - Use minuses instead of hyphens for command line options. (Martin) 2002-10-27 Ulf Betlehem * cplay (1.46pre8) - modified keymap! - updated help window - filelist tagging support (based on a patch by Jason M. Felice) - improved status message behavior - added retry if resize failed - show cursor in input mode 2002-10-24 Ulf Betlehem * cplay (1.46pre7) - a couple of status message changes - faster delete when not in random mode - rudimentary .pls playlist support - improved streaming support - advance playlist if player not found - changed player priority order 2002-10-21 Ulf Betlehem * cplay (1.46pre6) - new and improved random mode (Radu) 2002-10-20 Ulf Betlehem * cplay: - refactoring - list mode (l = toggle viewpoints) - q = quit (y/n) and Q = Quit immediately - isearch turnaround change - input cursor position - recursive search duplicates fix - case insensitive regex marking - regex marking matches viewpoint - VALID_SONG regex matches basename - playlist sorting by filename or pathname - don't move empty list of marked entries - SIGTERM -> SIGINT (again) - updated mikmod switches 2002-10-15 Ulf Betlehem * cplay: - pad input with space for cursor position 2002-10-11 Ulf Betlehem * cplay (1.46pre5) - string.punctuation kludge for python 1.5 - recursive search in filelist! - include 669|mtm|it in mikmod regex (Samium Gromoff) 2002-08-28 Ulf Betlehem * cplay (1.46pre4) - bugfix 2002-08-28 Ulf Betlehem * cplay (1.46pre3) - LIRC support via control FIFO (Pugo) 2002-08-21 Ulf Betlehem * cplay (1.46pre2) - allow printable chars as input - alias commands: Q for q and = for + - grid bug removed from line number display - keep current position after auto filelist updates - quiet auto filelist updates (Martin Michlmayr) - select child in filelist after a parent command - parse player output only once every second - PCM/MASTER volume commands show current volume * LICENSE: new file 2002-03-31 Ulf Betlehem * cplay (1.46pre1) - remember playlist filename (Patrice Neff) 2002-03-24 Ulf Betlehem *** 1.45 released *** 2002-03-19 Ulf Betlehem * cplay (1.45pre5): - emulate insstr() for python1.5 - new commands m/M = move after/before - new command D = delete current (Jay Felice) - line numbers 2002-01-19 Ulf Betlehem * cplay (1.45pre4): - added options -v and -V to control either PCM or MASTER volume - increase and decrease volume in steps of 3% (kludge) 2002-01-13 Ulf Betlehem * cplay (1.45pre3): - progressbar cosmetics - tilde expansion (Patrice Neff) 2001-12-27 Ulf Betlehem * cplay (1.45pre2): - added "--no-tty-control" option for madplay - removed "-d oss" option from ogg123 (Han) - use insstr instead of addstr to work around a classical curses- problem with writing the rightmost character without scrolling. 2001-12-01 Ulf Betlehem *** 1.44 released *** * cplay: - partial support for madplay - partial support for mikmod (yason) - removed sox support - unless someone needs it - toggle counter mode: time done / time left - seek acceleration based on song length - avoid listing dot-files (Martin Michlmayr) - remove ".." entry from root (Martin Michlmayr) - show playlist upon startup if playing (Patrice Neff) - removed TERMIOS warning with recent python versions - add directories from command line (Han) - fixed x-bug (Chris Liechti) - changed write_playlist key from 'o' to 'w' - changed goto command key from 'g' to 'o' - added 'g' (home) and 'G' (end) keys - added '/' and '?' keys for searching - misc tweaks * cplay.1: - update * README: - update 2001-03-15 Ulf Betlehem *** 1.43 released *** * cplay: - partial support for splay - commandline arguments: repeat/random (Gerald Stieglbauer) - volume fine tuning via +/- (Martin Michlmayr) - simplified player framework - mark/clear regexp 2001-01-18 Ulf Betlehem *** 1.42 released *** * cplay: - ignore bogus gettext module - correct devfs paths - use seconds instead of frames - shuffle speedup (Martin Persson) - changed player hierarchy - improved ogg123 support 2000-12-08 Ulf Betlehem *** 1.41 released *** * README: a few words about mpg123 and streaming * po/de.po, cplay.1: updated (Martin Michlmayr) * po/Makefile, Makefile: use "install -c" for compatibility * cplay: - autoplay initial playlist - is now a front-end for various audio players - ogg123 support (Martin Michlmayr) - devfs paths (Martin Michlmayr) - playlist url support (Charl P. Botha) - fixed signalling bug - minor code cleanup 2000-10-19 Ulf Betlehem *** v1.40 released *** * README: added instructions on how to change player options * cplay: new versioning scheme fixed locale setting python 2.0 compatible prefers standard gettext to fintl delayed warnings for missing players and unknown fileformats fixed hline with zero length in progressline set title to xterm in cleanup better support for mpg123 buffers by signalling progress groups * README: modified usage * Makefile: install man page * cplay.1: man page (Martin Michlmayr) * ChangeLog, TODO: new entry * po/de.po: update (Martin Michlmayr) 2000-09-06 Ulf Betlehem * cplay: Python 1.6 compatible 2000-08-09 Ulf Betlehem * po/de.po: new file * po/Makefile: new Makefile * killpgmodule.c: *** empty log message *** * README: new README * Makefile: new Makefile 2000-07-31 Ulf Betlehem * cplay: added i18n support by Martin Michlmayr fixed locale support 2000-07-25 Ulf Betlehem * cplay: added support for sox to play .wav, .au and other sound formats * cplay: shows status in titlebar under X -- thanks Chmouel Boudjnah 2000-05-23 Ulf Betlehem * cplay: doesn't stat() cwd when idle * cplay: supports both pyncurses and the old cursesmodule 2000-04-24 Ulf Betlehem * cplay: - restores terminal settings on exceptions - global mp3 and m3u regexps - new and improved keymap class - removed a possible "division by zero" bug 2000-03-24 Ulf Betlehem * cplay: translate evil characters to '?' 2000-02-07 Ulf Betlehem * cplay: fixed a bug in FilelistWindow.add_dir() 2000-01-20 Ulf Betlehem * cplay: - changed the player class so that one can hold down 'n' or 'p' when changing tracks without cplay crashing ;) 2000-01-19 Ulf Betlehem * cplay: Enter now plays files bypassing the playlist Space adds files to playlist a adds recursively z toggles pause x toggles stop m3u lines beginning with '#' are now silently discarded 1999-12-22 Ulf Betlehem * cplay: - lot's of small changes 1999-12-13 Ulf Betlehem * cplay: handles SIGWINCH correctly automatically rereads current dir when modified lot's of minor changes 1999-10-26 Ulf Betlehem * cplay: Added two commands: R = random play order (keeps your playlist intact) S = sort playlist by filename Removed a seldom used (also undocumented) command: N = previous track 1999-05-10 Ulf Betlehem * cplay: catches os.error if os.listfiles() fails. 1999-02-13 Ulf Betlehem * cplay: Added error-checking to prevent manipulating empty playlists. Raised default seek speed from Pi to 4. 1999-02-07 Ulf Betlehem * cplay: Corrected a feature that caused automatic loading of playlists upon entering a directory where the cursor was over a .m3u file. 1999-01-29 Ulf Betlehem * cplay: Uses frames_done and frames_left instead of time_done and time_left. Minor code clean-up. * cplay: Now supports at least mpg123 v0.59o through v0.59q 1999-01-19 Ulf Betlehem * cplay: o Is now "pure Python", which means there is no need for the killpgmodule.so anymore. Oh, joy! o mpg123 is now automatically located in the PATH if not specified absolutely. o Moved mark() to 'space' and pause_or_unpause() to 'p' and stop_or_unstop() to 'k'. o Playlists are now always saved with the extension .m3u. 1998-12-11 Ulf Betlehem * cplay: now consumes anything written on stdout 1998-11-29 Ulf Betlehem * cplay: select() now only timeouts when necessary. 1998-11-20 Ulf Betlehem * cplay: added PlaylistWindow.command_mark_all() 1998-11-12 Ulf Betlehem * cplay: SIGTERM -> SIGINT * cplay: fixed sigchld bug added help window 1998-11-11 Ulf Betlehem * cplay: random -> whrandom * cplay: Too many changes! Reorganization Change of policy 1998-10-29 Ulf Betlehem * cplay: separated PLAYER and COMMAND checks if the PLAYER is valid before it continues 1998-10-27 Ulf Betlehem * cplay: kludged mixed case in curses constants 1998-10-12 Ulf Betlehem * cplay: support for curses module versions with different key-case. 1998-10-05 Ulf Betlehem * cplay: changed progress bar * killpgmodule.c: New file. 1998-04-29 Ulf Betlehem * cplay: remember bufptr of directories 1998-04-20 Ulf Betlehem * cplay: code cleanup 1998-04-18 Ulf Betlehem * cplay: New file. cplay-1.50/LICENSE000066400000000000000000000431311155604254400135640ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU 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. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), 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 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 show them these terms so they know 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. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. 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 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 derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 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 License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 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. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary 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 License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 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 Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing 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 for copying, distributing or modifying the Program or works based on it. 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. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. 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 this 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 this License, you may choose any version ever published by the Free Software Foundation. 10. 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 11. 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. 12. 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 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 the public, 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) 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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 is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. cplay-1.50/Makefile000066400000000000000000000007501155604254400142170ustar00rootroot00000000000000PREFIX = /usr/local ENV = PREFIX=$(PREFIX) SUBDIRS = po all: recursive-all install: recursive-install install -c -m 755 cplay $(PREFIX)/bin install -c -m 755 cnq $(PREFIX)/bin install -c -m 644 cplay.1 $(PREFIX)/man/man1 clean: recursive-clean recursive-all recursive-install recursive-clean: @target=$@; \ for i in $(SUBDIRS); do \ (cd $$i && make $(ENV) $${target#recursive-}); \ done cplayrc: cplay awk '/^PLAYERS/ {p=1} /^$$/ {p=0} {if (p==1) {print}}' cplay > cplayrc cplay-1.50/README000066400000000000000000000056151155604254400134440ustar00rootroot00000000000000Description: cplay is a curses front-end for various audio players. It aims to provide a power-user-friendly interface with simple filelist and playlist control. cplay is written in Python and can use either pyncurses or the standard curses module. Requirements: - python http://www.python.org/ - pyalsaaudio (optional) http://pyalsaaudio.sourceforge.net/ For Alsa mixer support - mutagen (optional) http://code.google.com/p/mutagen/ For metadata support (IDv3 etc.) - magic (optional) http://www.darwinsys.com/file/ For better filetype recognition For playback either install mplayer (recommended): http://www.mplayerhq.hu/ or one or more of the following players: - mpg321 http://sourceforge.net/projects/mpg321/ - ogg123 http://www.vorbis.com/ - mpg123 http://www.mpg123.org/ - splay http://splay.sourceforge.net/ - madplay http://www.mars.org/home/rob/proj/mpeg/ - mikmod http://www.mikmod.org/ - xmp http://xmp.sf.net/ - sox http://sox.sf.net/ - speex http://www.speex.org/ Installation: make install Usage: cplay [-d ] [-n] [-r] -[R] [ file | dir | playlist ] ... -d Enable debugging output to . -n Start in restricted mode: No shell commands, changing directory, goto, or saving playlists. -r Start in repeat mode. -R Start in random mode. When in doubt, press 'h' for a friendly help page. Configuration: If you would like to change options passed to the actual players just edit the PLAYERS list in the cplay script or put the PLAYERS definition in either ~/.cplayrc or /etc/cplayrc. If one of these files is available, it is executed by cplay before initialization. Macros are defined using the MACRO dictionary, where the key is a key and the value is a string of cplay input. For example, the following would make ,d delete tagged (or current) files: MACRO['d'] = '!rm "$@"\n' Note, there is currently no version control for the rc-file! Miscellaneous: A playlist can contain URLs, but the playlist itself will have to be local. For mpeg streaming, splay is recommended. It is also possible to pipe a playlist to cplay, as stdin will be reopened on startup unless it is attached to a tty. Remote control is available via /var/tmp/cplay_control-$USER. Create this with mkfifo and see lircrc for examples. The shell command gets the full path of either all tagged items or the current item as positional arguments. cplay-1.50/TODO000066400000000000000000000125311155604254400132470ustar00rootroot00000000000000Keymap ------------------------------------------ Filelist: _b_def___________r____w_y_ ABCDEF_HI__LMNOP_RS__VWXYZ Playlist: ab__ef________o_________y_ ABC_EF_HI__L_NOP_____VW_YZ Overload: ____________m_____s_______ __________________________ TODO ------------------------------------------ x - external mixer framework (MIXERS list?) x - select player based on magic? 1 - use 00:00:00 instead of 00h 00m 00s ? x - remove inc_volume and dec_volume when control fifo takes args 4 - support wma (via mplayer?) 3 - support musepack 3 - support midi players 3 - support flac (command line player?) 3 - support xmms? x - replace current playlist (useful when streaming?) x - browse bookmarks? 3 - use "file" to both get mime-type and bitrate info? 2 - backspace does not work on gentoo? x - index-mode: group/sort/search by ctime, filename, metadata, etc. x - screen title patch x - tree view patch: expand 2 or more dirs mode for filelist? 4 - don't require both ID3 and pyogg for one of them to work - how to enable the metadata viewpoint? x - get_tag() is messy 5 - don't try to write m3u to search results path 4 - don't write dir/.m3u files for w + enter x - search results mode vs path x - shell from playlist? (requires new tab-completion?) 3 - incremental filter command 'f' like *amp 'j' 4 - optionally show all files in a dir 2 - show alternatives in filelist for ambiguous completion? 1 - :commands? x - macros / bind user commands 3 - center current line (requires one-line scrolling) x - shell prompt could show number of args? (tagged entries) 5 - change cwd for shell commands (crash if "search results"!?) x - embed search command in pathname to view in filelist? (bookmark results) - /path/name?search=args or /path/name?index=args - will allow bookmarks, except for refined searches? - don't allow bookmarking in search results (mode) x - command-line history? (now cursor-up cancels) x - persistence: save state on exit? x - replace help window with generic show file window (move help -> file) x - shuffle & sort tagged entries only? x - searching for empty string not currently possible with / x - make isearch use regexes? x - sanity check: (pause or stopped) and seek => play? 4 - add status message for unbound keys / commands x - change number of parent dirs to show .. makes pathname viewpoint obsolete? x - search/tag regex/... on str(entry) or entry.vp() ? .. currently sorting by vp, tagging by str and searching by str 2 - wait 0.5s between subsequent next/prev. NOT before starting player! .. or pause current player immediately on next/prev commands? .. compare with repeating enter? 3 - rc-file with 1. player configs 2. metadata viewpoint format 3. pathname viewpoint number of dirs to show (command also?) 4. persistent bookmarks 4 - enter opens playlists as virtual dir in filelist 5 + restricted mode (bang, write m3u, open path, soft chroot) 4 - pls-playlist TITLE and LENGTH support 3 - programmable delay between songs (useful for synchronized recording) 1 - improve isearch using bookmarks for previous position? 4 - error msg when following broken links (what?) 4 - don't block on slow commands (eg. listdir / add dir / recursive search) 2 - fast Esc (not possible with keypad?) 2 - hide cursor after SUSP & CONT cycle 4 - metadata info page 4 - try small screen layout patch 2 - check against old ogg.and.mp3.info.patch for missing features 3 - use i to toggle *info window? 5 - recursive search should save bufptr of prev dir 3 - clean up app.player.is_stopped() and app.kludge mess 2 - which -> WHICH (upcase global functions?) 3 - howto select player for streaming http://ip:port urls? misc thoughts ------------------------------------------ - use & for delayed commands? - import on demand wrapper? - mark or delete duplicate or no-longer existing playlist entries - locate and jump to (show) current playlist entry in the filelist - fork and exec /bin/sh and select on pipe for command completion? - use C as a shortcut for untag/clear all? - suspend + resize + continue -> should resize - sort search results - dynamic help page? - better input support (readline?) - toggle header / small screen mode (treshold?) - randomly play albums (groups / hierarchical playlist) - delwin before/in/after resize? - different marks/tags for filelist and playlist? - dust off id3 patch? - dust off cddb patch? - filtered point of view (obsoleted by recursive searching?) - mark filelist entries already in playlist - alternative scrolling method - metadata editor? - reread dir => search for current entry - support alsaplayer, xmp, others? - support cd-players? - delayed play or mark as next command (play after current is finished) - use 'N' to mark as next? - reset progress at end of playlist? (or when changing song?) - restore xterm title (not possible with aterm, rxvt, etc?) - mpg123 gives jumpy progress info for vbr files (averaging filter?) - should there be another way to start playing the playlist from the beginning than "next track"? (and Tab+Enter) - more vi-friendly keymap? - numerical arguments? - n and N could correspond to next and previous - f and b could select next and previous track? - a/A = Append mp3/dir - i/I = Insert mp3/dir - Meta-<, Meta-> commands? (avoid meta) - show progress-counter while streaming? - support slang? - fade in/out mode? (a la repeat/random) - crossfade mode - is Enter and cursor position logical / intuitive? (absolutely) cplay-1.50/cnq000077500000000000000000000025471155604254400132740ustar00rootroot00000000000000#!/usr/bin/env python # -*- python -*- """ cnq - enqueue files and URLs into cplay Copyright (C) 2009 Tom Adams 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ import os, sys CONTROL_FIFO = "%s/cplay-control-%s" % (os.environ.get("TMPDIR", "/tmp"), os.environ["USER"]) if __name__ == "__main__": if len(sys.argv) < 2: print('Arguments, please.') sys.exit(1) if os.path.exists(CONTROL_FIFO): fd = open(CONTROL_FIFO, "wb", 0) for a in sys.argv[1:]: if not a.startswith('http'): a = os.path.abspath(os.path.curdir) + '/' + a fd.write('add %s\n' % a) fd.close() else: print('Could not find %s.' % CONTROL_FIFO) sys.exit(2) cplay-1.50/cplay000077500000000000000000002006151155604254400136170ustar00rootroot00000000000000#!/usr/bin/env python # -*- python -*- __version__ = "cplay 1.50" """ cplay - A curses front-end for various audio players Copyright (C) 1998-2005 Ulf Betlehem 2005-2010 see AUTHORS 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ import curses import getopt import gettext import locale import logging import os import re import select import signal import string from subprocess import call import sys import time import traceback import tty locale.setlocale(locale.LC_ALL, "") code = locale.getpreferredencoding() _locale_domain = "cplay" _locale_dir = "/usr/local/share/locale" gettext.install(_locale_domain, _locale_dir) global mg try: import magic mg = magic.open(magic.MAGIC_NONE) mg.load() except ImportError: mg = None XTERM = re.search("rxvt|xterm", os.environ["TERM"]) CONTROL_FIFO = ("%s/cplay-control-%s" % (os.environ.get("TMPDIR", "/tmp"), os.environ["USER"])) # Ten band graphical equalizers for mplayer, see man (1) mplayer # Default: first entry EQUALIZERS = [ ("0:0:0:0:0:0:0:0:0:0", "flat"), ("3:3:3:2:0:-1:-1:0:0:1", "rock"), ] SPEED_OFFSET = 0.005 # ------------------------------------------ def which(program): for path in string.split(os.environ["PATH"], ":"): if os.path.exists(os.path.join(path, program)): return os.path.join(path, program) # ------------------------------------------ def cut(s, n, left=0): if left: return len(s) > n and "<%s" % s[-n+1:] or s else: return len(s) > n and "%s>" % s[:n-1] or s # ------------------------------------------ class Stack: def __init__(self): self.items = () def push(self, item): self.items = (item,) + self.items def pop(self): self.items, item = self.items[1:], self.items[0] return item # ------------------------------------------ class KeymapStack(Stack): def process(self, code): for keymap in self.items: if keymap and keymap.process(code): break # ------------------------------------------ class Keymap: def __init__(self): self.methods = [None] * curses.KEY_MAX def bind(self, key, method, args=None): if isinstance(key, (tuple, list)): for i in key: self.bind(i, method, args) return elif isinstance(key, str): key = ord(key) self.methods[key] = (method, args) def process(self, key): if self.methods[key] is None: return 0 method, args = self.methods[key] if args is None: args = (key,) method(*args) return 1 # ------------------------------------------ class Window: chars = string.letters+string.digits+string.punctuation+string.whitespace def __init__(self, parent): self.parent = parent self.children = [] self.name = None self.keymap = None self.visible = 1 self.resize() if parent: parent.children.append(self) def insstr(self, s): if not s: return self.w.addstr(s[:-1]) self.w.hline(ord(s[-1]), 1) # insch() work-around def __getattr__(self, name): return getattr(self.w, name) def getmaxyx(self): y, x = self.w.getmaxyx() try: curses.version # tested with 1.2 and 1.6 except AttributeError: # pyncurses - emulate traditional (silly) behavior y, x = y+1, x+1 return y, x def touchwin(self): try: self.w.touchwin() except AttributeError: self.touchln(0, self.getmaxyx()[0]) def attron(self, attr): try: self.w.attron(attr) except AttributeError: self.w.attr_on(attr) def attroff(self, attr): try: self.w.attroff(attr) except AttributeError: self.w.attr_off(attr) def newwin(self): return curses.newwin(curses.tigetnum('lines'), curses.tigetnum('cols'), 0, 0) def resize(self): self.w = self.newwin() self.ypos, self.xpos = self.getbegyx() self.rows, self.cols = self.getmaxyx() self.keypad(1) self.leaveok(0) self.scrollok(0) for child in self.children: child.resize() def update(self): self.clear() self.refresh() for child in self.children: child.update() # ------------------------------------------ class ProgressWindow(Window): def __init__(self, parent): Window.__init__(self, parent) self.value = 0 def newwin(self): return curses.newwin(1, self.parent.cols, self.parent.rows-2, 0) def update(self): self.move(0, 0) self.hline(ord('-'), self.cols) if self.value > 0: self.move(0, 0) x = int(self.value * self.cols) # 0 to cols-1 x and self.hline(ord('='), x) self.move(0, x) self.insstr('|') self.touchwin() self.refresh() def progress(self, value): self.value = min(value, 0.99) self.update() # ------------------------------------------ class StatusWindow(Window): def __init__(self, parent): Window.__init__(self, parent) self.default_message = '' self.current_message = '' self.tid = None def newwin(self): return curses.newwin(1, self.parent.cols-12, self.parent.rows-1, 0) def update(self): self.move(0, 0) self.clrtoeol() self.insstr(cut(self.current_message, self.cols)) self.touchwin() self.refresh() def status(self, message, duration = 0): self.current_message = str(message) if self.tid: app.timeout.remove(self.tid) if duration: self.tid = app.timeout.add(duration, self.timeout) else: self.tid = None self.update() def timeout(self): self.tid = None self.restore_default_status() def set_default_status(self, message): if self.current_message == self.default_message: self.status(message) self.default_message = message XTERM and sys.stderr.write("\033]0;%s\a" % (message or "cplay")) def restore_default_status(self): self.status(self.default_message) # ------------------------------------------ class CounterWindow(Window): def __init__(self, parent): Window.__init__(self, parent) self.values = [0, 0] # [seconds elapsed, seconds remaining # of current track] self.mode = 1 def newwin(self): return curses.newwin(1, 11, self.parent.rows-1, self.parent.cols-11) def update(self): h, s = divmod(self.values[self.mode], 3600) m, s = divmod(s, 60) self.move(0, 0) self.attron(curses.A_BOLD) self.insstr("%02dh %02dm %02ds" % (h, m, s)) self.attroff(curses.A_BOLD) self.touchwin() self.refresh() def counter(self, values): """Update the counter with [elapsed, remaining] seconds""" if (values[0] < 0 or values[1] < 0): logging.debug("Player reported negative value for (remaining) playing time.") else: self.values = values self.update() def toggle_mode(self): self.mode = not self.mode tmp = [_("elapsed"), _("remaining")][self.mode] app.status(_("Counting %s time") % tmp, 1) self.update() # ------------------------------------------ class RootWindow(Window): def __init__(self, parent): Window.__init__(self, parent) keymap = Keymap() app.keymapstack.push(keymap) self.win_progress = ProgressWindow(self) self.win_status = StatusWindow(self) self.win_counter = CounterWindow(self) self.win_tab = TabWindow(self) keymap.bind(12, self.update, ()) # C-l keymap.bind([curses.KEY_LEFT, 2], app.seek, (-1, 1)) # C-b keymap.bind([curses.KEY_RIGHT, 6], app.seek, (1, 1)) # C-f keymap.bind([1, '^'], app.seek, (0, 0)) # C-a keymap.bind([5, '$'], app.seek, (-1, 0)) # C-e keymap.bind(range(48,58), app.key_volume) # 0123456789 keymap.bind(['+'], app.mixer, ("cue", 1)) keymap.bind('-', app.mixer, ("cue", -1)) keymap.bind('n', app.next_song, ()) keymap.bind('p', app.prev_song, ()) keymap.bind('z', app.toggle_pause, ()) keymap.bind('x', app.toggle_stop, ()) keymap.bind('c', self.win_counter.toggle_mode, ()) keymap.bind('Q', app.quit, ()) keymap.bind('q', self.command_quit, ()) keymap.bind('v', app.mixer, ("toggle",)) keymap.bind(',', app.command_macro, ()) keymap.bind('[', app.speed_decr, ()) # FIXME Document this keymap.bind(']', app.speed_incr, ()) # FIXME Document this keymap.bind('=', app.speed_reset, ()) # FIXME Document this keymap.bind('e', app.eq_next, ()) # FIXME Document this keymap.bind('E', app.eq_prev, ()) # FIXME Document this def command_quit(self): app.do_input_hook = self.do_quit app.start_input(_("Quit? (y/N)")) def do_quit(self, ch): if chr(ch) == 'y': app.quit() app.stop_input() # ------------------------------------------ class TabWindow(Window): def __init__(self, parent): Window.__init__(self, parent) self.active_child = 0 self.win_filelist = self.add(FilelistWindow) self.win_playlist = self.add(PlaylistWindow) self.win_help = self.add(HelpWindow) keymap = Keymap() keymap.bind('\t', self.change_window, ()) # tab keymap.bind('h', self.help, ()) app.keymapstack.push(keymap) app.keymapstack.push(self.children[self.active_child].keymap) def newwin(self): return curses.newwin(self.parent.rows-2, self.parent.cols, 0, 0) def update(self): self.update_title() self.move(1, 0) self.hline(ord('-'), self.cols) self.move(2, 0) self.clrtobot() self.refresh() child = self.children[self.active_child] child.visible = 1 child.update() def update_title(self, refresh = 1): child = self.children[self.active_child] self.move(0, 0) self.clrtoeol() self.attron(curses.A_BOLD) self.insstr(child.get_title()) self.attroff(curses.A_BOLD) if refresh: self.refresh() def add(self, Class): win = Class(self) win.visible = 0 return win def change_window(self, window = None): app.keymapstack.pop() self.children[self.active_child].visible = 0 if window: self.active_child = self.children.index(window) else: # toggle windows 0 and 1 self.active_child = not self.active_child app.keymapstack.push(self.children[self.active_child].keymap) self.update() def help(self): if self.children[self.active_child] == self.win_help: self.change_window(self.win_last) else: self.win_last = self.children[self.active_child] self.change_window(self.win_help) app.status(__version__, 2) # ------------------------------------------ class ListWindow(Window): def __init__(self, parent): Window.__init__(self, parent) self.buffer = [] self.bufptr = self.scrptr = 0 self.search_direction = 0 self.last_search = "" self.hoffset = 0 self.keymap = Keymap() self.keymap.bind(['k', curses.KEY_UP, 16], self.cursor_move, (-1,)) self.keymap.bind(['j', curses.KEY_DOWN, 14], self.cursor_move, (1,)) self.keymap.bind(['K', curses.KEY_PPAGE], self.cursor_ppage, ()) self.keymap.bind(['J', curses.KEY_NPAGE], self.cursor_npage, ()) self.keymap.bind(['g', curses.KEY_HOME], self.cursor_home, ()) self.keymap.bind(['G', curses.KEY_END], self.cursor_end, ()) self.keymap.bind(['?', 18], self.start_search, (_("backward-isearch"), -1)) self.keymap.bind(['/', 19], self.start_search, (_("forward-isearch"), 1)) self.keymap.bind(['>'], self.hscroll, (8,)) self.keymap.bind(['<'], self.hscroll, (-8,)) def newwin(self): return curses.newwin(self.parent.rows-2, self.parent.cols, self.parent.ypos+2, self.parent.xpos) def update(self, force = 1): self.bufptr = max(0, min(self.bufptr, len(self.buffer) - 1)) first, last = self.scrptr, self.scrptr + self.rows - 1 if (self.bufptr < first): first = self.bufptr if (self.bufptr > last): first = self.bufptr - self.rows + 1 if force or self.scrptr != first: self.scrptr = first self.move(0, 0) self.clrtobot() i = 0 for entry in self.buffer[first:first+self.rows]: self.move(i, 0) i = i + 1 self.putstr(entry) if self.visible: self.refresh() self.parent.update_title() self.update_line(curses.A_REVERSE) def update_line(self, attr = None, refresh = 1): if not self.buffer: return ypos = self.bufptr - self.scrptr if attr: self.attron(attr) self.move(ypos, 0) self.hline(ord(' '), self.cols) self.putstr(self.current()) if attr: self.attroff(attr) if self.visible and refresh: self.refresh() def get_title(self, data=""): pos = "%s-%s/%s" % (self.scrptr+min(1, len(self.buffer)), min(self.scrptr+self.rows, len(self.buffer)), len(self.buffer)) width = self.cols-len(pos)-2 data = cut(data, width-len(self.name), 1) return "%-*s %s" % (width, cut(self.name+data, width), pos) def putstr(self, entry, *pos): s = str(entry) pos and self.move(*pos) if self.hoffset: s = "<%s" % s[self.hoffset+1:] self.insstr(cut(s, self.cols)) def current(self): if len(self.buffer) == 0: return None if self.bufptr >= len(self.buffer): self.bufptr = len(self.buffer) - 1 return self.buffer[self.bufptr] def cursor_move(self, ydiff): if app.input_mode: app.cancel_input() if not self.buffer: return self.update_line(refresh = 0) self.bufptr = (self.bufptr + ydiff) % len(self.buffer) self.update(force = 0) def cursor_ppage(self): self.bufptr = self.scrptr - 1 if self.bufptr < 0: self.bufptr = len(self.buffer) - 1 self.scrptr = max(0, self.bufptr - self.rows) self.update() def cursor_npage(self): self.bufptr = self.scrptr + self.rows if self.bufptr > len(self.buffer) - 1: self.bufptr = 0 self.scrptr = self.bufptr self.update() def cursor_home(self): self.cursor_move(-self.bufptr) def cursor_end(self): self.cursor_move(-self.bufptr - 1) def start_search(self, prompt_text, direction): self.search_direction = direction self.not_found = 0 if app.input_mode: app.input_prompt = "%s: " % prompt_text self.do_search(advance = direction) else: app.do_input_hook = self.do_search app.stop_input_hook = self.stop_search app.start_input(prompt_text) def stop_search(self): self.last_search = app.input_string app.status(_("ok"), 1) def do_search(self, ch = None, advance = 0): if ch in [8, 127]: app.input_string = app.input_string[:-1] elif ch: app.input_string = "%s%c" % (app.input_string, ch) else: app.input_string = app.input_string or self.last_search index = self.bufptr + advance while 1: if not 0 <= index < len(self.buffer): app.status(_("Not found: %s ") % app.input_string) self.not_found = 1 break line = string.lower(str(self.buffer[index])) if string.find(line, string.lower(app.input_string)) != -1: app.show_input() self.update_line(refresh = 0) self.bufptr = index self.update(force = 0) self.not_found = 0 break if self.not_found: app.status(_("Not found: %s ") % app.input_string) break index = index + self.search_direction def hscroll(self, value): self.hoffset = max(0, self.hoffset + value) self.update() # ------------------------------------------ class HelpWindow(ListWindow): def __init__(self, parent): ListWindow.__init__(self, parent) self.name = _("Help") self.keymap.bind('q', self.parent.help, ()) self.buffer = string.split(_("""\ Global t, T : tag current/regex ------ u, U : untag current/regex Up, Down, k, j, C-p, C-n, Sp, i : invert current/all PgUp, PgDn, K, J, !, , : shell, macro Home, End, g, G : movement Enter : chdir or play Filelist Tab : filelist/playlist -------- n, p : next/prev track a : add (tagged) to playlist z, x : toggle pause/stop s : recursive search BS, o : goto parent/specified dir Left, Right, m, ' : set/get bookmark C-f, C-b : seek forward/backward C-a, C-e : restart/end track Playlist C-s, C-r, / : isearch -------- C-g, Esc : cancel d, D : delete (tagged) tracks/playlist 1..9, +, - : volume control m, M : move tagged tracks after/before c, v : counter/volume mode r, R : toggle repeat/Random mode <, > : horizontal scrolling s, S : shuffle/Sort playlist C-l, l : refresh, list mode w, @ : write playlist, jump to active h, q, Q : help, quit?, Quit! X : stop playlist after each track """), "\n") # ------------------------------------------ class ListEntry: def __init__(self, pathname, dir=0): self.filename = os.path.basename(pathname) self.pathname = pathname self.slash = dir and "/" or "" self.tagged = 0 def set_tagged(self, value): self.tagged = value def is_tagged(self): return self.tagged == 1 def __str__(self): mark = self.is_tagged() and "#" or " " return "%s %s%s" % (mark, self.vp(), self.slash) def vp(self): return self.vps[0][1](self) def vp_filename(self): return self.filename or self.pathname def vp_pathname(self): return self.pathname vps = [[_("filename"), vp_filename], [_("pathname"), vp_pathname]] # ------------------------------------------ class PlaylistEntry(ListEntry): def __init__(self, pathname): ListEntry.__init__(self, pathname) self.metadata = None self.active = 0 def set_active(self, value): self.active = value def is_active(self): return self.active == 1 def vp_metadata(self): return self.metadata or self.read_metadata() def read_metadata(self): self.metadata = get_tag(self.pathname) logging.debug(self.metadata) return self.metadata vps = ListEntry.vps[:] + [[_("metadata"), vp_metadata]] # ------------------------------------------ class TagListWindow(ListWindow): def __init__(self, parent): ListWindow.__init__(self, parent) self.keymap.bind(' ', self.command_tag_untag, ()) self.keymap.bind('i', self.command_invert_tags, ()) self.keymap.bind('t', self.command_tag, (1,)) self.keymap.bind('u', self.command_tag, (0,)) self.keymap.bind('T', self.command_tag_regexp, (1,)) self.keymap.bind('U', self.command_tag_regexp, (0,)) self.keymap.bind('l', self.command_change_viewpoint, ()) self.keymap.bind('!', self.command_shell, ()) def command_shell(self): if app.restricted: return app.stop_input_hook = self.stop_shell app.complete_input_hook = self.complete_shell app.start_input(_("shell$ "), colon=0) def stop_shell(self): s = app.input_string curses.endwin() sys.stderr.write("\n") argv = map(lambda x: x.pathname, self.get_tagged()) argv or self.current() and argv.append(self.current().pathname) ret_value = call([s, '--'] + argv, shell=True) if ret_value != 0: sys.stderr.write("\nshell returned %s, press return!\n" % ret_value) sys.stdin.readline() app.win_root.update() app.restore_default_status() if ret_value == 0: app.status(_("Command succesfull"), 3) app.cursor(0) def complete_shell(self, line): return self.complete_generic(line, quote=1) def complete_generic(self, line, quote=0): import glob if quote: s = re.sub('.*[^\\\\][ \'"()\[\]{}$`]', '', line) s, part = re.sub('\\\\', '', s), line[:len(line)-len(s)] else: s, part = line, "" results = glob.glob(os.path.expanduser(s)+"*") if len(results) == 0: return line if len(results) == 1: lm = results[0] lm = lm + (os.path.isdir(lm) and "/" or "") else: lm = results[0] for result in results: for i in range(min(len(result), len(lm))): if result[i] != lm[i]: lm = lm[:i] break if quote: lm = re.sub('([ \'"()\[\]{}$`])', '\\\\\\1', lm) return part + lm def command_change_viewpoint(self, klass=ListEntry): klass.vps.append(klass.vps.pop(0)) app.status(_("Listing %s") % klass.vps[0][0], 1) app.player.update_status() self.update() def command_invert_tags(self): for i in self.buffer: i.set_tagged(not i.is_tagged()) self.update() def command_tag_untag(self): if not self.buffer: return tmp = self.buffer[self.bufptr] tmp.set_tagged(not tmp.is_tagged()) self.cursor_move(1) def command_tag(self, value): if not self.buffer: return self.buffer[self.bufptr].set_tagged(value) self.cursor_move(1) def command_tag_regexp(self, value): self.tag_value = value app.stop_input_hook = self.stop_tag_regexp app.start_input(value and _("Tag regexp") or _("Untag regexp")) def stop_tag_regexp(self): try: r = re.compile(app.input_string, re.I) for entry in self.buffer: if r.search(str(entry)): entry.set_tagged(self.tag_value) self.update() app.status(_("ok"), 1) except re.error, e: app.status(e, 2) def get_tagged(self): return filter(lambda x: x.is_tagged(), self.buffer) def not_tagged(self, l): return filter(lambda x: not x.is_tagged(), l) # ------------------------------------------ class FilelistWindow(TagListWindow): def __init__(self, parent): TagListWindow.__init__(self, parent) self.oldposition = {} try: self.chdir(os.getcwd()) except OSError: self.chdir(os.environ['HOME']) self.startdir = self.cwd self.mtime_when = 0 self.mtime = None self.keymap.bind(['\n', curses.KEY_ENTER], self.command_chdir_or_play, ()) self.keymap.bind(['.', 127, curses.KEY_BACKSPACE], self.command_chparentdir, ()) self.keymap.bind('a', self.command_add_recursively, ()) self.keymap.bind('o', self.command_goto, ()) self.keymap.bind('s', self.command_search_recursively, ()) self.keymap.bind('m', self.command_set_bookmark, ()) self.keymap.bind("'", self.command_get_bookmark, ()) self.bookmarks = { 39: [self.cwd, 0] } def command_get_bookmark(self): app.do_input_hook = self.do_get_bookmark app.start_input(_("bookmark")) def do_get_bookmark(self, ch): app.input_string = ch bookmark = self.bookmarks.get(ch) if bookmark: self.bookmarks[39] = [self.cwd, self.bufptr] dir, pos = bookmark self.chdir(dir) self.listdir() self.bufptr = pos self.update() app.status(_("ok"), 1) else: app.status(_("Not found!"), 1) app.stop_input() def command_set_bookmark(self): app.do_input_hook = self.do_set_bookmark app.start_input(_("set bookmark")) def do_set_bookmark(self, ch): app.input_string = ch self.bookmarks[ch] = [self.cwd, self.bufptr] ch and app.status(_("ok"), 1) or app.stop_input() def command_search_recursively(self): app.stop_input_hook = self.stop_search_recursively app.start_input(_("search")) def stop_search_recursively(self): try: re_tmp = re.compile(app.input_string, re.I) except re.error, e: app.status(e, 2) return app.status(_("Searching...")) results = [] for entry in self.buffer: if entry.filename == "..": continue if re_tmp.search(entry.filename): results.append(entry) elif os.path.isdir(entry.pathname): try: self.search_recursively(re_tmp, entry.pathname, results) except: pass if not self.search_mode: self.chdir(os.path.join(self.cwd,_("search results"))) self.search_mode = 1 self.buffer = results self.bufptr = 0 self.parent.update_title() self.update() app.restore_default_status() def search_recursively(self, re_tmp, dir, results): for filename in os.listdir(dir): pathname = os.path.join(dir, filename) if re_tmp.search(filename): if os.path.isdir(pathname): results.append(ListEntry(pathname, 1)) elif VALID_PLAYLIST(filename) or VALID_SONG(filename): results.append(ListEntry(pathname)) elif os.path.isdir(pathname): self.search_recursively(re_tmp, pathname, results) def get_title(self): self.name = _("Filelist: ") return ListWindow.get_title(self, re.sub("/?$", "/", self.cwd)) def listdir_maybe(self, now=0): if now < self.mtime_when+2: return self.mtime_when = now self.oldposition[self.cwd] = self.bufptr try: self.mtime == os.stat(self.cwd)[8] or self.listdir(quiet=1) except os.error: pass def listdir(self, quiet=0, prevdir=None): quiet or app.status(_("Reading directory...")) self.search_mode = 0 dirs = [] files = [] try: self.mtime = os.stat(self.cwd)[8] self.mtime_when = time.time() filenames = os.listdir(self.cwd) filenames.sort() for filename in filenames: if filename[0] == ".": continue pathname = os.path.join(self.cwd, filename) if os.path.isdir(pathname): dirs.append(pathname) elif VALID_SONG(filename): files.append(pathname) elif VALID_PLAYLIST(filename): files.append(pathname) except os.error: pass dots = ListEntry(os.path.join(self.cwd, ".."), 1) self.buffer = [[dots], []][self.cwd == "/"] for i in dirs: self.buffer.append(ListEntry(i, 1)) for i in files: self.buffer.append(ListEntry(i)) if prevdir: for self.bufptr in range(len(self.buffer)): if self.buffer[self.bufptr].filename == prevdir: break else: self.bufptr = 0 elif self.oldposition.has_key(self.cwd): self.bufptr = self.oldposition[self.cwd] else: self.bufptr = 0 self.parent.update_title() self.update() quiet or app.restore_default_status() def chdir(self, dir): if hasattr(self, "cwd"): self.oldposition[self.cwd] = self.bufptr self.cwd = os.path.normpath(dir) try: os.chdir(self.cwd) except: pass def command_chdir_or_play(self): if not self.buffer: return if self.current().filename == "..": self.command_chparentdir() elif os.path.isdir(self.current().pathname): self.chdir(self.current().pathname) self.listdir() elif VALID_SONG(self.current().filename): app.play(self.current()) def command_chparentdir(self): if app.restricted and self.cwd == self.startdir: return dir = os.path.basename(self.cwd) self.chdir(os.path.dirname(self.cwd)) self.listdir(prevdir=dir) def command_goto(self): if app.restricted: return app.stop_input_hook = self.stop_goto app.complete_input_hook = self.complete_generic app.start_input(_("goto")) def stop_goto(self): dir = os.path.expanduser(app.input_string) if dir[0] != '/': dir = os.path.join(self.cwd, dir) if not os.path.isdir(dir): app.status(_("Not a directory!"), 1) return self.chdir(dir) self.listdir() def command_add_recursively(self): l = self.get_tagged() if not l: app.win_playlist.add(self.current().pathname) self.cursor_move(1) return app.status(_("Adding tagged files"), 1) for entry in l: app.win_playlist.add(entry.pathname, quiet=1) entry.set_tagged(0) self.update() # ------------------------------------------ class PlaylistWindow(TagListWindow): def __init__(self, parent): TagListWindow.__init__(self, parent) self.pathname = None self.repeat = 0 self.random = 0 self.random_prev = [] self.random_next = [] self.random_left = [] self.stop = 0 self.keymap.bind(['\n', curses.KEY_ENTER], self.command_play, ()) self.keymap.bind('d', self.command_delete, ()) self.keymap.bind('D', self.command_delete_all, ()) self.keymap.bind('m', self.command_move, (1,)) self.keymap.bind('M', self.command_move, (0,)) self.keymap.bind('s', self.command_shuffle, ()) self.keymap.bind('S', self.command_sort, ()) self.keymap.bind('r', self.command_toggle_repeat, ()) self.keymap.bind('R', self.command_toggle_random, ()) self.keymap.bind('X', self.command_toggle_stop, ()) self.keymap.bind('w', self.command_save_playlist, ()) self.keymap.bind('@', self.command_jump_to_active, ()) def command_change_viewpoint(self, klass=PlaylistEntry): TagListWindow.command_change_viewpoint(self, klass) def get_title(self): space_out = lambda value, s: value and s or " "*len(s) self.name = _("Playlist %s %s %s") % ( space_out(self.repeat, _("[repeat]")), space_out(self.random, _("[random]")), space_out(self.stop, _("[stop]"))) return ListWindow.get_title(self) def append(self, item): self.buffer.append(item) if self.random: self.random_left.append(item) def add_dir(self, dir): try: filenames = os.listdir(dir) filenames.sort() subdirs = [] for filename in filenames: pathname = os.path.join(dir, filename) if VALID_SONG(filename): self.append(PlaylistEntry(pathname)) elif VALID_PLAYLIST(filename): self.add_playlist(pathname) if os.path.isdir(pathname): subdirs.append(pathname) map(self.add_dir, subdirs) except Exception, e: app.status(e, 2) def add_m3u(self, line): if re.match("^(#.*)?$", line): return if re.match("^(/|http://)", line): self.append(PlaylistEntry(self.fix_url(line))) else: dirname = os.path.dirname(self.pathname) self.append(PlaylistEntry(os.path.join(dirname, line))) def add_pls(self, line): # todo - support title & length m = re.match("File(\d+)=(.*)", line) if m: self.append(PlaylistEntry(self.fix_url(m.group(2)))) def add_playlist(self, pathname): self.pathname = pathname if re.search("\.m3u$", pathname, re.I): f = self.add_m3u if re.search("\.pls$", pathname, re.I): f = self.add_pls file = open(pathname) map(f, map(string.strip, file.readlines())) file.close() def add(self, pathname, quiet=0): try: if os.path.isdir(pathname): quiet or app.status(_("Working...")) self.add_dir(pathname) elif VALID_PLAYLIST(pathname): self.add_playlist(pathname) else: pathname = self.fix_url(pathname) self.append(PlaylistEntry(pathname)) # todo - refactor filename = os.path.basename(pathname) or pathname quiet or self.update() quiet or app.status(_("Added: %s") % filename, 1) except Exception, e: app.status(e, 2) def fix_url(self, url): return re.sub("(http://[^/]+)/?(.*)", "\\1/\\2", url) def putstr(self, entry, *pos): if entry.is_active(): self.attron(curses.A_BOLD) ListWindow.putstr(self, entry, *pos) if entry.is_active(): self.attroff(curses.A_BOLD) def change_active_entry(self, direction): if not self.buffer: return old = self.get_active_entry() new = None if self.random: if direction > 0: if self.random_next: new = self.random_next.pop() elif self.random_left: pass elif self.repeat: self.random_left = self.buffer[:] else: return if not new: import random new = random.choice(self.random_left) self.random_left.remove(new) try: self.random_prev.remove(new) except ValueError: pass self.random_prev.append(new) else: if len(self.random_prev) > 1: self.random_next.append(self.random_prev.pop()) new = self.random_prev[-1] else: return old and old.set_active(0) elif old: index = self.buffer.index(old)+direction if not (0 <= index < len(self.buffer) or self.repeat): return old.set_active(0) new = self.buffer[index % len(self.buffer)] else: new = self.buffer[0] new.set_active(1) self.update() return new def get_active_entry(self): for entry in self.buffer: if entry.is_active(): return entry def command_jump_to_active(self): entry = self.get_active_entry() if not entry: return self.bufptr = self.buffer.index(entry) self.update() def command_play(self): if not self.buffer: return entry = self.get_active_entry() entry and entry.set_active(0) entry = self.current() entry.set_active(1) self.update() app.play(entry) def command_delete(self): if not self.buffer: return current_entry, n = self.current(), len(self.buffer) self.buffer = self.not_tagged(self.buffer) if n > len(self.buffer): try: self.bufptr = self.buffer.index(current_entry) except ValueError: pass else: current_entry.set_tagged(1) del self.buffer[self.bufptr] if self.random: self.random_prev = self.not_tagged(self.random_prev) self.random_next = self.not_tagged(self.random_next) self.random_left = self.not_tagged(self.random_left) self.update() def command_delete_all(self): self.buffer = [] self.random_prev = [] self.random_next = [] self.random_left = [] app.status(_("Deleted playlist"), 1) self.update() def command_move(self, after): if not self.buffer: return current_entry, l = self.current(), self.get_tagged() if not l or current_entry.is_tagged(): return self.buffer = self.not_tagged(self.buffer) self.bufptr = self.buffer.index(current_entry)+after self.buffer[self.bufptr:self.bufptr] = l self.update() def command_shuffle(self): import random l = [] n = len(self.buffer) while n > 0: n = n-1 r = random.randint(0, n) l.append(self.buffer[r]) del self.buffer[r] self.buffer = l self.bufptr = 0 self.update() app.status(_("Shuffled playlist... Oops?"), 1) def command_sort(self): app.status(_("Working...")) self.buffer.sort(lambda x, y: x.vp() > y.vp() or -1) self.bufptr = 0 self.update() app.status(_("Sorted playlist"), 1) def command_toggle_repeat(self): self.toggle("repeat", _("Repeat: %s")) def command_toggle_random(self): self.toggle("random", _("Random: %s")) self.random_prev = [] self.random_next = [] self.random_left = self.buffer[:] def command_toggle_stop(self): self.toggle("stop", _("Stop playlist: %s")) def toggle(self, attr, format): setattr(self, attr, not getattr(self, attr)) app.status(format % (getattr(self, attr) and _("on") or _("off")), 1) self.parent.update_title() def command_save_playlist(self): if app.restricted: return default = self.pathname or "%s/" % app.win_filelist.cwd app.stop_input_hook = self.stop_save_playlist app.start_input(_("Save playlist"), default) def stop_save_playlist(self): pathname = app.input_string if pathname[0] != '/': pathname = os.path.join(app.win_filelist.cwd, pathname) if not re.search("\.m3u$", pathname, re.I): pathname = "%s%s" % (pathname, ".m3u") try: file = open(pathname, "w") for entry in self.buffer: file.write("%s\n" % entry.pathname) file.close() self.pathname = pathname app.status(_("ok"), 1) except IOError, e: app.status(e, 2) # ------------------------------------------ def get_type(pathname): if mg: mg_string = mg.file(pathname) logging.debug("Magic type:" + mg_string) if re.match("^Ogg data, Vorbis audio.*", mg_string): ftype = 'oggvorbis' elif re.match("^Ogg data, FLAC audio.*", mg_string): ftype = 'oggflac' elif re.match("FLAC audio bitstream.*", mg_string): ftype = 'flac' # For some reason not all ID3 tagged files return an ID3 identifier, # so we just need to look for mp3 files and hope they are also ID3d. elif re.match(".*MPEG ADTS, layer III.*", mg_string): ftype = 'id3' else: ftype = "unknown" logging.debug("Magic category: " + ftype) return ftype if re.match(".*\.ogg$", pathname, re.I): return 'oggvorbis' elif re.match(".*\.oga$", pathname, re.I): return 'oggflac' elif re.match(".*\.flac$", pathname, re.I): return 'flac' elif re.match(".*\.mp3$", pathname, re.I): return 'id3' return "unknown" # FIXME: Metadata gathering seems a bit slow now. Perhaps it could be done # in background so it wouldn't slow down responsiveness def get_tag(pathname): if re.compile("^http://").match(pathname) or not os.path.exists(pathname): return pathname try: import mutagen except ImportError: logging.debug("No mutagen available") app.status(_("Can't read metadata, module mutagen not available"), 2) return pathname ftype = get_type(pathname) try: if ftype == 'oggvorbis': import mutagen.oggvorbis metaopen = mutagen.oggvorbis.Open elif ftype == 'id3': import mutagen.easyid3 metaopen = mutagen.easyid3.Open elif ftype == 'flac': import mutagen.flac metaopen = mutagen.flac.Open elif ftype == 'oggflac': import mutagen.oggflac metaopen = mutagen.oggflac.Open else: app.status(_("Can't read metadata, I don't know this file"), 1) return os.path.basename(pathname) f = metaopen(pathname) except: logging.debug("Error reading metadata") logging.debug(traceback.format_exc()) app.status("Error reading metadata", 1) return os.path.basename(pathname) # FIXME: Allow user to configure metadata view try: return (" ".join(f.get('artist', ('?',))) + " - " + " ".join(f.get('album', ('?',))) + " - " + " ".join(f.get('tracknumber', ('?',))) + " " + " ".join(f.get('title', ('?',)))).encode(code, 'replace') except: logging.debug(traceback.format_exc()) return os.path.basename(pathname) # ------------------------------------------ class Player: stdin_r, stdin_w = os.pipe() stdout_r, stdout_w = os.pipe() stderr_r, stderr_w = os.pipe() def __init__(self, commandline, files, fps=1): self.commandline = commandline self.re_files = re.compile(files, re.I) self.fps = fps self.entry = None self.stopped = 0 # 1 only if stopped manually or playlist ran out self.paused = 0 self.time_setup = None self.buf = '' self.tid = None def setup(self, entry, offset): """Ready the player with given ListEntry and seek offset""" self.argv = string.split(self.commandline) self.argv[0] = which(self.argv[0]) for i in range(len(self.argv)): if self.argv[i] == "{file}": self.argv[i] = entry.pathname if self.argv[i] == "{offset}": self.argv[i] = str(offset*self.fps) self.entry = entry self.offset = offset if offset == 0: app.progress(0) self.offset = 0 self.length = 0 self.time_setup = time.time() return self.argv[0] def play(self): logging.debug(" ".join(["Executing"] + self.argv)) logging.debug("My offset is %d" % self.offset) # FIXME: Fork is complicated for no gain. subprocess.call # won't need which() either. self.pid = os.fork() if self.pid == 0: os.dup2(self.stdin_r, sys.stdin.fileno()) os.dup2(self.stdout_w, sys.stdout.fileno()) os.dup2(self.stderr_w, sys.stderr.fileno()) os.setpgrp() try: os.execv(self.argv[0], self.argv) except: os._exit(1) self.stopped = 0 self.paused = 0 self.step = 0 self.update_status() def stop(self, quiet=0): self.paused and self.toggle_pause(quiet) try: while 1: try: os.kill(-self.pid, signal.SIGINT) except os.error: pass os.waitpid(self.pid, os.WNOHANG) except Exception: pass self.stopped = 1 quiet or self.update_status() def toggle_pause(self, quiet=0): try: os.kill(-self.pid, [signal.SIGSTOP, signal.SIGCONT][self.paused]) except os.error: return self.paused = not self.paused quiet or self.update_status() def parse_progress(self): if self.stopped or self.step: self.tid = None else: self.parse_buf() self.tid = app.timeout.add(1.0, self.parse_progress) def read_fd(self, fd): self.buf = os.read(fd, 512) self.tid or self.parse_progress() def poll(self): try: # Returns (0, 0) when child still running os.waitpid(self.pid, os.WNOHANG) # return None except: # something broken? try again if self.time_setup and (time.time() - self.time_setup) < 2.0: self.play() return 0 app.set_default_status("") app.counter([0,0]) app.progress(0) return 1 def seek(self, offset, relative): if relative: d = offset * self.length * 0.002 self.step = self.step * (self.step * d > 0) + d self.offset = min(self.length, max(0, self.offset+self.step)) else: self.step = 1 self.offset = (offset < 0) and self.length+offset or offset self.show_position() def set_position(self, offset, length): """Update the visible playback position. offset is elapsed time, length the total length of track in seconds """ self.offset = offset self.length = length self.show_position() def show_position(self): app.counter((self.offset, self.length-self.offset)) app.progress(self.length and (float(self.offset) / self.length)) def update_status(self): if not self.entry: app.set_default_status("") elif self.stopped: app.set_default_status(_("Stopped: %s") % self.entry.vp()) elif self.paused: app.set_default_status(_("Paused: %s") % self.entry.vp()) else: logging.debug(self.entry.vp()) app.set_default_status(_("Playing: %s") % self.entry.vp()) # ------------------------------------------ class FrameOffsetPlayer(Player): re_progress = re.compile("Time.*\s(\d+):(\d+).*\[(\d+):(\d+)") def parse_buf(self): match = self.re_progress.search(self.buf) if match: m1, s1, m2, s2 = map(string.atoi, match.groups()) head, tail = m1*60+s1, m2*60+s2 self.set_position(head, head+tail) # ------------------------------------------ class FrameOffsetPlayerMpp(Player): re_progress = re.compile(".*\s(\d+):(\d+).*\s(\d+):(\d+)") def parse_buf(self): match = self.re_progress.search(self.buf) if match: m1, s1, m2, s2 = map(string.atoi, match.groups()) head = m1*60+s1 tail = (m2*60+s2) - head self.set_position(head, head+tail) # ------------------------------------------ class TimeOffsetPlayer(Player): re_progress = re.compile("(\d+):(\d+):(\d+)") def parse_buf(self): match = self.re_progress.search(self.buf) if match: h, m, s = map(string.atoi, match.groups()) tail = h*3600+m*60+s head = max(self.length, tail) - tail self.set_position(head, head+tail) # ------------------------------------------ class NoOffsetPlayer(Player): def parse_buf(self): head = self.offset+1 self.set_position(head, head*2) def seek(self, *dummy): return 1 # ------------------------------------------ class MPlayer(Player): re_progress = re.compile("^A:.*?(\d+)\.\d \([^)]+\) of (\d+)\.\d") speed = 1.0 eq_cur = 0 equalizer = EQUALIZERS[eq_cur][0] def play(self): Player.play(self) self.mplayer_send("speed_set %f" % self.speed) self.mplayer_send("af equalizer=" + self.equalizer) self.mplayer_send("seek %d\n" % self.offset) def parse_buf(self): match = self.re_progress.search(self.buf) if match: curS, totS = map(string.atoi, match.groups()) position, length = curS, totS self.set_position(position, length) else: logging.debug("Cannot parse mplayer output") def mplayer_send(self, arg): logging.debug("Sending command " + arg); try: os.write(self.stdin_w, arg + "\n") except IOError: logging.debug("Can't write to stdin_w.") app.status(_("ERROR: Cannot send commands to mplayer!"), 3) def speed_chg(self, set): self.speed = set self.mplayer_send("speed_set %f" % self.speed) app.status(_("Speed: %s%%") % (self.speed * 100), 1) def eq_chg(self, offset): if len(EQUALIZERS) == 0: app.status(_("No equalizers configured"), 2) return self.eq_cur = (self.eq_cur + offset) % (len(EQUALIZERS)) self.equalizer = EQUALIZERS[self.eq_cur][0] app.status(_("Equalizer: %s(%s)") % (EQUALIZERS[self.eq_cur][1], self.equalizer), 1) self.mplayer_send("af equalizer=" + self.equalizer); # ------------------------------------------ class Timeout: def __init__(self): self.next = 0 self.dict = {} def add(self, timeout, func, args=()): tid = self.next = self.next + 1 self.dict[tid] = (func, args, time.time() + timeout) return tid def remove(self, tid): del self.dict[tid] def check(self, now): for tid, (func, args, timeout) in self.dict.items(): if now >= timeout: self.remove(tid) func(*args) return len(self.dict) and 0.2 or None # ------------------------------------------ class FIFOControl: def __init__(self): self.commands = { "pause" : [app.toggle_pause, []], "next" : [app.next_song, []], "prev" : [app.prev_song, []], "forward" : [app.seek, [1, 1]], "backward" : [app.seek, [-1, 1]], "play" : [app.toggle_stop, []], "stop" : [app.toggle_stop, []], "volume" : [self.volume, None], "macro" : [app.run_macro, None], "add" : [app.win_playlist.add, None], "empty" : [app.win_playlist.command_delete_all, []], "quit" : [app.quit, []] } self.fd = None try: if os.path.exists(CONTROL_FIFO): os.unlink(CONTROL_FIFO) os.mkfifo(CONTROL_FIFO, 0600) self.fd = open(CONTROL_FIFO, "rb+", 0) except IOError: # warn that we're disabling the fifo because someone raced us? return def handle_command(self): argv = self.fd.readline().strip().split(" ", 1) if argv[0] in self.commands.keys(): f, a = self.commands[argv[0]] if a is None: a = argv[1:] f(*a) def volume(self, s): argv = s.split() app.mixer(argv[0], int(argv[1])) # ------------------------------------------ class Application: def __init__(self): self.keymapstack = KeymapStack() self.input_mode = 0 self.input_prompt = "" self.input_string = "" self.do_input_hook = None self.stop_input_hook = None self.complete_input_hook = None self.channels = [] self.restricted = 0 self.input_keymap = Keymap() self.input_keymap.bind(list(Window.chars), self.do_input) self.input_keymap.bind([127, curses.KEY_BACKSPACE], self.do_input, (8,)) self.input_keymap.bind([21, 23], self.do_input) self.input_keymap.bind(['\a', 27], self.cancel_input, ()) self.input_keymap.bind(['\n', curses.KEY_ENTER], self.stop_input, ()) def command_macro(self): app.do_input_hook = self.do_macro app.start_input(_("macro")) def do_macro(self, ch): app.stop_input() self.run_macro(chr(ch)) def run_macro(self, c): for i in MACRO.get(c, ""): self.keymapstack.process(ord(i)) def setup(self): if tty: self.tcattr = tty.tcgetattr(sys.stdin.fileno()) tcattr = tty.tcgetattr(sys.stdin.fileno()) tcattr[0] = tcattr[0] & ~(tty.IXON) tty.tcsetattr(sys.stdin.fileno(), tty.TCSANOW, tcattr) self.w = curses.initscr() curses.cbreak() curses.noecho() try: curses.meta(1) except: pass self.cursor(0) signal.signal(signal.SIGHUP, self.handler_quit) signal.signal(signal.SIGINT, self.handler_quit) signal.signal(signal.SIGTERM, self.handler_quit) signal.signal(signal.SIGWINCH, self.handler_resize) self.win_root = RootWindow(None) self.win_root.update() self.win_tab = self.win_root.win_tab self.win_filelist = self.win_root.win_tab.win_filelist self.win_playlist = self.win_root.win_tab.win_playlist self.win_status = self.win_root.win_status self.status = self.win_status.status self.set_default_status = self.win_status.set_default_status self.restore_default_status = self.win_status.restore_default_status self.counter = self.win_root.win_counter.counter self.progress = self.win_root.win_progress.progress self.player = PLAYERS[0] self.timeout = Timeout() self.play_tid = None self.win_filelist.listdir() self.control = FIFOControl() def cleanup(self): try: curses.endwin() except curses.error: return XTERM and sys.stderr.write("\033]0;%s\a" % "xterm") tty and tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN, self.tcattr) print # remove temporary files try: if os.path.exists(CONTROL_FIFO): os.unlink(CONTROL_FIFO) except IOError: pass def run(self): while 1: now = time.time() timeout = self.timeout.check(now) self.win_filelist.listdir_maybe(now) if not self.player.stopped: timeout = 0.5 if self.player.poll(): self.player.stopped = 1 # end of playlist hack if not self.win_playlist.stop: entry = self.win_playlist.change_active_entry(1) if not entry: self.player.stopped = 1 else: self.play(entry) R = [sys.stdin, self.player.stdout_r, self.player.stderr_r] self.control.fd and R.append(self.control.fd) try: r, w, e = select.select(R, [], [], timeout) except select.error: continue self.kludge = 1 # user if sys.stdin in r: c = self.win_root.getch() self.keymapstack.process(c) # player if self.player.stderr_r in r: self.player.read_fd(self.player.stderr_r) # player if self.player.stdout_r in r: self.player.read_fd(self.player.stdout_r) # remote if self.control.fd in r: self.control.handle_command() def play(self, entry, offset = 0): logging.debug("Starting to play " + str(entry)) self.play_tid = None if entry is None or offset is None: return self.player.stop(quiet=1) for self.player in PLAYERS: if self.player.re_files.search(entry.pathname): if self.player.setup(entry, offset): break else: # FIXME: Needs to report suitable players logging.debug("Player not found") app.status(_("Player not found!"), 1) self.player.stopped = 0 # keep going return self.player.play() def delayed_play(self, entry, offset): if self.play_tid: self.timeout.remove(self.play_tid) self.play_tid = self.timeout.add(0.5, self.play, (entry, offset)) def next_song(self): self.delayed_play(self.win_playlist.change_active_entry(1), 0) def prev_song(self): self.delayed_play(self.win_playlist.change_active_entry(-1), 0) def seek(self, offset, relative): if not self.player.entry: return self.player.seek(offset, relative) self.delayed_play(self.player.entry, self.player.offset) def toggle_pause(self): if not self.player.entry: return if not self.player.stopped: self.player.toggle_pause() def toggle_stop(self): if not self.player.entry: return if not self.player.stopped: self.player.stop() else: self.play(self.player.entry, self.player.offset) def key_volume(self, ch): self.mixer("set", (ch & 0x0f)*10) def mixer(self, cmd=None, arg=None): try: self._mixer(cmd, arg) except Exception, e: app.status(e, 2) def _mixer(self, cmd, arg): """Give a command to the audio mixer. cmd -- 'toggle' to change mixed channel to next, 'set' to set the volume to arg, or 'cue' to increase the volume by arg. """ try: import ossaudiodev mixer = ossaudiodev.openmixer() get, set = mixer.get, mixer.set self.channels = self.channels or \ [['MASTER', ossaudiodev.SOUND_MIXER_VOLUME], ['PCM', ossaudiodev.SOUND_MIXER_PCM]] if cmd == "toggle": self.channels.insert(0, self.channels.pop()) name, channel = self.channels[0] if cmd == "cue": arg = min(100, max(0, get(channel)[0] + arg)) if cmd in ["set", "cue"]: set(channel, (arg, arg)) app.status(_("%s volume %s%%") % (name, get(channel)[0]), 1) mixer.close() return except IOError: # If /dev/mixer is not available, opening the mixer fails. # Thus, we aren't using OSS. pass # FIXME: ALSA is probably the common case, so it should come first # but pyalsaaudio docs don't say what error is thrown if it's used # on a system with no alsa... try: # ALSA import alsaaudio mixer = alsaaudio.Mixer() get, set = mixer.getvolume, mixer.setvolume name = 'MASTER' # FIXME: No 'toggle' support if cmd is "set": set(arg) if cmd is "cue" and arg!=0: # ALSA doesn't do integer increments oldvolume = get()[0] newvol = get()[0] while (get()[0] is oldvolume): newvol = min(100, max(0, newvol + arg)) set(newvol) if ((oldvolume==0 and arg<0) or (oldvolume==100 and arg>0)): break app.status(_("%s volume %s%%") % (name, get()[0]), 1) return except ImportError: app.status(_("Not using OSS and no alsa support available"), 2) def speed_incr(self): if(isinstance(self.player, MPlayer)): self.player.speed_chg(self.player.speed + SPEED_OFFSET) else: app.status(_("Speed control requires MPlayer"), 1) def speed_decr(self): if(isinstance(self.player, MPlayer)): self.player.speed_chg(self.player.speed - SPEED_OFFSET) else: app.status(_("Speed control requires MPlayer"), 1) def speed_reset(self): if(isinstance(self.player, MPlayer)): self.player.speed_chg(1.0) else: app.status(_("Speed control requires MPlayer"), 1) def eq_next(self): if(isinstance(self.player, MPlayer)): self.player.eq_chg(1) else: app.status(_("Equalizer support requires MPlayer"), 1) def eq_prev(self): if(isinstance(self.player, MPlayer)): self.player.eq_chg(-1) else: app.status(_("Equalizer support requires MPlayer"), 1) def show_input(self): n = len(self.input_prompt)+1 s = cut(self.input_string, self.win_status.cols-n, left=1) app.status("%s%s " % (self.input_prompt, s)) def start_input(self, prompt="", data="", colon=1): self.input_mode = 1 self.cursor(1) app.keymapstack.push(self.input_keymap) self.input_prompt = prompt + (colon and ": " or "") self.input_string = data self.show_input() def do_input(self, *args): if self.do_input_hook: return self.do_input_hook(*args) ch = args and args[0] or None if ch in [8, 127]: # backspace self.input_string = self.input_string[:-1] elif ch == 9 and self.complete_input_hook: self.input_string = self.complete_input_hook(self.input_string) elif ch == 21: # C-u self.input_string = "" elif ch == 23: # C-w self.input_string = re.sub("((.* )?)\w.*", "\\1", self.input_string) elif ch: self.input_string = "%s%c" % (self.input_string, ch) self.show_input() def stop_input(self, *args): self.input_mode = 0 self.cursor(0) app.keymapstack.pop() if not self.input_string: app.status(_("cancel"), 1) elif self.stop_input_hook: self.stop_input_hook(*args) self.do_input_hook = None self.stop_input_hook = None self.complete_input_hook = None def cancel_input(self): self.input_string = "" self.stop_input() def cursor(self, visibility): try: curses.curs_set(visibility) except: pass def quit(self, status=0): self.player.stop(quiet=1) sys.exit(status) def handler_resize(self, sig, frame): # curses trickery while 1: try: curses.endwin(); break except: time.sleep(1) self.w.refresh() self.win_root.resize() self.win_root.update() def handler_quit(self, sig, frame): self.quit(1) # ------------------------------------------ def main(): try: opts, args = getopt.getopt(sys.argv[1:], "nrRd:") except: usage = _("Usage: %s [-d ] [-nrR]" "[ file | dir | playlist ] ...\n") sys.stderr.write(usage % sys.argv[0]) sys.exit(1) for opt, optarg in opts: # FIXME option checking in two places if opt == "-d": logging.basicConfig(filename=optarg, level=logging.DEBUG) global app app = Application() playlist = [] if not sys.stdin.isatty(): playlist = map(string.strip, sys.stdin.readlines()) os.close(0) os.open("/dev/tty", 0) try: app.setup() for opt, optarg in opts: if opt == "-n": app.restricted = 1 if opt == "-r": app.win_playlist.command_toggle_repeat() if opt == "-R": app.win_playlist.command_toggle_random() logging.debug("Preferred locale is " + str(code)) if args or playlist: for i in args or playlist: i = os.path.exists(i) and os.path.abspath(i) or i app.win_playlist.add(i) app.win_tab.change_window() app.run() except SystemExit: app.cleanup() except Exception: app.cleanup() traceback.print_exc() # ------------------------------------------ PLAYERS = [ MPlayer("mplayer -slave -vc null -vo null {file}", "^http://|\.(mp[123]|ogg|oga|flac|spx|mp[cp+]|mod|xm|fm|s3m|" + "med|col|669|it|mtm|stm|aiff|au|cdr|wav|wma|m4a|m4b)$"), FrameOffsetPlayer("ogg123 -q -v -k {offset} {file}", "\.(ogg|flac|spx)$"), FrameOffsetPlayer("splay -f -k {offset} {file}", "(^http://|\.mp[123]$)", 38.28), FrameOffsetPlayer("mpg123 -q -v -k {offset} {file}", "(^http://|\.mp[123]$)", 38.28), FrameOffsetPlayer("mpg321 -q -v -k {offset} {file}", "(^http://|\.mp[123]$)", 38.28), FrameOffsetPlayerMpp("mppdec --gain 2 --start {offset} {file}", "\.mp[cp+]$"), TimeOffsetPlayer("madplay -v --display-time=remaining -s {offset} {file}", "\.mp[123]$"), NoOffsetPlayer("mikmod -q -p0 {file}", "\.(mod|xm|fm|s3m|med|col|669|it|mtm)$"), NoOffsetPlayer("xmp -q {file}", "\.(mod|xm|fm|s3m|med|col|669|it|mtm|stm)$"), NoOffsetPlayer("play {file}", "\.(aiff|au|cdr|mp3|ogg|wav)$"), NoOffsetPlayer("speexdec {file}", "\.spx$"), ] MACRO = {} def VALID_SONG(name): for player in PLAYERS: if player.re_files.search(name): return 1 def VALID_PLAYLIST(name): if re.search("\.(m3u|pls)$", name, re.I): return 1 for rc in [os.path.expanduser("~/.cplayrc"), "/etc/cplayrc"]: try: execfile(rc); break except IOError: pass # ------------------------------------------ if __name__ == "__main__": main() cplay-1.50/cplay.1000066400000000000000000000035171155604254400137550ustar00rootroot00000000000000.\" Copyright (C) 2000, 2002 Martin Michlmayr .\" This manual is freely distributable under the terms of the GPL. .\" It was originally written for Debian GNU/Linux (but may be used .\" by others). .\" .TH CPLAY 1 "November 2002" .SH NAME .PP cplay \- a front-end for various audio players .SH SYNOPSIS .PP \fBcplay\fR [\-options] [ \fIfile\fP | \fIdir\fP | \fIplaylist\fP ] ... .SH DESCRIPTION .PP .B cplay is a front-end for various audio players. It aims to provide a user-friendly interface with simple filelist and playlist control. Invoking .B cplay without any options puts you in the filelist in which you can navigate around looking for audio files. When you specify an audio file, .B cplay automatically adds it to the playlist which can be accessed by pressing the tabulator key. .PP Use 'h' to display the help window. .PP Shell command-lines are executed with tagged or current entries as positional parameters, which means that "$@" might be useful. .PP Currently, the following audio formats are supported: MP3 (through mpg321, splay, mpg123 or madplay), Ogg Vorbis (through ogg123), and various module-formats (through mikmod and xmp). .SH OPTIONS .IP \fB\-n Enable \fIrestricted\fI mode .IP \fB\-r Toggles playlist \fIrepeat\fP mode .IP \fB\-R Toggles playlist \fIrandom\fP mode .IP \fB\-v Toggles PCM and MASTER (default) volume control .SH SEE ALSO .PP .BR ogg123 (1), .BR mpg123 (1), .BR mpg321 (1), .BR splay (1), .BR madplay (1), .BR mikmod (1), .BR xmp (1), .BR play (1), .BR speexdec (1) .SH FILES .PP .I /var/tmp/cplay_control - Optional remote control fifo. .I /etc/cplayrc - Optional configuration file. .I ~/.cplayrc - Optional configuration file. .SH AUTHOR .PP Ulf Betlehem .SH BUGS .PP In order for either mp3info (ID3) or ogginfo to work, both corresponding python modules have to be installed. cplay-1.50/cplay.list000066400000000000000000000013521155604254400145630ustar00rootroot00000000000000# cplay list file # tested with epm 2.5 and cplay 1.48 # Manpage extensions... $MAN1EXT=1 # Directories... $prefix=/usr/local $bindir=${prefix}/bin $confdir=/etc $docdir=${prefix}/doc/cplay $mandir=${prefix}/man/man1 # Product information %product cplay %copyright GPL %vendor Ulf Betlehem %license COPYING %readme README %description cplay, a curses front-end for various audio players. %version 1.48 %packager Giuseppe "Cowo" Corbelli # Executables %system all f 0555 root sys ${bindir}/cplay cplay # Doc f 0444 root sys ${docdir}/README README f 0444 root sys ${docdir}/TODO TODO # Man pages f 0444 root sys ${mandir}/cplay.${MAN1EXT} cplay.1 #Configuration f 0644 root sys ${confdir}/cplayrc cplayrc cplay-1.50/lircrc000066400000000000000000000026111155604254400137560ustar00rootroot00000000000000begin remote = ANIMAX button = SKIP_FORWARD_DOWN prog = irexec repeat = 0 config = echo "next" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = SKIP_BACKWARD_DOWN prog = irexec repeat = 0 config = echo "prev" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = REWIND_DOWN prog = irexec repeat = 1 config = echo "backward" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = FORWARD_DOWN prog = irexec repeat = 1 config = echo "forward" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = PLAY_DOWN prog = irexec repeat = 0 config = echo "play" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = STOP_DOWN prog = irexec repeat = 0 config = echo "stop" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = VOLUME_UP_DOWN prog = irexec repeat = 1 config = echo "volume cue 1" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = VOLUME_DOWN_DOWN prog = irexec repeat = 1 config = echo "volume cue -1" > ${TMPDIR-/tmp}/cplay-control-$USER end begin remote = ANIMAX button = POWER_DOWN prog = irexec repeat = 0 config = echo "quit" > ${TMPDIR-/tmp}/cplay-control-$USER end cplay-1.50/po/000077500000000000000000000000001155604254400131735ustar00rootroot00000000000000cplay-1.50/po/Makefile000066400000000000000000000005631155604254400146370ustar00rootroot00000000000000POFILES = $(wildcard *.po) MOFILES = $(POFILES:.po=.mo) $(MOFILES): $(POFILES) for i in $(POFILES); do msgfmt $$i -o $${i%.po}.mo; done all: $(MOFILES) install: all for i in $(MOFILES); do \ mkdir -p $(PREFIX)/share/locale/$${i%.mo}/LC_MESSAGES; \ install -c -m 644 $$i $(PREFIX)/share/locale/$${i%.mo}/LC_MESSAGES/cplay.mo; \ done clean: rm -f $(MOFILES) *~ cplay-1.50/po/da.po000066400000000000000000000145361155604254400141300ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR ORGANIZATION # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: Tue Jul 29 17:01:48 2003\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.4\n" #: cplay:287 msgid "elapsed" msgstr "spillet" #: cplay:287 msgid "remaining" msgstr "tilbage" #: cplay:288 msgid "Counting %s time" msgstr "Tæller %s gange" #: cplay:320 msgid "Quit? (y/N)" msgstr "Afslut? (y/N)" #: cplay:405 msgid "backward-isearch" msgstr "baglæns-isøgning" #: cplay:407 msgid "forward-isearch" msgstr "forlæns-isøgning" #: cplay:496 cplay:657 cplay:748 cplay:760 cplay:1148 msgid "ok" msgstr "ok" #: cplay:505 cplay:517 msgid "Not found: %s " msgstr "%s ikke fundet " #: cplay:525 msgid "Help" msgstr "Hjælp" #: cplay:527 msgid "" "\n" " Global Space : tag/untag current\n" " ------ t, T : tag current/regex\n" " Up, Down, k, j, C-p, C-n, u, U : untag current/regex\n" " PgUp, PgDn, K, J, i : invert tags\n" " Home, End, g, G : movement\n" " Enter : chdir or play Filelist\n" " Tab : filelist/playlist --------\n" " n, p : next/prev track BkSpc : parent dir\n" " z, x : toggle pause/stop o, s : goto, search recursively\n" " Left, Right, a : add (tagged) to playlist\n" " C-f, C-b : seek forward/backward\n" " c : counter mode Playlist\n" " C-s, C-r, / : isearch --------\n" " C-g, Esc : cancel d, D : delete (tagged) tracks/playlist\n" " 1..9, +, - : volume control m, M : move tagged tracks after/before\n" " v : PCM or MASTER volume r, R : toggle repeat/Random mode\n" " C-l, l : refresh, list mode s, S : shuffle/Sort playlist\n" " h, q, Q : help, quit?, Quit! w, @ : write playlist, jump to current\n" "\n" "\n" "\n" " Goodies\n" " -------\n" " b, ' : set/get filelist bookmark\n" " X : stop playlist after each track\n" " C-a, ^ : seek to beginning of current track (restart)\n" " C-e, $ : seek to end of current track (useless?)\n" " ! : shell command ($@ = tagged or current)\n" " " msgstr "" "\n" " Globalt Space : vælg/fravælg nuværende\n" " ------ t, T : vælg nuværende/regex\n" " Up, Ned, k, j, C-p, C-n, u, U : fravælg nuværede/regex\n" " PgUp, PgDn, K, J, i : vend vælg om\n" " Home, End, g, G : bevægelse\n" " Enter : chdir eller afspil Filliste\n" " Tab : filliste/spilleliste --------\n" " n, p : næste/forrige nummer BkSpc : et filkatalog op\n" " z, x : pause/stop fra og til o, s : gå til, søg gennemgående\n" " Venstre, Højre, a : tilføj (valgte) til spilleliste\n" " C-f, C-b : søg forlæns/baglæns\n" " c : tæller-type Spilleliste\n" " C-s, C-r, / : isøgning --------\n" " C-g, Esc : afbryd d, D : fjern (valgte) numre/spillelist\n" " 1..9, +, - : lydstyrke m, M : flyt valgte numre efter/før\n" " v : PCM eller MASTER volume r, R : repeat/Random fra og til\n" " C-l, l : opfrisk, vis liste s, S : bland/Sortér spillelist\n" " h, q, Q : hjælp, afslut?, Afslut! w, @ : gem spillelist, gå til nuværende\n" "\n" "\n" "\n" " Godbider\n" " -------\n" " b, ' : sæt/hent filliste-bogmærke\n" " X : stop spilleiste efter hvert nummer\n" " C-a, ^ : gå til begyndelsen af det nyværende nummer (start om)\n" " C-e, $ : gå til slutningen af det nuværende nummer (ubrugelig?)\n" " ! : skal-kommando ($@ = valgte eller nuværende)\n" " " #: cplay:593 msgid "filename" msgstr "filnavn" #: cplay:594 msgid "pathname" msgstr "stinavn" #: cplay:625 msgid "Listing %s" msgstr "Sææter %s på liste" #: cplay:648 msgid "Tag regexp" msgstr "Vælg regexp" #: cplay:648 msgid "Untag regexp" msgstr "Fravælg regexp" #: cplay:687 msgid "shell$ " msgstr "skal$ " #: cplay:734 msgid "bookmark" msgstr "bogmærke" #: cplay:750 msgid "Not found!" msgstr "Ikke fundet!" #: cplay:755 msgid "set bookmark" msgstr "sæt bogmærke" #: cplay:764 msgid "search" msgstr "søg" #: cplay:771 msgid "Searching..." msgstr "Søger..." #: cplay:782 msgid "search results" msgstr "søgnings-resultater" #: cplay:802 msgid "Filelist: " msgstr "Filliste: " #: cplay:813 msgid "Reading directory..." msgstr "Læser filkatalog..." #: cplay:868 msgid "goto" msgstr "gå til" #: cplay:874 msgid "Not a directory!" msgstr "Ikke et filkatalog" #: cplay:919 msgid "metadata" msgstr "metadata" #: cplay:925 msgid "Playlist %s %s %s" msgstr "Spilleliste %s %s %s" #: cplay:926 msgid "[repeat]" msgstr "[gentag]" #: cplay:927 msgid "[random]" msgstr "[tilfældig]" #: cplay:928 msgid "[stop]" msgstr "[stop]" #: cplay:981 cplay:1108 msgid "Working..." msgstr "Arbejder..." #: cplay:990 msgid "Added: %s" msgstr "Tilføjede: %s" #: cplay:1079 msgid "Deleted playlist" msgstr "Fjernede spilleliste" #: cplay:1105 msgid "Shuffled playlist... Oops?" msgstr "Blandede spilleliste... Hovsa?" #: cplay:1112 msgid "Sorted playlist" msgstr "Sortérede spilleliste" #: cplay:1115 msgid "Repeat: %s" msgstr "Gentag: %s" #: cplay:1118 msgid "Random: %s" msgstr "Tilfældig: %s" #: cplay:1124 msgid "Stop playlist: %s" msgstr "Stop spilleliste" #: cplay:1128 msgid "off" msgstr "fra" #: cplay:1128 msgid "on" msgstr "til" #: cplay:1134 msgid "Save playlist" msgstr "Gem spilleliste" #: cplay:1310 msgid "Stopped: %s" msgstr "Stoppet: %s" #: cplay:1312 msgid "Paused: %s" msgstr "Sat på pause: %s" #: cplay:1314 msgid "Playing: %s" msgstr "Spiller: %s" #: cplay:1491 msgid "Player not found!" msgstr "Afspiller ikke fundet!" #: cplay:1548 msgid "Volume %s%%" msgstr "Lydstyrke %s%" #: cplay:1556 msgid "%s volume %s%%" msgstr "%s lydstyrke %s%" #: cplay:1587 msgid "cancel" msgstr "afbryd" #: cplay:1623 msgid "" "Usage: %s [-rRv] [ file | dir | playlist ] ...\n" msgstr "" "Brug: %s [-rRv] [ fil | filkatalog | spilleliste ] ...\n" cplay-1.50/po/de.po000066400000000000000000000114431155604254400141260ustar00rootroot00000000000000# Copyright (C) 2000 Martin Michlmayr # msgid "" msgstr "" "Project-Id-Version: 1.0\n" "PO-Revision-Date: Sat Jul 22 00:21:05 2000\n" "Last-Translator: Martin Michlmayr \n" "Language-Team: Martin Michlmayr \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: cplay:828 msgid "Almost there..." msgstr "Fast fertig..." #: cplay:834 msgid "Cleared all marks..." msgstr "Lösche alle Markierungen..." #: cplay:746 msgid "IOError" msgstr "I/O-Fehler" #: cplay:882 cplay:888 msgid "off" msgstr "aus" #: cplay:918 msgid "Cannot write playlist!" msgstr "Kann Playliste nicht schreiben!" #: cplay:412 msgid "forward-isearch" msgstr "Vorwärts-isuche" #: cplay:539 msgid "Not found: %s" msgstr "Nicht gefunden: %s" #: cplay:727 msgid "Playlist %s %s" msgstr "Playliste %s %s" #: cplay:411 msgid "backward-isearch" msgstr "Rückwärts-isuche" #: cplay:878 msgid "Sorted playlist..." msgstr "Sortiere Playliste..." #: cplay:205 msgid "Help" msgstr "Hilfe" #: cplay:419 cplay:916 msgid "ok" msgstr "ok" #: cplay:958 msgid "Paused: %s" msgstr "Pause: %s" #: cplay:882 msgid "Repeat %s" msgstr "Wiederholung %s" #: cplay:882 cplay:888 msgid "on" msgstr "ein" #: cplay:742 cplay:749 msgid "Added: %s" msgstr "Hinzugefügt: %s" #: cplay:728 cplay:729 msgid "[random]" msgstr "[zufällig]" #: cplay:872 msgid "Shuffled playlist... Oops?" msgstr "Durchwühle Playliste... Oops?" #: cplay:418 cplay:639 cplay:904 msgid "cancel" msgstr "Abbruch" #: cplay:463 msgid "probably not ok" msgstr "wahrscheinlich nicht ok" #: cplay:575 msgid "Reading directory..." msgstr "Lese Verzeichnis..." #: cplay:1162 msgid "Player not found!" msgstr "Player nicht gefunden!" #: cplay:611 msgid "Filelist: " msgstr "Dateiliste: " #: cplay:1240 msgid "Usage: %s [ filename | playlist.m3u ] ...\n" msgstr "Verwendung: %s [ datei | playliste.m3u ] ...\n" #: cplay:1217 msgid "Volume %d%%" msgstr "Lautstärke %d%%" #: cplay:941 cplay:964 msgid "Playing: %s" msgstr "Spiele: %s" #: cplay:181 msgid "" "\n" " Global Filelist\n" " ------ --------\n" " Up, C-p, k, Space : add to playlist\n" " Down, C-n, j, a : add recursively\n" " PgUp, PgDown, g : goto\n" " Home, End : movement Enter : chdir or play\n" " Tab : filelist/playlist Backspace : parent dir\n" " n,p : next/prev track \n" " z,x : toggle pause/stop Playlist\n" " Left, Right, --------\n" " C-b, C-f : seek Enter : play track\n" " C-s : forward-isearch Space : mark\n" " C-r : backward-isearch a,c : mark/clear all\n" " C-g, Esc : cancel m : move marked tracks\n" " 1..9, +- : volume d : delete marked tracks\n" " C-l : refresh screen r, R : toggle repeat/Random mode\n" " h : help s, S : shuffle/Sort playlist\n" " q : quit o : save playlist (to .m3u file)\n" msgstr "" "\n" " Global Dateiliste\n" " ------ ----------\n" " Up, C-p, k, Space : Zu Playliste hinzufügen\n" " Down, C-n, j, a : Füge rekursiv hinzu\n" " PgUp, PgDown, g : Gehzu\n" " Home, End : Bewegung Enter : Wechsle Verzeichnis oder " "spiele\n" " Tab : Dateiliste/Spielliste Backspace : Übergeordnetes Verzeichnis\n" " n,p : nächster/vorheriger Track\n" " z,x : schalte Pause/Stop Playliste\n" " Left, Right, ---------\n" " C-b, C-f : Suche Enter : Spiele Track\n" " C-s : Vorwärts-isuche Space : markiere\n" " C-r : Rückwärts-isuche a,c : markiere/lösche alle\n" " C-g, Esc : Abbruch m : verschiebe markierte Tracks\n" " 1..9, +- : Lautstärke d : lösche markierte Tracks\n" " C-l : stelle Bildschirm her r, R : schalte widerhole/zufällig " "Modus\n" " h : Hilfe s, S : durchwühle/ordne Playliste\n" " q : Ende o : speichere Playliste (als .m3u " "Datei)\n" #: cplay:727 cplay:728 msgid "[repeat]" msgstr "[wiederhole]" #: cplay:888 msgid "Random %s" msgstr "Zufall %s" #: cplay:894 msgid "Save playlist" msgstr "Speichere Playliste" #: cplay:629 msgid "goto" msgstr "Gehzu" #: cplay:975 msgid "Stopped: %s" msgstr "Gestoppt: %s" #: cplay:1209 cplay:1219 msgid "Cannot open mixer device %s" msgstr "Kann Mixer-Device %s nicht öffnen." #: cplay:710 msgid "Playlist" msgstr "Playliste" #: cplay:644 msgid "Not a directory!" msgstr "Kein Verzeichnis!" cplay-1.50/po/fr.po000066400000000000000000000217331155604254400141500ustar00rootroot00000000000000# French translation for cplay # Copyright (C) 2004 Yoann Aubineau # This file is distributed under the same license as the cplay package. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: cplay 1.49\n" "Report-Msgid-Bugs-To: Yoann Aubineau \n" "POT-Creation-Date: 2004-07-03 16:04+0100\n" "PO-Revision-Date: 2004-07-03 16:04+0100\n" "Last-Translator: Yoann Aubineau \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: cplay:273 msgid "elapsed" msgstr "écoulé" #: cplay:273 msgid "remaining" msgstr "restant" #: cplay:274 #, python-format msgid "Counting %s time" msgstr "Mesure du temps %s" #: cplay:306 msgid "Quit? (y/N)" msgstr "Quitter ? (y/N)" #: cplay:392 msgid "backward-isearch" msgstr "Recherche en arrière " #: cplay:394 msgid "forward-isearch" msgstr "Recherche en avant " #: cplay:486 cplay:642 cplay:737 cplay:749 cplay:1127 msgid "ok" msgstr "ok" #: cplay:495 cplay:507 #, python-format msgid "Not found: %s " msgstr "Non trouvé : %s" #: cplay:519 msgid "Help" msgstr "Aide" #: cplay:521 msgid "" " Global t, T : tag current/regex\n" " ------ u, U : untag current/regex\n" " Up, Down, k, j, C-p, C-n, Sp, i : invert current/all\n" " PgUp, PgDn, K, J, ! : shell ($@ = tagged or current)\n" " Home, End, g, G : movement\n" " Enter : chdir or play Filelist\n" " Tab : filelist/playlist --------\n" " n, p : next/prev track a : add (tagged) to playlist\n" " z, x : toggle pause/stop s : recursive search\n" " BS, o : goto parent/specified dir\n" " Left, Right, m, ' : set/get bookmark\n" " C-f, C-b : seek forward/backward \n" " C-a, C-e : restart/end track Playlist\n" " C-s, C-r, / : isearch --------\n" " C-g, Esc : cancel d, D : delete (tagged) tracks/playlist\n" " 1..9, +, - : volume control m, M : move tagged tracks after/before\n" " c, v : counter/volume mode r, R : toggle repeat/Random mode\n" " <, > : horizontal scrolling s, S : shuffle/Sort playlist\n" " C-l, l : refresh, list mode w, @ : write playlist, jump to active\n" " h, q, Q : help, quit?, Quit! X : stop playlist after each track\n" msgstr "" " Navigation au sein de l'application\n" " ------------------------------------\n" "\n" " Tabulation : basculer entre la liste des fichiers et celle de lecture\n" " h : afficher/masquer l'aide\n" " q : quitter cplay\n" " Q : quitter cplay sans demande de confirmation\n" "\n" " Ctrl-l : rafraichir l'affichage courant\n" " Ctrl-g, Echap : annuler l'action en cours (rechercher par exemple)\n" " ! : lancer une commande ($@ représente la sélection ou le fichier courant\n" "\n" "\n" " Navigation dans les listes\n" " --------------------------\n" "\n" " FlècheHaut, Ctrl-n, k : déplacer le curseur d'une ligne vers le haut\n" " FlècheBas, Ctrl-p, j : déplacer le curseur d'une ligne vers le bas\n" " PagePrécédente, K : déplacer le curseur d'une page vers le haut\n" " PageSuivante, J : déplacer le curseur d'une page vers le bas\n" " Début, g : déplacer le curseur en début de liste\n" " Fin, G : déplacer le curseur en fin de liste\n" " < : défilement de la liste vers la gauche\n" " > : défilement de la liste vers la droite\n" "\n" "\n" " Sélection\n" " ---------\n" "\n" " t : sélectionner la ligne courante\n" " u : désélectionner la ligne courante\n" "\n" " T : séléctionner plusieurs lignes à l'aide d'une expression rationnelle\n" " U : désélectioner plusieurs lignes à l'aide d'une expression rationnelle\n" "\n" " espace : inverser la sélection pour la ligne courante\n" " i : inverser la sélection pour la liste entière\n" "\n" "\n" " Utilisation de la liste des fichiers\n" " ------------------------------------\n" "\n" " Entrée : lister le contenu d'un répertoire\n" " backspace : remonter au réperoire parent\n" " o : aller directement à un répertoire spécifique\n" " s : effectuer une recherche récursive dans les répertoires\n" "\n" " m : définir un marque-page pour le répertoire courant\n" " ' : atteindre un marque-page\n" "\n" " l : baculer entre l'affiche des noms des fichiers ou de leur chemin complet\n" "\n" "\n" " Utilisation de la liste de lecture\n" " ----------------------------------\n" "\n" " a : ajouter un morceau, une liste de lecture, un répertoire ou une sélection\n" " d : supprimer la piste courante\n" " D : vider la liste de lecture\n" "\n" " s : mélanger la liste liste lecture\n" " S : trier la liste de lecture par ordre alphabétique\n" " m : déplacer les pistes sélectionnées avant la piste courante\n" " M : déplacer les pistes sélectionnées après la piste courante\n" "\n" " @ : placer le curseur sur la piste en cours de lecture\n" " l : baculer entre l'affiche des noms des fichiers ou de leur chemin complet\n" " W : enregistrer la liste de lecture\n" "\n" "\n" " Contrôle de la lecture\n" " ----------------------\n" "\n" " Entrée : lire un fichier ou une piste\n" " n : piste suivante\n" " p : piste précédente\n" " z : pause (appuyer de nouveau pour relancer la lecture)\n" " x : arrêt (appuyer de nouveau pour reprendre la lecture)\n" "\n" " FlècheGauche, Ctrl-b : reculer la lecture d'un pas\n" " FlècheDroite, Ctrl-f : avancer la lecture d'un pas\n" " Ctrl-a, ^ : reculer la lecture jusqu'au début du morceau\n" " Ctrl-e, $ : avancer la lecture jusqu'à la fin du morceau\n" "\n" " r : activer/désactiver la lecture en boucle (repeat)\n" " R : activer/désactiver la lecture aléatoire (Random)\n" " x : activer/désactiver la lecture manuelle\n" "\n" " c : basculer entre l'affichage du temps restant ou celui écoulé\n" "\n" "\n" " Volume\n" " ------\n" "\n" " 1 .. 9 : modifier le volume (en dixaine de pourcentage)\n" " + : augmenter le volume de 1%\n" " - : diminuer le volume de 1%\n" " v : sélectionner le volume à modifier (principal ou auxilliaire)" #: cplay:571 msgid "filename" msgstr "fichiers seulement" #: cplay:572 msgid "pathname" msgstr "chemins complets" #: cplay:610 #, python-format msgid "Listing %s" msgstr "Affichage des %s" #: cplay:633 msgid "Tag regexp" msgstr "Sélection " #: cplay:633 msgid "Untag regexp" msgstr "Déselection " #: cplay:678 msgid "shell$ " msgstr "Commande : " #: cplay:725 msgid "bookmark" msgstr "Atteindre le marque-page " #: cplay:739 msgid "Not found!" msgstr "Marque-page introuvable !" #: cplay:744 msgid "set bookmark" msgstr "Poser un marque-page " #: cplay:753 msgid "search" msgstr "Recherche récursive " #: cplay:760 msgid "Searching..." msgstr "Recherche en cours ..." #: cplay:771 msgid "search results" msgstr "recherche" #: cplay:791 msgid "Filelist: " msgstr "Liste des fichiers : " #: cplay:802 msgid "Reading directory..." msgstr "Parcours du répertoire ..." #: cplay:859 msgid "goto" msgstr "Se déplacer vers " #: cplay:865 msgid "Not a directory!" msgstr "Répertoire introuvable !" #: cplay:876 msgid "Adding tagged files" msgstr "Ajout de la sélection effectué" #: cplay:912 msgid "metadata" msgstr "meta-donnée" #: cplay:918 #, python-format msgid "Playlist %s %s %s" msgstr "Liste de Lecture %s %s %s" #: cplay:919 msgid "[repeat]" msgstr "[boucle]" #: cplay:920 msgid "[random]" msgstr "[aléatoire]" #: cplay:921 msgid "[stop]" msgstr "[manuel]" #: cplay:964 cplay:1086 msgid "Working..." msgstr "Ajout en cours ..." #: cplay:973 #, python-format msgid "Added: %s" msgstr "Ajout de \"%s\" effectué" #: cplay:1059 msgid "Deleted playlist" msgstr "Liste vidée" #: cplay:1083 msgid "Shuffled playlist... Oops?" msgstr "Liste mélangée" #: cplay:1090 msgid "Sorted playlist" msgstr "Liste triée" #: cplay:1093 #, python-format msgid "Repeat: %s" msgstr "Lecture en boucle %s" #: cplay:1096 #, python-format msgid "Random: %s" msgstr "Lecture aléatoire %s" #: cplay:1102 #, python-format msgid "Stop playlist: %s" msgstr "Lecture manuelle %s" #: cplay:1106 msgid "on" msgstr "activée" #: cplay:1106 msgid "off" msgstr "désactivée" #: cplay:1113 msgid "Save playlist" msgstr "Enregistrement de la liste " #: cplay:1274 #, python-format msgid "Stopped: %s" msgstr "Arrêt : %s" #: cplay:1276 #, python-format msgid "Paused: %s" msgstr "Pause : %s" #: cplay:1278 #, python-format msgid "Playing: %s" msgstr "Lecture : %s" #: cplay:1463 msgid "Player not found!" msgstr "Programme de lecture introuvable pour ce fichier !" #: cplay:1524 #, python-format msgid "%s volume %s%%" msgstr "%s : volume à %s%%" #: cplay:1561 msgid "cancel" msgstr "Action annulée" #: cplay:1597 #, python-format msgid "Usage: %s [-nrRv] [ file | dir | playlist ] ...\n" msgstr "Usage %s [-nrRv] [ fichier | répertoire | liste_de_lecture ] ...\n"cplay-1.50/po/hu.po000066400000000000000000000114211155604254400141460ustar00rootroot00000000000000# Copyright (C) 2001 Gergely Nagy <8@free.bsd.hu> # msgid "" msgstr "" "Project-Id-Version: 1.0\n" "PO-Revision-Date: Thu Jun 7 12:29:48 CEST 2001\n" "Last-Translator: Gergely Nagy <8@free.bsd.hu>\n" "Language-Team: Gergely Nagy <8@free.bsd.hu>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: cplay:828 msgid "Almost there..." msgstr "Majdnem kész..." #: cplay:834 msgid "Cleared all marks..." msgstr "Minden jel törölve..." #: cplay:746 msgid "IOError" msgstr "I/O-hiba" #: cplay:882 cplay:888 msgid "off" msgstr "ki" #: cplay:918 msgid "Cannot write playlist!" msgstr "Nem tudom menteni a számlistát!" #: cplay:412 msgid "forward-isearch" msgstr "keresés elõre" #: cplay:539 msgid "Not found: %s" msgstr "Nem található: %s" #: cplay:727 msgid "Playlist %s %s" msgstr "Számlista %s %s" #: cplay:411 msgid "backward-isearch" msgstr "keresés hátra" #: cplay:878 msgid "Sorted playlist..." msgstr "Rendezett számlista..." #: cplay:205 msgid "Help" msgstr "Segítség" #: cplay:419 cplay:916 msgid "ok" msgstr "ok" #: cplay:958 msgid "Paused: %s" msgstr "Szünetel: %s" #: cplay:882 msgid "Repeat %s" msgstr "Ismétel %s" #: cplay:882 cplay:888 msgid "on" msgstr "be" #: cplay:742 cplay:749 msgid "Added: %s" msgstr "Hozzáadva: %s" #: cplay:728 cplay:729 msgid "[random]" msgstr "[véletlenszerû]" #: cplay:872 msgid "Shuffled playlist... Oops?" msgstr "Kevert számlista... Hopsz?" #: cplay:418 cplay:639 cplay:904 msgid "cancel" msgstr "mégsem" #: cplay:463 msgid "probably not ok" msgstr "valószinûleg nem jó" #: cplay:575 msgid "Reading directory..." msgstr "Könyvtár olvasása..." #: cplay:1162 msgid "Player not found!" msgstr "Lejátszó nem található!" #: cplay:611 msgid "Filelist: " msgstr "Állománylista: " #: cplay:1240 msgid "Usage: %s [ filename | playlist.m3u ] ...\n" msgstr "Használat: %s [ állományok | számlista.m3u ] ...\n" #: cplay:1217 msgid "Volume %d%%" msgstr "Hangerõ %d%%" #: cplay:941 cplay:964 msgid "Playing: %s" msgstr "Lejátszás: %s" #: cplay:181 msgid "" "\n" " Global Filelist\n" " ------ --------\n" " Up, C-p, k, Space : add to playlist\n" " Down, C-n, j, a : add recursively\n" " PgUp, PgDown, g : goto\n" " Home, End : movement Enter : chdir or play\n" " Tab : filelist/playlist Backspace : parent dir\n" " n,p : next/prev track \n" " z,x : toggle pause/stop Playlist\n" " Left, Right, --------\n" " C-b, C-f : seek Enter : play track\n" " C-s : forward-isearch Space : mark\n" " C-r : backward-isearch a,c : mark/clear all\n" " C-g, Esc : cancel m : move marked tracks\n" " 1..9, +- : volume d : delete marked tracks\n" " C-l : refresh screen r, R : toggle repeat/Random mode\n" " h : help s, S : shuffle/Sort playlist\n" " q : quit o : save playlist (to .m3u file)\n" msgstr "" "\n" " Általános Állománylista\n" " --------- -------------\n" " Fel, C-p, k, Szóköz : hozzáadás a számlistához\n" " Le, C-n, j, a : rekurzív hozzáadás\n" " PgUp, PgDown, g : ugrás\n" " Home, End : mozgás Enter : könyvtárváltás vagy lejátszás\n" " Tab : állomány/számlista Backspace : elõzõ könyvtár\n" " n,p : elõzõ/következp szám \n" " z,x : szünet/megállítás Számlista\n" " Baéra, Jobbra, ---------\n" " C-b, C-f : tekerés Enter : szám lejátszása\n" " C-s : keresés elõre Szóköz : megjelõlés\n" " C-r : keresés hátra a,c : összes megjelõlése/jelölés törlése\n" " C-g, Esc : mégse m : kijelölt számok mozgatása\n" " 1..9, +- : hangerõ d : kijelölt számok törlése\n" " C-l : képernyõ frissítés r, R : ismétlõ/kevert mód váltása\n" " h : segítség s, S : számlista keverése/rendezése\n" " q : kilépés o : számlista mentése (.m3u állományba)\n" #: cplay:727 cplay:728 msgid "[repeat]" msgstr "[ismétlés]" #: cplay:888 msgid "Random %s" msgstr "Véletlenszerû %s" #: cplay:894 msgid "Save playlist" msgstr "Számlista mentése" #: cplay:629 msgid "goto" msgstr "ugrás" #: cplay:975 msgid "Stopped: %s" msgstr "Megállítva: %s" #: cplay:1209 cplay:1219 msgid "Cannot open mixer device %s" msgstr "A %s keverõ-eszköz nem nyitható meg" #: cplay:710 msgid "Playlist" msgstr "Számlista" #: cplay:644 msgid "Not a directory!" msgstr "Nem könyvtár!" cplay-1.50/po/pl.po000066400000000000000000000161211155604254400141470ustar00rootroot00000000000000# Copyright (C) 2003 Marcin D. Mikielewicz # msgid "" msgstr "" "Project-Id-Version: 1.0\n" "PO-Revision-Date: Mon Apr 14 02:36:52 2003\n" "Last-Translator: Marcin D. Mikielewicz \n" "Language-Team: Marcin D. Mikielewicz \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: cplay:287 msgid "elapsed" msgstr "odegranego" #: cplay:287 msgid "remaining" msgstr "pozosta³ego" #: cplay:288 msgid "Counting %s time" msgstr "Licznik %s czasu" #: cplay:320 msgid "Quit? (y/N)" msgstr "Wyj¶æ (y/N)" #: cplay:405 msgid "backward-isearch" msgstr "szukanie-wstecz" #: cplay:407 msgid "forward-isearch" msgstr "szukanie-do przodu" #: cplay:496 cplay:657 cplay:748 cplay:760 cplay:1148 msgid "ok" msgstr "ok" #: cplay:505 cplay:517 msgid "Not found: %s " msgstr "Nie znaleziono: %s" #: cplay:525 msgid "Help" msgstr "Pomoc" #: cplay:528 msgid "" "\n" " Global Space : tag/untag current\n" " ------ t, T : tag current/regex\n" " Up, Down, k, j, C-p, C-n, u, U : untag current/regex\n" " PgUp, PgDn, K, J, i : invert tags\n" " Home, End, g, G : movement\n" " Enter : chdir or play Filelist\n" " Tab : filelist/playlist --------\n" " n, p : next/prev track BkSpc : parent dir\n" " z, x : toggle pause/stop o, s : goto, search recursively\n" " Left, Right, a : add (tagged) to playlist\n" " C-f, C-b : seek forward/backward\n" " c : counter mode Playlist\n" " C-s, C-r, / : isearch --------\n" " C-g, Esc : cancel d, D : delete (tagged) tracks/playlist\n" " 1..9, +, - : volume control m, M : move tagged tracks after/before\n" " v : PCM or MASTER volume r, R : toggle repeat/Random mode\n" " C-l, l : refresh, list mode s, S : shuffle/Sort playlist\n" " h, q, Q : help, quit?, Quit! w, @ : write playlist, jump to current\n" "\n" "\n" "\n" " Goodies\n" " -------\n" " b, ' : set/get filelist bookmark\n" " X : stop playlist after each track\n" " C-a, ^ : seek to beginning of current track (restart)\n" " C-e, $ : seek to end of current track (useless?)\n" " ! : shell command ($@ = tagged or current)\n" " " msgstr "" "\n" " Globalne Spacja: zaznacz/odznacz bie¿±cy\n" " ------ t, T : zaznacz bie¿±cy/regex\n" " Góra, Dó³, k, j, C-p, C-n, u, U : odznacz bie¿±cy/regex\n" " PgUp, PgDn, K, J, i : odwróæ zaznaczenia\n" " Home, End, g, G : poruszanie siê\n" " Enter : chdir or play Lista plików\n" " Tab : filelist/playlist --------\n" " n, p : nastêpny/poprzedniutwór BkSpc : katalog macierzysty\n" " z, x : prze³±cznik pauza/stop o, s : id¼ do, szukaj rekursywnie\n" " Lewo, Prawo, a : dodaj (zazanaczone) do listy odgrywania\n" " C-f, C-b : szukaj w przód/wstecz\n" " c : tryb licznika Lista odgrywania\n" " C-s, C-r, / : szukanie --------\n" " C-g, Esc : anuluj d, D : delete (tagged) tracks/playlist\n" " 1..9, +, - : kontrola g³o¶no¶ci m, M : move tagged tracks after/before\n" " v : g³o¶no¶æ PCM lub MASTER r, R : prze³±cznik trybu powtarzania/losowo¶ci\n" " C-l, l : od¶wie¿, tryb listy s, S : przetasuj/Sortuj listê odtwarzania\n" " h, q, Q : pomoc,wyj¶cie?,Wyj¶cie! w, @ : zapisz listê odtwarzania, skocz do bie¿±cego\n" "\n" "\n" "\n" " Dobrodziejstwa\n" " --------------\n" " b, ' : ustaw/pobierz listê plików z zak³adki\n" " X : zatrzymaj listê utworów po ka¿dym utworze\n" " C-a, ^ : szukaj do pocz±tku od bie¿±cego utworu (restart)\n" " C-e, $ : szukaj do koñca bie¿±cego utworu (u¿yteczne?)\n" " ! : komenda pow³oki ($@ = zaznaczone lub bie¿±ce)\n" " " #: cplay:593 msgid "filename" msgstr "plików" #: cplay:594 msgid "pathname" msgstr "¶cie¿ek" #: cplay:625 msgid "Listing %s" msgstr "Lista %s" #: cplay:648 msgid "Tag regexp" msgstr "Zaznacz wyra¿enie" #: cplay:648 msgid "Untag regexp" msgstr "Odznacz wyra¿enie" #: cplay:687 msgid "shell$ " msgstr "pow³oka$ " #: cplay:700 msgid "\nshell returned %s, press return!\n" msgstr "\npow³oka zwróci³a %s, wci¶nij enter!\n" #: cplay:734 msgid "bookmark" msgstr "zak³adka" #: cplay:750 msgid "Not found!" msgstr "Nie znaleziono!" #: cplay:755 msgid "set bookmark" msgstr "ustaw zak³adkê" #: cplay:764 msgid "search" msgstr "szukaj" #: cplay:771 msgid "Searching..." msgstr "Wyszukiwanie..." #: cplay:782 msgid "search results" msgstr "wyniki wyszukiwania" #: cplay:802 msgid "Filelist: " msgstr "Lista plików: " #: cplay:813 msgid "Reading directory..." msgstr "Wczytywanie katalogu..." #: cplay:868 msgid "goto" msgstr "id¼ do" #: cplay:874 msgid "Not a directory!" msgstr "To nie jest katalog!" #: cplay:919 msgid "metadata" msgstr "metadata" #: cplay:925 msgid "Playlist %s %s %s" msgstr "Lista utworów %s %s %s" #: cplay:926 msgid "[repeat]" msgstr "[powtarzanie]" #: cplay:927 msgid "[random]" msgstr "[losowo]" #: cplay:928 msgid "[stop]" msgstr "[zatrzymano]" #: cplay:967 msgid "File(\\d+)=(.*)" msgstr "Plik(\\d+)=(.*)" #: cplay:981 cplay:1108 msgid "Working..." msgstr "Zajety..." #: cplay:990 msgid "Added: %s" msgstr "Dodano: %s" #: cplay:990 msgid "Deleted playlist" msgstr "Skasowano listê utworów" #: cplay:1105 msgid "Shuffled playlist... Oops?" msgstr "Przetasowano listê utworów... Oops?" #: cplay:1112 msgid "Sorted playlist" msgstr "Posortowano listê utworów" #: cplay:1115 msgid "repeat" msgstr "powtarzanie" #: cplay:1115 msgid "Repeat: %s" msgstr "Powtarzanie: %s" #: cplay:1118 msgid "random" msgstr "losowanie" #: cplay:1118 msgid "Random: %s" msgstr "Losowo¶æ: %s" #: cplay:1124 cplay:1375 msgid "stop" msgstr "zatrzymanie" #: cplay:1124 msgid "Stop playlist: %s" msgstr "Zatrzymano listê utworów: %s" #: cplay:1128 msgid "on" msgstr "w³±czone" #: cplay:1128 msgid "off" msgstr "wy³±czone" #: cplay:1134 msgid "Save playlist" msgstr "Zapisz listê utworów" #: cplay:1310 msgid "Stopped: %s" msgstr "Zatrzymano: %s" #: cplay:1312 msgid "Paused: %s" msgstr "Pauza: %s" #: cplay:1314 msgid "Playing: %s" msgstr "Odtwarzanie: %s" #: cplay:1318 msgid "Time.*\\s(\\d+):(\\d+).*\\[(\\d+):(\\d+)" msgstr "Czas.*\\s(\\d+):(\\d+).*\\[(\\d+):(\\d+)" #: cplay:1369 msgid "pause" msgstr "pauza" #: cplay:1370 msgid "next" msgstr "nastêpny" #: cplay:1371 msgid "prev" msgstr "poprzedni" #: cplay:1372 msgid "forward" msgstr "do przodu" #: cplay:1373 msgid "backward" msgstr "wstecz" #: cplay:1374 msgid "play" msgstr "odtwarzaj" #: cplay:1491 msgid "Player not found!" msgstr "Nie znaleziono programu odtwarzaj±cego!" #: cplay:1548 msgid "Volume %s%%" msgstr "G³o¶no¶æ %s%%" #: cplay:1556 msgid "%s volume %s%%" msgstr "%s g³o¶no¶æ %s%%" #: cplay:1587 msgid "cancel" msgstr "anulowanie" #: cplay:1375 msgid "Usage: %s [-rRv] [ file | dir | playlist ] ...\n" msgstr "U¿ycie: %s [-rRv] [ plik | katalog | lista utworów ] ...\n" cplay-1.50/po/pt_BR.po000066400000000000000000000150021155604254400145370ustar00rootroot00000000000000# Brazilian portuguese translation for cplay # Copyright (C) 2004 # This file is distributed under the same license as the cplay package. # Ricardo Niederberger Cabral , 2004. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: 1.50pre1\n" "Report-Msgid-Bugs-To: nieder at mail dot ru\n" "POT-Creation-Date: 2004-02-06 23:57-0200\n" "PO-Revision-Date: 2004-02-06 23:57-0200\n" "Last-Translator: Ricardo Niederberger Cabral \n" "Language-Team: Ricardo Niederberger Cabral \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: cplay:273 msgid "elapsed" msgstr "passado" #: cplay:273 msgid "remaining" msgstr "restante" #: cplay:274 #, python-format msgid "Counting %s time" msgstr "Marcando tempo %s" #: cplay:307 msgid "Sair? (y/N)" msgstr "" #: cplay:393 msgid "busca incremental reversa" msgstr "" #: cplay:395 msgid "busca incremental adiante" msgstr "" #: cplay:487 cplay:643 cplay:738 cplay:750 cplay:1129 msgid "ok" msgstr "ok" #: cplay:496 cplay:508 #, python-format msgid "Not found: %s " msgstr "Não encontrado: %s " #: cplay:520 msgid "Help" msgstr "Ajuda" #: cplay:522 msgid "" " Global t, T : tag current/regex\n" " ------ u, U : untag current/regex\n" " Up, Down, k, j, C-p, C-n, Sp, i : invert current/all\n" " PgUp, PgDn, K, J, !, , : shell, macro\n" " Home, End, g, G : movement\n" " Enter : chdir or play Filelist\n" " Tab : filelist/playlist --------\n" " n, p : next/prev track a : add (tagged) to playlist\n" " z, x : toggle pause/stop s : recursive search\n" " BS, o : goto parent/specified dir\n" " Left, Right, m, ' : set/get bookmark\n" " C-f, C-b : seek forward/backward \n" " C-a, C-e : restart/end track Playlist\n" " C-s, C-r, / : isearch --------\n" " C-g, Esc : cancel d, D : delete (tagged) tracks/" "playlist\n" " 1..9, +, - : volume control m, M : move tagged tracks after/" "before\n" " c, v : counter/volume mode r, R : toggle repeat/Random mode\n" " <, > : horizontal scrolling s, S : shuffle/Sort playlist\n" " C-l, l : refresh, list mode w, @ : write playlist, jump to " "active\n" " h, q, Q : help, quit?, Quit! X : stop playlist after each " "track\n" msgstr "" " Global t, T : marca atual/regex\n" " ------ u, U : desmarca atual/regex\n" " Cima, Baixo, k, j, C-p, C-n, Sp, i : inverte seleção\n" " PgUp, PgDn, K, J, !, , : shell, macro\n" " Home, End, g, G : movimentação\n" " Enter : muda dir or toca Lista de arquivos\n" " Tab : lista/arquivos -----------------\n" " n, p : próx/anterior a : adiciona (marcados) à lista\n" " z, x : pausa/para s : procura recursiva\n" " BS, o : vai para dir superior/pai\n" " Esq., Direita, m, ' : define/recupera marcação\n" " C-f, C-b : avança frente/trás\n" " C-a, C-e : reinicia/termina Lista de músicas\n" " C-s, C-r, / : busca incremental ----------------\n" " C-g, Esc : cancela d, D : apaga musicas (marcadas)/" "playlist\n" " 1..9, +, - : controle de volume m, M : move marcadas depois/antes" " c, v : modo contador/volume r, R : modo de repetição/aleatório\n" " <, > : scroll horizontal s, S : embaralha/Ordena listagem\n" " C-l, l : atualiza listagem w, @ : grava lista, pula para lista\n" " h, q, Q : ajuda, sair?, Sair! X : para lista após cada faixa\n" #: cplay:572 msgid "filename" msgstr "nome do arquivo" #: cplay:573 msgid "pathname" msgstr "caminho" #: cplay:611 #, python-format msgid "Listing %s" msgstr "Exibindo %s" #: cplay:634 msgid "Tag regexp" msgstr "Marcar exp. regular" #: cplay:634 msgid "Untag regexp" msgstr "Desmarcar exp. regular" #: cplay:679 msgid "shell$ " msgstr "shell$ " #: cplay:726 msgid "bookmark" msgstr "marcador" #: cplay:740 msgid "Not found!" msgstr "Não encontrado!" #: cplay:745 msgid "set bookmark" msgstr "criar marcador" #: cplay:754 msgid "search" msgstr "procurar" #: cplay:761 msgid "Searching..." msgstr "Procurando..." #: cplay:772 msgid "search results" msgstr "resultados da busca" #: cplay:792 msgid "Filelist: " msgstr "Lista de arquivos:" #: cplay:803 msgid "Reading directory..." msgstr "Lendo diretório..." #: cplay:860 msgid "goto" msgstr "ir para" #: cplay:866 msgid "Not a directory!" msgstr "Diretório inválido!" #: cplay:877 msgid "Adding tagged files" msgstr "Adicionando arquivos marcados" #: cplay:913 msgid "metadata" msgstr "metadados" #: cplay:919 #, python-format msgid "Playlist %s %s %s" msgstr "Lista de músicas %s %s %s" #: cplay:920 msgid "[repeat]" msgstr "[repetir]" #: cplay:921 msgid "[random]" msgstr "[aleatório]" #: cplay:922 msgid "[stop]" msgstr "[parar]" #: cplay:965 cplay:1088 msgid "Working..." msgstr "Aguarde..." #: cplay:975 #, python-format msgid "Added: %s" msgstr "Adicionado: %s" #: cplay:1061 msgid "Deleted playlist" msgstr "Lista de músicas excluida" #: cplay:1085 msgid "Shuffled playlist... Oops?" msgstr "Lista de músicas embaralhada" #: cplay:1092 msgid "Sorted playlist" msgstr "Lista de músicas ordenada" #: cplay:1095 #, python-format msgid "Repeat: %s" msgstr "Repetir: %s" #: cplay:1098 #, python-format msgid "Random: %s" msgstr "Aleatório: %s" #: cplay:1104 #, python-format msgid "Stop playlist: %s" msgstr "Parar lista de músicas: %s" #: cplay:1108 msgid "on" msgstr "ligado" #: cplay:1108 msgid "off" msgstr "desligado" #: cplay:1115 msgid "Save playlist" msgstr "Salvar lista de músicas" #: cplay:1276 #, python-format msgid "Stopped: %s" msgstr "Parado: %s" #: cplay:1278 #, python-format msgid "Paused: %s" msgstr "Pausado: %s" #: cplay:1280 #, python-format msgid "Playing: %s" msgstr "Tocando: %s" #: cplay:1383 msgid "macro" msgstr "macro" #: cplay:1475 msgid "Player not found!" msgstr "Tocador não encontrado!" #: cplay:1536 #, python-format msgid "%s volume %s%%" msgstr "%s volume %s%%" #: cplay:1573 msgid "cancel" msgstr "cancelar" #: cplay:1609 #, python-format msgid "Usage: %s [-nrRv] [ file | dir | playlist ] ...\n" msgstr "Uso: %s [-nrRv] [ arquivo | dir | lista ] ...\n"