File Coverage

blib/lib/App/MPDSync.pm
Criterion Covered Total %
statement 18 65 27.6
branch 0 10 0.0
condition n/a
subroutine 6 13 46.1
pod 0 6 0.0
total 24 94 25.5


line stmt bran cond sub pod time code
1             package App::MPDSync;
2              
3 1     1   29225 use strict;
  1         2  
  1         43  
4 1     1   5 use warnings;
  1         2  
  1         29  
5 1     1   32 use 5.010;
  1         8  
  1         57  
6              
7             our $VERSION = '0.02';
8              
9 1     1   1267 use Getopt::Long;
  1         18390  
  1         6  
10 1     1   949 use Net::MPD;
  1         58522  
  1         39  
11 1     1   1079 use Proc::Daemon;
  1         12167  
  1         724  
12              
13             sub new {
14 0     0 0   my ($class, @options) = @_;
15              
16 0           my $self = bless {
17             from => '',
18             to => 'localhost',
19             daemon => 1,
20             verbose => 0,
21             source => undef,
22             @options,
23             }, $class;
24             }
25              
26             sub parse_options {
27 0     0 0   my ($self, @args) = @_;
28              
29 0           local @ARGV = @args;
30              
31 0           Getopt::Long::Configure('bundling');
32 0           Getopt::Long::GetOptions(
33             'D|daemon!' => \$self->{daemon},
34             'V|version' => \&show_version,
35             'f|from=s' => \$self->{from},
36             't|to=s' => \$self->{to},
37             'h|help' => \&show_help,
38             'v|verbose' => \$self->{verbose},
39             );
40             }
41              
42             sub vprint {
43 0     0 0   my ($self, @message) = @_;
44 0 0         say @message if $self->{verbose};
45             }
46              
47             sub show_help {
48 0     0 0   print <<'HELP';
49             Usage: mpd-sync [options] --from source [--to dest]
50              
51             Options:
52             -f,--from Source MPD instance (required)
53             -t,--to Destination MPD instance (default localhost)
54             -v,--verbose Be noisy
55             --no-daemon Do not fork to background
56             -V,--version Show version and exit
57             -h,--help Show this help and exit
58             HELP
59              
60 0           exit;
61             }
62              
63             sub show_version {
64 0     0 0   say "mpd-sync (App::MPDSync) version $VERSION";
65 0           exit;
66             }
67              
68             sub execute {
69 0     0 0   my ($self) = @_;
70              
71             local @SIG{qw{ INT TERM HUP }} = sub {
72 0     0     exit 0;
73 0           };
74              
75 0 0         unless ($self->{from}) {
76 0           say STDERR 'Source MPD not provided';
77 0           show_help;
78             }
79              
80 0           my $source = Net::MPD->connect($self->{from});
81              
82 0 0         if ($self->{daemon}) {
83 0           $self->vprint('Forking to background');
84 0           Proc::Daemon::Init;
85             }
86              
87             {
88 0           $self->vprint('Syncrhonizing initial playlist');
  0            
89              
90 0           my $dest = Net::MPD->connect($self->{to});
91 0           $dest->stop;
92 0           $dest->clear;
93 0           $dest->add($_->{uri}) for $source->playlist_info;
94              
95 0           $source->update_status;
96 0           $dest->play;
97 0           $dest->seek($source->song, int $source->elapsed);
98             }
99              
100 0           while (1) {
101 0           $source->idle('playlist');
102              
103 0           $self->vprint('Source playlist changed');
104              
105 0           $source->update_status;
106 0           my @playlist = $source->playlist_info;
107              
108 0           my $dest = Net::MPD->connect($self->{to});
109 0           foreach my $item ($dest->playlist_info) {
110 0 0         if (@playlist) {
111 0 0         if ($item->{uri} eq $playlist[0]{uri}) {
112 0           shift @playlist;
113             } else {
114 0           $self->vprint("Removing $item->{uri} from destination playlist");
115 0           $dest->delete_id($item->{Id});
116             }
117             } else {
118 0           $self->vprint('Out of entries from source!');
119             }
120             }
121              
122 0           foreach (@playlist) {
123 0           $self->vprint("Adding $_->{uri} to destination");
124 0           $dest->add($_->{uri});
125             }
126             }
127             }
128              
129             1;
130             __END__