#!/usr/bin/perl -w use strict; use lib qw( /export/www/hosts/dragor/lib /home/dragor/Perl/lib /home/dragor/www/lib ); use CGI; use Data::Dumper; use HTML::Template; use Time::ParseDate; use File::Basename; use Switch; use Album::Collection; use AlbumCache; use AlbumIndexCache; use POSIX qw( strftime ); use constant DATEFORMAT => '%e %b %Y'; use constant LISTALBUMLIMIT => '10'; use constant THUMBDIR => 'thumb'; use constant IMAGEDIR => 'resized'; # FIXME: command line/config file/ENV?? # FIXME: should take from command line/ENV use vars qw( $CONFIG $DEBUG $PATH ); $| = 1; my $PATH = (`hostname` =~ /^courgette/) ? '/home/dragor/www/var/album' :'/export/www/hosts/dragor/var/album'; my $CONFIG = { NUMCOLS => 5, TEMPLATE => { '0' => 'me/me.html', '1' => 'me/folio.html', '2' => 'me/dev.html', '3' => 'me/links.html', '4' => 'me/contact.html', '5' => 'me/gallery.html', '6' => 'me/modelling.html', }, TEMPLATEPATH => [ '/export/www/hosts/dragor/inc', '/home/dragor/www/inc', ], CATEGORYFILE => 'categories.txt', CATEGORY => [ ], }; sub main(); sub getParams(); sub showPage($$); sub readCategories(); sub getFiles($); sub retrieveCategoryData($); sub getViewImageUrl($$); sub getThumbImageUrl($$); sub showAlbum($$$); sub showImage($$$); sub streamImage($); sub listAlbums($;$); sub getPublicAlbums($$); sub getFullImageUrl($$); sub getViewAlbumUrl($); sub getPageAlbumsUrl($); sub getMostPopularThumbUrl($); sub makeLinkPath(;$); main(); sub main() { my $params = getParams(); my $uri = (defined $ENV{REQUEST_URI}) ? $ENV{REQUEST_URI} : undef; my $data = { }; readCategories(); my $p = (defined $params->{p}) ? $params->{p} : '0'; my $page = undef; my $templates = $CONFIG->{TEMPLATE}; if (defined $templates->{$p}) { $page = $templates->{$p}; } else { $page = $templates->{'0'}; } switch ($p) { case 1 { # get data for categories my $cats = $CONFIG->{CATEGORY}; my $count = 0; foreach my $cat (@{$cats}) { push @{$data->{category}}, { title => $cat->{title}, url => '?p=5&c='. $count++, }; } } case 5 { # show category my $c = (defined $params->{c}) ? $params->{c} : undef; if (defined $c) { my $cats = $CONFIG->{CATEGORY}; print STDERR Dumper($cats). "<===\n\n\n"; if (defined $cats->[$c]) { $data->{section} = $cats->[$c]->{title}; } else { $page = $templates->{'1'}; } } push @{$data->{path}}, { title => 'photography', url => '?p=1', }; $data->{photos} = retrieveCategoryData($c); } else { } } showPage($page,$data); } sub getParams() { my $cgi = new CGI(); # FIXME: tidy # my %params; my %params = $cgi->Vars(); # foreach my $item ($cgi->param()) { # $params{$item} = $cgi->param($item); # } return \%params; } sub showPage($$) { my($page,$data) = @_; my $tmpl = new HTML::Template( die_on_bad_params => 0, path => $CONFIG->{TEMPLATEPATH}, filename => $page, loop_context_vars => 1, ); foreach my $key (keys %{$data}) { $tmpl->param( $key => $data->{$key} ); } my $lastUpdated = `date +"%k:%m %e %b %Y"`; chomp $lastUpdated; $tmpl->param( lastupdated => $lastUpdated ); print "Content-type: text/html\n\n". $tmpl->output(); } sub readCategories() { open(FILE, $CONFIG->{CATEGORYFILE}) or return; while (my $line = ) { next if ($line =~ /$^/); chomp; $line =~ s/^\s+//; $line =~ s/\s+$//; next if ($line =~ /$^/); my @fields = split(/:/, $line); if (defined $fields[1]) { my $title = $fields[0]; my $dir = $fields[1]; my $files = getFiles("$dir/". THUMBDIR); push @{$CONFIG->{CATEGORY}}, { title => $title, dir => $dir, } if ($#{$files}+1 > 1); } } close FILE; } sub getFiles($) { my($dir) = @_; return undef if (!-d $dir); my @contents = (<$dir/*.*>); my @files; foreach my $file (@contents) { if (!-d $file && -f $file) { $file =~ s/^.*\/([^\/]+)$/$1/; push @files, $file; } } return \@files; } sub retrieveCategoryData($) { my($id) = @_; my $rows; my $dir = (defined $CONFIG->{CATEGORY}->[$id]) ? $CONFIG->{CATEGORY}->[$id]->{dir} : undef; return undef if (!defined $dir); my $files = getFiles("$dir/". THUMBDIR); my $row; foreach my $file (@{$files}) { push @{$row}, { url => getViewImageUrl($dir, $file), img => getThumbImageUrl($dir, $file), }; } return $row; } sub getViewImageUrl($$) { my($id,$file) = @_; return "$id/". IMAGEDIR ."/$file"; } sub getThumbImageUrl($$) { my($id,$file) = @_; return "$id/". THUMBDIR ."/$file"; } ####################################################################### sub showAlbum($$$) { my($files,$cache,$id) = @_; my $struct = [ ]; # Prepare structure for HTML::Template while ($#{$files} >= 0) { my $row = { }; for (my $x = 0; $x < $CONFIG->{NUMCOLS}; $x++) { my $filename = shift @{$files}; if (defined $filename) { # if we dont have record of it, then leave it alone # next if (!$cache->isFile($filename)); # FIXME: tidy push @{$row->{rowset}}, { image => getViewImageUrl($id,$filename), thumbnail => getThumbImageUrl($id,$filename), comment => $cache->getFileComment($filename), }; } else { push @{$row->{rowset}}, { empty => 1, image => '', thumbnail => '', comment => '', }; } } push @{$struct}, $row; } # Generate index.html using template my $tmpl = new HTML::Template( die_on_bad_params => 0, path => $CONFIG->{TEMPLATEPATH}, filename => $CONFIG->{TEMPLATE}->{album}, loop_context_vars => 1, ); $tmpl->param(albumlisturl => '?'); $tmpl->param(title => $cache->getTitle()); $tmpl->param(photos => $struct); $tmpl->param(date => strftime(DATEFORMAT, localtime($cache->getUnixTime()))); $tmpl->param(path => makeLinkPath() ); my $lastUpdated = `date +"%k:%m %e %b %Y"`; chomp $lastUpdated; $tmpl->param( lastupdated => $lastUpdated ); print "Content-type: text/html\n\n". $tmpl->output(); } sub showImage($$$) { my($filename,$cache,$id) = @_; my $struct = [ ]; # Generate index.html using template my $tmpl = new HTML::Template( die_on_bad_params => 0, path => $CONFIG->{TEMPLATEPATH}, filename => $CONFIG->{TEMPLATE}->{image}, ); # FIXME: tidy $tmpl->param(title => $cache->getTitle()); $tmpl->param(image => getFullImageUrl($id,$filename)); $tmpl->param(comment => $cache->getFileComment($filename)); $tmpl->param(date => strftime(DATEFORMAT, localtime($cache->getUnixTime()))); $tmpl->param(path => makeLinkPath( { name => $cache->getTitle(), link => getViewAlbumUrl($id) } ) ); # FOO my $file; $file = $cache->getNextFile($filename); if (defined $file) { $tmpl->param( next => getViewImageUrl($id,$file) ); } $file = $cache->getPreviousFile($filename); if (defined $file) { $tmpl->param( previous => getViewImageUrl($id,$file) ); } my $lastUpdated = `date +"%k:%m %e %b %Y"`; chomp $lastUpdated; $tmpl->param( lastupdated => $lastUpdated ); print "Content-type: text/html\n\n". $tmpl->output(); } sub streamImage($) { my($file) = @_; # FIXME: add accounting for viewing file # should check file is openable return if (!-f $file); open(FILE,$file) or die "Cannot open file"; print "Content-type: image/jpeg\n\n"; while () { print $_; } close FILE; } sub listAlbums($;$) { my($path,$page) = @_; # my($cache,$page) = @_; $page = 0 if (!defined $page); my $tmpl = new HTML::Template( die_on_bad_params => 0, path => $CONFIG->{TEMPLATEPATH}, filename => $CONFIG->{TEMPLATE}->{albums}, loop_context_vars => 1, ); my $lastUpdated = `date +"%k:%m %e %b %Y"`; chomp $lastUpdated; $tmpl->param( lastupdated => $lastUpdated ); # simply list them # my($albums,$prev,$next) = getUsersPublicAlbums($path,$page); my($albums,$prev,$next) = getPublicAlbums($path,$page); $tmpl->param( albums => $albums ); $tmpl->param( prevpage => (defined $prev) ? getPageAlbumsUrl($prev) : $prev ); $tmpl->param( nextpage => (defined $next) ? getPageAlbumsUrl($next) : $next ); # FIXME: calendar format $tmpl->param( monthview => getCalendarStruct($albums) ); $tmpl->param( monthname => strftime('%B', localtime() )); $tmpl->param(path => makeLinkPath() ); print "Content-type: text/html\n\n". $tmpl->output(); } sub orderByTime($) { my($albums) = @_; return undef if ($#{$albums}+1 == 0); my @ordered = sort { $b->{unixtime} <=> $a->{unixtime} } @{$albums}; return \@ordered; } sub getUsersPublicAlbums($) { my($path) = @_; my $albums = undef; #{ private => 0, title => '', directory => '', unixtime => '' } my $cmd = 'find '. $path . ' -name .public'; my @res = `$cmd`; foreach my $line (@res) { chomp $line; $line = dirname($line); my $dirname = dirname($line); my $basename = basename($line); my $ut; if ($basename =~ /^(\d+)_/) { $ut = $1; } my $album = new Album::Collection( path => $line ); $album->load(); push @{$albums}, { private => 0, title => $album->getTitle(), directory => $basename, unixtime => $ut }; } $albums = orderByTime($albums); return $albums; } sub getPublicAlbums($$) { my($path,$page) = @_; my($prev,$next) = (undef,undef); my $albums = getUsersPublicAlbums($path); foreach my $album (@{$albums}) { $album->{url} = getViewAlbumUrl($album->{directory}); $album->{date} = strftime(DATEFORMAT, localtime($album->{unixtime})); } if (LISTALBUMLIMIT) { my $tmp = undef; my $size = $#{$albums}; my $start = $page * LISTALBUMLIMIT; my $end = $start + LISTALBUMLIMIT; for (my $i=0; $i < $end; $i++ ) { push @{$tmp}, ${$albums}[$i] if ($i >= $start and defined $albums->[$i]); } $albums = $tmp; $next = $page + 1 if ($end < $size); $prev = $page - 1 if ($start - LISTALBUMLIMIT >= 0); } foreach my $album (@{$albums}) { $album->{thumburl} = getMostPopularThumbUrl($album); } # return $albums; # ($albums,$prev,$next); return ($albums,$prev,$next); } sub getCalendarStruct($) { my($albums) = @_; my @calLayout = `cal -m`; my $item = '([\d ]{2})[ ]{0,1}'; my @month = (); my $viewable; my $mon = strftime('%b', localtime()); my $yr = strftime('%Y', localtime()); foreach my $album (@{$albums}) { my $date = strftime(DATEFORMAT, localtime($album->{unixtime})); $date =~ s/^\s+//; $date =~ s/\s+$//; my($day,$month,$year) = split(/ /, $date); if ($mon eq $month && $yr eq $year) { $day = " $day" if ($day =~ /^\d$/); $viewable->{$day} = $album; } } for (my $i=0; $i < $#calLayout+1; $i++) { my @array; my $line = $calLayout[$i]; chomp $line; if ($i > 1) { if (@array = $line =~ /^(?:$item)(?:$item){0,1}(?:$item){0,1}(?:$item){0,1}(?:$item){0,1}(?:$item){0,1}(?:$item){0,1}$/) { my @week = (); for (my $i=0; $i<($#array+1); $i++) { if (defined $array[$i] and $array[$i] !~ /^\s+$/) { # we've got some albums for this date if (defined $viewable->{$array[$i]}) { my $id = $viewable->{$array[$i]}->{directory}; push @week, { day => $array[$i], url => getViewAlbumUrl($id), }; # nothing here to see.. move along } else { push @week, { day => $array[$i], }; } } else { push @week, { blank => 1, }; } } push @month, { week => \@week }; } } } return \@month; } sub getFullImageUrl($$) { my($id,$file) = @_; return "?id=$id&file=$file&full"; } sub getViewAlbumUrl($) { my($id) = @_; return "?id=$id"; } sub getPageAlbumsUrl($) { my($id) = @_; return "index.cgi?p=$id"; } sub getMostPopularThumbUrl($) { my($album) = @_; my $path = getFullAlbumPath($album->{directory}); my $cache = new AlbumCache( path => $PATH ); my $files = getFiles($path); if ($#{$files} >= 0) { my $popular = undef; foreach my $filename (@{$files}) { # FIXME: get most popular return getThumbImageUrl($album->{directory},$filename); # next if (!$cache->isFile($filename)); } } else { return undef; } } sub getFullAlbumPath($) { my($id) = @_; my $path = $PATH; if ($path =~ /\/$/) { return "${path}${id}"; } return "${path}/${id}"; } sub makeLinkPath(;$) { my($other) = @_; my $array; my $path = undef; my $dirname = dirname($ENV{REQUEST_URI}); foreach my $node (split('/', $dirname)) { next if ($node =~ /^$/); next if (!defined $node); $path .= "/$node"; push @{$array}, { name => $node, link => $path }; } unshift(@{$array},{ name => 'home', link => '/' }); if (defined $other) { if (ref($other) eq 'ARRAY') { print STDERR "foo bar\n"; } else { push @{$array}, $other; } } return $array; }