#!/usr/bin/env perl # reads directory of images, converts to thumbnails & saves .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~

[% title %]

[% BLOCK tds; # no leading '/' on "images/$jpg" - relative to public_html %] ${t.jpg} [MP4 ${t.size} Mb] [% END %] [% i = 1; FOREACH t IN data; # hashrefs INCLUDE tds; "\n" UNLESS i % 4; # skips 1st 4 i = i + 1; END; %]
~; 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);