RSS Git Download  Clone
Raw Blame History
#!/usr/bin/env perl

# reads directory of images, converts to thumbnails & saves <dayname>.html
# in ~/public_html
# requires motion to save video as mp4 (version 4+) or mkv
# relies on identical ctime of jpg & video files (have different filename timestamps)
# mp4 files stream in browser, mkv downloads and opens in default player

#==============================================================================
my $www_html_dir = '/home/pi/public_html/'; # trailing '/' for appending
my $img_dir_name = 'images'; # subdir of www html dir
my $img_src_dir  = '/media/usb/picam';
my $dimensions   = '320x240'; # thumbnail size
my @filetypes    = qw(jpg mp4 mkv); # permitted filetypes in picam dir
#==============================================================================

use lib '/home/pi/perl5/lib/perl5';

use Getopt::Std;
getopts('d:'); # days
our($opt_d); # warn $opt_d;

use Image::Magick;
use Data::Printer;
use Modern::Perl;
use DateTime;
use Template;
use IO::All;

my $duration = $opt_d || 0;
# ref date is -d value, or time now minus 1 hr (to allow for midnight run):
my @date_args = $duration ? (days => $duration) : (hours => 1); # p @date_args;
my $ref_date  = DateTime->now->subtract(@date_args); # p $ref_date->ymd; exit;

my $permitted_filetypes = join '|', @filetypes;

my $www_img_dir = $www_html_dir . $img_dir_name; # p $www_img_dir;
my $html_file   = $www_html_dir . lc $ref_date->day_name . '.html'; # p $html_file;

# sort contents by ctime, then file extension - ensures jpg before mp4/mkv:
my @contents =
    sort { $a->ctime <=> $b->ctime || $a->ext cmp $b->ext } 
        grep { DateTime->from_epoch(epoch => $_->ctime)->ymd eq $ref_date->ymd }
            grep { $_->filename =~ /($permitted_filetypes)$/ }
                io($img_src_dir)->all_files; # p $_->filename for @contents; exit;
    # say join ':', $_->ctime, $_->filename for @contents; exit;

# hashmap of jpg => mp4/mkv [name & size]:
my %video_map;
{
    # 1st create hash of ctime => [jpg + mp4/mkv] pairs:
    my %ctimes;
    for my $f (@contents) {
        push @{ $ctimes{$f->ctime} },
            $f->ext eq 'jpg'
            ? $f->filename
            : { mpg => $f->filename, size => $f->size },
    } # p %ctimes; exit;
    # check for existence of 2nd element in case orphaned file:
    %video_map = map { $_->[0] => $_->[1] } grep $_->[1], values %ctimes;
} # p %video_map;  exit;

my @rows;
my $i = 0;
for my $f (@contents) {
    next unless $f->ext eq 'jpg'; # skip mpgs
    # create new jpg unless already exists:
    my $new = join '/', $www_img_dir, $f->filename; # warn $new;
    unless (-e $new) { # skip if jpg already exists
        my $iMagic = Image::Magick->new; # new ImageMagick object for each image
        my $x = $iMagic->Read($f->file); warn $x if $x;
        $x = $iMagic->Resize(geometry => $dimensions); warn $x if $x;
        say "writing $new";
        $iMagic->Write($new); warn $x if $x;
        undef $iMagic; # returns memory asap
    }
    my $jpg  = $f->filename;
    my $mpg  = $video_map{$jpg}{mpg};
    my $size = sprintf '%.1f', $video_map{$jpg}{size} / 1_000_000; # bytes to Mb
    push @rows, { jpg => $jpg, mpg => $mpg, size => $size };
} # p @rows; exit;

my $title = join ' ', $ref_date->day_abbr, $ref_date->dmy;
my $tmpl  = q~<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    .picam span { font-size: small; font-weight: bold; }
  </style>
</head>
<body>
    <h2>[% title %]</h2>
    [% BLOCK tds; # no leading '/' on "images/$jpg" - relative to public_html %]
        <td> 
            <a target="_new" href="/stream/${t.mpg}">
                <img src="images/${t.jpg}" />
            </a>
            <span>${t.jpg} [MP4 ${t.size} Mb]</span>
        </td>
    [% END %]
    <table class="picam">
        <tr>
            [%  i = 1; 
                FOREACH t IN data; # hashrefs
                    INCLUDE tds;
                    "</tr>\n<tr>" UNLESS i % 4; # skips 1st 4
                    i = i + 1;
                END;
             %]
        </tr>
    </table>
</body>
</html>
~;
my $html;
my $tt = Template->new({ INTERPOLATE => 1 });
$tt->process(\$tmpl, { data => \@rows, title => $title }, \$html)
    || die $tt->error(), "\n"; # p $html; exit;
io($html_file)->print($html);