Exemple #1
0
def main():
    try:
        addons.download_addons()
    except Exception as e:
        cli.message('Failed to load Exodus: %s' % str(e))
        _exit(-1)

    _setup_paths()
    _inject_xbmc()
    _clear_log()

    args = ('plugin://plugin.video.exodus', 0, '')
    while True:
        t = threading.Thread(target=_run_exodus, args=args)
        t.daemon = True
        cli.message('Loading...')
        t.start()
        t.join()

        handle = args[1]

        while True:
            try:
                selected = _dir_select(handle)
            except KeyboardInterrupt:
                _exit(0)
            args = _determine_args(*selected)
            if args: break
Exemple #2
0
def main():
    try:
        addons.download_addons()
    except Exception as e:
        cli.message('Failed to load Exodus: %s' % str(e))
        _exit(-1)

    _setup_paths()
    _inject_xbmc()
    _clear_log()

    args = ('plugin://plugin.video.exodus', 0, '')
    while True:
        t = threading.Thread(target=_run_exodus, args=args)
        t.daemon = True
        cli.message('Loading...')
        t.start()
        t.join()

        handle = args[1]

        while True:
            try:
                selected = _dir_select(handle)
            except KeyboardInterrupt:
                _exit(0)
            args = _determine_args(*selected)
            if args: break
Exemple #3
0
def _download(id, b64url, zipmd5, version):
    '''Download one addon from base64 encoded url
    Checks md5
    Loads zip contents into addons directory
    '''
    version_file = path.join(config.addonsdir, id + '.version')
    dir = path.join(config.addonsdir, id)

    if path.isfile(version_file):
        try:
            with open(version_file, 'r') as f:
                curr_version = f.read(
                    30).strip()  # version should not be more than 30 bytes
        except:
            # try to remove version file if failed to read from it
            remove(version_file)
            raise
        if curr_version == version and path.isdir(dir):
            return

    cli.message('Retrieving %s (%s)...' % (id, version))

    if path.isdir(dir):
        shutil.rmtree(dir)

    url = base64.b64decode(b64url)
    resp = urllib2.urlopen(url)
    s = resp.read(5 * 1000 * 1000)  # should not be larger than 5MB

    m = hashlib.md5(s)
    if m.hexdigest() != zipmd5:
        raise Exception('Invalid md5 for %s', id)

    f = StringIO(s)
    try:
        with zipfile.ZipFile(f) as z:
            z.extractall(config.addonsdir)
    except:
        # try to remove directory if anything went wrong
        if path.isdir(dir):
            shutil.rmtree(dir)
        raise

    try:
        with open(version_file, 'w+') as f:
            f.write(version)
    except:
        # try to remove version file if failed to write to it
        if path.isfile(version_file):
            remove(version_file)
        raise

    cli.message('Loaded %s' % id)
Exemple #4
0
def executebuiltin(function):
    m = re.match(_re_notification, function)
    if m:
        header, message, time, image = m.groups()
        cli.message('%s: %s' % (header.strip(), message.strip()))
        try:
            t = int(time)
            cli.message('(resume in %s seconds)' % round(t / 1000.0))
        except TypeError:
            t = 0
        sleep(t)
        return

    m = re.match(_re_update, function)
    if m:
        # this is completely different from how Kodi deals with Container.Update
        # Kodi creates new addon process to run the url, here we're making assumptions
        # on how Exodus works, and run Exodus again in the same thread from the entry
        # point with the query string supplied from the Container.Update call
        url = m.group(1)
        parts = urlparse(url)
        if parts.scheme == 'plugin' and parts.netloc == config.exodus['id']:
            qs = parts.query
            kv = dict(parse_qsl(qs))
            if kv['action'] in [
                    'addItem', 'moviePersons', 'movies', 'tvPersons', 'tvshows'
            ]:
                exodus, _ = os.path.splitext(config.exodus['entryfile'])
                old_argv = sys.argv[:]
                sys.argv[2] = '?' + qs
                runpy.run_module(exodus)
                sys.argv = old_argv
                return
        raise NotImplementedError

    if function == 'Dialog.Close(virtualkeyboard)':
        return

    if function == 'Dialog.Close(yesnoDialog)':
        return

    if function == 'Dialog.Close(busydialog)':
        return

    if function == 'Container.SetViewMode(500)':
        return

    if function == 'Container.SetViewMode(504)':
        return

    raise NotImplementedError
Exemple #5
0
def executebuiltin(function):
    m = re.match(_re_notification, function)
    if m:
        header, message, time, image = m.groups()
        cli.message('%s: %s' % (header.strip(), message.strip()))
        try:
            t = int(time)
            cli.message('(resume in %s seconds)' % round(t/1000.0))
        except TypeError:
            t = 0
        sleep(t)
        return

    m = re.match(_re_update, function)
    if m:
        # this is completely different from how Kodi deals with Container.Update
        # Kodi creates new addon process to run the url, here we're making assumptions
        # on how Exodus works, and run Exodus again in the same thread from the entry
        # point with the query string supplied from the Container.Update call
        url = m.group(1)
        parts = urlparse(url)
        if parts.scheme == 'plugin' and parts.netloc == config.exodus['id']:
            qs = parts.query
            kv = dict(parse_qsl(qs))
            if kv['action'] in ['addItem', 'moviePersons', 'movies', 'tvPersons', 'tvshows']:
                exodus, _ = os.path.splitext(config.exodus['entryfile'])
                old_argv = sys.argv[:]
                sys.argv[2] = '?' + qs
                runpy.run_module(exodus)
                sys.argv = old_argv
                return
        raise NotImplementedError

    if function == 'Dialog.Close(virtualkeyboard)':
        return

    if function == 'Dialog.Close(yesnoDialog)':
        return

    if function == 'Dialog.Close(busydialog)':
        return

    if function == 'Container.SetViewMode(500)':
        return

    if function == 'Container.SetViewMode(504)':
        return

    raise NotImplementedError
Exemple #6
0
def _determine_args(handle, index):
    '''Return arguments tuple (used for calling Exodus) based on selected item
    Return None if it is a special item or is unsupported
    '''
    url, listitem, isfolder = xbmcplugin._dirs[handle][index]
    urlparts = urlparse(url)
    scheme = urlparts.scheme

    if scheme == 'plugin':
        base = '%s://%s' % (scheme, urlparts.netloc)
        query = '?%s' % urlparts.query
        return (base, handle + 1, query)

    elif scheme == 'browser':
        link = url[len('browser://'):]
        try:
            webbrowser.get().open(link)
        except webbrowser.Error:
            cli.message('Failed to open URL in browser')
        return None

    elif scheme == 'print':
        link = url[len('print://'):]
        cli.message(link)
        return None

    else:
        cli.message('Unsupported item')
        return None
Exemple #7
0
def _determine_args(handle, index):
    '''Return arguments tuple (used for calling Exodus) based on selected item
    Return None if it is a special item or is unsupported
    '''
    url, listitem, isfolder = xbmcplugin._dirs[handle][index]
    urlparts = urlparse(url)
    scheme = urlparts.scheme

    if scheme == 'plugin':
        base = '%s://%s' % (scheme, urlparts.netloc)
        query = '?%s' % urlparts.query
        return (base, handle + 1, query)

    elif scheme == 'browser':
        link = url[len('browser://'):]
        try:
            webbrowser.get().open(link)
        except webbrowser.Error:
            cli.message('Failed to open URL in browser')
        return None

    elif scheme == 'print':
        link = url[len('print://'):]
        cli.message(link)
        return None

    else:
        cli.message('Unsupported item')
        return None
Exemple #8
0
def _exit(status):
    cli.message('\nBye\n')
    sys.exit(status)
Exemple #9
0
def _exit(status):
    cli.message('\nBye\n')
    sys.exit(status)
Exemple #10
0
 def update(self, percent, line1='', line2='', line3=''):
     for l in [line1, line2, line3]:
         if l:
             cli.message('%s: %s' % (self.heading, l))
     cli.message('%s: %s%%' % (self.heading, percent))
Exemple #11
0
 def create(self, heading, line1='', line2='', line3=''):
     self.heading = heading
     for l in [line1, line2, line3]:
         if l:
             cli.message('%s: %s' % (heading, l))