def register(search, search_movie, search_episode): import base64 import json import sys try: payload = json.loads(base64.b64decode(sys.argv[1])) except: notify(ADDON.getLocalizedString(30102).encode('utf-8'), time=1000) return results = () method = { "search": search, "search_movie": search_movie, "search_episode": search_episode, }.get(payload["method"]) or (lambda *a, **kw: []) try: results = () objects = method(payload["search_object"]) if objects is not None: results = tuple(objects) finally: urllib2.urlopen( payload["callback_url"], data=json.dumps(results) )
def request(url, params={}, headers={}, data=None, method=None): if params: url = "".join([url, "?", urlencode(params)]) req = urllib2.Request(url) if method: req.get_method = lambda: method req.add_header("User-Agent", USER_AGENT) req.add_header("Accept-Encoding", "gzip") for k, v in headers.items(): req.add_header(k, v) if data: req.add_data(data) try: with closing(urllib2.urlopen(req)) as response: data = response.read() if response.headers.get("Content-Encoding", "") == "gzip": import zlib data = zlib.decompressobj(16 + zlib.MAX_WBITS).decompress(data) response.data = data response.json = lambda: parse_json(data) response.xml = lambda: parse_xml(data) return response except Exception as e: notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) map(log.error, traceback.format_exc().split("\n")) return None, None
def run(url_suffix=""): if not os.path.exists(os.path.join(xbmc.translatePath(ADDON.getAddonInfo("path")), ".firstrun")): notify(ADDON.getLocalizedString(30101).encode('utf-8')) system_information() return socket.setdefaulttimeout(300) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.info("Requesting %s" % url) try: data = _json(url) except Exception as e: map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (ADDON.getLocalizedString(30225).encode('utf-8'), e)) return if not data: return if data["content_type"]: xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, data["content_type"]) listitems = range(len(data["items"])) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = GetLocalizedString(item["label"]) if item["label2"][0:8] == "LOCALIZE": item["label2"] = GetLocalizedString(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"], iconImage=item["icon"], thumbnailImage=item["thumbnail"]) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in item["stream_info"].items(): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = GetLocalizedString(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in item["properties"].items(): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=True)
def reset_rpc(): try: data = [{ "method": "Reset", "params": [{}], "jsonrpc": "2.0" }] req = urllib2.Request(QUASARD_EXT_HOST, json.dumps(data), {"Content-type": "application/json"}) urllib2.urlopen(req) except Exception as e: notify("%s" % e)
def quasard_thread(monitor): crash_count = 0 try: monitor_abort = xbmc.Monitor() # For Kodi >= 14 while not monitor_abort.abortRequested(): log.info("quasard: starting quasard") proc = start_quasard(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if not proc: break threading.Thread(target=wait_for_abortRequested, args=[proc, monitor]).start() if PLATFORM["os"] == "windows": while proc.poll() is None: log.info(proc.stdout.readline()) else: # Kodi hangs on some Android (sigh...) systems when doing a blocking # read. We count on the fact that Quasar daemon flushes its log # output on \n, creating a pretty clean output import fcntl import select fd = proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while proc.poll() is None: try: to_read, _, _ = select.select([proc.stdout], [], []) for ro in to_read: line = ro.readline() if line == "": # write end is closed break log.info(line) except IOError: time.sleep(1) # nothing to read, sleep log.info("quasard: proc.return code: %s" % str(proc.returncode)) if proc.returncode == 0 or proc.returncode == -9 or monitor_abort.abortRequested( ): break crash_count += 1 notify(getLocalizedString(30100), time=3000) xbmc.executebuiltin("Dialog.Close(all, true)") system_information() time.sleep(5) if crash_count >= 3: notify(getLocalizedString(30110), time=3000) break except Exception as e: import traceback list(map(log.error, traceback.format_exc().split("\n"))) if not PY3: notify("%s: %s" % (getLocalizedString(30226), repr(e).encode('utf-8'))) else: notify("%s: %s" % (getLocalizedString(30226), repr(e))) raise
def quasard_thread(monitor): try: while not xbmc.abortRequested: log.info("quasard: starting quasard") proc = start_quasard(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if not proc: break threading.Thread(target=wait_for_abortRequested, args=[proc, monitor]).start() if PLATFORM["os"] == "windows": while proc.poll() is None: log.info(proc.stdout.readline()) else: # Kodi hangs on some Android (sigh...) systems when doing a blocking # read. We count on the fact that Quasar daemon flushes its log # output on \n, creating a pretty clean output import fcntl import select fd = proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while proc.poll() is None: try: to_read, _, _ = select.select([proc.stdout], [], []) for ro in to_read: line = ro.readline() if line == "": # write end is closed break log.info(line) except IOError: time.sleep(1) # nothing to read, sleep if proc.returncode == 0 or xbmc.abortRequested: break notify(ADDON.getLocalizedString(30100).encode('utf-8'), time=3000) xbmc.executebuiltin("Dialog.Close(all, true)") system_information() time.sleep(3) except Exception as e: notify("%s: %s" % (ADDON.getLocalizedString(30226).encode('utf-8'), e)) map(log.error, traceback.format_exc().split("\n")) raise
def AddonFailure(self, addonId): if ADDON.getSetting("provider_disable_failing") == u"false": return 0 if addonId in self._failures: self._failures[addonId] += 1 else: self._failures[addonId] = 1 log.warning("Recorded failure %d for %s" % (self._failures[addonId], addonId)) if self._failures[addonId] > int(ADDON.getSetting("provider_allowed_failures")): try: time.sleep(10) notify(getLocalizedString(30111)) urllib2.urlopen("%s/provider/%s/disable" % (QUASARD_HOST, addonId)) except: notify(getLocalizedString(30112)) return 0 return self._failures[addonId]
def AddonFailure(self, addonId): if ADDON.getSetting("provider_disable_failing") == u"false": return 0 if addonId in self._failures: self._failures[addonId] += 1 else: self._failures[addonId] = 1 log.warning("Recorded failure %d for %s" % (self._failures[addonId], addonId)) if self._failures[addonId] > int(ADDON.getSetting("provider_allowed_failures")): try: time.sleep(10) notify(ADDON.getLocalizedString(30111).encode('utf-8')) urllib2.urlopen("%s/provider/%s/disable" % (QUASARD_HOST, addonId)) except: notify(ADDON.getLocalizedString(30112).encode('utf-8')) return 0 return self._failures[addonId]
def register(search, search_movie, search_episode): try: payload = json.loads(base64.b64decode(sys.argv[1])) except: notify(ADDON.getLocalizedString(30102).encode('utf-8'), time=1000) return results = () method = { "search": search, "search_movie": search_movie, "search_episode": search_episode, }.get(payload["method"]) or (lambda *a, **kw: []) try: results = () try: objects = method(payload["search_object"]) if objects is not None: results = tuple(objects) except Exception as e: notify("%s: %s" % (ADDON.getLocalizedString(30224).encode('utf-8'), e)) map(log.error, traceback.format_exc().split("\n")) finally: try: req = urllib2.Request(payload["callback_url"], data=json.dumps(results)) with closing(urllib2.urlopen(req)) as response: log.info("%s" % repr(response)) except Exception as e: notify("%s: %s" % (ADDON.getLocalizedString(30224).encode('utf-8'), e)) map(log.error, traceback.format_exc().split("\n"))
def quasard_thread(monitor): try: import xbmc while not xbmc.abortRequested: log.info("quasard: starting quasard") proc = start_quasard(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) threading.Thread(target=wait_for_abortRequested, args=[proc, monitor]).start() if PLATFORM["os"] == "windows": while proc.poll() is None: log.info(proc.stdout.readline()) else: # Kodi hangs on some Android (sigh...) systems when doing a blocking # read. We count on the fact that Quasar daemon flushes its log # output on \n, creating a pretty clean output import fcntl fd = proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while proc.poll() is None: try: log.info(proc.stdout.readline()) continue except IOError: time.sleep(1) # nothing to read, sleep if proc.returncode == 0 or xbmc.abortRequested: break notify(ADDON.getLocalizedString(30100).encode('utf-8'), time=1000) reset_rpc() time.sleep(3) except Exception: import xbmc import traceback map(xbmc.log, traceback.format_exc().split("\n")) raise
def register(search, search_movie, search_episode, search_season=None): try: payload = json.loads(base64.b64decode(sys.argv[1])) except: notify(getLocalizedString(30102), time=1000) return results = () method = { "search": search, "search_movie": search_movie, "search_season": search_season, "search_episode": search_episode, }.get(payload["method"]) or (lambda *a, **kw: []) try: results = () try: objects = method(payload["search_object"]) if objects is not None: results = tuple(objects) except Exception as e: import traceback list(map(log.error, traceback.format_exc().split("\n"))) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib.request.urlopen("%s/provider/%s/failure" % (QUASARD_HOST, ADDON_ID)) except: pass finally: try: req = urllib.request.Request(payload["callback_url"], data=json.dumps(results)) with closing(urllib.request.urlopen(req)) as response: log.debug("callback returned: %d" % response.getcode()) except Exception as e: import traceback list(map(log.error, traceback.format_exc().split("\n"))) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib.request.urlopen("%s/provider/%s/failure" % (QUASARD_HOST, ADDON_ID)) except: pass
def register(search, search_movie, search_episode, search_season=None): try: payload = json.loads(base64.b64decode(sys.argv[1])) except: notify(getLocalizedString(30102), time=1000) return results = () method = { "search": search, "search_movie": search_movie, "search_season": search_season, "search_episode": search_episode, }.get(payload["method"]) or (lambda *a, **kw: []) try: results = () try: objects = method(payload["search_object"]) if objects is not None: results = tuple(objects) except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib2.urlopen("%s/provider/%s/failure" % (QUASARD_HOST, ADDON_ID)) except: pass finally: try: req = urllib2.Request(payload["callback_url"], data=json.dumps(results)) with closing(urllib2.urlopen(req)) as response: log.debug("callback returned: %d" % response.getcode()) except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib2.urlopen("%s/provider/%s/failure" % (QUASARD_HOST, ADDON_ID)) except: pass
def get_quasar_binary(): binary = "quasar" + (PLATFORM["os"] == "windows" and ".exe" or "") log.info("PLATFORM: %s" % str(PLATFORM)) binary_dir = os.path.join(ADDON_PATH, "resources", "bin", "%(os)s_%(arch)s" % PLATFORM) if PLATFORM["os"] == "android": log.info("Detected binary folder: %s" % binary_dir) binary_dir_legacy = binary_dir.replace("/storage/emulated/0", "/storage/emulated/legacy") if os.path.exists(binary_dir_legacy): binary_dir = binary_dir_legacy app_id = android_get_current_appid() xbmc_data_path = translatePath("special://xbmcbin/").replace('user/0', 'data').replace('cache/apk/assets', 'files/quasar') log.info("Trying binary Kodi folder: %s" % xbmc_data_path) try: #Test if there is any permisions problem if not os.path.exists(xbmc_data_path): os.makedirs(xbmc_data_path) except Exception as e: log.info("ERROR %s in binary Kodi folder: %s" % (str(e), xbmc_data_path)) if not os.path.exists(xbmc_data_path): xbmc_data_path = translatePath("special://xbmcbin/").replace('cache/apk/assets', 'files/quasar') log.info("Trying alternative binary Kodi folder: %s" % xbmc_data_path) try: #Test if there is any permisions problem if not os.path.exists(xbmc_data_path): os.makedirs(xbmc_data_path) except Exception as e: log.info("ERROR %s in alternative binary Kodi folder: %s" % (str(e), xbmc_data_path)) dest_binary_dir = xbmc_data_path else: if not PY3: dest_binary_dir = os.path.join(translatePath(ADDON.getAddonInfo("profile")).decode('utf-8'), "bin", "%(os)s_%(arch)s" % PLATFORM) else: dest_binary_dir = os.path.join(translatePath(ADDON.getAddonInfo("profile")), "bin", "%(os)s_%(arch)s" % PLATFORM) if PY3 and isinstance(dest_binary_dir, bytes): dest_binary_dir = dest_binary_dir.decode("utf8") log.info("Using destination binary folder: %s" % dest_binary_dir) binary_path = os.path.join(binary_dir, binary) dest_binary_path = os.path.join(dest_binary_dir, binary) if not os.path.exists(binary_path): notify((getLocalizedString(30103) + " %(os)s_%(arch)s" % PLATFORM), time=7000) system_information() try: log.info("Source directory (%s):\n%s" % (binary_dir, os.listdir(os.path.join(binary_dir, "..")))) log.info("Destination directory (%s):\n%s" % (dest_binary_dir, os.listdir(os.path.join(dest_binary_dir, "..")))) except Exception: pass #return False, False if os.path.isdir(dest_binary_path): log.warning("Destination path is a directory, expected previous binary file, removing...") try: shutil.rmtree(dest_binary_path) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() #return False, False if not os.path.exists(dest_binary_path) or get_quasard_checksum(dest_binary_path) != get_quasard_checksum(binary_path): log.info("Updating quasar daemon...") try: os.makedirs(dest_binary_dir) except OSError: pass try: shutil.rmtree(dest_binary_dir) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() #return False, False try: shutil.copytree(binary_dir, dest_binary_dir) except Exception as e: log.error("Unable to copy to destination path for update: %s" % e) system_information() #return False, False # Clean stale files in the directory, as this can cause headaches on # Android when they are unreachable if os.path.exists(dest_binary_dir): try: dest_files = set(os.listdir(dest_binary_dir)) orig_files = set(os.listdir(binary_dir)) log.info("Deleting stale files %s" % (dest_files - orig_files)) for file_ in (dest_files - orig_files): path = os.path.join(dest_binary_dir, file_) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) except: pass return dest_binary_dir, ensure_exec_perms(dest_binary_path)
def Notify(self, header, message, image): return notify(GetLocalizedString(message), header, 3000, image)
def get_quasar_binary(): binary = "quasar" + (PLATFORM["os"] == "windows" and ".exe" or "") log.info("PLATFORM: %s" % str(PLATFORM)) binary_dir = os.path.join(ADDON_PATH, "resources", "bin", "%(os)s_%(arch)s" % PLATFORM) if PLATFORM["os"] == "android": log.info("Detected binary folder: %s" % binary_dir) binary_dir_legacy = binary_dir.replace("/storage/emulated/0", "/storage/emulated/legacy") if os.path.exists(binary_dir_legacy): binary_dir = binary_dir_legacy log.info("Using binary folder: %s" % binary_dir) app_id = android_get_current_appid() xbmc_data_path = os.path.join("/data", "data", app_id) try: #Test if there is any permisions problem f = open(os.path.join(xbmc_data_path, "test.txt"), "wb") f.write("test") f.close() os.remove(os.path.join(xbmc_data_path, "test.txt")) except: xbmc_data_path = '' if not os.path.exists(xbmc_data_path): log.info("%s path does not exist, so using %s as xbmc_data_path" % (xbmc_data_path, xbmc.translatePath("special://xbmcbin/"))) xbmc_data_path = xbmc.translatePath("special://xbmcbin/") try: #Test if there is any permisions problem f = open(os.path.join(xbmc_data_path, "test.txt"), "wb") f.write("test") f.close() os.remove(os.path.join(xbmc_data_path, "test.txt")) except: xbmc_data_path = '' if not os.path.exists(xbmc_data_path): log.info("%s path does not exist, so using %s as xbmc_data_path" % (xbmc_data_path, xbmc.translatePath("special://masterprofile/"))) xbmc_data_path = xbmc.translatePath("special://masterprofile/") dest_binary_dir = os.path.join(xbmc_data_path, "files", ADDON_ID, "bin", "%(os)s_%(arch)s" % PLATFORM) else: dest_binary_dir = os.path.join(xbmc.translatePath(ADDON.getAddonInfo("profile")).decode('utf-8'), "bin", "%(os)s_%(arch)s" % PLATFORM) log.info("Using destination binary folder: %s" % dest_binary_dir) binary_path = os.path.join(binary_dir, binary) dest_binary_path = os.path.join(dest_binary_dir, binary) if not os.path.exists(binary_path): notify((getLocalizedString(30103) + " %(os)s_%(arch)s" % PLATFORM), time=7000) system_information() try: log.info("Source directory (%s):\n%s" % (binary_dir, os.listdir(os.path.join(binary_dir, "..")))) log.info("Destination directory (%s):\n%s" % (dest_binary_dir, os.listdir(os.path.join(dest_binary_dir, "..")))) except Exception: pass return False, False if os.path.isdir(dest_binary_path): log.warning("Destination path is a directory, expected previous binary file, removing...") try: shutil.rmtree(dest_binary_path) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() return False, False if not os.path.exists(dest_binary_path) or get_quasard_checksum(dest_binary_path) != get_quasard_checksum(binary_path): log.info("Updating quasar daemon...") try: os.makedirs(dest_binary_dir) except OSError: pass try: shutil.rmtree(dest_binary_dir) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() pass try: shutil.copytree(binary_dir, dest_binary_dir) except Exception as e: log.error("Unable to copy to destination path for update: %s" % e) system_information() return False, False # Clean stale files in the directory, as this can cause headaches on # Android when they are unreachable dest_files = set(os.listdir(dest_binary_dir)) orig_files = set(os.listdir(binary_dir)) log.info("Deleting stale files %s" % (dest_files - orig_files)) for file_ in (dest_files - orig_files): path = os.path.join(dest_binary_dir, file_) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) return dest_binary_dir, ensure_exec_perms(dest_binary_path)
def Notify(self, header, message, image): return notify(getLocalizedLabel(message), header, 3000, image)
def get_quasar_binary(): binary = "quasar" + (PLATFORM["os"] == "windows" and ".exe" or "") binary_dir = os.path.join(ADDON.getAddonInfo("path"), "resources", "bin", "%(os)s_%(arch)s" % PLATFORM) if PLATFORM["os"] == "android": log.info("Detected binary folder: %s" % binary_dir) binary_dir_legacy = binary_dir.replace("/storage/emulated/0", "/storage/emulated/legacy") if os.path.exists(binary_dir_legacy): binary_dir = binary_dir_legacy log.info("Using binary folder: %s" % binary_dir) app_id = android_get_current_appid() xbmc_data_path = os.path.join("/data", "data", app_id) dest_binary_dir = os.path.join(xbmc_data_path, "files", ADDON_ID, "bin", "%(os)s_%(arch)s" % PLATFORM) else: dest_binary_dir = os.path.join(xbmc.translatePath(ADDON.getAddonInfo("profile")), "bin", "%(os)s_%(arch)s" % PLATFORM) try: binary_dir = binary_dir.decode("latin1") dest_binary_dir = dest_binary_dir.decode("latin1") except UnicodeEncodeError: log.info("Unable to decode: binary_dir=%s dest_binary_dir=%s" % (repr(binary_dir), repr(dest_binary_dir))) binary_path = os.path.join(binary_dir, binary) dest_binary_path = os.path.join(dest_binary_dir, binary) if not os.path.exists(binary_path): notify(ADDON.getLocalizedString(30103).encode('utf-8')) system_information() return False, False if not os.path.exists(dest_binary_path) or get_quasard_checksum(dest_binary_path) != get_quasard_checksum(binary_path): log.info("Updating quasar daemon...") try: os.makedirs(dest_binary_dir) except OSError: pass try: shutil.rmtree(dest_binary_dir) except OSError as e: log.error("Unable to remove destination path for update: %s" % e) system_information() pass try: shutil.copytree(binary_dir, dest_binary_dir) except OSError as e: log.error("Unable to copy to destination path for update: %s" % e) notify(ADDON.getLocalizedString(30227).encode('utf-8')) system_information() pass # Clean stale files in the directory, as this can cause headaches on # Android when they are unreachable dest_files = set(os.listdir(dest_binary_dir)) orig_files = set(os.listdir(binary_dir)) log.info("Deleting stale files %s" % (dest_files - orig_files)) for file_ in (dest_files - orig_files): path = os.path.join(dest_binary_dir, file_) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) return dest_binary_dir, ensure_exec_perms(dest_binary_path)
def run(url_suffix=""): if not os.path.exists(os.path.join(ADDON_PATH, ".firstrun")): notify(getLocalizedString(30101)) system_information() return donatePath = os.path.join(ADDON_PATH, ".donate") if not os.path.exists(donatePath): with open(donatePath, "w"): os.utime(donatePath, None) dialog = xbmcgui.Dialog() dialog.ok("Quasar", getLocalizedString(30141)) socket.setdefaulttimeout(int(ADDON.getSetting("buffer_timeout"))) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except urllib2.URLError as e: if 'Connection refused' in e.reason: notify(getLocalizedString(30116), time=7000) else: import traceback map(log.error, traceback.format_exc().split("\n")) notify(e.reason, time=7000) return except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) try: msg = unicode(e) except: try: msg = str(e) except: msg = repr(e) notify(getLocalizedLabel(msg), time=7000) return if not data: return if data["content_type"]: content_type = data["content_type"] if data["content_type"].startswith("menus"): content_type = data["content_type"].split("_")[1] xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) if content_type != "tvshows": xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, content_type) listitems = range(len(data["items"])) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = unicode(getLocalizedLabel(item["label"]), 'utf-8') if item["label2"][0:8] == "LOCALIZE": item["label2"] = getLocalizedLabel(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"], iconImage=item["icon"], thumbnailImage=item["thumbnail"]) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in item["stream_info"].items(): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) elif ADDON.getSetting('default_fanart') == 'true' and item["label"] != unicode(getLocalizedString(30218), 'utf-8'): fanart = os.path.join(ADDON_PATH, "fanart.jpg") listItem.setArt({'fanart': fanart}) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = getLocalizedLabel(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in item["properties"].items(): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) # Set ViewMode if data["content_type"]: viewMode = ADDON.getSetting("viewmode_%s" % data["content_type"]) if viewMode: try: xbmc.executebuiltin('Container.SetViewMode(%s)' % viewMode) except Exception as e: log.warning("Unable to SetViewMode(%s): %s" % (viewMode, repr(e))) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=True)
def run(url_suffix=""): if not os.path.exists(os.path.join(xbmc.translatePath(ADDON.getAddonInfo("path")), ".firstrun")): notify(getLocalizedString(30101)) system_information() return donatePath = os.path.join(xbmc.translatePath(ADDON.getAddonInfo("path")), ".donate") if not os.path.exists(donatePath): with open(donatePath, "w"): os.utime(donatePath, None) dialog = xbmcgui.Dialog() dialog.ok("Quasar", "Please support Quasar development by visiting https://quasar.surge.sh to donate with Bitcoin, or buying a VPN subscription using the affiliate link at the bottom.") socket.setdefaulttimeout(300) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except Exception as e: map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30225), repr(e).encode('utf-8'))) return if not data: return if data["content_type"]: xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) if data["content_type"] != "tvshows": xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, data["content_type"]) listitems = range(len(data["items"])) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = getLocalizedLabel(item["label"]) if item["label2"][0:8] == "LOCALIZE": item["label2"] = getLocalizedLabel(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"], iconImage=item["icon"], thumbnailImage=item["thumbnail"]) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in item["stream_info"].items(): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = getLocalizedLabel(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in item["properties"].items(): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) # Set ViewMode if data["content_type"]: viewMode = ADDON.getSetting("viewmode_%s" % data["content_type"]) try: xbmc.executebuiltin('Container.SetViewMode(%s)' % (viewMode)) except Exception as e: log.warning("Unable to SetViewMode(%s): %s" % (viewMode, repr(e))) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=True)
def run(url_suffix=""): if not os.path.exists(os.path.join(ADDON_PATH, ".firstrun")): notify(getLocalizedString(30101)) system_information() return donatePath = os.path.join(ADDON_PATH, ".donate") if not os.path.exists(donatePath): with open(donatePath, "w"): os.utime(donatePath, None) dialog = xbmcgui.Dialog() dialog.ok("Quasar", getLocalizedString(30141)) socket.setdefaulttimeout(int(ADDON.getSetting("buffer_timeout"))) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) # Pause currently playing Quasar file to avoid doubling requests if xbmc.Player().isPlaying() and ADDON_ID in xbmc.Player().getPlayingFile(): xbmc.Player().pause() url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except urllib2.URLError as e: if 'Connection refused' in e.reason: notify(getLocalizedString(30116), time=7000) else: import traceback list(map(log.error, traceback.format_exc().split("\n"))) notify(e.reason, time=7000) return except Exception as e: import traceback list(map(log.error, traceback.format_exc().split("\n"))) try: msg = unicode(e) except: try: msg = str(e) except: msg = repr(e) notify(getLocalizedLabel(msg), time=7000) return if not data: return if data["content_type"]: content_type = data["content_type"] if data["content_type"].startswith("menus"): content_type = data["content_type"].split("_")[1] xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) if content_type != "tvshows": xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) else: xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_TITLE_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, content_type) listitems = list(range(len(data["items"]))) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": if not PY3: item["label"] = unicode(getLocalizedLabel(item["label"]), 'utf-8') else: item["label"] = getLocalizedLabel(item["label"]) if isinstance(item["label"], bytes): item["label"] = item["label"].decode("utf8") if item["label2"][0:8] == "LOCALIZE": item["label2"] = getLocalizedLabel(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"]) listItem.setArt({'icon': item["icon"]}) listItem.setArt({'thumb': item["thumbnail"]}) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in list(item["stream_info"].items()): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) elif ADDON.getSetting('default_fanart') == 'true' and ((not PY3 and item["label"] != unicode(getLocalizedString(30218), 'utf-8')) or (PY3 and item["label"] != str(getLocalizedString(30218)))): fanart = os.path.join(ADDON_PATH, "fanart.jpg") listItem.setArt({'fanart': fanart}) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = getLocalizedLabel(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in list(item["properties"].items()): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) # Set ViewMode if data["content_type"]: viewMode = ADDON.getSetting("viewmode_%s" % data["content_type"]) if viewMode: try: xbmc.executebuiltin('Container.SetViewMode(%s)' % viewMode) except Exception as e: log.warning("Unable to SetViewMode(%s): %s" % (viewMode, repr(e))) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=False)
def get_quasar_binary(): binary = "quasar" + (PLATFORM["os"] == "windows" and ".exe" or "") binary_dir = os.path.join(ADDON.getAddonInfo("path"), "resources", "bin", "%(os)s_%(arch)s" % PLATFORM) if PLATFORM["os"] == "android": log.info("Detected binary folder: %s" % binary_dir) binary_dir_legacy = binary_dir.replace("/storage/emulated/0", "/storage/emulated/legacy") if os.path.exists(binary_dir_legacy): binary_dir = binary_dir_legacy log.info("Using binary folder: %s" % binary_dir) app_id = android_get_current_appid() xbmc_data_path = os.path.join("/data", "data", app_id) dest_binary_dir = os.path.join(xbmc_data_path, "files", ADDON_ID, "bin", "%(os)s_%(arch)s" % PLATFORM) else: dest_binary_dir = os.path.join( xbmc.translatePath(ADDON.getAddonInfo("profile")), "bin", "%(os)s_%(arch)s" % PLATFORM) try: binary_dir = binary_dir.decode("latin1") dest_binary_dir = dest_binary_dir.decode("latin1") except UnicodeEncodeError: log.info("Unable to decode: binary_dir=%s dest_binary_dir=%s" % (repr(binary_dir), repr(dest_binary_dir))) binary_path = os.path.join(binary_dir, binary) dest_binary_path = os.path.join(dest_binary_dir, binary) if not os.path.exists(binary_path): notify(ADDON.getLocalizedString(30103).encode('utf-8')) system_information() return False, False if not os.path.exists(dest_binary_path) or get_quasard_checksum( dest_binary_path) != get_quasard_checksum(binary_path): log.info("Updating quasar daemon...") try: os.makedirs(dest_binary_dir) except OSError: pass try: shutil.rmtree(dest_binary_dir) except OSError as e: log.error("Unable to remove destination path for update: %s" % e) system_information() pass try: shutil.copytree(binary_dir, dest_binary_dir) except OSError as e: log.error("Unable to copy to destination path for update: %s" % e) notify(ADDON.getLocalizedString(30227).encode('utf-8')) system_information() pass # Clean stale files in the directory, as this can cause headaches on # Android when they are unreachable dest_files = set(os.listdir(dest_binary_dir)) orig_files = set(os.listdir(binary_dir)) log.info("Deleting stale files %s" % (dest_files - orig_files)) for file_ in (dest_files - orig_files): path = os.path.join(dest_binary_dir, file_) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) return dest_binary_dir, ensure_exec_perms(dest_binary_path)
def binary_stat(p, action, retry=False, init=False, app_response={}): if init: log.info('## Binary_stat: action: %s; PID: %s; retry: %s; init: %s; awake: %s; app_r: %s' % \ (action, p.pid, retry, init, p.binary_awake, app_response)) import traceback import base64 import requests import json import time import xbmc try: if action in ['poll', 'communicate']: url = p.url_app + '/getBinaryStatus?pid=%s&flushAfterRead=true' % str(p.pid) url_alt = p.url_app_alt + '/getBinaryStatus?pid=%s&flushAfterRead=true' % str(p.pid) if action == 'killBinary': url = p.url_app + '/killBinary?pid=%s' % str(p.pid) url_alt = p.url_app_alt + '/killBinary?pid=%s' % str(p.pid) url_close = p.url_app + '/terminate' cmd_android = 'StartAndroidActivity("%s", "", "%s", "%s")' % (p.app, 'open', 'about:blank') cmd_android_quit = 'StartAndroidActivity("%s", "", "%s", "%s")' % (p.app, 'quit', 'about:blank') cmd_android_close = 'StartAndroidActivity("%s", "", "%s", "%s")' % (p.app, 'terminate', 'about:blank') cmd_android_permissions = 'StartAndroidActivity("%s", "", "%s", "%s")' % (p.app, 'checkPermissions', 'about:blank') finished = False retry_req = False retry_app = False stdout_acum = '' stderr_acum = '' msg = '' binary_awake = 0 binary_awake_safe = 300*1000 while not finished: if not app_response.get('retCode', 0) >= 999: try: resp = p.sess.get(url, timeout=5) except Exception as e: resp = requests.Response() resp.status_code = str(e) if resp.status_code != 200 and not retry_req: if action == 'killBinary' or p.monitor.abortRequested(): app_response = {'pid': p.pid, 'retCode': 998} else: log.error("## Binary_stat: Invalid app requests response for PID: %s: %s - retry: %s - awake: %s" % \ (p.pid, resp.status_code, retry_req, p.binary_awake)) retry_req = True url = url_alt msg += str(resp.status_code) stdout_acum += str(resp.status_code) xbmc.executebuiltin(cmd_android) binary_awake = (int(time.time()) - int(p.binary_time)) * 1000 - binary_awake_safe if binary_awake < binary_awake_safe: binary_awake = 0 log.info('## Time.awake: %s; binary_awake: %s; p.binary_awake: %s' % \ ((int(time.time()) - int(p.binary_time))*1000, binary_awake, p.binary_awake)) time.sleep(5) continue if resp.status_code != 200 and retry_req and app_response.get('retCode', 0) != 999: log.error("## Binary_stat: Invalid app requests response for PID: %s: %s - retry: %s - awake: %s. Closing Assistant" % \ (p.pid, resp.status_code, retry_req, p.binary_awake)) msg += str(resp.status_code) stdout_acum += str(resp.status_code) app_response = {'pid': p.pid, 'retCode': 999} if p.torrest: time.sleep(10) # let Torrest recover first else: xbmc.executebuiltin(cmd_android_close) time.sleep(5) xbmc.executebuiltin(cmd_android) if binary_awake > binary_awake_safe: if p.binary_awake: if binary_awake < p.binary_awake: p.binary_awake = binary_awake else: p.binary_awake = binary_awake time.sleep(5) log.info('## Time.awake: %s; binary_awake: %s; p.binary_awake: %s' % \ ((int(time.time()) - int(p.binary_time))*1000, binary_awake, p.binary_awake)) try: if not 'awakingInterval' in url: url += '&awakingInterval=%s' % p.binary_awake resp = p.sess.get(url, timeout=5) except: pass time.sleep(1) continue time.sleep(5) continue if resp.status_code == 200: try: app_response = resp.content if PY3 and isinstance(app_response, bytes): app_response = app_response.decode() app_response_save = app_response app_response = re.sub('\n|\r|\t', '', app_response) app_response = json.loads(app_response) test_json = app_response["pid"] except: status_code = resp.content log.error("## Binary_stat: Invalid app response for PID: %s: %s - retry: %s - awake: %s" % \ (p.pid, resp.content, retry_app, p.binary_awake)) if retry_app: app_response = {'pid': p.pid} app_response['retCode'] = 999 msg += app_response_save stdout_acum += app_response_save else: retry_app = True app_response = {} if not p.torrest: if not 'awakingInterval' in url and (binary_awake > 0 or p.binary_awake > 0): if p.binary_awake: if binary_awake and binary_awake < p.binary_awake: p.binary_awake = binary_awake else: p.binary_awake = binary_awake url += '&awakingInterval=%s' % p.binary_awake log.info('## Time.awake: %s; binary_awake: %s; p.binary_awake: %s' % \ ((int(time.time()) - int(p.binary_time))*1000, binary_awake, p.binary_awake)) time.sleep(1) continue if app_response.get("pid", 0): if app_response.get('output'): stdout_acum += base64.b64decode(app_response['output']).decode('utf-8') msg += base64.b64decode(app_response['output']).decode('utf-8') if app_response.get('error'): stderr_acum += base64.b64decode(app_response['error']).decode('utf-8') msg += base64.b64decode(app_response['error']).decode('utf-8') if app_response.get('startDate'): p.startDate = base64.b64decode(app_response['startDate']).decode('utf-8') if app_response.get('endDate'): p.endDate = base64.b64decode(app_response['endDate']).decode('utf-8') if app_response.get('cmd'): p.cmd_app = base64.b64decode(app_response['cmd']).decode('utf-8') if app_response.get('finalCmd'): p.finalCmd = base64.b64decode(app_response['finalCmd']).decode('utf-8') # If still app permissions not allowed, give it a retry if 'permission denied' in msg: notify('Accept Assitant permissions', time=15000) time.sleep(5) xbmc.executebuiltin(cmd_android_permissions) time.sleep(10) xbmc.executebuiltin(cmd_android_quit) time.sleep(5) if msg: try: for line in msg.split('\n'): line += '\n' if PY3 and not isinstance(line, (bytes, bytearray)): line = line.encode('utf-8') p.stdin.write(line) p.stdin.flush() except: pass p.returncode = None if action == 'killBinary' and not app_response.get('retCode', ''): app_response['retCode'] = 137 if app_response.get('retCode', '') or action == 'killBinary' or \ (action == 'communicate' and app_response.get('retCode', '') != ''): try: p.stdin.flush() p.stdin.close() except: pass try: p.returncode = int(app_response['retCode']) except: p.returncode = app_response['retCode'] if action == 'communicate' and p.returncode is not None: log.info("## Binary_stat: communicate Quasar: %s - Returncode: %s" % (p.pid, p.returncode)) return stdout_acum, stderr_acum elif action == 'poll': if init and msg: #log.warning('## Binary_stat: Quasar initial response: %s' % msg) return True return p.returncode elif action == 'killBinary': log.info("## Binary_stat: killBinary Quasar: %s - Returncode: %s" % (p.pid, p.returncode)) try: if p.monitor.abortRequested(): if not p.torrest: try: resp_t = p.sess.get(url_close, timeout=1) except: pass elif p.returncode == 998: if not p.torrest: xbmc.executebuiltin(cmd_android_close) time.sleep(10) except: logging.info(traceback.format_exc()) time.sleep(1) if not p.torrest: xbmc.executebuiltin(cmd_android_close) time.sleep(2) return p time.sleep(5) msg = '' app_response = {} except: log.error(traceback.format_exc()) return None
def install_app(APP_PARAMS): import traceback import requests import xbmc import time try: user_params = {} apk_OK = False ANDROID_STORAGE = os.getenv('ANDROID_STORAGE') if not ANDROID_STORAGE: ANDROID_STORAGE = '/storage' LOCAL_DOWNLOAD_PATH = os.path.join(ANDROID_STORAGE, 'emulated', '0', 'Download') USER_APP_PATH = os.path.join(ANDROID_STORAGE, 'emulated', '0', 'Android', 'data') for user_addon, user_params in list(APP_PARAMS.items()): if not user_params['ACTIVE']: continue for apk_path in user_params['USER_APK']: if apk_path.endswith('.apk'): download_path = LOCAL_DOWNLOAD_PATH elif user_params['USER_ADDON_STATUS']: download_path = user_params['USER_ADDON_USERDATA'] else: continue if apk_path.startswith('http'): try: apk_body = requests.get(apk_path, timeout=10) except Exception as e: apk_body = requests.Response() apk_body.status_code = str(e) if apk_body.status_code != 200: log.error("## Install_app: Invalid app requests response: %s" % (apk_body.status_code)) apk_OK = False continue with open(os.path.join(download_path, \ os.path.basename(apk_path)), "wb") as f: f.write(apk_body.content) apk_OK = True else: if os.path.exists(apk_path): shutil.copy(apk_path, download_path) apk_OK = True else: continue if not apk_OK: break if apk_OK: log.info("## Install_app: Installing the APK from: %s" % LOCAL_DOWNLOAD_PATH) notify('Install your Assistant %s from folder %s' % \ (os.path.basename(user_params['USER_APK'][0]), \ LOCAL_DOWNLOAD_PATH)) cmd_android = 'StartAndroidActivity("%s", "", "%s", "%s")' % (user_params['USER_APP'], 'open', 'about:blank') cmd_android_permissions = 'StartAndroidActivity("%s", "", "%s", "%s")' % (user_params['USER_APP'], 'checkPermissions', 'about:blank') cmd_android_close = 'StartAndroidActivity("%s", "", "%s", "%s")' % (user_params['USER_APP'], 'terminate', 'about:blank') xbmc.executebuiltin(cmd_android) time.sleep(1) # Lets give the user 5 minutes to install the app an retry automatically for x in range(300): if os.path.exists(os.path.join(USER_APP_PATH, user_params['USER_APP'])): log.info("## Install_app: APP installed: %s" % user_params['USER_APP']) notify('Accept Assistant permissions') log.info("## Install_app: Requesting permissions: %s" % user_params['USER_APP']) time.sleep(5) xbmc.executebuiltin(cmd_android_permissions) time.sleep(15) log.info("## Install_app: closing APP: %s" % user_params['USER_APP']) notify('Accept Assistant permissions') xbmc.executebuiltin(cmd_android_close) log.info("## Install_app: APP closed: %s" % user_params['USER_APP']) time.sleep(10) return user_params xbmc.executebuiltin(cmd_android) time.sleep(1) break except: log.info(traceback.format_exc()) user_params = {} return user_params
def run(url_suffix=""): if not os.path.exists( os.path.join(xbmc.translatePath(ADDON.getAddonInfo("path")), ".firstrun")): notify(getLocalizedString(30101)) system_information() return donatePath = os.path.join(xbmc.translatePath(ADDON.getAddonInfo("path")), ".donate") if not os.path.exists(donatePath): with open(donatePath, "w"): os.utime(donatePath, None) dialog = xbmcgui.Dialog() dialog.ok( "Quasar", "Please support Quasar development by visiting https://quasar.surge.sh to donate with Bitcoin, or buying a VPN subscription using the affiliate link at the bottom." ) socket.setdefaulttimeout(300) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except Exception as e: map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30225), repr(e).encode('utf-8'))) return if not data: return if data["content_type"]: xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) if data["content_type"] != "tvshows": xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, data["content_type"]) listitems = range(len(data["items"])) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = getLocalizedLabel(item["label"]) if item["label2"][0:8] == "LOCALIZE": item["label2"] = getLocalizedLabel(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"], iconImage=item["icon"], thumbnailImage=item["thumbnail"]) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in item["stream_info"].items(): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = getLocalizedLabel(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in item["properties"].items(): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) # Set ViewMode if data["content_type"]: viewMode = ADDON.getSetting("viewmode_%s" % data["content_type"]) try: xbmc.executebuiltin('Container.SetViewMode(%s)' % (viewMode)) except Exception as e: log.warning("Unable to SetViewMode(%s): %s" % (viewMode, repr(e))) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=True)