/usr/local/CPAN/WWW-ImageSpool/WWW/ImageSpool/Directory.pm


#!perl

package WWW::ImageSpool::Directory;
use strict;
use warnings;

use Fcntl qw(S_IFREG S_IRUSR S_IWUSR);
use IO::Dir;
use URI;
use URI::Escape qw(uri_unescape);
use LWP::Simple qw(getstore is_success);
use HTTP::Status qw(status_message);
use Image::Size qw(imgsize);

return 1;

sub new
{
 my $class = shift;
 my $self = bless { @_ }, $class;
 my %tied;
 if(!$self->{dir})
 {
  warn "ImageSpool::Directory->new(): \"dir\" is required!\n";
  return;
 }
 elsif(!-d($self->{dir}))
 {
  warn "ImageSpool::Directory->new(): \"", $self->{dir}, "\" is not a directory.\n";
  return;
 }
 elsif((! -r($self->{dir}) || (! -x($self->{dir}))))
 {
  warn "ImageSpool::Directory->new(): Need read and execute permissions to \"", $self->{dir}, "\".\n";
  return;
 }
 
 $self->{max} ||= 104857600; # 100 megs
 $self->{minx} ||= 160;
 $self->{miny} ||= 120;
 $self->prune();
 return $self;
}

sub refresh
{
 my $self = shift;
 my %dir;
 tie %dir, "IO::Dir", $self->{dir};
 $self->{files} = {};
 $self->{total_size} = 0;
 my $rv = 0;

 while(my($file, $stat) = each(%dir))
 {
  if(($stat->mode & (S_IFREG | S_IRUSR | S_IWUSR)) == (S_IFREG | S_IRUSR | S_IWUSR))
  {
   $self->{files}->{$file} = $stat;
   $self->{total_size} += $stat->size;
   $rv++;
  }
  else
  {
   if($self->{verbose} > 1 && ($stat->mode & S_IFREG))
   {
    print "Bad file \"$file\" in directory.\n";
   }
  }
 }
 
 if($rv)
 {
  return $rv;
 }
 else
 {
  return;
 }
}

sub prune
{
 my $self = shift;
 $self->refresh();

 return -1
  if($self->{total_size} <= $self->{max});

 my $rv = 0;
 my(@keys) = sort { $self->{files}->{$b}->mtime <=> $self->{files}->{$a}->mtime } (keys(%{$self->{files}}));
 
 while(($self->{total_size} > $self->{max}) && (@keys))
 {
  my $file = shift(@keys);
  if(unlink($self->{dir} . "/$file"))
  {
   $self->{total_size} -= $self->{files}->{$file}->size;
   delete($self->{files}->{$file});
   $rv++;
  }
  else
  {
   warn "ImageSpool(", $self->{dir}, ")::Directory->prune(): unlink \"", $file, "\" failed: $!\n";
  }
 }
 
 if($rv)
 {
  return $rv;
 }
 else
 {
  return;
 }
}

sub uri_filename
{
 my($self, $uri) = @_;
 my $urio = URI->new($uri);
# my $fn = uri_unescape($urio->path());
 my $fn = $urio->path();
 $fn =~ s{^.*/}{}g;
# my $fileexpr = sprintf("%s+%s", $urio->host, $fn);
# if($fn =~ /\./)
# {
#  my $ffn = $fn;
#  $ffn =~ s{^(.*)\.(.*?)$}{$1-\%04d.$2}g;
#  $fileexpr = sprintf("%s+%s", $urio->host(), $ffn);
# }
# else
# {
#  $fileexpr = sprintf("%s+%s-%%04d", $urio->host(), $fn);
# }
 my $n = 0;
 my $file = sprintf("%s+%s", $urio->host, $fn);
 my $path = $self->{dir} . "/$file";

 if(-e($path))
 {
  if($self->{verbose} > 1)
  {
   print "\"$file\" already exists.\n";
  }
  return;
 }
 else
 {
  return $file;
 }

#  if(!-e($path))
# {
#  $n++;
#  $file = sprintf($fileexpr, $n);
#  $path = $self->{dir} . "/$file";
# }

}

sub fetch
{
 my($self, @urls) = @_;
 my $rv = 0;
 my $url;

 while($url = shift(@urls))
 {
  if(my $filename = $self->uri_filename($url))
  {
   my $pathname = $self->{dir} . "/$filename";
   my $code = getstore($url, $pathname);
    
   if(is_success($code))
   {
    my($x,$y) = (imgsize($pathname));
    if(defined($x) && defined($y) && ($x >= $self->{minx}) && ($y >= $self->{miny}))
    {
     if($self->{verbose} > 2)
     {
      print "$url -> $filename\n";
     }
     $rv++;
    }
    else
    {
     if($self->{verbose} > 3)
     {
      if(!defined($x) || !defined($y))
      {
       print "$url: Not an image.\n";
      }
      else
      {
       print "$url: Too small (${x}x${y}<", $self->{minx}, "x", $self->{miny}, ").\n";
      }
     }
     unlink($pathname);
    }
   }
   else
   {
    if($self->{verbose} > 2)
    {
     print "$url -> $filename failed: ", status_message($code), "\n";
    }
    unlink($pathname);
   }
  }
 }
 
 $self->prune();
 
 if($rv)
 {
  return $rv;
 }
 else
 {
  return;
 }
}