def update_addons(quiet=True): from distutils.version import LooseVersion if not quiet: kodi.open_busy_dialog() sources = DB.query("SELECT addon_id, source FROM install_history") update_count = 0 for source in sources: addon_id = source[0] source = json.loads(source[1]) if kodi.get_condition_visiblity("System.HasAddon(%s)" % addon_id): if source['type'] == SOURCES.ZIP: url, filename, full_name, version = github.find_zip(source['user'], addon_id) current_version = kodi.get_addon(addon_id).getAddonInfo('version') if LooseVersion(version) > LooseVersion(current_version): GitHub_Installer(addon_id, url, full_name, kodi.vfs.join("special://home", "addons"), False, quiet) update_count += 1 elif source['type'] == SOURCES.REPO: full_name = sources['user'] + '/' + sources['repo'] xml_str = github.find_xml(full_name) xml = BeautifulSoup(xml_str) addon = xml.find('addon') current_version = kodi.get_addon(addon_id).getAddonInfo('version') if LooseVersion(addon['version']) > LooseVersion(current_version): GitHub_Installer(addon_id, source['url'], full_name, kodi.vfs.join("special://home", "addons"), True, quiet) update_count += 1 if not quiet: kodi.close_busy_dialog() if update_count > 0: kodi.notify("Update complete",'Some addons may require restarting kodi.') else: kodi.notify("Update complete",'No updates found.')
def resolve_url(self, raw_url): resolved_url = '' host = self.get_domain_from_url(raw_url) if host not in self.get_domains(): return '' from commoncore.dispatcher import WeightedDispatcher dispatcher = WeightedDispatcher() @dispatcher.register(kodi.get_setting('premiumize_priority', ADDON_ID), [raw_url]) def pm_resolver(raw_url): if host not in self.premiumize_hosts: return '' try: response = premiumize.get_download(raw_url) return response['result']['location'] except: return '' @dispatcher.register(kodi.get_setting('realdebrid_priority', ADDON_ID), [raw_url]) def rd_resolver(raw_url): if host not in self.realdebrid_hosts: return '' try: return realdebrid.resolve_url(raw_url) except: return '' kodi.open_busy_dialog() try: resolved_url = dispatcher.run() except: kodi.close_busy_dialog() kodi.close_busy_dialog() return resolved_url
def update_addons(quiet=True): from distutils.version import LooseVersion if not quiet: kodi.open_busy_dialog() sources = DB.query("SELECT addon_id, source FROM install_history") update_count = 0 for source in sources: addon_id = source[0] source = json.loads(source[1]) if kodi.get_condition_visiblity("System.HasAddon(%s)" % addon_id): if source['type'] == SOURCES.ZIP: url, filename, full_name, version = github.find_zip(source['user'], addon_id) current_version = kodi.get_addon(addon_id).getAddonInfo('version') if LooseVersion(version) > LooseVersion(current_version): GitHub_Installer(addon_id, url, full_name, kodi.vfs.join("special://home", "addons"), False, quiet) update_count += 1 elif source['type'] == SOURCES.REPO: full_name = sources['user'] + '/' + sources['repo'] xml_str = github.find_xml(full_name) xml = BeautifulSoup(xml_str) addon = xml.find('addon') current_version = kodi.get_addon(addon_id).getAddonInfo('version') if LooseVersion(addon['version']) > LooseVersion(current_version): GitHub_Installer(addon_id, source['url'], full_name, kodi.vfs.join("special://home", "addons"), True, quiet) update_count += 1 if not quiet: kodi.close_busy_dialog() if update_count > 0: kodi.notify("Update complete",'Some addons may require restarting kodi.') else: kodi.notify("Update complete",'No updates found.')
def download(url, addon_id, destination, unzip=False, quiet=False): version = None filename = addon_id + '.zip' r = requests.get(url, stream=True) kodi.log("Download: %s" % url) if r.status_code == requests.codes.ok: temp_file = kodi.vfs.join(kodi.get_profile(), "downloads") if not kodi.vfs.exists(temp_file): kodi.vfs.mkdir(temp_file, recursive=True) temp_file = kodi.vfs.join(temp_file, filename) try: total_bytes = int(r.headers["Content-Length"]) except: total_bytes = 0 block_size = 1000 cached_bytes = 0 if not quiet: pb = xbmcgui.DialogProgress() pb.create("Downloading",filename,' ', ' ') kodi.sleep(150) start = time.time() with open(temp_file, 'wb') as f: for block in r.iter_content(chunk_size=block_size): if not block: break if not quiet and pb.iscanceled(): raise downloaderException('Download Aborted') return False cached_bytes += len(block) f.write(block) if total_bytes > 0: delta = int(time.time() - start) if delta: bs = int(cached_bytes / (delta)) else: bs = 0 if not quiet: percent = int(cached_bytes * 100 / total_bytes) pb.update(percent, "Downloading",filename, format_status(cached_bytes, total_bytes, bs)) if not quiet: pb.close() if unzip: zip_ref = zipfile.ZipFile(temp_file, 'r') zip_ref.extractall(destination) zip_ref.close() kodi.vfs.rm(temp_file, quiet=True) try: xml = kodi.vfs.read_file(kodi.vfs.join(destination, kodi.vfs.join(addon_id, 'addon.xml')), soup=True) version = get_version_by_xml(xml) if not version: version = get_version_by_name(filename) except: kodi.log("Unable to fine version from addon.xml for addon: %s" % addon_id) else: kodi.vfs.mv(temp_file, kodi.vfs.join(destination, filename)) else: kodi.close_busy_dialog() raise downloaderException(r.status_code) return version
def resolve_url(self, raw_url): resolved_url = '' kodi.open_busy_dialog() hash = self.get_hash_from_magnet(raw_url) if not hash: hash = self.get_hash_from_url(raw_url) if hash: kodi.set_property('Playback.Hash', hash) else: kodi.clear_property('Playback.Hash') attempt = 0 attempts = 5 try: response = premiumize.create_transfer(raw_url) id = response['id'] except: premiumize.clear_transfers() response = premiumize.create_transfer(raw_url) id = response['id'] try: while attempt < attempts: folder_id = False file_id = False target_folder_id = False kodi.log("Resolve Attempt %s" % attempt) temp = premiumize.list_transfers() for t in temp['transfers']: if t['id'] == id and t['status'] == 'finished': target_folder_id = t['target_folder_id'] folder_id = t['folder_id'] file_id = t['file_id'] break if folder_id: response = premiumize.list_folder(folder_id) resolved_url = premiumize.get_folder_stream(response) break if target_folder_id: response = premiumize.list_folder(target_folder_id) resolved_url = premiumize.get_folder_stream(response) break attempt += 1 kodi.sleep(150) except: kodi.close_busy_dialog() kodi.close_busy_dialog() return resolved_url
def handel_error(self, error, response, request_args, request_kwargs): if response.status_code == 401: traceback.print_stack() kodi.close_busy_dialog() raise githubException("Unauthorized: %s" % error) elif response.status_code == 403 and 'X-RateLimit-Reset' in response.headers: import time retry = int(response.headers['X-RateLimit-Reset']) - int( time.time()) for delay in range(retry, 0, -1): kodi.notify("API Rate limit exceeded", "Retry in %s seconds(s)" % delay, timeout=1000) kodi.sleep(1000) return self.request(*request_args, **request_kwargs) elif response.status_code == 422 and 'Only the first 1000' in response.text: kodi.handel_error('Result count exceeds API limit.', 'Try different search or result filter.') kodi.close_busy_dialog() traceback.print_stack() else: kodi.close_busy_dialog() traceback.print_stack() raise githubException("Status %s: %s" % (response.status_code, response.text))
def handel_error(self, error, response, request_args, request_kwargs): if response.status_code == 401: traceback.print_stack() kodi.close_busy_dialog() raise githubException("Unauthorized: %s" % error) elif response.status_code == 403 and 'X-RateLimit-Reset' in response.headers: import time retry = int(response.headers['X-RateLimit-Reset']) - int(time.time()) for delay in range(retry, 0, -1): kodi.notify("API Rate limit exceeded", "Retry in %s seconds(s)" % delay, timeout=1000) kodi.sleep(1000) return self.request(*request_args, **request_kwargs) elif response.status_code == 422 and 'Only the first 1000' in response.text: kodi.handel_error('Result count exceeds API limit.', 'Try different search or result filter.') kodi.close_busy_dialog() traceback.print_stack() else: kodi.close_busy_dialog() traceback.print_stack() raise githubException("Status %s: %s" % (response.status_code, response.text))
def resolve_url(self, raw_url): from commoncore.dispatcher import WeightedDispatcher resolved_url = '' hash = self.get_hash(raw_url) kodi.set_property('Playback.Hash', hash) dispatcher = WeightedDispatcher() @dispatcher.register(kodi.get_setting('premiumize_priority', ADDON_ID), [raw_url]) def premiumize_resolver(raw_url): resolved_url = '' if kodi.get_setting('premiumize_enable', ADDON_ID) != 'true': return resolved_url attempt = 0 attempts = 5 try: response = premiumize.create_transfer(raw_url) id = response['id'] except: premiumize.clear_transfers() response = premiumize.create_transfer(raw_url) id = response['id'] try: while attempt < attempts: folder_id = False file_id = False target_folder_id = False kodi.log("Resolve Attempt %s" % attempt) temp = premiumize.list_transfers() for t in temp['transfers']: if t['id'] == id and t['status'] == 'finished': if 'target_folder_id' in t: target_folder_id = t['target_folder_id'] if 'folder_id' in t: folder_id = t['folder_id'] if 'file_id' in t: file_id = t['file_id'] break if file_id: response = premiumize.item_details(file_id) resolved_url = response['stream_link'] kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', file_id) return resolved_url if folder_id: response = premiumize.list_folder(folder_id) resolved_url = premiumize.get_folder_stream(response) kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', folder_id) return resolved_url if target_folder_id: response = premiumize.list_folder(target_folder_id) resolved_url = premiumize.get_folder_stream(response) kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', target_folder_id) return resolved_url attempt += 1 kodi.sleep(150) except: pass return resolved_url @dispatcher.register(kodi.get_setting('realdebrid_priority', ADDON_ID), [raw_url]) def realdebrid_resolver(raw_url): resolved_url = '' if kodi.get_setting('realdebrid_enable', ADDON_ID) != 'true': return resolved_url response = realdebrid.add_torrent(raw_url) try: torrent_id = response['id'] info = realdebrid.get_torrent_info(torrent_id) file_id = realdebrid.get_stream_file(info['files']) if not file_id: return realdebrid.select_torrent_files(torrent_id, file_id) kodi.sleep(500) info = realdebrid.get_torrent_info(torrent_id) raw_url = info['links'][0] kodi.set_property('Playback.Resolver', 'realdebrid') kodi.set_property('Playback.ID', torrent_id) resolved_url = realdebrid.resolve_url(raw_url) except: pass return resolved_url kodi.open_busy_dialog() try: resolved_url = dispatcher.run() except Exception, e: kodi.log(e) kodi.close_busy_dialog()
class TorrentScraper(BaseScraper): valid = (kodi.get_setting('premiumize_enable', ADDON_ID) == 'true' and kodi.get_setting('premiumize_username', ADDON_ID) != '' ) or kodi.get_setting('realdebrid_enable', ADDON_ID) == 'true' torrent = True return_cached = True def __init__(self): self._make_media_object = self.make_media_object def make_media_object(obj): media = self._make_media_object(obj) media['torrent'] = True return media self.make_media_object = make_media_object def get_hash_from_magnet(self, magnet): match = re.search("btih:([^&]+)&", magnet, re.IGNORECASE) if match: return match.group(1) else: return False def get_hash_from_url(self, url): match = re.search('([a-fA-F0-9]{40})', url) if match: return match.group(1) else: return False def get_hash(self, source): if source[0:6] == 'magnet': return self.get_hash_from_magnet(source) else: return self.get_hash_from_url(source) def check_hashes(self, hashes): results = {'realdebrid': {}, "premiumize": {}} if kodi.get_setting('realdebrid_enable', ADDON_ID) == 'true': results['realdebrid'] = realdebrid.check_hashes(hashes) if kodi.get_setting('premiumize_enable', ADDON_ID) == 'true': results['premiumize'] = premiumize.check_hashes(hashes) return results def get_torrent_services(self): pass def verify_hash(self, hash): if kodi.get_setting('realdebrid_enable', ADDON_ID) == 'true': try: if self.verified_hashes['realdebrid'][hash]['rd'] != []: return True except: pass if kodi.get_setting('premiumize_enable', ADDON_ID) == 'true': try: if self.verified_hashes['premiumize']['hashes'][hash][ 'status'] == 'finished': return True except: pass return False def verify_results(self, processor, results): hashes = [self.get_hash(r['raw_url']) for r in results] self.verified_hashes = self.check_hashes(hashes) for r in results: hash = self.get_hash(r['raw_url']) if self.verify_hash(hash): self.verify_result([r]) return (self.name, self.verified_results) def resolve_url(self, raw_url): from commoncore.dispatcher import WeightedDispatcher resolved_url = '' hash = self.get_hash(raw_url) kodi.set_property('Playback.Hash', hash) dispatcher = WeightedDispatcher() @dispatcher.register(kodi.get_setting('premiumize_priority', ADDON_ID), [raw_url]) def premiumize_resolver(raw_url): resolved_url = '' if kodi.get_setting('premiumize_enable', ADDON_ID) != 'true': return resolved_url attempt = 0 attempts = 5 try: response = premiumize.create_transfer(raw_url) id = response['id'] except: premiumize.clear_transfers() response = premiumize.create_transfer(raw_url) id = response['id'] try: while attempt < attempts: folder_id = False file_id = False target_folder_id = False kodi.log("Resolve Attempt %s" % attempt) temp = premiumize.list_transfers() for t in temp['transfers']: if t['id'] == id and t['status'] == 'finished': if 'target_folder_id' in t: target_folder_id = t['target_folder_id'] if 'folder_id' in t: folder_id = t['folder_id'] if 'file_id' in t: file_id = t['file_id'] break if file_id: response = premiumize.item_details(file_id) resolved_url = response['stream_link'] kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', file_id) return resolved_url if folder_id: response = premiumize.list_folder(folder_id) resolved_url = premiumize.get_folder_stream(response) kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', folder_id) return resolved_url if target_folder_id: response = premiumize.list_folder(target_folder_id) resolved_url = premiumize.get_folder_stream(response) kodi.set_property('Playback.Resolver', 'premiumize') kodi.set_property('Playback.ID', target_folder_id) return resolved_url attempt += 1 kodi.sleep(150) except: pass return resolved_url @dispatcher.register(kodi.get_setting('realdebrid_priority', ADDON_ID), [raw_url]) def realdebrid_resolver(raw_url): resolved_url = '' if kodi.get_setting('realdebrid_enable', ADDON_ID) != 'true': return resolved_url response = realdebrid.add_torrent(raw_url) try: torrent_id = response['id'] info = realdebrid.get_torrent_info(torrent_id) file_id = realdebrid.get_stream_file(info['files']) if not file_id: return realdebrid.select_torrent_files(torrent_id, file_id) kodi.sleep(500) info = realdebrid.get_torrent_info(torrent_id) raw_url = info['links'][0] kodi.set_property('Playback.Resolver', 'realdebrid') kodi.set_property('Playback.ID', torrent_id) resolved_url = realdebrid.resolve_url(raw_url) except: pass return resolved_url kodi.open_busy_dialog() try: resolved_url = dispatcher.run() except Exception, e: kodi.log(e) kodi.close_busy_dialog() kodi.close_busy_dialog() return resolved_url
def __init__(self, addon_id, url, full_name, destination, master=False, quiet=False, installed_list=[], batch=False): self.installed_list = installed_list self.quiet = quiet self.batch=batch if not self.quiet: kodi.open_busy_dialog() v = kodi.get_kodi_version() # Grab a list of KNOWN addons from the database. Unfortunately Jarvis requires direct database access for the installed flag if v >= 17: response = kodi.kodi_json_request("Addons.GetAddons", { "installed": False, "properties": ["path", "dependencies"]}) for a in response['result']['addons']: self.available_addons += [a['addonid']] self.source_table[a['addonid']] = a['path'] else: from sqlite3 import dbapi2 dbf = kodi.vfs.join("special://profile/Database", "Addons20.db") with dbapi2.connect(dbf) as dbh: dbc = dbh.cursor() dbc.execute("SELECT addon.addonID, broken.addonID is Null AS enabled, addon.path FROM addon LEFT JOIN broken on addon.addonID=broken.addonID WHERE enabled=1") for a in dbc.fetchall(): self.available_addons += [a[0]] self.source_table[a[0]] = a[2] dbh.close() self._addon_id = addon_id self._url = url self._full_name = full_name self._user, self.repo = full_name.split("/") self._master = master self._destination = destination # Add the final addon target to the sources list with type of zip # Initiate install routine self.install_addon(addon_id, url, full_name, master) completed = list(reversed(self.completed)) if not quiet: pb = kodi.ProgressBar() pb.new('Enabling Addons', len(completed)+1) pb.update_subheading('Building Addon List') kodi.run_command("XBMC.UpdateLocalAddons()") kodi.sleep(500) for addon_id in completed: if not quiet: #percent = 100* (completed.index(addon_id) / len(completed)) #pb.update(percent, "Enabling Addons", addon_id, '') pb.next(addon_id) kodi.sleep(100) self.enable_addon(addon_id) if not quiet: pb.next("Looking for Updates", "") kodi.sleep(500) kodi.run_command('XBMC.UpdateAddonRepos') # Enable installed addons if not self.quiet: pb.close() kodi.close_busy_dialog() if self.install_error: kodi.notify("Install failed", self._addon_id) else: kodi.notify("Install complete", self._addon_id)
def build_dependency_list(self, addon_id, url, full_name, master): #if test in ['xbmc.python', 'xbmc.gui'] or kodi.get_condition_visiblity('System.HasAddon(%s)' % addon_id) == 1: return True if addon_id in self.installed_list: kodi.log('Dependency is already installed: %s' % addon_id) return True user, repo = full_name.split("/") kodi.log('Finding dependencies for: %s' % addon_id) if master: self.sources[addon_id] = {"type": SOURCES.REPO, "url": url, "user": user, "repo": repo, "version": ""} xml_str = github.find_xml(full_name) self.sources[addon_id]['version'] = github.get_version_by_xml(BeautifulSoup(xml_str)) else: version = downloader.download(url, addon_id, self._destination, True, self.quiet) src_file = kodi.vfs.join("special://home/addons", addon_id) kodi.vfs.join(src_file, "addon.xml") xml = kodi.vfs.read_file(kodi.vfs.join(src_file, "addon.xml"), soup=True) self.save_source(addon_id, {"type": SOURCES.ZIP, "url": url, "user": user, "repo": repo, "version": version}) for dep in xml.findAll('import'): test = dep['addon'] try: if dep['optional'].lower() == 'true': if kodi.get_setting('install_optional') == 'false': continue elif kodi.get_setting('prompt_optional') == "true": c = kodi.dialog_confirm("Install Optional Dependency", dep['name'], dep['addon']) if not c: continue except: pass if test in ['xbmc.python', 'xbmc.gui'] or kodi.get_condition_visiblity('System.HasAddon(%s)' % test) == 1 or test in self.installed_list: kodi.log('Dependency is already installed: %s' % test) continue self.required_addons += [test] if test not in self.available_addons: self.unmet_addons += [test] else: self.sources[test] = {"type": SOURCES.DEFAULT, "url": self.source_table[test]} kodi.log("%s dependency met in %s" % (test, self.source_table[test])) def user_resolver(user, unmet): dep_url, dep_filename, dep_full_name, version = github.find_zip(user, unmet) if dep_url: kodi.log("%s found in %s repo" % (unmet, user)) self.met_addons.append(unmet) user, repo = dep_full_name.split("/") self.sources[unmet] = {"type": SOURCES.ZIP, "url": dep_url, "user": user, "repo": repo, "version": ""} kodi.log("%s dependency met in %s" % (unmet, dep_url)) return True return False def github_resolver(unmet): results = github.web_search(unmet) c = kodi.dialog_select("GitHub Search Results for %s" % unmet, [r['full_name'] for r in results['items']]) if c is not False: dep = results['items'][c] dep_url = url = "https://github.com/%s/archive/master.zip" % (dep['full_name']) self.met_addons.append(unmet) dep_filename = "%s.zip" % unmet self.sources[unmet] = {"type": SOURCES.REPO, "url": dep_url, "user": user, "repo": repo, "version": ""} kodi.log("%s dependency met in %s" % (unmet, dep_url)) self.install_addon(unmet, dep_url, dep['full_name'], master=True) return True return False for unmet in self.unmet_addons: # Now attempt to locate dependencies from available sources # The addons that can be found in any enabled repos will be installed at the end. # check if this exists in users root repo if kodi.get_setting('source_user') == 'true': if user_resolver(user, unmet): continue # check if this exists in tva root repo if kodi.get_setting('source_tva') == 'true': if user_resolver(tva_user, unmet): continue # check if this exists on github if kodi.get_setting('source_github') == 'true': if github_resolver(unmet): continue self.unmet_addons = list(set(self.unmet_addons) - set(self.met_addons)) if len(self.unmet_addons): self.install_error = True if not self.quiet: kodi.close_busy_dialog() kodi.raise_error("", "Unmet Dependencies:", "See log or install manually", ','.join(self.unmet_addons)) kodi.log("Unmet Dependencies for addon install: %s" % addon_id) # % self.addon_id) kodi.log(','.join(self.unmet_addons)) inserts = [(a, ) for a in self.unmet_addons] DB.execute_many("INSERT INTO failed_depends(addon_id) VALUES(?)", inserts) DB.commit() self.completed.append(addon_id)
def download(url, addon_id, destination, unzip=False, quiet=False): version = None filename = addon_id + '.zip' r = requests.get(url, stream=True) kodi.log("Download: %s" % url) if r.status_code == requests.codes.ok: temp_file = kodi.vfs.join(kodi.get_profile(), "downloads") if not kodi.vfs.exists(temp_file): kodi.vfs.mkdir(temp_file, recursive=True) temp_file = kodi.vfs.join(temp_file, filename) try: total_bytes = int(r.headers["Content-Length"]) except: total_bytes = 0 block_size = 1000 cached_bytes = 0 if not quiet: pb = xbmcgui.DialogProgress() pb.create("Downloading", filename, ' ', ' ') kodi.sleep(150) start = time.time() with open(temp_file, 'wb') as f: for block in r.iter_content(chunk_size=block_size): if not block: break if not quiet and pb.iscanceled(): raise downloaderException('Download Aborted') return False cached_bytes += len(block) f.write(block) if total_bytes > 0: delta = int(time.time() - start) if delta: bs = int(cached_bytes / (delta)) else: bs = 0 if not quiet: percent = int(cached_bytes * 100 / total_bytes) pb.update(percent, "Downloading", filename, format_status(cached_bytes, total_bytes, bs)) if not quiet: pb.close() if unzip: zip_ref = zipfile.ZipFile(temp_file, 'r') zip_ref.extractall(destination) zip_ref.close() kodi.vfs.rm(temp_file, quiet=True) try: xml = kodi.vfs.read_file(kodi.vfs.join( destination, kodi.vfs.join(addon_id, 'addon.xml')), soup=True) version = get_version_by_xml(xml) if not version: version = get_version_by_name(filename) except: kodi.log( "Unable to fine version from addon.xml for addon: %s" % addon_id) else: kodi.vfs.mv(temp_file, kodi.vfs.join(destination, filename)) else: kodi.close_busy_dialog() raise downloaderException(r.status_code) return version
def download(url, full_name, addon_id, destination, unzip=False, quiet=False, verify_hash=True): version = None filename = addon_id + ".zip" r = requests.get(url, stream=True) kodi.log("Download: %s" % url) if r.status_code == requests.codes.ok: temp_file = kodi.vfs.join(kodi.get_profile(), "downloads") if not kodi.vfs.exists(temp_file): kodi.vfs.mkdir(temp_file, recursive=True) temp_file = kodi.vfs.join(temp_file, filename) try: total_bytes = int(r.headers["Content-Length"]) except: total_bytes = 0 block_size = 1000 cached_bytes = 0 if not quiet: pb = xbmcgui.DialogProgress() pb.create("Downloading", filename, " ", " ") kodi.sleep(150) start = time.time() is_64bit = sys.maxsize > 2**32 with open(temp_file, "wb") as f: for chunk in r.iter_content(chunk_size=block_size): if chunk: if not quiet and pb.iscanceled(): raise downloaderException("Download Aborted") return False cached_bytes += len(chunk) shutil.copyfileobj(functionIO(chunk), f, 8096) if total_bytes > 0: delta = int(time.time() - start) if delta: bs = int(cached_bytes / (delta)) else: bs = 0 if not quiet: percent = int(cached_bytes * 100 / total_bytes) pb.update( percent, "Downloading", filename, format_status(cached_bytes, total_bytes, bs), ) if not quiet: pb.close() if verify_hash: local_sha = hash_func(temp_file, "sha1") remote_sha = get_sha(full_name, url) if remote_sha != local_sha: kodi.close_busy_dialog() kodi.handel_error("Download Error", "Checksum mismatch!") if unzip: if is_64bit: zip_ref = zipfile.ZipFile(temp_file, "r") else: with open(temp_file, "rb") as zip_file: zip_ref = zip_file.ZipFile(functionIO(zip_file.read())) zip_ref.extractall(destination) zip_ref.close() kodi.vfs.rm(temp_file, quiet=True) try: xml = kodi.vfs.read_file( kodi.vfs.join(destination, kodi.vfs.join(addon_id, "addon.xml")), soup=True, ) version = get_version_by_xml(xml) if not version: version = get_version_by_name(filename) except: kodi.log( "Unable to fine version from addon.xml for addon: %s" % addon_id) else: kodi.vfs.mv(temp_file, kodi.vfs.join(destination, filename)) else: kodi.close_busy_dialog() raise downloaderException(r.status_code) return version
def __init__(self, addon_id, url, full_name, destination, master=False, quiet=False, installed_list=[], batch=False): self.installed_list = installed_list self.quiet = quiet self.batch=batch if not self.quiet: kodi.open_busy_dialog() v = kodi.get_kodi_version() # Grab a list of KNOWN addons from the database. Unfortunately Jarvis requires direct database access for the installed flag if v >= 17: response = kodi.kodi_json_request("Addons.GetAddons", { "installed": False, "properties": ["path", "dependencies"]}) for a in response['result']['addons']: self.available_addons += [a['addonid']] self.source_table[a['addonid']] = a['path'] else: from sqlite3 import dbapi2 dbf = kodi.vfs.join("special://profile/Database", "Addons20.db") with dbapi2.connect(dbf) as dbh: dbc = dbh.cursor() dbc.execute("SELECT addon.addonID, broken.addonID is Null AS enabled, addon.path FROM addon LEFT JOIN broken on addon.addonID=broken.addonID WHERE enabled=1") for a in dbc.fetchall(): self.available_addons += [a[0]] self.source_table[a[0]] = a[2] dbh.close() self._addon_id = addon_id self._url = url self._full_name = full_name self._user, self.repo = full_name.split("/") self._master = master self._destination = destination # Add the final addon target to the sources list with type of zip # Initiate install routine self.install_addon(addon_id, url, full_name, master) completed = list(reversed(self.completed)) if not quiet: pb = kodi.ProgressBar() pb.new('Enabling Addons', len(completed)+1) pb.update_subheading('Building Addon List') kodi.run_command("XBMC.UpdateLocalAddons()") kodi.sleep(500) for addon_id in completed: if not quiet: #percent = 100* (completed.index(addon_id) / len(completed)) #pb.update(percent, "Enabling Addons", addon_id, '') pb.next(addon_id) kodi.sleep(100) self.enable_addon(addon_id) if not quiet: pb.next("Looking for Updates", "") kodi.sleep(500) kodi.run_command('XBMC.UpdateAddonRepos') # Enable installed addons if not self.quiet: pb.close() kodi.close_busy_dialog() if self.install_error: kodi.notify("Install failed", self._addon_id) else: kodi.notify("Install complete", self._addon_id)
def build_dependency_list(self, addon_id, url, full_name, master): #if test in ['xbmc.python', 'xbmc.gui'] or kodi.get_condition_visiblity('System.HasAddon(%s)' % addon_id) == 1: return True if addon_id in self.installed_list: kodi.log('Dependency is already installed: %s' % addon_id) return True user, repo = full_name.split("/") kodi.log('Finding dependencies for: %s' % addon_id) if master: self.sources[addon_id] = {"type": SOURCES.REPO, "url": url, "user": user, "repo": repo, "version": ""} xml_str = github.find_xml(full_name) self.sources[addon_id]['version'] = github.get_version_by_xml(BeautifulSoup(xml_str)) else: version = downloader.download(url, addon_id, self._destination, True, self.quiet) src_file = kodi.vfs.join("special://home/addons", addon_id) kodi.vfs.join(src_file, "addon.xml") xml = kodi.vfs.read_file(kodi.vfs.join(src_file, "addon.xml"), soup=True) self.save_source(addon_id, {"type": SOURCES.ZIP, "url": url, "user": user, "repo": repo, "version": version}) for dep in xml.findAll('import'): test = dep['addon'] try: if dep['optional'].lower() == 'true': if kodi.get_setting('install_optional') == 'false': continue elif kodi.get_setting('prompt_optional') == "true": c = kodi.dialog_confirm("Install Optional Dependency", dep['name'], dep['addon']) if not c: continue except: pass if test in ['xbmc.python', 'xbmc.gui'] or kodi.get_condition_visiblity('System.HasAddon(%s)' % test) == 1 or test in self.installed_list: kodi.log('Dependency is already installed: %s' % test) continue self.required_addons += [test] if test not in self.available_addons: self.unmet_addons += [test] else: self.sources[test] = {"type": SOURCES.DEFAULT, "url": self.source_table[test]} kodi.log("%s dependency met in %s" % (test, self.source_table[test])) def user_resolver(user, unmet): dep_url, dep_filename, dep_full_name, version = github.find_zip(user, unmet) if dep_url: kodi.log("%s found in %s repo" % (unmet, user)) self.met_addons.append(unmet) user, repo = dep_full_name.split("/") self.sources[unmet] = {"type": SOURCES.ZIP, "url": dep_url, "user": user, "repo": repo, "version": ""} kodi.log("%s dependency met in %s" % (unmet, dep_url)) return True return False def github_resolver(unmet): results = github.web_search(unmet) c = kodi.dialog_select("GitHub Search Results for %s" % unmet, [r['full_name'] for r in results['items']]) if c is not False: dep = results['items'][c] dep_url = url = "https://github.com/%s/archive/master.zip" % (dep['full_name']) self.met_addons.append(unmet) dep_filename = "%s.zip" % unmet self.sources[unmet] = {"type": SOURCES.REPO, "url": dep_url, "user": user, "repo": repo, "version": ""} kodi.log("%s dependency met in %s" % (unmet, dep_url)) self.install_addon(unmet, dep_url, dep['full_name'], master=True) return True return False for unmet in self.unmet_addons: # Now attempt to locate dependencies from available sources # The addons that can be found in any enabled repos will be installed at the end. # check if this exists in users root repo if kodi.get_setting('source_user') == 'true': if user_resolver(user, unmet): continue # check if this exists in tva root repo if kodi.get_setting('source_tva') == 'true': if user_resolver(tva_user, unmet): continue # check if this exists on github if kodi.get_setting('source_github') == 'true': if github_resolver(unmet): continue self.unmet_addons = list(set(self.unmet_addons) - set(self.met_addons)) if len(self.unmet_addons): self.install_error = True if not self.quiet: kodi.close_busy_dialog() kodi.raise_error("", "Unmet Dependencies:", "See log or install manually", ','.join(self.unmet_addons)) kodi.log("Unmet Dependencies for addon install: %s" % addon_id) # % self.addon_id) kodi.log(','.join(self.unmet_addons)) self.completed.append(addon_id)