#!/usr/bin/perl -w # This will try to be as compact as possible, all in 1 script preferably # so that it can be used anywhere. It will read whatever it's called.cfg # for the config options # Lines beginning with % are keys and directories where pics are stored # Lines beginning with $ are option/value pairs use strict; use vars qw( %ENV $VERSION ); use DB_File; use CGI qw( :standard :cgi-lib ); $VERSION = "0.24"; my %opts = ( perpage => 9, convert => '/usr/X11R6/bin/convert', thumbsize => '150x150', cache => undef, suffixes => '(jpeg|jpg|bmp|png|gif|JPG|BMP|PNG|GIF)', columns => 3, maxwidth => 1024, maxheight => 768, maxpercent => 150 ); my %ablums = ( _all => [] ); # Read/parse config my $basename = $ENV{ SCRIPT_FILENAME }; $basename =~ s#^.*/##; open( IN, "$basename.cfg" ); my( $line, $key, $val ); while( $line = ) { chomp( $line ); $line =~ s/#.*//; # Handle comments $line =~ s/^\s*//; $line =~ s/\s*$//; if( $line =~ /^\%/ ) { # Dir pair $line =~ s/^.//; ( $key, $val ) = $line =~ /^\s*(\S+)\s+(\S.*)/; $val =~ s/\s*$//; my $dval = $val; $val =~ s/\W/_/g; # Cleanse URL key $ablums{ $val } = $key; push( @{ $ablums{ _all } }, { name => $val, dir => $key, dispname => $dval } ); }elsif( $line =~ /^\$/ ) { # Option $line =~ s/^.//; ( $key, $val ) = $line =~ /^\s*(\S+)\s+(\S.*)/; $val =~ s/\s*$//; $opts{ $key } = $val; } } close( IN ); my $suffixes = $opts{ suffixes }; my $action = param( 'ACTION' ) || ""; # -w my $page = param( 'PAGE' ) || 1; my %comments; tie %comments, 'DB_File', "$opts{cache}/.comments"; # Do based on action: # IMAGE Do some image magick, makes a jpg # LIST Show a list of the images in folder FOLDER # DETAIL Show detail about a particular picture number IMAGE in folder FOLDER # If no action, then list available ablums # # IMAGE is the relative pathname # FOLDER is a single keyword, the folder name. It must match exactly a # key defined in the ablums config file my $image = param( 'IMAGE' ) || ""; # the || quiets up -w # Cleanse image name $image =~ s|\.\.||g; $image =~ s|^/+||g; # Grab other params my $folder = param( 'FOLDER' ) || ""; my $subfolder = param( 'SUBFOLDER' ) || ""; my $image_path = $ablums{ $folder } . "/$image"; my( $header, $footer ); # Makes it easier to add new actions this way my %ACTIONS = ( IMAGE => \&action_IMAGE, LIST => \&action_LIST, DETAIL => \&action_DETAIL, CACHEBUILD => \&action_CACHEBUILD, LOGIN => \&action_LOGIN ); if( $ACTIONS{ $action } ) { &{ $ACTIONS{ $action } }() || action_DEFAULT(); }else{ action_DEFAULT(); } # Action handlers sub action_IMAGE { print "Content-type: image/jpg\n\n"; my @opts; my( $size, $w, $h, $percent ); if ( param( 'SIZE' ) ) { if( param( 'SIZE' ) =~ /x/ ) { # WxH ( $w, $h ) = split( 'x', param( 'SIZE' ) ); $w = $opts{ maxwidth } if $w > $opts{ maxwidth }; $h = $opts{ maxheight } if $h > $opts{ maxheight }; $size = "${w}x$h"; }else{ $percent = param( 'SIZE' ); $percent =~ s/[^0-9]//g; $percent = $opts{ maxpercent } if $percent > $opts{ maxpercent }; $size = $percent . '%'; } # Handle fixed size 100%, 800x600, etc $size = $opts{ fixedsize } if $opts{ fixedsize }; # Override all for thumbs $size = $opts{ thumbsize } if param( 'SIZE' ) eq 'thumb'; push( @opts, '-geometry', $size ); } if( $opts{ cache } ) { # Handle caching local *IMG; open( IMG, cache_build( $image_path, @opts ) ); print $_ while ; close( IMG ); }else{ # Always real-time convert system( $opts{ convert }, $image_path, @opts, 'jpg:-' ); } return( 1 ); } sub action_LIST { text_html_header(); tmpl_header(); local *DIR; my %vars = Vars(); my $cnt = 0; my $dir = $ablums{$folder} ? "$ablums{$folder}/$image" : '/&'; if( -d $dir ) { opendir( DIR, $dir ); my $f; my $col_width = int( 100 / $opts{ columns } ); my @files; print ''; while( $f = readdir( DIR ) ) { if ( $f !~ /^\./ ) { if ( $f =~ /\.$suffixes$/i ) { push( @files, $f ); #Files to show } elsif ( -d "$dir/$f" ) { # Subdirs printf( '', $col_width, $basename, $folder, $image ? "$image/$f" : $f, $f ); $cnt++; if ( ( $cnt % $opts{ columns } ) == 0 ) { print ""; $cnt = 0; } } } } print '
%s
'; my $start = ( $page - 1 ) * $opts{ perpage }; my $end = $start + $opts{ perpage }; $end = $end > scalar( @files ) ? scalar( @files ) : $end; $end--; # 0 based $cnt = 0; # Handle saving comments my $imkey; for( keys( %vars ) ) { if( /^\!/ ) { $imkey = $_; $imkey =~ s/^.//; # print STDERR "$imkey=$vars{$_}\n"; # print STDERR "$folder/$imkey\n"; $comments{ "$folder/$imkey" } = $vars{ $_ }; $comments{ "$folder/$imkey" } =~ s/\r//g; } } printf( '
', $folder, $page ) if isadmin(); print ''; for( $start .. $end ) { $f = $files[ $_ ]; printf( '"; $cnt++; if( ( $cnt % $opts{ columns } ) == 0 ) { print ""; $cnt = 0; } } print '
', $col_width, $basename, $folder, "$image/$f" ); printf( '
', $basename, $folder, "$image/$f" ); print "$f

"; # print STDERR "$folder/$f\n"; printf( ' ', $f, $comments{ "$folder/$f" } || "" ) if isadmin(); print $comments{ "$folder/$f" } || "" unless isadmin(); print "
'; print '
' if isadmin(); closedir( DIR ); # Print a page listing my $total = scalar( @files ); # Adding 0.9 lets us do an int and causes a round up my $pages = int( ( $total / $opts{ perpage } ) + 0.9 ); for( 1 .. $pages ) { if( $page == $_ ) { print "[$_] "; }else{ printf( '[%s] ', $basename, $folder, $_, $image, $_ ); } } }else{ print "Error, unable to find '$folder'"; } printf( '
Back to main
', $basename ); tmpl_footer(); return( 1 ); } sub action_DETAIL { text_html_header(); tmpl_header(); my $curr_scale = sprintf( '%01d', param( 'SCALE' ) || '100' ); printf( '
', $basename, $folder, $image, $curr_scale ); print $image; print "
" . $comments{ "$folder/$image" } . "
"; # Make a little scale thingy if( ! $opts{ fixedsize } ) { printf( '
'; } printf( 'To folder %s', $basename, $folder, $folder ); tmpl_footer(); return( 1 ); } sub action_DEFAULT { # List folders text_html_header(); tmpl_header(); print ""; tmpl_footer(); return( 1 ); } sub action_CACHEBUILD { # Build the cache up with common options return() unless $opts{ cache }; return() unless isadmin(); text_html_header(); tmpl_header(); for( keys( %ablums ) ) { recurse_buildcache( $ablums{ $_ } ); } tmpl_footer(); } sub action_LOGIN { if( ! $opts{ password } ) { action_DEFAULT(); return(); } if( param( 'password' ) ) { # Handle logging in my $cookie = cookie( -name => 'ablum.password', -value => param( 'password' ) ); # print "Content-type: text/plain\n\n\n\n"; print redirect( -cookie => $cookie, -uri => $basename ); }else{ text_html_header(); tmpl_header(); print '
'; tmpl_footer(); } return( 1 ); } # Misc subs sub text_html_header { print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "\n"; # Prep the template if( -f "$basename.tmpl" ) { local *IN; open( IN, "$basename.tmpl" ); { undef $/; my $tmpl = ; ( $header, $footer ) = split( /&:&/, $tmpl ); } close( IN ); } } sub tmpl_header { print $header; print qq{ Rebuild Cache - Logout
} if isadmin(); } sub tmpl_footer { print $footer; } sub cache_build { # Makes a single item in the cache, takes the full path # Returns the full path to the cache file my $inputfile = shift(); my @opts = @_; my $cachename = $inputfile; return( undef ) unless -f $inputfile; return( undef ) unless $inputfile =~ /\.$suffixes$/i; return( undef ) if $inputfile =~ /^\./; $cachename .= join( '-', @opts ); $cachename =~ s|[^A-Za-z0-9.-]|_|g; $cachename = "$opts{cache}/$cachename"; # print STDERR "Handling cache: $inputfile - $cachename\n"; if( -f $cachename ) { # Do cache thing my $filetime = ( stat( $inputfile ) )[ 9 ]; my $cachetime = ( stat( $cachename ) )[ 9 ]; # print STDERR "Cache hit: $filetime/$cachetime\n"; if( $filetime > $cachetime ) { # Modified, make copy # print STDERR "Cache modified, regen\n"; system( $opts{ convert }, $inputfile, @opts, "jpg:$cachename" ); } }else{ # Make a cachecopy # print STDERR "Cache miss\n"; system( $opts{ convert }, $inputfile, @opts, "jpg:$cachename" ); } return( $cachename ); } sub isadmin { return( 0 ) unless $opts{ password }; return( cookie( 'ablum.password' ) eq $opts{ password } ); } sub recurse_buildcache { my $dir = shift; my $f; local *DIR; opendir( DIR, $dir ); while ( $f = readdir( DIR ) ) { if ( $f !~ /^\./ ) { if ( -f "$dir/$f" ) { print "Bulding cache for: $dir/$f
"; #cache_build( "$dir/$f" ); cache_build( "$dir/$f", '-geometry', $opts{ thumbsize } ); } elsif ( -d "$dir/$f" ) { recurse_buildcache( "$dir/$f" ); } } } closedir( DIR ); }