import psist v0.2
[psist.git] / Psist.pm
1 # $HeadURL: http://svn.mzet.net/psist/Psist.pm $
2 # $Author: zet $
3 # $Date: 2006-08-24 15:39:25 +0200 (Thu, 24 Aug 2006) $
4 # $Revision: 12 $
5
6 package Psist;
7
8 use strict;
9 use Time::Local;
10
11 sub new
12 {
13   my $type = shift;
14   my %args = @_;
15   my $self = {
16     profile => $args{profile},
17     outfile => $args{outfile},
18     silent  => $args{silent},
19     verbose => 1,
20     version => $args{version},
21     history => 30,
22
23     start   => time,
24     now     => 0,
25
26     jids    => {},
27     nicks   => {},
28     snicks  => [],
29     lines   => 0,
30     days    => [],
31     hours   => []
32   };
33   my ($mday,$mon,$year) = (localtime(time))[3,4,5];
34   $self->{now} = timelocal(0, 0, 0, $mday, $mon, $year);
35   
36   my $i = 0;
37   my $j = 0;
38   while($i < $self->{history}) {
39     while($j < 4) {
40       $self->{days}[$i][$j] = 0;
41       $j++;
42     }
43     $j = 0;
44     $i++;
45   }
46
47   $i = 0;
48   while($i < 24) {
49     $self->{hours}[$i] = 0;
50     $i++;
51   }
52
53   bless($self, $type);
54   return $self;
55 }
56
57 sub run
58 {
59   my $self = shift;
60   my $time;
61   
62   print "psist v$self->{version} - PSI Statistics Generator\n\n" unless $self->{silent};
63
64   $self->load_config();
65   $self->parse_history();
66   $self->gen_html();
67
68   $time = time - $self->{start};
69   print "\n",'DONE. Generated in ',sprintf('%02d:%02d:%02d', $time / 3600, ($time % 3600) / 60, ($time % 3600) % 60),"\n";
70 }
71
72 sub load_config
73 {
74   my $self = shift;
75   my $row;
76   my $i;
77   my $nick;
78   
79   print "loading contacts...\n" unless $self->{silent};
80   open(CONFIGXML, $self->{profile} . "/config.xml");
81   while($row = <CONFIGXML>) {
82     if($row =~ /<item.*name="(.*?)".*jid="(.*?)".*>/) {
83       if(length($1) == 0) {
84         $nick = $2;
85       }
86       else {
87         $nick = $1;
88       }
89       $self->{jids}{$2} = $nick;
90       $self->{nicks}{$nick}{lines} = 0;
91       $self->{nicks}{$nick}{linest}[0] = 0;
92       $self->{nicks}{$nick}{linest}[1] = 0;
93       $self->{nicks}{$nick}{linest}[2] = 0;
94       $self->{nicks}{$nick}{linest}[3] = 0;
95       $self->{nicks}{$nick}{to} = 0;
96       $self->{nicks}{$nick}{sfrom} = 0;
97       $self->{nicks}{$nick}{sto} = 0;
98       $self->{nicks}{$nick}{last} = 0;
99     }
100   }
101   close(CONFIGXML);
102 }
103
104 sub parse_history
105 {
106   my $self = shift;
107   my ($jidf,$nick);
108   my ($row,$ts,$tsfull,$dago,$dp);
109
110   print "parsing history data...\n" unless $self->{silent};
111   foreach my $jid (keys %{$self->{jids}}) {
112     $nick = $self->{jids}{$jid};
113     $jidf = $jid;
114     $jidf =~ s/@/_at_/;
115     $jidf =~ s/\+/%2b/;
116     open(HISTFIL, $self->{profile} . '/history/' . $jidf . '.history') or next;
117     print '  >> "',$jid,'" (',$nick,')',"\n" if $self->{verbose};
118     while($row = <HISTFIL>) {
119
120       # row processing
121       if($row =~ /^\|(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\|1\|([a-z]+)\|.{4}\|(.*)/) {
122         $ts = timelocal(0, 0, 0, $3, $2 - 1, $1);
123         $tsfull = timelocal($6, $5, $4, $3, $2 - 1, $1);
124         $dp = ($4 < 6) ? 0 : (($4 < 12) ? 1 : (($4 < 18) ? 2 : 3));
125         $dago = int(($self->{now} - $ts) / 86400);
126         if($dago < $self->{history}) {
127           $self->{days}[$dago][$dp]++;
128         }
129         $self->{hours}[$4]++;
130         $self->{lines}++;
131
132         $self->{nicks}{$nick}{lines}++;
133         $self->{nicks}{$nick}{linest}[$dp]++;
134         if($7 eq 'to') {
135           $self->{nicks}{$nick}{to}++;
136         }
137         if($self->{nicks}{$nick}{last} < $tsfull) {
138           $self->{nicks}{$nick}{last} = $tsfull;
139         }
140       }
141     }
142     close(HISTFIL);
143   }
144   
145   print "sorting contacts by lines count...\n" unless $self->{silent};
146   @{$self->{snicks}} = sort { $self->{nicks}{$b}{lines} <=> $self->{nicks}{$a}{lines} } keys %{$self->{nicks}};
147 }
148
149 sub gen_html
150 {
151   my $self = shift;
152
153   my ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time));
154   my ($max_d,$max_h,$sum_h,$i,$sum);
155   my ($time,$nick);
156   
157   $mon++;
158   $year += 1900;
159
160   # max for days
161   $max_d = 1;
162   $i = $self->{history};
163   while($i > 0) {
164     $i--;
165     $sum = $self->{days}[$i][0] + $self->{days}[$i][1] + $self->{days}[$i][2] + $self->{days}[$i][3];
166     $max_d = ($sum > $max_d) ? $sum : $max_d;
167   }
168
169   # max and sum for hours
170   $max_h = 0;
171   $sum_h = 0;
172   $i = 0;
173   while($i < 24) {
174     $sum_h += $self->{hours}[$i];
175     $max_h = ($self->{hours}[$i] > $max_h) ? $self->{hours}[$i] : $max_h;
176     $i++;
177   }
178   $max_h = ($max_h == 0) ? 1 : $max_h;
179   $sum_h = ($sum_h == 0) ? 1 : $sum_h;
180   
181
182   print "generating HTML file...\n" unless $self->{silent};
183   open(HTMLFIL, '> '.$self->{outfile});
184   print HTMLFIL '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',"\n";
185   print HTMLFIL '<html>',"\n";
186   print HTMLFIL '<head>',"\n";
187   print HTMLFIL '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',"\n";
188   print HTMLFIL '<title>',$self->translate('PSI Statistics'),'</title>',"\n";
189   print HTMLFIL '<link type="text/css" rel="stylesheet" href="style.css" media="screen,projection" />',"\n";
190   print HTMLFIL '</head>',"\n";
191   print HTMLFIL '<body>',"\n";
192   print HTMLFIL '<div align="center">',"\n";
193   print HTMLFIL '<span class="title">',$self->translate('PSI Statistics'),'</span><br /><br />',"\n";
194   print HTMLFIL $self->translate('Statistics have been generated at '),'"',sprintf('%02d.%02d.%d %02d:%02d:%02d', $mday, $mon, $year, $hour, $min, $sec),'"<br /><br /><br />',"\n";
195
196   # daily activity
197   print HTMLFIL '<div class="headtext">',$self->translate('Daily activity'),'</div>',"\n";
198   print HTMLFIL '<table border="0"><tr>',"\n";
199   $i = $self->{history};
200   while($i > 0) {
201     $i--;
202     $sum = $self->{days}[$i][0] + $self->{days}[$i][1] + $self->{days}[$i][2] + $self->{days}[$i][3];
203     print HTMLFIL '<td align="center" valign="bottom" class="asmall">',$sum,'<br />',"\n";
204     print HTMLFIL '<img src="./red-v.png" width="15" height="',int($self->{days}[$i][3] * 100 / $max_d),'" alt="',$sum,'" title="',$sum,'" /><br />',"\n";
205     print HTMLFIL '<img src="./yellow-v.png" width="15" height="',int($self->{days}[$i][2] * 100 / $max_d),'" alt="',$sum,'" title="',$sum,'" /><br />',"\n";
206     print HTMLFIL '<img src="./green-v.png" width="15" height="',int($self->{days}[$i][1] * 100 / $max_d),'" alt="',$sum,'" title="',$sum,'" /><br />',"\n";
207     print HTMLFIL '<img src="./blue-v.png" width="15" height="',int($self->{days}[$i][0] * 100 / $max_d),'" alt="',$sum,'" title="',$sum,'" /><br />',"\n";
208     print HTMLFIL '</td>',"\n";
209   }
210   print HTMLFIL '</tr><tr>',"\n";
211   $i = $self->{history};
212   while($i > 0) {
213     $i--;
214     print HTMLFIL '<td class="rankc10center" align="center">',$i,'</td>',"\n";
215   }
216   print HTMLFIL '</tr></table>',"\n";
217   print HTMLFIL '<table align="center" border="0" width="520"><tr>',"\n";
218   print HTMLFIL '<td align="center" class="asmall"><img src="./blue-h.png" width="40" height="15" align="middle" alt="0-5" /> = 0-5</td>',"\n";
219   print HTMLFIL '<td align="center" class="asmall"><img src="./green-h.png" width="40" height="15" align="middle" alt="6-11" /> = 6-11</td>',"\n";
220   print HTMLFIL '<td align="center" class="asmall"><img src="./yellow-h.png" width="40" height="15" align="middle" alt="12-17" /> = 12-17</td>',"\n";
221   print HTMLFIL '<td align="center" class="asmall"><img src="./red-h.png" width="40" height="15" align="middle" alt="18-23" /> = 18-23</td>',"\n";
222   print HTMLFIL '</tr></table><br />',"\n";
223   
224   # most active times
225   print HTMLFIL '<div class="headtext">',$self->translate('Most active times'),'</div>',"\n";
226   print HTMLFIL '<table border="0"><tr>',"\n";
227   $i = 0;
228   while($i < 24) {
229     print HTMLFIL '<td align="center" valign="bottom" class="asmall">',sprintf('%.1f', $self->{hours}[$i] * 100 / $sum_h),'%<br /><img src="./',(($i < 6) ? 'blue' : (($i < 12) ? 'green' : (($i < 18) ? 'yellow' : 'red' ))),'-v.png" width="15" height="',int($self->{hours}[$i] * 100 / $max_h),'" alt="',$self->{hours}[$i],'" title="',$self->{hours}[$i],'"/></td>',"\n";
230     $i++;
231   }
232   print HTMLFIL '</tr><tr>',"\n";
233   $i = 0;
234   while($i < 24) {
235     print HTMLFIL '<td class="',(($self->{hours}[$i] == $max_h) ? 'hi' : ''),'rankc10center" align="center">',$i,'</td>',"\n";
236     $i++;
237   }
238   print HTMLFIL '</tr></table><br />',"\n";
239
240   # contacts
241   print HTMLFIL '<div class="headtext">',$self->translate('Contacts'),'</div>',"\n";
242   print HTMLFIL '<table border="0" width="794">',"\n";
243   print HTMLFIL '<tr><td>&nbsp;</td><td class="tdtop" width="25%">',$self->translate('Nick'),'</td><td class="tdtop" style="text-align: right" width="12%">',$self->translate('Posts'),'</td><td class="tdtop" width="65">',$self->translate('Time'),'</td><td class="tdtop" width="10%">',$self->translate('To'),'</td><td class="tdtop" width="10%">',$self->translate('From'),'</td><td class="tdtop" width="25%">',$self->translate('Last message'),'</td></tr>',"\n";
244   $i = 0;
245   foreach $nick (@{$self->{snicks}}) {
246     $i++;
247     if($self->{nicks}{$nick}{lines} > 0) {
248       $sum = $self->{nicks}{$nick}{linest}[0] + $self->{nicks}{$nick}{linest}[1] + $self->{nicks}{$nick}{linest}[2] + $self->{nicks}{$nick}{linest}[3];
249       $sum = ($sum > 0) ? $sum : 1;
250       my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($self->{nicks}{$nick}{last}));
251       $year += 1900;
252       $mon++;
253       print HTMLFIL '<tr><td class="',(($i == 1) ? 'hi' : ''),'rankc">',$i,'</td><td style="background-color: #babadc">{nickname}</td><td style="background-color: #babadc; text-align: right">',$self->{nicks}{$nick}{lines},'</td><td style="background-color: #babadc; text-align: center">';
254       print HTMLFIL '<img src="./blue-h.png" border="0" width="',int($self->{nicks}{$nick}{linest}[0] * 60 / $sum),'" height="15" alt="',$self->{nicks}{$nick}{linest}[0],'" title="',$self->{nicks}{$nick}{linest}[0],'" />';
255       print HTMLFIL '<img src="./green-h.png" border="0" width="',int($self->{nicks}{$nick}{linest}[1] * 60 / $sum),'" height="15" alt="',$self->{nicks}{$nick}{linest}[1],'" title="',$self->{nicks}{$nick}{linest}[1],'" />';
256       print HTMLFIL '<img src="./yellow-h.png" border="0" width="',int($self->{nicks}{$nick}{linest}[2] * 60 / $sum),'" height="15" alt="',$self->{nicks}{$nick}{linest}[2],'" title="',$self->{nicks}{$nick}{linest}[2],'" />';
257       print HTMLFIL '<img src="./red-h.png" border="0" width="',int($self->{nicks}{$nick}{linest}[3] * 60 / $sum),'" height="15" alt="',$self->{nicks}{$nick}{linest}[3],'" title="',$self->{nicks}{$nick}{linest}[3],'" />';
258       print HTMLFIL '</td><td style="background-color: #babadc">',sprintf('%.2f', $self->{nicks}{$nick}{to} * 100 / $self->{nicks}{$nick}{lines}),'%</td><td style="background-color: #babadc">',sprintf('%.2f', 100 - $self->{nicks}{$nick}{to} * 100 / $self->{nicks}{$nick}{lines}),'%</td>';
259       print HTMLFIL '<td style="background-color: #babadc">',sprintf('%02d.%02d.%d %02d:%02d:%02d', $mday, $mon, $year, $hour, $min, $sec),'</td>';
260       print HTMLFIL '</tr>',"\n";
261     }
262   }
263   print HTMLFIL '</table><br />',"\n";
264   
265   # footer
266   print HTMLFIL $self->translate('Total number of lines'),': ',$self->{lines},'<br /><br />',"\n";
267   print HTMLFIL '<span class="small">',"\n";
268   print HTMLFIL $self->translate('Stats generated by'),' <a href="http://www.mzet.net/psist" class="background">psist</a> v',$self->{version},'<br />',"\n";
269   print HTMLFIL 'psist by <a href="http://www.mzet.net/" class="background">Michal Zbortek (zet)</a><br />',"\n";
270   $time = time - $self->{start};
271   print HTMLFIL $self->translate('Stats generated in'),' ',sprintf('%02d:%02d:%02d', $time / 3600, ($time % 3600) / 60, ($time % 3600) % 60),"\n";
272   print HTMLFIL '</span>',"\n";
273   
274   print HTMLFIL '</div>',"\n";
275   print HTMLFIL '</body>',"\n";
276   print HTMLFIL '</html>',"\n";
277   close(HTMLFIL);
278 }
279
280 sub translate
281 {
282   my $self = shift;
283   my $message = shift;
284   
285   return $message;
286 }
287
288 return 1;
289