Skip to content

Instantly share code, notes, and snippets.

@dru8274
Created January 4, 2016 00:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dru8274/33032f5682320232ef4a to your computer and use it in GitHub Desktop.
Save dru8274/33032f5682320232ef4a to your computer and use it in GitHub Desktop.
Fvwm Ncmpcpp
## Fvwm Ncmpcpp
How I did the mpd/ncmpcpp player from this scrot : http://i.imgur.com/RaeCY46.png?1
1] MusicPlayer. The fvwmbuttons definition for the musicplayer. It contains swallow commands for
ncmpcpp and the mpdbar perl script.
2] colors_ncmpcpp A perl script used to change colors of the terminal used by ncmpcpp. Optional.
3] mpdbar. My perl script that creates a progress bar for mpd. It is intended to look similar to
the ncmpcpp progressbar. It listens to mpd to detect when the track has changed. In between track
changes, and alarm function periodically updates the progressbar for the current track. When a
new track is started, mpdbar runs the coverart script.
4] coverart.sh My script to update the coverart image. All my mp3s have embedded cover.jpg, but
your system may be different. When it has extracted the current cover image, it sends a
SendToModule command to fvwm to update the image in the MusicPlayer
5] ncmpcpp_config Lastly, my ncmpcpp config. Nothing special here to note except that I have
turned some things like progressbars off to make it very minimal.
When I put this together, I wasn't really thinking about the beauty of coding. It is at least 2
or 3 revisions away from that, I'm afraid.
Looking below, I have used the Term::ExtendedColor and Term::ExtendedColor::Xresources perl modules
to change the colors of a 256 terminal. I don't like to be limited to just the colors in my ~/.Xresources.
However, I you are using Debian, those modules are not in the repos. They have to be installed via cpan
using your favourite method. apt-get install cpanminus liblocal-lib-perl
## On Debian, tells you which perl lib to install to provide a certain perl module
http://deb.perl.it/debian/cpan-deb/
#!/usr/bin/perl
use strict ;
use warnings ;
use local::lib ;
use Term::ExtendedColor qw(:all) ;
use Term::ExtendedColor::Xresources qw(
get_xterm_color
set_xterm_color
set_foreground_color
set_background_color
);
## Apart from black/white, red(1/9) yellow(3/11) blue(4/12) and
## magenta(5/13) are only colors that have been set intentionally.
my $colors = set_xterm_color({
0 => "181818",
1 => "a67558",
2 => "a67458",
3 => "bfb273",
4 => "5f86ad",
5 => "996b99",
6 => "86c1b9",
7 => "d8d8d8",
8 => "585858",
9 => "cc8f6c",
10 => "a1b56c",
11 => "e6d68a",
12 => "88add1",
13 => "c493c4",
14 => "86c1b9",
15 => "f8f8f8",
16 => "dc9656",
});
print $_ for values %{ $colors } ;
#!/bin/bash
## Coverart script. Extracts cover art imahes from an mp3 using eyeD3.
## Converts it to the right size with imagemagick.
## Sends an fvwm command that updates the current image.
if mkdir /tmp/eyeD3 2>&1 1>/dev/null ; then
cd /tmp/eyeD3
rm *png *jpg *jpeg 2>&1 1>/dev/null
#GEOM='150x150!'
#GEOM='198x198!'
GEOM='250x250!'
COVERART="$FVWM_USERDIR/images/coverart.png"
DEFAULT="$HOME/.fvwm/images/beachhouse.png"
eyeD3 -i . "$1" 2>&1 1>/dev/null
while IFS= read FILEX ; do
[[ -e "$FILEX" ]] && break
done <<EOF
FRONT_COVER.png
FRONT_COVER.jpg
FRONT_COVER.jpeg
FRONT_COVER1.png
FRONT_COVER1.jpg
FRONT_COVER1.jpeg
OTHER.png
OTHER.jpg
OTHER.jpeg
EOF
if [[ -e "$FILEX" ]] ; then
convert -quality 95% "$FILEX" -adaptive-resize "$GEOM" "$COVERART"
else
convert -quality 95% "$DEFAULT" -adaptive-resize "$GEOM" "$COVERART"
fi
rm -r /tmp/eyeD3 2>&1 1>/dev/null
FvwmCommand UpdateCoverArt
fi
#!/usr/bin/perl
## Displays a progress bar + current track/album/artist for MPD in urxvt.
## It monitors `mpc idleloop` to detect changes in MPD status, and
## displays info accordingly. An external coverart script is called
## when a new track is detected.
##
## Intended to look very similar to the progress+trackinfo for ncmpcpp.
## Expects to be run in a 256-color terminal like urxvt.
## ~/temp-fvwmperl/006/test6.pl
use strict ;
use warnings ;
use v5.18 ;
use POSIX qw(mkfifo) ;
use Term::ExtendedColor qw(:all) ;
use Term::ExtendedColor::Xresources qw( set_xterm_color ) ;
use Time::HiRes qw( ualarm ) ;
use Math::Round qw( nearest ) ;
use Text::Unidecode ;
use Term::ReadKey ;
use local::lib ;
use Data::Dump qw( dump ) ;
## Debian: libterm-readkey-perl libmath-round-perl libtext-unidecode-perl
## Install from CPAN : Term::ExtendedColor Term::ExtendedColor::Xresources
## MPD music directory
my $music_dir = $ENV{HOME} . "/Music" ;
## autoflush the buffer
$| = 1 ;
## invisible cursor (tput civis)
print "\x1b\x5b\x3f\x32\x35\x6c" ;
## terminal char width
my $urxvt_width ;
($urxvt_width, $_, $_, $_) = GetTerminalSize() ;
my $coverart_exec = "$ENV{FVWM_USERDIR}/bin/coverart.sh" ;
## COLORS
## black(0/8) red(1/9) green(2/10) yellow(3/11)
## blue(4/12) magenta(5/13) cyan(6/14) grey(7/15)
## Define colors for urxvt
my $urxvt_colors = set_xterm_color({
0 => "181818",
1 => "ab4642",
2 => "a1b56c",
3 => "f7ca88",
4 => "6A96A6",
5 => "ba8baf",
6 => "86c1b9",
7 => "d8d8d8",
8 => "404040",
9 => "ab4642",
10 => "a1b56c",
11 => "f7ca88",
12 => "7cafc2",
13 => "ba8baf",
14 => "86c1b9",
15 => "8C8C8C",
});
## Set the defined colors
print $_ for values %{ $urxvt_colors } ;
## Progress bar.
#my $prog_width = $urxvt_width - 2 ;
my $prog_color_on = 4 ;
my $prog_color_off = 8 ;
my $bookends_color = 7 ;
## Vars that define the track info tickr.
## $track_info_width is target width for trackinfo, whereas
## $track_info_length is the raw sum of @trackinfo.
## Such that if length > width, then rotation will be needed.
my @trackinfo = () ;
my ($trackinfo_length, $track_info_width, $elapsed_width) ;
my ($first_idx, $first_offset, $last_idx, $last_offset) ;
## Format chars to display trackinfo.
my $tup = "\x1b\x4d" ;
my $tcel = "\x0d\x1b\x5b\x4b" ; # \r$(tput el)
my $mode_color = 15 ;
my $elapsed_color = 15 ;
my @color = qw( 3 1 2 1 12 1 ) ;
my @div = ( " * ", " * ", " ** " ) ;
my %mpcdata = (
state => "stop",
file_uri => "notrack",
title => "",
artist => "",
album => "",
elapsed => 0,
duration => 0,
percent => 0,
) ;
#### MAIN LOOP
## Setup periodic alarm for during playback.
$SIG{ALRM} = \&polling ;
my $pollinterval = 1000000 ;
## Using mpc idleloop to detect mpd events.
open(MPC, "echo && mpc idleloop 2>/dev/null | ") || die "MPC failed. \n" ;
LOOP: while (<MPC>) {
## Get current mpd info from mpc.
my %newdata = ( state => "stop" ) ;
foreach (`mpc -f "%title%:::%artist%:::%album%:::%file%:::"`) {
if ( /^(.*):::(.*):::(.*):::(.*):::$/ ) {
$newdata{title} = unidecode($1) ;
$newdata{artist} = unidecode($2) ;
$newdata{album} = unidecode($3) ;
$newdata{file_uri} = "$music_dir/$4" ;
} elsif (/^[[](\w+)[]]\s+\#[^ ]+\s+([:\d]+)\/([:\d]+)\s\((\d+)%\)\s*$/) {
@newdata{"state", "elapsed"} = ($1, $2) ;
@newdata{"duration", "percent"} = ( $3, $4) ;
}
}
## Ensure that %newdata has complete data, else goto stop mode.
foreach my $key (keys %mpcdata) {
if (not defined $newdata{$key}) {
#say STDERR "STOP" ;
$mpcdata{state} = "stop" ;
clear_bar() ;
next LOOP ;
}
}
## Stop mode
if ($newdata{state} eq "stop" or not -e $newdata{file_uri} ) {
$mpcdata{state} = "stop" ;
#say STDERR "STOP" ;
clear_bar() ;
next ;
}
## Play or pause mode, but the file_uri is unchanged.
if ($newdata{file_uri} eq $mpcdata{file_uri}) {
$mpcdata{"state"} = $newdata{"state"} ;
if ($mpcdata{state} eq "playing") {
polling()
} else {
update_elapsed() ;
print_trackinfo() ;
}
## An entirely new track in play mode.
} else {
%mpcdata = %newdata ;
init_track_info() ;
polling() ;
system("exec $coverart_exec \"$mpcdata{file_uri}\" 2>&1 1>/dev/null &") ;
}
}
#### SUBROUTINES
sub polling {
if ($mpcdata{state} eq "playing") {
update_elapsed() ;
print_trackinfo() ;
rotate_trackinfo() ;
ualarm($pollinterval) ;
return ;
} else {
ualarm 0 ;
return ;
}
}
sub init_track_info {
## Calc format widths for the tickr bar.
$elapsed_width = (length($mpcdata{duration}) * 2) + 3 ;
$track_info_width = $urxvt_width - $elapsed_width - 10 ;
## Assorted items that comprise the trackinfo tickr.
@trackinfo = (
$mpcdata{title}, $div[0],
$mpcdata{artist}, $div[1],
$mpcdata{album}, $div[2],
) ;
## Raw summed length of assorted items that comprise @trackinfo.
$trackinfo_length = 0 ;
foreach (@trackinfo) { $trackinfo_length += length($_) }
## Indexes and offsets into @trackinfo used to calc its rotation.
$first_idx = $first_offset = 0 ;
$last_idx = $last_offset = 0 ;
for (my $idx = my $l = 0 ; $idx <= $#trackinfo ; $idx++) {
$l += length($trackinfo[$idx]) ;
if ($l >= $track_info_width) {
$last_idx = $idx ;
$last_offset = length($trackinfo[$idx]) -
$l + $track_info_width ;
last ;
}
}
}
sub print_trackinfo {
my $info ;
if ($trackinfo_length <= $track_info_width) {
for (my $idx = 0 ; $idx <= $#trackinfo ; $idx++ ) {
$info .= fg($color[$idx], $trackinfo[$idx]) ;
}
## sprintf method wont work here coz of color chars
my $num = ($track_info_width - $trackinfo_length) ;
$info .= " " x $num ;
} elsif ($first_idx == $last_idx and $first_offset < $last_offset) {
#my $num_chars = $last_offset - $first_offset + 1 ;
my $num_chars = $last_offset - $first_offset ;
$info .= fg( $color[$first_idx],
substr($trackinfo[$first_idx], $first_offset, $num_chars)
)
} else {
$info .= fg( $color[$first_idx],
substr($trackinfo[$first_idx], $first_offset)
) ;
for ( my $idx = ($first_idx + 1)%($#trackinfo + 1) ;
$idx != $last_idx ;
$idx = ($idx + 1)%($#trackinfo + 1)) {
$info .= fg($color[$idx], $trackinfo[$idx])
}
$info .= fg( $color[$last_idx],
substr($trackinfo[$last_idx], 0, $last_offset)
) ;
}
## Put bits of colored text together and print.
my $progress = get_progress($mpcdata{percent}) ;
my $mode = $mpcdata{state} eq "playing" ? "Playing:" : "[Paused]" ;
$mode = fg($mode_color, $mode) ;
my $time_info = "[$mpcdata{elapsed}/$mpcdata{duration}]" ;
my $fmt = "%${elapsed_width}.${elapsed_width}s" ;
$time_info = sprintf($fmt , $time_info) ;
$time_info = fg($elapsed_color, $time_info) ;
# my $pad = " " x ($elapsed_width - length($time_info)) ;
# $time_info = $pad . $time_info ;
#printf "%s\n%s\n", $progress, "$mode $info $time_info" ;
printf "${tup}\r%s\n\r%s", $progress, "$mode $info $time_info" ;
}
sub rotate_trackinfo {
if (($first_offset + 1) < length($trackinfo[$first_idx])) {
$first_offset++
} else {
$first_offset = 0 ;
$first_idx = ($first_idx + 1)%($#trackinfo + 1) ;
}
if (($last_offset + 1) < length($trackinfo[$last_idx])) {
$last_offset++
} else {
$last_offset = 0 ;
$last_idx = ($last_idx + 1)%($#trackinfo + 1) ;
}
}
sub update_elapsed {
foreach (`mpc status`) {
if (/^[[].+#[^ ]+\s+([:\d]+)\/[:\d]+\s\((\d+)%\)\s*$/) {
@mpcdata{"elapsed", "percent"} = ($1, $2) ;
}
}
}
sub get_progress {
my $num_in = shift ;
my $prog_width = $urxvt_width ;
my $normal_width = nearest(1, $num_in * $prog_width / 100) ;
#my $out = fg($bookends_color, "[") ;
my $out = fg($prog_color_on, "■" x $normal_width) ;
$out .= fg($prog_color_off, "■" x ($prog_width - $normal_width)) ;
#$out .= fg($bookends_color, "]") ;
return $out ;
}
sub clear_bar {
print $tup ;
say $tcel ;
print $tcel ;
}
Colorset 130 TiledPixmap "digital-tile-2.png"
#Colorset 131 hi #274A66, sh #274A66, Pixmap "term-tile.png"
Colorset 131 hi #274A66, sh #274A66, bg grey9
#Colorset 132 bg #1F1E1C, VGradient 20 grey11 grey18
Colorset 132 bg grey9
Colorset 133 bg orange
Colorset 140 fg SteelBlue4, bg SteelBlue4
DestroyModuleConfig Ncmpcpp: *
*Ncmpcpp: Geometry 778x384
*Ncmpcpp: Columns 778
*Ncmpcpp: Rows 384
#*Ncmpcpp: Rows 262
*Ncmpcpp: Padding 0 0
*Ncmpcpp: BoxSize fixed
*Ncmpcpp: Frame 0
*Ncmpcpp: Colorset 130
*Ncmpcpp: (778x20)
#### NCMPCPP PLAYER
*Ncmpcpp: (20x7)
*Ncmpcpp: (454x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (264x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (20x10)
*Ncmpcpp: (7x10, Colorset 140)
*Ncmpcpp: (440x10, Colorset 132)
*Ncmpcpp: (7x10, Colorset 140)
*Ncmpcpp: (20x10)
*Ncmpcpp: (7x10, Colorset 140)
#*Ncmpcpp: (250x250, Back olive)
*Ncmpcpp: (250x250, Id coverart, Icon coverart3.png )
*Ncmpcpp: (7x10, Colorset 140)
*Ncmpcpp: (20x10)
*Ncmpcpp: (20x240)
*Ncmpcpp: (7x240, Colorset 140)
#*Ncmpcpp: (440x240, Back olive)
*Ncmpcpp: (440x240, Swallow "myncmpcpp" "Exec exec urxvt -T myncmpcpp -g 44x12 -bg grey9 -fn -misc-tamsyn-bold-r-normal--20-145-100-100-c-100-iso8859-1 -fb -misc-tamsyn-bold-r-normal--20-145-100-100-c-100-iso8859-1 -e sh -c \"$FVWM_USERDIR/bin/colors_ncmpcpp && exec ncmpcpp -c $HOME/.ncmpcpp/config.minimal\" " )
*Ncmpcpp: (7x240, Colorset 140)
*Ncmpcpp: (20x240)
*Ncmpcpp: (7x240, Colorset 140)
*Ncmpcpp: (7x240, Colorset 140)
*Ncmpcpp: (20x240)
*Ncmpcpp: (20x7)
*Ncmpcpp: (454x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (264x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (778x20)
*Ncmpcpp: (20x7)
*Ncmpcpp: (738x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (20x3)
*Ncmpcpp: (7x3, Colorset 140)
*Ncmpcpp: (724x3, Colorset 132)
*Ncmpcpp: (7x3, Colorset 140)
*Ncmpcpp: (20x3)
*Ncmpcpp: (20x40)
*Ncmpcpp: (7x40, Colorset 140)
*Ncmpcpp: (12x40, Colorset 132)
#*Ncmpcpp: (700x40, Back olive)
*Ncmpcpp: (700x40, Colorset 132, Swallow "ngbar" "Exec exec urxvt -T ngbar -g 70x2 -fn -misc-tamsyn-bold-r-normal--20-145-100-100-c-100-iso8859-1 -fb -misc-tamsyn-bold-r-normal--20-145-100-100-c-100-iso8859-1 -e \"$[FVWM_USERDIR]/bin/mpdbar\" "
*Ncmpcpp: (12x40, Colorset 132)
*Ncmpcpp: (7x40, Colorset 140)
*Ncmpcpp: (20x40)
*Ncmpcpp: (20x3)
*Ncmpcpp: (7x3, Colorset 140)
*Ncmpcpp: (724x3, Colorset 132)
*Ncmpcpp: (7x3, Colorset 140)
*Ncmpcpp: (20x3)
*Ncmpcpp: (20x7)
*Ncmpcpp: (738x7, Colorset 140)
*Ncmpcpp: (20x7)
*Ncmpcpp: (778x19)
*Ncmpcpp: (778x1)
#### STYLES
## If anything goes wrong, these windows will stay on desk7 as an error.
Style myncmpcpp StartsOnDesk 7
Style ngbar StartsOnDesk 7
Style ngbar !Title, !Borders, !Handles
Style Ncmpcpp FixedSize, StartsOnDesk 2
Style Ncmpcpp PositionPlacement -+20p ++20p, InitialMapCommand Move -+20p ++20p
Style Ncmpcpp !Title, Borderwidth 7, Handlewidth 7
DestroyFunc UpdateCoverArt
AddToFunc UpdateCoverArt
+ I SendToModule Ncmpcpp ChangeButton coverart Icon coverart.png
KillModule FvwmButtons Ncmpcpp
Module FvwmButtons Ncmpcpp
## ████ ██ ██████ ████ ████ ███████ ██████ ███████ ███████
## ░██░██ ░██ ██░░░░██░██░██ ██░██░██░░░░██ ██░░░░██░██░░░░██░██░░░░██
## ░██░░██ ░██ ██ ░░ ░██░░██ ██ ░██░██ ░██ ██ ░░ ░██ ░██░██ ░██
## ░██ ░░██ ░██░██ ░██ ░░███ ░██░███████ ░██ ░███████ ░███████
## ░██ ░░██░██░██ ░██ ░░█ ░██░██░░░░ ░██ ░██░░░░ ░██░░░░
## ░██ ░░████░░██ ██░██ ░ ░██░██ ░░██ ██░██ ░██
## ░██ ░░███ ░░██████ ░██ ░██░██ ░░██████ ░██ ░██
## ░░ ░░░ ░░░░░░ ░░ ░░ ░░ ░░░░░░ ░░ ░░
## Config modified from xero's config here...
## https://github.com/xero/dotfiles/blob/master/.ncmpcpp/config
## █▓▒░ Setup
ncmpcpp_directory = "/home/nostromo/.ncmpcpp"
external_editor = "/usr/bin/vim"
## █▓▒░ MPD Settings
mpd_crossfade_time = "3"
mpd_music_dir = "/home/nostromo/Music"
## █▓▒░ Start Options
## startup_screen = "2"
## display_screens_numbers_on_start = "no"
jump_to_now_playing_song_at_start = "yes"
mouse_support = "no"
enable_window_title = "no"
## allow_physical_files_deletion = "no"
## allow_physical_directories_deletion = "no"
colors_enabled = "yes"
titles_visibility = "no"
header_visibility = "no"
statusbar_visibility = "no"
display_volume_level = "no"
display_bitrate = "no"
display_remaining_time = "no"
progressbar_look = " "
## to make the progressbar invisible
user_interface = "classic"
ignore_leading_the = "yes"
discard_colors_if_item_is_selected = "yes"
autocenter_mode = "yes"
centered_cursor = "yes"
## "Classic" and "column" styles for song display - may apply to several views.
song_list_format = "{$5%a $1• $8}{%t$1$R}"
##### columns settings #####
##
## syntax of song columns list format is "column column etc."
##
## - syntax for each column is:
##
## (width of column)[column's color]{displayed tag}
##
## Note: Width is by default in %, if you want a column to
## have fixed size, add 'f' after the value, e.g. (10)[white]{a}
## will be the column that take 10% of screen (so the real column's
## width will depend on actual screen size), whereas (10f)[white]{a}
## will take 10 terminal cells, no matter how wide the screen is.
##
## - color is optional (if you want the default one, type [])
##
## Note: You can give a column additional attributes by putting appropriate
## character after displayed tag character. Available attributes are:
##
## - r - column will be right aligned
## - E - if tag is empty, empty tag marker won't be displayed
##
## E.g. {lr} will give you right aligned column of lengths.
#song_columns_list_format = "(2f)[magenta]{} (55)[magenta]{t} (1f)[magenta]{} (45)[blue]{a} (2f)[blue]{} (5f)[yellow]{lr} (1f)[yellow]{}$b"
song_columns_list_format = "(2f)[magenta]{} (80)[magenta]{t} (1f)[magenta]{} (6f)[yellow]{lr} (1f)[yellow]{}$b"
#song_columns_list_format = "(2f)[red]{} (32f)[red]{t} (1f)[red]{} (29f)[blue]{a} (2f)[blue]{} (6f)[yellow]{l}$b"
## song_columns_list_format = "(2f)[white]{} (6f)[yellow]{l} (32f)[green]{t} (1f)[white]{} (30f)[blue]{ar} (2f)[white]{}$b"
## song_columns_list_format = "(1f)[white]{} (7f)[yellow]{l} (22f)[white]{t} (1f)[white]{} (30f)[blue]{ar} (1f)[white]{}$b"
## Modified color and format for selected songs.
selected_item_prefix = "$4"
selected_item_suffix = "$1"
## Modified color and format for the current song - may apply to several views.
now_playing_prefix = "$b$1"
now_playing_suffix = "$/b"
## View one - color for text and titles.
main_window_color = "white"
main_window_highlight_color = "white"
## Options for view two.
playlist_display_mode = "columns"
playlist_disable_highlight_delay = "1"
playlist_separate_albums = "no"
## Options for view three.
## The $5 below seems to provide color to folders in the browser.
browser_display_mode = "columns"
browser_playlist_prefix = "$8P:$5"
## View four - the display style.
search_engine_display_mode = "columns"
## View six - the display style.
playlist_editor_display_mode = "columns"
window_border_color = "yellow"
active_window_border = "red"
## Visualizer Options
visualizer_fifo_path = "/tmp/mpd.fifo"
visualizer_output_name = "My FIFO"
visualizer_in_stereo = "no"
visualizer_type = "wave"
visualizer_sample_multiplier = "1"
visualizer_sync_interval = "10"
# visualizer_look = STRING
visualizer_color = "blue"
## Statusbar has been DISABLED
## Statusbar - colors the "timer" and "Playing/Paused/Stopped" indicator.
## statusbar_color = "black"
## Statusbar - display format for the current song playing.
#song_status_format = "$5%a $1•$b $4%b$1 • $8%t $1$b"
#song_status_format = "$5%a $1• $4%b$1 • $8%t $1"
## Progressbar options.
## about the progressbar color -
## https://bbs.archlinux.org/viewtopic.php?pid=615179#p615179
#progressbar_color = "black"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment