/ domm

I hack Perl for fun and profit.

Follow me on twitter!
Atom Icom ... on Atom!
<<<<<<<<<<
24.11.2015: Vienna.pm TechMeet
04.09.2015: Things I learned at YAPC::Europe 2015 in Granada
01.08.2015: Announcing Measure::Everything
26.07.2015: Announcing InfluxDB::LineProtocol
02.07.2015: How to notify 1/14th of your users every fortnight
14.06.2015: Make a playlist quickly
31.05.2015: Porting a very simple script to Perl6
10.05.2015: Things I learned at German Perl Workshop 2015
14.01.2015: Picture-of-the-day helper script

As you may have noticed, I'm currently trying to shoot one photo each day and post it here and on twitter. Until now it was fun, but copying and resizing the image was getting boring. And boring things are to be automated!

The Task

Each day, I have to do the following steps:

The Code

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Imager;
use Path::Class;
use File::Copy;
use DateTime;
use File::HomeDir;

my $raw = file( $ARGV[0] );
die "No such file $ARGV[0]" unless -e $raw;
my $not_scheduled = 1 if $ARGV[1];

my $home     = dir( File::HomeDir->my_home );
my $blio_src = $home->subdir(qw(privat domm.plix.at src potd));
my $now      = DateTime->now;
$now->add( days => 1 ) unless $not_scheduled;
my $basename   = $now->ymd('-');
my $target_img = $blio_src->file( $basename . '.jpg' );
my $target_txt = $blio_src->file( $basename . '.txt' );
if ( -e $target_img ) {
    say "target $basename.jpg already exists, aborting";
    exit;
}

my $image = Imager->new;
$image->read( file => $raw );
my $scaled = $image->scale( xpixels => 800 );
$scaled->write( file => $target_img );

move( $raw,
    $home->subdir(qw(media fotos 2015 potd))->file( $basename . '.jpg' ) );

my $publish_date = $basename . 'T10:00:00';
$target_txt->spew(
    <<EOBLIO
title: 
date: $publish_date
converter: textile
template: potd.tt

EOBLIO
);
system("vim $target_txt");

chdir( $target_img->parent );
system( join( ' ', 'git add ', $target_img, $target_txt ) );
system("git commit -m 'potd $basename'");
system('git push');

This is a rather simple and straight-forward, old-school Perl solution to my problem.

I declare a bunch of modules I'm going to use:

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Imager;
use Path::Class;
use File::Copy;
use DateTime;
use File::HomeDir;

I do some very basic command line parsing:

my $raw = file( $ARGV[0] );
die "No such file $ARGV[0]" unless -e $raw;
my $not_scheduled = 1 if $ARGV[1];

I could have used Getopt::Long or similar, but it's easy enough to just pop off the filename of the selected image from ARGV. $not_scheduled is a flag I can set if I do not want the blog post to be scheduled for the next day, but published immediately.

Now I define a bunch of variables I'm going to need:

my $home     = dir( File::HomeDir->my_home );
my $blio_src = $home->subdir(qw(privat domm.plix.at src potd));
my $now      = DateTime->now;
$now->add( days => 1 ) unless $not_scheduled;
my $basename   = $now->ymd('-');
my $target_img = $blio_src->file( $basename . '.jpg' );
my $target_txt = $blio_src->file( $basename . '.txt' );
if ( -e $target_img ) {
    say "target $basename.jpg already exists, aborting";
    exit;
}

File::HomeDir is very handy to figure out my home-dir. (I could have hardcoded it to /home/domm/). $blio_src defined the location where I want the image to be copied to. I use DateTime to figure out the current date and add a day unless I don't want to schedule the post. (Yes, this can result in a "bug" if I run the script after midnight and forget to add the not-scheduled-flag). I then use the very nice ymd method on the DateTime object to get something like 2015-01-14. This $basename is then used to generate the name of the image and text file. If the image file already exists, I abort, because I don't want to overwrite my old images. (ok, they are in git, but still...)

The next step is to resize the image to 800 pixels, which I do using Imager.

my $image = Imager->new;
$image->read( file => $raw );
my $scaled = $image->scale( xpixels => 800 );
$scaled->write( file => $target_img );

Instead of writing the image somewhere and then copy it to the right location (as listed in my initial spec), I just tell Imager to write the resized image to the final location. (I'm afraid this is the smartest part of this script...)

The next line moves the original image to my backup location

move( $raw,
    $home->subdir(qw(media fotos 2015 potd))->file( $basename . '.jpg' ) );

Now I create my blog post (which is a plain text file using some header-like fields):

my $publish_date = $basename . 'T10:00:00';
$target_txt->spew(
    <<EOBLIO
title: 
date: $publish_date
converter: textile
template: potd.tt

EOBLIO
);
system("vim $target_txt");

After preparing the data (no title, because I'll enter the title and some comments by hand; date set to the timestamp, at 10:00), I use spew (of Path::Class) to write the file. And then I just call vim, which opens an editor, so I can enter the title etc.

The last step is to commit the new files and push them:

chdir( $target_img->parent );
system( join( ' ', 'git add ', $target_img, $target_txt ) );
system("git commit -m 'potd $basename'");
system('git push');

I could have probably use some git wrapper, but just calling system is good enough for this simple set of commands.

And we're done!

Time saved

It took me a bit less than hour to write that script. The manual steps took me ~3 minutes. This year has 350 days left, so I'm going to save 350 * 3 - 60 = 990 minutes. Which means I can watch the upcoming episodes of The Walking Dead and Brooklyn Nine-Nine for "free", and still have some time left. Yay!

Next Steps

You can expect more blog posts as soon as I've solved this issues.

And for those of you who managed to read this far, here's a picture of my code!

Tags: ~/bin, Blio, potd

Comments (via disqus)

06.01.2015: Metaprogramming HTML::FormHandler
>>>>>>>>>>