kodi-czsk/plugin.video.sosac.ph

View on GitHub
resources/lib/sutils.py

Summary

Maintainability
F
1 wk
Test Coverage
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)