resources/lib/sutils.py
import util
import xbmcprovider
import xbmcutil
import xbmcvfs
import xbmcgui
import xbmc
import unicodedata
import os
import re
import time
import string
import datetime
import urllib
import sosac
class XBMCSosac(xbmcprovider.XBMCMultiResolverContentProvider):
last_run = 0
sleep_time = 1000 * 1 * 60
subs = None
def __init__(self, provider, settings, addon):
xbmcprovider.XBMCMultiResolverContentProvider.__init__(
self, provider, settings, addon)
provider.parent = self
self.dialog = xbmcgui.DialogProgress()
try:
import StorageServer
self.cache = StorageServer.StorageServer("Downloader")
except:
import storageserverdummy as StorageServer
self.cache = StorageServer.StorageServer("Downloader")
def make_name(self, text, lower=True):
text = self.normalize_filename(
text, "-_.' %s%s" % (string.ascii_letters, string.digits))
word_re = re.compile(r'\b\w+\b')
text = ''.join([c for c in text if (c.isalnum() or c == "'" or c ==
'.' or c == '-' or c.isspace())]) if text else ''
text = '-'.join(word_re.findall(text))
return text.lower() if lower else text
def normalize_filename(self, name, validChars=None):
validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
if (validChars is not None):
validFilenameChars = validChars
cleanedFilename = self.encode(name)
return ''.join(c for c in cleanedFilename if c in validFilenameChars)
def service(self):
util.info("SOSAC Service Started")
try:
sleep_time = int(self.getSetting("start_sleep_time")) * 1000 * 60 * 60
except:
sleep_time = self.sleep_time
pass
self.sleep(sleep_time)
try:
self.last_run = float(self.cache.get("subscription.last_run"))
except:
self.last_run = time.time()
self.cache.set("subscription.last_run", str(self.last_run))
pass
if not xbmc.abortRequested and time.time() > self.last_run:
self.evalSchedules()
while not xbmc.abortRequested:
# evaluate subsciptions every 10 minutes
if(time.time() > self.last_run + 600):
self.evalSchedules()
self.last_run = time.time()
self.cache.set("subscription.last_run", str(self.last_run))
self.sleep(self.sleep_time)
util.info("SOSAC Shutdown")
def showNotification(self, title, message, time=1000):
xbmcgui.Dialog().notification(self.encode(title), self.encode(message), time=time,
icon=xbmc.translatePath(
self.addon_dir() + "/icon.png"),
sound=False)
def evalSchedules(self):
if not self.scanRunning() and not self.isPlaying():
notified = False
util.info("SOSAC Loading subscriptions")
subs = self.get_subs()
new_items = False
for url, sub in subs.iteritems():
if xbmc.abortRequested:
util.info("SOSAC Exiting")
return
if sub['type'] == sosac.LIBRARY_TYPE_TVSHOW:
if self.scanRunning() or self.isPlaying():
self.cache.delete("subscription.last_run")
return
refresh = int(sub['refresh'])
if refresh > 0:
next_check = sub['last_run'] + (refresh * 3600 * 24)
if next_check < time.time():
if not notified:
self.showNotification(
'Subscription', 'Chcecking')
notified = True
util.debug("SOSAC Refreshing " + url)
new_items |= self.run_custom({
'action': sosac.LIBRARY_ACTION_ADD,
'type': sosac.LIBRARY_TYPE_TVSHOW,
'update': True,
'url': url,
'name': sub['name'],
'refresh': sub['refresh']
})
self.sleep(3000)
else:
n = (next_check - time.time()) / 3600
util.debug("SOSAC Skipping " + url +
" , next check in %dh" % n)
if new_items:
xbmc.executebuiltin('UpdateLibrary(video)')
notified = False
else:
util.info("SOSAC Scan skipped")
def isPlaying(self):
return xbmc.Player().isPlaying()
def scanRunning(self):
return (xbmc.getCondVisibility('Library.IsScanningVideo') or
xbmc.getCondVisibility('Library.IsScanningMusic'))
def getTVDB(self, name, id):
if id:
data = util.request('http://thetvdb.com/api/GetSeriesByRemoteID.php?imdbid=tt' +
id + '&language=all')
tvid = re.search('<id>(\d+)</id>', data)
if tvid:
return tvid.group(1)
shortname = re.search('(.+) (\(\d{4}\))', name).group(1)
urllang = [urllib.urlencode({'seriesname': shortname, 'language': 'cs'}),
urllib.urlencode({'seriesname': shortname, 'language': 'all'}),
urllib.urlencode({'seriesname': name, 'language': 'cs'}),
urllib.urlencode({'seriesname': name, 'language': 'all'})]
for iter in urllang:
data = util.request('http://thetvdb.com/api/GetSeries.php?' + iter)
tvid = re.search('<id>(\d+)</id>', data)
if tvid:
return tvid.group(1)
return None
def add_item(self, params):
error = False
if not 'refresh' in params:
params['refresh'] = str(self.getSetting("refresh_time"))
sub = {'name': params['name'], 'refresh': params[
'refresh'], 'type': params['type']}
sub['last_run'] = time.time()
arg = {"play": params['url'], 'cp': 'sosac.ph', "title": sub['name']}
item_url = xbmcutil._create_plugin_url(
arg, 'plugin://' + self.addon_id + '/')
util.info("item: " + item_url + " | " + str(params))
new_items = False
# self.showNotification('Linking', params['name'])
if params['type'] == sosac.LIBRARY_TYPE_VIDEO:
# movies are not stored in subs database
item_dir = self.getSetting('library-movies')
nfo_file = os.path.join(item_dir, self.normalize_filename(
sub['name']), self.normalize_filename(params['name']) + '.nfo')
if not xbmcvfs.exists(nfo_file):
metadata = ""
if ('imdb' in params and params['imdb'] and not
re.match('^$|^[?0]$', params['imdb'])):
metadata += "http://www.imdb.com/title/tt{0}/\n".format(params['imdb'])
if ('csfd' in params and params['csfd'] and not
re.match('^$|^[?0]$', params['csfd'])):
metadata += "http://www.csfd.cz/film/{0}\n".format(params['csfd'])
if metadata != "":
self.add_item_to_library(nfo_file, metadata)
(error, new_items) = self.add_item_to_library(
os.path.join(item_dir, self.normalize_filename(sub['name']),
self.normalize_filename(params['name'])) + '.strm', item_url)
elif params['type'] == sosac.LIBRARY_TYPE_TVSHOW:
if not ('notify' in params):
self.showNotification(sub['name'], 'Checking new content')
subs = self.get_subs()
item_dir = self.getSetting('library-tvshows')
subs.update({params['url']: sub})
self.set_subs(subs)
# self.addon.setSetting('tvshows-subs', json.dumps(subs))
nfo_file = os.path.join(item_dir, self.normalize_filename(params['name']), 'tvshow.nfo')
if not xbmcvfs.exists(nfo_file):
metadata = ""
if ('imdb' in params and params['imdb'] and not
re.match('^$|^[?0]$', params['imdb'])):
metadata += "http://www.imdb.com/title/tt{0}/\n".format(params['imdb'])
if ('csfd' in params and params['csfd'] and not
re.match('^$|^[?0]$', params['csfd'])):
metadata += "http://www.csfd.cz/film/{0}\n".format(params['csfd'])
tvid = self.getTVDB(params['name'], params['imdb'])
if tvid:
metadata += "http://thetvdb.com/index.php?tab=series&id={0}\n".format(tvid)
if metadata != "":
self.add_item_to_library(nfo_file, metadata)
episodes = self.provider.list_episodes(params['url'])
for itm in episodes:
arg = {"play": itm['url'], 'cp': 'sosac.ph',
"title": itm['title']}
item_url = xbmcutil._create_plugin_url(
arg, 'plugin://' + self.addon_id + '/')
dirname = "Season " + str(itm['season'])
epname = "S%02dE%02d.strm" % (itm['season'], itm['episode'])
filename = os.path.join(item_dir, self.normalize_filename(
params['name']), dirname, epname)
(err, new) = self.add_item_to_library(filename, item_url)
error |= err
if new is True and not err:
new_items = True
if not error and new_items and not ('update' in params) and not ('notify' in params):
self.showNotification(params['name'], 'Found new content')
xbmc.executebuiltin('UpdateLibrary(video)')
elif not error and not ('notify' in params):
self.showNotification(params['name'], 'No new content')
if error and not ('notify' in params):
self.showNotification('Failed, Please check kodi logs', 'Linking')
return new_items
def run_custom(self, params):
if 'action' in params:
icon = os.path.join(self.addon.getAddonInfo('path'), 'icon.png')
if params['action'] == sosac.LIBRARY_ACTION_REMOVE_SUBSCRIPTION:
subs = self.get_subs()
if params['url'] in subs.keys():
del subs[params['url']]
self.set_subs(subs)
self.showNotification(
params['name'], 'Removed from subscriptions')
xbmc.executebuiltin('Container.Refresh')
return False
if params['action'] == sosac.LIBRARY_ACTION_ADD:
if self.add_item(params):
xbmc.executebuiltin('Container.Refresh')
return True
return False
if params['action'] == sosac.LIBRARY_ACTION_REMOVE_ALL:
self.set_subs({})
return True
if params['action'] == sosac.LIBRARY_ACTION_ADD_ALL:
self.dialog.create("Sosac", "Adding All Movies to library")
self.dialog.update(0)
if params['type'] == sosac.LIBRARY_TYPE_ALL_VIDEOS:
self.dialog.create("Sosac", "Adding All Movies to library")
self.dialog.update(0)
videos = self.provider.library_list_all_videos()
for video in videos:
if self.dialog.iscanceled():
return
if 'progress' in video:
self.dialog.update(video['progress'])
else:
item = video['menu'][sosac.LIBRARY_MENU_ITEM_ADD]
item["update"] = True
item["notify"] = True
item["type"] = sosac.LIBRARY_TYPE_VIDEO
self.add_item(item)
self.dialog.close()
if params['type'] == sosac.LIBRARY_TYPE_RECENT_VIDEOS:
self.dialog.create("Sosac", "Adding Recent Movies to library")
self.dialog.update(0)
videos = self.provider.library_list_recent_videos()
for video in videos:
if self.dialog.iscanceled():
return
if 'progress' in video:
self.dialog.update(video['progress'])
else:
item = video['menu'][sosac.LIBRARY_MENU_ITEM_ADD]
item["update"] = True
item["notify"] = True
item["type"] = sosac.LIBRARY_TYPE_VIDEO
self.add_item(item)
self.dialog.close()
elif params['type'] == sosac.LIBRARY_TYPE_ALL_SHOWS:
self.dialog.create(
"Sosac", "Adding All TV Shows to library")
self.dialog.update(0)
shows = self.provider.library_list_all_tvshows()
for show in shows:
if self.dialog.iscanceled():
return
if 'progress' in show:
self.dialog.update(show['progress'])
else:
item = show['menu'][sosac.LIBRARY_MENU_ITEM_ADD]
item["update"] = True
item["notify"] = True
item["type"] = sosac.LIBRARY_TYPE_TVSHOW
self.add_item(item)
xbmc.executebuiltin('UpdateLibrary(video)')
return False
def add_item_to_library(self, item_path, item_url):
error = False
new = False
if item_path:
item_path = xbmc.translatePath(item_path)
dir = os.path.dirname(item_path)
if not xbmcvfs.exists(dir):
try:
xbmcvfs.mkdirs(dir)
except Exception, e:
error = True
util.error('Failed to create directory 1: ' + dir)
if not xbmcvfs.exists(item_path):
try:
file_desc = xbmcvfs.File(item_path, 'w')
file_desc.write(item_url)
file_desc.close()
new = True
except Exception, e:
util.error('Failed to create .strm file: ' +
item_path + " | " + str(e))
error = True
else:
error = True
return (error, new)
def get_subs(self):
if self.subs is not None:
return self.subs
data = self.cache.get("subscription-1")
try:
if data == '':
return {}
self.subs = eval(data)
return self.subs
except Exception, e:
util.error(e)
return {}
def set_subs(self, subs):
self.subs = subs
self.cache.set("subscription-1", repr(subs))
@staticmethod
def encode(string):
return unicodedata.normalize('NFKD', string.decode('utf-8')).encode('ascii', 'ignore')
def addon_dir(self):
return self.addon.getAddonInfo('path')
def data_dir(self):
return self.addon.getAddonInfo('profile')
def getSetting(self, name):
return self.addon.getSetting(name)
def getString(self, string_id):
return self.addon.getLocalizedString(string_id)
@staticmethod
def sleep(sleep_time):
while not xbmc.abortRequested and sleep_time > 0:
sleep_time -= 1
xbmc.sleep(1)