KoD 1.3
- Aggiunti i canali Mediaset Play e La 7. - Riscritto Animeunity. - Le stagioni concluse vengono ora escluse dall'aggiornamento della videoteca. - Ora è possibile aggiornare gli episodi di Kod dal menu contestuale della Libreria di Kod (se non gestite da Kod verranno cercate) - Fix Adesso in Onda su ATV - Fix Vari
This commit is contained in:
@@ -52,7 +52,7 @@ def dialog_notification(heading, message, icon=3, time=5000, sound=True):
|
||||
dialog_ok(heading, message)
|
||||
|
||||
|
||||
def dialog_yesno(heading, line1, line2="", line3="", nolabel="No", yeslabel="Si", autoclose=0, customlabel=None):
|
||||
def dialog_yesno(heading, line1, line2="", line3="", nolabel=config.get_localized_string(70170), yeslabel=config.get_localized_string(30022), autoclose=0, customlabel=None):
|
||||
# customlabel only on kodi 19
|
||||
dialog = xbmcgui.Dialog()
|
||||
if config.get_platform() == 'kodi-matrix':
|
||||
@@ -109,9 +109,9 @@ def dialog_textviewer(heading, text): # available from kodi 16
|
||||
return xbmcgui.Dialog().textviewer(heading, text)
|
||||
|
||||
|
||||
def dialog_browse(_type, heading, default=""):
|
||||
def dialog_browse(_type, heading, shares="files", mask="", useThumbs=False, treatAsFolder=False, defaultt="", enableMultiple=False):
|
||||
dialog = xbmcgui.Dialog()
|
||||
d = dialog.browse(_type, heading, 'files')
|
||||
d = dialog.browse(_type, heading, shares, mask, useThumbs, treatAsFolder, defaultt, enableMultiple)
|
||||
return d
|
||||
|
||||
|
||||
@@ -179,13 +179,13 @@ def render_items(itemlist, parent_item):
|
||||
|
||||
# if cloudflare and cloudscraper is used, cookies are needed to display images taken from site
|
||||
# before checking domain (time consuming), checking if tmdb failed (so, images scraped from website are used)
|
||||
if item.action in ['findvideos'] and not item.infoLabels['tmdb_id']:
|
||||
# if item.action in ['findvideos'] and not item.infoLabels['tmdb_id']:
|
||||
# faster but ugly way of checking
|
||||
for d in httptools.FORCE_CLOUDSCRAPER_LIST:
|
||||
if d + '/' in item.url:
|
||||
item.thumbnail = httptools.get_url_headers(item.thumbnail)
|
||||
item.fanart = httptools.get_url_headers(item.fanart)
|
||||
break
|
||||
# for d in httptools.FORCE_CLOUDSCRAPER_LIST:
|
||||
# if d + '/' in item.url:
|
||||
# item.thumbnail = httptools.get_url_headers(item.thumbnail)
|
||||
# item.fanart = httptools.get_url_headers(item.fanart)
|
||||
# break
|
||||
|
||||
icon_image = "DefaultFolder.png" if item.folder else "DefaultVideo.png"
|
||||
listitem = xbmcgui.ListItem(item.title)
|
||||
@@ -248,7 +248,7 @@ def getCurrentView(item=None, parent_item=None):
|
||||
elif (item.contentType in ['movie'] and parent_item.action in parent_actions) \
|
||||
or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']) \
|
||||
or (parent_item.channel in ['favorites'] and parent_item.action in ['mainlist']) \
|
||||
or parent_item.action in ['now_on_tv', 'now_on_misc', 'now_on_misc_film', 'mostrar_perfil', 'live']:
|
||||
or parent_item.action in ['now_on_tv', 'now_on_misc', 'now_on_misc_film', 'mostrar_perfil', 'live', 'replay', 'news']:
|
||||
return 'movie', 'movies'
|
||||
|
||||
elif (item.contentType in ['tvshow'] and parent_item.action in parent_actions) \
|
||||
@@ -505,7 +505,7 @@ def is_playing():
|
||||
|
||||
def play_video(item, strm=False, force_direct=False, autoplay=False):
|
||||
logger.info()
|
||||
# logger.debug(item.tostring('\n'))
|
||||
logger.debug(item.tostring('\n'))
|
||||
if item.channel == 'downloads':
|
||||
logger.info("Play local video: %s [%s]" % (item.title, item.url))
|
||||
xlistitem = xbmcgui.ListItem(path=item.url)
|
||||
@@ -545,9 +545,15 @@ def play_video(item, strm=False, force_direct=False, autoplay=False):
|
||||
# if it is a video in mpd format, the listitem is configured to play it ith the inpustreamaddon addon implemented in Kodi 17
|
||||
# from core.support import dbg;dbg()
|
||||
if mpd:
|
||||
if not os.path.exists(os.path.join(xbmc.translatePath('special://home/addons/'),'inputstream.adaptive')): install_inputstream()
|
||||
if not install_inputstream():
|
||||
return
|
||||
xlistitem.setProperty('inputstreamaddon', 'inputstream.adaptive')
|
||||
xlistitem.setProperty('inputstream.adaptive.manifest_type', 'mpd')
|
||||
if item.drm and item.license:
|
||||
install_widevine()
|
||||
xlistitem.setProperty("inputstream.adaptive.license_type", item.drm)
|
||||
xlistitem.setProperty("inputstream.adaptive.license_key", item.license)
|
||||
xlistitem.setMimeType('application/dash+xml')
|
||||
|
||||
if force_direct: item.play_from = 'window'
|
||||
|
||||
@@ -1067,17 +1073,201 @@ def resume_playback(item, return_played_time=False):
|
||||
item.nfo = item.strm_path = ""
|
||||
return item, None, None, None
|
||||
|
||||
|
||||
##### INPUTSTREM #####
|
||||
|
||||
def install_inputstream():
|
||||
from xbmcaddon import Addon
|
||||
try:
|
||||
# See if there's an installed repo that has it
|
||||
xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', wait=True)
|
||||
if not os.path.exists(os.path.join(xbmc.translatePath('special://home/addons/'),'inputstream.adaptive')) and not os.path.exists(os.path.join(xbmc.translatePath('special://xbmcbinaddons/'),'inputstream.adaptive')):
|
||||
try:
|
||||
# See if there's an installed repo that has it
|
||||
xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', wait=True)
|
||||
|
||||
# Check if InputStream add-on exists!
|
||||
Addon('inputstream.adaptive')
|
||||
# Check if InputStream add-on exists!
|
||||
Addon('inputstream.adaptive')
|
||||
|
||||
logger.info('InputStream add-on installed from repo.')
|
||||
return True
|
||||
except RuntimeError:
|
||||
logger.info('InputStream add-on not installed.')
|
||||
return False
|
||||
logger.info('InputStream add-on installed from repo.')
|
||||
except RuntimeError:
|
||||
logger.info('InputStream add-on not installed.')
|
||||
dialog_ok(config.get_localized_string(20000), config.get_localized_string(30126))
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
Addon('inputstream.adaptive')
|
||||
logger.info('InputStream add-on is installed and enabled')
|
||||
except:
|
||||
logger.info('enabling InputStream add-on')
|
||||
xbmc.executebuiltin('UpdateLocalAddons')
|
||||
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "inputstream.adaptive", "enabled": true }}')
|
||||
return True
|
||||
|
||||
|
||||
def install_widevine():
|
||||
platform = get_platform()
|
||||
if platform['os'] != 'android':
|
||||
from core.httptools import downloadpage
|
||||
from xbmcaddon import Addon
|
||||
from core import jsontools
|
||||
from distutils.version import LooseVersion
|
||||
path = xbmc.translatePath(Addon('inputstream.adaptive').getSetting('DECRYPTERPATH'))
|
||||
|
||||
# if Widevine CDM is not installed
|
||||
if not os.path.exists(path):
|
||||
select = dialog_yesno('Widevine CDM', config.get_localized_string(70808))
|
||||
if select > 0:
|
||||
if not 'arm' in platform['arch']:
|
||||
last_version = downloadpage('https://dl.google.com/widevine-cdm/versions.txt').data.split()[-1]
|
||||
download_widevine(last_version, platform, path)
|
||||
else:
|
||||
json = downloadpage('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json').data
|
||||
devices = jsontools.load(json)
|
||||
download_chromeos_image(devices, platform, path)
|
||||
|
||||
# if Widevine CDM is outdated
|
||||
elif platform['os'] != 'android':
|
||||
if not 'arm' in platform['arch']:
|
||||
last_version = downloadpage('https://dl.google.com/widevine-cdm/versions.txt').data.split()[-1]
|
||||
current_version = jsontools.load(open(os.path.join(path, 'manifest.json')).read())['version']
|
||||
if LooseVersion(last_version) > LooseVersion(current_version):
|
||||
select = dialog_yesno(config.get_localized_string(70810),config.get_localized_string(70809))
|
||||
if select > 0: download_widevine(last_version, platform, path)
|
||||
else:
|
||||
devices = jsontools.load(downloadpage('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json').data)
|
||||
current_version = jsontools.load(open(os.path.join(path, 'config.json')).read())['version']
|
||||
last_version = best_chromeos_image(devices)['version']
|
||||
if LooseVersion(last_version) > LooseVersion(current_version):
|
||||
select = dialog_yesno(config.get_localized_string(70810),config.get_localized_string(70809))
|
||||
if select > 0:download_chromeos_image(devices, platform, path)
|
||||
|
||||
|
||||
def download_widevine(version, platform, path):
|
||||
# for x86 architectures
|
||||
from zipfile import ZipFile
|
||||
from xbmcaddon import Addon
|
||||
from core import downloadtools
|
||||
archiveName = 'https://dl.google.com/widevine-cdm/' + version + '-' + platform['os'] + '-' + platform['arch'] + '.zip'
|
||||
fileName = config.get_temp_file('widevine.zip')
|
||||
if not os.path.exists(archiveName):
|
||||
if not os.path.exists(fileName):
|
||||
downloadtools.downloadfile(archiveName, fileName, header='Download Widevine CDM')
|
||||
zip_obj = ZipFile(fileName)
|
||||
for filename in zip_obj.namelist():
|
||||
zip_obj.extract(filename, path)
|
||||
zip_obj.close()
|
||||
os.remove(fileName)
|
||||
|
||||
|
||||
def download_chromeos_image(devices, platform, path):
|
||||
# for arm architectures
|
||||
from core import downloadtools
|
||||
from zipfile import ZipFile
|
||||
from core import jsontools
|
||||
best = best_chromeos_image(devices)
|
||||
archiveName = best['url']
|
||||
version = best['version']
|
||||
|
||||
fileName = config.get_temp_file(archiveName.split('/')[-1])
|
||||
if not os.path.exists(fileName):
|
||||
downloadtools.downloadfile(archiveName, fileName, header='Download Widevine CDM')
|
||||
from lib.arm_chromeos import ChromeOSImage
|
||||
ChromeOSImage(fileName).extract_file(
|
||||
filename='libwidevinecdm.so',
|
||||
extract_path=os.path.join(path),
|
||||
progress=dialog_progress(config.get_localized_string(70811),config.get_localized_string(70812)))
|
||||
recovery_file = os.path.join(path, os.path.basename('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json'))
|
||||
config_file = os.path.join(path, 'config.json')
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
with open(recovery_file, 'w') as reco_file:
|
||||
reco_file.write(jsontools.dump(devices, indent=4))
|
||||
reco_file.close()
|
||||
with open(config_file, 'w') as conf_file:
|
||||
conf_file.write(jsontools.dump(best))
|
||||
conf_file.close()
|
||||
os.remove(fileName)
|
||||
|
||||
def best_chromeos_image(devices):
|
||||
best = None
|
||||
for device in devices:
|
||||
# Select ARM hardware only
|
||||
for arm_hwid in ['BIG','BLAZE','BOB','DRUWL','DUMO','ELM','EXPRESSO','FIEVEL','HANA','JAQ','JERRY','KEVIN','KITTY','MICKEY','MIGHTY','MINNIE','PHASER','PHASER360','PI','PIT','RELM','SCARLET','SKATE','SNOW','SPEEDY','SPRING','TIGER']:
|
||||
if arm_hwid in device['hwidmatch']:
|
||||
hwid = arm_hwid
|
||||
break # We found an ARM device, rejoice !
|
||||
else:
|
||||
continue # Not ARM, skip this device
|
||||
|
||||
device['hwid'] = hwid
|
||||
|
||||
# Select the first ARM device
|
||||
if best is None:
|
||||
best = device
|
||||
continue # Go to the next device
|
||||
|
||||
# Skip identical hwid
|
||||
if hwid == best['hwid']:
|
||||
continue
|
||||
|
||||
# Select the newest version
|
||||
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module,useless-suppression
|
||||
if LooseVersion(device['version']) > LooseVersion(best['version']):
|
||||
logger.info('%s (%s) is newer than %s (%s)' % (device['hwid'], device['version'], best['hwid'], best['version']))
|
||||
best = device
|
||||
|
||||
# Select the smallest image (disk space requirement)
|
||||
elif LooseVersion(device['version']) == LooseVersion(best['version']):
|
||||
if int(device['filesize']) + int(device['zipfilesize']) < int(best['filesize']) + int(best['zipfilesize']):
|
||||
logger.info('%s (%d) is smaller than %s (%d)' % (device['hwid'], int(device['filesize']) + int(device['zipfilesize']), best['hwid'], int(best['filesize']) + int(best['zipfilesize'])))
|
||||
best = device
|
||||
return best
|
||||
|
||||
def get_platform():
|
||||
import 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 "ia32",
|
||||
"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"] = "arm64"
|
||||
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"] = "win"
|
||||
ret["arch"] = "x64"
|
||||
elif xbmc.getCondVisibility("system.platform.windows"):
|
||||
ret["os"] = "win"
|
||||
if platform.machine().endswith('64'):
|
||||
ret["arch"] = "x64"
|
||||
elif xbmc.getCondVisibility("system.platform.osx"):
|
||||
ret["os"] = "mac"
|
||||
ret["arch"] = "x64"
|
||||
elif xbmc.getCondVisibility("system.platform.ios"):
|
||||
ret["os"] = "ios"
|
||||
ret["arch"] = "arm"
|
||||
|
||||
return ret
|
||||
@@ -326,7 +326,7 @@ def updateFromZip(message=config.get_localized_string(80050)):
|
||||
hash = fixZipGetHash(localfilename)
|
||||
logger.info(hash)
|
||||
|
||||
with zipfile.ZipFile(fOpen(localfilename, 'rb')) as zip:
|
||||
with zipfile.ZipFile(filetools.file_open(localfilename, 'rb', vfs=False)) as zip:
|
||||
size = sum([zinfo.file_size for zinfo in zip.filelist])
|
||||
cur_size = 0
|
||||
for member in zip.infolist():
|
||||
@@ -425,7 +425,7 @@ def rename(dir1, dir2):
|
||||
# https://stackoverflow.com/questions/3083235/unzipping-file-results-in-badzipfile-file-is-not-a-zip-file
|
||||
def fixZipGetHash(zipFile):
|
||||
hash = ''
|
||||
with fOpen(zipFile, 'r+b') as f:
|
||||
with filetools.file_open(zipFile, 'r+b', vfs=False) as f:
|
||||
data = f.read()
|
||||
pos = data.find(b'\x50\x4b\x05\x06') # End of central directory signature
|
||||
if pos > 0:
|
||||
@@ -438,17 +438,6 @@ def fixZipGetHash(zipFile):
|
||||
|
||||
return str(hash)
|
||||
|
||||
def fOpen(file, mode = 'r'):
|
||||
# per android è necessario, su kodi 18, usare FileIO
|
||||
# https://forum.kodi.tv/showthread.php?tid=330124
|
||||
# per xbox invece, è necessario usare open perchè _io è rotto :(
|
||||
# https://github.com/jellyfin/jellyfin-kodi/issues/115#issuecomment-538811017
|
||||
if xbmc.getCondVisibility('system.platform.linux') and xbmc.getCondVisibility('system.platform.android'):
|
||||
logger.info('android, uso FileIO per leggere')
|
||||
return io.FileIO(file, mode)
|
||||
else:
|
||||
return io.open(file, mode)
|
||||
|
||||
|
||||
def _pbhook(numblocks, blocksize, filesize, url, dp):
|
||||
try:
|
||||
|
||||
@@ -525,6 +525,21 @@ def search_library_path():
|
||||
return None
|
||||
|
||||
|
||||
def search_local_path(item):
|
||||
ids = [item.infoLabels['imdb_id'], item.infoLabels['tmdb_id'], item.infoLabels['tvdb_id']]
|
||||
for Id in ids:
|
||||
nun_ids, ids = execute_sql_kodi('SELECT idShow FROM tvshow_view WHERE uniqueid_value LIKE "%s"' % Id)
|
||||
if nun_ids >= 1:
|
||||
nun_records, records = execute_sql_kodi('SELECT idPath FROM tvshowlinkpath WHERE idShow LIKE "%s"' % ids[0][0])
|
||||
if nun_records >= 1:
|
||||
for record in records:
|
||||
num_path, path_records = execute_sql_kodi('SELECT strPath FROM path WHERE idPath LIKE "%s"' % record[0])
|
||||
for path in path_records:
|
||||
if config.get_setting('videolibrarypath') not in path[0]:
|
||||
return path[0]
|
||||
return ''
|
||||
|
||||
|
||||
def set_content(content_type, silent=False, custom=False):
|
||||
"""
|
||||
Procedure to auto-configure the kodi video library with the default values
|
||||
@@ -904,7 +919,7 @@ def clean(path_list=[]):
|
||||
if path.startswith("special://"):
|
||||
path = path.replace('/profile/', '/%/').replace('/home/userdata/', '/%/')
|
||||
sep = '/'
|
||||
elif '://' in path:
|
||||
elif '://' in path or path.startswith('/') or path.startswith('%/'):
|
||||
sep = '/'
|
||||
else: sep = os.sep
|
||||
|
||||
@@ -1001,6 +1016,20 @@ def clean(path_list=[]):
|
||||
progress.close()
|
||||
|
||||
|
||||
def check_db(path):
|
||||
if '\\' in path: sep = '\\'
|
||||
else: sep = '/'
|
||||
if path.endswith(sep): path = path[:-len(sep)]
|
||||
ret = False
|
||||
sql_path = '%' + sep + path.split(sep)[-1] + sep + '%'
|
||||
sql = 'SELECT idShow FROM tvshow_view where strPath LIKE "%s"' % sql_path
|
||||
logger.info('sql: ' + sql)
|
||||
nun_records, records = execute_sql_kodi(sql)
|
||||
if records:
|
||||
ret = True
|
||||
return ret
|
||||
|
||||
|
||||
def execute_sql_kodi(sql):
|
||||
"""
|
||||
Run sql query against kodi database
|
||||
|
||||
Reference in New Issue
Block a user