Skip to content

Instantly share code, notes, and snippets.

@jkschoen
Created August 3, 2012 04:53
Show Gist options
  • Save jkschoen/3244485 to your computer and use it in GitHub Desktop.
Save jkschoen/3244485 to your computer and use it in GitHub Desktop.
Script that will work with Script Launcher module in Maraschino to delete watched tv shows in xbmc.
import datetime, getopt, sys, urllib, urllib2
import base64, httplib, json, os, socket
HOSTS = [
{'host': '192.168.1.2', 'port': 8080, 'username': 'xbmc', 'password': ''},
{'host': '192.168.1.3', 'port': 8080, 'username': 'xbmc', 'password': ''}
]
#XBMC access media through the network, an handles the various networking
#protocols. I do not. The script assumes that the media is accessible
#through the normal file system. So the first value is the part of
#the filepath that XBMC uses to access the media, that we need to
#replace to access the file from the system running the script. The
#second part is the part that it will be replaced with. If you have multiple
#items that may need to be replaced, just seperate them with a comma.
PATH_SUBS = {
'nfs://192.168.1.15/shares/':'/shares/drive1/'
}
#This is for when there is a show you want to hang on to and not delete,
#or even just a certain season of a show. You can put the path to the
#directory where the show or season is, and the script will skip thos
#items found there.
IGNORE_FOLDERS = [
'/drive1/TV Shows/Burn Notice'
]
def main(argv):
try:
opts, args = getopt.getopt(argv, "ipsw:", ["ip=", "port=", "script_id=", "webroot="])
except getopt.GetoptError:
sys.exit(2)
ip = None
port = None
script_id = None
webroot = None
for opt, arg in opts:
if opt in ("-i", "--ip"):
ip = arg
elif opt in ("-p", "--port"):
port = arg
elif opt in ("-s", "--script_id"):
script_id = arg
elif opt in ("-w", "--webroot"):
webroot = arg
#loop through our hosts to see if we have on that is on right now
for host in HOSTS:
try:
conn = JSONConnection(host['host'], host['port'], host['username'], host['password'])
data = conn.VideoLibrary.GetEpisodes(properties=["playcount","file"])
update_status("Getting watched episodes", ip, port, webroot, script_id)
watched = findWatchedEpisodes(data)
update_status("%s Watched shows" % len(watched), ip, port, webroot, script_id)
deleteWatchedEpisodes(watched, ip, port, webroot, script_id)
update_status("Starting Clean of Library", ip, port, webroot, script_id)
data = conn.VideoLibrary.Clean()
finished(ip, port, webroot, script_id)
break
except socket.error:
update_status("Failed: Make sure XBMC is running", ip, port, webroot, script_id)
def findWatchedEpisodes(data):
watched = []
for episode in data["episodes"]:
if (episode["playcount"] > 0 ):
watched.append(episode)
return watched
def deleteWatchedEpisodes(watched, ip=None, port=None, webroot=None, script_id=None):
count = len(watched)
for episode in watched:
filePath = episode["file"]
#first replace prefix with mounted location
modPath = filePath
for key, value in PATH_SUBS.iteritems():
if filePath.startswith(key):
modPath = filePath.replace(key, value, 1)
break
ignoreThisOne = False;
for ignore in IGNORE_FOLDERS:
if modPath.startswith(ignore):
ignoreThisOne = True;
continue
if (ignoreThisOne == False):
#then get filename without extension
filename = os.path.basename(modPath)
minusExt = os.path.splitext(filename)[0]
#then delete all files found in the same directory that start with filename regardless of extension
folderPath = os.path.dirname(modPath)
for subdir, dirs, files in os.walk(folderPath):
for file in files:
if (os.path.splitext(file)[0] == minusExt):
fullfilePath = os.path.join(folderPath, file)
try:
os.unlink(fullfilePath)
except:
pass
count = count - 1
update_status("%s Watched shows" % count, ip, port, webroot, script_id)
def finished(ip=None, port=None, webroot=None, script_id=None):
now = datetime.datetime.now()
update_status("Last Ran: %s" % now.strftime("%m-%d-%Y %H:%M"), ip, port, webroot, script_id)
def update_status(status, ip=None, port=None, webroot=None, script_id=None):
if script_id == None or ip == None or port == None:
return
path = None
if webroot:
path='http://%s:%s/%s/xhr/script_launcher/script_status/%s' % (ip, port, webroot, script_id)
else:
path='http://%s:%s/xhr/script_launcher/script_status/%s' % (ip, port, script_id)
data = [('status', status)]
data=urllib.urlencode(data)
req=urllib2.Request(path, data)
req.add_header("Content-type", "application/x-www-form-urlencoded")
open=urllib2.urlopen(req)
page = open.read()
# I found this code on the XBMC Forums somewhere if I remember right, but I con not
# find it again. If you know where it is please let me know, so I can add a link to this.
__all__ = ['JSONConnection', 'JSONRPCError', 'JSONConnectionError', 'JSONUserPassError']
class JSONError(Exception):
pass
class JSONRPCError(JSONError):
def __init__(self, code, message):
JSONError.__init__(self, message)
self.code = code
self.message = message
class JSONConnectionError(JSONError):
def __init__(self, code, message):
JSONError.__init__(self, message)
self.code = code
self.message = message
class JSONUserPassError(JSONError):
pass
class JSONConnection(object):
# def __init__(self, host='192.168.1.2', port=8080, username='xbmc', password=''):
def __init__(self, host='', port=0, username='', password=''):
self.host = host
self.port = port
self.username = username
self.password = password
self._namespace_cache = {}
def __getattr__(self, namespace):
if namespace in self._namespace_cache:
return self._namespace_cache[namespace]
nsobj = self.Namespace(namespace, self)
self._namespace_cache[namespace] = nsobj
return nsobj
class Namespace(object):
def __init__(self, name, connection):
self.name = name
self.connection = connection
self._id = 1
self._handler_cache = {}
def __getattr__(self, method):
if method in self._handler_cache:
return self._handler_cache[method]
def handler(**kwargs):
data = {'jsonrpc': '2.0',
'id': self._id,
'method': '%s.%s' % (self.name, method)
}
if kwargs:
data['params'] = {}
for k in kwargs:
data['params'][k] = kwargs[k]
postdata = json.dumps(data, ensure_ascii=False)
postdata = postdata.encode('utf-8')
headers = {'Content-Type': 'application/json-rpc; charset=utf-8'}
if self.connection.password != '':
userpass = base64.encodestring('%s:%s' % \
(self.connection.username, self.connection.password))[:-1]
headers['Authorization'] = 'Basic %s' % userpass
conn = httplib.HTTPConnection(self.connection.host,
self.connection.port)
conn.request('POST', '/jsonrpc', postdata, headers)
data = None
response = conn.getresponse()
if response.status == httplib.OK:
data = response.read()
conn.close()
if response.status != httplib.OK:
if response.status == httplib.UNAUTHORIZED:
raise JSONUserPassError()
else:
raise JSONConnectionError(response.status,
'Connection Error: %s' % httplib.responses[response.status])
conn.close()
self._id += 1
if data is not None:
response = json.loads(data)
if 'error' in response:
raise JSONRPCError(json['error']['code'],
json['error']['message'])
return response['result']
else:
return None
handler.method = method
self._handler_cache[method] = handler
return handler
if __name__ == '__main__':
main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment