Skip to content

Instantly share code, notes, and snippets.

@CarstenG2
Created February 11, 2026 10:50
Show Gist options
  • Select an option

  • Save CarstenG2/45e4b6ee18798c978313cdbb71f601ac to your computer and use it in GitHub Desktop.

Select an option

Save CarstenG2/45e4b6ee18798c978313cdbb71f601ac to your computer and use it in GitHub Desktop.
xShip: download manager support (JD1, JD2, MyJD, PyLoad) - all new + modified files
# 2023-05-10
# edit 2025-06-12
import sys, json
from resources.lib import control
params = dict(control.parse_qsl(control.urlsplit(sys.argv[2]).query))
action = params.get('action')
name = params.get('name')
table = params.get('table')
title = params.get('title')
source = params.get('source')
# ------ navigator --------------
if action == None or action == 'root':
from resources.lib.indexers import navigator
navigator.navigator().root()
elif action == 'pluginInfo':
from resources.lib import supportinfo
supportinfo.pluginInfo()
elif action == 'movieNavigator':
from resources.lib.indexers import navigator
navigator.navigator().movies()
elif action == 'tvNavigator':
from resources.lib.indexers import navigator
navigator.navigator().tvshows()
elif action == 'toolNavigator':
from resources.lib.indexers import navigator
navigator.navigator().tools()
elif action == 'downloadNavigator':
from resources.lib.indexers import navigator
navigator.navigator().downloads()
# -------------------------------------------
elif action == 'download':
image = params.get('image')
from resources.lib import downloader
from resources.lib import sources
try: downloader.download(name, image, sources.sources().sourcesResolve(json.loads(source)[0], True))
except: pass
elif action == 'sendToJD':
from resources.lib import sources
from resources.lib.handler.jdownloaderHandler import cJDownloaderHandler
url = sources.sources().sourcesResolve(json.loads(source)[0], True)
if url:
if '|' in url: url = url.split('|')[0]
cJDownloaderHandler().sendToJDownloader(url)
elif action == 'sendToJD2':
from resources.lib import sources
from resources.lib.handler.jdownloader2Handler import cJDownloader2Handler
url = sources.sources().sourcesResolve(json.loads(source)[0], True)
if url:
if '|' in url: url = url.split('|')[0]
cJDownloader2Handler().sendToJDownloader2(url)
elif action == 'sendToMyJD':
from resources.lib import sources
from resources.lib.handler.myjdownloaderHandler import cMyJDownloaderHandler
url = sources.sources().sourcesResolve(json.loads(source)[0], True)
if url:
if '|' in url: url = url.split('|')[0]
cMyJDownloaderHandler().sendToMyJDownloader(url, name)
elif action == 'sendToPyLoad':
from resources.lib import sources
from resources.lib.handler.pyLoadHandler import cPyLoadHandler
url = sources.sources().sourcesResolve(json.loads(source)[0], True)
if url:
if '|' in url: url = url.split('|')[0]
cPyLoadHandler().sendToPyLoad(name, url)
elif action == 'playExtern':
import json
if not control.visible(): control.busy()
try:
sysmeta = {}
for key, value in params.items():
if key == 'action': continue
elif key == 'year' or key == 'season' or key == 'episode': value = int(value)
if value == 0: continue
sysmeta.update({key : value})
if int(params.get('season')) == 0:
mediatype = 'movie'
else:
mediatype = 'tvshow'
sysmeta.update({'mediatype': mediatype})
# if control.getSetting('hosts.mode') == '2':
# sysmeta.update({'select': '2'})
# else:
# sysmeta.update({'select': '1'})
sysmeta.update({'select': control.getSetting('hosts.mode')})
sysmeta = json.dumps(sysmeta)
params.update({'sysmeta': sysmeta})
from resources.lib import sources
sources.sources().play(params)
except:
pass
elif action == 'playURL':
try:
import resolveurl
import xbmcgui, xbmc
#url = 'https://streamvid.net/embed-uhgo683xes41'
#url = 'https://moflix-stream.click/v/gcd0aueegeia'
url = xbmcgui.Dialog().input("URL Input")
hmf = resolveurl.HostedMediaFile(url=url, include_disabled=True, include_universal=False)
try:
if hmf.valid_url(): url = hmf.resolve()
except:
pass
item = xbmcgui.ListItem('URL-direkt')
kodiver = int(xbmc.getInfoLabel("System.BuildVersion").split(".")[0])
if ".m3u8" in url or '.mpd' in url:
item.setProperty("inputstream", "inputstream.adaptive")
if '.mpd' in url:
if kodiver < 21: item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
item.setMimeType('application/dash+xml')
else:
if kodiver < 21: item.setProperty('inputstream.adaptive.manifest_type', 'hls')
item.setMimeType("application/vnd.apple.mpegurl")
item.setContentLookup(False)
if '|' in url:
stream_url, strhdr = url.split('|')
item.setProperty('inputstream.adaptive.stream_headers', strhdr)
if kodiver > 19: item.setProperty('inputstream.adaptive.manifest_headers', strhdr)
# item.setPath(stream_url)
url = stream_url
item.setPath(url)
xbmc.Player().play(url, item)
except:
#print('Kein Video Link gefunden')
control.infoDialog("Keinen Video Link gefunden", sound=True, icon='WARNING', time=1000)
elif action == 'UpdatePlayCount':
from resources.lib import playcountDB
playcountDB.UpdatePlaycount(params)
control.execute('Container.Refresh')
# listings -------------------------------
elif action == 'listings':
from resources.lib.indexers import listings
listings.listings().get(params)
elif action == 'movieYears':
from resources.lib.indexers import listings
listings.listings().movieYears()
elif action == 'movieGenres':
from resources.lib.indexers import listings
listings.listings().movieGenres()
elif action == 'tvGenres':
from resources.lib.indexers import listings
listings.listings().tvGenres()
# search ----------------------
elif action == 'searchNew':
from resources.lib import searchDB
searchDB.search_new(table)
elif action == 'searchClear':
from resources.lib import searchDB
searchDB.remove_all_query(table)
# if len(searchDB.getSearchTerms()) == 0:
# control.execute('Action(ParentDir)')
elif action == 'searchDelTerm':
from resources.lib import searchDB
searchDB.remove_query(name, table)
# if len(searchDB.getSearchTerms()) == 0:
# control.execute('Action(ParentDir)')
# person ----------------------
elif action == 'person':
from resources.lib.indexers import person
person.person().get(params)
elif action == 'personSearch':
from resources.lib.indexers import person
person.person().search()
elif action == 'personCredits':
from resources.lib.indexers import person
person.person().getCredits(params)
elif action == 'playfromPerson':
if not control.visible(): control.busy()
sysmeta = json.loads(params['sysmeta'])
if sysmeta['mediatype'] == 'movie':
from resources.lib.indexers import movies
sysmeta = movies.movies().super_meta(sysmeta['tmdb_id'])
sysmeta = json.dumps(sysmeta)
else:
from resources.lib.indexers import tvshows
sysmeta = tvshows.tvshows().super_meta(sysmeta['tmdb_id'])
sysmeta = control.quote_plus(json.dumps(sysmeta))
params.update({'sysmeta': sysmeta})
from resources.lib import sources
sources.sources().play(params)
# movies ----------------------
elif action == 'movies':
from resources.lib.indexers import movies
movies.movies().get(params)
elif action == 'moviesSearch':
from resources.lib.indexers import movies
movies.movies().search()
# tvshows ---------------------------------
elif action == 'tvshows': # 'tvshowPage'
from resources.lib.indexers import tvshows
tvshows.tvshows().get(params)
elif action == 'tvshowsSearch':
from resources.lib.indexers import tvshows
tvshows.tvshows().search()
# seasons ---------------------------------
elif action == 'seasons':
from resources.lib.indexers import seasons
seasons.seasons().get(params) # params
# episodes ---------------------------------
elif action == 'episodes':
from resources.lib.indexers import episodes
episodes.episodes().get(params)
# sources ---------------------------------
elif action == 'play':
if not control.visible(): control.busy()
from resources.lib import sources
sources.sources().play(params)
elif action == 'addItem':
from resources.lib import sources
sources.sources().addItem(title)
elif action == 'playItem':
if not control.visible(): control.busy()
from resources.lib import sources
sources.sources().playItem(title, source)
# Settings ------------------------------
elif action == "settings": # alle Quellen aktivieren / deaktivieren
from resources import settings
settings.run(params)
elif action == 'addonSettings':
# query = None
query = params.get('query')
control.openSettings(query)
elif action == 'resetSettings':
status = control.resetSettings()
if status:
control.reload_profile()
control.sleep(500)
control.execute('RunAddon("%s")' % control.addonId)
elif action == 'resolverSettings':
import resolveurl as resolver
resolver.display_settings()
# try:
# import pydevd
# if pydevd.connected: pydevd.kill_all_pydev_threads()
# except:
# pass
# finally:
# exit()
# -*- coding: utf-8 -*-
# Python 3
import re
from resources.lib import control
from xbmc import LOGINFO as LOGNOTICE, log
from urllib.request import Request, urlopen
from urllib.parse import urlencode
class cJDownloader2Handler:
def sendToJDownloader2(self, sUrl):
if self.__checkConfig() is False:
control.infoDialog('Einstellungen nicht konfiguriert', heading='JDownloader 2', icon='ERROR')
return False
if self.__checkConnection() is False:
control.infoDialog('Verbindung fehlgeschlagen', heading='JDownloader 2', icon='ERROR')
return False
if self.__download(sUrl) is True:
control.infoDialog('Link gesendet', heading='JDownloader 2', icon='INFO')
return True
return False
def __client(self, path, params):
sHost = self.__getHost()
sPort = self.__getPort()
ENCODING = 'utf-8'
url = 'http://{}:{}/{}'.format(sHost, sPort, path)
if params is not None:
headers = {'Content-Type': 'application/x-www-form-urlencoded;charset={}'.format(ENCODING)}
request = Request(url, urlencode(params).encode(ENCODING), headers)
else:
request = Request(url)
return urlopen(request).read().decode(ENCODING).strip()
def __download(self, sFileUrl):
log('xShip -> [jdownloader2Handler]: JD2 Link: ' + str(sFileUrl), LOGNOTICE)
params = {'passwords': 'myPassword', 'source': 'http://jdownloader.org/spielwiese', 'urls': sFileUrl, 'submit': 'Add Link to JDownloader'}
if self.__client('flash/add', params).lower() == 'success':
return True
else:
return False
def __checkConfig(self):
log('xShip -> [jdownloader2Handler]: check JD2 Addon settings', LOGNOTICE)
bEnabled = control.getSetting('jd2_enabled')
if bEnabled == 'true':
return True
return False
def __getHost(self):
return control.getSetting('jd2_host')
def __getPort(self):
return control.getSetting('jd2_port')
def __checkConnection(self):
log('xShip -> [jdownloader2Handler]: check JD2 Connection', LOGNOTICE)
try:
output = self.__client('jdcheck.js', None)
pattern = re.compile(r'jdownloader\s*=\s*true', re.IGNORECASE)
if pattern.search(output) != None:
return True
except Exception:
return False
return False
# -*- coding: utf-8 -*-
# Python 3
from xbmc import LOGINFO as LOGNOTICE, log
from resources.lib import control
from urllib.request import Request, urlopen
class cJDownloaderHandler:
def sendToJDownloader(self, sUrl):
if self.__checkConfig() == False:
control.infoDialog('Einstellungen nicht konfiguriert', heading='JDownloader', icon='ERROR')
return False
if self.__checkConnection() == False:
control.infoDialog('Verbindung fehlgeschlagen', heading='JDownloader', icon='ERROR')
return False
bDownload = self.__download(sUrl)
if bDownload == True:
control.infoDialog('Link gesendet', heading='JDownloader', icon='INFO')
def __checkConfig(self):
log('xShip -> [jdownloaderHandler]: check JD Addon settings', LOGNOTICE)
bEnabled = control.getSetting('jd_enabled')
if bEnabled == 'true':
return True
return False
def __getHost(self):
return control.getSetting('jd_host')
def __getPort(self):
return control.getSetting('jd_port')
def __getAutomaticStart(self):
bAutomaticStart = control.getSetting('jd_automatic_start')
if bAutomaticStart == 'true':
return True
return False
def __getLinkGrabber(self):
bGrabber = control.getSetting('jd_grabber')
if bGrabber == 'true':
return True
return False
def __download(self, sFileUrl):
sHost = self.__getHost()
sPort = self.__getPort()
bAutomaticDownload = self.__getAutomaticStart()
bLinkGrabber = self.__getLinkGrabber()
sLinkForJd = self.__createJDUrl(sFileUrl, sHost, sPort, bAutomaticDownload, bLinkGrabber)
log('xShip -> [jdownloaderHandler]: JD Link: ' + str(sLinkForJd), LOGNOTICE)
request = Request(sLinkForJd)
urlopen(request).read()
return True
def __createJDUrl(self, sFileUrl, sHost, sPort, bAutomaticDownload, bLinkGrabber):
sGrabber = '1' if bLinkGrabber else '0'
sAutomaticStart = '1' if bAutomaticDownload else '0'
sUrl = 'http://' + str(sHost) + ':' + str(sPort) + '/action/add/links/grabber' + sGrabber + '/start' + sAutomaticStart + '/' + sFileUrl
return sUrl
def __checkConnection(self):
log('xShip -> [jdownloaderHandler]: check JD Connection', LOGNOTICE)
sHost = self.__getHost()
sPort = self.__getPort()
sLinkForJd = 'http://' + str(sHost) + ':' + str(sPort)
try:
request = Request(sLinkForJd)
urlopen(request).read()
return True
except Exception:
return False
# -*- coding: utf-8 -*-
# Python 3
import hashlib
import hmac
import json
import time
import base64
import requests
try:
from resources.lib import pyaes
except ImportError:
try:
import pyaes
except ImportError:
from resolveurl.lib import pyaes
from urllib.parse import quote
class MYJDException(BaseException):
pass
def PAD(s):
BS = 16
try:
return s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
except Exception:
return s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
def UNPAD(s):
try:
return s[0:-s[-1]]
except Exception:
return s[0:-ord(s[-1])]
class System:
def __init__(self, device):
self.device = device
self.url = '/system'
def exit_jd(self):
return self.device.action(self.url + "/exitJD")
def restart_jd(self):
return self.device.action(self.url + "/restartJD")
def hibernate_os(self):
return self.device.action(self.url + "/hibernateOS")
def shutdown_os(self, force):
return self.device.action(self.url + "/shutdownOS", force)
def standby_os(self):
return self.device.action(self.url + "/standbyOS")
class Update:
def __init__(self, device):
self.device = device
self.url = '/update'
def restart_and_update(self):
return self.device.action(self.url + "/restartAndUpdate")
def run_update_check(self):
return self.device.action(self.url + "/runUpdateCheck")
def is_update_available(self):
return self.device.action(self.url + "/isUpdateAvailable")
class DownloadController:
def __init__(self, device):
self.device = device
self.url = '/downloadcontroller'
def start_downloads(self):
return self.device.action(self.url + "/start")
def stop_downloads(self):
return self.device.action(self.url + "/stop")
def pause_downloads(self, value):
params = [value]
return self.device.action(self.url + "/pause", params)
def get_speed_in_bytes(self):
return self.device.action(self.url + "/getSpeedInBps")
def force_download(self, link_ids, package_ids):
params = [link_ids, package_ids]
return self.device.action(self.url + "/forceDownload", params)
def get_current_state(self):
return self.device.action(self.url + "/getCurrentState")
class Linkgrabber:
def __init__(self, device):
self.device = device
self.url = '/linkgrabberv2'
def clear_list(self):
return self.device.action(self.url + "/clearList", http_action="POST")
def move_to_downloadlist(self, links_ids, packages_ids):
params = [links_ids, packages_ids]
return self.device.action(self.url + "/moveToDownloadlist", params)
def query_links(self, params=[
{"bytesTotal": True,
"comment": True,
"status": True,
"enabled": True,
"maxResults": -1,
"startAt": 0,
"hosts": True,
"url": True,
"availability": True,
"variantIcon": True,
"variantName": True,
"variantID": True,
"variants": True,
"priority": True}]):
return self.device.action(self.url + "/queryLinks", params)
def cleanup(self, action, mode, selection_type, links_ids=[], packages_ids=[]):
params = [links_ids, packages_ids]
params += [action, mode, selection_type]
return self.device.action(self.url + "/cleanup", params)
def add_container(self, type_, content):
params = [type_, content]
return self.device.action(self.url + "/addContainer", params)
def get_download_urls(self, links_ids, packages_ids, url_display_type):
params = [packages_ids, links_ids, url_display_type]
return self.device.action(self.url + "/getDownloadUrls", params)
def set_priority(self, priority, links_ids, packages_ids):
params = [priority, links_ids, packages_ids]
return self.device.action(self.url + "/setPriority", params)
def set_enabled(self, params):
return self.device.action(self.url + "/setEnabled", params)
def get_variants(self, params):
return self.device.action(self.url + "/getVariants", params)
def add_links(self, params=[
{"autostart": False,
"links": None,
"packageName": None,
"extractPassword": None,
"priority": "DEFAULT",
"downloadPassword": None,
"destinationFolder": None,
"overwritePackagizerRules": False}]):
return self.device.action("/linkgrabberv2/addLinks", params)
def get_childrenchanged(self):
pass
def remove_links(self):
pass
def get_downfolderhistoryselectbase(self):
pass
def help(self):
return self.device.action("/linkgrabberv2/help", http_action="GET")
def rename_link(self):
pass
def move_links(self):
pass
def set_variant(self):
pass
def get_package_count(self):
pass
def rename_package(self):
pass
def query_packages(self):
pass
def move_packages(self):
pass
def add_variant_copy(self):
pass
class Downloads:
def __init__(self, device):
self.device = device
self.url = "/downloadsV2"
def query_links(self, params=[
{"bytesTotal": True,
"comment": True,
"status": True,
"enabled": True,
"maxResults": -1,
"startAt": 0,
"packageUUIDs": [],
"host": True,
"url": True,
"bytesloaded": True,
"speed": True,
"eta": True,
"finished": True,
"priority": True,
"running": True,
"skipped": True,
"extractionStatus": True}]):
return self.device.action(self.url + "/queryLinks", params)
def query_packages(self, params=[
{"bytesLoaded": True,
"bytesTotal": True,
"comment": True,
"enabled": True,
"eta": True,
"priority": True,
"finished": True,
"running": True,
"speed": True,
"status": True,
"childCount": True,
"hosts": True,
"saveTo": True,
"maxResults": -1,
"startAt": 0}]):
return self.device.action(self.url + "/queryPackages", params)
def cleanup(self, action, mode, selection_type, links_ids=[], packages_ids=[]):
params = [links_ids, packages_ids]
params += [action, mode, selection_type]
return self.device.action(self.url + "/cleanup", params)
class Jddevice:
def __init__(self, jd, device_dict):
self.name = device_dict["name"]
self.device_id = device_dict["id"]
self.device_type = device_dict["type"]
self.myjd = jd
self.linkgrabber = Linkgrabber(self)
self.downloads = Downloads(self)
self.downloadcontroller = DownloadController(self)
self.update = Update(self)
self.system = System(self)
def action(self, path, params=(), http_action="POST"):
action_url = self.__action_url()
response = self.myjd.request_api(path, http_action, params, action_url)
if response is None:
return False
return response['data']
def __action_url(self):
return "/t_" + self.myjd.get_session_token() + "_" + self.device_id
class Myjdapi:
def __init__(self):
self.__request_id = int(time.time() * 1000)
self.__api_url = "http://api.jdownloader.org"
self.__app_key = "http://git.io/vmcsk"
self.__api_version = 1
self.__devices = None
self.__login_secret = None
self.__device_secret = None
self.__session_token = None
self.__regain_token = None
self.__server_encryption_token = None
self.__device_encryption_token = None
self.__connected = False
def get_session_token(self):
return self.__session_token
def is_connected(self):
return self.__connected
def set_app_key(self, app_key):
self.__app_key = app_key
def __secret_create(self, email, password, domain):
secret_hash = hashlib.sha256()
secret_hash.update(email.lower().encode('utf-8') + password.encode('utf-8') + domain.lower().encode('utf-8'))
return secret_hash.digest()
def __update_encryption_tokens(self):
if self.__server_encryption_token is None:
old_token = self.__login_secret
else:
old_token = self.__server_encryption_token
new_token = hashlib.sha256()
new_token.update(old_token + bytearray.fromhex(self.__session_token))
self.__server_encryption_token = new_token.digest()
new_token = hashlib.sha256()
new_token.update(self.__device_secret + bytearray.fromhex(self.__session_token))
self.__device_encryption_token = new_token.digest()
def __signature_create(self, key, data):
signature = hmac.new(key, data.encode('utf-8'), hashlib.sha256)
return signature.hexdigest()
def __decrypt(self, secret_token, data):
init_vector = secret_token[:len(secret_token) // 2]
key = secret_token[len(secret_token) // 2:]
decryptor = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(key, init_vector))
decrypted_data = decryptor.feed(base64.b64decode(data))
decrypted_data += decryptor.feed()
return decrypted_data
def __encrypt(self, secret_token, data):
init_vector = secret_token[:len(secret_token) // 2]
key = secret_token[len(secret_token) // 2:]
encryptor = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, init_vector))
encrypted_data = encryptor.feed(data)
encrypted_data += encryptor.feed()
encrypted_data = base64.b64encode(encrypted_data)
return encrypted_data.decode('utf-8')
def update_request_id(self):
self.__request_id = int(time.time())
def connect(self, email, password):
self.__login_secret = self.__secret_create(email, password, "server")
self.__device_secret = self.__secret_create(email, password, "device")
response = self.request_api("/my/connect", "GET", [("email", email), ("appkey", self.__app_key)])
self.__connected = True
self.update_request_id()
self.__session_token = response["sessiontoken"]
self.__regain_token = response["regaintoken"]
self.__update_encryption_tokens()
self.update_devices()
def reconnect(self):
response = self.request_api("/my/reconnect", "GET", [("sessiontoken", self.__session_token), ("regaintoken", self.__regain_token)])
self.update_request_id()
self.__session_token = response["sessiontoken"]
self.__regain_token = response["regaintoken"]
self.__update_encryption_tokens()
def disconnect(self):
self.request_api("/my/disconnect", "GET", [("sessiontoken", self.__session_token)])
self.update_request_id()
self.__login_secret = None
self.__device_secret = None
self.__session_token = None
self.__regain_token = None
self.__server_encryption_token = None
self.__device_encryption_token = None
self.__devices = None
self.__connected = False
def update_devices(self):
response = self.request_api("/my/listdevices", "GET", [("sessiontoken", self.__session_token)])
self.update_request_id()
self.__devices = response["list"]
def list_devices(self):
return self.__devices
def get_device(self, device_name=None, device_id=None):
if not self.is_connected():
raise (MYJDException("No connection established\n"))
if device_id is not None:
for device in self.__devices:
if device["id"] == device_id:
return Jddevice(self, device)
elif device_name is not None:
for device in self.__devices:
if device["name"] == device_name:
return Jddevice(self, device)
raise MYJDException("Device not found\n")
def request_api(self, path, http_method="GET", params=None, action=None):
data = None
if not self.is_connected() and path != "/my/connect":
raise (MYJDException("No connection established\n"))
if http_method == "GET":
query = [path + "?"]
for param in params:
if param[0] != "encryptedLoginSecret":
query += ["%s=%s" % (param[0], quote(param[1]))]
else:
query += ["&%s=%s" % (param[0], param[1])]
query += ["rid=" + str(self.__request_id)]
if self.__server_encryption_token is None:
query += ["signature=" + str(self.__signature_create(self.__login_secret, query[0] + "&".join(query[1:])))]
else:
query += ["signature=" + str(self.__signature_create(self.__server_encryption_token, query[0] + "&".join(query[1:])))]
query = query[0] + "&".join(query[1:])
encrypted_response = requests.get(self.__api_url + query)
else:
params_request = []
for param in params:
if not isinstance(param, list):
params_request += [json.dumps(param)]
else:
params_request += [param]
params_request = {"apiVer": self.__api_version, "url": path, "params": params_request, "rid": self.__request_id}
data = json.dumps(params_request).replace('"null"', "null").replace("'null'", "null")
encrypted_data = self.__encrypt(self.__device_encryption_token, data)
if action is not None:
request_url = self.__api_url + action + path
else:
request_url = self.__api_url + path
encrypted_response = requests.post(request_url, headers={"Content-Type": "application/aesjson-jd; charset=utf-8"}, data=encrypted_data)
if encrypted_response.status_code != 200:
error_msg = json.loads(encrypted_response.text)
msg = "\n\tSOURCE: " + error_msg["src"] + "\n\tTYPE: " + \
error_msg["type"] + "\n------\nREQUEST_URL: " + \
self.__api_url + path
if http_method == "GET":
msg += query
msg += "\n"
if data is not None:
msg += "DATA:\n" + data
raise (MYJDException(msg))
if action is None:
if not self.__server_encryption_token:
response = self.__decrypt(self.__login_secret, encrypted_response.text)
else:
response = self.__decrypt(self.__server_encryption_token, encrypted_response.text)
else:
if params is not None:
response = self.__decrypt(self.__device_encryption_token, encrypted_response.text)
else:
return {"data": response}
jsondata = json.loads(response.decode('utf-8'))
if jsondata['rid'] != self.__request_id:
self.update_request_id()
return None
self.update_request_id()
return jsondata
# -*- coding: utf-8 -*-
# Python 3
from resources.lib.handler import myjdapi
from resources.lib import control
from xbmc import LOGINFO as LOGNOTICE, log
class cMyJDownloaderHandler:
def sendToMyJDownloader(self, sUrl, sMovieTitle):
if self.__checkConfig() == False:
control.infoDialog('Einstellungen nicht konfiguriert', heading='My.JDownloader', icon='ERROR')
return False
jd = myjdapi.Myjdapi()
try:
jd.connect(self.__getUser(), self.__getPass())
except Exception:
control.infoDialog('Verbindung fehlgeschlagen', heading='My.JDownloader', icon='ERROR')
return False
try:
jd.update_devices()
except Exception:
control.infoDialog('Keine Geraete gefunden', heading='My.JDownloader', icon='ERROR')
return False
try:
device = jd.get_device(self.__getDevice())
if device.linkgrabber.add_links([{"autostart": False, "links": sUrl, "packageName": sMovieTitle}])['id'] > 0:
control.infoDialog('Link gesendet', heading='My.JDownloader', icon='INFO')
return True
except Exception:
control.infoDialog('Fehler beim Senden', heading='My.JDownloader', icon='ERROR')
return False
def __checkConfig(self):
log('xShip -> [myjdownloaderHandler]: check MYJD Addon settings', LOGNOTICE)
if control.getSetting('myjd_enabled') == 'true':
return True
return False
def __getDevice(self):
return control.getSetting('myjd_device')
def __getUser(self):
return control.getSetting('myjd_user')
def __getPass(self):
return control.getSetting('myjd_pass')
# -*- coding: utf-8 -*-
# Python 3
import sys
from resources.lib import control
from xbmc import LOGINFO as LOGNOTICE, log
from urllib.request import Request, urlopen, build_opener
from urllib.error import HTTPError
from urllib.parse import urlencode, quote_plus
class cPyLoadHandler:
def sendToPyLoad(self, sPackage, sUrl):
log('xShip -> [pyLoadHandler]: PyLoad package: ' + str(sPackage) + ', ' + str(sUrl), LOGNOTICE)
if self.__sendLinkToCore(sPackage, sUrl):
control.infoDialog('Link gesendet', heading='PyLoad', icon='INFO')
else:
control.infoDialog('Senden fehlgeschlagen', heading='PyLoad', icon='ERROR')
def __sendLinkToCore(self, sPackage, sUrl):
log('xShip -> [pyLoadHandler]: Sending link...', LOGNOTICE)
try:
py_host = control.getSetting('pyload_host')
py_port = control.getSetting('pyload_port')
py_user = control.getSetting('pyload_user')
py_passwd = control.getSetting('pyload_passwd')
mydata = [('username', py_user), ('password', py_passwd)]
mydata = urlencode(mydata)
# check if host has a leading http://
if py_host.find('http://') != 0:
py_host = 'http://' + py_host
log('xShip -> [pyLoadHandler]: Attempting to connect to PyLoad at: ' + py_host + ':' + py_port, LOGNOTICE)
req = Request(py_host + ':' + py_port + '/api/login', mydata)
req.add_header("Content-type", "application/x-www-form-urlencoded")
page = urlopen(req).read()
page = page[1:]
session = page[:-1]
opener = build_opener()
opener.addheaders.append(('Cookie', 'beaker.session.id=' + session))
sPackage = sPackage.translate(str.maketrans('\\/:*?"<>|', '_________'))
py_url = py_host + ':' + py_port + '/api/addPackage?name="' + quote_plus(sPackage) + '"&links=["' + quote_plus(sUrl) + '"]'
log('xShip -> [pyLoadHandler]: PyLoad API call: ' + py_url, LOGNOTICE)
sock = opener.open(py_url).read()
sock.close()
return True
except HTTPError as e:
log('xShip -> [pyLoadHandler]: unable to send link: Error= ' + str(sys.exc_info()[0]), LOGNOTICE)
log(str(e.code), LOGNOTICE)
try:
sock.close()
except Exception:
log('xShip -> [pyLoadHandler]: unable to close socket...', LOGNOTICE)
return False
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
<category label="Allgemein">
<setting id="hosts.mode" type="enum" label="Standard-Aktion" values="Dialog|Verzeichnis|Autoplay" default="1" />
<setting id="scrapers.timeout" type="slider" label="Zeitlimit für Indexseiten" default="35" range="10,60" option="int" />
<setting id="fanart" type="bool" label="Fanart verwenden" default="true" />
<setting id="search.doku" type="bool" label="Auch nach Dokumentationen suchen" default="false" />
<setting type="lsep" label="Einstellungen RequestHandler" />
<setting default="10" id="requestTimeout" label="Timeout für HTTP-Anfragen in Sekunden" option="int" range="1,1,60" type="slider" />
<setting default="600" id="cacheTime" label="Cachezeit für Webseiten (HtmlCache) in Sekunden" option="int" range="0,60,1800" type="slider" />
<setting default="true" id="volatileHtmlCache" type="bool" label= "HTML Inhalte werden nur im RAM zwischengespeichert" visible="true"/>
<setting default="2" id="cacheDeltaDay" label="Html Cache nach Tage löschen" option="int" range="1,1,7" type="slider" />
<setting id="delHtmlCache" label="[B][COLOR red]Html Cache einmalig bei Neustart löschen[/COLOR][/B]" type="bool" default="false" />
<setting type="lsep" label="Status - gesehen / ungesehen" />
<setting type="text" label="[COLOR blue]Auf leistungsschwachen Geräten benötigt diese [CR]Komfortfunktion etwas mehr Zeit![/COLOR]" />
<setting id="status.refresh" type="text" label="Status aktualisieren (refresh)" default="" visible="false"/>
<setting id="status.refresh.movies" type="bool" label="Filme - Status aktualisieren (refresh)" default="true" />
<setting id="status.refresh.episodes" type="bool" label="Episoden - Status aktualisieren (refresh)" default="true" />
<setting id="status.position" type="bool" label="Status - Bei Serien die aktuelle Position setzen" default="true" />
<setting id="status.debug" type="bool" label="Debug" default="false" />
</category>
<category label="Indexseiten (DE)">
<setting type="text" label="[COLOR blue]ACHTUNG: Die folgenden Optionen werden sofort[/COLOR]" />
<setting type="text" label="[COLOR blue]und für [B]alle[/B] Indexseiten ausgeführt![/COLOR]" />
<setting type="sep"/>
<!--<setting label="Einstellung auf Defaults setzen" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=defaultsGerman)"/> -->
<setting label="Alle Quellen aktivieren" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=toggleGerman&amp;setting=true)" option=""/>
<setting label="Alle Quellen deaktivieren" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=toggleGerman&amp;setting=false)" option=""/>
<!-- <setting type="lsep" label="Scrapers" /> -->
<setting type="sep"/>
<setting id="provider.aniworld" type="bool" label="ANIWORLD | [B][COLOR green]Serien[/COLOR][/B]" default="false"/>
<setting id="provider.aniworld.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.aniworld.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.einschalten" type="bool" label="EINSCHALTEN | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.einschalten.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.einschalten.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.filmpalast" type="bool" label="FILMPALAST | [B][COLOR blue] Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.filmpalast.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.filmpalast.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.filmpro" type="bool" label="FILMPRO | [B][COLOR blue] Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.filmpro.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.filmpro.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<!--<setting id="provider.flimmerstube" type="bool" label="FLIMMERSTUBE | [B][COLOR blue] Filme &amp; Serien[/COLOR][/B]" default="false" />
<setting id="provider.flimmerstube.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.flimmerstube.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>-->
<setting id="provider.hdfilme" type="bool" label="HDFILME | [B][COLOR blue] Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.hdfilme.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.hdfilme.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<!--<setting id="provider.huhu" type="bool" label="HUHU | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.huhu.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.huhu.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>-->
<setting id="provider.kinoger" type="bool" label="KINOGER | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.kinoger.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.kinoger.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.kinokiste" type="bool" label="KINOKISTE | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.kinokiste.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.kinokiste.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.kinox" type="bool" label="KINOX | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.kinox.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.kinox.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.kkiste" type="bool" label="KKISTE | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.kkiste.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.kkiste.check" label="Check" type="bool" default="true" visible="false"/>
<setting id="provider.kkiste.checkHoster" type="bool" label="Streams auf Verfügbarkeit überprüfen (langsamer)" default="true" visible="eq(-2,true)"/>
</category>
<category label="Indexseiten 2 (DE)">
<setting type="text" label="[COLOR blue]ACHTUNG: Die folgenden Optionen werden sofort[/COLOR]" />
<setting type="text" label="[COLOR blue]und für [B]alle[/B] Indexseiten ausgeführt![/COLOR]" />
<setting type="sep"/>
<!--<setting label="Einstellung auf Defaults setzen" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=defaultsGerman)"/> -->
<setting label="Alle Quellen aktivieren" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=toggleGerman&amp;setting=true)" option=""/>
<setting label="Alle Quellen deaktivieren" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=toggleGerman&amp;setting=false)" option=""/>
<!-- <setting type="lsep" label="Scrapers" /> -->
<setting type="sep"/>
<setting id="provider.megakino" type="bool" label="MEGAKINO | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.megakino.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.megakino.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.moflix" type="bool" label="MOFLIX-STREAM | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.moflix.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.moflix.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.movie2k" type="bool" label="MOVIE2k | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true"/>
<setting id="provider.movie2k.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.movie2k.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.movie4k" type="bool" label="MOVIE4k | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true"/>
<setting id="provider.movie4k.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.movie4k.check" label="Check" type="bool" default="true" visible="false"/>
<setting id="provider.movie4k.checkHoster" type="bool" label="Streams auf Verfügbarkeit überprüfen" default="true" visible="eq(-2,true)"/>
<setting type="sep"/>
<setting id="provider.netzkino" type="bool" label="NETZKINO | [B][COLOR red]Filme[/COLOR][/B]" default="false" />
<setting id="provider.netzkino.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.netzkino.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.serienstream" type="bool" label="SERIENSTREAM | [B][COLOR green]Serien[/COLOR][/B]" default="true"/>
<setting id="provider.serienstream.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.serienstream.check" label="Check" type="bool" default="true" visible="false"/>
<!--<setting type="sep"/>
<setting id="provider.serien-stream" type="bool" label="Serien-Stream | [B][COLOR green]Serien[/COLOR][/B]" default="true"/>
<setting id="provider.serien-stream.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.serien-stream.check" label="Check" type="bool" default="true" visible="false"/>-->
<setting type="sep"/>
<setting id="provider.streamcloud" type="bool" label="STREAMCLOUD | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting id="provider.streamcloud.domain" label="[B][COLOR red]PluginError oder Domain nicht erreichbar[/COLOR][/B]" type="text" default="" visible="eq(1,false)"/>
<setting id="provider.streamcloud.check" label="Check" type="bool" default="true" visible="false"/>
<setting type="sep"/>
<setting id="provider.vavoo" type="bool" label="VAVOO | [B][COLOR blue]Filme &amp; Serien[/COLOR][/B]" default="true" />
<setting type="sep"/>
</category>
<category label="Wiedergabe">
<setting id="progress.dialog" type="enum" label="Fortschrittsdialog" values="Vordergrund|Hintergrund" default="1" />
<!--<setting id="prem.identify" type="enum" label="Textfarbe für Premium-Links" values="Blau|Rot|Gelb|Altrosa|Cyan|Grasgrün|Gold|Magenta|Gelbgrün|Ohne Farbe" default="0" /> -->
<setting type="lsep" label="Dateinanbieter-Filter" />
<setting id="hosts.quality" type="enum" label="Höchste Qualität" values="4K|1440p|1080p|720p|480p" default="0" />
<setting id="hosts.sort.priority" type="bool" label="Indexseiten bei Serien nach Priorität sortieren" default="true" />
<setting id="hosts.sort.provider" type="bool" label="Indexseiten nach Anbieter sortieren" default="true" />
<setting id="hosts.refresh" type="text" label="Status aktualisieren (refresh)" default="" visible="true"/>
<setting id="hosts.limit" type="bool" label="Limit Hosteranzahl" default="False" />
<setting id="hosts.limit.num" type="slider" label="Liste begrenzen auf:" default="15" range="5,50" option="int" visible="eq(-1,true)"/>
<setting id="hosts.filter" type="text" label="Hoster ausschließen (Liste)" default=""/>
<setting type="lsep" label="Bei Wiedergabe-Start..." />
<setting id="bookmarks" type="bool" label="Fortsetzen" default="true" />
<setting id="bookmarks.auto" type="bool" label="Automatisch Fortsetzen" default="true" enable="!eq(-1,false)" />
</category>
<category label="Konten">
<setting type="lsep" label="Konto [B]SerienStream.to[/B]"/>
<setting id="serienstream.user" type="text" label="Email" default=""/>
<setting id="serienstream.pass" type="text" option="hidden" label="Password" default=""/>
<setting type="lsep" label="Konto [B]FlimmerStube.com[/B]"/>
<setting id="flimmerstube.user" type="text" label="Email" default=""/>
<setting id="flimmerstube.pass" type="text" option="hidden" label="Password" default=""/>
<setting type="lsep" label="Konto [B]Aniworld.io[/B]"/>
<setting id="aniworld.user" type="text" label="Email" default=""/>
<setting id="aniworld.pass" type="text" option="hidden" label="Password" default=""/>
<setting type="lsep" label="TMDb" />
<setting id="api.tmdb" type="text" option="hidden" label="API-Key" default="0b529d296545c2545a68db5cb903cd94" />
<setting type="lsep" label="TRAKT" />
<setting id="api.trakt" type="text" option="hidden" label="API-Key" default="85d3b28a69fd4d8162b3ea78689e1c8b15ff2ad9c1430ef6fc5a950662aee3ec" />
<setting type="lsep" label="FANART.TV" />
<setting id="api.fanart.tv" type="text" label="API-Key" option="hidden" default="e376e8591e1580089d93ab4135fcc082" />
<setting type="lsep" label="Konto [B]opensubtitles.org[/B]"/>
<!-- <setting id="subtitles.os_user" type="text" label="UserName" default=""/>
<setting id="subtitles.os_pass" type="text" option="hidden" label="Password" default=""/> -->
</category>
<category label="Downloads / Untertitel">
<setting id="downloads" type="bool" label="Herunterladen aktivieren" default="false" />
<!-- <setting type="sep" /> -->
<setting type="lsep" label="Bitte Ordnerpfade eingeben" />
<!--<<setting type="text" label="oder [COLOR blue]smb://ServerIP/path_to_files/ | nfs://ServerIP/path_to_files/[/COLOR]" /> -->
<setting label="[COLOR blue]Hier Hilfe zum Syntax für den Ordnerpfad[/COLOR]" type="action" action="RunPlugin(plugin://plugin.video.xship/?action=settings&amp;subaction=downloadInfo)" option=""/>
<setting id="download.movie.path" type="text" label="Filme" enable="!eq(-3,false)" default="" />
<!--<setting id="download.tv.path" type="folder" label="TV-Serien" enable="!eq(-4,false)" default="" /> -->
<setting id="download.tv.path" type="text" label="TV-Serien" enable="!eq(-4,false)" default="" />
<setting type="lsep" label="[CR]" />-->
<!--<setting type="text" label="Herunterladen ist standardmäßig deaktiviert." />-->
<setting type="sep" />
<setting id="subtitles" type="bool" label="Untertitel aktivieren" default="false" />
<setting type="text" label="[COLOR blue]Konto auf [B]opensubtitles.org[/B] einrichten und[CR]die Zugandsdaten unter Einstellungen / Konten eintragen![CR][/COLOR]" visible="!eq(-1,false)"/>
<setting type="lsep" label="Konto [B]opensubtitles.org[/B]"/>
<setting id="subtitles.os_user" type="text" label="UserName" default=""/>
<setting id="subtitles.os_pass" type="text" option="hidden" label="Password" default=""/>
<setting type="sep" />
<setting id="subtitles.lang.1" type="select" label="Hauptsprache" values="Afrikaans|Albanian|Arabic|Armenian|Basque|Bengali|Bosnian|Breton|Bulgarian|Burmese|Catalan|Chinese|Croatian|Czech|Danish|Dutch|English|Esperanto|Estonian|Finnish|French|Galician|Georgian|German|Greek|Hebrew|Hindi|Hungarian|Icelandic|Indonesian|Italian|Japanese|Kazakh|Khmer|Korean|Latvian|Lithuanian|Luxembourgish|Macedonian|Malay|Malayalam|Manipuri|Mongolian|Montenegrin|Norwegian|Occitan|Persian|Polish|Portuguese|Portuguese(Brazil)|Romanian|Russian|Serbian|Sinhalese|Slovak|Slovenian|Spanish|Swahili|Swedish|Syriac|Tagalog|Tamil|Telugu|Thai|Turkish|Ukrainian|Urdu" enable="!eq(-3,false)" default="German" />
<setting id="subtitles.lang.2" type="select" label="Zweitsprache" values="Afrikaans|Albanian|Arabic|Armenian|Basque|Bengali|Bosnian|Breton|Bulgarian|Burmese|Catalan|Chinese|Croatian|Czech|Danish|Dutch|English|Esperanto|Estonian|Finnish|French|Galician|Georgian|German|Greek|Hebrew|Hindi|Hungarian|Icelandic|Indonesian|Italian|Japanese|Kazakh|Khmer|Korean|Latvian|Lithuanian|Luxembourgish|Macedonian|Malay|Malayalam|Manipuri|Mongolian|Montenegrin|Norwegian|Occitan|Persian|Polish|Portuguese|Portuguese(Brazil)|Romanian|Russian|Serbian|Sinhalese|Slovak|Slovenian|Spanish|Swahili|Swedish|Syriac|Tagalog|Tamil|Telugu|Thai|Turkish|Ukrainian|Urdu" enable="!eq(-4,false)" default="English" />
<setting id="subtitles.utf" type="bool" label="Untertitel nach UTF-8 umwandeln" enable="!eq(-5,false)" default="false" />
<setting type="lsep" label="Download-Manager" />
<setting id="jd_enabled" type="bool" label="JDownloader aktivieren" default="false" />
<setting id="jd_host" type="text" label="Host" default="127.0.0.1" enable="!eq(-1,false)" />
<setting id="jd_port" type="number" label="Port" default="10025" enable="!eq(-2,false)" />
<setting id="jd_automatic_start" type="bool" label="Automatischer Start" default="false" enable="!eq(-3,false)" />
<setting id="jd_grabber" type="bool" label="LinkGrabber verwenden" default="true" enable="!eq(-4,false)" />
<setting type="sep" />
<setting id="jd2_enabled" type="bool" label="JDownloader 2 aktivieren" default="false" />
<setting id="jd2_host" type="text" label="Host" default="127.0.0.1" enable="!eq(-1,false)" />
<setting id="jd2_port" type="number" label="Port" default="9666" enable="!eq(-2,false)" />
<setting type="sep" />
<setting id="myjd_enabled" type="bool" label="My.JDownloader aktivieren" default="false" />
<setting id="myjd_device" type="text" label="Gerätename" default="JDownloader@Device" enable="!eq(-1,false)" />
<setting id="myjd_user" type="text" label="E-Mail" default="" enable="!eq(-2,false)" />
<setting id="myjd_pass" type="text" label="Passwort" option="hidden" default="" enable="!eq(-3,false)" />
<setting type="sep" />
<setting id="pyload_enabled" type="bool" label="PyLoad aktivieren" default="false" />
<setting id="pyload_host" type="text" label="Host" default="127.0.0.1" enable="!eq(-1,false)" />
<setting id="pyload_port" type="number" label="Port" default="8000" enable="!eq(-2,false)" />
<setting id="pyload_user" type="text" label="Benutzername" default="" enable="!eq(-3,false)" />
<setting id="pyload_passwd" type="text" label="Passwort" option="hidden" default="" enable="!eq(-4,false)" />
</category>
</settings>
# edit 2025-06-12
import sys
import re, json, random, time
from concurrent.futures import ThreadPoolExecutor
from resources.lib import log_utils, utils, control
from resources.lib.control import py2_decode, py2_encode, quote_plus, parse_qsl
import resolveurl as resolver
# from functools import reduce
from resources.lib.control import getKodiVersion
if int(getKodiVersion()) >= 20: from infotagger.listitem import ListItemInfoTag
# für self.sysmeta - zur späteren verwendung als meta
_params = dict(parse_qsl(sys.argv[2].replace('?',''))) if len(sys.argv) > 1 else dict()
class sources:
def __init__(self):
self.getConstants()
self.sources = []
self.current = int(time.time())
if 'sysmeta' in _params: self.sysmeta = _params['sysmeta'] # string zur späteren verwendung als meta
self.watcher = False
self.executor = ThreadPoolExecutor(max_workers=20)
self.url = None
def get(self, params):
data = json.loads(params['sysmeta'])
self.mediatype = data.get('mediatype')
self.aliases = data.get('aliases') if 'aliases' in data else []
title = py2_encode(data.get('title'))
originaltitle = py2_encode(data.get('originaltitle')) if 'originaltitle' in data else title
year = data.get('year') if 'year' in data else None
imdb = data.get('imdb_id') if 'imdb_id' in data else data.get('imdbnumber') if 'imdbnumber' in data else None
if not imdb and 'imdb' in data: imdb = data.get('imdb')
tmdb = data.get('tmdb_id') if 'tmdb_id' in data else None
#if tmdb and not imdb: print 'hallo' #TODO
season = data.get('season') if 'season' in data else 0
episode = data.get('episode') if 'episode' in data else 0
premiered = data.get('premiered') if 'premiered' in data else None
meta = params['sysmeta']
select = data.get('select') if 'select' in data else None
return title, year, imdb, season, episode, originaltitle, premiered, meta, select
def play(self, params):
title, year, imdb, season, episode, originaltitle, premiered, meta, select = self.get(params)
try:
url = None
#Liste der gefundenen Streams
items = self.getSources(title, year, imdb, season, episode, originaltitle, premiered)
select = control.getSetting('hosts.mode') if select == None else select
## unnötig
#select = '1' if control.getSetting('downloads') == 'true' and not (control.getSetting('download.movie.path') == '' or control.getSetting('download.tv.path') == '') else select
# # TODO überprüfen wofür mal gedacht
# if control.window.getProperty('PseudoTVRunning') == 'True':
# return control.resolveUrl(int(sys.argv[1]), True, control.item(path=str(self.sourcesDirect(items))))
if len(items) > 0:
# Auswahl Verzeichnis
if select == '1' and 'plugin' in control.infoLabel('Container.PluginName'):
control.window.clearProperty(self.itemsProperty)
control.window.setProperty(self.itemsProperty, json.dumps(items))
control.window.clearProperty(self.metaProperty)
control.window.setProperty(self.metaProperty, meta)
control.sleep(2)
return control.execute('Container.Update(%s?action=addItem&title=%s)' % (sys.argv[0], quote_plus(title)))
# Auswahl Dialog
elif select == '0' or select == '1':
url = self.sourcesDialog(items)
if url == 'close://': return
# Autoplay
else:
url = self.sourcesDirect(items)
if url == None: return self.errorForSources()
try: meta = json.loads(meta)
except: pass
from resources.lib.player import player
player().run(title, url, meta)
except Exception as e:
log_utils.log('Error %s' % str(e), log_utils.LOGERROR)
# Liste gefundene Streams Indexseite|Hoster
def addItem(self, title):
control.playlist.clear()
items = control.window.getProperty(self.itemsProperty)
items = json.loads(items)
if items == None or len(items) == 0: control.idle() ; sys.exit()
sysaddon = sys.argv[0]
syshandle = int(sys.argv[1])
systitle = sysname = quote_plus(title)
meta = control.window.getProperty(self.metaProperty)
meta = json.loads(meta)
#TODO
if meta['mediatype'] == 'movie':
# downloads = True if control.getSetting('downloads') == 'true' and control.exists(control.translatePath(control.getSetting('download.movie.path'))) else False
downloads = True if control.getSetting('downloads') == 'true' and control.getSetting('download.movie.path') else False
else:
# downloads = True if control.getSetting('downloads') == 'true' and control.exists(control.translatePath(control.getSetting('download.tv.path'))) else False
downloads = True if control.getSetting('downloads') == 'true' and control.getSetting('download.tv.path') else False
addonPoster, addonBanner = control.addonPoster(), control.addonBanner()
addonFanart, settingFanart = control.addonFanart(), control.getSetting('fanart')
if 'backdrop_url' in meta and 'http' in meta['backdrop_url']: fanart = meta['backdrop_url']
elif 'fanart' in meta and 'http' in meta['fanart']: fanart = meta['fanart']
else: fanart = addonFanart
if 'cover_url' in meta and 'http' in meta['cover_url']: poster = meta['cover_url']
elif 'poster' in meta and 'http' in meta['poster']: poster = meta['poster']
else: poster = addonPoster
sysimage = poster
if 'season' in meta and 'episode' in meta:
sysname += quote_plus(' S%02dE%02d' % (int(meta['season']), int(meta['episode'])))
elif 'year' in meta:
sysname += quote_plus(' (%s)' % meta['year'])
for i in range(len(items)):
try:
label = items[i]['label']
syssource = quote_plus(json.dumps([items[i]]))
item = control.item(label=label, offscreen=True)
item.setProperty('IsPlayable', 'true')
item.setArt({'poster': poster, 'banner': addonBanner})
if settingFanart == 'true': item.setProperty('Fanart_Image', fanart)
cm = []
if downloads:
cm.append(("Download", 'RunPlugin(%s?action=download&name=%s&image=%s&source=%s)' % (sysaddon, sysname, sysimage, syssource)))
if control.getSetting('jd_enabled') == 'true':
cm.append(("Sende zum JDownloader", 'RunPlugin(%s?action=sendToJD&name=%s&source=%s)' % (sysaddon, sysname, syssource)))
if control.getSetting('jd2_enabled') == 'true':
cm.append(("Sende zum JDownloader2", 'RunPlugin(%s?action=sendToJD2&name=%s&source=%s)' % (sysaddon, sysname, syssource)))
if control.getSetting('myjd_enabled') == 'true':
cm.append(("Sende zu My.JDownloader", 'RunPlugin(%s?action=sendToMyJD&name=%s&source=%s)' % (sysaddon, sysname, syssource)))
if control.getSetting('pyload_enabled') == 'true':
cm.append(("Sende zu PyLoad", 'RunPlugin(%s?action=sendToPyLoad&name=%s&source=%s)' % (sysaddon, sysname, syssource)))
cm.append(('Einstellungen', 'RunPlugin(%s?action=addonSettings)' % sysaddon))
item.addContextMenuItems(cm)
url = "%s?action=playItem&title=%s&source=%s" % (sysaddon, systitle, syssource)
# ## Notwendig für Library Exporte ##
# ## Amazon Scraper Details ##
# if "amazon" in label.lower():
# aid = re.search(r'asin%3D(.*?)%22%2C', url)
# url = "plugin://plugin.video.amazon-test/?mode=PlayVideo&asin=" + aid.group(1)
##https: // codedocs.xyz / AlwinEsch / kodi / group__python__xbmcgui__listitem.html # ga0b71166869bda87ad744942888fb5f14
name = '%s%sStaffel: %s Episode: %s' % (title, "\n", meta['season'], meta['episode']) if 'season' in meta else title
plot = meta['plot'] if 'plot' in meta and len(meta['plot'].strip()) >= 1 else ''
plot = '[COLOR blue]%s[/COLOR]%s%s' % (name, "\n\n", py2_encode(plot))
if 'duration' in meta:
infolable = {'plot': plot,'duration': meta['duration']}
else:
infolable = {'plot': plot}
# TODO
# if 'cast' in meta and meta['cast']: item.setCast(meta['cast'])
# # # remove unsupported InfoLabels
meta.pop('cast', None) # ersetzt durch item.setCast(i['cast'])
meta.pop('number_of_seasons', None)
meta.pop('imdb_id', None)
meta.pop('tvdb_id', None)
meta.pop('tmdb_id', None)
## Quality Video Stream from source.append quality - items[i]['quality']
video_streaminfo ={}
if "4k" in items[i]['quality'].lower():
video_streaminfo.update({'width': 3840, 'height': 2160})
elif "1080p" in items[i]['quality'].lower():
video_streaminfo.update({'width': 1920, 'height': 1080})
elif "hd" in items[i]['quality'].lower() or "720p" in items[i]['quality'].lower():
video_streaminfo.update({'width': 1280,'height': 720})
else:
# video_streaminfo.update({"width": 720, "height": 576})
video_streaminfo.update({})
## Codec for Video Stream from extra info - items[i]['info']
if 'hevc' in items[i]['label'].lower():
video_streaminfo.update({'codec': 'hevc'})
elif '265' in items[i]['label'].lower():
video_streaminfo.update({'codec': 'h265'})
elif 'mkv' in items[i]['label'].lower():
video_streaminfo.update({'codec': 'mkv'})
elif 'mp4' in items[i]['label'].lower():
video_streaminfo.update({'codec': 'mp4'})
else:
# video_streaminfo.update({'codec': 'h264'})
video_streaminfo.update({'codec': ''})
## Quality & Channels Audio Stream from extra info - items[i]['info']
audio_streaminfo = {}
if 'dts' in items[i]['label'].lower():
audio_streaminfo.update({'codec': 'dts'})
elif 'plus' in items[i]['label'].lower() or 'e-ac3' in items[i]['label'].lower():
audio_streaminfo.update({'codec': 'eac3'})
elif 'dolby' in items[i]['label'].lower() or 'ac3' in items[i]['label'].lower():
audio_streaminfo.update({'codec': 'ac3'})
else:
# audio_streaminfo.update({'codec': 'aac'})
audio_streaminfo.update({'codec': ''})
## Channel update ##
if '7.1' in items[i].get('info','').lower():
audio_streaminfo.update({'channels': 8})
elif '5.1' in items[i].get('info','').lower():
audio_streaminfo.update({'channels': 6})
else:
# audio_streaminfo.update({'channels': 2})
audio_streaminfo.update({'channels': ''})
if int(getKodiVersion()) <= 19:
item.setInfo(type='Video', infoLabels=infolable)
item.addStreamInfo('video', video_streaminfo)
item.addStreamInfo('audio', audio_streaminfo)
else:
info_tag = ListItemInfoTag(item, 'video')
info_tag.set_info(infolable)
stream_details = {
'video': [video_streaminfo],
'audio': [audio_streaminfo]}
info_tag.set_stream_details(stream_details)
# info_tag.set_cast(aActors)
control.addItem(handle=syshandle, url=url, listitem=item, isFolder=False)
except:
pass
control.content(syshandle, 'videos')
control.plugincategory(syshandle, control.addonVersion)
control.endofdirectory(syshandle, cacheToDisc=True)
def playItem(self, title, source):
isDebug = False
if isDebug: log_utils.log('start playItem', log_utils.LOGWARNING)
try:
meta = control.window.getProperty(self.metaProperty)
meta = json.loads(meta)
header = control.addonInfo('name')
# control.idle() #ok
progressDialog = control.progressDialog if control.getSetting('progress.dialog') == '0' else control.progressDialogBG
progressDialog.create(header, '')
progressDialog.update(0)
item = json.loads(source)[0]
#if isDebug: log_utils.log('playItem 237', log_utils.LOGWARNING)
if item['source'] == None: raise Exception()
future = self.executor.submit(self.sourcesResolve, item)
waiting_time = 30
while waiting_time > 0:
try:
if control.abortRequested: return sys.exit()
if progressDialog.iscanceled(): return progressDialog.close()
except:
pass
if future.done(): break
control.sleep(1)
waiting_time = waiting_time - 1
progressDialog.update(int(100 - 100. / 30 * waiting_time), str(item['label']))
#if isDebug: log_utils.log('playItem 252', log_utils.LOGWARNING)
if control.condVisibility('Window.IsActive(virtualkeyboard)') or \
control.condVisibility('Window.IsActive(yesnoDialog)'):
# or control.condVisibility('Window.IsActive(PopupRecapInfoWindow)'):
waiting_time = waiting_time + 1 # dont count down while dialog is presented
if future.done(): break
try: progressDialog.close()
except: pass
if isDebug: log_utils.log('playItem 261', log_utils.LOGWARNING)
control.execute('Dialog.Close(virtualkeyboard)')
control.execute('Dialog.Close(yesnoDialog)')
if isDebug: log_utils.log('playItem url: %s' % self.url, log_utils.LOGWARNING)
if self.url == None:
#self.errorForSources()
return
from resources.lib.player import player
player().run(title, self.url, meta)
return self.url
except Exception as e:
log_utils.log('Error %s' % str(e), log_utils.LOGERROR)
def getSources(self, title, year, imdb, season, episode, originaltitle, premiered, quality='HD', timeout=30):
#TODO
# self._getHostDict()
control.idle() #ok
progressDialog = control.progressDialog if control.getSetting('progress.dialog') == '0' else control.progressDialogBG
progressDialog.create(control.addonInfo('name'), '')
progressDialog.update(0)
progressDialog.update(0, "Quellen werden vorbereitet")
sourceDict = self.sourceDict
sourceDict = [(i[0], i[1], i[1].priority) for i in sourceDict]
random.shuffle(sourceDict)
sourceDict = sorted(sourceDict, key=lambda i: i[2])
content = 'movies' if season == 0 or season == '' or season == None else 'shows'
aliases, localtitle = utils.getAliases(imdb, content)
if localtitle and title != localtitle and originaltitle != localtitle:
if not title in aliases: aliases.append(title)
title = localtitle
for i in self.aliases:
if not i in aliases:
aliases.append(i)
titles = utils.get_titles_for_search(title, originaltitle, aliases)
futures = {self.executor.submit(self._getSource, titles, year, season, episode, imdb, provider[0], provider[1]): provider[0] for provider in sourceDict}
provider_names = {provider[0].upper() for provider in sourceDict}
string4 = "Total"
try: timeout = int(control.getSetting('scrapers.timeout'))
except: pass
quality = control.getSetting('hosts.quality')
if quality == '': quality = '0'
source_4k = 0
source_1080 = 0
source_720 = 0
source_sd = 0
total = d_total = 0
total_format = '[COLOR %s][B]%s[/B][/COLOR]'
pdiag_format = ' 4K: %s | 1080p: %s | 720p: %s | SD: %s | %s: %s '.split('|')
for i in range(0, 4 * timeout):
try:
if control.abortRequested: return sys.exit()
try:
if progressDialog.iscanceled(): break
except:
pass
if len(self.sources) > 0:
if quality in ['0']:
source_4k = len([e for e in self.sources if e['quality'] == '4K'])
source_1080 = len([e for e in self.sources if e['quality'] in ['1440p','1080p']])
source_720 = len([e for e in self.sources if e['quality'] in ['720p','HD']])
source_sd = len([e for e in self.sources if e['quality'] not in ['4K','1440p','1080p','720p','HD']])
elif quality in ['1']:
source_1080 = len([e for e in self.sources if e['quality'] in ['1440p','1080p']])
source_720 = len([e for e in self.sources if e['quality'] in ['720p','HD']])
source_sd = len([e for e in self.sources if e['quality'] not in ['4K','1440p','1080p','720p','HD']])
elif quality in ['2']:
source_1080 = len([e for e in self.sources if e['quality'] in ['1080p']])
source_720 = len([e for e in self.sources if e['quality'] in ['720p','HD']])
source_sd = len([e for e in self.sources if e['quality'] not in ['4K','1440p','1080p','720p','HD']])
elif quality in ['3']:
source_720 = len([e for e in self.sources if e['quality'] in ['720p','HD']])
source_sd = len([e for e in self.sources if e['quality'] not in ['4K','1440p','1080p','720p','HD']])
else:
source_sd = len([e for e in self.sources if e['quality'] not in ['4K','1440p','1080p','720p','HD']])
total = source_4k + source_1080 + source_720 + source_sd
source_4k_label = total_format % ('red', source_4k) if source_4k == 0 else total_format % ('lime', source_4k)
source_1080_label = total_format % ('red', source_1080) if source_1080 == 0 else total_format % ('lime', source_1080)
source_720_label = total_format % ('red', source_720) if source_720 == 0 else total_format % ('lime', source_720)
source_sd_label = total_format % ('red', source_sd) if source_sd == 0 else total_format % ('lime', source_sd)
source_total_label = total_format % ('red', total) if total == 0 else total_format % ('lime', total)
try:
info = [name.upper() for future, name in futures.items() if not future.done()]
percent = int(100 * float(i) / (2 * timeout) + 1)
if quality in ['0']:
line1 = '|'.join(pdiag_format) % (source_4k_label, source_1080_label, source_720_label, source_sd_label, str(string4), source_total_label)
elif quality in ['1']:
line1 = '|'.join(pdiag_format[1:]) % (source_1080_label, source_720_label, source_sd_label, str(string4), source_total_label)
elif quality in ['2']:
line1 = '|'.join(pdiag_format[1:]) % (source_1080_label, source_720_label, source_sd_label, str(string4), source_total_label)
elif quality in ['3']:
line1 = '|'.join(pdiag_format[2:]) % (source_720_label, source_sd_label, str(string4), source_total_label)
else:
line1 = '|'.join(pdiag_format[3:]) % (source_sd_label, str(string4), source_total_label)
if (i / 2) < timeout:
string = "Verbleibende Indexseiten: %s"
else:
string = 'Waiting for: %s'
if len(info) > 6: line = line1 + string % (str(len(info)))
elif len(info) > 1: line = line1 + string % (', '.join(info))
elif len(info) == 1: line = line1 + string % (''.join(info))
else: line = line1 + 'Suche beendet!'
progressDialog.update(max(1, percent), line)
if len(info) == 0: break
except Exception as e:
log_utils.log('Exception Raised: %s' % str(e), log_utils.LOGERROR)
control.sleep(1)
except:
pass
time.sleep(1)
try: progressDialog.close()
except: pass
self.sourcesFilter()
return self.sources
def _getSource(self, titles, year, season, episode, imdb, source, call):
try:
sources = call.run(titles, year, season, episode, imdb) # kasi self.hostDict
if sources == None or sources == []: raise Exception()
sources = [json.loads(t) for t in set(json.dumps(d, sort_keys=True) for d in sources)]
for i in sources:
i.update({'provider': source})
if not 'priority' in i: i.update({'priority': 100})
if not 'prioHoster' in i: i.update({'prioHoster': 100})
self.sources.extend(sources)
except:
pass
def sourcesFilter(self):
# hostblockDict = utils.getHostDict()
# self.sources = [i for i in self.sources if i['source'].split('.')[0] not in str(hostblockDict)] # Hoster ausschließen (Liste)
quality = control.getSetting('hosts.quality')
if quality == '': quality = '0'
random.shuffle(self.sources)
self.sources = sorted(self.sources, key=lambda k: k['prioHoster'], reverse=False)
for i in range(len(self.sources)):
q = self.sources[i]['quality']
if q.lower() == 'hd': self.sources[i].update({'quality': '720p'})
filter = []
if quality in ['0']: filter += [i for i in self.sources if i['quality'] == '4K']
if quality in ['0', '1']: filter += [i for i in self.sources if i['quality'] == '1440p']
if quality in ['0', '1', '2']: filter += [i for i in self.sources if i['quality'] == '1080p']
if quality in ['0', '1', '2', '3']: filter += [i for i in self.sources if i['quality'] == '720p']
#filter += [i for i in self.sources if i['quality'] in ['SD', 'SCR', 'CAM']]
filter += [i for i in self.sources if i['quality'] not in ['4k', '1440p', '1080p', '720p']]
self.sources = filter
if control.getSetting('hosts.sort.provider') == 'true':
self.sources = sorted(self.sources, key=lambda k: k['provider'])
if control.getSetting('hosts.sort.priority') == 'true' and self.mediatype == 'tvshow': self.sources = sorted(self.sources, key=lambda k: k['priority'], reverse=False)
if str(control.getSetting('hosts.limit')) == 'true':
self.sources = self.sources[:int(control.getSetting('hosts.limit.num'))]
else:
self.sources = self.sources[:100]
for i in range(len(self.sources)):
p = self.sources[i]['provider']
q = self.sources[i]['quality']
s = self.sources[i]['source']
## s = s.rsplit('.', 1)[0]
l = self.sources[i]['language']
try: f = (' | '.join(['[I]%s [/I]' % info.strip() for info in self.sources[i]['info'].split('|')]))
except: f = ''
label = '%02d | [B]%s[/B] | ' % (int(i + 1), p)
if q in ['4K', '1440p', '1080p', '720p']: label += '%s | [B][I]%s [/I][/B] | %s' % (s, q, f)
elif q == 'SD': label += '%s | %s' % (s, f)
else: label += '%s | %s | [I]%s [/I]' % (s, f, q)
label = label.replace('| 0 |', '|').replace(' | [I]0 [/I]', '')
label = re.sub(r'\[I\]\s+\[/I\]', ' ', label)
label = re.sub(r'\|\s+\|', '|', label)
label = re.sub(r'\|(?:\s+|)$', '', label)
self.sources[i]['label'] = label.upper()
# ## EMBY shown as premium link ##
# if self.sources[i]['provider']=="emby" or self.sources[i]['provider']=="amazon" or self.sources[i]['provider']=="netflix" or self.sources[i]['provider']=="maxdome":
# prem_identify = 'blue'
# self.sources[i]['label'] = ('[COLOR %s]' % (prem_identify)) + label.upper() + '[/COLOR]'
self.sources = [i for i in self.sources if 'label' in i]
return self.sources
def sourcesResolve(self, item, info=False):
try:
self.url = None
url = item['url']
direct = item['direct']
local = item.get('local', False)
provider = item['provider']
call = [i[1] for i in self.sourceDict if i[0] == provider][0]
url = call.resolve(url)
if not direct == True:
try:
hmf = resolver.HostedMediaFile(url=url, include_disabled=True, include_universal=False)
if hmf.valid_url():
url = hmf.resolve()
if url == False or url == None or url == '': url = None # raise Exception()
except:
url = None
if url == None or (not '://' in str(url) and not local):
log_utils.log('Kein Video Link gefunden: Provider %s / %s / %s ' % (item['provider'], item['source'] , str(item['source'])), log_utils.LOGERROR)
raise Exception()
# if not utils.test_stream(url):
# log_utils.log('URL Test Error: %s' % url, log_utils.LOGERROR)
# raise Exception()
# url = utils.m3u8_check(url)
if url:
self.url = url
return url
else:
raise Exception()
except:
if info: self.errorForSources()
return
def sourcesDialog(self, items):
labels = [i['label'] for i in items]
select = control.selectDialog(labels)
if select == -1: return 'close://'
next = [y for x,y in enumerate(items) if x >= select]
prev = [y for x,y in enumerate(items) if x < select][::-1]
items = [items[select]]
items = [i for i in items+next+prev][:40]
header = control.addonInfo('name')
header2 = header.upper()
progressDialog = control.progressDialog if control.getSetting('progress.dialog') == '0' else control.progressDialogBG
progressDialog.create(header, '')
progressDialog.update(0)
block = None
try:
for i in range(len(items)):
try:
if items[i]['source'] == block: raise Exception()
future = self.executor.submit(self.sourcesResolve, items[i])
try:
if progressDialog.iscanceled(): break
progressDialog.update(int((100 / float(len(items))) * i), str(items[i]['label']))
except:
progressDialog.update(int((100 / float(len(items))) * i), str(header2) + str(items[i]['label']))
waiting_time = 30
while waiting_time > 0:
try:
if control.abortRequested: return sys.exit() #xbmc.Monitor().abortRequested()
if progressDialog.iscanceled(): return progressDialog.close()
except:
pass
if future.done(): break
control.sleep(1)
waiting_time = waiting_time - 1
if control.condVisibility('Window.IsActive(virtualkeyboard)') or \
control.condVisibility('Window.IsActive(yesnoDialog)') or \
control.condVisibility('Window.IsActive(ProgressDialog)'):
waiting_time = waiting_time + 1 #dont count down while dialog is presented ## control.condVisibility('Window.IsActive(PopupRecapInfoWindow)') or \
if not future.done(): block = items[i]['source']
if self.url == None: raise Exception()
self.selectedSource = items[i]['label']
try: progressDialog.close()
except: pass
control.execute('Dialog.Close(virtualkeyboard)')
control.execute('Dialog.Close(yesnoDialog)')
return self.url
except:
pass
try: progressDialog.close()
except: pass
except Exception as e:
try: progressDialog.close()
except: pass
log_utils.log('Error %s' % str(e), log_utils.LOGINFO)
def sourcesDirect(self, items):
# TODO - OK
# filter = [i for i in items if i['source'].lower() in self.hostcapDict and i['debrid'] == '']
# items = [i for i in items if not i in filter]
# items = [i for i in items if ('autoplay' in i and i['autoplay'] == True) or not 'autoplay' in i]
u = None
header = control.addonInfo('name')
header2 = header.upper()
try:
control.sleep(1)
progressDialog = control.progressDialog if control.getSetting('progress.dialog') == '0' else control.progressDialogBG
progressDialog.create(header, '')
progressDialog.update(0)
except:
pass
for i in range(len(items)):
try:
if progressDialog.iscanceled(): break
progressDialog.update(int((100 / float(len(items))) * i), str(items[i]['label']))
except:
progressDialog.update(int((100 / float(len(items))) * i), str(header2) + str(items[i]['label']))
try:
if control.abortRequested: return sys.exit()
url = self.sourcesResolve(items[i])
if u == None: u = url
if not url == None: break
except:
pass
try: progressDialog.close()
except: pass
return u
def errorForSources(self):
control.infoDialog("Keine Streams verfügbar oder ausgewählt", sound=False, icon='INFO')
def getTitle(self, title):
title = utils.normalize(title)
return title
def getConstants(self):
self.itemsProperty = '%s.container.items' % control.Addon.getAddonInfo('id')
self.metaProperty = '%s.container.meta' % control.Addon.getAddonInfo('id')
from scrapers import sources
self.sourceDict = sources()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment