XBMC Library Updater
Re: XBMC Library Updater
Please do! It's great to share our work
Re: XBMC Library Updater
Here's a Perl script I use to perform some automated functions on my XBMC HTPC.
A few notes:
Enjoy!
Scott
A few notes:
- It probably has bugs.
It should use GetOpt but doesn't.
It could be coded better but isn't (please don't tell me how it could be).
It should be commented in-line but isn't.
You need to have the XBMC web server enabled (I use port 8080).
You'll need RPC::Client installed
Most called to XBMC are asynchronous, so they return immediately. (ie, you should wait after calling a 'clean' before calling an 'update').
Some calls only work on Frodo (RPC 6 I think), like 'GUI.ShowNotification'.
I have a three XBMC HTPCs (one on OSX, two on ATVs) so there is code there to let me choose which one the code runs against. Delete this and hardcode '$host' if you like.
The 'ping' code there is because my HTPC sleeps when not being used and needs to be woken sometimes. The ping call expects to run on FreeBSD. YMMV. Remove it if you have trouble.
Code: Select all
use strict;
use warnings;
use JSON::RPC::Client;
use Data::Dumper;
my $client = new JSON::RPC::Client;
my $method; my $title; my $message; my $verbose = 0; my $silent = 0; my $host = ''; my $addon_id;
my $timeout = 5; my $notify_time = 1500;
sub bail () { die "Error: please specify a method (scan/update music|video, clean music|video, library, notify, quit, ping, version, sleep, wake, fullscreen, artwork, addon 'addon')"; exit 0; };
if (defined $ARGV[0] and $ARGV[0] eq '-v') { $verbose = 1; shift @ARGV; }
if (defined $ARGV[0] and $ARGV[0] eq '-s') { $silent = 1; shift @ARGV; }
if (defined $ARGV[0] and $ARGV[0] eq 'atv-bedroom') { $host = 'atv-bedroom'; shift @ARGV; }
elsif (defined $ARGV[0] and $ARGV[0] eq 'atv-main') { $host = 'atv-main'; shift @ARGV; }
elsif (defined $ARGV[0] and $ARGV[0] eq 'htpc-main') { $host = 'htpc-main'; shift @ARGV; }
else { $host = 'htpc-main'; }
$client->ua->credentials("$host:8080",'XBMC','xbmc'=>'xbmc',);
my $pingcheck = "/sbin/ping -n -c 2 -i 1 -W 500 -o $host 2>&1 >/dev/null";
if (!defined $ARGV[0]) { bail; }
if ($ARGV[0] =~ /^(scan|update)$/i) { $method = 'Library.Scan'; $ARGV[1] or $ARGV[1] = 'video'; if ($ARGV[1] =~ m/music/i) { $method = "Audio$method" } else { $method = "Video$method" } }
elsif ($ARGV[0] =~ /^clean$/i) { $method = 'Library.Clean'; $ARGV[1] or $ARGV[1] = 'video'; if ($ARGV[1] =~ m/music/i) { $method = "Audio$method" } else { $method = "Video$method" } }
elsif ($ARGV[0] =~ /^library$/i) { $method = 'VideoLibrary.'; $timeout = 60; if ($ARGV[1] =~ m/tv/i) { $method .= 'GetTVShows' } else { $method .= 'GetMovies' } }
elsif ($ARGV[0] =~ /^notify$/i) { $method = 'GUI.ShowNotification'; $title = $ARGV[1] || 'empty'; $message = $ARGV[2] || "empty"; $notify_time = int $ARGV[3] || 1500 }
elsif ($ARGV[0] =~ /^(ping|wake)$/i) { $method = 'JSONRPC.Ping' }
elsif ($ARGV[0] =~ /^version$/i) { $method = 'JSONRPC.Version' }
elsif ($ARGV[0] =~ /^quit$/i) { $method = 'Application.Quit' }
elsif ($ARGV[0] =~ /^sleep$/i) { $method = 'System.Suspend' }
elsif ($ARGV[0] =~ /^fullscreen$/i) { $method = 'GUI.SetFullscreen' }
elsif ($ARGV[0] =~ /^addon$/i) { $method = 'Addons.ExecuteAddon'; $addon_id = $ARGV[1] or die }
elsif ($ARGV[0] =~ /^artwork$/i) { $method = 'Addons.ExecuteAddon'; $addon_id = 'script.artwork.downloader'; }
else { bail }
$client->ua->timeout($timeout);
my $url = "http://$host:8080/jsonrpc";
my $pingobj = { jsonrpc=>'2.0', id=>'1', method=>'JSONRPC.Ping', };
my $sleepobj = { jsonrpc=>'2.0', id=>'1', method=>'System.Suspend', };
my $json_true = JSON::true;
my $json_false = JSON::false;
my $callobj = {
jsonrpc => '2.0',
id => '1',
method => $method,
};
if ($method eq 'GUI.ShowNotification') {
$callobj = {
%$callobj,
params => {
title => $title,
message => $message,
displaytime => $notify_time,
},
};
}
if ($method eq 'GUI.SetFullscreen') {
$callobj = {
%$callobj,
params => {
fullscreen => 'toggle',
},
};
}
if ($method eq 'Addons.ExecuteAddon') {
$callobj = {
%$callobj,
params => {
addonid => $addon_id,
},
};
}
print Dumper $callobj if $verbose;
my $result = '';
my $att = 0; my $was_awake ='0';
do {
sleep 3 if $att;
system($pingcheck);
if ($? and !$att and $verbose) { print "Waking...\n" }
if (!$? and !$att) { $was_awake = 1; }
my $call_result = $client->call($url, $pingobj);
$result = $$call_result{content}{result};
$att++;
} until ($result and $result eq 'pong' or $att > 5 or $was_awake);
if (!$was_awake and $result and $result ne 'pong') {
die "Could not wake $host for operaton.";
}
if (!$was_awake and $verbose) { print "Awake now ($att).\n"; }
my $call_result = $client->call($url, $callobj);
print Dumper $call_result if $verbose;
if ($call_result) {
if ($call_result->is_error) {
print "Error : ", $call_result->error_message;
} else {
if ($method =~ m/^VideoLibrary\.Get(.*)$/) {
(my $type = $1) =~ tr/A-Z/a-z/;
foreach (@{$$call_result{content}{result}{$type}}) {
print $_->{label} . "\n";
}
} elsif ($method =~ m/^JSONRPC\.Ping$/) {
$result = $$call_result{content}{result};
print "$result\n" if !$silent;
} elsif ($method =~ m/^JSONRPC\.Version$/) {
$result = $$call_result{content}{result}{version};
print "$result\n";
}
}
# if (!$was_awake) { print "Sleeping...\n" if $verbose; my $call_result = $client->call($url, $sleepobj) }
exit 0;
} else {
print $client->status_line . "\n";
exit 1;
}
Scott
Re: XBMC Library Updater
just what i needed! modified it a little bit because i only needed /movieABC/ scanned but with a few edits it working perfectly! also now i get a success output which i didn't get before.ericab wrote:the final command is:
Code: Select all
echo "curl -s -H \"Content-Type: application/json\" -u xbmc:xbmc -X POST -d '{\"jsonrpc\": \"2.0\", \"method\": \"VideoLibrary.Scan\", \"params\":{\"directory\":\"nfs://192.168.2.104/export/_TV/show/\"}, \"id\": \"scan\"}' http://192.168.2.33:8090/jsonrpc" | sed 's_show_'"$show"'_g' | sh
unRAID 4.7 Pro: ASUS M4A88T-M | AMD Sempron 145 Sargas @ 2.8GHz | 1GB DDR3 SDRAM 1066 (PC3 8500) RAM | Antec NEO ECO 620C 620W PSU | NETGEAR gigE
Re: XBMC Library Updater
just a little update incase anyone was interested;
ive got a repo up of my library update post proc script.
https://github.com/wavrunrx/SAB-XBMC_Lib-Update
any questions, let me know !
enjoy.
** Note
it may require some modifications to work for your specific setup
ive got a repo up of my library update post proc script.
https://github.com/wavrunrx/SAB-XBMC_Lib-Update
any questions, let me know !
enjoy.
** Note
it may require some modifications to work for your specific setup
Re: XBMC Library Updater
Hi all,
new to the forum, but using SAB for years. Currently in the middle of setting up my unRAID NAS, which is all setup aside from some tweaks with SAB, which is causing me a huge headache with this library updater script.
Currently endless frustration with creating a post-processing script to go along with SABnzbd, so I thought if I opened it up to the forum, hopefully someone with some python scripting skills can help.
Here's where I'm at.
I currently have nzbgeek-report script running and workign fine, and within, on the second-script area of the script, I have the xbmc library updater script (Originally from JohnSCS on page 4 of this thread, adapted with my information, etc) that I'm trying to tailor to myself.
The NZBgeekreport goes through fine, and then the xbmc script attempts to go, but fails immediately. This is the report from SABnzbd:
[INFO] NZB OK (SABNZBD STATUS=0)
[INFO] Status OK sent to NZBgeek
[INFO] Running: /mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py
[INFO] Success : /mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 2: import: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 3: from: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 4:: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 5:: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 7: full_path: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 9: syntax error near unexpected token `('
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 9: `full_path=full_path.split("\\")
and so forth and so on.. Essentially, the whole script not functioning.
What could be causing this? I'm a complete newb to scripting, especially in python, but follow directions well and there's plenty of information to lead me in the right direction in here, so any help would be greatly appreciated.
I'm essentially using this script to just have SAB notify XBMC to only update the folder thats currently downloaded, NOT a full library scan.
new to the forum, but using SAB for years. Currently in the middle of setting up my unRAID NAS, which is all setup aside from some tweaks with SAB, which is causing me a huge headache with this library updater script.
Currently endless frustration with creating a post-processing script to go along with SABnzbd, so I thought if I opened it up to the forum, hopefully someone with some python scripting skills can help.
Here's where I'm at.
I currently have nzbgeek-report script running and workign fine, and within, on the second-script area of the script, I have the xbmc library updater script (Originally from JohnSCS on page 4 of this thread, adapted with my information, etc) that I'm trying to tailor to myself.
The NZBgeekreport goes through fine, and then the xbmc script attempts to go, but fails immediately. This is the report from SABnzbd:
[INFO] NZB OK (SABNZBD STATUS=0)
[INFO] Status OK sent to NZBgeek
[INFO] Running: /mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py
[INFO] Success : /mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 2: import: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 3: from: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 4:: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 5:: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 7: full_path: command not found
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 9: syntax error near unexpected token `('
/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py: line 9: `full_path=full_path.split("\\")
and so forth and so on.. Essentially, the whole script not functioning.
What could be causing this? I'm a complete newb to scripting, especially in python, but follow directions well and there's plenty of information to lead me in the right direction in here, so any help would be greatly appreciated.
I'm essentially using this script to just have SAB notify XBMC to only update the folder thats currently downloaded, NOT a full library scan.
Re: XBMC Library Updater
What does the first line of the script say?
Can you run it from an ssh session window?
Can you run it from an ssh session window?
Re: XBMC Library Updater
The very first line?
#!/usr/bin/python
The nzbgeek reporting script is run, and then within:
# SECOND SCRIPT TO RUN
# It will only run if PAR and UNPACK FINISHES OK
# For windows use .cmd file. For linux use .py file (Don't need to add 'python' before the script. Only filename with fullpath.
# Dont forget to check permission
SCRIPT='/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py'
that script is the file I'm currently running and getting that error from (which is right now a pick up of the script JohnSCS posted on page 5. Seen here, just NAS ip's and paths put in)
https://sabnzbd.org/viewtopic.php?f=9&t ... =60#p54410
#!/usr/bin/python
The nzbgeek reporting script is run, and then within:
# SECOND SCRIPT TO RUN
# It will only run if PAR and UNPACK FINISHES OK
# For windows use .cmd file. For linux use .py file (Don't need to add 'python' before the script. Only filename with fullpath.
# Dont forget to check permission
SCRIPT='/mnt/cache/apps/SABnzbd/config/post-proc/TESTING_XBMC_Notify.py'
that script is the file I'm currently running and getting that error from (which is right now a pick up of the script JohnSCS posted on page 5. Seen here, just NAS ip's and paths put in)
https://sabnzbd.org/viewtopic.php?f=9&t ... =60#p54410
Re: XBMC Library Updater
Make sure the script is in Unix format (using only LF characters for end-of-line).
MSDOS/Windows files (using CR+LF) will fail as scripts.
MSDOS/Windows files (using CR+LF) will fail as scripts.
Re: XBMC Library Updater
I believe that they already are, I don't see any discrepancies, but then again my eyes aren't using to looking over code. I'm really not trying to be a nuisance here, I honestly have no idea what could be wrong with this or why I'm getting the errors. The code itself looks right and is formatted right in notepad++
Code: Select all
# Python 2.6.4 | http://www.python.org/download/releases/2.6.4/
import socket,sys,urllib2,os
from urllib2 import Request, URLError, urlopen
# Get final folder name
full_path = sys.argv[1]
# Split into drive and folder names
full_path=full_path.split("\\")
# Shorten folder_name by removing Season folder (eg S:\TV Series\Showname\Season 1\ to S:\TV Series\Showname\)
# This helped fix some issues with episodes not being added to library
folder_name=full_path[0] + "\\" + full_path[1] + "\\" + full_path[2] + "\\" + full_path[3] + "\\"
print folder_name
# As SAB runs on my NAS, use the following line to change from a drive letter to a SMB share
folder_name=folder_name.replace('S:', 'SMB://NAS-IP/SHARE')
# Make folder_name URL friendly
folder_name=folder_name.replace(' ', '%20')
print folder_name
# Rename the movie file to match the folder (job) name - ** Thanks to rudyb **
# Get the Newzbin category
cat = sys.argv[4]
# Get the folder name again
ugly_folder = sys.argv[1]
# Get the job name
ugly_jobname = sys.argv[3]
# Set movie (and related) file extensions. These are filetypes we care about. Add more if you want those renamed, too
movie_extensions = ['avi', 'mkv', 'wmv', 'ts', 'img', 'iso', 'sub', 'idx', 'srt']
print cat
def ext_count(file_list):
# Create the extensions dictionary
extensions = {}
# Loop through the file list to make a list of extensions and how many there are of each
for filename in file_list:
# Split filename by period
ext = filename.split('.')
# Get the file extension
ext = ext[-1]
# Check if the extension exists in the array list yet
if extensions.has_key(ext):
extensions[ext] = extensions[ext] + 1
# If so, add one to the existing entry
else:
# Otherwise, create the list entry
extensions[ext] = 1
return extensions
# Apply this to movies only
if (cat == "movies"):
# Make an empty dictionary for counting how many we've renamed of each extension
ext_tally = {}
# Make a list (downloaded_files) containing all of the downloaded files
downloaded_files = sorted(os.listdir(ugly_folder))
# Create a dictionary of extensions (the key) and the number of each (the value)
extensions = ext_count(downloaded_files)
# Loop through the list of downloaded files
for filename in downloaded_files:
# We don't know if this file is relevant to our interests
is_video = 0
# See if the ext matches one we care about. Loop through movie_extensions
for mov_ext in movie_extensions:
# See if the filename ends with a relevant extension
if filename.endswith('.' + mov_ext):
# Flag the file as relevant
is_video = 1
# Stop checking (theoretically, it shouldn't have more than one extension)
break
# If we determined that the file was relevant...
if is_video == 1:
# Start building the new filename
new_filename = ugly_jobname
# Get the extension of the file
file_extension = filename.split('.')[-1]
# Check to see if there was more than one of that extension
if extensions[file_extension] > 1:
# If so, add " - CD" to the end
new_filename = new_filename + ' - CD'
# Check to see if we've already renamed one file with this extension
if ext_tally.has_key(file_extension):
# If so, add one to the count
ext_tally[file_extension] = ext_tally[file_extension] + 1
else:
# If not, create a counter and set it to 1
ext_tally[file_extension] = 1
# Then append that number to the end of the filename
new_filename = new_filename + str(ext_tally[file_extension])
# Finally, add the extension
new_filename = new_filename + '.' + file_extension
# See if the new filename and the old filename match
if filename == new_filename:
# If so, end this iteration without renaming, and say so:
print "Filenames are the same. Not renaming"
continue
# Uncomment this line to print the original filename and new filename
print 'Renaming ' + filename + ' to ' + new_filename
# Last, but not least, rename the file
os.rename(ugly_folder + '\\' + filename, ugly_folder + '\\' + new_filename)
# Get current date/time and strip spaces
from time import gmtime, strftime
event_time = strftime("%d/%m/%y %H:%M")
event_time=event_time.replace(' ', '%20')
# Strip illegal/unwanted chars from NZB name
job_name=job_name.replace(' ', '%20')
job_name=job_name.replace('_', '%20')
job_name=job_name.replace('.', '%20')
# Lounge Room XBMC Live PC. Note the different path for the JPG image when using AppleTV XBMC.
xbmc3=urllib2.Request("http://user:pass@ip:port/xbmcCmds/xbmcHttp?command=ExecBuiltIn(Notification(" + job_title + "," + job_name + ",20000,//NAS-IP/boot/config/plugins/sabnzbd/sabnzbd.png))")
try: urllib2.urlopen(xbmc3)
except URLError, e:
print 'Lounge Room XBMC Failed'
else:
urllib2.urlopen("http://user:[email protected]:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn¶meter=XBMC.updatelibrary(video," + folder_name + ")")
Last edited by magiin83 on December 22nd, 2014, 9:41 am, edited 1 time in total.
Re: XBMC Library Updater
A script should start with something like this:
#!/usr/bin/python
Otherwise the operating system doesn't know how to run it.
Check that the path to Python is actually /usr/bin/python
#!/usr/bin/python
Otherwise the operating system doesn't know how to run it.
Check that the path to Python is actually /usr/bin/python
Re: XBMC Library Updater
This part is OLD for notify, you have to use JSON commands now !!
like this
wget -q -O --header="Accept: application/json" --header="Content-type: application/json" --post-data="{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"GUI.ShowNotification\",\"params\":{\"title\":\"Movie Mode\",\"message\":\"Movie Mode is ingeschakeld\",\"image\":\"http://2.bp.blogspot.com/-uERK9tX0Fs4/T ... cation.png\"}}" "http://192.168.2.4:8088/jsonrpc
rm jsonrpc"
like this
wget -q -O --header="Accept: application/json" --header="Content-type: application/json" --post-data="{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"GUI.ShowNotification\",\"params\":{\"title\":\"Movie Mode\",\"message\":\"Movie Mode is ingeschakeld\",\"image\":\"http://2.bp.blogspot.com/-uERK9tX0Fs4/T ... cation.png\"}}" "http://192.168.2.4:8088/jsonrpc
rm jsonrpc"
# Lounge Room XBMC Live PC. Note the different path for the JPG image when using AppleTV XBMC.
xbmc3=urllib2.Request("http://user:pass@ip:port/xbmcCmds/xbmcHttp?command=ExecBuiltIn(Notification(" + job_title + "," + job_name + ",20000,//NAS-IP/boot/config/plugins/sabnzbd/sabnzbd.png))")
try: urllib2.urlopen(xbmc3)
except URLError, e:
print 'Lounge Room XBMC Failed'
else:
urllib2.urlopen("http://user:[email protected]:8080/xbm ... rary(video," + folder_name + ")")