File Coverage

blib/lib/POE/Component/IRC/Plugin/RTorrentStatus.pm
Criterion Covered Total %
statement 50 115 43.4
branch 5 48 10.4
condition 1 3 33.3
subroutine 16 25 64.0
pod 1 4 25.0
total 73 195 37.4


line stmt bran cond sub pod time code
1             package POE::Component::IRC::Plugin::RTorrentStatus;
2             BEGIN {
3 2     2   386439 $POE::Component::IRC::Plugin::RTorrentStatus::AUTHORITY = 'cpan:HINRIK';
4             }
5             BEGIN {
6 2     2   33 $POE::Component::IRC::Plugin::RTorrentStatus::VERSION = '0.17';
7             }
8              
9 2     2   19 use strict;
  2         5  
  2         108  
10 2     2   12 use warnings FATAL => 'all';
  2         12  
  2         97  
11 2     2   9 use Carp qw(croak);
  2         4  
  2         243  
12 2     2   2572 use DateTime;
  2         316388  
  2         81  
13 2     2   2095 use DateTime::Format::Human::Duration;
  2         5186  
  2         75  
14 2     2   15 use File::Glob ':glob';
  2         5  
  2         610  
15 2     2   15 use File::Spec::Functions 'rel2abs';
  2         5  
  2         115  
16 2     2   4348 use Format::Human::Bytes;
  2         1072  
  2         63  
17 2     2   869 use POE::Component::IRC::Plugin qw(PCI_EAT_NONE);
  2         390  
  2         252  
18 2     2   1784 use POE::Component::IRC::Common qw(NORMAL DARK_GREEN DARK_BLUE ORANGE TEAL BROWN PURPLE MAGENTA);
  2         24438  
  2         268  
19 2     2   2016 use POE::Component::IRC::Plugin::FollowTail;
  2         206471  
  2         2895  
20              
21             sub new {
22 1     1 1 7171 my ($package, %args) = @_;
23 1         5 my $self = bless \%args, $package;
24              
25 1 50       10 if (!defined $self->{Torrent_log}) {
26 0         0 croak __PACKAGE__ . ": No torrent log file defined";
27             }
28              
29 1 50 33     16 if (ref $self->{Channels} ne 'ARRAY' || !$self->{Channels}) {
30 0         0 croak __PACKAGE__ . ': No channels defined';
31             }
32              
33 1         46 $self->{Torrent_log} = rel2abs(bsd_glob($self->{Torrent_log}));
34 1 50       40 if (!-e $self->{Torrent_log}) {
35 0 0       0 open my $foo, '>', $self->{Torrent_log}
36             or die "Can't create $self->{Torrent_log}: $!\n";
37 0         0 close $foo;
38             }
39              
40             # defaults
41 1 50       6 $self->{Method} = 'notice' if !defined $self->{Method};
42 1 50       4 $self->{Color} = 1 if !defined $self->{Color};
43              
44 1         4 return $self;
45             }
46              
47             sub PCI_register {
48 1     1 0 503 my ($self, $irc) = @_;
49              
50 1         13 $irc->plugin_add(TorrentTail => POE::Component::IRC::Plugin::FollowTail->new(
51             filename => $self->{Torrent_log},
52             ));
53              
54 1         1033 $irc->plugin_register($self, 'SERVER', qw(tail_input));
55 1         34 return 1;
56             }
57              
58             sub PCI_unregister {
59 1     1 0 2396 my ($self, $irc) = @_;
60 1         4 return 1;
61             }
62              
63             sub S_tail_input {
64 0     0 0   my ($self, $irc) = splice @_, 0, 2;
65 0           my $filename = ${ $_[0] };
  0            
66 0           my $input = ${ $_[1] };
  0            
67 0 0         return if $filename ne $self->{Torrent_log};
68              
69 0           my ($date, $action, @args) = split /\t/, $input;
70 0           my $method = "_${action}_torrent";
71 0           my $msg = $self->$method(@args);
72              
73 0 0         if (defined $msg) {
74 0           for my $chan (@{ $self->{Channels} }) {
  0            
75 0           $irc->yield($self->{Method}, $chan, $msg);
76             }
77             }
78              
79 0           return PCI_EAT_NONE;
80             }
81              
82             sub _inserted_new_torrent {
83 0     0     my ($self, $name, $user, $bytes) = @_;
84              
85 0           my $size = _fmt_bytes($bytes);
86 0 0         my $msg = $self->{Color}
87             ? DARK_BLUE.'Enqueued: '.ORANGE.$name.NORMAL." ($size, by $user)"
88             : "Enqueued: $name ($size, by $user)";
89              
90 0           return $msg;
91             }
92              
93             sub _hash_queued_torrent {
94 0     0     my ($self, $name, $enqueued, $finished, $bytes) = @_;
95              
96 0           my $duration = _duration($enqueued, $finished);
97 0           my $secs = $finished - $enqueued;
98 0 0         $secs = 1 if $secs == 0; # avoid division by zero
99              
100 0           my $bps = $bytes / $secs;
101 0           my $size = _fmt_bytes($bps);
102 0           my $rate = "$size/s";
103              
104 0 0         return $self->{Color}
105             ? DARK_GREEN.'Finished: '.ORANGE.$name.NORMAL." in $duration ($rate); Checking hash..."
106             : "Finished: $name in $duration ($rate). Checking hash...";
107             }
108              
109             sub _finished_torrent {
110 0     0     my ($self, $name, $hash_started, $hash_done, $rars) = @_;
111              
112 0           my $duration = _duration($hash_started, $hash_done);
113              
114 0 0         my $msg = $self->{Color}
115             ? PURPLE.'Hashed: '.ORANGE.$name.NORMAL." in $duration"
116             : "Hashed: $name in $duration";
117              
118 0 0         if ($rars > 0) {
119 0 0         my $archives = $rars > 1 ? 'archives' : 'archive';
120 0           $msg .= "; $rars $archives to unrar...";
121             }
122              
123 0           return $msg;
124             }
125              
126             sub _unrar_torrent {
127 0     0     my ($self, $name, $start, $finish, $rars, $file) = @_;
128              
129 0           my $duration = _duration($start, $finish);
130 0 0         my $archives = $rars > 1 ? 'archives' : 'archive';
131 0 0         my $info = defined $file ? $file : "$rars $archives";
132              
133 0 0         my $msg = $self->{Color}
134             ? MAGENTA.'Unrared: '.ORANGE.$name.NORMAL." in $duration ($info)"
135             : "Unrared: $name in $duration ($info)";
136              
137 0           return $msg;
138             }
139              
140             sub _unrar_failed_torrent {
141 0     0     my ($self, $name, $error) = @_;
142 0 0         $error = '' if !defined $error;
143              
144 0 0         return $self->{Color}
145             ? BROWN.'Unrar failed: '.ORANGE.$name.NORMAL.": $error"
146             : "Unrared failed: $name: $error";
147             }
148              
149             sub _erased_torrent {
150 0     0     my ($self, $name, $size_bytes, $down_bytes, $up_bytes, $ratio) = @_;
151 0           my $up = _fmt_bytes($up_bytes);
152 0 0         $ratio /= 1000 if $ratio != 0;
153 0           $ratio = sprintf '%.2f', $ratio;
154              
155 0           my $msg;
156 0 0         if ($size_bytes == $down_bytes) {
157 0 0         $msg = $self->{Color}
158             ? TEAL.'Removed: '.ORANGE.$name.NORMAL." (ratio: $ratio, uploaded: $up)"
159             : "Removed: $name (ratio: $ratio, uploaded: $up)";
160             }
161             else {
162 0           my $done = sprintf '%.f%%', $down_bytes / $size_bytes * 100;
163 0 0         $msg = $self->{Color}
164             ? BROWN.'Aborted: '.ORANGE.$name.NORMAL." ($done done, ratio: $ratio, uploaded: $up)"
165             : "Aborted: $name ($done done, ratio: $ratio, uploaded: $up)";
166             }
167              
168 0           return $msg;
169             }
170              
171             sub _duration {
172 0     0     my ($start, $finish) = @_;
173              
174 0           my $enq_date = DateTime->from_epoch(epoch => $start);
175 0           my $fin_date = DateTime->from_epoch(epoch => $finish);
176 0           my $dur_obj = $fin_date - $enq_date;
177 0           my $span = DateTime::Format::Human::Duration->new();
178 0           return $span->format_duration($dur_obj);
179             }
180              
181             sub _fmt_bytes {
182 0     0     my ($bytes) = @_;
183 0 0         return '0B' if $bytes == 0;
184 0           return Format::Human::Bytes::base2($_[0]) }
185              
186             1;
187              
188             =encoding utf8
189              
190             =head1 NAME
191              
192             POE::Component::IRC::Plugin::RTorrentStatus - A PoCo-IRC plugin which prints RTorrent status messages to IRC
193              
194             =head1 SYNOPSIS
195              
196             To quickly get an IRC bot with this plugin up and running, you can use
197             L:
198              
199             $ pocoirc -s irc.perl.org -j '#bots' -a 'RTorrentStatus{ "Channels": ["#bots"], "Torrent_log": "/tmp/torrentlog" }'
200              
201             Or use it in your code:
202              
203             use POE::Component::IRC::Plugin::RTorrentStatus;
204              
205             # post status updates to #foobar
206             $irc->plugin_add(Torrent => POE::Component::IRC::Plugin::RTorrentStatus->new(
207             Torrent_log => '/tmp/torrentlog',
208             Channels => ['#foobar'],
209             ));
210              
211             =head1 DESCRIPTION
212              
213             POE::Component::IRC::Plugin::RTorrentStatus is a
214             L plugin. It reads a log file
215             generated by the included L program and posts messages to
216             IRC describing the events. See the documentation for L
217             on how to set it up with RTorrent.
218              
219             -MyBot:#channel- Enqueued: ubuntu-9.10-desktop-i386.iso (700MB, by hinrik)
220             -MyBot:#channel- Aborted: ubuntu-9.10-desktop-i386.iso (10% done, ratio: 0.05, up: 35MB)
221             -MyBot:#channel- Enqueued: ubuntu-9.10-desktop-amd64.iso (700MB, by hinrik)
222             -MyBot:#channel- Finished: ubuntu-9.10-desktop-amd64.iso in 20 minutes (597kB/s); Checking hash...
223             -MyBot:#channel- Hashed: ubuntu-9.10-desktop-amd64.iso in 10 seconds
224             -MyBot:#channel- Removed: ubuntu-9.10-desktop-amd64.iso (ratio: 2.00, up: 1400MB)
225              
226             And if you've got unraring enabled:
227              
228             -MyBot:#channel- Enqueued: foobar (100MB, by hinrik)
229             -MyBot:#channel- Finished: foobar in 10 minutes (171kB/s); Checking hash...
230             -MyBot:#channel- Hashed: foobar in 5 seconds; 1 archive to unrar
231             -MyBot:#channel- Unrared: foobar in 5 seconds (1 archive)
232             -MyBot:#channel- Removed: foobar (ratio: 2.00, uploaded: 200MB)
233              
234             =head1 METHODS
235              
236             =head2 C
237              
238             Takes the following arguments:
239              
240             B<'Torrent_log'>, the path to the torrent log file generated by the
241             L program. This argument is required.
242              
243             B<'Channels'>, an array reference of channels to post messages to. You must
244             specify at least one channel.
245              
246             B<'Color'>, whether to print colorful status messages. True by default.
247              
248             B<'Method'>, how you want messages to be delivered. Valid options are
249             'notice' (the default) and 'privmsg'.
250              
251             Returns a plugin object suitable for feeding to
252             L's C method.
253              
254             =head1 AUTHOR
255              
256             Hinrik Ern SigurEsson, hinrik.sig@gmail.com
257              
258             =head1 LICENSE AND COPYRIGHT
259              
260             Copyright 2010 Hinrik Ern SigurEsson
261              
262             This program is free software, you can redistribute it and/or modify
263             it under the same terms as Perl itself.
264              
265             =cut