ELementum Come Client di Default

This commit is contained in:
Alhaziel01
2020-04-19 21:24:27 +02:00
parent 2502ac48b2
commit 27ae5c8058
178 changed files with 1394 additions and 6501 deletions
-295
View File
@@ -1,295 +0,0 @@
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
log.info("quasard: proc.return code: %s" % str(proc.returncode))
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
-260
View File
@@ -1,260 +0,0 @@
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)
-56
View File
@@ -1,56 +0,0 @@
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()
-72
View File
@@ -1,72 +0,0 @@
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