diff options
author | Rasmus Steinke <rasi@xssn.at> | 2017-08-05 20:37:53 +0200 |
---|---|---|
committer | Rasmus Steinke <rasi@xssn.at> | 2017-08-05 20:37:53 +0200 |
commit | ea6d94d4b64245d84b62bd8a2ec6b1085a05a427 (patch) | |
tree | 03520c1188b53772d8d506793d20a7e41efcfb87 /clerk.pl | |
parent | 5dc8f9a11136f3fe2f8680109b4312f3d41c6b68 (diff) | |
download | perl-app-clerk-ea6d94d4b64245d84b62bd8a2ec6b1085a05a427.tar.gz perl-app-clerk-ea6d94d4b64245d84b62bd8a2ec6b1085a05a427.tar.xz |
Add install script for arch linux
Diffstat (limited to 'clerk.pl')
-rwxr-xr-x | clerk.pl | 277 |
1 files changed, 0 insertions, 277 deletions
diff --git a/clerk.pl b/clerk.pl deleted file mode 100755 index 7b0f5e6..0000000 --- a/clerk.pl +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env perl - -binmode(STDOUT, ":utf8"); -use v5.10; -use warnings; -use strict; -use utf8; -use Config::Simple; -use DDP; -use Data::Dumper; -use Data::MessagePack; -use File::Basename; -use File::Path qw(make_path); -use File::Slurper 'read_binary'; -use File::stat; -use Getopt::Std; -use HTTP::Date; -use IO::Select; -use IPC::Run qw( timeout start ); -use List::Util qw(any); -use Net::MPD; -use autodie; - -$ENV{TMUX_TMPDIR}='/tmp/clerk/tmux'; -make_path($ENV{TMUX_TMPDIR}) unless(-d $ENV{TMUX_TMPDIR}); - -my $config_file = $ENV{'HOME'} . "/.config/clerk/clerk.conf"; - -if ($ENV{CLERK_CONF}) { - $config_file = $ENV{CLERK_CONF}; -} - -# read configuration file -my $cfg = new Config::Simple(filename=>"$config_file"); - -my $general_cfg = $cfg->param(-block=>"General"); -my $mpd_host = $general_cfg->{mpd_host}; -my $tmux_config = $general_cfg->{tmux_config}; -my $db_file = $general_cfg->{database}; -my $backend = $general_cfg->{backend}; -my $chunksize = $general_cfg->{chunksize}; - -my $columns_cfg = $cfg->param(-block=>"Columns"); -my $albumartist_l = $columns_cfg->{albumartist_l}; -my $album_l = $columns_cfg->{album_l}; -my $date_l = $columns_cfg->{date_l}; -my $title_l = $columns_cfg->{title_l}; -my $track_l = $columns_cfg->{track_l}; -my $artist_l = $columns_cfg->{artist_l}; - -if ($ENV{CLERK_BACKEND}) { - $backend = $ENV{CLERK_BACKEND}; -} - -# open connection to MPD -my $mpd = Net::MPD->connect($ENV{MPD_HOST} // $mpd_host // 'localhost'); - -sub main { - create_db(); - if ($backend eq "fzf") { - system('tmux', 'has-session', '-t', 'music'); - if ($? != -0) { - system('tmux', '-f', $tmux_config, 'new-session', '-s', 'music', '-n', 'albums', '-d', './clerk.pl', '-a'); - system('tmux', 'new-window', '-t', 'music', '-n', 'tracks', './clerk.pl', '-t'); - system('tmux', 'new-window', '-t', 'music', '-n', 'latest', './clerk.pl', '-l'); - system('tmux', 'new-window', '-t', 'music', '-n', 'playlists', './clerk.pl', '-p'); - system('tmux', 'new-window', '-t', 'music', '-n', 'queue', 'ncmpcpp'); - } - system('tmux', 'attach', '-t', 'music'); - } -# elsif ($backend eq "rofi") { - my %options=(); - getopts("talp", \%options); - - if (defined $options{t}) { - list_db_entries_for("Tracks"); - } elsif (defined $options{a}) { - list_db_entries_for("Albums"); - } elsif (defined $options{p}) { - list_playlists(); - } elsif (defined $options{l}) { - list_db_entries_for("Latest"); - } -} - - -sub create_db { - # Get database copy and save as messagepack file, if file is either missing - # or older than latest mpd database update. - # get number of songs to calculate number of searches needed to copy mpd database - my $mpd_stats = $mpd->stats(); - my $songcount = $mpd_stats->{songs}; - my $last_update = $mpd_stats->{db_update}; - - if (!-f "$db_file" || stat("$db_file")->mtime < $last_update) { - print STDERR "::: No cache found or cache file outdated\n"; - print STDERR "::: Chunksize set to $chunksize songs\n"; - my $times = int($songcount / $chunksize + 1); - print STDERR "::: Requesting $times chunks from MPD\n"; - my @db; - # since mpd will silently fail, if response is larger than command buffer, let's split the search. - my $chunk_size = $chunksize; - for (my $i=0;$i<=$songcount;$i+=$chunk_size) { - my $endnumber = $i+$chunk_size; - my @temp_db = $mpd->search('filename', '', 'window', "$i:$endnumber"); - push @db, @temp_db; - } - - # only save relevant tags to keep messagepack file small - # note: maybe use a proper database instead? See list_album function. - my @filtered = map { $_->{mtime} = str2time($_->{'Last-Modified'}); +{$_->%{qw/Album Artist Date AlbumArtist Title Track uri mtime/}} } @db; - pack_msgpack(\@filtered); - } -} - -sub backend_call { - my ($in, $fields) = @_; - my $input; - my $out; - $fields //= "1,2,3"; - my %backends = ( - fzf => [ qw(fzf - --reverse - --no-sort - -m - -e - -i - -d - \t - --tabstop=4 - +s - --ansi), - "--with-nth=$fields" - ], - rofi => [ - 'rofi', - '-width', - '1300', - '-dmenu', - '-multi-select', - '-i', - '-p', - '> ' - ] - ); - my $handle = start $backends{$backend} // die('backend not found'), \$input, \$out; - $input = join "", (@{$in}); - finish $handle or die "No selection"; - return $out; -} - -sub pack_msgpack { - my ($filtered_db) = @_; - my $msg = Data::MessagePack->pack($filtered_db); - my $filename = "$db_file"; - open(my $out, '>:raw', $filename) or die "Could not open file '$filename' $!"; - print $out $msg; - close $out; -} - -sub unpack_msgpack { - my $mp = Data::MessagePack->new->utf8(); - my $msgpack = read_binary("$db_file"); - my $rdb = $mp->unpack($msgpack); - return $rdb; -} - -sub do_action { - my ($in, $context) = @_; - my @action_items = ("Add\n", "Replace\n"); - my $action = backend_call(\@action_items); - if ($action eq "Replace\n") { - $mpd->clear(); - } - my $input; - if ($context eq "playlist") { - chomp $in; - $mpd->load("$in"); - } elsif ($context eq "tracks") { - foreach my $line (split /\n/, $in) { - my $uri = (split /[\t\n]/, $line)[-1]; - $mpd->add($uri); - } - } - if ($action eq "Replace\n") { - $mpd->play(); - } - my @queue_cmd = ('tmux', 'findw', '-t', 'music', 'queue'); - system(@queue_cmd); -} - -sub list_playlists { - my @playlists = $mpd->list_playlists(); - my $output = formated_playlists(\@playlists); - - for (;;) { - my $out = backend_call($output); - do_action($out, "playlist"); - } -} - -sub formated_albums { - my ($rdb, $sorted) = @_; - - my %uniq_albums; - for my $i (@$rdb) { - my $newkey = join "", $i->@{qw/AlbumArtist Album Date/}; - if (!exists $uniq_albums{$newkey}) { - my $dir = (dirname($i->{uri}) =~ s/\/CD.*$//r); - $uniq_albums{$newkey} = {$i->%{qw/AlbumArtist Album Date mtime/}, Dir => $dir}; - } else { - if ($uniq_albums{$newkey}->{'mtime'} < $i->{'mtime'}) { - $uniq_albums{$newkey}->{'mtime'} = $i->{'mtime'} - } - } - } - - my @albums; - my $fmtstr = join "", map {"%-${_}.${_}s\t"} ($albumartist_l, $date_l, $album_l); - - my @skeys; - if ($sorted) { - @skeys = sort { $uniq_albums{$b}->{mtime} <=> $uniq_albums{$a}->{mtime} } keys %uniq_albums; - } else { - @skeys = sort keys %uniq_albums; - } - - for my $k (@skeys) { - my @vals = (map { "$_" // "Unknown" } $uniq_albums{$k}->@{qw/AlbumArtist Date Album/}), $uniq_albums{$k}->{Dir}; - my $strval = sprintf $fmtstr."%s\n", @vals; - push @albums, $strvals; - - } - - return \@albums; -} - -sub formated_tracks { - my ($rdb) = @_; - my $fmtstr = join "", map {"%-${_}.${_}s\t"} ($track_l, $title_l, $artist_l, $album_l); - my @tracks = map { - sprintf $fmtstr."%-s\n", (map { "$_" // "unknown" } $_->@{qw/Track Title Artist Album/}), $_->{uri}; -# sprintf $fmtstr."%-s\n", $_->@{qw/Track Title Artist Album uri/} - } @{$rdb}; - - return \@tracks; -} - -sub formated_playlists { - my ($rdb) = @_; - my @playlists = map { - sprintf "%s\n", $_->{playlist} - } @{$rdb}; - - return \@playlists; -} - -sub list_db_entries_for { - my ($kind) = @_; - die "Wrong kind" unless any {; $_ eq $kind} qw/Albums Latest Tracks/; - - my $rdb = unpack_msgpack(); - my %fields = (Albums=> "1,2,3", Latest => "1,2,3", Tracks => "1,2,3,4"); - my %formater = ( - Albums => sub {formated_albums(@_, 0)}, - Latest => sub {formated_albums(@_, 1)}, - Tracks => \&formated_tracks - ); - - my $output = $formater{$kind}->($rdb); - for (;;) { - my $out = backend_call($output, $fields{$kind}); - do_action($out, "tracks"); - } -} - -main; |