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:
@@ -216,12 +216,14 @@ def downloadbest(video_urls, title, continuar=False):
|
||||
return -2
|
||||
|
||||
|
||||
def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False, resumir=True):
|
||||
def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False, resumir=True, header=''):
|
||||
logger.info("url= " + url)
|
||||
logger.info("filename= " + nombrefichero)
|
||||
|
||||
if headers is None:
|
||||
headers = []
|
||||
if not header:
|
||||
header = "plugin"
|
||||
|
||||
progreso = None
|
||||
|
||||
@@ -269,7 +271,7 @@ def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False
|
||||
|
||||
# Create the progress dialog
|
||||
if not silent:
|
||||
progreso = platformtools.dialog_progress("plugin", "Downloading...", url, nombrefichero)
|
||||
progreso = platformtools.dialog_progress(header, "Downloading...", url, nombrefichero)
|
||||
|
||||
# If the platform does not return a valid dialog box, it assumes silent mode
|
||||
if progreso is None:
|
||||
|
||||
+21
-9
@@ -6,6 +6,8 @@
|
||||
|
||||
from __future__ import division
|
||||
# from builtins import str
|
||||
import io
|
||||
|
||||
from future.builtins import range
|
||||
from past.utils import old_div
|
||||
import sys
|
||||
@@ -43,6 +45,11 @@ if os.name == "nt":
|
||||
else:
|
||||
fs_encoding = "utf8"
|
||||
|
||||
# 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
|
||||
fileIo = platformtools.xbmc.getCondVisibility('system.platform.linux') and platformtools.xbmc.getCondVisibility('system.platform.android')
|
||||
|
||||
|
||||
def validate_path(path):
|
||||
@@ -142,19 +149,20 @@ def read(path, linea_inicio=0, total_lineas=None, whence=0, silent=False, vfs=Tr
|
||||
total_lineas = None
|
||||
if xbmc_vfs and vfs:
|
||||
if not exists(path): return False
|
||||
f = xbmcvfs.File(path, "rb")
|
||||
f = xbmcvfs.File(path, "r")
|
||||
data = f.read()
|
||||
|
||||
if total_lineas == None:
|
||||
total_lineas = 9999999999
|
||||
if linea_inicio > 0:
|
||||
if not isinstance(whence, int):
|
||||
try:
|
||||
whence = int(whence)
|
||||
except:
|
||||
return False
|
||||
f.seek(linea_inicio, whence)
|
||||
logger.debug('POSITION of beginning of reading,, tell(): %s' % f.seek(0, 1))
|
||||
if total_lineas == None:
|
||||
total_lineas = 0
|
||||
data = f.read(total_lineas)
|
||||
return "".join(data)
|
||||
data = '\n'.join(data.split('\n')[linea_inicio:total_lineas])
|
||||
|
||||
return data
|
||||
elif path.lower().startswith("smb://"):
|
||||
f = samba.smb_open(path, "rb")
|
||||
else:
|
||||
@@ -179,7 +187,7 @@ def read(path, linea_inicio=0, total_lineas=None, whence=0, silent=False, vfs=Tr
|
||||
return unicode(b"".join(data))
|
||||
|
||||
|
||||
def write(path, data, mode="wb", silent=False, vfs=True):
|
||||
def write(path, data, mode="w", silent=False, vfs=True):
|
||||
"""
|
||||
Save the data to a file
|
||||
@param path: file path to save
|
||||
@@ -233,7 +241,11 @@ def file_open(path, mode="r", silent=False, vfs=True):
|
||||
elif path.lower().startswith("smb://"):
|
||||
return samba.smb_open(path, mode)
|
||||
else:
|
||||
return open(path, mode)
|
||||
if fileIo:
|
||||
return io.FileIO(path, mode)
|
||||
else:
|
||||
# return io.open(path, mode, decode='utf-8')
|
||||
return open(path, mode)
|
||||
except:
|
||||
logger.error("ERROR when opening file: %s, %s" % (path, mode))
|
||||
if not silent:
|
||||
|
||||
+13
-12
@@ -56,7 +56,7 @@ HTTPTOOLS_DEFAULT_RANDOM_HEADERS = False
|
||||
# with open(CF_LIST_PATH, "rb") as CF_File:
|
||||
# CF_LIST = CF_File.read().splitlines()
|
||||
|
||||
FORCE_CLOUDSCRAPER_LIST = []
|
||||
FORCE_CLOUDSCRAPER_LIST = ['akvideo.stream']
|
||||
|
||||
def get_user_agent():
|
||||
# Returns the global user agent to be used when necessary for the url.
|
||||
@@ -256,7 +256,7 @@ def downloadpage(url, **opt):
|
||||
|
||||
Parameter Type Description
|
||||
-------------------------------------------------- -------------------------------------------------- ------------
|
||||
HTTPResponse.sucess: bool True: Request successful | False: Error when making the request
|
||||
HTTPResponse.success: bool True: Request successful | False: Error when making the request
|
||||
HTTPResponse.code: int Server response code or error code if an error occurs
|
||||
HTTPResponse.error: str Description of the error in case of an error
|
||||
HTTPResponse.headers: dict Dictionary with server response headers
|
||||
@@ -270,7 +270,7 @@ def downloadpage(url, **opt):
|
||||
# global CF_LIST
|
||||
CF = False
|
||||
|
||||
if domain in FORCE_CLOUDSCRAPER_LIST:
|
||||
if domain in FORCE_CLOUDSCRAPER_LIST or opt.get('cf', False):
|
||||
from lib import cloudscraper
|
||||
session = cloudscraper.create_scraper()
|
||||
CF = True
|
||||
@@ -278,10 +278,10 @@ def downloadpage(url, **opt):
|
||||
from lib import requests
|
||||
session = requests.session()
|
||||
|
||||
# if domain in CF_LIST or opt.get('CF', False):
|
||||
if opt.get('CF', False):
|
||||
url = 'https://web.archive.org/save/' + url
|
||||
CF = True
|
||||
# if domain in CF_LIST or opt.get('CF', False):
|
||||
if opt.get('CF', False):
|
||||
url = 'https://web.archive.org/save/' + url
|
||||
CF = True
|
||||
|
||||
if config.get_setting('resolver_dns') and not opt.get('use_requests', False):
|
||||
from specials import resolverdns
|
||||
@@ -380,9 +380,10 @@ def downloadpage(url, **opt):
|
||||
req = requests.Response()
|
||||
if not opt.get('ignore_response_code', False) and not proxy_data.get('stat', ''):
|
||||
response['data'] = ''
|
||||
response['sucess'] = False
|
||||
response['success'] = False
|
||||
info_dict.append(('Success', 'False'))
|
||||
response['code'] = str(e)
|
||||
import traceback
|
||||
response['code'] = traceback.format_exc()
|
||||
info_dict.append(('Response code', str(e)))
|
||||
info_dict.append(('Finished in', time.time() - inicio))
|
||||
if not opt.get('alfa_s', False):
|
||||
@@ -393,7 +394,7 @@ def downloadpage(url, **opt):
|
||||
|
||||
else:
|
||||
response['data'] = ''
|
||||
response['sucess'] = False
|
||||
response['success'] = False
|
||||
response['code'] = ''
|
||||
return type('HTTPResponse', (), response)
|
||||
|
||||
@@ -476,10 +477,10 @@ def fill_fields_post(info_dict, req, response, req_headers, inicio):
|
||||
|
||||
if response['code'] == 200:
|
||||
info_dict.append(('Success', 'True'))
|
||||
response['sucess'] = True
|
||||
response['success'] = True
|
||||
else:
|
||||
info_dict.append(('Success', 'False'))
|
||||
response['sucess'] = False
|
||||
response['success'] = False
|
||||
|
||||
info_dict.append(('Response data length', len(response['data'])))
|
||||
|
||||
|
||||
+7
-5
@@ -352,7 +352,7 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t
|
||||
quality=quality,
|
||||
url=scraped["url"],
|
||||
infoLabels=infolabels,
|
||||
thumbnail=item.thumbnail if function == 'episodios' or not scraped["thumb"] else scraped["thumb"],
|
||||
thumbnail=item.thumbnail if not scraped["thumb"] else scraped["thumb"],
|
||||
args=item.args,
|
||||
contentSerieName= title if 'movie' not in [contentType] and function != 'episodios' else item.contentSerieName,
|
||||
contentTitle= title if 'movie' in [contentType] and function == 'peliculas' else item.contentTitle,
|
||||
@@ -429,6 +429,7 @@ def scrape(func):
|
||||
typeContentDict = args['typeContentDict'] if 'typeContentDict' in args else {}
|
||||
debug = args['debug'] if 'debug' in args else False
|
||||
debugBlock = args['debugBlock'] if 'debugBlock' in args else False
|
||||
disabletmdb = args['disabletmdb'] if 'disabletmdb' in args else False
|
||||
if 'pagination' in args and inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: pagination = args['pagination'] if args['pagination'] else 20
|
||||
else: pagination = ''
|
||||
lang = args['deflang'] if 'deflang' in args else ''
|
||||
@@ -506,7 +507,7 @@ def scrape(func):
|
||||
page=pag + 1,
|
||||
thumbnail=thumb()))
|
||||
|
||||
if action != 'play' and function != 'episodios' and 'patronMenu' not in args and item.contentType in ['movie', 'tvshow', 'episode']:
|
||||
if action != 'play' and function != 'episodios' and 'patronMenu' not in args and item.contentType in ['movie', 'tvshow', 'episode'] and not disabletmdb:
|
||||
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
|
||||
|
||||
if anime:
|
||||
@@ -1095,6 +1096,7 @@ def videolibrary(itemlist, item, typography='', function_level=1, function=''):
|
||||
contentSerieName=contentSerieName,
|
||||
url=item.url,
|
||||
action=action,
|
||||
from_action=item.action,
|
||||
extra=extra,
|
||||
path=item.path,
|
||||
thumbnail=get_thumb('add_to_videolibrary.png')
|
||||
@@ -1334,9 +1336,9 @@ def addQualityTag(item, itemlist, data, patron):
|
||||
else:
|
||||
log('nessun tag qualità trovato')
|
||||
|
||||
def get_jwplayer_mediaurl(data, srvName):
|
||||
def get_jwplayer_mediaurl(data, srvName, onlyHttp=False):
|
||||
video_urls = []
|
||||
block = scrapertools.find_single_match(data, r'sources: \[([^\]]+)\]')
|
||||
block = scrapertools.find_single_match(data, r'sources:\s*\[([^\]]+)\]')
|
||||
if 'file:' in block:
|
||||
sources = scrapertools.find_multiple_matches(block, r'file:\s*"([^"]+)"(?:,label:\s*"([^"]+)")?')
|
||||
elif 'src:' in block:
|
||||
@@ -1346,7 +1348,7 @@ def get_jwplayer_mediaurl(data, srvName):
|
||||
for url, quality in sources:
|
||||
quality = 'auto' if not quality else quality
|
||||
if url.split('.')[-1] != 'mpd':
|
||||
video_urls.append(['.' + url.split('.')[-1] + ' [' + quality + '] [' + srvName + ']', url])
|
||||
video_urls.append(['.' + url.split('.')[-1] + ' [' + quality + '] [' + srvName + ']', url if not onlyHttp else url.replace('https://', 'http://')])
|
||||
|
||||
video_urls.sort(key=lambda x: x[0].split()[1])
|
||||
return video_urls
|
||||
+95
-24
@@ -435,7 +435,9 @@ def save_tvshow(item, episodelist, silent=False):
|
||||
logger.debug("NOT FOUND contentSerieName or code")
|
||||
return 0, 0, -1, path # Salimos sin guardar
|
||||
|
||||
contentTypeBackup = item.contentType # Fix errors in some channels
|
||||
scraper_return = scraper.find_and_set_infoLabels(item)
|
||||
item.contentType = contentTypeBackup # Fix errors in some channels
|
||||
# At this point we can have:
|
||||
# scraper_return = True: An item with infoLabels with the updated information of the series
|
||||
# scraper_return = False: An item without movie information (it has been canceled in the window)
|
||||
@@ -574,19 +576,63 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
|
||||
|
||||
# process local episodes
|
||||
local_episodes_path = ''
|
||||
local_episodelist = []
|
||||
update = False
|
||||
nfo_path = filetools.join(path, "tvshow.nfo")
|
||||
head_nfo, item_nfo = read_nfo(nfo_path)
|
||||
|
||||
if item_nfo.update_last:
|
||||
local_episodes_path = item_nfo.local_episodes_path
|
||||
elif config.get_setting("local_episodes", "videolibrary"):
|
||||
done, local_episodes_path = config_local_episodes_path(path, serie.show)
|
||||
done, local_episodes_path = config_local_episodes_path(path, serie)
|
||||
if done < 0:
|
||||
logger.info("An issue has occurred while configuring local episodes, going out without creating strm")
|
||||
return 0, 0, done
|
||||
item_nfo.local_episodes_path = local_episodes_path
|
||||
filetools.write(nfo_path, head_nfo + item_nfo.tojson())
|
||||
|
||||
if local_episodes_path:
|
||||
process_local_episodes(local_episodes_path, path)
|
||||
from platformcode.xbmc_videolibrary import check_db, clean
|
||||
# check if the local episodes are in the Kodi video library
|
||||
if check_db(local_episodes_path):
|
||||
local_episodelist += get_local_content(local_episodes_path)
|
||||
clean_list = []
|
||||
for f in filetools.listdir(path):
|
||||
match = scrapertools.find_single_match(f, r'[S]?(\d+)(?:x|_|\.)?[E]?(\d+)')
|
||||
if match:
|
||||
ep = '%dx%02d' % (int(match[0]), int(match[1]))
|
||||
if ep in local_episodelist:
|
||||
del_file = filetools.join(path, f)
|
||||
filetools.remove(del_file)
|
||||
if f.endswith('strm'):
|
||||
sep = '\\' if '\\' in path else '/'
|
||||
clean_path = path[:-len(sep)] if path.endswith(sep) else path
|
||||
clean_path = '%/' + clean_path.split(sep)[-1] + '/' + f
|
||||
clean_list.append(clean_path)
|
||||
clean_list.append(clean_path.replace('/','\\'))
|
||||
|
||||
if clean_list:
|
||||
clean(clean_list)
|
||||
update = True
|
||||
|
||||
if item_nfo.local_episodes_list:
|
||||
difference = [x for x in item_nfo.local_episodes_list if (x not in local_episodelist)]
|
||||
if len(difference) > 0:
|
||||
clean_list = []
|
||||
for f in difference:
|
||||
sep = '\\' if '\\' in local_episodes_path else '/'
|
||||
clean_path = local_episodes_path[:-len(sep)] if local_episodes_path.endswith(sep) else local_episodes_path
|
||||
clean_path = '%/' + clean_path.split(sep)[-1] + '/%' + f.replace('x','%') + '%'
|
||||
clean_list.append(clean_path)
|
||||
clean_list.append(clean_path.replace('/','\\'))
|
||||
clean(clean_list)
|
||||
update = True
|
||||
|
||||
item_nfo.local_episodes_list = sorted(local_episodelist)
|
||||
filetools.write(nfo_path, head_nfo + item_nfo.tojson())
|
||||
# the local episodes are not in the Kodi video library
|
||||
else:
|
||||
process_local_episodes(local_episodes_path, path)
|
||||
|
||||
insertados = 0
|
||||
sobreescritos = 0
|
||||
@@ -667,12 +713,13 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
|
||||
logger.info("There is no episode list, we go out without creating strm")
|
||||
return 0, 0, 0
|
||||
|
||||
local_episodelist += get_local_content(path)
|
||||
|
||||
# fix float because division is done poorly in python 2.x
|
||||
try:
|
||||
t = float(100) / len(new_episodelist)
|
||||
except:
|
||||
t = 0
|
||||
|
||||
for i, e in enumerate(scraper.sort_episode_list(new_episodelist)):
|
||||
if not silent:
|
||||
p_dialog.update(int(math.ceil((i + 1) * t)), config.get_localized_string(60064), e.title)
|
||||
@@ -694,6 +741,10 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
|
||||
nfo_path = filetools.join(path, "%s.nfo" % season_episode)
|
||||
json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower())
|
||||
|
||||
if season_episode in local_episodelist:
|
||||
logger.info('Skipped: Serie ' + serie.contentSerieName + ' ' + season_episode + ' available as local content')
|
||||
continue
|
||||
|
||||
# check if the episode has been downloaded
|
||||
if filetools.join(path, "%s [downloads].json" % season_episode) in ficheros:
|
||||
logger.info('INFO: "%s" episode %s has been downloaded, skipping it' % (serie.contentSerieName, season_episode))
|
||||
@@ -817,14 +868,17 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
|
||||
filetools.write(tvshow_path, head_nfo + tvshow_item.tojson())
|
||||
except:
|
||||
logger.error("Error updating tvshow.nfo")
|
||||
logger.error("Unable to save %s emergency urls in the video library" % tvshow_item.contentSerieName)
|
||||
logger.error("Unable to save %s emergency urls in the video library" % serie.contentSerieName)
|
||||
logger.error(traceback.format_exc())
|
||||
fallidos = -1
|
||||
else:
|
||||
# ... if it was correct we update the Kodi video library
|
||||
if config.is_xbmc() and config.get_setting("videolibrary_kodi") and not silent:
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update()
|
||||
update = True
|
||||
|
||||
if update:
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update()
|
||||
|
||||
if fallidos == len(episodelist):
|
||||
fallidos = -1
|
||||
@@ -833,23 +887,25 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
|
||||
return insertados, sobreescritos, fallidos
|
||||
|
||||
|
||||
def config_local_episodes_path(path, title, silent=False):
|
||||
logger.info()
|
||||
|
||||
local_episodes_path = ''
|
||||
if not silent:
|
||||
silent = platformtools.dialog_yesno(config.get_localized_string(30131), config.get_localized_string(80044) % title)
|
||||
if silent:
|
||||
if config.is_xbmc() and not config.get_setting("videolibrary_kodi"):
|
||||
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(80043))
|
||||
local_episodes_path = platformtools.dialog_browse(0, config.get_localized_string(80046))
|
||||
if local_episodes_path == '':
|
||||
logger.info("User has canceled the dialog")
|
||||
return -2, local_episodes_path
|
||||
elif path in local_episodes_path:
|
||||
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(80045))
|
||||
logger.info("Selected folder is the same of the TV show one")
|
||||
return -2, local_episodes_path
|
||||
def config_local_episodes_path(path, item, silent=False):
|
||||
logger.info(item)
|
||||
from platformcode.xbmc_videolibrary import search_local_path
|
||||
local_episodes_path=search_local_path(item)
|
||||
if not local_episodes_path:
|
||||
title = item.contentSerieName if item.contentSerieName else item.show
|
||||
if not silent:
|
||||
silent = platformtools.dialog_yesno(config.get_localized_string(30131), config.get_localized_string(80044) % title)
|
||||
if silent:
|
||||
if config.is_xbmc() and not config.get_setting("videolibrary_kodi"):
|
||||
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(80043))
|
||||
local_episodes_path = platformtools.dialog_browse(0, config.get_localized_string(80046))
|
||||
if local_episodes_path == '':
|
||||
logger.info("User has canceled the dialog")
|
||||
return -2, local_episodes_path
|
||||
elif path in local_episodes_path:
|
||||
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(80045))
|
||||
logger.info("Selected folder is the same of the TV show one")
|
||||
return -2, local_episodes_path
|
||||
|
||||
if local_episodes_path:
|
||||
# import artwork
|
||||
@@ -901,6 +957,21 @@ def process_local_episodes(local_episodes_path, path):
|
||||
filetools.write(nfo_path, head_nfo + item_nfo.tojson())
|
||||
|
||||
|
||||
def get_local_content(path):
|
||||
logger.info()
|
||||
|
||||
local_episodelist = []
|
||||
for root, folders, files in filetools.walk(path):
|
||||
for file in files:
|
||||
season_episode = scrapertools.get_season_and_episode(file)
|
||||
if season_episode == "" or filetools.exists(filetools.join(path, "%s.strm" % season_episode)):
|
||||
continue
|
||||
local_episodelist.append(season_episode)
|
||||
local_episodelist = sorted(set(local_episodelist))
|
||||
|
||||
return local_episodelist
|
||||
|
||||
|
||||
def add_movie(item):
|
||||
"""
|
||||
Keep a movie at the movie library. The movie can be a link within a channel or a previously downloaded video.
|
||||
@@ -969,7 +1040,7 @@ def add_tvshow(item, channel=None):
|
||||
|
||||
else:
|
||||
# This mark is because the item has something else apart in the "extra" attribute
|
||||
item.action = item.extra if item.extra else item.action
|
||||
# item.action = item.extra if item.extra else item.action
|
||||
if isinstance(item.extra, str) and "###" in item.extra:
|
||||
item.action = item.extra.split("###")[0]
|
||||
item.extra = item.extra.split("###")[1]
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ class ziptools(object):
|
||||
if not dir.endswith(':') and not filetools.exists(dir):
|
||||
filetools.mkdir(dir)
|
||||
|
||||
zf = zipfile.ZipFile(file)
|
||||
zf = zipfile.ZipFile(filetools.file_open(file, vfs=False))
|
||||
if not folder_to_extract:
|
||||
self._createstructure(file, dir)
|
||||
num_files = len(zf.namelist())
|
||||
@@ -93,7 +93,7 @@ class ziptools(object):
|
||||
filetools.mkdir(curdir)
|
||||
|
||||
def _listdirs(self, file):
|
||||
zf = zipfile.ZipFile(file)
|
||||
zf = zipfile.ZipFile(filetools.file_open(file, vfs=False))
|
||||
dirs = []
|
||||
for name in zf.namelist():
|
||||
if name.endswith('/'):
|
||||
@@ -104,7 +104,7 @@ class ziptools(object):
|
||||
|
||||
def zip(self, dir, file):
|
||||
import os
|
||||
zf = zipfile.ZipFile(file, "w", zipfile.ZIP_DEFLATED)
|
||||
zf = zipfile.ZipFile(filetools.file_open(file, "w", vfs=False), "w", zipfile.ZIP_DEFLATED)
|
||||
abs_src = os.path.abspath(dir)
|
||||
for dirname, subdirs, files in os.walk(dir):
|
||||
for filename in files:
|
||||
|
||||
Reference in New Issue
Block a user