| Chess | Tools | Data | Blog | Poetry | Why? | Wiki | Admin | Logout |

Download


#!/usr/bin/perl 
# $Revision: 1.114 $
# Luis Mondesi  <lemsx1@gmail.com>
#
# HELP: $0 --help
# DESC: pixdir2html - makes thumbnails and custom html files for pictures
# REQUIRED: ImageMagick's Perl module and a dialog
#           program or Term::Pogressbar Perl module
use strict;
$|++;    # disable buffer (autoflush)

my $DEBUG = 0;

# standard Perl modules
use Getopt::Long;
Getopt::Long::Configure('bundling');
use POSIX qw/ getcwd /;
use File::Spec::Functions qw/ splitpath curdir updir catfile catdir abs2rel /;
use File::Copy;
use File::Find;        # find();
use File::Basename;    # basename() && dirname()
use FileHandle;        # for progressbar

# non-standard modules:
my $USE_CONVERT = 0;
eval "use Image::Magick";
if ($@)
{
    print STDERR "
ERROR: Could not load the Image::Magick module.
"
      . "       To install this module use:
"
      . "       Use: perl -e shell -MCPAN to install it.
"
      . "       On Debian just: apt-get install perlmagic 

"
      . "       FALLING BACK to 'convert'

";
    print STDERR "$@
";
    if (-x "/usr/bin/convert" || -x "/usr/local/bin/convert")
    {
        $USE_CONVERT = 1;
    }
    else
    {
        print STDERR "
ERROR: 'convert' was not found in /usr/bin or 
"
          . "/usr/local/bin. 
 Exiting...

";
        exit 1;
    }
}

# Get Nautilus current working directory, if under Natilus:
my $nautilus_root = "";
if (exists $ENV{'NAUTILUS_SCRIPT_CURRENT_URI'}
    && $ENV{'NAUTILUS_SCRIPT_CURRENT_URI'} =~ m#^file:/+#)
{

    # convert special HTML char to plain text characters
    ($nautilus_root = $ENV{'NAUTILUS_SCRIPT_CURRENT_URI'}) =~
      s#%([0-9A-Fa-f]{2})#chr(hex($1))#ge;

    # remove file:// from full Nautilus URI: file:///tmp -> /tmp
    $nautilus_root =~ s#^file://##g;
    warn
      "The path from env variable NAUTILUS_SCRIPT_CURRENT_URI is not in the current directory
"
      if ($nautilus_root ne getcwd());
}

my $ROOT_DIRECTORY = (-d $nautilus_root) ? $nautilus_root : getcwd();
chdir($ROOT_DIRECTORY);

my $LOG         = "$ROOT_DIRECTORY/pixdir2html.log";
my $CONFIG_FILE = ".pixdir2htmlrc";
my $THUMBNAIL    = "t";    # individual thumnails files will be placed here
my $HTMLDIR      = "h";    # individual HTML files
my $THUMB_PREFIX = "t";    # no need to ever change this... this starts

# the name for all thumbnail images
# list directories that should be skipped here
# separated by |
my $EXCEPTION_LIST = "CVS|RCS";

# regex of files we want to include
my $EXT_INCL_EXPR = "\.(jpg|png|jpeg|gif)";

# dont worry if you don't have a log rotation facility...
# just leave it as is
my $SAVELOG       = "/usr/bin/savelog";
my $SKIP_DIR_FILE = ".nopixdir2htmlrc";   # filename to flag directories to skip

#**************************************************************#
###        Nothing below this line should be changed.        ###
#**************************************************************#
my @pixdir      = ();    # for menu
my @pixfiles    = ();    # for all picture files
my %thumbfiles  = ();    # hash of arrays for all thumbnails
                         # created by mkthumb
my %config      = ();    # hash of hashes to hold config per directories
my $TOTAL_LINKS = 0;
my $FORCE       = 0;
my $NOMENU      = 0;
my $MENUONLY    = 0;
my $THUMBSONLY  = 0;
my $CUT_DIRS    = 0;
my $NOINDEX     = 0;
my $HELP        = 0;
my $PVERSION    = 0;

# How big are the thumbnails?
my $PERCENT = "20%";

# How many TDs per table in e/a index.EXT?
my $TD = 4;

# How many TDs per menu table?
my $menu_td = 10;

# How big are strings in menus?
my $STR_LIMIT = 32;

# progressbar stuff here:
my $GAUGE                   = new FileHandle;
my $MODE                    = "text";
my $DIA                     = "";
my $use_console_progressbar = 0;             # a simple flag
my $MENU_TYPE               = "";            # default menu-type is "classic".
                                             # put 'menu-type: modern' in config
                                             # or pass --menu-type="modern" from
                                             # command line to change

my $EXT           = "html";    # default extension for generated HTML files
my $FILE_NAME     = "index";
my $MENU_NAME     = "menu";
my $NEW_MENU_NAME = "";

# others
my $menu_str = "";
my $revision = "Pixdir2html v1.8
 Luis Mondesi <lemsx1\@hotmail.com>
";

# get options
GetOptions(

    # flags
    'v|version'     => \$PVERSION,
    'n|no-menu'     => \$NOMENU,
    'f|force'       => \$FORCE,
    'h|help'        => \$HELP,
    'M|menu-only'   => \$MENUONLY,
    't|thumbs-only' => \$THUMBSONLY,
    'N|no-index'    => \$NOINDEX,

    # strings
    'E|extension=s' => \$EXT,
    'D|directory=s' => \$ROOT_DIRECTORY,
    'F|front-end=s' => \$DIA,
    'm|menu-type=s' => \$MENU_TYPE,
    'menu-name=s'   => \$NEW_MENU_NAME,

    # numbers
    'menu-td=i'      => \$menu_td,
    'l|menu-links=i' => \$menu_td,
    'td=i'           => \$TD,
    'str-limit=i'    => \$STR_LIMIT,
    'c|cut-dirs=i'   => \$CUT_DIRS
);
if ($HELP)
{
    use Pod::Text;
    my $parser = Pod::Text->new(sentence => 0, width => 78);
    $parser->parse_from_file(File::Spec->catfile("$0"), \*STDOUT);
    exit 0;
}

if ($PVERSION) { print STDOUT ($revision, "
"); exit 0; }

# Xdialog is a better implementation than gdialog.
# Zenity is better than all so far...
my @xbinaries = ("zenity", "Xdialog", "xdialog", "gdialog", "kdialog");
my @binaries = ("dialog", "whiptail", "cdialog");
my $FOUND = 0;    # flag
if ($DIA eq "console")
{
    print STDERR ("Trying Term::ProgressBar
");
    eval "use Term::ProgressBar";
    if (!$@)
    {
        $use_console_progressbar = 1;    # update flag
    }
    else
    {

        # no hope at this point...
        print STDERR (
                    "Run without --front-end='console' to autodetect dialog
");
        print STDERR ("Term::ProgressBar is not installed. Exiting
");
        exit 1;
    }
}
elsif ($DIA eq "")
{
    foreach my $path (split(/:/, $ENV{"PATH"}))
    {
        next if ($FOUND == 1);
        if (exists $ENV{"NAUTILUS_SCRIPT_CURRENT_URI"})
        {
            $MODE = "x";
            foreach my $binary (@xbinaries)
            {
                next if ($FOUND == 1);
                if (-x "$path/$binary")
                {
                    $DIA = "$path/$binary";

                    # gets out of these loops
                    $FOUND = 1;
                }
            }    # end foreach @xbinaries
        }
        else
        {
            $MODE = "text";
            foreach my $binary (@binaries)
            {
                next if ($FOUND == 1);
                if (-x "$path/$binary")
                {
                    $DIA   = "$path/$binary";
                    $FOUND = 1;
                }
            }    # end foreach @binaries
        }    # end if NAUTILUS_SCRIPT_CURRENT_URI
    }    # end foreach $PATH
         # make sure DIA is set or exit abnormally
    if ($MODE eq "x")
    {
        if ($DIA eq "")
        {

            # error
            print STDERR ("Graphical Dialog was not found.
");
            print STDERR ("Please install any of these programs:
");
            print STDERR join(" ", @xbinaries) . "
";
            exit 1;
        }
    }
    elsif ($MODE eq "text")
    {
        if ($DIA eq "")
        {

            # error only if no DIA
            # being userfriendly here...
            print STDERR ("Console Dialog was not found.
");
            print STDERR ("Please install any of these programs:
");
            print STDERR join(" ", @binaries) . "
";

            # fallback to console...
            print STDERR ("Trying Term::ProgressBar
");
            eval "use Term::ProgressBar";
            if (!$@)
            {
                print STDERR ("Using Term::Progressbar
");
                $use_console_progressbar = 1;    # update flag
            }
            else
            {

                # yikes! no hope at this point...
                print STDERR ("Term::ProgressBar is not installed. Exiting
");
                exit 1;
            }

            # we should never reach this...
            exit 1;
        }    # end if DIA eq console
    }    # end if MODE
}    # end if DIA
my $LOGFILE       = new FileHandle;
my $THUMBNAILSDIR = "$ROOT_DIRECTORY/$THUMBNAIL";
my $HTMLSDIR      = "$ROOT_DIRECTORY/$HTMLDIR";

main();

#-------------------------------------------------#
#                   FUNCTIONS                     #
#-------------------------------------------------#

sub main
{
    $LOGFILE->open("> $LOG");
    $LOGFILE->autoflush(1);
    my $err = 0;
    my $ARGS =
      ($DIA =~ /zenity/)
      ? ""
      : " --clear --backtitle 'Picture Directory to HTML' ";
    if ($use_console_progressbar == 1)
    {
        $GAUGE = Term::ProgressBar->new(100);    # will be setup later...
    }
    else
    {
        if ($DIA =~ /zenity/)
        {

            # zenity uses --progress # 'Thumbnails Creation'
            $GAUGE->open(
                "| $DIA $ARGS --title='Picture Directory to HTML' --progress  8 70 0 2>&1"
            );
        }
        else
        {
            $GAUGE->open(
                "| $DIA $ARGS --title 'Picture Progress' --gauge 'Thumbnails Creation' 8 70 0 2>&1"
            );
        }
        $GAUGE->autoflush(1);
    }

    # which progressbar are we using?
    print $LOGFILE ("Mode $MODE
");
    print $LOGFILE "= Start directory $ROOT_DIRECTORY 
";

    # setup our internal variables:
    my $create_config =
      (!-f File::Spec->catfile($ROOT_DIRECTORY, $CONFIG_FILE))
      ? "true"
      : "false";
    print STDERR ("DEBUG: main() reading config file at dir $ROOT_DIRECTORY
")
      if ($DEBUG);
    init_config($ROOT_DIRECTORY, $create_config);

    # --------------------------- STEPS -----------------------------#
    # 1.
    # Create an array of all image files that we will work on.
    # HINT: check EXCEPT for files we will be ignoring.
    my @ary = do_file_ary($ROOT_DIRECTORY);

    # remove duplicates:
    my %seen = ();
    my @uniq = grep(!$seen{$_}++, @ary);
    @pixfiles = @uniq;    # copies all unique files to pixfiles
                          # free up memory:
    @ary      = ();
    %seen     = ();
    @uniq     = ();
    undef @ary;
    undef %seen;
    undef @uniq;

    # 2.
    # we need to create thumbnails first...
    # make all thumbnails and save all thumbs in %thumbfiles
    # so that mkindex() can create the indices.
    $err = mkthumb($ROOT_DIRECTORY);
    exit(0) if ($err > 0 or $THUMBSONLY > 0);

    # 3.
    # We need to create a menu string to pass it to mkindex()
    if ($NOMENU != 1 or $config{$ROOT_DIRECTORY}{"menutype"} eq "modern")
    {
        print $LOGFILE ("= Creating menu string
");
        $menu_str = menu_file_or_string();

        # When menuonly is set, we print to a menu.$EXT file and exit
        exit(0) if ($MENUONLY > 0);
    }

    if ($NOINDEX == 0)
    {

        # 4.
        # make all supporting HTML files for e/a thumbnail image.
        # i.e. under the "t" directory
        #
        # TODO this should use %thumbfiles (see mkindex())
        print $LOGFILE ("= Creating thumbnails HTML files
");
        mkthumb_files(\%thumbfiles);

        # 5.
        # create index.$EXT files for thumbnails. The index file contains
        # the links to e/a h/t$file.$EXT

        print $LOGFILE ("= Creating all index files
");
        mkindex(\%thumbfiles, $menu_str);
    }

    # close progressbar
    if ($use_console_progressbar != 1)
    {
        eof($GAUGE);
    }
    undef($GAUGE);    # this also closes the gauge... but...
                      # close log
    $LOGFILE->close();
    if (-x $SAVELOG)
    {
        system("$SAVELOG $LOG > /dev/null 2>&1");
    }
    return 0;
}    # endmain

sub write_config
{

    # @param 0 string := directory to write $CONFIG_FILE to
    # @param 1 hashref := hash of hashes containing what to write
    my $dir     = shift;
    my $hashref = shift;
    if (open(CONFIG, ">$dir/$CONFIG_FILE"))
    {
        foreach my $key (keys %{$hashref})
        {
            foreach my $subkey (keys %{$hashref->{$key}})
            {
                print CONFIG "$subkey="
                  . $hashref->{"$key"}->{"$subkey"} . "
";
            }
        }
    }
    else
    {
        print STDERR "Could not write $dir/$CONFIG_FILE. Check permissions?";
    }
    close(CONFIG);
}    # end write_config

sub init_config
{

    # @param 0 string := directory with config file
    # @param 1 string := optional, do we want to create a config file?
    # saves found variables to global %config database
    my $ROOT          = shift;
    my $create_config = shift;
    my $line          = "";

    # Some default values:
    $config{"$ROOT"}{"uri"} =
      "";    # all URL generated are relative the the path of the current dir
    $config{"$ROOT"}{"percent"} = ($PERCENT) ? $PERCENT : "20%";
    $config{"$ROOT"}{"title"} = "Images";
    $config{"$ROOT"}{"meta"} =
      "<meta http-equiv='content-type' content='text/html;charset=iso-8859-1'>";
    $config{"$ROOT"}{"stylesheet"} = "../styles.css";
    $config{"$ROOT"}{"html_msg"} = "<h1 class='pdheader1'>Free form HTML</h1>";
    $config{"$ROOT"}{"body"}     = "<body class='pdbody'>";
    $config{"$ROOT"}{"p"}        = "<p class='pdparagraph'>";
    $config{"$ROOT"}{"table"}    = "<table border='0' class='pdtable'>";
    $config{"$ROOT"}{"td"} = "<td valign='top' align='left' class='pdtd'>";
    $config{"$ROOT"}{"tr"} = "<tr class='pdtr'>";

    # when header is set, title, meta, stylesheet, etc...
    # are discarded. So do a complete set
    # such as <HTML><head><title>...
    # and close with "footer"
    $config{"$ROOT"}{"header"}            = "";
    $config{"$ROOT"}{"footer"}            = "";
    $config{"$ROOT"}{"menuheader_footer"} = 0;

    # ext can be passed in a .pixdir2htmlrc file
    # like: ext=html or ext=php ...
    $config{"$ROOT"}{"ext"}      = ($EXT)       ? $EXT       : "html";
    $config{"$ROOT"}{"menutype"} = ($MENU_TYPE) ? $MENU_TYPE : "classic";
    $config{"$ROOT"}{"menuname"} = ($MENU_NAME) ? $MENU_NAME : "menu";
    $config{"$ROOT"}{"menutd"}   = ($menu_td)   ? $menu_td   : 10;
    $config{"$ROOT"}{"ntd"}      = ($TD)        ? $TD        : 4;
    $config{"$ROOT"}{"strlimit"} = ($STR_LIMIT) ? $STR_LIMIT : 32;
    $config{"$ROOT"}{"cutdirs"}  = ($CUT_DIRS)  ? $CUT_DIRS  : 0;

    print STDERR ("DEBUG: init_config() root $ROOT
") if ($DEBUG);
    my $config_file = File::Spec->catfile($ROOT, $CONFIG_FILE);
    if (-f $config_file)
    {
        open(CONFIG, "< $config_file")
          or mydie("Could not read $config_file
", "init_config");

        # suppress warnings for now...
        no warnings;
        while (defined($line = <CONFIG>))
        {
            next if /^\s*#/;
            chomp $line;

            # attempts to be forgiven about backslashes
            # to break lines that continues over
            # multiple lines
            if ($line =~ s/\\$//)
            {
                $line .= <CONFIG>;
                redo unless eof(CONFIG);
            }
            $config{$ROOT}{$1} = $2 if ($line =~ m,^\s*([^=]+)=(.+),);
        }
        close(CONFIG);
    }

    #construct a header if it doesn't yet exist:
    if ($config{"$ROOT"}{"header"} =~ /^\s*$/)
    {
        print $LOGFILE (": Blank header. Generating my own [$ROOT] ... 
");
        $config{"$ROOT"}{"header"} =
            "<html><head>"
          . $config{"$ROOT"}{"meta"}
          . "<title>"
          . $config{"$ROOT"}{"title"}
          . "</title><link rel='stylesheet' href='"
          . $config{"$ROOT"}{"stylesheet"}
          . "' type='text/css'></head>"
          . $config{"$ROOT"}{"body"}
          . "<center>"
          . $config{"$ROOT"}{"html_msg"};
    }

    #construct a footer if it doesn't yet exist:
    if ($config{"$ROOT"}{"footer"} =~ /^\s*$/)
    {
        print $LOGFILE (": Blank footer. Generating my own [$ROOT] ... 
");
        $config{"$ROOT"}{"footer"} = "</center></body></html>";
    }

    # write configuration
    if ($create_config =~ /true/)
    {

        # uncomment for debugging...
        #use Data::Dumper;
        #print STDOUT Dumper(%config);
        #print STDOUT "


";
        write_config($ROOT, \%config);
    }
    warn "Could not find $config_file
" if (!-f $config_file);
}    # end init_config

sub mkindex
{

    # @param 0 hash :=
    #   takes a two-dimensional hash of arrays in the form:
    #   $name{base}->[0] = 'path/file'
    #   and does a index.$EXT file for e/a 'base' of
    #   all files referenced
    # @param 1 string := menu to use for e/a file

    my $hashref  = $_[0];    # saves the name of the var passed
                             # e/a key holds a full array of files
    my $MENU_STR = $_[1];
    my $i        = 0;
    my ($this_file, $this_base) = "";    # holds keys for hash
    my @files = ();

    foreach $this_base (sort keys %$hashref)
    {
        next if (-f File::Spec->catfile($this_base, $SKIP_DIR_FILE));
        my ($my_bgcolor, $file_name) = "";
        $i = 0;

        # read specific config file for this directory
        if (!-f File::Spec->catfile($this_base, $CONFIG_FILE))
        {

            # oops, missing config file copying from root dir
            if (
                copy(File::Spec->catfile($ROOT_DIRECTORY, $CONFIG_FILE),
                     File::Spec->catfile($this_base,      $CONFIG_FILE))
               )
            {
                print $LOGFILE (  ": mkindex() Copied "
                                . " $ROOT_DIRECTORY/$CONFIG_FILE "
                                . "==> $this_base/$CONFIG_FILE 
");
            }
        }    # end if/elsif
        if (!exists $config{$this_base})
        {

            # this should rarely happen
            print $LOGFILE "++ mkindex() Reading config for '$this_base'
";
            print STDERR (
                   "DEBUG: mkindex() reading config file at dir '$this_base'
")
              if ($DEBUG);
            init_config($this_base, "false");
        }

        # "serialization"
        my @files = @{$$hashref{$this_base}};

        dict_sort(\@files);

        # FILE_NAME is a global
        open(FILE,
                 "> "
               . $this_base . "/"
               . $FILE_NAME . "."
               . $config{"$this_base"}{"ext"}
            )
          or mydie(
                   "Couldn't write file $FILE_NAME."
                     . $config{"$this_base"}{"ext"}
                     . " to $this_base",
                   "mkindex"
                  );

        # start HTML
        print FILE ($config{"$this_base"}{"header"} . "
");

        # print menu (if any)
        print FILE ("$MENU_STR");

        # start table
        print FILE ($config{"$this_base"}{"table"} . "
");

        #print all picts now
        foreach (@files)
        {
            $this_file = basename($_);
            if ($i == 0)
            {

                # open a new row
                # this row doesn't need bgcolor
                if ($config{"$this_base"}{"tr"} =~ m/\%+bgcolor\%+/i)
                {
                    my $tmp_tr = "";
                    ($tmp_tr = $config{"$this_base"}{"tr"}) =~
                      s/\%+bgcolor\%+//i;
                    print FILE ($tmp_tr);
                }
                else
                {
                    print FILE ($config{"$this_base"}{"tr"} . "
");
                }
            }
            print FILE ("\t" . $config{"$this_base"}{"td"} . "
");
            ($file_name = $this_file) =~ s/$EXT_INCL_EXPR//gi;
            ($file_name = $file_name) =~ s/^$THUMB_PREFIX//;    # removes prefix
                  # EXT is a global and so is THUMBNAIL
            print FILE ("\t\t<a class='pdlink' href='$HTMLDIR/$file_name."
                      . $config{"$this_base"}{"ext"} . "'>"
                      . "\t\t<img class='pdimage' src='$THUMBNAIL/$THUMB_PREFIX"
                      . "$this_file' border=0 alt='$file_name'></a>
");
            print FILE ("\t</td>
");
            if ($i < ($TD - 1))
            {
                $i++;
            }
            else
            {

                # wrap and reset counter
                print FILE ("</tr>
");
                $i = 0;
            }
        }    # end for e/a @files
             # complete missing TD
        if ($i != 0)
        {
            for (; $i < $TD ; $i++)
            {
                print FILE ("\t" . $config{"$this_base"}{"td"} . "
");
                print FILE ("&nbsp;");
                print FILE ("\t</td>
");
            }
        }
        print FILE ("</tr>
");
        print FILE ("</table>
");
        print FILE ($config{"$this_base"}{"footer"} . "
");
        print FILE ("
");
        close(FILE);
    }    # end for e/a this_base
}    # end mkindex

sub mkthumb
{

    # Creates thumbnails for a given directory
    # and save all to the global hash %thumbfiles
    # @param 0 := root dir to make the images
    #
    my $ROOT = $_[0];

    # globals
    %thumbfiles = ();    # reset
                         # locals: reset some locals
    my @ls = ();
    my (
        $this_file,      $pix_name,          $file_name,
        $next_pix_name,  $next_file_name,    $last_pix_name,
        $last_html_file, $current_html_file, $last_file_name,
        $current_link,   $last_link,         $LAST_BASE,
        $NEXT_BASE,      $HTMLSDIR
       ) = "";

    # these two are special...
    # init to some strange string...
    my $BASE     = ",\/trash";
    my $tmp_BASE = ",\/more_trash";

    # error reporting:
    my $err = 0;
    my $i   = 0;

    print $LOGFILE ("= Making thumbnails in $ROOT 
");
    if (!defined $pixfiles[0] or !-f $pixfiles[0])
    {
        print STDERR ("DEBUG: can't read Pixfile " . $pixfiles[0] . "
")
          if ($DEBUG);
        mydie("Sorry, do_file_ary() didn't do its job
", "mkthumb");
    }

    # parse array of images
    foreach (@pixfiles)
    {
        $this_file = basename($_);
        next if ($this_file =~ m/$EXCEPTION_LIST/);
        next if ($_         =~ m/\b$THUMBNAIL\b/i);
        next if ($this_file !~ m/$EXT_INCL_EXPR$/i);
        print STDERR ("DEBUG: mkthumb() adding pixfile $_
") if ($DEBUG);
        push @ls, $_;
        $this_file = "";
    }    #end images array creation
         #print STDERR @ls;
    dict_sort(\@ls);

    # progressbar stuff
    # gauge message
    my $MESSAGE = "Thumbnails Creation";

    # initial values for gauge
    my $PROGRESS = 0;
    my $TOTAL    = $#ls + 1;
    if ($use_console_progressbar == 1)
    {
        $GAUGE->new({'name' => $MESSAGE, 'count' => $TOTAL});
    }
    else
    {
        progressbar_msg($MESSAGE);
    }
    print $LOGFILE ("= $TOTAL pictures 
");

    print $LOGFILE ("
= Using system command convert  
")
      if ($USE_CONVERT == 1);

    #print $LOGFILE join(" ",@ls)."
";
    for ($i = 0 ; $i < $TOTAL ; $i++)
    {
        $PROGRESS++;

        # get base directory
        $BASE = dirname($ls[$i]);
        print STDERR ("DEBUG: base directory in mkthumb() is $BASE
")
          if ($DEBUG);

        # BASE is blank if we are already inside the directory
        # for which to do thumbnails, thus:
        if (not defined($BASE) or $BASE eq "" or !-d $BASE)
        {
            $BASE = getcwd();
        }
        next if (-f File::Spec->catfile($BASE, $SKIP_DIR_FILE));
        next if (basename($BASE) eq $THUMBNAIL);
        if ($BASE ne $tmp_BASE)
        {

            # Note that this tmp_BASE comparison is meant
            # to avoid doing this for e/a directory more than once:
            if ($FORCE > 0 or !-f File::Spec->catfile($BASE, $CONFIG_FILE))
            {
                copy(File::Spec->catfile($ROOT_DIRECTORY, $CONFIG_FILE),
                     File::Spec->catfile($BASE, $CONFIG_FILE))
                  or mydie(
                    "Could not copy $ROOT_DIRECTORY/$CONFIG_FILE to $BASE/$CONFIG_FILE. $!",
                    "mkthumb"
                  );
                print $LOGFILE (
                    ": Copied $ROOT_DIRECTORY/$CONFIG_FILE ==> $BASE/$CONFIG_FILE 
"
                );
            }    # end if missing $CONFIG_FILE
                 # read specific config file for this directory
            if (!exists $config{$BASE})
            {
                print $LOGFILE "+ mkthumb Reading config for '$BASE'
";
                print STDERR (
                          "DEBUG: mkthumb() reading config file at dir $BASE
")
                  if ($DEBUG);
                init_config($BASE, "false");
            }
        }    # end if base not equal tmp_base
             # update flag
        $tmp_BASE = $BASE;

        $pix_name = basename($ls[$i]);

        # strip extension from file name
        ($file_name = $pix_name) =~ s/$EXT_INCL_EXPR$//gi;

        # construct PATH for thumbnail directory
        $THUMBNAILSDIR = File::Spec->catfile($BASE, $THUMBNAIL);

        if (!-d $THUMBNAILSDIR)
        {
            print $LOGFILE ("= Making thumbnail's directory in $BASE
");
            mkdir($THUMBNAILSDIR, 0755);
        }
        my $_pix_name_tmp = File::Spec->catfile($BASE, $pix_name);
        my $_thumb_pix_name_tmp =
          File::Spec->catfile($THUMBNAILSDIR, $THUMB_PREFIX . $pix_name);
        if (!-f $_thumb_pix_name_tmp)
        {
            print $LOGFILE (
                 "
= Converting file $BASE/$pix_name $_thumb_pix_name_tmp 
");
            if ($USE_CONVERT == 1)
            {

                system(
                    "convert -geometry $PERCENT $_pix_name_tmp $_thumb_pix_name_tmp"
                );
                if ($? != 0)
                {
                    print $LOGFILE
                      "** ERROR: $_pix_name_tmp conversion failed: $! 
";
                    $err = 1;
                }
            }
            else
            {

                # there is no way around defining $image here...
                my $image = Image::Magick->new;
                $image->Read($_pix_name_tmp);
                $image->Resize($PERCENT);
                $image->Write($_thumb_pix_name_tmp);
                undef $image;
            }
            print $LOGFILE ("= Wrote $_thumb_pix_name_tmp
");
        }

        # end if thumbnail file

        print STDERR ("DEBUG: mkthumb() saving base to \%thumbfiles{$BASE}
")
          if ($DEBUG);
        print STDERR ("DEBUG: mkthumb() saving pix file $_thumb_pix_name_tmp
")
          if ($DEBUG);

        # save pixname for the index.html file
        # NOTE: do not use abs2rel here because it makes a crazy path
        push(@{$thumbfiles{$BASE}}, $_thumb_pix_name_tmp);

        # update flags
        $LAST_BASE = $BASE;

        # update progressbar
        if ($use_console_progressbar == 1)
        {
            $GAUGE->update($PROGRESS);
        }
        else
        {
            progressbar($PROGRESS, $TOTAL);
        }
    }    #end for @ls
    return $err;
}    # end mkthumb

sub mkthumb_files
{

    # creates HTML file for each thumbnail image
    # @param 0 hash := $name{$base}->[$i] = 'path/t/timage_file'
    my $hashref = shift;
    mydie("Error while creating thumb_files HTML indeces
", "mkthumb_files")
      if (not defined $hashref);

    # locals
    my @ls = ();
    my $i  = 0;
    my (
        $this_file,         $pix_name,       $file_name,
        $next_pix_name,     $next_file_name, $last_pix_name,
        $current_html_file, $last_file_name, $current_link,
        $last_link,         $LAST_BASE,      $NEXT_BASE,
        $HTMLSDIR
       ) = "";

    # TODO find a more elegant solution here
    # init to dummy string:
    my $BASE           = "trash/\\file";
    my $last_html_file = "this_is/dummy\\string";

    # some sanity checks plus "serializes" our hashref into a more manageable array @ls
    # TODO are these really needed?
    # TODO sometimes the $this_base is the full file others is a key??
    # FIXME we need to strip $THUMBNAIL/t$file out of the names
    #
    # after this loop:
    # Path: 2007-oct/t/tIMGA4284.JPG
    # becomes: 2007-oct/IMGA4284.JPG
    # FIXME why not just pass to this functon the array of images that 
    # we first did (not the array of thumbnails?
    foreach my $this_base (keys %$hashref)
    {
        print $LOGFILE "DEBUG:$this_base
";
        if ($this_base =~ m/$EXT_INCL_EXPR$/i)
        {
            #print $LOGFILE "DEBUG:base0:$this_base
";
            $this_base =~ s|(.+)\/$THUMBNAIL\/t|$1/|g;
            push @ls, $this_base;
            #print $LOGFILE "DEBUG:base:$this_base
";
            #    next;
        }
        foreach my $_file (@{$$hashref{$this_base}})
        {

            #print $LOGFILE "DEBUG:file0:$_file
";
            next if ($_file =~ m/$EXCEPTION_LIST/);
            next if ($_file !~ m/$EXT_INCL_EXPR$/i);

            #next if ($_file =~ m/\/$THUMBNAIL\/.*$EXT_INCL_EXPR$/i);
            $_file =~ s|(.+)\/$THUMBNAIL\/t|$1/|g;
            push @ls, $_file;

            #print $LOGFILE "DEBUG:file:$_file
";
        }    #end images array creation
    }
    dict_sort(\@ls);

    # progressbar stuff
    # gauge message
    my $MESSAGE = "HTML Creation";

    # initial values for gauge, note total
    # is number of elements in array ;-)
    my $PROGRESS = 0;

    # $#VAR gets index of last element in an array
    my $TOTAL = $#ls + 1;
    if ($use_console_progressbar == 1)
    {
        $GAUGE->new({'name' => $MESSAGE, 'count' => $TOTAL});
    }
    else
    {
        progressbar_msg($MESSAGE);
    }

    #print all picts now
    for ($i = 0 ; $i < $TOTAL ; $i++)
    {
        $PROGRESS++;

        # get base directory
        $BASE = dirname($ls[$i]);
        next if ($BASE eq $THUMBNAIL);

        # BASE is blank if we are already inside the directory
        # for which to do thumbnails, thus:
        if (!-d $BASE)
        {
            print $LOGFILE "+ mkthumb_files changed based $BASE to .
";
            $BASE = ".";
        }
        next if (-f File::Spec->catfile($BASE, $SKIP_DIR_FILE));
        $pix_name = basename($ls[$i]);

        # strip extension from file name
        ($file_name = $pix_name) =~ s/$EXT_INCL_EXPR$//gi;

        # if we have not already read this config file,
        # do so now:
        if (!exists $config{$BASE})
        {
            print $LOGFILE "+ mkthumb_files Reading config for '$BASE'
";
            print STDERR (
                    "DEBUG: mkthumb_files() reading config file at dir $BASE
")
              if ($DEBUG);
            init_config($BASE, 'false');
        }

        # construct PATH for html directory
        $HTMLSDIR = File::Spec->catfile($BASE, $HTMLDIR);
        if (!-d $HTMLSDIR)
        {
            print $LOGFILE ("= Making HTML directory in $BASE
");
            mkdir($HTMLSDIR, 0755);
        }

        $current_html_file = File::Spec->catfile($HTMLSDIR,
                                      $file_name . "." . $config{$BASE}{"ext"});
        $current_link = $file_name . "." . $config{$BASE}{"ext"};

        my $msg = "= Creating";
        if (-f $current_html_file)
        {
            $msg = ": Overriding";
        }
        print $LOGFILE ("$msg html file '$current_html_file'
");

        # TODO routine for creating file should be called here...
        open(FILE, "> $current_html_file")
          or mydie("Couldn't write file $current_html_file", "mkthumb_files");

        # start HTML
        print FILE ($config{"$BASE"}{"header"} . "
");

        # start table
        print FILE ($config{"$BASE"}{"table"} . "
");

        # set menu-name now (from command-line or config file)
        if ($NEW_MENU_NAME gt "")
        {
            $MENU_NAME = $NEW_MENU_NAME;
        }
        elsif (defined($config{"$ROOT_DIRECTORY"}{"menuname"})
               and $config{"$ROOT_DIRECTORY"}{"menuname"} gt "")
        {
            $MENU_NAME = $config{"$ROOT_DIRECTORY"}{"menuname"};
        }    # else MENU_NAME keeps the default name

        if ($config{"$BASE"}{"menutype"} eq "modern")
        {

            # TODO use relative path instead of URI here
            print FILE (  "\t\t<a class='pdlink' href='"
                        . $config{"$BASE"}{"uri"} . "/"
                        . $MENU_NAME . "."
                        . $config{"$BASE"}{"ext"}
                        . "'>&lt;&lt;</a>
");
        }

        # backward link here
        if (    $last_html_file ne "this_is/dummy\string"
            and -f $last_html_file
            and ($BASE eq $LAST_BASE))
        {
            print FILE ("\t\t<a class='pdlink' href='$last_link'>&lt;==</a>
");
        }
        else
        {
            print FILE ("&lt;==");
        }

        # home link here # TODO ../ should be replaced with relative str
        print FILE (  "\t\t | <a class='pdlink' href='../$FILE_NAME."
                    . $config{"$BASE"}{"ext"}
                    . "'>HOME</a> | 
");

        if (-f $ls[$i + 1])
        {
            $next_pix_name = "....";

            # calculate next base
            $next_pix_name = basename($ls[$i + 1]);

            # get next base directory
            $NEXT_BASE = dirname($ls[$i + 1]);
        }

        # forward link here
        if (-f $ls[$i + 1] and ($BASE eq $NEXT_BASE))
        {
            $next_file_name = "";
            ($next_file_name = $next_pix_name) =~ s/$EXT_INCL_EXPR$//gi;

            #print FILE ("==&gt;");
            print FILE (  "\t\t<a class='pdlink' href='$next_file_name."
                        . $config{"$BASE"}{"ext"}
                        . "'>==&gt;</a> 
");
        }
        else
        {
            print FILE ("==&gt;");

            # TODO would be nice to jump to next directory in the
            #       array...
            #print FILE (" <a href='../$next_file_name.$EXT'>&gt;&gt;</a> 
");
        }
        print FILE ("</div></td></tr>
");
        print FILE ("<tr><td align='center'>
<div align='center'>
");

        # image here # TODO ../ should be replaced with relative str
        print FILE ("<img src='../$pix_name' alt='$file_name' border=0>
");
        print FILE (
            "</div></td></tr>
<tr><td valign='bottom' align='center'><div align='center'>
"
        );
        print FILE ("</table>
");
        print FILE ($config{"$BASE"}{"footer"} . "
");
        close(FILE);

        # end HTML
        # keep track of links
        $last_html_file = $current_html_file;
        $last_link      = $current_link;

        # update flags
        $LAST_BASE = $BASE;
        $NEXT_BASE = "";

        #$PRINT_NEXT_LINK = 0;
        # update progressbar
        if ($use_console_progressbar == 1)
        {
            $GAUGE->update($PROGRESS);
        }
        else
        {
            progressbar($PROGRESS, $TOTAL);
        }
    }    #end foreach $i
}    # end mkthumb_files

sub menu_file_or_string
{

    #---------------------------------------------#
    # this function creates a menu.$EXT file at
    # the root level of the picture
    # directory (at the first
    # directory that was passed to the script) or
    # it returns a string to be put in e/a index.$EXT file
    #
    # This function must be called after mkthumb() have created
    # all thumbnails.
    #
    # if there is a file named .new
    # inside the given directory,
    # then a IMG tag will be put in
    # front of the link with an image
    # src=myscript{new} in it
    #
    # Thus in the config file put a line as such:
    # new=http://images.server.com/new_icon.png;
    #----------------------------------------------#

    # deprecated: init_config($ROOT_DIRECTORY);

    my $MENU_STR = "";    # return this instead of making file
    my $IMG      = "";
    my $line     = "";

    #my $this_file= "";
    my $y      = 0;       # counts number of td's
    my $i      = 0;       # general purpose counter
    my $j      = 0;       # count number of TR's
    my @ls     = ();
    my $ts     = "";
    my @files  = ();
    my @pixdir = ();      # reset array

    my @ary = do_dir_ary($ROOT_DIRECTORY);

    # remove duplicates:
    my %seen = ();
    my @uniq = grep(!$seen{$_}++, @ary);

    if ($config{"$ROOT_DIRECTORY"}{"uri"} ne "")
    {

        # make sure we have a forward slash at the end of our URL
        $config{"$ROOT_DIRECTORY"}{"uri"} =
          ($config{"$ROOT_DIRECTORY"}{"uri"} =~ /\/$/)
          ? $config{"$ROOT_DIRECTORY"}{"uri"}
          : $config{"$ROOT_DIRECTORY"}{"uri"} . "/";
    }

    # for e/a directory here
    # check if a $SKIP_DIR_FILE file exists
    # if it does, then skip it and do the next one.
    # if it doesn't, then assume this will contain
    # a index.$EXT file and add it to the menu.
    foreach my $directory (@uniq)
    {
        next if (!-d File::Spec->catfile($directory, $THUMBNAIL));
        next if (-f File::Spec->catfile($directory, $SKIP_DIR_FILE));
        next
          if (basename($directory) =~ /^\.[^\/]/)
          ;    # skip dir names starting with .
               # remove ./ or . from begining of names
        $directory =~ s,^\./*,,g;

        # note that @ls holds the HTML links...
        # thus, paths are relative and not absolute here:
        push(
             @ls,
             File::Spec->catfile(
                              $directory,
                              $FILE_NAME . "." . $config{$ROOT_DIRECTORY}{"ext"}
             )
            );
    }
    dict_sort(\@ls);    # sort in dictionary order
    $TOTAL_LINKS = $#ls + 1;

    # set menu-name now (from command-line or config file)
    if ($NEW_MENU_NAME !~ /^\s*$/)
    {
        $MENU_NAME = $NEW_MENU_NAME;
    }
    elsif (defined($config{$ROOT_DIRECTORY}{"menuname"})
           and $config{$ROOT_DIRECTORY}{"menuname"} !~ /^\s*$/)
    {
        $MENU_NAME = $config{$ROOT_DIRECTORY}{"menuname"};
    }                   # else MENU_NAME keeps the default name

    if ($config{$ROOT_DIRECTORY}{"menutype"} eq "modern")
    {

        # create modern menu
        # modern menu is a file, no --menu-only needed here
        open(FILE,
             "> $ROOT_DIRECTORY/$MENU_NAME." . $config{$ROOT_DIRECTORY}{"ext"})
          or mydie(
                   "Couldn't write file $MENU_NAME."
                     . $config{"$ROOT_DIRECTORY"}{"ext"}
                     . " to $ROOT_DIRECTORY",
                   "menu_file_or_string"
                  );
        print FILE ($config{"$ROOT_DIRECTORY"}{"header"} . "
");
        print FILE ($config{"$ROOT_DIRECTORY"}{"table"} . "
");

        # loop
        foreach (@ls)
        {
            if ($config{$ROOT_DIRECTORY}{"tr"} =~ m/\%+bgcolor\%+/i)
            {
                my $tmp_tr = "";

                # alternate colors for TR?
                my $color = (($j % 2) == 0) ? "bgcolor=\"#efefef\"" : "";
                ($tmp_tr = $config{$ROOT_DIRECTORY}{"tr"}) =~
                  s/\%+bgcolor\%+/$color/i;
                print FILE ($tmp_tr . "
");
            }
            else
            {
                print FILE ($config{"$ROOT_DIRECTORY"}{"tr"} . "
");
            }
            if (-f $config{$ROOT_DIRECTORY}{"albumpix"})
            {
                print FILE (  "\t<td background='"
                            . $config{"$ROOT_DIRECTORY"}{"albumpix"}
                            . "' align='center'>
");
            }
            else
            {
                print FILE ("\t" . $config{"$ROOT_DIRECTORY"}{"td"} . "
");
            }

            #if ( $ls[$i] !~ /^\s*$/ )
            #{
            # if link exists, otherwise leave it blank
            $ts = dirname($ls[$i]);
            if ($nautilus_root gt "")
            {
                $ls[$i] =~ s,$nautilus_root/,,g;
                $ts     =~ s,$nautilus_root/*,,g;
            }
            $IMG =
              (-f File::Spec->catfile($ts, ".new"))
              ? "<img valign='middle' border=0 src='"
              . $config{"$ROOT_DIRECTORY"}{"new"}
              . "' alt='new'>"
              : "";
            my $tmp_ts = basename("$ts");
            $tmp_ts = str_truncate($tmp_ts);    # truncate up to $STR_LIMIT
            $tmp_ts = ucfirst($tmp_ts);         # uppercase first letter
            my $image = "";
            if (-d File::Spec->catfile($ts, $THUMBNAIL))
            {

                # get all files starting with 't' and ending in .???
                # (3 characters); they might or might not be picture files,
                # but... we are trusting they are for now
                my @glob_ary = glob("$ts/$THUMBNAIL/t*.???");
                my $attempts = 3;    # number of tries to get an image
              IMAGE:
                $image = $glob_ary[rand(@glob_ary)];
                if (   $image !~ /$EXT_INCL_EXPR$/i
                    or !-f $image
                    or $attempts != 0)
                {
                    print LOGFILE "$image is not an IMAGE file
";
                    $attempts--;
                    goto IMAGE;
                }
                my $tmp_image = "";
                if (-f $image)
                {
                    $tmp_image =
                      "<img src='$image' border=0 alt='$tmp_ts album'>";
                }
                else
                {
                    $tmp_image =
                        "MISSING. Try re-running "
                      . basename($0)
                      . " with no arguments";
                }
                print FILE (
                    "\t\t<a class='pdlink' href='$ls[$i]' target='_top'>
\t\t$tmp_image</a></td>
\t"
                      . $config{"$ROOT_DIRECTORY"}{"td"}
                      . "
\t\t<a class='pdlink' href='$ls[$i]' target='_top'>$IMG $tmp_ts</a>
"
                );
            }
            else
            {
                print LOGFILE
                  "$ts has no thumbnail [$THUMBNAIL] directory. Have you executed "
                  . basename($0)
                  . " without --menu-only or --menu-type='modern' yet?";
            }

            # close table row  (TR)
            print FILE ("\t</td>
</tr>
");

            # TODO do we need two counters here?
            $i++;    # incr file counter
                     #}
            $j++;    # incr TR counter
        }    # end while loop
        print FILE ("</table>
");
        print FILE ($config{"$ROOT_DIRECTORY"}{"footer"} . "
");

        # close file
        close(FILE);

        # return a menu that contains a link back to menu.$EXT
        # Note that we use the URI here and not try to guess the relative path...
        $MENU_STR .=
          $config{"$ROOT_DIRECTORY"}{"table"}
          . "
<tr>
\t<td align='center'>
<div align='center'>
";

        # assumes menu is one directory above the current dir
        $MENU_STR .=
            "\t\t<a class='pdlink' href='" . "../"
          . $MENU_NAME . "."
          . $config{"$ROOT_DIRECTORY"}{"ext"}
          . "'>Back to Previous</a>
</div>
";
        $MENU_STR .= "\t</td>
</tr>
</table>
";
    }
    else
    {

        # classic is default menu type
        if ($MENUONLY > 0)
        {
            open(FILE,
                     "> "
                   . $ROOT_DIRECTORY . "/"
                   . $MENU_NAME . "."
                   . $config{"$ROOT_DIRECTORY"}{"ext"}
                )
              or mydie(
                       "Couldn't write file $MENU_NAME."
                         . $config{"$ROOT_DIRECTORY"}{"ext"}
                         . " to $ROOT_DIRECTORY",
                       "menu_file_or_string"
                      );
        }

        # menus are now part of the index.EXT...
        # print header only if menuonly is set and we want to show
        # the header/footer set in .pixdir2htmlrc
        if (   $MENUONLY > 0
            && $config{"$ROOT_DIRECTORY"}{"menuheader_footer"} > 0)
        {
            print FILE ($config{"$ROOT_DIRECTORY"}{"header"} . "
");
        }

        # generate menu
        if ($TOTAL_LINKS > 1)
        {
            if ($MENUONLY > 0)
            {
                print FILE ($config{"$ROOT_DIRECTORY"}{"table"} . "
");
            }
            $MENU_STR .= $config{"$ROOT_DIRECTORY"}{"table"} . "
";

            # print all links now
            my $tmp_tr = "";    # used to color the rows
            foreach (@ls)
            {

                # temporarily turn off warnings
                no warnings;

                # TODO
                # menu only routine: prints to a file... should merge
                # with the str portion (see else)
                #
                if ($MENUONLY > 0)
                {
                    if ($config{"$ROOT_DIRECTORY"}{"tr"} =~ m/\%+bgcolor\%+/i)
                    {
                        if (($j % 2) == 0)
                        {
                            ($tmp_tr = $config{"$ROOT_DIRECTORY"}{"tr"}) =~
                              s/\%+bgcolor\%+/bgcolor="#efefef"/i;
                        }
                        else
                        {
                            ($tmp_tr = $config{"$ROOT_DIRECTORY"}{"tr"}) =~
                              s/\%+bgcolor\%+//i;
                        }
                        print FILE ($tmp_tr . "
");
                    }
                    else
                    {
                        print FILE ($config{"$ROOT_DIRECTORY"}{"tr"} . "
");
                    }
                    for ($y = 1 ;
                         $y <= $config{"$ROOT_DIRECTORY"}{"menutd"} ;
                         $y++)
                    {

                        # close the TD tags
                        if ($y > 1)
                        {
                            print FILE ("\t </td> 
");
                        }
                        print FILE (
                                "\t" . $config{"$ROOT_DIRECTORY"}{"td"} . "
");

                        if ($ls[$i] ne "")
                        {

                            # if link exists, otherwise leave it blank
                            $ts = dirname($ls[$i]);

                            # from nautilus one cannot pass arguments
                            # "--menuonly" but... just to keep things
                            # consistent...
                            # if number of characters is greater than $STR_LIMIT
                            # truncate $ts to a few characters.
                            if ($nautilus_root gt "")
                            {
                                $ls[$i] =~ s,$nautilus_root/,,g;
                                $ts     =~ s,$nautilus_root/*,,g;
                            }

                            # remove CUT_DIRS number of directories from ts
                            if ($CUT_DIRS > 0)
                            {
                                $ts = cut_dirs($ts, $CUT_DIRS);
                            }

                            my $tmp_ts = str_truncate($ts);

                            $IMG =
                              (-f "$ts/.new")
                              ? "<img valign='middle' border=0 src='"
                              . $config{"$ROOT_DIRECTORY"}{"new"}
                              . "' alt='new'>"
                              : "";    # if .new file
                            $ts = ucfirst($tmp_ts);
                            print FILE (  "\t\t<a href='"
                                        . $config{"$ROOT_DIRECTORY"}{"uri"}
                                        . $ls[$i]
                                        . "' target='_top'>$IMG $ts</a>
");
                        }
                        else
                        {
                            print FILE ("&nbsp;");
                        }
                        $i++;
                    }    # end for $y
                    print FILE ("</tr>
");
                    $j++;    # incr TR counter
                }
                else
                {

                    # general menu routine
                    # TODO cleanup
                    if ($config{"$ROOT_DIRECTORY"}{"tr"} =~ m/\%+bgcolor\%+/i)
                    {
                        if (($j % 2) == 0)
                        {
                            ($tmp_tr = $config{"$ROOT_DIRECTORY"}{"tr"}) =~
                              s/\%+bgcolor\%+/bgcolor="#efefef"/i;
                        }
                        else
                        {
                            ($tmp_tr = $config{"$ROOT_DIRECTORY"}{"tr"}) =~
                              s/\%+bgcolor\%+//i;
                        }
                        $MENU_STR .= $tmp_tr . "
";
                    }
                    else
                    {
                        $MENU_STR .= $config{"$ROOT_DIRECTORY"}{"tr"} . "
";
                    }
                    for ($y = 1 ;
                         $y <= $config{"$ROOT_DIRECTORY"}{"menutd"} ;
                         $y++)
                    {

                        # close the TD tags
                        if ($y > 1)
                        {
                            $MENU_STR .= "\t </td> 
";
                        }
                        $MENU_STR .=
                          "\t" . $config{"$ROOT_DIRECTORY"}{"td"} . "
";

                        # menu entries
                        if ($ls[$i] ne "")
                        {

                            # if link exists, otherwise leave it blank
                            $ts = dirname($ls[$i]);
                            $IMG =
                              (-f "$ts/.new")
                              ? "<img valign='middle' border=0 src='"
                              . $config{"$ROOT_DIRECTORY"}{"new"}
                              . "' alt='new'>"
                              : "";    # if .new file
                             # if number of characters is greater than $STR_LIMIT
                             # truncate $ts to a few characters.
                            if ($nautilus_root gt "")
                            {
                                $ls[$i] =~ s,$nautilus_root/,,g;
                                $ts     =~ s,$nautilus_root/*,,g;
                            }

                            # remove CUT_DIRS number of directories from ts
                            if ($CUT_DIRS > 0)
                            {
                                $ts = cut_dirs($ts, $CUT_DIRS);
                            }
                            my $tmp_ts = str_truncate($ts);
                            $ts = ucfirst($tmp_ts);

                            # $ls tends to hold the whole filename path+filename
                            # we don't care about the whole path here...
                            $MENU_STR .=
                                "\t\t<a href='"
                              . $config{"$ROOT_DIRECTORY"}{"uri"}
                              . "$ls[$i]' target='_top'>$IMG $ts</a>
";
                        }
                        else
                        {
                            $MENU_STR .= "&nbsp;";
                        }
                        $i++;
                    }    # end for $y
                    $MENU_STR .= "</tr>
";
                    $j++;    # incr TR counter
                }    # end if/else menuonly
            }
            if ($MENUONLY > 0)
            {
                print FILE ("</table>
");
            }
            $MENU_STR .= "</table>
";

            # end if TOTAL_LINKS
        }
        else
        {
            print $LOGFILE (": Not a single link found
");
        }

        # see previous notes on header
        if (   $MENUONLY > 0
            && $config{"$ROOT_DIRECTORY"}{"menuheader_footer"} > 0)
        {
            print FILE ($config{"$ROOT_DIRECTORY"}{"footer"} . "
");
        }
        if ($MENUONLY > 0)
        {
            close(FILE);
        }
    }
    if ($TOTAL_LINKS > 1)
    {
        print $LOGFILE (": $TOTAL_LINKS links in menu.
");
    }
    return $MENU_STR;
}    #end menu_file_or_string

# ---- HELPER functions ----- #

sub str_truncate
{
    my $str        = shift;
    my $str_length = length($str);
    $str =
      ($str_length > $STR_LIMIT)
      ? "..." . substr($str, ($STR_LIMIT / 2), $str_length)
      : $str;

    # return truncated string
    return $str;
}    #end str_truncate

sub progressbar
{
    my ($PROGRESS, $TOTAL) = @_;
    chomp($PROGRESS);
    chomp($TOTAL);
    my $current = 0;

    # make sure we don't divide by 0
    if ($TOTAL > 0)
    {
        $current = sprintf("%02d", ($PROGRESS / $TOTAL) * 100);
        if ($use_console_progressbar == 1)
        {
            $GAUGE->update($current);
        }
        else
        {
            print $GAUGE $current . "
";
        }
    }
}    # end progressbar

sub progressbar_msg
{
    my ($MESSAGE) = @_;

    chomp($MESSAGE);
    if ($use_console_progressbar != 1)
    {
        print $GAUGE "XXX
" . $MESSAGE . "
XXX
";
    }
}    # end progressbar_msg

sub do_dir_ary
{

    # uses find() to recur thru directories
    # returns an array of directories
    # i.e. in directory "a" with structure:
    # /a
    # /a/b
    # /a/b/c
    # /a/b2/c2
    #
    # my @ary = &do_dir_ary(".");
    #
    # will yield:
    # a
    # a/b
    # a/b/c
    # a/b2/c2
    #

    my $ROOT = shift;
    my %opt = (wanted => \&process_dir, no_chdir => 1);
    find(\%opt, $ROOT);
    return @pixdir;
}    # end do_dir_ary

sub process_dir
{
    my $base_name = basename($_);
    if (   -d File::Spec->catfile($_, $THUMBNAIL)
        && !-f File::Spec->catfile($_, $SKIP_DIR_FILE)
        && $base_name !~ m/^($EXCEPTION_LIST)$/
        && $base_name !~ m/\b$THUMBNAIL\b/
        && $base_name !~ m/\b$HTMLDIR\b/
        && $base_name !~ m/^\.[a-zA-Z0-9]+$/)
    {
        push @pixdir, abs2rel($_, $ROOT_DIRECTORY);
    }
}    # end process_dir

sub do_file_ary
{

    # uses find() to recur thru directories
    # returns an array of files
    # i.e. in directory "a" with the files:
    # /a/file.txt
    # /a/b/file-b.txt
    # /a/b/c/file-c.txt
    # /a/b2/c2/file-c2.txt
    #
    # my @ary = &do_file_ary(".");
    #
    # will yield:
    # a/file.txt
    # a/b/file-b.txt
    # a/b/c/file-c.txt
    # a/b2/c2/file-c2.txt
    #
    my $ROOT = shift;
    my %opt = (wanted => \&process_file, no_chdir => 1);
    find(\%opt, $ROOT);
    return @pixfiles;
}    # end do_file_ary

sub process_file
{
    my $base_name = basename($_);
    my $dir_name  = dirname($_);
    if (
           -f $_
        && !-f "$dir_name/$SKIP_DIR_FILE"
        && $base_name =~ m/$EXT_INCL_EXPR$/i    # only pictures please
        && $base_name !~ m/^($EXCEPTION_LIST)$/
        && $base_name !~ m/\b$THUMBNAIL\b/
        && $base_name !~ m/\b$HTMLDIR\b/
        && $base_name !~ m/^\.[a-zA-Z0-9]+$/    # skip dot files
       )
    {
        s#^\.\/*##;                             # no ./
        my $relative = abs2rel($_, $ROOT_DIRECTORY);
        print STDERR ("DEBUG: $relative
") if ($DEBUG);
        push(@pixfiles, $relative);
    }
}    # end process_file

sub cut_dirs
{

    # call like cut_dirs($ts,$CUT_DIRS);
    # where ts is a path in the form "path/to/something"
    # and $CUT_DIRS is an integer
    my $path = shift;
    my $cut  = shift;

    # TODO is there a way to know the OS separator string in Perl
    # a la Python?
    $path =~ s,^/,,g;    # remove leading slashes
    my @tmp_path = split(/\//, $path);
    my $tmp_str = "";

    for (my $i = 0 ; $i <= $#tmp_path ; $i++)
    {
        if ($i >= $cut)    # to be safe, display the last name
        {
            $tmp_str .= $tmp_path[$i] . "/";
        }
    }
    return $tmp_str;
}    # end cut_dirs

sub dict_sort
{

    # sort menus alphabetically (dictionary order):
    #@param 0 array_ref := array to sort
    #@param 1 string/pattern := what to ignore [optional]
    my $aryref = shift;
    my $ignore = shift;

    #open(UNSORTED,">unsorted.txt");
    #print UNSORTED join(' ', @$aryref), "
";
    #close(UNSORTED);

    my $da;
    my $db;

    if ($ignore ne "")
    {

        # TODO what's the best way to ignore this pattern?
        #        my @local_ls;
        #        my $i = 0;
        #        foreach( @$aryref )
        #        {
        #            ( $local_ls[$i] = $_ ) =~ s/$ignore//g;
        #            $i++;
        #        }
        @$aryref = sort {

            # TODO ignore here?
            ($da = lc $a) =~ s/[\W_]+//g;
            ($db = lc $b) =~ s/[\W_]+//g;
            $da cmp $db;
        } @$aryref;
    }
    else
    {
        @$aryref = sort {
            ($da = lc $a) =~ s/[\W_]+//g;
            ($db = lc $b) =~ s/[\W_]+//g;
            $da cmp $db;
        } @$aryref;
    }
}    # end dict_sort()

sub mydie
{

    # @param 0 string := message to log
    # @param 1 string := function which called us
    my $msg = shift;
    my $fun = shift;
    print LOGFILE "DIE: $fun : $msg
";
    print STDERR ("DIE: $fun : $msg
") if ($DEBUG);
    die("Stopping execution $fun");
}

#-------------------------------------------------#
#                 DOCUMENTATION                   #
#-------------------------------------------------#
__END__

=head1 NAME

pixdir2html - makes thumbnails and custom html files for pictures

=head1 SYNOPSIS

B<pixdir2html.pl>  [-n,--no-menu]
                [-N,--no-index]
                [-f,--force] 
                [-M,--menu-only]
                [-E,--extension] 
                [-t,--thumbs-only]
                [-D,--directory] 
                [-l,--menu-links,--menu-td]
                [-m,--menu-type=[classic,modern]]
                [--menu-name=[menu]]
                [-c,--cut-dirs]
                [-F,--front-end=[Xdialog,zenity,console,...]]
                [--td]
                [--str-limit]
                [-h,--help]

=head1 DESCRIPTION 

For the Impatient:
    Passes current directory to script 
    shell> pixdir2html.pl 
    
    Force copies the "rootdir"/.pixdir2htmlrc
    to all other directories within this tree
    shell> pixdir2html.pl -f --directory="rootdir"
    
    To use this script in a non interactive way with Nautilus,
    make this file executable and put it in:
        ~/.gnome2/nautilus-scripts

    Then run it from from the File->Scripts menu in Nautilus

=head1 OPTIONS

=over 8

=item -n,--no-menu

do not create menu file after finishing creating thumbnails

=item -N,--no-index

do not create the index.EXT files after creating thumbnails

=item -f,--force

copy the .pixdir2htmlrc file from rootdir in every subdirectory

=item -M,--menu-only

only create a menu file and exit

=item -E,--extension 

extension to use for output files. Defaults to "html"

=item -t,--thumbs-only

generate thumbnail files only in thumbnail directory. Defaults to "t"

=item -D,--directory

directory containing all pictures to work with. Defaults to "."

=item -l,--menu-links,--menu-td

number of links to put in the Menu per row in classic menus. Default is 10

=item -m,--menu-type=[classic,modern]

menu type to use for albums (directories).
    Classic uses plain text menus.
    Modern lays menus vertically with a sample thumbnail and their name

=item --menu-name=[index]

name to use for menu files. Defaults to "menu"

=item -c,--cut-dirs

number of directories to cut from the classic Menu string. Default is 0

=item -F,--front-end=[Xdialog,zenity,console,...]

dialog to use to display progress. Must be compatible with Xdialog
or you can also choose "console" if you have Term::ProgressBar 
installed. Defaults to Zenity for Nautilus

=item --td

number of cells in e/a index file for classic Menus

=item --str-limit

size of the longest string allowed in menus. Defaults to unlimited

=item -h,--help

prints this help and exit

e.g.

cd /path/to/picture_directory

pixdir2html --extension="php"

is the same as:

pixdir2html -E php
 
You could customize each directory differently by having a
file named .pixdir2htmlrc in the directory containing the
pictures. Put a .nopixdir2htmlrc file in directories for which 
you do not want thumbnails and/or index.$EXT to be written. A
sample .pixdir2htmlrc should have the following:

uri=http://absolute.path.com/images # must be absolute. no trailing /

header=

percent=30% #size of the thumbnails for this folder

title=

meta=

stylesheet=http://absolute.path.com/styles/styles.css

html_msg=<h1 class="pdheader1">Free form using HTML tags</h1> 

body=<body bgcolor="#000000" class="pdbody">

p=<p class="pdparagraph">

table=<table border="0" class="pdtable">

td=<td valign="left" class="pdtd">

tr=<tr %%bgcolor%% class="pdtr">

new=http://absolute.path.com/images/new.png # for dirs with .new files

footer=<a href="#" class="pdlink">A footer here</a>

# set this to 1 to avoid printing a header

# or footer in the menu file menu.$EXT

menuheader_footer=0

ext=html

menutype=classic

# full path to a picture which will be used as the background image 

# for the album icons. album"s thumbnails must be exactly the 

# same size for this to look good.

albumpix=album.png  

A simple styles.css file should have things like:

.pdimage {
  border: 0;
}

.pdbody { 
  font-family: Verdana, Lucida, sans-serif;
  color: #ce7500;
  text-decoration: none;
  background: #ffffff;
  background-image: url("/path/to/images/image.png"); 
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-position: center;
}

.pdtd {
  vertical-align: top;
  padding: 2px 0px 0px 0px;
  font-family : "hoefler text", Tahoma, Helvetica, sans-serif;
  font-size : 11pt;
  color : #000000;
  text-decoration : none;
  background-color: transparent;
}

.pdtr {}

.pdparagraph {}

.pdtable {}

.pdlink a {
  vertical-align: top;
  padding: 2px 0px 0px 0px;
  color:  #7090A6;
  background-color: transparent;
  font-weight: bold;
  text-decoration:    none;
}

.pdlink a:visited  {
  vertical-align: top;
  padding: 2px 0px 0px 0px;
  text-decoration:    none;
  font-weight: bold;
  color:  #7090A6;
  background-color: transparent;
}

.pdlink a:hover {
  vertical-align: top;
  padding: 2px 0px 0px 0px;
  background-color: transparent;
  font-weight: bold;
  color:  #7090A6;
  text-decoration:    none;
}

=back

=head1 ENVIRONMENT

No environment variables are used.

=head1 AUTHORS

Luis Mondesi <lemsx1@gmail.com>

=head1 SEE ALSO

perl(1), pod2man(1), Image::Magick(3), Term::Progressbar(3)

=cut


Advertisement