From 127a7f455a2d835e1ce76a450b7d874f9902aac3 Mon Sep 17 00:00:00 2001
From: Kingbox <37674310+lopezvg@users.noreply.github.com>
Date: Wed, 6 Feb 2019 16:57:11 +0100
Subject: [PATCH 1/2] =?UTF-8?q?NewPct1:=20opci=C3=B3n=20de=20Buscar=20en?=
=?UTF-8?q?=20Novedades?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
plugin.video.alfa/channels/newpct1.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/plugin.video.alfa/channels/newpct1.py b/plugin.video.alfa/channels/newpct1.py
index a55f0871..5c89f60b 100644
--- a/plugin.video.alfa/channels/newpct1.py
+++ b/plugin.video.alfa/channels/newpct1.py
@@ -264,6 +264,7 @@ def submenu_novedades(item):
itemlist = []
itemlist_alt = []
item.extra2 = ''
+ thumb_buscar = get_thumb("search.png")
#Renombramos el canal al nombre de clone inicial desde la URL
item.channel_host = host
@@ -327,6 +328,9 @@ def submenu_novedades(item):
item.post = "date=%s" % value
itemlist.append(item.clone(action="listado_busqueda", title=title, url=item.url, post=item.post))
+ itemlist.append(
+ Item(channel=item.channel, action="search", title="Buscar", url=item.channel_host + "buscar", thumbnail=thumb_buscar, category=item.category, channel_host=item.channel_host))
+
itemlist.append(item.clone(action='', title="[COLOR yellow]Lo Último en la Categoría:[/COLOR]"))
for value, title in matches:
if value.isdigit():
From 3fd060770ab46363adff7393a18d0ccba6dbe5f1 Mon Sep 17 00:00:00 2001
From: Kingbox <37674310+lopezvg@users.noreply.github.com>
Date: Wed, 6 Feb 2019 16:59:07 +0100
Subject: [PATCH 2/2] =?UTF-8?q?Quasar:=20Sistema=20de=20actualizaci=C3=B3n?=
=?UTF-8?q?=20desde=20Alfa?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
plugin.video.alfa/channels/setting.py | 14 +
plugin.video.alfa/lib/quasar/daemon.py | 294 ++++++++++++++++++
plugin.video.alfa/lib/quasar/navigation.py | 260 ++++++++++++++++
plugin.video.alfa/lib/quasar/osarch.py | 56 ++++
plugin.video.alfa/lib/quasar/util.py | 72 +++++
plugin.video.alfa/platformcode/custom_code.py | 72 ++++-
plugin.video.alfa/resources/settings.xml | 6 +-
7 files changed, 769 insertions(+), 5 deletions(-)
create mode 100644 plugin.video.alfa/lib/quasar/daemon.py
create mode 100644 plugin.video.alfa/lib/quasar/navigation.py
create mode 100644 plugin.video.alfa/lib/quasar/osarch.py
create mode 100644 plugin.video.alfa/lib/quasar/util.py
diff --git a/plugin.video.alfa/channels/setting.py b/plugin.video.alfa/channels/setting.py
index 78e02242..da6bb262 100644
--- a/plugin.video.alfa/channels/setting.py
+++ b/plugin.video.alfa/channels/setting.py
@@ -306,6 +306,8 @@ def submenu_tools(item):
itemlist.append(Item(channel=CHANNELNAME, action="check_quickfixes", folder=False,
title="Comprobar actualizaciones urgentes", plot="Versión actual: %s" % config.get_addon_version() ))
+ itemlist.append(Item(channel=CHANNELNAME, action="update_quasar", folder=False,
+ title="Actualizar addon externo Quasar"))
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False,
thumbnail=get_thumb("setting_0.png")))
@@ -336,6 +338,18 @@ def check_quickfixes(item):
return updater.check_addon_updates(verbose=True)
+def update_quasar(item):
+ logger.info()
+
+ from platformcode import custom_code, platformtools
+ stat = False
+ stat = custom_code.update_external_addon("quasar")
+ if stat:
+ platformtools.dialog_notification("Actualización Quasar", "Realizada con éxito")
+ else:
+ platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log")
+
+
def conf_tools(item):
logger.info()
diff --git a/plugin.video.alfa/lib/quasar/daemon.py b/plugin.video.alfa/lib/quasar/daemon.py
new file mode 100644
index 00000000..3754d8d4
--- /dev/null
+++ b/plugin.video.alfa/lib/quasar/daemon.py
@@ -0,0 +1,294 @@
+import os
+import stat
+import time
+import xbmc
+import shutil
+import socket
+import urllib2
+import xbmcgui
+import threading
+import subprocess
+from quasar.logger import log
+from quasar.osarch import PLATFORM
+from quasar.config import QUASARD_HOST
+from quasar.addon import ADDON, ADDON_ID, ADDON_PATH
+from quasar.util import notify, system_information, getLocalizedString, getWindowsShortPath
+
+def ensure_exec_perms(file_):
+ st = os.stat(file_)
+ os.chmod(file_, st.st_mode | stat.S_IEXEC)
+ return file_
+
+def android_get_current_appid():
+ with open("/proc/%d/cmdline" % os.getpid()) as fp:
+ return fp.read().rstrip("\0")
+
+def get_quasard_checksum(path):
+ try:
+ with open(path) as fp:
+ fp.seek(-40, os.SEEK_END) # we put a sha1 there
+ return fp.read()
+ except Exception:
+ return ""
+
+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 clear_fd_inherit_flags():
+ # Ensure the spawned quasar binary doesn't inherit open files from Kodi
+ # which can break things like addon updates. [WINDOWS ONLY]
+ from ctypes import windll
+
+ HANDLE_RANGE = xrange(0, 65536)
+ HANDLE_FLAG_INHERIT = 1
+ FILE_TYPE_DISK = 1
+
+ for hd in HANDLE_RANGE:
+ if windll.kernel32.GetFileType(hd) == FILE_TYPE_DISK:
+ if not windll.kernel32.SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0):
+ log.error("Error clearing inherit flag, disk file handle %x" % hd)
+
+
+def jsonrpc_enabled(notify=False):
+ try:
+ s = socket.socket()
+ s.connect(('127.0.0.1', 9090))
+ s.close()
+ log.info("Kodi's JSON-RPC service is available, starting up...")
+ del s
+ return True
+ except Exception as e:
+ log.error(repr(e))
+ if notify:
+ xbmc.executebuiltin("ActivateWindow(ServiceSettings)")
+ dialog = xbmcgui.Dialog()
+ dialog.ok("Quasar", getLocalizedString(30199))
+ return False
+
+def start_quasard(**kwargs):
+ jsonrpc_failures = 0
+ while jsonrpc_enabled() is False:
+ jsonrpc_failures += 1
+ log.warning("Unable to connect to Kodi's JSON-RPC service, retrying...")
+ if jsonrpc_failures > 1:
+ time.sleep(5)
+ if not jsonrpc_enabled(notify=True):
+ log.error("Unable to reach Kodi's JSON-RPC service, aborting...")
+ return False
+ else:
+ break
+ time.sleep(3)
+
+ quasar_dir, quasar_binary = get_quasar_binary()
+
+ if quasar_dir is False or quasar_binary is False:
+ return False
+
+ lockfile = os.path.join(ADDON_PATH, ".lockfile")
+ if os.path.exists(lockfile):
+ log.warning("Existing process found from lockfile, killing...")
+ try:
+ with open(lockfile) as lf:
+ pid = int(lf.read().rstrip(" \t\r\n\0"))
+ os.kill(pid, 9)
+ except Exception as e:
+ log.error(repr(e))
+
+ if PLATFORM["os"] == "windows":
+ log.warning("Removing library.db.lock file...")
+ try:
+ library_lockfile = os.path.join(xbmc.translatePath(ADDON.getAddonInfo("profile")).decode('utf-8'), "library.db.lock")
+ os.remove(library_lockfile)
+ except Exception as e:
+ log.error(repr(e))
+
+ SW_HIDE = 0
+ STARTF_USESHOWWINDOW = 1
+
+ args = [quasar_binary]
+ kwargs["cwd"] = quasar_dir
+
+ if PLATFORM["os"] == "windows":
+ args[0] = getWindowsShortPath(quasar_binary)
+ kwargs["cwd"] = getWindowsShortPath(quasar_dir)
+ si = subprocess.STARTUPINFO()
+ si.dwFlags = STARTF_USESHOWWINDOW
+ si.wShowWindow = SW_HIDE
+ clear_fd_inherit_flags()
+ kwargs["startupinfo"] = si
+ else:
+ env = os.environ.copy()
+ env["LD_LIBRARY_PATH"] = "%s:%s" % (quasar_dir, env.get("LD_LIBRARY_PATH", ""))
+ kwargs["env"] = env
+ kwargs["close_fds"] = True
+
+ wait_counter = 1
+ while xbmc.getCondVisibility('Window.IsVisible(10140)') or xbmc.getCondVisibility('Window.IsActive(10140)'):
+ if wait_counter == 1:
+ log.info('Add-on settings currently opened, waiting before starting...')
+ if wait_counter > 300:
+ break
+ time.sleep(1)
+ wait_counter += 1
+
+ return subprocess.Popen(args, **kwargs)
+
+def shutdown():
+ try:
+ urllib2.urlopen(QUASARD_HOST + "/shutdown")
+ except:
+ pass
+
+def wait_for_abortRequested(proc, monitor):
+ monitor.closing.wait()
+ log.info("quasard: exiting quasard daemon")
+ try:
+ proc.terminate()
+ except OSError:
+ pass # Process already exited, nothing to terminate
+ log.info("quasard: quasard daemon exited")
+
+def quasard_thread(monitor):
+ crash_count = 0
+ 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
+
+ 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
+ map(log.error, traceback.format_exc().split("\n"))
+ notify("%s: %s" % (getLocalizedString(30226), repr(e).encode('utf-8')))
+ raise
diff --git a/plugin.video.alfa/lib/quasar/navigation.py b/plugin.video.alfa/lib/quasar/navigation.py
new file mode 100644
index 00000000..70658b6c
--- /dev/null
+++ b/plugin.video.alfa/lib/quasar/navigation.py
@@ -0,0 +1,260 @@
+import os
+import sys
+import socket
+import urllib2
+import urlparse
+import xbmc
+import xbmcgui
+import xbmcplugin
+from quasar.logger import log
+from quasar.config import QUASARD_HOST
+from quasar.addon import ADDON, ADDON_ID, ADDON_PATH
+from quasar.util import notify, getLocalizedString, getLocalizedLabel, system_information
+
+try:
+ import simplejson as json
+except ImportError:
+ import json
+
+
+HANDLE = int(sys.argv[1])
+
+
+class InfoLabels(dict):
+ def __init__(self, *args, **kwargs):
+ self.update(*args, **kwargs)
+
+ def __getitem__(self, key):
+ return dict.get(self, key.lower(), "")
+
+ def __setitem__(self, key, val):
+ dict.__setitem__(self, key.lower(), val)
+
+ def update(self, *args, **kwargs):
+ for k, v in dict(*args, **kwargs).iteritems():
+ self[k] = v
+
+
+class closing(object):
+ def __init__(self, thing):
+ self.thing = thing
+
+ def __enter__(self):
+ return self.thing
+
+ def __exit__(self, *exc_info):
+ self.thing.close()
+
+
+class NoRedirectHandler(urllib2.HTTPRedirectHandler):
+ def http_error_302(self, req, fp, code, msg, headers):
+ import urllib
+ infourl = urllib.addinfourl(fp, headers, headers["Location"])
+ infourl.status = code
+ infourl.code = code
+ return infourl
+ http_error_300 = http_error_302
+ http_error_301 = http_error_302
+ http_error_303 = http_error_302
+ http_error_307 = http_error_302
+
+
+def getInfoLabels():
+ id_list = [int(s) for s in sys.argv[0].split("/") if s.isdigit()]
+ tmdb_id = id_list[0] if id_list else None
+
+ if not tmdb_id:
+ parsed_url = urlparse.urlparse(sys.argv[0] + sys.argv[2])
+ query = urlparse.parse_qs(parsed_url.query)
+ log.debug("Parsed URL: %s, Query: %s", repr(parsed_url), repr(query))
+ if 'tmdb' in query and 'show' not in query:
+ tmdb_id = query['tmdb'][0]
+ url = "%s/movie/%s/infolabels" % (QUASARD_HOST, tmdb_id)
+ elif 'show' in query:
+ tmdb_id = query['show'][0]
+ if 'season' in query and 'episode' in query:
+ url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, query['season'][0], query['episode'][0])
+ else:
+ url = "%s/show/%s/infolabels" % (QUASARD_HOST, tmdb_id)
+ else:
+ url = "%s/infolabels" % (QUASARD_HOST)
+ elif 'movie' in sys.argv[0]:
+ url = "%s/movie/%s/infolabels" % (QUASARD_HOST, tmdb_id)
+ elif ('episode' in sys.argv[0] or 'show' in sys.argv[0]) and len(id_list) > 2:
+ url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, id_list[1], id_list[2])
+ elif 'show' in sys.argv[0] and len(id_list) == 2:
+ url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, id_list[1], 1)
+ else:
+ url = "%s/infolabels" % (QUASARD_HOST)
+
+ log.debug("Resolving TMDB item by calling %s for %s" % (url, repr(sys.argv)))
+
+ try:
+ with closing(urllib2.urlopen(url)) as response:
+ resolved = json.loads(response.read())
+ if not resolved:
+ return {}
+
+ if 'info' in resolved and resolved['info']:
+ resolved.update(resolved['info'])
+
+ if 'art' in resolved and resolved['art']:
+ resolved['artbanner'] = ''
+ for k, v in resolved['art'].items():
+ resolved['art' + k] = v
+
+ if 'info' in resolved:
+ del resolved['info']
+ if 'art' in resolved:
+ del resolved['art']
+ if 'stream_info' in resolved:
+ del resolved['stream_info']
+
+ if 'dbtype' not in resolved:
+ resolved['dbtype'] = 'video'
+ if 'mediatype' not in resolved or resolved['mediatype'] == '':
+ resolved['Mediatype'] = resolved['dbtype']
+
+ return resolved
+ except:
+ log.debug("Could not resolve TMDB item: %s" % tmdb_id)
+ return {}
+
+
+def _json(url):
+ with closing(urllib2.urlopen(url)) as response:
+ if response.code >= 300 and response.code <= 307:
+ # Pause currently playing Quasar file to avoid doubling requests
+ if xbmc.Player().isPlaying() and ADDON_ID in xbmc.Player().getPlayingFile():
+ xbmc.Player().pause()
+ _infoLabels = InfoLabels(getInfoLabels())
+
+ item = xbmcgui.ListItem(
+ path=response.geturl(),
+ label=_infoLabels["label"],
+ label2=_infoLabels["label2"],
+ thumbnailImage=_infoLabels["thumbnail"])
+
+ item.setArt({
+ "poster": _infoLabels["artposter"],
+ "banner": _infoLabels["artbanner"],
+ "fanart": _infoLabels["artfanart"]
+ })
+
+ item.setInfo(type='Video', infoLabels=_infoLabels)
+ xbmcplugin.setResolvedUrl(HANDLE, True, item)
+ return
+
+ payload = response.read()
+
+ try:
+ if payload:
+ return json.loads(payload)
+ except:
+ raise Exception(payload)
+
+
+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
+ 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)
diff --git a/plugin.video.alfa/lib/quasar/osarch.py b/plugin.video.alfa/lib/quasar/osarch.py
new file mode 100644
index 00000000..5b580c28
--- /dev/null
+++ b/plugin.video.alfa/lib/quasar/osarch.py
@@ -0,0 +1,56 @@
+import xbmc
+import sys
+import platform
+
+def get_platform():
+ build = xbmc.getInfoLabel("System.BuildVersion")
+ kodi_version = int(build.split()[0][:2])
+ ret = {
+ "auto_arch": sys.maxsize > 2 ** 32 and "64-bit" or "32-bit",
+ "arch": sys.maxsize > 2 ** 32 and "x64" or "x86",
+ "os": "",
+ "version": platform.release(),
+ "kodi": kodi_version,
+ "build": build
+ }
+ if xbmc.getCondVisibility("system.platform.android"):
+ ret["os"] = "android"
+ if "arm" in platform.machine() or "aarch" in platform.machine():
+ ret["arch"] = "arm"
+ if "64" in platform.machine() and ret["auto_arch"] == "64-bit":
+ ret["arch"] = "arm"
+ #ret["arch"] = "x64" #The binary is corrupted in install package
+ elif xbmc.getCondVisibility("system.platform.linux"):
+ ret["os"] = "linux"
+ if "aarch" in platform.machine() or "arm64" in platform.machine():
+ if xbmc.getCondVisibility("system.platform.linux.raspberrypi"):
+ ret["arch"] = "armv7"
+ elif ret["auto_arch"] == "32-bit":
+ ret["arch"] = "armv7"
+ elif ret["auto_arch"] == "64-bit":
+ ret["arch"] = "arm64"
+ elif platform.architecture()[0].startswith("32"):
+ ret["arch"] = "arm"
+ else:
+ ret["arch"] = "arm64"
+ elif "armv7" in platform.machine():
+ ret["arch"] = "armv7"
+ elif "arm" in platform.machine():
+ ret["arch"] = "arm"
+ elif xbmc.getCondVisibility("system.platform.xbox"):
+ ret["os"] = "windows"
+ ret["arch"] = "x64"
+ elif xbmc.getCondVisibility("system.platform.windows"):
+ ret["os"] = "windows"
+ if platform.machine().endswith('64'):
+ ret["arch"] = "x64"
+ elif xbmc.getCondVisibility("system.platform.osx"):
+ ret["os"] = "darwin"
+ ret["arch"] = "x64"
+ elif xbmc.getCondVisibility("system.platform.ios"):
+ ret["os"] = "ios"
+ ret["arch"] = "arm"
+ return ret
+
+
+PLATFORM = get_platform()
diff --git a/plugin.video.alfa/lib/quasar/util.py b/plugin.video.alfa/lib/quasar/util.py
new file mode 100644
index 00000000..c3c3b63b
--- /dev/null
+++ b/plugin.video.alfa/lib/quasar/util.py
@@ -0,0 +1,72 @@
+import platform
+import xbmc
+import xbmcgui
+from quasar.logger import log
+from quasar.osarch import PLATFORM
+from quasar.addon import ADDON, ADDON_NAME, ADDON_ICON
+
+
+def notify(message, header=ADDON_NAME, time=5000, image=ADDON_ICON):
+ sound = ADDON.getSetting('do_not_disturb') == 'false'
+ dialog = xbmcgui.Dialog()
+ return dialog.notification(toUtf8(header), toUtf8(message), toUtf8(image), time, sound)
+
+def getLocalizedLabel(label):
+ try:
+ if "LOCALIZE" not in label:
+ return label
+ if ";;" not in label and label.endswith(']'):
+ return getLocalizedString(int(label[9:-1]))
+ else:
+ parts = label.split(";;")
+ translation = getLocalizedString(int(parts[0][9:14]))
+ for i, part in enumerate(parts[1:]):
+ if part[0:8] == "LOCALIZE":
+ parts[i + 1] = getLocalizedString(int(part[9:14]))
+
+ return (translation.decode('utf-8', 'replace') % tuple(parts[1:])).encode('utf-8', 'ignore')
+ except:
+ return label
+
+def getLocalizedString(stringId):
+ try:
+ return ADDON.getLocalizedString(stringId).encode('utf-8', 'ignore')
+ except:
+ return stringId
+
+def toUtf8(string):
+ if isinstance(string, unicode):
+ return string.encode('utf-8', 'ignore')
+ return string
+
+def system_information():
+ build = xbmc.getInfoLabel("System.BuildVersion")
+ log.info("System information: %(os)s_%(arch)s %(version)s" % PLATFORM)
+ log.info("Kodi build version: %s" % build)
+ log.info("OS type: %s" % platform.system())
+ log.info("uname: %s" % repr(platform.uname()))
+ return PLATFORM
+
+def getShortPath(path):
+ if PLATFORM["os"] == "windows":
+ return getWindowsShortPath(path)
+ return path
+
+def getWindowsShortPath(path):
+ try:
+ import ctypes
+ import ctypes.wintypes
+
+ ctypes.windll.kernel32.GetShortPathNameW.argtypes = [
+ ctypes.wintypes.LPCWSTR, # lpszLongPath
+ ctypes.wintypes.LPWSTR, # lpszShortPath
+ ctypes.wintypes.DWORD # cchBuffer
+ ]
+ ctypes.windll.kernel32.GetShortPathNameW.restype = ctypes.wintypes.DWORD
+
+ buf = ctypes.create_unicode_buffer(1024) # adjust buffer size, if necessary
+ ctypes.windll.kernel32.GetShortPathNameW(path, buf, len(buf))
+
+ return buf.value
+ except:
+ return path
diff --git a/plugin.video.alfa/platformcode/custom_code.py b/plugin.video.alfa/platformcode/custom_code.py
index af06d125..87dcbc97 100644
--- a/plugin.video.alfa/platformcode/custom_code.py
+++ b/plugin.video.alfa/platformcode/custom_code.py
@@ -5,8 +5,11 @@
import os
import json
+import traceback
+import xbmc
+import xbmcaddon
-from platformcode import config, logger
+from platformcode import config, logger, platformtools
from core import jsontools
from core import filetools
@@ -54,6 +57,15 @@ def init():
"""
try:
+ #QUASAR: Preguntamos si se hacen modificaciones a Quasar
+ if not filetools.exists(os.path.join(config.get_data_path(), "quasar.json")) and not config.get_setting('addon_quasar_update', default=False):
+ question_update_external_addon("quasar")
+
+ #QUASAR: Hacemos las modificaciones a Quasar, si está permitido, y si está instalado
+ if config.get_setting('addon_quasar_update', default=False):
+ if not update_external_addon("quasar"):
+ platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log")
+
#Existe carpeta "custom_code" ? Si no existe se crea y se sale
custom_code_dir = os.path.join(config.get_data_path(), 'custom_code')
if os.path.exists(custom_code_dir) == False:
@@ -70,7 +82,7 @@ def init():
#Se verifica si la versión del .json y del add-on son iguales. Si es así se sale. Si no se copia "custom_code" al add-on
verify_copy_folders(custom_code_dir, custom_code_json_path)
except:
- pass
+ logger.error(traceback.format_exc())
def create_folder_structure(custom_code_dir):
@@ -88,11 +100,11 @@ def create_folder_structure(custom_code_dir):
return
-def create_json(custom_code_json_path):
+def create_json(custom_code_json_path, json_name=json_data_file_name):
logger.info()
#Guardamaos el json con la versión de Alfa vacía, para permitir hacer la primera copia
- json_data_file = filetools.join(custom_code_json_path, json_data_file_name)
+ json_data_file = filetools.join(custom_code_json_path, json_name)
json_file = open(json_data_file, "a+")
json_file.write(json.dumps({"addon_version": ""}))
json_file.close()
@@ -123,3 +135,55 @@ def verify_copy_folders(custom_code_dir, custom_code_json_path):
filetools.write(json_data_file, jsontools.dump(json_data))
return
+
+
+def question_update_external_addon(addon_name):
+ logger.info(addon_name)
+
+ #Verificamos que el addon está instalado
+ stat = False
+ if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name):
+ #Si es la primera vez que se pregunta por la actualización del addon externo, recogemos la respuesta,
+ # guardaos un .json en userdat/alfa para no volver a preguntar otra vez, y se actualiza el setting en Alfa.
+ stat = platformtools.dialog_yesno('Actualización de %s' % addon_name.capitalize(), '¿Quiere que actualicemos Quasar para que sea compatible con las últimas versiones de Kodi? (recomendado: SÍ)', '', 'Si actualiza Quasar, reinicie Kodi en un par de minutos')
+
+ #Con la respuesta actualizamos la variable en Alfa settings.xml. Se puede cambiar en Ajustes de Alfa, Otros
+ if stat:
+ config.set_setting('addon_quasar_update', True)
+ else:
+ config.set_setting('addon_quasar_update', False)
+
+ #Creamos un .json en userdata para no volver a preguntar otra vez
+ create_json(config.get_data_path(), "%s.json" % addon_name)
+
+ return stat
+
+def update_external_addon(addon_name):
+ logger.info(addon_name)
+
+ #Verificamos que el addon está instalado
+ if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name):
+ #Path de actuali
-
+
+
+
+
+