File:Xmbc inotify.pl

From RARForge
Jump to navigation Jump to search

Xmbc_inotify.pl(file size: 8 KB, MIME type: application/x-perl)

Warning: This file type may contain malicious code. By executing it, your system may be compromised.

<source lang=perl>

  1. !/usr/bin/perl -w

use strict; use Linux::Inotify2; use Path::Class; use Number::Bytes::Human; use File::stat; use Data::Dumper;

    1. JSON rpc call

use LWP::UserAgent; use HTTP::Request; use JSON::PP;

my $debug=1; ## just more verbose


  1. Define required credentials.

my $jsonUser = "xbmc"; my $jsonPass = "<YOU XBMC password>"; my $jsonHost = "localhost:8080";

my $wait=60; ## how many seconds to wait after proccessing an event. This will allow us to group events/updates. (60 seconds default)

    1. only update xbmc / notify on these extentions

my @video_files = qw(avi mkv mpg mpeg mp4 mov wmv flv m1v m2v mpe);

    1. watched dirs - recursive

my @dirs = ("/Videos/", "/OtherVideoDir/",

   );
    1. This requires the script from prowl app
    2. url: http://prowlapp.com/static/prowl.pl

my $prowl = {'enabled' => '0', 'script' => '/usr/local/bin/prowl.pl', 'api_key' => 'FIXME', 'app_name' => 'XBMC Inotify', };

                                                                                                              1. Configuration DONE #######################################################

my @files; my $inotify = Linux::Inotify2->new

   or die "unable to create new inotify object: $!";

my $host=`hostname`; ## maybe used for later my $pid=$$;

    1. on start - lets scan the library

&jsonXBMC('VideoLibrary.Scan'); &notifyProwl('Initializing','program startup');


    1. setup initial watch dirs

my $dirs =0; my $update_xbmc=0; my $clean_xbmc=0; my @start_list; ## used for notifications my @finish_list; ## used for notifications my @remove_list; ## used for notifications

    1. Intialize watched dirs - INIT

foreach my $drop_dir(@dirs) {

   &log("Processing subdirs for: $drop_dir\n",1);
   my $dir = dir($drop_dir);
   my $c = 0;
   $dir->traverse(sub{

my ($child, $cont, $indent) = @_; if ($child->is_dir) { $dirs++; &log("subdir: $child",1); $inotify->watch("$child", IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_TO | IN_DELETE , \&MyWatch);

## in_modify if too verbose.. it grabs any changes to file before final close ## IN_CLOSE_WRITE == after a file is written too/closed ## IN_CREATE == new directories/files ## IN_MOVED_TO == moved directory/files (to watch dirs only) } $cont->($c + 1); }); }

    1. log/notify status of watched dirs

my $init_s = "Watching $dirs directories"; &log($init_s,1); &notifyProwl('Initialized',$init_s);

    1. LOOP to keep watching dirs/files

while (1) {

   $inotify->poll;
   my $had_event = 0;
   ## notify on sync start and finish
   if (@start_list)  {  

my $info = join(', ', @start_list); my $title = 'rSync Started'; &notifyProwl($title,$info); ## notify XBMC my %params = ( "title" => $title, "message" => $info, "displaytime" => 10000, ); &jsonXBMC('GUI.ShowNotification',\%params); @start_list = ();

   }
   if (@finish_list) {  

my $info = join(', ', @finish_list); my $title = 'rSync Finished'; &notifyProwl($title,$info); ## notify XBMC my %params = ( "title" => $title, "message" => $info, "displaytime" => 10000, ); &jsonXBMC('GUI.ShowNotification',\%params); @finish_list = ();

   }
   if (@remove_list)  { 

&notifyProwl('Removed',join(', ', @remove_list)); @remove_list = ();

   }


   if ($update_xbmc) {

$had_event = 1; $update_xbmc = 0; &log("Updating XBMC library"); &jsonXBMC('VideoLibrary.Scan');

   }
   if ($clean_xbmc) {

$had_event = 1; $clean_xbmc = 0; &log("Cleaning XBMC library"); &jsonXBMC('VideoLibrary.Clean');

   }
   if ($had_event) {

&log("Sleeping '$wait' seconds before processing any new events"); sleep($wait); &log("I\'m awake again - ready to process any new events");

   }

}


sub MyWatch() {

   #$inotify->watch("$child",  IN_CLOSE_WRITE | IN_MOVED_TO , sub {
   my $event = shift;
   my $name = $event->fullname;		
   my $file_name = $event->name;		
   ## continue on..
   my $log = 'unknown';
   if ($event->IN_IGNORED) {

$event->w->cancel; ## cancel watch

#$update_xbmc = 1; frodo doesn't work well yet with deleting after update.. so enableing clean again $log = "DIR $name removed -- cancelling watch"; foreach my $ext (@video_files) { $clean_xbmc = 1; ## only clean if we care if ($name =~ /\.$ext/i) { push (@remove_list,$name); } } #&notifyProwl('removed',$log); ## remove watch - if directory

   } elsif ( $event->IN_DELETE) {

## this is a file - so nothign really to do other than notify $log = "FILE: $name removed"; ## group deletes together -- otherwise.. flurry of prowl notify foreach my $ext (@video_files) { $log = "FILE: VIDEO $name removed - will notify prowl"; $clean_xbmc = 1; if ($name =~ /\.$ext/i) { push (@remove_list,$name); } }

   } else {		

if (-d $name) { $inotify->watch($name, IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_TO , \&MyWatch); $log = "DIR: $name created -- adding to watchlist"; &notifyProwl('new',$log); } elsif (-f $name && $event->IN_CREATE) { ## file is created, but has not finished writing - do not update xbmc ### this is where we would notify on start sync -- only notify on files we watch $log = "$name is FILE -- in_create called.. waiting for IN_CLOSE_WRITE to process"; foreach my $ext (@video_files) { ## push new files to start_list (sync started notifications) if ($file_name =~ /\.$ext/i) { push (@start_list,$name); } } } else { $log = "$name is IN_CLOSE_WRITE" if $event->IN_CLOSE_WRITE; $log = "$name is IN_CREATE" if $event->IN_CREATE; $log = "$name is IN_MOVED_TO" if $event->IN_MOVED_TO; $log = "events for $name have been lost\n" if $event->IN_Q_OVERFLOW; if ($file_name =~ /^\..*\.\w{5}$/) { &log("$file_name must be rsync - skip it"); } else { ## only update video files foreach my $ext (@video_files) { ## push new files to finish_list (sync finished notifications) if ($file_name =~ /\.$ext$/i) { ## SIZE OF FILE my $human = Number::Bytes::Human->new(); my $size = stat($name)->size; my $hsize = $human->format($size); push (@finish_list,"[$hsize] $name"); &log("$name $ext is video file -- update xbmc"); $update_xbmc = 1; ## new videos - set update xbmc } } if (!$update_xbmc) {&log("$file_name is NOT a video file -- skipping update xbmc"); } } }

   }
   &log($log);

}


sub log() {

   my $msg = shift;
   my $print= shift;
   if ($debug || $print) {

print localtime . ": $msg\n";

   }
   system("logger  -t $0\[$pid\] \"$msg\"");

}


sub jsonXBMC() {

   my $method = shift;
   my $tmp = shift;
   my %params;
   if ($tmp) {

%params = %$tmp;

   }
   # Construct JSON RPC URL.
   my $jsonUrl = sprintf("http://%s:%s@%s/jsonrpc",

$jsonUser, $jsonPass, $jsonHost,);

   my %hash = ("jsonrpc" => "2.0",

"method" => "$method", "params" => \%params, "id" => $method, );

   #my $json = encode_json \%hash;
   my $js = JSON::PP->new;
   $js->canonical(1);
   my $json = $js->encode(\%hash);
   
   # Setup a new HTTP Request object.
   my $http = HTTP::Request->new('POST', $jsonUrl);
   
   $http->header('Content-Type' => 'application/json');
   $http->content($json);
   
   # Fire off the request.
   my $ua  = LWP::UserAgent->new;
   my $res = $ua->request($http);
   
   # Return the HTTP status and exit.
   my $result = sprintf("XBMC JSON-RPC $method: host:$jsonHost, user:$jsonUser, pass:<hidden>, Result: %s\n", $res->status_line);
   &log($result);
   if ($res->status_line !~ /200\s+OK/i) {

&notifyProwl('XBMC JSON: ' . $method,$res->status_line);

   }

}


sub notifyProwl() {

   if (defined($prowl->{enabled}) && $prowl->{enabled} == 1) {

my ($event,$msg) = @_; my $cmd = sprintf("perl %s -apikey='%s' -application='%s' -event='%s' -notification='%s'",$prowl->{script}, $prowl->{api_key}, $prowl->{app_name}, $event, $msg); my $res = `$cmd`; &log("Notify Prowl Event: $cmd\n"); &log("Notify: Prowl Result: $res\n");

   }

}

</source>

File history

Click on a date/time to view the file as it appeared at that time.

Date/TimeDimensionsUserComment
current23:38, 19 April 2013 (8 KB)Robertr (talk | contribs)

The following page uses this file: