1# XMMSInfo.pm 2# this should be in a separate file... 3package XMMSInfo; 4 5# should write docs... 6 7use strict; 8use POSIX; 9use IO::File; 10use MP3::Info; 11use vars qw($PIPE $STATUS @ISA @EXPORT); 12 13@ISA = qw(Exporter); 14@EXPORT = qw($STATUS); 15 16$PIPE = '/tmp/xmms-info'; 17$STATUS = { 18 -1 => 'Fatal error', 19 0 => 'Not running', 20 1 => 'Stopped', 21 2 => 'Playing', 22 3 => 'Paused', 23}; 24 25sub new { 26 my($class) = shift; 27 28 my($self) = {}; 29 bless($self, $class); 30 31 $self->die("Try calling some methods first. \$obj->getInfo() is currently the only one available..."); 32 33 $self; 34} 35 36sub parseArgs { 37 my($self) = shift; 38 39 $#_ % 2 || return $self->die("Invalid number of arguments"); 40 for(my $i = 0; $i < $#_; $i += 2) { 41 my($k, $v) = ($_[$i], $_[$i + 1]); 42 $self->{Args}->{'.'.uc($k)} = $v; 43 } 44 45 1; 46} 47 48sub die { 49 my($self) = shift; 50 $self->setError(shift); 51 $self->setStatus(-1); 52 undef; 53} 54 55sub round { 56 my($d) = shift; 57 return $d unless $d =~ /^(\d+)\.(\d)/; 58 $d = $1; 59 $d++ if $2 >= 5; 60 $d; 61} 62 63sub getInfo { 64 my($self) = shift; 65 66 $self->parseArgs(@_) || return; 67 68 my($f) = $self->argPipe || $PIPE; 69 -r $f || return $self->setStatus(0); 70 my($fh) = IO::File->new($f) || 71 return $self->die("Can't open $f for reading: $!"); 72 73 while(<$fh>) { 74 chomp; 75 next unless /^(.+?): (.+)$/; 76 if($1 eq 'Status') { 77 $self->setStatus($2); 78 } else { 79 $self->{Info}->{'.'.uc($1)} = $2; 80 } 81 } 82 $fh->close; 83 84 return $self->die("Invalid input") unless $self->{Info}->{'.INFOPIPE PLUGIN VERSION'}; 85 86 my($t) = get_mp3tag($self->infoFile) || return $self->die("Can't read ID3 tag: ". $self->infoFile); 87 my($i) = get_mp3info($self->infoFile) || return $self->die("Can't read MP3 info: ". $self->infoFile); 88 89 my($k, $v); 90 while(($k, $v) = (each(%$t), each(%$i))) { 91 $self->{Info}->{'.'.$k} = $v; 92 } 93 94 $self->getStatus; 95} 96 97sub setStatus { 98 my($self, $s) = @_; 99 if($s =~ /^*\d+$/) { 100 $self->{Status}->{'.STATUS'} = $s; 101 $self->{Status}->{'.STATUSSTRING'} = $STATUS->{$s}; 102 } else { 103 foreach my $k (keys %$STATUS) { 104 my($v) = $STATUS->{$k}; 105 if($s eq $v) { 106 $self->{Status}->{'.STATUS'} = $k; 107 $self->{Status}->{'.STATUSSTRING'} = $s; 108 return $self->getStatus; 109 } 110 } 111 die "HELP"; 112 } 113 114 $self->getStatus; 115} 116 117sub setError { 118 shift->{Status}->{'.ERROR'} = pop; 119} 120 121sub getStatus { 122 shift->{Status}->{'.STATUS'}; 123} 124 125sub getStatusString { 126 shift->{Status}->{'.STATUSSTRING'}; 127} 128 129sub getError { 130 shift->{Status}->{'.ERROR'}; 131} 132 133sub isFatalError { 134 shift->getStatus == -1; 135} 136 137sub isXmmsRunning { 138 shift->getStatus > 0; 139} 140 141sub isPlaying { 142 shift->getStatus == 2; 143} 144 145sub isPaused { 146 shift->getStatus == 3; 147} 148 149sub isStopped { 150 shift->getStatus == 1; 151} 152 153sub argPipe { 154 shift->{Args}->{'.PIPE'}; 155} 156 157sub infoPlayListItems { 158 shift->{Info}->{'.TUNES IN PLAYLIST'}; 159} 160 161sub infoCurrentItemInPlaylist { 162 shift->{Info}->{'.CURRENTLY PLAYING'}; 163} 164 165sub infoTimeNow { 166 shift->{Info}->{'.POSITION'}; 167} 168 169sub infoTimeTotal { 170 shift->{Info}->{'.TIME'}; 171} 172 173sub infoSecondsTotal { 174 POSIX::ceil (shift->{Info}->{'.SECS'}); 175} 176 177sub infoSecondsNow { 178 my($self) = shift; 179 my($s) = $self->infoTimeNow; 180 die "HELP" unless $s =~ /^(\d+):(\d+)$/; 181 $1 * 60 + $2; 182} 183 184sub infoMinutesTotal { 185 shift->{Info}->{'.MM'}; 186} 187 188sub infoMinutesNow { 189 my($self) = shift; 190 my($s) = $self->infoTimeNow; 191 die "HELP" unless $s =~ /^(\d+):\d+$/; 192 $1; 193} 194 195sub infoSecondsTotalLeftover { 196 shift->{Info}->{'.SS'}; 197} 198 199sub infoSecondsNowLeftover { 200 my($self) = shift; 201 $self->infoSecondsNow - ($self->infoMinutesNow * 60); 202} 203 204sub infouSecTotal { 205 shift->{Info}->{'.USECTIME'}; 206} 207 208sub infouSecNow { 209 shift->{Info}->{'.USECPOSITION'}; 210} 211 212sub infoPercentage { 213 my($self) = shift; 214 my($p) = ($self->infouSecNow / $self->infouSecTotal) * 100; 215 round($p); 216} 217 218sub infoTitle { 219 shift->{Info}->{'.TITLE'}; 220} 221 222sub infoFile { 223 shift->{Info}->{'.FILE'}; 224} 225 226sub infoArtist { 227 shift->{Info}->{'.ARTIST'}; 228} 229 230sub infoAlbum { 231 shift->{Info}->{'.ALBUM'}; 232} 233 234sub infoYear { 235 shift->{Info}->{'.YEAR'}; 236} 237 238sub infoComment { 239 shift->{Info}->{'.COMMENT'}; 240} 241 242sub infoGenre { 243 shift->{Info}->{'.GENRE'}; 244} 245 246sub infoVersion { 247 shift->{Info}->{'.VERSION'}; 248} 249 250sub infoLayer { 251 shift->{Info}->{'.LAYER'}; 252} 253 254sub infoIsStereo { 255 shift->{Info}->{'.STEREO'}; 256} 257 258sub infoIsVbr { 259 shift->{Info}->{'.VBR'}; 260} 261 262sub infoBitrate { 263 shift->{Info}->{'.BITRATE'}; 264} 265 266sub infoFrequency { 267 shift->{Info}->{'.FREQUENCY'}; 268} 269 270sub infoSizeBytes { 271 shift->{Info}->{'.SIZE'}; 272} 273 274sub infoSize { 275 shift->infoSizeBytes; 276} 277 278sub infoSizeKiloBytes { 279 round(shift->infoSizeBytes / 1024); 280} 281 282sub infoSizeMegaBytes { 283 round(shift->infoSizeKiloBytes / 1024); 284} 285 286sub infoIsCopyright { 287 shift->{Info}->{'.COPYRIGHT'}; 288} 289 290sub infoIsPadded { 291 shift->{Info}->{'.PADDING'}; 292} 293 294sub infoFrames { 295 shift->{Info}->{'.FRAMES'}; 296} 297 298sub infoFramesLength { 299 shift->{Info}->{'.FRAMESLENGTH'}; 300} 301 302sub infoVbrScale { 303 shift->{Info}->{'.VBR_SCALE'}; 304} 305 3061; 307 308# EOF 309