#!/usr/bin/perl
use strict; $|++;
use warnings;
#
# Pick random flickr images for X11 wallpaper.
# -Rex Roof <code@rexroof.com>
#
use Getopt::Std;
use Imager;
use List::Util 'shuffle';
use LWP::Simple qw/get mirror/;
use Time::HiRes qw(time);
use Flickr::API;
use Data::Dumper;
my $height = 1024;
my $width = 1280;
$ENV{'DISPLAY'} = ":0.0";
my @wallpaper_cmd = ("/usr/X11R6/bin/hsetroot", "-full");
my $info_file = $ENV{'HOME'}.'/.slather.info';
sub findurl ($);
sub timewalk ($);
my $final_file = "slather_final-$$.jpg";
my $max_results = 4000; ## current bug in flickr. workaround below
require "/home/rex/flickr_keys.pl"; ## contains my flickr key
our ($api_key, $api_secret);
## this file contains lines like these, optionally use these lines and
## remove the above two lines: (replace with your own api key and secret, duh)
### my $api_key = "99999x9xx999999xxxx9x9xx99999x99" ;
### my $api_secret = "9xx9xxxx9x99x999";
my ($photos, @pics);
our($opt_i, $opt_t, $opt_s, $opt_f, $opt_u, $opt_d, $opt_o, $opt_q, $opt_T);
our $VERSION = 0.99;
getopts('t:idu:oqTs:f');
# tag we're searching for. I like food. (ignored if -i)
my $tag = $opt_t || 'food';
sub HELP_MESSAGE () {
print "slather: set x11 backgrounds from random flickr images\n";
print "Usage:\n";
print "\t -t [tag,tag,...] comma separated list of tags to search for\n";
print "\t -u [user] pick random pictures from one user\n";
print "\t -i use most recent top interesting photos (tags ignored)\n";
print "\t -d debug mode (just dumps flickr api result)\n";
print "\t -q be quiet\n";
print "\t -f Just fetch images (-o is implied)\n";
print "\t -s [num] number of screens (defaults to 2)\n";
print "\t -T print timing info\n";
print "\t -o write jpegs out to files.\n";
exit;
}
my $start = time;
my $response;
my ($method, $method_options);
timewalk(scalar(localtime).": script started");
my $api = Flickr::API->new({ 'key'=>$api_key, 'secret'=> $api_secret });
timewalk("api loaded");
my $nsid;
if ( $opt_u ) {
if ( $opt_u =~ m/^\d+\@...$/ ) {
# this looks like an nsid to me...
$nsid = $opt_u;
} else {
die "username not valid" unless ($opt_u =~ m/\w/);
$response = $api->execute_method('flickr.people.findByUsername',
{ username => $opt_u } );
$nsid = $response->{tree}->{children}->[1]->{attributes}->{nsid};
}
unless ( $nsid and $nsid =~ m/^\d+\@...$/ ) {
die "no nsid for username found.\n";
}
}
if ( $opt_i ) {
$method = 'flickr.interestingness.getList';
$method_options = { 'sort' => 'interestingness-desc',
'per_page' => 20,
'extras' => 'original_format,icon_server'
};
} else {
$method = 'flickr.photos.search';
$method_options = { 'tags' => $tag,
'sort' => 'interestingness-desc',
'per_page' => 200,
'extras' => 'original_format,icon_server'
};
if ( $opt_u and $nsid ) {
$method_options->{user_id} = $nsid;
unless ( $opt_t ) {
delete $method_options->{tags};
}
}
}
$opt_s = 2 unless ( defined $opt_s ) ;
print "calling $method with these options: \n";
print Dumper($method_options);
$response = $api->execute_method($method, $method_options);
timewalk("api response");
if ( defined $opt_d ) {
print Dumper($response);
exit;
}
my $result_count = $response->{tree}->{children}->[1]->{attributes}->{total};
die "no images found.\n" unless ($result_count);
## current flickr bug workaround.
# $result_count = $max_results if ($result_count > $max_results);
# my $pages = int($result_count / $per_page);
$photos = $response->{tree}->{children}->[1]->{children};
# only every other array element has a picture in it... so I remove the rest.
while ( $#$photos >= 0 ) {
pop(@$photos);
push(@pics, pop(@$photos));
}
timewalk("photos extracted");
# shuffle pics, and fill @selections with random picture urls that match:
#
#
@pics = shuffle(@pics);
timewalk("photos shuffled");
my @selections;
open I, ">$info_file" or die $!;
while ( $#selections < ($opt_s - 1) ) {
if ( my ($jpg,$url) = findurl(pop(@pics)) ) {
next unless ( $jpg );
push(@selections, $jpg);
print I $url;
print I $/;
}
}
close I or die $!;
timewalk("$opt_s qualifiying pics found");
# unlink "leftscreen.jpg", "rightscreen.jpg";
my @jpegdata;
foreach my $url ( @selections ) {
push(@jpegdata, get($url));
timewalk("... picture downloaded.");
die "no data found for $url " unless (length($jpegdata[-1]));
}
my $final_img = Imager->new(xsize=>($width * $opt_s),ysize=>$height);
my @imagers;
foreach ( my $i=0 ; $i <= $#jpegdata; $i++ ) {
push(@imagers, Imager->new);
timewalk("Imager object $i made.");
$imagers[-1]->read(data=>$jpegdata[$i]) or die $imagers[-1]->errstr;
timewalk("Imager data for #$i read.");
#$imagers[-1] = $imagers[-1]->scale(xpixels=>$width, ypixels=>$height);
$imagers[-1] = $imagers[-1]->scaleX(pixels=>$width);
$imagers[-1] = $imagers[-1]->scaleY(pixels=>$height);
timewalk("Imager object $i scaled.");
if ( defined($opt_o) or defined($opt_f) ) {
$imagers[-1]->write(file=> int($i)."_slather_$$.jpg");
timewalk("Image $i written.");
}
}
$final_img->paste(left=>0, top=>0, img=>(pop(@imagers)) );
timewalk("first image added to final image.");
foreach ( my $i=0 ; $i <= $#imagers; $i++ ) {
$final_img->paste(left=>(($width * ($i+1))+1), top=>0, img=>($imagers[$i]));
timewalk("Next image ($i) added to final image.");
}
$final_img->write(file=>$final_file);
timewalk("final image written");
exit if ( defined $opt_f );
if ( system("/usr/X11R6/bin/xset q 2>/dev/null >/dev/null") == 0 ) {
system(@wallpaper_cmd, $final_file);
warn "background seemingly slathered\n" unless ( defined $opt_q );
} else {
warn "display apparently not found.\n" unless ( defined $opt_q );
}
timewalk("display set");
unlink $final_file unless ( defined $opt_o );
sub findurl ($) {
my $ref = shift;
my $response = $api->execute_method('flickr.photos.getSizes', {
'photo_id' =>
$ref->{attributes}->{id}
});
my $pics = $response->{tree}->{children}->[1]->{children};
foreach my $img ( @{$pics} ) {
next unless ( $img->{attributes} );
my $h = $img->{attributes}->{height};
my $w = $img->{attributes}->{width};
# my criteria:
# width > 800
# 1.2 < (width/height) < 1.4 ## aspect ratio like wallpaper
next unless ( $w > 800 );
my $aspect = ($w/$h);
next if ( $aspect < 1.2 or $aspect > 1.4 );
# find the real url to the picture
$response = $api->execute_method('flickr.photos.getInfo', {
'photo_id' =>
$ref->{attributes}->{id}
});
my $photourl;
foreach my $h ( @{$response->{tree}->{children}->[1]->{children}} ) {
if ( defined($h->{name}) and $h->{name} eq 'urls' ) {
$photourl = $h->{children}->[1]->{children}->[0]->{content};
}
}
return ($img->{attributes}->{source}, $photourl);
}
return (undef, undef);
}
sub timewalk ($) {
return unless (defined $opt_T);
my $msg = shift;
print $msg;
print " ";
print (time - $start);
print " seconds from start.";
print $/;
}
syntax highlighted by Code2HTML, v. 0.9.1