Added ability to set lock screen to setbg
[clearscm.git] / bin / setbg
index ddfa756..86a647a 100755 (executable)
--- a/bin/setbg
+++ b/bin/setbg
@@ -30,24 +30,43 @@ $Date: 2012/11/09 15:31:30 $
 
 =head1 SYNOPSIS
 
- Usage: setbg [-u|sage] [-ve|rbose] [-d|ebug] [-s|leep <n>] [-bgdir <bgdir>]
+ Usage: setbg [-u|sage] [-h|elp] [-ve|rbose] [-d|ebug] [-s|leep <n>]
+              [-bgdirs <bgdir> -bgdirs ...]
  
  Where:
 
  -u|sage:     Displays this usage
+ -h|elp:      Display full help
  -ve|rbose:   Be verbose
  -d|ebug:     Output debug messages
 
  -s|leep:     Number of minutes to sleep between setting the background
              (Default: 1 hour)
- -b|gdir:     Directory to scan for images (Default: /web/Pictures)
+ -b|gdirs:    Directories to scan for images
 
 =head1 DESCRIPTION
 
-This script sets the background image randomly based on images $imgDir. Note
-if this script is run again it senses that it was previously run and sends the
-previous script a SIGUSR2 which the script intrprets as "Change the background
-now", then exits.
+This script sets the background image randomly based on images found in bgdirs.
+Note if this script is run again it senses that it was previously run and sends
+the previous script a SIGUSR2 which the script intrprets as "Change the
+background now", then exits.
+
+Data is written to the following files:
+
+ ~/.setbg:      Contains the filename of the current background image
+ ~/.setbg.hist  Contains a history of all images displayed for this run
+ ~/.setbg.stats Contains statistical information for the current run
+
+Also note that this script will process a SIGUSR1 to mean "re-evaluate the
+contents of the bgdirs incase it has changed and display a new image". This is
+useful for script to be able to alert setbg that something has changed. For
+example, a script named rmbg might look at ~/.setbg to get the name of the
+current background image file and remove it then signal setbg with SIGUSR1 to
+have it re-evaluate the state of bgdirs. 
+
+Finally setbg will perform the this re-evaluation at midnight everyday. This is
+useful because we point setbg to look at -bgdirs from Dropbox where Camera 
+Uploads is included and new pictures can arrive everyday.
 
 =cut
 
@@ -57,74 +76,194 @@ use warnings;
 use FindBin;
 use Getopt::Long;
 use Proc::ProcessTable;
+use File::Spec;
+use CGI qw/:standard/;
 
 use lib "$FindBin::Bin/../lib";
 
+use Pod::Usage;
+
+use DateUtils;
 use Display;
+use Logger;
 use Utils;
 
-my $VERSION  = '$Revision: 1.10 $';
+my $VERSION  = '$Revision: 1.11 $';
   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
 
-my $processes = new Proc::ProcessTable;
+my $processes = Proc::ProcessTable->new;
+my %opts = (
+  sleep   => 60,
+  usage   => sub { pod2usage },
+  help    => sub { pod2usage (-verbose => 2)},
+  verbose => sub { set_verbose },
+  debug   => sub { set_debug },
+);
 
-foreach my $process (@{$processes->table}) {
-  if ($process->cmndline =~ /setbg/ and
-      $process->pid != $$) { 
-    kill 12, $process->pid;
+my %totals;
 
-    exit 0;
-  } # if
-} # foreach
+sub displayStats () {
+  my $statsFile = Logger->new(
+    name      => ".$FindBin::Script.stats",
+    path      => $ENV{HOME},
+    extension => '',
+  );
 
-$0 = "$FindBin::Script " . join ' ', @ARGV;
+  $statsFile->log('At ' . localtime());
+  $statsFile->log('Sleep: ' . $opts{sleep});
+  $statsFile->log('Image directories:');
 
-verbose "$FindBin::Script v$VERSION";
+  for (my $i = 0; $i < scalar @{$opts{bgdirs}}; $i++) {
+    $statsFile->log("\t$opts{bgdirs}[$i]: $opts{bgdircnt}[$i]")
+  } # for
 
-my $sleep  = 60 * 60;
-my $imgDir = $ENV{SETBG_DIR} ? $ENV{SETBG_DIR} : '/web/Pictures';
+  Stats \%totals, $statsFile;
 
-GetOptions (
-  'usage'              => sub { Usage },
-  'verbose'            => sub { set_verbose },
-  'debug'              => sub { set_debug },
-  'sleep=i'            => \$sleep,
-  'bgdir=s'            => \$imgDir,
-) || Usage;
+  return;
+} # displayStats
 
-error "$imgDir is not a directory", 1 unless -d $imgDir;
+sub fillPictures () {
+  my @images;
 
-# Using gsettings
-my $setbg      = "gsettings";
-my $setbgOpts  = "set org.gnome.desktop.background picture-uri \"file://";
+  $totals{bgdirs} = 0;
+
+  for (@{$opts{bgdirs}}) {
+    my @pics = `find "$_" -type f -name "*.jpg"`;
 
-chomp (my @images = `find $imgDir -type f -name "*.jpg"`);
+    chomp @pics;
+
+    push @images, @pics;
+    push @{$opts{bgdircnt}}, scalar @pics;
+
+    $totals{bgdirs}++;
+  } # for
+
+  $totals{images} = scalar @images;
+
+  return @images;
+} # fillPictures
+
+sub updateSetBG ($$) {
+  my ($bgimage, $lockimage) = @_;
+
+  open my $setbg, '>', "$ENV{HOME}/.$FindBin::Script"
+    or error "Unable to open $ENV{HOME}/.$FindBin::Script for writing - $!", 1;
+
+  display $bgimage,   $setbg;
+
+  close $setbg;
+
+  my $msg = localtime() . ":$bgimage lock:$lockimage";
+
+  open my $hist, '>>', "$ENV{HOME}/.$FindBin::Script.hist"
+    or error "Unable to open $ENV{HOME}/.$FindBin::Script.hist for append - $!", 1;
+
+  display $msg, $hist;
+
+  close $hist;
+
+  return;
+} # updateSetBG
 
 sub SwitchWallPaper {
   # We don't need to do anything here, just handle the interrupt and
   # let the while loop continue.
   debug 'SwitchWallPaper: Interrupt received';
+  displayStats;
+
+  return;
 } # SwitchWallPaper
 
+## Main
+verbose "$FindBin::Script v$VERSION";
+
+my @argvCopy = @ARGV;
+
+GetOptions (
+  \%opts,
+  'usage',
+  'help',
+  'verbose',
+  'debug',
+  'sleep=i',
+  'bgdirs=s@',
+) || Usage;
+
+local $0 = "$FindBin::Script " . join ' ', @argvCopy;
+
+for my $process (@{$processes->table}) {
+  if ($process->cmndline =~ /setbg/ and
+      $process->pid != $$) { 
+    kill 12, $process->pid;
+
+    exit 0;
+  } # if
+} # for
+
+for (my $i = 0; $i < scalar @{$opts{bgdirs}}; $i++) {
+  error "$opts{bgdirs}[$i] is not a directory", 1 unless -d $opts{bgdirs}[$i];
+
+  $opts{bgdirs}[$i] = File::Spec->rel2abs ($opts{bgdirs}[$i]);
+} # for
+
+# Using gsettings
+my $setbg       = "gsettings";
+my $setbgOpts   = "set org.gnome.desktop.background picture-uri \"file://";
+my $setLockOpts = "set org.gnome.desktop.screensaver picture-uri \"file://";
+
+my @images = fillPictures;
+
+Usage "No images to display. Must specify -bgdirs" unless @images;
+
 $SIG{USR2} = \&SwitchWallPaper;
+$SIG{USR1} = \&fillPictures;
 
 my $debugger = $DB::OUT;
+my $today;
+
+truncate "$ENV{HOME}/.$FindBin::Script.hist", 0;
 
 EnterDaemonMode unless defined $DB::OUT;
 
 while () {
-  my $image = $images[int (rand $#images)];
+  my $bgimage   = escapeHTML ($images[int (rand $#images)]);
+  my $lockimage = escapeHTML ($images[int (rand $#images)]);
+
+  my $cmd = "$setbg $setbgOpts$bgimage\" 2> /dev/null";
 
-  open my $log, '>', "$ENV{HOME}/.$FindBin::Script"
-    or error "Unable to open $ENV{HOME}/.setbg for writing - $!", 1;
+  my @output = `$cmd`;
 
-  display $image, $log;
+  if ($? != 0) {
+    error "Trying to set background - command used \"$cmd\"\n\nOutput\n\n" . 
+      join "\n", @output;
+    $totals{errors}++;
+  } else {
+    $totals{'Images displayed'}++;
+  } # if
 
-  my $cmd = "$setbg $setbgOpts$image\" 2> /dev/null";
+  $cmd = "$setbg $setLockOpts$lockimage\" 2> /dev/null";
 
-  `$cmd`;
+  @output = `$cmd`;
 
-  close $log;
-  
-  sleep $sleep;
+  if ($? != 0) {
+    error "Trying to set lock screen - command used \"$cmd\"\n\nOutput\n\n" .
+      join "\n", @output;
+    $totals{errors}++;
+  } else {
+    $totals{'Lock screens displayed'}++;
+  } # if
+
+  updateSetBG $bgimage, $lockimage;
+
+  displayStats;
+
+  $today = YMD;
+
+  sleep $opts{sleep} * 60;
+
+  if ($today ne YMD){
+    @images = fillPictures;
+
+    displayStats;
+  } # if
 } # while