#!/usr/bin/perl # $Id: xmmsinfo.pl,v 1.1.1.1 2002/03/24 21:00:55 tj Exp $ # # Copyright (0) 2002 Tuomas Jormola # # $Log: xmmsinfo.pl,v $ # Revision 1.1.1.1 2002/03/24 21:00:55 tj # Initial import. # # # TODO: # * Configurable string to print (%t = title, %a = artist ...) use strict; use Irssi; use XMMSInfo; use vars qw($VERSION %IRSSI); # global variables $VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /^.+?(\d+)\.(\d+)/); %IRSSI = ( authors => 'Tuomas Jormola', contact => 'tjormola@cc.hut.fi', name => 'XMMSInfo', description => '/xmmsinfo to tell what you\'re currently playing', license => 'GPLv2', url => 'http://shakti.tky.hut.fi/stuff.xml#irssi', changed => '2002-0324T22:42+0300', ); if(runningUnderIrssi()) { Irssi::settings_add_str('misc', 'xmms_info_pipe', '/tmp/xmms-info'); Irssi::command_bind('xmmsinfo', 'commandXmmsInfo'); Irssi::print("$IRSSI{name} $VERSION loaded, /xmmsinfo -help"); } else { (my $s = $0) =~ s/.*\///; $ARGV[0] || die("Usage: $s \n"); commandXmmsInfo(); } # command handler sub commandXmmsInfo { my($args, $server, $target) = @_; if(lc($args) eq "-help") { Irssi::print("XMMSInfo $VERSION by $IRSSI{authors} <$IRSSI{contact}>"); Irssi::print(""); Irssi::print("Displays what your XMMS is playing using information"); Irssi::print("provided by the XMMS InfoPipe plugin"); Irssi::print(""); Irssi::print("Define filename of the pipe where from the InfoPipe output is read"); Irssi::print("Default is /tmp/xmms-info"); return; } my($p) = runningUnderIrssi() ? Irssi::settings_get_str('xmms_info_pipe') : $ARGV[0]; my($i) = XMMSInfo->new; $i->getInfo(pipe => $p); my($o) = "XMMS: " . $i->getStatusString; if($i->isFatalError) { $o .= ": " . $i->getError; } elsif($i->isXmmsRunning) { my($t) = $i->infoTitle || "(unknown song)"; my($a) = $i->infoArtist || "(unknown artist)"; my($g) = lc($i->infoGenre) || "(unknown genre)"; my($pos) = $i->infoMinutesNow . "m" . $i->infoSecondsNowLeftover."s"; my($tot) = $i->infoMinutesTotal . "m" . $i->infoSecondsTotalLeftover."s"; my($per) = $i->infoPercentage; my($b) = $i->infoBitrate . "kbps"; my($f) = $i->infoFrequency . "kHz"; $o .= " $g tune $t by $a." if ($i->isPlaying || $i->isPaused); $o .= " Played $pos of total $tot ($per%)." if $i->isPlaying; $o .= " [$b/$f]" if ($i->isPlaying || $i->isPaused); } if(!runningUnderIrssi()) { print "$o\n"; } elsif($i->isFatalError || !$server || !$server->{connected} || (!$args && !$target)) { Irssi::print($o); } else { my($t) = $args || $target->{name}; $server->command("msg $t $o"); } } sub runningUnderIrssi { $0 eq '-e'; } # END OF SCRIPT # XMMSInfo.pm # this should be in a separate file... package XMMSInfo; # should write docs... use strict; use POSIX; use IO::File; use MP3::Info; use vars qw($PIPE $STATUS @ISA @EXPORT); @ISA = qw(Exporter); @EXPORT = qw($STATUS); $PIPE = '/tmp/xmms-info'; $STATUS = { -1 => 'Fatal error', 0 => 'Not running', 1 => 'Stopped', 2 => 'Playing', 3 => 'Paused', }; sub new { my($class) = shift; my($self) = {}; bless($self, $class); $self->die("Try calling some methods first. \$obj->getInfo() is currently the only one available..."); $self; } sub parseArgs { my($self) = shift; $#_ % 2 || return $self->die("Invalid number of arguments"); for(my $i = 0; $i < $#_; $i += 2) { my($k, $v) = ($_[$i], $_[$i + 1]); $self->{Args}->{'.'.uc($k)} = $v; } 1; } sub die { my($self) = shift; $self->setError(shift); $self->setStatus(-1); undef; } sub round { my($d) = shift; return $d unless $d =~ /^(\d+)\.(\d)/; $d = $1; $d++ if $2 >= 5; $d; } sub getInfo { my($self) = shift; $self->parseArgs(@_) || return; my($f) = $self->argPipe || $PIPE; -r $f || return $self->setStatus(0); my($fh) = IO::File->new($f) || return $self->die("Can't open $f for reading: $!"); while(<$fh>) { chomp; next unless /^(.+?): (.+)$/; if($1 eq 'Status') { $self->setStatus($2); } else { $self->{Info}->{'.'.uc($1)} = $2; } } $fh->close; return $self->die("Invalid input") unless $self->{Info}->{'.INFOPIPE PLUGIN VERSION'}; my($t) = get_mp3tag($self->infoFile) || return $self->die("Can't read ID3 tag: ". $self->infoFile); my($i) = get_mp3info($self->infoFile) || return $self->die("Can't read MP3 info: ". $self->infoFile); my($k, $v); while(($k, $v) = (each(%$t), each(%$i))) { $self->{Info}->{'.'.$k} = $v; } $self->getStatus; } sub setStatus { my($self, $s) = @_; if($s =~ /^*\d+$/) { $self->{Status}->{'.STATUS'} = $s; $self->{Status}->{'.STATUSSTRING'} = $STATUS->{$s}; } else { foreach my $k (keys %$STATUS) { my($v) = $STATUS->{$k}; if($s eq $v) { $self->{Status}->{'.STATUS'} = $k; $self->{Status}->{'.STATUSSTRING'} = $s; return $self->getStatus; } } die "HELP"; } $self->getStatus; } sub setError { shift->{Status}->{'.ERROR'} = pop; } sub getStatus { shift->{Status}->{'.STATUS'}; } sub getStatusString { shift->{Status}->{'.STATUSSTRING'}; } sub getError { shift->{Status}->{'.ERROR'}; } sub isFatalError { shift->getStatus == -1; } sub isXmmsRunning { shift->getStatus > 0; } sub isPlaying { shift->getStatus == 2; } sub isPaused { shift->getStatus == 3; } sub isStopped { shift->getStatus == 1; } sub argPipe { shift->{Args}->{'.PIPE'}; } sub infoPlayListItems { shift->{Info}->{'.TUNES IN PLAYLIST'}; } sub infoCurrentItemInPlaylist { shift->{Info}->{'.CURRENTLY PLAYING'}; } sub infoTimeNow { shift->{Info}->{'.POSITION'}; } sub infoTimeTotal { shift->{Info}->{'.TIME'}; } sub infoSecondsTotal { POSIX::ceil (shift->{Info}->{'.SECS'}); } sub infoSecondsNow { my($self) = shift; my($s) = $self->infoTimeNow; die "HELP" unless $s =~ /^(\d+):(\d+)$/; $1 * 60 + $2; } sub infoMinutesTotal { shift->{Info}->{'.MM'}; } sub infoMinutesNow { my($self) = shift; my($s) = $self->infoTimeNow; die "HELP" unless $s =~ /^(\d+):\d+$/; $1; } sub infoSecondsTotalLeftover { shift->{Info}->{'.SS'}; } sub infoSecondsNowLeftover { my($self) = shift; $self->infoSecondsNow - ($self->infoMinutesNow * 60); } sub infouSecTotal { shift->{Info}->{'.USECTIME'}; } sub infouSecNow { shift->{Info}->{'.USECPOSITION'}; } sub infoPercentage { my($self) = shift; my($p) = ($self->infouSecNow / $self->infouSecTotal) * 100; round($p); } sub infoTitle { shift->{Info}->{'.TITLE'}; } sub infoFile { shift->{Info}->{'.FILE'}; } sub infoArtist { shift->{Info}->{'.ARTIST'}; } sub infoAlbum { shift->{Info}->{'.ALBUM'}; } sub infoYear { shift->{Info}->{'.YEAR'}; } sub infoComment { shift->{Info}->{'.COMMENT'}; } sub infoGenre { shift->{Info}->{'.GENRE'}; } sub infoVersion { shift->{Info}->{'.VERSION'}; } sub infoLayer { shift->{Info}->{'.LAYER'}; } sub infoIsStereo { shift->{Info}->{'.STEREO'}; } sub infoIsVbr { shift->{Info}->{'.VBR'}; } sub infoBitrate { shift->{Info}->{'.BITRATE'}; } sub infoFrequency { shift->{Info}->{'.FREQUENCY'}; } sub infoSizeBytes { shift->{Info}->{'.SIZE'}; } sub infoSize { shift->infoSizeBytes; } sub infoSizeKiloBytes { round(shift->infoSizeBytes / 1024); } sub infoSizeMegaBytes { round(shift->infoSizeKiloBytes / 1024); } sub infoIsCopyright { shift->{Info}->{'.COPYRIGHT'}; } sub infoIsPadded { shift->{Info}->{'.PADDING'}; } sub infoFrames { shift->{Info}->{'.FRAMES'}; } sub infoFramesLength { shift->{Info}->{'.FRAMESLENGTH'}; } sub infoVbrScale { shift->{Info}->{'.VBR_SCALE'}; } 1; # EOF