File:Xmbc inotify.pl
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>
- !/usr/bin/perl -w
use strict; use Linux::Inotify2; use Path::Class; use Number::Bytes::Human; use File::stat; use Data::Dumper;
- JSON rpc call
use LWP::UserAgent; use HTTP::Request; use JSON::PP;
my $debug=1; ## just more verbose
- 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)
- only update xbmc / notify on these extentions
my @video_files = qw(avi mkv mpg mpeg mp4 mov wmv flv m1v m2v mpe);
- watched dirs - recursive
my @dirs = ("/Videos/", "/OtherVideoDir/",
);
- This requires the script from prowl app
- url: http://prowlapp.com/static/prowl.pl
my $prowl = {'enabled' => '0', 'script' => '/usr/local/bin/prowl.pl', 'api_key' => 'FIXME', 'app_name' => 'XBMC Inotify', };
- 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=$$;
- on start - lets scan the library
&jsonXBMC('VideoLibrary.Scan'); ¬ifyProwl('Initializing','program startup');
- 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
- 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); }); }
- log/notify status of watched dirs
my $init_s = "Watching $dirs directories"; &log($init_s,1); ¬ifyProwl('Initialized',$init_s);
- 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'; ¬ifyProwl($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'; ¬ifyProwl($title,$info); ## notify XBMC my %params = ( "title" => $title, "message" => $info, "displaytime" => 10000, ); &jsonXBMC('GUI.ShowNotification',\%params); @finish_list = ();
} if (@remove_list) {
¬ifyProwl('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); } } #¬ifyProwl('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"; ¬ifyProwl('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) {
¬ifyProwl('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/Time | Dimensions | User | Comment | |
---|---|---|---|---|
current | 23:38, 19 April 2013 | (8 KB) | Robertr (talk | contribs) |
File usage
The following page uses this file: