From 44a3d2d1b9f97def795cbe8ab846d2a1593cfb64 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 3 Jan 2011 09:49:13 -0800 Subject: mpdtoys (0.24) unstable; urgency=low * mprandomwalk: New toy to play random bits of all queued songs. * mpinsert: Add -p option to begin playing inserted songs. Closes: #608690 # imported from the archive --- mprompt | 370 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100755 mprompt (limited to 'mprompt') diff --git a/mprompt b/mprompt new file mode 100755 index 0000000..c58cc75 --- /dev/null +++ b/mprompt @@ -0,0 +1,370 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Audio::MPD q{0.19.0}; +use MpdToys; +use Getopt::Long; +use Term::ReadKey; +use Encode; + +=head1 NAME + +mprompt - simple prompt-based control for mpd + +=head1 SYNOPSIS + +mpompt [-s] [-m key=key] [-t n] [-f] [tty] [-T] [host] + +=cut + +sub usage { + die "Usage: mprompt [-s] [-m key=key] [-t n] [-f] [-t] [tty] [host]\n"; +} + +=head1 DESCRIPTION + +B is a mpd client with a prompt-based interface. It is +designed to be usable on a headless machine. + +At the prompt, enter the name of a playlist, or part of the name of an +album, artist, or song. Matching items will start playing. You can also +paste in urls to stream. + +(If the perl String::Approx module is available, it will be used to handle +typos, etc in the names you enter.) + +Use the left and right arrow keys to adjust volume, and the up and down +arrow keys to move through the playlist. + +The Tab and Enter keys can both be used to pause and unpause playback. +(Enter toggles pause only if nothing has been entered at the prompt.) + +Example of how to run mprompt in /etc/inittab: + + 1:2345:respawn:/usr/bin/mprompt /dev/tty1 + +=head1 OPTIONS + +=over 4 + +=item -s + +This option allows shell commands to be typed in to mprompt, to be +run by whatever user it is running as. (Typically root if it is run from +/etc/inittab). + +To enter a shell command, type a "!", followed by the command to run, +followed by Enter. + +=item -m key=key + +This option allows remapping keys. Any key can be remapped to any other +key, which is useful to support keyboard with unusual key layouts, or +missing keys. + +For alphanumeric and punctuation keys, individual symbols can be remapped. +For example, "-m a=b" will turn each entered "a" into "b". + +For other keys, use the following names: + +=over 4 + +=item + +=item + +=item + +=item + +=item + +=item + +=item + +=item + +=back + +For example, -m "n=" will map the "n" key to the down arrow, causing +that key to change to the next track; -m "=" will make the space +bar act as a pause. + +It's possible to swap keys too. For example, -m "=" -m "=" + +A single key can also be bound to a series of keystrokes. For example, +-m "1=Mule Variations" will cause the "1" key to play the "Mule +Variations" album, a nice choice. + +=item -t n + +Adds a timeout, a specified number of seconds after which the entry +on the command line will be cleared. Useful for headless systems, to avoid +cat-on-keyboard confusing your later commands. + +=item -T + +Enables terse output mode. This mode tries to avoid displaying excessive +or complex things, with the intent that mprompt's output can be piped into +a speech synthesiser, such as espeak. + +=back + +=head1 SEE ALSO + +vipl(1) mptoggle(1) mpd(1) + +=head1 AUTHOR + +Copyright 2009 Joey Hess + +Licensed under the GNU GPL version 2 or higher. + +http://kitenet.net/~joey/code/mpdtoys + +=cut + +my $tty; +my $shell=0; +my $timeout=0; +my $terse=0; +my %controlchars = GetControlChars; +my %keysyms = ( + "\n" => '', + "\t" => '', + " " => '', + "\e[A" => '', + "\e[3~" => '', # delete on some terminals, raw on others + "\e[B" => '', + "\e[D" => '', + "\e[C" => '', + $controlchars{ERASE} => "", +); +my %keymap; + +Getopt::Long::Configure("no_ignore_case"); +GetOptions( + "s" => \$shell, + "m=s" => sub { + my ($old, $new)=split(/=/, $_[1], 2); + $keymap{$old}=$new; + }, + "t=i" => \$timeout, + "f" => sub { print STDERR "the -f option is now enabled by default\n" }, + "T" => \$terse, +) || usage(); + +if (@ARGV) { + $tty=shift; + close STDIN; + close STDOUT; + open(STDIN, "<", $tty) || die "open $tty: $!"; + open(STDOUT, ">", $tty) || die "open $tty: $!"; +} +if (@ARGV) { + $ENV{MPD_HOST}=shift; +} +my $mpd=Audio::MPD->new(conntype => "reuse"); + +sub quit { + ReadMode("restore"); + exit(0); +}; +$SIG{INT}=$SIG{TERM}=\&quit; +ReadMode("raw"); + +$|=1; + +my $line=""; +my $sequence; +my $laststroke=time; + +showprompt(); + +KEY: while (my $key = ReadKey(0)) { + if ($timeout) { + if (length $line && time - $laststroke > $timeout) { + $line=""; + print " \n" unless $terse; + showprompt(); + } + $laststroke=time; + } + + if ($key eq $controlchars{INTERRUPT} || + $key eq $controlchars{EOF}) { + quit(); + } + + # Sequences are started with escape, and accumulated + # until a recognised sequence is seen, or until it becomes clear + # that it is not part of a recognised sequence. + if (defined $sequence) { + $sequence.=$key; + if (exists $keysyms{$sequence}) { + $key=$sequence; + $sequence=undef; + } + else { + foreach my $sym (keys %keysyms) { + if ($sym=~/^\Q$sequence\E/) { + next KEY; # unfinished sequence + } + } + $key=$sequence; + $sequence=undef; + } + } + + $key = $keysyms{$key} if exists $keysyms{$key}; + $key = $keymap{$key} if exists $keymap{$key}; + + # The key may be mapped to a multiple letter sequence. + while (length $key) { + if ($key=~s/^(<[^>]+>)//) { + handle($1); + } + elsif ($key=~s/(.)//) { + handle($1); + } + } +} + +sub handle { + my $key=shift; + + if ($key eq "\e") { + $sequence=$key; + } + elsif ($key eq '') { + if ($shell && $line =~ /^\!(.*)/) { + print "\nrunning $1\n"; + system($1); + } + elsif (length $line && $line !~ /^\s*$/) { + queue($line); + } + else { + toggle(); + } + $line=""; + showprompt(); + } + elsif ($key eq '') { + if (length $line) { + chop $line; + print "\b \b"; + } + } + elsif ($key eq '') { + print " "; + $line.=" "; + } + elsif ($key eq '') { + toggle(); + showprompt(); + } + elsif ($key eq '') { + adjustvolume(-5); + } + elsif ($key eq '') { + adjustvolume(+5); + } + elsif ($key eq '') { + $mpd->prev; + $mpd->play; + showplaying(); + showprompt(); + } + elsif ($key eq '') { + $mpd->next; + $mpd->play; + showplaying(); + showprompt(); + } + else { + print "$key"; + $line.=$key; + } +} + +sub adjustvolume { + my $amount=shift; + my $vol=$mpd->status->volume; + + $vol+=$amount; + if ($vol > 100) { + $vol=100; + } + elsif ($vol < 0) { + $vol=0; + } + + if (! $terse) { + print "\nvolume: $vol%\n"; + } + $mpd->volume($vol); + showprompt(); +} + +sub showprompt { + print "> $line"; +} + +sub showplaying { + print "\n"; + my $song=$mpd->current; + if (! defined $song) { + print "nothing queued\n"; + } + else { + if (! $terse) { + print encode_utf8($song->as_string)."\n"; + } + } +} + +sub toggle { + $mpd->pause; + my $state=$mpd->status->state; + print "\n"; + print "$state\n" if ! $terse || $state ne "play"; +} + +sub queue { + my $line=shift; + + print "\n"; + + my $pl=$mpd->playlist; + + eval q{$pl->load($line)}; + if (! $@) { + $pl->clear; + $pl->load($line); + $mpd->play; + + print "added $line playlist"; + showplaying(); + return; + } + + my @matches=MpdToys::findmatchingsongs($line, $mpd); + if (! @matches && MpdToys::canmatch_fuzzy()) { + print "trying fuzzy match..\n"; + @matches=MpdToys::findmatchingsongs_fuzzy($line, $mpd); + } + if (@matches) { + $pl->clear; + foreach (@matches) { + $pl->add($_->file); + } + $mpd->play; + print "added ".int(@matches)." songs"; + showplaying(); + } + else { + print "no matches found for \"$line\"\n"; + } +} -- cgit v1.2.3