#!/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