App-Pimpd

 view release on metacpan or  search on metacpan

lib/App/Pimpd/Collection/Album.pm  view on Meta::CPAN

use App::Pimpd::Validate;
use Term::ExtendedColor qw(fg);

sub delete_album {
  my $file = $mpd->current->file;

  my($path) = $file =~ m|(.+)/.+$|m;
  my @songs = $mpd->collection->all_items_simple($path);


  printf("Remove %s ? [y/N] ", fg('bold', $path));

  chomp(my $answer = <STDIN>);
  if(lc($answer) ne 'y') {
    return 1;
  }

  $path = "$config{music_directory}/$path";

  if(remote_host()) {
    open(OLD_STDOUT, '>&', STDOUT) or die("Cant dupe STDOUT: $!");
    close(STDOUT);
    system(
      'ssh', "-p $config{ssh_port}",
      "$config{ssh_user}\@$config{ssh_host}",
      "rm -rv '$path'",
    ) == 0 and do {
      open(STDOUT, '>&', OLD_STDOUT) or die("Cant reopen STDOUT: $!");
      printf("Removed %s successfully\n", fg('bold', $path));
      return;
    };
    open(STDOUT, '>&', OLD_STDOUT) or die("Cant reopen STDOUT: $!");

  }
  else {
    if(remove_path($path)) {
      printf("removed '%s'\n", fg('bold', $path));
      return;
    }
    print STDERR "remove_path($path): $!\n";
    return;
  }
  return;
}


sub albums_by_artist {

lib/App/Pimpd/Doc.pm  view on Meta::CPAN

  if(exists($help{$cmd})) {
    return $help{$cmd}->();
  }
  else {
    return "No such topic.\n";
  }
}

sub _help_status {
  return << "EOF"
@{[fg('bold', 'Usage')]}: status

Display MPD status

EOF
}
sub _help_stats {
  return << "EOF"
@{[fg('bold', 'Usage')]}: stats

Display statistics about MPD

EOF
}

sub _help_unlove {
  return << "EOF"
@{[fg('bold', 'Usage')]}: unlove PATTERN

Un-love file(s) matching PATTERN.

EOF
}

sub _help_add_album {
  return << "EOF"
@{[fg('bold', 'Usage')]}: add-album ALBUM

Add all songs from ALBUM to playlist.
If ALBUM is omitted, use albumtag from the current song.

EOF
}


sub _help_add {
  return << "EOF"
@{[fg('bold', 'Usage')]}: add FILES || PLAYLIST

Argument can be either a playlist or a command that produces file lists.
Those commands include;

  songs   add all songs from the current album
  slove   add all songs matching pattern given to slove

EOF
}

sub _help_slove {
  return << "EOF"
@{[fg('bold', 'Usage')]}: slove PATTERN

Search the database with loved songs for PATTERN.

If PATTERN is omitted, returns all loved songs.

The results are added to the current playlist.
EOF
}

sub _help_random_track {
  return << "EOF"
@{[fg('bold', 'Usage')]}: randomtrack

Play a random song from the current playlist.
EOF
}

sub _help_stop {
  return << "EOF"
@{[fg('bold', 'Usage')]}: stop

Stop @{[fg('bold', 'local and remote')]} playback.
EOF
}


sub _help_kill {
  return << "EOF"
@{[fg('bold', 'Usage')]}: kill

Stop @{[fg('bold', 'local')]} playback.
EOF
}

sub _help_crop {
  return << "EOF"
@{[fg('bold', 'Usage')]}: crop

Remove all but the current song from the playlist.
EOF
}


sub _help_clear {
  return << "EOF"
@{[fg('bold', 'Usage')]}: clear

Clear the current playlist.
EOF
}

sub _help_random {
  return << "EOF"
@{[fg('bold', 'Usage')]}: random

Toggle random on/off.
EOF
}

sub _help_repeat {
  return << "EOF"
@{[fg('bold', 'Usage')]}: repeat

Toggle repeat on/off.
EOF
}

sub _help_pause {
  return << "EOF"
@{[fg('bold', 'Usage')]}: pause

Toggle playback status.
EOF
}

sub _help_previous {
  return << "EOF"
@{[fg('bold', 'Usage')]}: previous

Play the previous song in playlist.
EOF
}

sub _help_next {
  return << "EOF"
@{[fg('bold', 'Usage')]}: next

Play the next song in playlist.
EOF
}


sub _help_stitle {
  return << "EOF"
@{[fg('bold', 'Usage')]}: sartist TITLE

Search the collection for songs where the title tag
@{[fg('bold', 'partially')]} matches TITLE.
The results are added to the current playlist.
EOF
}

sub _help_salbum {
  return << "EOF"
@{[fg('bold', 'Usage')]}: sartist ALBUM

Search the collection for songs where the album tag
@{[fg('bold', 'partially')]} matches ALBUM.
The results are added to the current playlist.
EOF
}
sub _help_sartist {
  return << "EOF"
@{[fg('bold', 'Usage')]}: sartist ARTIST

Search the collection for songs where the artist tag
@{[fg('bold', 'partially')]} matches ARTIST.
The results are added to the current playlist.
EOF
}



sub _help_sany {
  return << "EOF"
@{[fg('bold', 'Usage')]}: sany PATTERN

Search the collection for filenams matching PATTERN.
The results are added to the current playlist.
EOF
}


sub _help_albums {
  return << "EOF"
@{[fg('bold', 'Usage')]}: albums [ARTIST]

List albums where ARTIST is featured.
If ARTIST is omitted, use the artist tag from the currently
playing song.
EOF
}


sub _help_songs {
  return << "EOF"
@{[fg('bold', 'Usage')]}: songs [ALBUM]

List songs on ALBUM.
If ALBUM is omitted, use the album tag from the currently playing
song.
EOF
}



sub _help_queue {
  return << "EOF"
@{[fg('bold', 'Usage')]}: queue INTEGERs

Put songs in a queue.
Arguments need to be valid playlist position IDs, as shown in
the 'playlist' output.
EOF
}

sub _help_splaylist {
  return << "EOF"
@{[fg('bold', 'Usage')]}: splaylist PATTERN

Search the current playlist for PATTERN.
If more then one result is found, queue up the results.

See 'help queue'.
EOF
}

sub _help_love {
  return << "EOF"
@{[fg('bold', 'Usage')]}: love [PLAYLIST]

Add the currently playing track to the library of loved songs.
If PLAYLIST is omitted, the song is added to a playlist following
this naming scheme:

  @{[fg($c[0], '%year-%month-%genre.m3u')]}

If a genre tag is missing, the string 'undef' is used in its place.
EOF
}

sub _help_loved {
  return << "EOF"
@{[fg('bold', 'Usage')]}: loved?

Check if the current song is already loved.
EOF
}

sub _help_delete_album {
  return << "EOF"
@{[fg('bold', 'Usage')]}: delete_album

Deletes the current album from disk.
EOF
}


sub _help_rm_album {
  return << "EOF"
@{[fg('bold', 'Usage')]}: rmalbum PATTERN

Search the current playlist for albums matching PATTERN and
removes the matches from the playlist.
EOF
}



sub _help_playlists {
  return << "EOF"
@{[fg('bold', 'Usage')]}: playlists

List all by MPD known playlists.
EOF
}


sub _help_playlist {
  return << "EOF"
@{[fg('bold', 'Usage')]}: playlist

Show the current playlist.
EOF
}


sub _help_shell {
  return sprintf("\n%s%s",
  "@{[fg('bold', fg($c[8], 'OPTIONS'))]}\t\t    " .
  "@{[fg('bold', fg($c[3], 'DESCRIPTION'))]} \t\t\t\t   "
,"
      np            show the current song
      info          show all current information
      copy          copy song to destination
      copya         copy album to destination
      queue         put songs in a queue

@{[fg('bold', fg($c[0], '  Playlist'))]}
      lsplaylists   list all known playlists
      add           add playlists or songs to the current playlist
      add-album     add songs from album to playlist
      rmalbum       remove album from playlist
      randomize     randomize a new playlist with n tracks
      randomalbum   and n random full albums
      love          love song
      loved?        check if the current song is loved
      unlove        unlove file(s) matching PATTERN
      splaylist     search the current playlist for str

@{[fg('bold', fg($c[0], '  Collection'))]}
      songs         list songs on album
      albums        list albums by artist
      sartist       search for artist str
      salbum        search for album str
      stitle        search for title str
      sany          search database for str
      slove         search the database with loved songs for pattern

@{[fg('bold', fg($c[0], '  Controls'))]}
      next          next track in playlist
      previous      previous track in playlist
      pause         toggle playback
      repeat        toggle repeat on/off
      random        toggle random on/off
      clear         clear playlist
      crop          remove all tracks but the current one
      kill          stop local playback

      help          show help for command
      exit          exit pimpd2

        \n", shift,
      );
}


sub _help_copy {
  return << "EOF"
@{[fg('bold', 'Usage')]}: copy [DESTINATION]

Copy the currently playing song to DESTINATION.

If DESTINATION is omitted, use the @{[fg($c[0], '$target_directory')]}
setting defined in @{[fg('bold', 'pimpd2.conf')]}.
EOF
}


sub _help_info {
  return << "EOF"
@{[fg('bold', 'Usage')]}: info

Show all available song metadata, as well as playback status
and various MPD settings.
EOF
}


sub _help_np {
  return << "EOF"
@{[fg('bold', 'Usage')]}: np

Show basic song metadata on a single line.
EOF
}



sub _help_randomize {
  return << "EOF"
@{[fg('bold', 'Usage')]}: randomize [INTEGER] [ARTIST]

Add n random songs from the collection to the current playlist.

The first, optional argument, is the number of songs to add.
The second, optional argument, is an artist name.
If a second argument is provided, add n random songs from that artist.

Defaults to 100 random songs.
EOF
}

sub _help_randomize_albums {
return << "EOF"
@{[fg('bold', 'Usage')]}: randomalbum [INTEGER]

Add n random full albums to the current playlist.

Defaults to 10 albums.
EOF
}

1;

__END__

lib/App/Pimpd/Info.pm  view on Meta::CPAN

  }
  return;
}

sub current {
  _current_update();

  my $output;
  if(to_terminal()) {
    $output = sprintf("%s - %s on %s from %s [%s]",
        fg($c[3], fg('bold',  $current{artist})),
        fg($c[11], $current{title}),
        fg($c[0], $current{album}),
        fg($c[4], fg('bold', $current{date})),
        $current{genre},
      );
  }
  else {
    $output = sprintf("%s - %s on %s from %s [%s]",
      $current{artist},
      $current{title},
      $current{album},
      $current{date},
      $current{genre},

lib/App/Pimpd/Info.pm  view on Meta::CPAN

  }

  $status{'state'} = 'Playing' if($status{'state'} eq 'play');
  $status{'state'} = 'Paused'  if($status{'state'} eq 'pause');
  $status{'state'} = 'Stopped' if($status{'state'} eq 'stop');

  if($status{volume} < 0) {
    $status{volume} = 'N/A (Software Mixer)';
  }

  printf("%s %8s: %.66s\n", fg('bold', fg('251', 'S')),
    'Artist', fg($c[3], fg('bold', $current{artist}))
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('250', 'O')),
    'Album', fg($c[0], $current{album})
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('249', 'N')),
    'Song', fg($c[11], fg('bold', $current{title}))
  );

  printf("%s %8s: %.66s\n", fg('bold', fg(248, 'G')),
    'Genre', fg($c[13], $current{genre})
  );
  printf("%s %9s: %s\n", fg('bold', undef),
    'File', fg($c[7], $current{file})
  );

  printf("%s %8s: %.66s\n", fg('bold', fg('247', 'I')),
    'Date', $current{date}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('246', 'N')),
    'Time', $current{time}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('245', 'F')),
    'Bitrate', $current{bitrate}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('244', 'O')),
    'Audio', $current{audio}
  );

  print fg($c[15]);
  print '-' x 25, clear(), "\n";

  printf("%s %8s: %.66s\n", fg('bold', fg('243', 'S')),
    'Repeat', $status{repeat}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('242', 'T')),
    'Shuffle', $status{shuffle}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('242', 'A')),
    'Xfade', $status{xfade}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('241', 'T')),
    'Volume', $status{volume}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('240', 'U')),
   'State', $status{state}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('239', 'S')),
   'List V', $status{list}
  );

  print fg($c[15]);
  print '-' x 25, clear(), "\n";

  printf("%s %8s: %.66s\n", fg('bold', fg('238', 'S')),
    'Song', $stats{song}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('237', 'T')),
    'List', $stats{length} . ' songs'
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('236', 'A')),
    'Songs', $stats{songs}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('235', 'T')),
    'Albums', $stats{albums}
  );
  printf("%s %8s: %.66s\n", fg('bold', fg('234', 'S')),
   'Artists', $stats{artists}
  );
  return;
}

sub _on_off {
  my $state = shift;

  if($state > 1) {
    return "ON ($state)";

lib/App/Pimpd/Player.pm  view on Meta::CPAN

  return;
}

sub player_destruct {
  open(my $fh, '<', $pidfile_pimpd) or return 1; # for now
  my $pimpd_player = <$fh>;
  close($fh);

  if(kill(9, $pimpd_player)) {
    unlink($player_tmp_log);
    #printf("%s %s\n", fg('bold', $pimpd_player), 'terminated');
  }

  open(my $fh, '<', $pidfile_player) or confess($!);
  my $pimpd_target = <$fh>;
  close($fh);

  if(kill(9, $pimpd_target)) {
    #printf("%s %s\n", fg('bold', $pimpd_target, 'terminated'));
  }

  if(kill(9, $pimpd_target+1)) {
    #printf("%s %s\n", fg('bold', $pimpd_target + 1), 'terminated');
  }
  return 0;
}


1;

__END__

=pod

lib/App/Pimpd/Playlist.pm  view on Meta::CPAN



  $mpd->random(0);
  $mpd->play(shift(@to_play));
  $mpd->playlist->move($mpd->current->pos, 0);

  return 0 if(scalar(@to_play) == 0);


  my $next_pos = $mpd->current->pos + 1;
  print fg('bold', 'Queueing'), ":\n";
  for(@to_play) {
    printf("%-50.50s %s\n", fg($c[3], $list{$_}), "( $_ => $next_pos )");

    $mpd->playlist->move($_, $next_pos);
    $next_pos++;
  }
  return;
}

sub show_playlist {

lib/App/Pimpd/Playlist.pm  view on Meta::CPAN

    my $crnt_title  = $mpd->current->title // undef;
    my $crnt_artist = $mpd->current->artist // undef;
    $title       =~ s/(\w+)/\u\L$1/gm;
    $artist      =~ s/(\w+)/\u\L$1/gm;
    $crnt_title  =~ s/(\w+)/\u\L$1/gm;
    $crnt_artist =~ s/(\w+)/\u\L$1/gm;

    if($mpd->current->pos == $i) {
      # bg('red4', $i) will add another 17 chars

      printf("%19s %51.51s |@{[fg('bold', 'x')]}| %-47.47s\n",
        bg($c[4], $i), fg($c[5], fg('bold',  $artist)), $title);

    }
    else {
      printf("%4d %25.25s | | %-47.47s\n",
        $i, $artist, $title);
    }
    $i++;
  }
  return;
}

lib/App/Pimpd/Playlist/Favorite.pm  view on Meta::CPAN

      printf("%s by %s is already loved!\n",
        fg($c[11], $title), fg($c[2], $artist),
      );

      return;
    }
  }
  else {
    if(already_loved($file, $favlist_m3u)) {
      printf("%s by %s is already loved in %s\n",
        fg($c[11], $title), fg($c[2], $artist), fg('bold', $favlist_m3u),
      );
      return;
    }
  }


  $genre =~ s/\s+/_/gm; # evil whitespace

  my(undef, undef, undef, undef, $month, $year) = localtime(time);
  $month += 1;

lib/App/Pimpd/Playlist/Favorite.pm  view on Meta::CPAN

      return 0;
    };
    return 1;
  } # Nope, not remote

  open(my $fh, '>>', $favlist_m3u)
    or die("Could not open '$favlist_m3u' in append mode: $!");
  print $fh "$file\n";
  close($fh);

  print fg($c[8], fg('bold', $title)), ' => ', fg($c[6], $favlist_m3u), "\n";

  return;
}


1;

__END__

=pod

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

  $opts = {

    'randomize'      => sub {
      if(!defined($_[0])) {
        $_[0] = 100;
      }
      elsif(defined($_[0]) and $_[0] !~ /^\d+$/m) {
        print STDERR "Need a valid integer\n";
        $_[0] = 100;
      }
      print 'Adding ' . fg('bold', @_) . " random tracks...\n";
      my @random = randomize(@_);

      print "$_\n" for @random;
      clear_playlist();
      add_to_playlist(@random);
    },


    'randomalbum'   => sub {
      $_[0] = 10 if(!$_[0]);
      print 'Adding ' . fg('bold', $_[0]) . " random albums...\n\n";
      my @albums = randomize_albums($_[0]);

      my $old = undef;
      for(@albums) {
        my($album_dir) = $_ =~ m|(.+)/.+|m;
        if($old ne $album_dir) {
          print "> $album_dir\n";
          $old = $album_dir;
        }
      }

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

      add_to_playlist(@albums);
    },


    'playlist'       => sub {
      if(empty_playlist()) {
        print STDERR "Playlist is empty\n";
        return 1;
      }
      show_playlist();
      print fg('bold', ' >'), '> ', current(), "\n";
    },


    'love'           => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      add_to_favlist(@_);
    },

    'loved?'          => sub {
      if(already_loved($mpd->current->file)) {
        printf("%s, %s by %s is loved.\n",
          fg('bold', 'Yes'),
          fg($c[10], $mpd->current->title),
          fg($c[2],  fg('bold', $mpd->current->artist)),
        );
      }
      else {
        printf("%s, %s by %s is not loved yet.\n",
          fg('bold', 'No'),
          fg($c[10], $mpd->current->title),
          fg($c[2],  fg('bold', $mpd->current->artist)),
        );
      }
    },

    'unlove'            => sub {
      if(!@_) {
        print help('unlove');
        return;
      }
      remove_favorite(@_);

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

    'add-album'       => sub {
      add_to_playlist( map{ $_->file } get_album_songs(@_));
    },
    'lsplaylists'     => sub { print "$_\n" for list_all_playlists(); },
    'add'             => sub {

      if($_[0] eq 'songs') {
        local $\ = "\n";
        my @songs = map { $_->file } songs_on_album();
        printf("Adding %d songs from %s\n",
          scalar(@songs), fg('bold', $mpd->current->album),
        );
        add_to_playlist(@songs);
      }

      elsif($_[0] eq 'slove') {
        shift @_; # so we can grab the PATTERN
        my @result = search_favlist(@_);

        if(scalar(@result) > 0) {
          print "$_\n" for @result;

          add_to_playlist(@result);
          printf("\nAdded %s loved %s matching '%s'\n",
            fg('bold', scalar(@result)),
            (scalar(@result) > 1) ? 'songs' : 'song',
            fg($c[4], fg('bold', $_[0])),
          );
        }
        else {
          printf("No songs matching '%s' were found\n",
            fg($c[4], fg('bold', $_[0])),
          );
        }
      }

      else {
        add_playlist(@_);
      }
    },

    'next'            => sub {

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

      if(invalid_playlist_pos(@_)) {
        printf("No such song%s\n", (@_ < 1) ? 's' : '');
        return 1;
      }
      queue(@_);
    },

    'random'           => sub {
      $mpd->random;
      my $status =  ($mpd->status->random)
        ? "Random: " . fg('bold', 'On')
        : "Random: " . fg('bold', 'Off');
      print "$status\n";
    },

    'repeat'           => sub {
      $mpd->repeat;
      my $status = ($mpd->status->repeat)
        ? "Repeat: " . fg('bold', 'On')
        : "Repeat: " . fg('bold', 'Off');
      print "$status\n";
    },

    'stats'            => sub { stats(); },
    'status'           => sub { print status(), "\n"; },

    'randomtrack'      => sub {
      play_pos_from_playlist(random_track_in_playlist());
      print current(), "\n";
    },

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

      if( defined($opts->{$_[0]}) ) {
        print help($_[0]);
      }
      else {
        print help('shell');
      }
    },
  };

  while(1) {
    #print fg($c[6], 'pimpd'), fg('bold', '> ');

    #chomp(my $choice = <STDIN>);
    my @available_cmd = keys(%{$opts});
    push(@available_cmd, 'shell');

    my $term = Term::ReadLine->new('pimpd2');
    my $attr = $term->Attribs;

    $attr->{completion_function} = sub {
      my($text, $line, $start) = @_;

lib/App/Pimpd/Shell.pm  view on Meta::CPAN

    };

    $attr->{autolist} = 0;
    $attr->{maxcomplete} = 0;
    # Sane keymap please.
    $term->set_keymap('vi');

    my $choice;

    while(1) {
      $choice = $term->readline(fg($c[6], 'pimpd') . fg('bold', '> '));
      $term->addhistory($choice) if $choice =~ /\S/m;

      ($cmd) = $choice =~ m/^(\S+)/m;
      ($arg) = $choice =~ m/\s+(.+)$/m;
      @cmd_args  = split(/\s+/m, $arg);

      if(defined($opts->{$cmd})) {
        $mpd->play;
        $opts->{$cmd}->(@cmd_args);
      }

lib/App/Pimpd/Validate.pm  view on Meta::CPAN

      if(scalar(@choices) == 0) {
        print STDERR "No such playlist '" . fg($c[5], $list), "'\n";
        return;
      }


      print "'all' uses all playlists\n\n";

      my $i = 0;
      for my $choice(@choices) {
        print fg('bold', sprintf("%3d", $i)), " $choice\n";
        $i++;
      }
      print "choice: ";
      chomp(my $answer = <STDIN>);

      if( ($answer eq 'all') or ($answer eq '') ) {
        return @choices;
      }
      elsif($answer eq 'current') {
        return(undef);

pimpd2  view on Meta::CPAN


  'cp|copy'              => sub { cp(@ARGV ? @ARGV : $config{target_directory}) },
  'cpa|copy-album'       => sub {
    cp_album(@ARGV ? @ARGV : $config{target_directory})
  },

  'fav|favorite|love'    => sub { add_to_favlist(@ARGV); }, # FIXME
  'loved'                => sub {
    if(already_loved($mpd->current->file)) {
      printf("%s, %s by %s is loved.\n",
        fg('bold', 'Yes'),
        fg($c[10], $mpd->current->title),
        fg($c[2],  fg('bold', $mpd->current->artist)),
      );
    }

    else {
      printf("%s, %s by %s is not loved yet.\n",
        fg('bold', 'No'),
        fg($c[10], $mpd->current->title),
        fg($c[2],  fg('bold', $mpd->current->artist)),
      );
    }
  },

  'unlove'               => sub { remove_favorite(@ARGV); },

  'aa|add-album'         => sub {
    add_to_playlist( map{ $_->file } get_album_songs(@ARGV) );
  },
  'slove'                => sub {



( run in 0.600 second using v1.01-cache-2.11-cpan-5dc5da66d9d )