Album

 view release on metacpan or  search on metacpan

script/album  view on Meta::CPAN

#!/usr/bin/perl -w

# Author          : Johan Vromans
# Created On      : Tue Sep 15 15:59:04 2002
# Last Modified By: Johan Vromans
# Last Modified On: Wed Jul  8 16:55:54 2026
# Update Count    : 3376
# Status          : Unknown, Use with caution!

################ Common stuff ################

use strict;

# Package or program libraries, if appropriate.
# $LIBDIR = $ENV{'LIBDIR'} || '/usr/local/lib/sample';
# use lib qw($LIBDIR);
# require 'common.pl';

use Album;

# Package name.
my $my_package = 'Sciurix';
# Program name and version.
my $my_name = "album";
my $my_version = $Album::VERSION;

my $creator = qq{Created with <a href="https://metacpan.org/dist/Album">Album</a> $my_version};

################ Command line parameters ################

use Getopt::Long 2.13;

# Command line options.
my $import_exif = 0;
my $import_dir;
my $update = 0;			# add new from large/import
our $dest_dir = ".";		# needs occasional 'local'
my $info_file;
my $linkthem = 1;		# link orig to large, if possible
my $clobber = 0;		# overwrite medium/thumbnails
my $mediumonly = 0;		# only medium size (for web export)
my $forcemedium = 0;		# force medium size if large is smaller
my $externalize_css = 0;	# create external css files
my $externalize_formats = 0;	# create external format files
my $select = 'default';		# select images
my $verbose = 1;		# verbose processing

# These are left undefined, for set_defaults. Note: our, not my.
our $index_columns;
our $index_rows;
our $thumb;
our $medium;			# medium size, between large and small
our $album_title;
our $caption;
our $datefmt;
our $icon;
our $locale;
our $lib_common;
our $home_link;
our $skew;			# time skew

# These are not command line options.
my $journal;			# create journal
my $encoding;			# info_file encoding

# Development options (not shown with -help).
my $debug = 0;			# debugging
my $trace = 0;			# trace (show process)
my $test = 0;			# test mode.

# Process command line options.
app_options();

# Post-processing.
$trace |= ($debug || $test);
$dest_dir =~ s;^\./;;;
$import_dir =~ s;^\./;; if $import_dir;

################ Presets ################

use constant DEFAULTS => { info       => "info.dat",
			   title      => "Photo Album",
			   medium     => 0,
			   mediumsize => 915,
			   thumbsize  => 200,
			   indexrows  => 3,
			   indexcols  => 4,
			   caption    => "fct",
			   captionmin => "f",
			   dateformat => '%F',
			   icon	      => 0,
			 };

my $TMPDIR = $ENV{TMPDIR} || $ENV{TEMP} || '/usr/tmp';

my $picpat = qr{(?i:jpe?g|png|gif|nef|webp)};
my $movpat = qr{(?i:mpe?g|mov|avi|mp4|mts)};
my $xtrpat = qw{(?i:html?)};
my $suffixpat = qr{\.$picpat|$movpat};
my $xsuffixpat = qr{\.$picpat|$movpat|$xtrpat};

my %capfun = ('c' => \&c_caption,
	      'f' => \&f_caption,
	      's' => \&s_caption,
	      't' => \&t_caption,
	     );

my $br = br();

# Max.number of clickable index numbers (should be odd).
use constant IXLIST => 15;

# Stylesheets version.
my $css_major = 1;
my $css_minor = 0;

# Formats version.
my $fmt_major = 1;
my $fmt_minor = 0;

# Helper programs
my $prog_jpegtran;#  = findexec("jpegtran");
my $prog_mplayer   = findexec("mplayer");
my $prog_mencoder  = findexec("mencoder");

################ The Process ################

use File::Spec;
use File::Path;
use File::Basename;
use Time::Local;
use Image::Info;
use Image::ExifTool;
use Image::Magick;
use Data::Dumper;
use POSIX qw(locale_h strftime);
use locale;

# The files already there, if any.
my $gotlist = new FileList;
# The files in the import dir, if any.
my $implist = new FileList;

# The list of files, in the order to be processed.
# This list is initialy filled from info.dat, and (optionally) updated
# from the other lists.
my $filelist = new FileList;

# This is the list of all entries to be journalled (all images, plus
# possible interspersed loose annotations).
my @journal;

# Load cached info, if possible.
load_cache();

# Load image names and info from the info file, if any.
# This produces the initial file list.
load_info();
#print STDERR Data::Dumper->Dump([$filelist],[qw(filelist)]);

# Load image names and info for files we already got.
load_files()  if -d d_large();
#print STDERR Data::Dumper->Dump([$gotlist],[qw(gotlist)]);

# Load image names and info for files we can import.
load_import() if $import_dir && -d $import_dir;
#print STDERR Data::Dumper->Dump([$implist],[qw(implist)]);

# Apply defaults to unset parameters.
set_defaults();

# warn("date => ", strftime($datefmt, localtime(time)), "\n");

# Verify and update the file list.
my $added = update_filelist();

# Perform selection. Normally, hidden entries are ignored.
# Option --select=all overrides this.
$filelist = $filelist->filter($select);

#print STDERR Data::Dumper->Dump([$filelist],[qw(filelist)]);

my $num_entries = $filelist->tally;
print STDERR ("Number of entries = $num_entries",
	      $added ? " ($added added)" : "",
	      "\n") if $verbose > 1;
die("Nothing to do?\n") unless $num_entries > 0;
exit(0) if $test;

# Clean up and create directories.
if ( $clobber ) {
    rmtree([d_index(), d_medium()], $verbose > 1);
    rmtree([d_journal()], $verbose > 1);
}
mkpath([d_index(), d_large(), d_icons()], $verbose > 1);
mkpath([d_medium()], $verbose > 1) if $medium;

script/album  view on Meta::CPAN

sub hjoin	 { join("/", @_); }

# $fjoin will be dynamically switched depending on context.
our $fjoin; INIT { $fjoin = \&fjoin }

sub d_dest       { unshift(@_, $dest_dir) unless $dest_dir eq ".";
		   $fjoin->(@_); }
sub d_index      { unshift(@_, "index");      goto &d_dest; }
sub d_large      { unshift(@_, "large");      goto &d_dest; }
sub d_medium     { unshift(@_, "medium");     goto &d_dest; }
sub d_journal    { unshift(@_, "journal");    goto &d_dest; }
sub d_up	 { unshift(@_, "..");         goto &d_dest; }

sub d_destc      { unshift(@_, $lib_common) if $lib_common; goto &d_dest; }
sub d_icons      { unshift(@_, "icons");      goto &d_destc; }
sub d_css        { unshift(@_, "css");        goto &d_destc; }
sub d_fmt        { unshift(@_, "formats");    goto &d_destc; }

my %optcfg;			# option set from config files

sub setopt {
    no strict qw(refs);
    return if defined(${$_[0]});
    print STDERR ("setopt $_[0] -> $_[1]\n") if $trace;
    ${$_[0]} = $_[1];
    $optcfg{$_[0]} = 1;
}

sub parse_line {
    local ($_) = (@_);
    my $err = 0;

    if ( /^!?\s*(\S.*)/ ) {
	$_ = $1;
	if ( /^title\s+(.*)/ ) {
	    setopt("album_title", $1);
	}
	elsif ( /^page\s+(\d+)x(\d+)/ ) {
	    setopt("index_rows", $1);
	    setopt("index_columns", $2);
	}
	elsif ( /^thumbsize\s*(\d+)/ ) {
	    setopt("thumb", $1);
	}
	elsif ( /^mediumsize\s*(\d+)(!)?/ ) {
	    setopt("medium", $1);
	    $forcemedium = defined $2;
	}
	elsif ( /^medium\s*(-?\d+)?/ ) {
	    setopt("medium", $1 || DEFAULTS->{mediumsize});
	}
	elsif ( /^dateformat\s*(.*)/ ) {
	    setopt("datefmt", $1);
	}
	elsif ( /^caption\s*(.*)/ ) {
	    setopt("caption", $1);
	}
	elsif ( /^icon\s*(.*)/ ) {
	    setopt("icon", defined($1) && length($1) ? $1 : 1);
	}
	elsif ( /^locale\s*(.*)/ ) {
	    setopt("locale", $1);
	}
	elsif ( /^depth\s+(\d+)/ ) {
	    # lib_common is used in the HTML, don't use fjoin.
	    setopt("lib_common", join("/", ("..") x $1));
	}
	elsif ( /^home\s+(.+)/ ) {
	    setopt("home_link", $1);
	}
	elsif ( /^skew\s+(.+)/ ) {
	    setopt("skew", $1);
	}
	else {
	    warn("Unknown control: $_[0]\n");
	    $err++;
	}
    }
    else {
	warn("Invalid control: $_[0]\n");
	$err++;
    }
    $err;
}

sub set_defaults {
    # Load settings from user files.
    my $sl;
    unless ( $sl = $ENV{ALBUMCONFIG} ) {
	$sl = ".albumrc";
	$sl .= ":".$ENV{HOME}."/.albumrc" if $ENV{HOME};
    }
    foreach my $cf ( split(/:/, $sl) ) {
	unless ( -f $cf ) {
	    warn("$cf: $!\n") if $ENV{ALBUMCONFIG};
	    next;
	}
	open(my $fh, "<", $cf) || next;
	warn("parsing: $cf\n") if $trace;
	my $err = 0;
	while ( <$fh> ) {
	    next if /^\s*#/;
	    next unless /\S/;
	    $err += parse_line($_);
	}
	close($fh);
	die("Errors in config file $cf, aborted\n") if $err;
    }

    # Finally, apply defaults if necessary.
    warn("apply defaults\n") if $trace;
    setopt("album_title",   DEFAULTS->{title});
    setopt("index_rows",    DEFAULTS->{indexrows});
    setopt("index_columns", DEFAULTS->{indexcols});
    setopt("thumb",         DEFAULTS->{thumbsize});
    setopt("datefmt",       DEFAULTS->{dateformat});
    setopt("icon",          DEFAULTS->{icon});

    $medium = DEFAULTS->{mediumsize} if defined($medium) && !$medium || $mediumonly;
    $medium = 0 if defined($medium) && $medium < 0;

    # Caption values.
    setopt("caption", DEFAULTS->{( -s $info_file || $import_dir) ?
				 "caption" : "captionmin" });
    die("Invalid value for caption: $caption\n")
      unless $caption =~ /^[fsct]*$/i;
    $caption = lc($caption);

    if ( $locale ) {
	setlocale(LC_TIME, $locale);
	setlocale(LC_COLLATE, $locale);
    }

    if ( defined($lib_common) ) {
	$lib_common =~ s;/+$;;;
    }
    $lib_common ||= "";
}

sub load_info {
    my %typemap = ( 'p' => T_JPG, 'm' => T_MPG, 'v' => T_VOICE );

    # If an info has been supplied, it'd better exist.
    if ( $info_file ) {
	die("$info_file: $!\n") unless -s $info_file;
    }
    else {
	# Try default.
	$info_file = d_dest(DEFAULTS->{info});
	unless ( -s $info_file ) {
	    my $add_new; $add_new++ if $import_dir;
	    my $add_src; $add_src++ if -d d_large();
	    print STDERR ("No ", d_dest(DEFAULTS->{info}));
	    print STDERR (", adding images from ") if $add_src || $add_new;
	    print STDERR (d_large())               if $add_src;
	    print STDERR (" and ")                 if $add_src && $add_new;
	    print STDERR ($import_dir)             if $add_new;
	    print STDERR ("\n");
	    return;
	}
    }

    my $err = 0;
    my $file;
    my $tag;

    my $fh = do { local *FH; *FH };
    die("$info_file: $!\n")
      unless open($fh, "<:encoding(UTF-8)", $info_file);
    warn("parsing: $info_file\n") if $trace;

    my $el;
    my %dirs;

    while ( <$fh> ) {
	chomp;

	# Detection of condig system for info_file.
	# Uses GNU Emacs syntax, e.g.,
	#  # blah        -*- mode: album; coding: utf-8 -*-
	if ( $. == 1
	     &&
	     m/^\s*\#			# start with #
	      .*			# arb
	      -\*-			# -*-
	      (?:.*?;)*			# things, must be ; terminated
	      \s*			# ws
	      coding\s*:\s*([\w\d-]+)	# coding: utf-8
	      \s*			# ws
	      (?:;.*)*			# things, must be ; started
	      -\*-			# -*-



( run in 1.214 second using v1.01-cache-2.11-cpan-941387dca55 )