KoD 1.6.1

-Migliorata l'efficacia del riconoscimento dei contenuti in ricerca film/serie
- corretti alcuni bug e fatti alcuni fix per i soliti cambi di struttura
This commit is contained in:
mac12m99
2021-03-09 22:08:09 +01:00
parent f1da5c7a0b
commit fa0fe6e534
29 changed files with 377 additions and 330 deletions

View File

@@ -1,4 +1,4 @@
<addon id="plugin.video.kod" name="Kodi on Demand" version="1.6" provider-name="KoD Team">
<addon id="plugin.video.kod" name="Kodi on Demand" version="1.6.1" provider-name="KoD Team">
<requires>
<!-- <import addon="script.module.libtorrent" optional="true"/> -->
<import addon="metadata.themoviedb.org"/>
@@ -27,10 +27,8 @@
<screenshot>resources/media/themes/ss/2.png</screenshot>
<screenshot>resources/media/themes/ss/3.png</screenshot>
</assets>
<news>- rimosso supporto a TVDB (l'accesso alle API diventerà a pagamento)
- aggiunto canale Discovery+
- aggiunta possibilità di scegliere numerazioni alternative per le serie tv
- migliorie interne di vario tipo (tra cui un migliore riconoscimento dei contenuti nel caso siano scritti male)</news>
<news>-Migliorata l'efficacia del riconoscimento dei contenuti in ricerca film/serie
- corretti alcuni bug e fatti alcuni fix per i soliti cambi di struttura</news>
<description lang="it">Naviga velocemente sul web e guarda i contenuti presenti</description>
<disclaimer>[COLOR red]The owners and submitters to this addon do not host or distribute any of the content displayed by these addons nor do they have any affiliation with the content providers.[/COLOR]
[COLOR yellow]Kodi © is a registered trademark of the XBMC Foundation. We are not connected to or in any other way affiliated with Kodi, Team Kodi, or the XBMC Foundation. Furthermore, any software, addons, or products offered by us will receive no support in official Kodi channels, including the Kodi forums and various social networks.[/COLOR]</disclaimer>

View File

@@ -22,7 +22,7 @@
"eurostreaming": "https://eurostreaming.team",
"filmgratis": "https://www.filmaltadefinizione.me",
"filmigratis": "https://filmigratis.org",
"filmsenzalimiticc": "https://www.filmsenzalimiti01.surf",
"filmsenzalimiticc": "https://www.filmsenzalimiti01.xyz",
"filmstreaming01": "https://filmstreaming01.com",
"guardaserie_stream": "https://guardaserie.yoga",
"guardaseriecam": "https://guardaserie.cam",

View File

@@ -10,14 +10,7 @@ typo = support.typo
session = requests.Session()
host = support.config.get_channel_url()
def getToken():
token = config.get_setting('token', 'discoveryplus', None)
if not token:
token = session.get('https://disco-api.discoveryplus.it/token?realm=dplayit').json()['data']['attributes']['token']
config.set_setting('token', token, 'discoveryplus')
return token
token = getToken()
token = session.get('https://disco-api.discoveryplus.it/token?realm=dplayit').json()['data']['attributes']['token']
api = "https://disco-api.discoveryplus.it"
headers = {'User-Agent': 'Mozilla/50.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0',
@@ -70,7 +63,7 @@ def live(item):
logger.debug()
itemlist =[]
for name, values in liveDict().items():
itemlist.append(item.clone(title=typo(name), fulltitle=name, plot=values['plot'], url=values['url'], id=values['id'], action='play', forcethumb=True, no_return=True))
itemlist.append(item.clone(title=typo(name,'bold'), fulltitle=name, plot=values['plot'], url=values['url'], id=values['id'], action='play', forcethumb=True, no_return=True))
return support.thumb(itemlist, live=True)

View File

@@ -307,7 +307,7 @@ def play(item):
data = support.match(sec_data, patron=r'<video src="([^"]+)').match
break
else:
support.dbg()
# support.dbg()
data = url
return support.servertools.find_video_items(item, data=data)

View File

@@ -88,7 +88,7 @@ def peliculas(item):
patron = r'href="(?P<url>[^"]+)"[^>]+>(?P<title>.+?)(?:\s(?P<year>\d{4})|<)'
patronBlock = r'Lista dei film disponibili in streaming e anche in download\.</p>(?P<block>.*?)<div class="footer_c">'
else:
patron = r'<tr><td><a href="(?P<url>[^"]+)"(?:|.+?)?>(?:&nbsp;&nbsp;)?[ ]?(?P<title>.*?)[ ]?(?P<quality>HD)?[ ]?(?P<year>\d+)?(?: | HD | Streaming | MD(?: iSTANCE)? )?</a>'
patron = r'<tr><td><a href="(?P<url>[^"]+)"(?:|.+?)?>(?:&nbsp;&nbsp;)?[ ]?(?P<title>.*?)[ ]?(?P<quality>HD)?[ ]?(?P<year>\d+)?(?: | HD[^<]*| Streaming[^<]*| MD(?: iSTANCE)? [^<]*)?</a>'
def itemHook(item):
if 'film' in item.url:

View File

@@ -5,17 +5,11 @@
from core import support
import sys
if sys.version_info[0] >= 3: from concurrent import futures
else: from concurrent_py2 import futures
host = support.config.get_channel_url()
headers = [['Referer', host]]
@support.menu
def mainlist(item):
@@ -33,22 +27,10 @@ def search(item, text):
support.info(text)
# item.args='search'
item.text = text
itemlist = []
itlist = []
item.url = item.url + '/?%73=' + text.replace(' ', '+')
try:
# item.url = host + '/lista-serie-tv/'
# item.contentType = 'tvshow'
# itemlist += peliculas(item)
with futures.ThreadPoolExecutor() as executor:
for par in [['/serie-tv/', 'tvshow', ''],['/anime/', 'tvshow', ''], ['/-anime-sub-ita/', 'tvshow', 'sub'], ['/film-animazione/', 'movie', '']]:
item.url = host + par[0]
item.contentType = par[1]
item.args = par[2]
itlist.append(executor.submit(peliculas, item))
for res in futures.as_completed(itlist):
itemlist += res.result()
return itemlist
return peliculas(item)
# Continua la ricerca in caso di errore
except:
import sys
@@ -75,21 +57,26 @@ def newest(categoria):
@support.scrape
def peliculas(item):
search = item.text
# debugBlock = True
# debug = True
# search = item.text
if item.contentType != 'movie': anime = True
action = 'findvideos' if item.contentType == 'movie' else 'episodios'
blacklist = ['-Film Animazione disponibili in attesa di recensione ']
if search:
if item.action == 'search':
pagination = ''
patronBlock = '"lcp_catlist"[^>]+>(?P<block>.*)</ul>'
patron = r'href="(?P<url>[^"]+)" title="(?P<title>[^"]+)"'
#patronBlock = '"lcp_catlist"[^>]+>(?P<block>.*)</ul>'
patronBlock = '<main[^>]+>(?P<block>.*?)</ma'
#patron = r'href="(?P<url>[^"]+)" title="(?P<title>[^"]+)"'
patron = r'<a href="(?P<url>[^"]+)"[^>]*>(?P<title>[^<]+)<[^>]+>[^>]+><div'
elif item.args == 'last':
patronBlock = 'Aggiornamenti</h2>(?P<block>.*)</ul>'
patron = r'<a href="(?P<url>[^"]+)">\s*<img[^>]+src(?:set)?="(?P<thumbnail>[^ ]+)[^>]+>\s*<span[^>]+>(?P<title>[^<]+)'
patron = r'<a href="(?P<url>[^"]+)">\s*<img[^>]+src[set]{0,3}="(?P<thumbnail>[^ ]+)[^>]+>\s*<span[^>]+>(?P<title>[^<]+)'
else:
patronBlock = '<main[^>]+>(?P<block>.*)</main>'
patron = r'<a href="(?P<url>[^"]+)" rel="bookmark">(?P<title>[^<]+)</a>[^>]+>[^>]+>[^>]+><img.*?src="(?P<thumb>[^"]+)".*?<p>(?P<plot>[^<]+)</p>.*?<span class="cat-links">Pubblicato in.*?.*?(?P<type>(?:[Ff]ilm|</artic))[^>]+>'
# patron = r'<a href="(?P<url>[^"]+)" rel="bookmark">(?P<title>[^<]+)</a>[^>]+>[^>]+>[^>]+><img.*?src="(?P<thumb>[^"]+)".*?<p>(?P<plot>[^<]+)</p>.*?<span class="cat-links">Pubblicato in.*?.*?(?P<type>(?:[Ff]ilm|</artic))[^>]+>'
patron = r'<a href="(?P<url>[^"]+)"[^>]+>(?P<title>[^<]+)</a>[^>]+>[^>]+>[^>]+><img.*?src="(?P<thumb>[^"]+)".*?<p>(?P<plot>[^<]+)</p>.*?tag">.*?(?P<type>(?:[Ff]ilm|</art|Serie Tv))'
typeContentDict={'movie':['film']}
typeActionDict={'findvideos':['film']}
patronNext = '<a class="next page-numbers" href="([^"]+)">'

View File

@@ -350,7 +350,7 @@ class Item(object):
def fromurl(self, url):
"""
Generate an item from a text string. The string can be created by the tourl () function or have
        the old format: plugin: //plugin.video.kod/? channel = ... (+ other parameters)
the old format: plugin: //plugin.video.kod/? channel = ... (+ other parameters)
Use: item.fromurl("string")
@param url: url

View File

@@ -66,6 +66,10 @@ otmdb_global = None
from core import db
def clean_cache():
db['tmdb_cache'].clear()
# The function name is the name of the decorator and receives the function that decorates.
def cache_response(fn):
logger.debug()
@@ -180,7 +184,8 @@ def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda=def_lang,
"""
Concurrently, it gets the data of the items included in the item_list.
The API has a limit of 40 requests per IP every 10 '' and that is why the list should not have more than 30 items to ensure the proper functioning of this function.
The API in the past had a limit of 40 requests per IP every 10 '', now there's no limit (https://developers.themoviedb.org/3/getting-started/request-rate-limiting)
If a limit will be re-added uncomment "tmdb_threads" and related code
@param item_list: list of Item objects that represent movies, series or chapters. The infoLabels attribute of each Item object will be modified including the extra localized data.
@type item_list: list
@@ -197,18 +202,18 @@ def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda=def_lang,
return
import threading
threads_num = config.get_setting("tmdb_threads", default=20)
semaforo = threading.Semaphore(threads_num)
# threads_num = config.get_setting("tmdb_threads", default=20)
# semaforo = threading.Semaphore(threads_num)
lock = threading.Lock()
r_list = list()
i = 0
l_hilo = list()
def sub_thread(_item, _i, _seekTmdb):
semaforo.acquire()
# semaforo.acquire()
ret = set_infoLabels_item(_item, _seekTmdb, idioma_busqueda, lock)
# logger.debug(str(ret) + "item: " + _item.tostring())
semaforo.release()
# semaforo.release()
r_list.append((_i, _item, ret))
for item in item_list:
@@ -560,16 +565,14 @@ def select_group(groups, item):
selected = -1
url = 'https://api.themoviedb.org/3/tv/{}?api_key=a1ab8b8669da03637a4b98fa39c39228&language={}'.format(item.infoLabels['tmdb_id'], def_lang)
res = requests.get(url).json()
selections = ['[B]Original[/B] Seasons: {} Episodes: {}'.format(res.get('number_of_seasons',0), res.get('number_of_episodes',0))]
selections = [['Original',res.get('number_of_seasons',0), res.get('number_of_episodes',0), '', item.thumbnail]]
ids = ['original']
for group in groups:
name = '[B]{}[/B] Seasons: {} Episodes: {}'.format(group.get('name',''), group.get('group_count',0), group.get('episode_count',0))
description = group.get('description','')
if description:
name = '{}\n{}'.format(name, description)
# name = '{} Seasons: {} Episodes: {}'.format(group.get('name',''), group.get('group_count',0), group.get('episode_count',0))
# description = group.get('description','')
ID = group.get('id','')
if ID:
selections.append(name)
selections.append([group.get('name',''), group.get('group_count',0), group.get('episode_count',0), group.get('description',''), item.thumbnail])
ids.append(ID)
if selections and ids:
selected = platformtools.dialog_select_group(config.get_localized_string(70831), selections)
@@ -1454,7 +1457,14 @@ class Tmdb(object):
def get_list_episodes(self):
url = 'https://api.themoviedb.org/3/tv/{id}?api_key=a1ab8b8669da03637a4b98fa39c39228&language={lang}'.format(id=self.busqueda_id, lang=self.busqueda_idioma)
results = requests.get(url).json().get('seasons', [])
return results if 'Error' not in results else []
seasons = []
if results and 'Error' not in results:
for season in results:
url = 'https://api.themoviedb.org/3/tv/{id}/season/{season}?api_key=a1ab8b8669da03637a4b98fa39c39228&language={lang}'.format(id=self.busqueda_id, season=season['season_number'], lang=self.busqueda_idioma)
try: start_from = requests.get(url).json()['episodes'][0]['episode_number']
except: start_from = 1
seasons.append({'season_number':season['season_number'], 'episode_count':season['episode_count'], 'start_from':start_from})
return seasons
def get_videos(self):
"""
@@ -1617,7 +1627,7 @@ class Tmdb(object):
elif k == 'credits_cast' or k == 'temporada_cast' or k == 'episodio_guest_stars':
dic_aux = dict((name, character) for (name, character) in l_castandrole)
l_castandrole.extend([(p['name'], p.get('character', '') or p.get('character_name', '')) \
for p in v if p['name'] not in list(dic_aux.keys())])
for p in v if 'name' in p and p['name'] not in list(dic_aux.keys())])
elif k == 'videos':
if not isinstance(v, list):

View File

@@ -33,7 +33,7 @@ def country(config, common_words):
return CountryFinder(allowed_countries, common_words).find(string)
rebulk.functional(find_countries,
#  Prefer language and any other property over country if not US or GB.
# Prefer language and any other property over country if not US or GB.
conflict_solver=lambda match, other: match
if other.name != 'language' or match.value not in (babelfish.Country('US'),
babelfish.Country('GB'))

View File

@@ -1370,13 +1370,13 @@
video_codec: Xvid
release_group: Etc-Group
type: movie
# Fallback to movie type because we can't tell it's a series ...
# Fallback to movie type because we can't tell it's a series ...
? Show.Name.Part.1.and.Part.2.Blah-Group
: part: [1, 2]
title: Show Name
type: movie
# Fallback to movie type because we can't tell it's a series ...
# Fallback to movie type because we can't tell it's a series ...
? Show Name - 01 - Ep Name
: episode: 1

View File

@@ -544,7 +544,7 @@
episode:
- 1
- 7
episode_title: FooBar-Group # Make sure it doesn't conflict with uuid
episode_title: FooBar-Group # Make sure it doesn't conflict with uuid
season: 1
title: Test
type: episode

View File

@@ -191,20 +191,20 @@ class autorenumber():
seasons =[]
groupedSeasons = tmdb.get_group(self.group.replace('\n','').split('/')[-1])
for groupedSeason in groupedSeasons:
seasons.append({'season_number':groupedSeason['order'], 'episode_count':len(groupedSeason['episodes'])})
seasons.append({'season_number':groupedSeason['order'], 'episode_count':len(groupedSeason['episodes']), 'start_from':groupedSeason['episodes'][0]['episode_number']})
else:
seasons = tmdb.Tmdb(id_Tmdb=self.id).get_list_episodes()
count = 0
for season in seasons:
s = season['season_number']
c = season['episode_count']
fe = season['start_from']
self.seasonsdict[str(s)] = c
if s > 0:
for e in range(1, c + 1):
count += 1
self.epdict[count] = '{}x{:02d}'.format(s,e)
self.epdict[count] = '{}x{:02d}'.format(s, e + fe - 1)
if self.item.renumber or self.manual:
self.item.renumber = False

View File

@@ -170,13 +170,13 @@ def enable_disable_autorun(is_enabled):
set_setting('autostart', True)
return True
def get_all_settings_addon():
# Read the settings.xml file and return a dictionary with {id: value}
from core import scrapertools
infile = open(os.path.join(get_data_path(), "settings.xml"), "r")
data = infile.read()
infile.close()
with open(os.path.join(get_data_path(), "settings.xml"), "rb") as infile:
data = infile.read().decode('utf-8')
ret = {}
matches = scrapertools.find_multiple_matches(data, '<setting id=\"([^\"]+)\"[^>]*>([^<]*)</setting>')

View File

@@ -134,8 +134,8 @@ def run(item=None):
elif item.action == "script":
from core import tmdb
if tmdb.drop_bd():
platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False)
tmdb.clean_cache()
platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False)
elif item.action == "itemInfo":
platformtools.dialog_textviewer('Item info', item.parent)
elif item.action == "open_browser":
@@ -332,7 +332,7 @@ def run(item=None):
platformtools.dialog_ok(config.get_localized_string(60087) % Channel, config.get_localized_string(60014))
else:
if platformtools.dialog_yesno(config.get_localized_string(60038), config.get_localized_string(60015)):
run(Item(channel="setting", action="report_menu"))
platformtools.itemlist_update(Item(channel="setting", action="report_menu"), True)
finally:
# db need to be closed when not used, it will cause freezes
from core import db

View File

@@ -239,9 +239,14 @@ def dialog_select_group(heading, _list, preselect=0):
def onInit(self):
self.getControl(1).setText(self.heading)
itemlist = []
for n, text in enumerate(self.list):
for n, it in enumerate(self.list):
logger.debug(it)
item = xbmcgui.ListItem(str(n))
item.setProperty('title', text)
item.setProperty('title', it[0])
item.setProperty('seasons', str(it[1]))
item.setProperty('episodes', str(it[2]))
item.setProperty('description', '\n' + it[3])
item.setProperty('thumb', it[4])
itemlist.append(item)
self.getControl(2).addItems(itemlist)
@@ -441,13 +446,13 @@ def set_view_mode(item, parent_item):
def set_infolabels(listitem, item, player=False):
"""
Method to pass the information to the listitem (see tmdb.set_InfoLabels())
    item.infoLabels is a dictionary with the key / value pairs described in:
    http://mirrors.xbmc.org/docs/python-docs/14.x-helix/xbmcgui.html#ListItem-setInfo
    https://kodi.wiki/view/InfoLabels
    @param listitem: xbmcgui.ListItem object
    @type listitem: xbmcgui.ListItem
    @param item: Item object that represents a movie, series or chapter
    @type item: item
item.infoLabels is a dictionary with the key / value pairs described in:
http://mirrors.xbmc.org/docs/python-docs/14.x-helix/xbmcgui.html#ListItem-setInfo
https://kodi.wiki/view/InfoLabels
@param listitem: xbmcgui.ListItem object
@type listitem: xbmcgui.ListItem
@param item: Item object that represents a movie, series or chapter
@type item: item
"""
infoLabels_dict = {'aired': 'aired', 'album': 'album', 'artist': 'artist', 'cast': 'cast',
@@ -482,31 +487,30 @@ def set_infolabels(listitem, item, player=False):
def set_context_commands(item, item_url, parent_item, **kwargs):
"""
Function to generate context menus.
        1. Based on the data in item.context
            a. Old method item.context type str separating options by "|" (example: item.context = "1 | 2 | 3")
                (only predefined)
            b. List method: item.context is a list with the different menu options:
                - Predefined: A predefined option will be loaded with a name.
                    item.context = ["1", "2", "3"]
1. Based on the data in item.context
a. Old method item.context type str separating options by "|" (example: item.context = "1 | 2 | 3")
(only predefined)
b. List method: item.context is a list with the different menu options:
- Predefined: A predefined option will be loaded with a name.
item.context = ["1", "2", "3"]
                - dict (): The current item will be loaded modifying the fields included in the dict () in case of
                    modify the channel and action fields these will be saved in from_channel and from_action.
                    item.context = [{"title": "Name of the menu", "action": "action of the menu", "channel": "menu channel"}, {...}]
- dict (): The current item will be loaded modifying the fields included in the dict () in case of
modify the channel and action fields these will be saved in from_channel and from_action.
item.context = [{"title": "Name of the menu", "action": "action of the menu", "channel": "menu channel"}, {...}]
        2. Adding options according to criteria
            Options can be added to the context menu to items that meet certain conditions.
2. Adding options according to criteria
Options can be added to the context menu to items that meet certain conditions.
3. Adding options to all items
Options can be added to the context menu for all items
        3. Adding options to all items
            Options can be added to the context menu for all items
4. You can disable the context menu options by adding a command 'no_context' to the item.context.
The options that Kodi, the skin or another added add to the contextual menu cannot be disabled.
        4. You can disable the context menu options by adding a command 'no_context' to the item.context.
            The options that Kodi, the skin or another added add to the contextual menu cannot be disabled.
    @param item: element that contains the contextual menus
    @type item: item
    @param parent_item:
    @type parent_item: item
@param item: element that contains the contextual menus
@type item: item
@param parent_item:
@type parent_item: item
"""
context_commands = []
# num_version_xbmc = config.get_platform(True)['num_version']
@@ -821,9 +825,9 @@ def show_channel_settings(**kwargs):
def show_video_info(*args, **kwargs):
"""
It shows a window with the info of the video.
    The parameters passed to it can be seen in the method that is called
The parameters passed to it can be seen in the method that is called
    @return: returns the window with the elements
@return: returns the window with the elements
@rtype: InfoWindow
"""
@@ -1420,6 +1424,7 @@ def get_played_time(item):
logger.debug()
from core import db
played_time = 0
if not item.infoLabels:
return 0
ID = item.infoLabels.get('tmdb_id', '')
@@ -1430,13 +1435,18 @@ def get_played_time(item):
E = item.infoLabels.get('episode')
result = None
if item.contentType == 'movie':
result = db['viewed'].get(ID)
elif S and E:
result = db['viewed'].get(ID, {}).get(str(S)+'x'+str(E))
try:
if item.contentType == 'movie':
result = db['viewed'].get(ID)
elif S and E:
result = db['viewed'].get(ID, {}).get(str(S)+'x'+str(E))
if not result: played_time = 0
else: played_time = result
if result:
played_time = result
except:
import traceback
logger.error(traceback.format_exc())
del db['viewed'][ID]
return played_time
@@ -1456,13 +1466,17 @@ def set_played_time(item):
S = item.infoLabels.get('season', 0)
E = item.infoLabels.get('episode')
if item.contentType == 'movie':
db['viewed'][ID] = played_time
elif E:
newDict = db['viewed'].get(ID, {})
newDict[str(S) + 'x' + str(E)] = played_time
db['viewed'][ID] = newDict
try:
if item.contentType == 'movie':
db['viewed'][ID] = played_time
elif E:
newDict = db['viewed'].get(ID, {})
newDict[str(S) + 'x' + str(E)] = played_time
db['viewed'][ID] = newDict
except:
import traceback
logger.error(traceback.format_exc())
del db['viewed'][ID]
def prevent_busy(item):

View File

@@ -132,7 +132,7 @@ def SettingOnPosition(item):
def select(item):
from core.support import dbg;dbg()
# from core.support import dbg;dbg()
from platformcode import config, platformtools
# item.id = setting ID
# item.type = labels or values

View File

@@ -104,7 +104,7 @@ def check(background=False):
patch_url = commitJson['html_url'] + '.patch'
logger.info('applicando ' + patch_url)
from lib import patch
patch.fromurl(patch_url).apply(root=addonDir)
patchOk = patch.fromurl(patch_url).apply(root=addonDir)
for file in commitJson['files']:
if file["filename"] == trackingFile: # il file di tracking non si modifica
@@ -115,7 +115,7 @@ def check(background=False):
poFilesChanged = True
if 'service.py' in file["filename"]:
serviceChanged = True
if (file['status'] == 'modified' and 'patch' not in file) or file['status'] == 'added':
if (file['status'] == 'modified' and 'patch' not in file) or file['status'] == 'added' or (file['status'] == 'modified' and not patchOk):
# è un file NON testuale che è stato modificato, oppure è un file nuovo (la libreria non supporta la creazione di un nuovo file)
# lo devo scaricare
filename = os.path.join(addonDir, file['filename'])

View File

@@ -2017,7 +2017,7 @@ msgid "Yes, the option to display merged or split results by channels can be fou
msgstr ""
msgctxt "#60467"
msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s"
msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s"
msgstr ""
msgctxt "#60468"

View File

@@ -2016,7 +2016,7 @@ msgid "Yes, the option to display merged or split results by channels can be fou
msgstr "Sì, l'opzione per mostrare i risultati uniti o divisi per canali si trova in 'Impostazioni>Impostazioni ricerca globale>Altre impostazioni'. Vuoi accedere a queste impostazioni?"
msgctxt "#60467"
msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s"
msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s"
msgstr "Per segnalare un problema su 'https://t.me/kodiondemand' è necessario:|la versione che si sta usando di Kodi on Demand.|La versione che si sta usando di Kodi, mediaserver, ecc.|la versione e il nome del sistema operativo che si sta usando.|Il nome della skin (nel caso in cui si stia usando Kodi) e se l'utilizzo della skin predefinita ha risolto il problema.|La descrizione del problema e tutti i casi di test.Per attivare il log in modalità dettagliata, andare su:|Configurazione.|Preferenze.|Nella scheda Generale - Selezionare l'opzione: Genera log dettagliato Il file di log dettagliato si trova nel seguente percorso: \n\n%s"
msgctxt "#60468"

View File

@@ -90,7 +90,7 @@
<setting id="search_channels" type="action" label="59994" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWxfbmV3IiwNCiAgICAiY2hhbm5lbCI6InNlYXJjaCINCn0=)"/>
<setting label="70154" type="lsep"/>
<setting id="tmdb_active" default="true" visible="false"/>
<setting id="tmdb_threads" type="slider" option="int" range="5,5,30" label="70155" default="20"/>
<!-- <setting id="tmdb_threads" type="slider" option="int" range="5,5,30" label="70155" default="20"/>-->
<setting id="tmdb_plus_info" type="bool" label="70156" default="false"/>
<setting id="tmdb_cache" type="bool" label="70157" default="true"/>
<setting id="tmdb_cache_expire" type="select" lvalues="70158|70159|70160|70161|70170" label="70162" enable="eq(-1,true)" default="4"/>

View File

@@ -12,9 +12,9 @@
<controls>
<control type="group">
<description>Container</description>
<left>200</left>
<left>40</left>
<top>60</top>
<width>860</width>
<width>1200</width>
<height>600</height>
<control type="image">
<description>Background</description>
@@ -22,49 +22,56 @@
<height>100%</height>
<texture colordiffuse="FF232323">white.png</texture>
</control>
<control type="image">
<description>Poster</description>
<top>0</top>
<left>0</left>
<height>600</height>
<width>400</width>
<texture>$INFO[Container(2).ListItem.Property(thumb)]</texture>
</control>
<control type="textbox" id="1">
<description>Heading</description>
<top>0</top>
<left>0</left>
<height>60</height>
<width>100%</width>
<left>460</left>
<height>80</height>
<width>680</width>
<font>font13</font>
<textcolor>FFFFFFFF</textcolor>
<align>center</align>
<align>left</align>
<aligny>center</aligny>
<label></label>
</control>
<control type="group">
<left>30</left>
<top>70</top>
<width>795</width>
<height>530</height>
<left>440</left>
<top>80</top>
<width>720</width>
<height>480</height>
<control type="list" id="2">
<description>List</description>
<left>0</left>
<top>0</top>
<width>795</width>
<width>720</width>
<height>530</height>
<onup>100</onup>
<onright>4</onright>
<orientation>vertical</orientation>
<scrolltime>200</scrolltime>
<pagecontrol>4</pagecontrol>
<itemlayout height="150" width="795">
<itemlayout height="60" width="720">
<control type="textbox">
<description>Selected Item</description>
<left>20</left>
<top>20</top>
<width>765</width>
<height>110</height>
<top>0</top>
<width>680</width>
<height>60</height>
<font>font13</font>
<textcolor>FFFFFFFF</textcolor>
<label>$INFO[ListItem.Property(title)]</label>
<align>center</align>
<label>[B]$INFO[ListItem.Property(title)][/B] $ADDON[plugin.video.kod 30140]: $INFO[ListItem.Property(seasons)] $ADDON[plugin.video.kod 70362]: $INFO[ListItem.Property(episodes)]</label>
<align>left</align>
<aligny>center</aligny>
</control>
</itemlayout>
<focusedlayout height="150" width="795">
<focusedlayout height="200" width="720">
<control type="image">
<top>1</top>
<width>100%</width>
@@ -75,39 +82,22 @@
<description>Selected Item</description>
<left>20</left>
<top>20</top>
<width>765</width>
<height>110</height>
<width>680</width>
<height>160</height>
<font>font13</font>
<textcolor>FFFFFFFF</textcolor>
<label>$INFO[ListItem.Property(title)]</label>
<label>[B]$INFO[ListItem.Property(title)][/B] $ADDON[plugin.video.kod 30140]: $INFO[ListItem.Property(seasons)] $ADDON[plugin.video.kod 70362]: $INFO[ListItem.Property(episodes)]$INFO[ListItem.Property(description)]</label>
<autoscroll time="3000" delay="3000" repeat="3000">True</autoscroll>
<align>center</align>
<align>left</align>
<aligny>center</aligny>
</control>
</focusedlayout>
</control>
<control type="scrollbar" id="4">
<description>Scrollbar</description>
<left>800</left>
<top>0</top>
<width>5</width>
<height>470</height>
<visible>true</visible>
<texturesliderbackground colordiffuse="FF232323">white.png</texturesliderbackground>
<texturesliderbar colordiffuse="FFFFFFFF">white.png</texturesliderbar>
<texturesliderbarfocus colordiffuse="FF0081C2">white.png</texturesliderbarfocus>
<textureslidernib colordiffuse="FFFFFFFF">white.png</textureslidernib>
<textureslidernibfocus colordiffuse="FFFFFFFF">white.png</textureslidernibfocus>
<orientation>vertical</orientation>
<showonepage>false</showonepage>
<onleft>2</onleft>
<onright>3</onright>
</control>
</control>
<control type="button" id="100">
<description>Close Button</description>
<right>20</right>
<top>10</top>
<top>20</top>
<width>40</width>
<height>40</height>
<texturefocus colordiffuse="FFFFFFFF">close.png</texturefocus>

View File

@@ -1,10 +1,9 @@
{
"active": true,
"find_videos": {
"ignore_urls": [],
"patterns": [
{
"pattern": "ninjastream.to/(?:watch/)?([0-9a-zA-Z]+)",
"pattern": "ninjastream\\.to/(?:watch|download)/([0-9a-zA-Z]+)",
"url": "https://ninjastream.to/watch/\\1"
}
]

View File

@@ -20,11 +20,17 @@ def get_video_url(page_url, premium=False, user="", password="", video_password=
logger.debug("URL", page_url)
video_urls = []
h = json.loads(support.match(data, patron='stream="([^"]+)"').match.replace('&quot;','"').replace('\\',''))
baseurl = h['host'] + h['hash']
h = json.loads(support.match(data, patron='stream="([^"]+)"').match.replace('&quot;','"'))
baseurl = decode(h['host']) + h['hash']
matches = support.match(baseurl + '/index.m3u8', patron=r'RESOLUTION=\d+x(\d+)\s*([^\s]+)').matches
for quality, url in matches:
video_urls.append(["{} {}p [NinjaStream]".format(url.split('.')[-1], quality), '{}/{}'.format(baseurl, url)])
return video_urls
return video_urls
def decode(host):
Host = ''
for n in range(len(host)):
Host += chr(ord(host[n]) ^ ord('2'))
return Host

View File

@@ -12,10 +12,10 @@ def test_video_exists(page_url):
logger.debug("(page_url='%s')" % page_url)
global data
data = httptools.downloadpage(page_url, cookies=False).data
if 'Video embed restricted for this domain'in data:
headers = {'Referer':''}
if 'Video embed restricted for this domain' in data:
headers = {'Referer': ''}
data = httptools.downloadpage(page_url, headers=headers, cookies=False).data
if 'File is no longer available as it expired or has been deleted' in data:
if 'File is no longer available as it expired or has been deleted' in data or 'fake-' in data:
return False, config.get_localized_string(70449) % "SuperVideo"
return True, ""

View File

@@ -18,5 +18,8 @@ def get_video_url(page_url, premium=False, user="", password="", video_password=
logger.debug("url=" + page_url)
global data
video_urls = support.get_jwplayer_mediaurl(data, 'Vidmoly')
for url in video_urls:
logger.debug(url)
url[-1] = url[-1].replace(',','').replace('.urlset','').replace('/hls','')
return video_urls

View File

@@ -477,15 +477,15 @@ def get_server_position(server):
def get_match_list(data, match_list, order_list=None, only_ascii=False, ignorecase=False):
"""
Search for matches in a text string, with a dictionary of "ID" / "List of search strings":
    {"ID1": ["String 1", "String 2", "String 3"],
      "ID2": ["String 4", "String 5", "String 6"]
    }
{"ID1": ["String 1", "String 2", "String 3"],
"ID2": ["String 4", "String 5", "String 6"]
}
    The dictionary could not contain the same search string in several IDs.
    The search is performed in order of search string size (from longest to shortest) if a string matches,
    it is removed from the search string for the following, so that two categories are not detected if one string is part of another:
    for example: "Spanish Language" and "Spanish" if the first appears in the string "Pablo knows how to speak the Spanish Language"
    It will match "Spanish Language" but not "Spanish" since the longest match has priority.
The dictionary could not contain the same search string in several IDs.
The search is performed in order of search string size (from longest to shortest) if a string matches,
it is removed from the search string for the following, so that two categories are not detected if one string is part of another:
for example: "Spanish Language" and "Spanish" if the first appears in the string "Pablo knows how to speak the Spanish Language"
It will match "Spanish Language" but not "Spanish" since the longest match has priority.
"""
match_dict = dict()

View File

@@ -235,23 +235,25 @@ def new_search(item):
def live(item):
import sys
import channelselector
if sys.version_info[0] >= 3:
from concurrent import futures
else:
from concurrent_py2 import futures
itemlist = []
channels_dict = {}
channels = ['raiplay', 'mediasetplay', 'la7', 'paramount']
channels = channelselector.filterchannels('live')
with futures.ThreadPoolExecutor() as executor:
itlist = [executor.submit(load_live, channel) for channel in channels]
itlist = [executor.submit(load_live, ch.channel) for ch in channels]
for res in futures.as_completed(itlist):
if res.result():
channel_name, itlist = res.result()
channels_dict[channel_name] = itlist
for channel in channels:
itemlist += channels_dict[channel]
for ch in channels:
itemlist += channels_dict[ch.channel]
return itemlist

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import xbmc, xbmcgui, sys, channelselector, time, os
from core import support
from core.support import dbg, tmdb
from core.item import Item
from core import channeltools, servertools, scrapertools
@@ -8,8 +9,12 @@ from platformcode import platformtools, config, logger
from platformcode.launcher import run
from threading import Thread
if sys.version_info[0] >= 3: from concurrent import futures
else: from concurrent_py2 import futures
if sys.version_info[0] >= 3:
PY3 = True
from concurrent import futures
else:
PY3 = False
from concurrent_py2 import futures
info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json
def_lang = info_language[config.get_setting("info_language", "videolibrary")]
@@ -75,17 +80,14 @@ class SearchWindow(xbmcgui.WindowXML):
self.channels = []
self.persons = []
self.episodes = []
self.servers = []
self.results = {}
self.focus = SEARCH
self.process = True
self.page = 1
self.moduleDict = moduleDict
self.searchActions = searchActions
self.thread = None
self.selected = False
self.pos = 0
selfeppos = 0
self.items = []
if not searchActions:
@@ -116,6 +118,7 @@ class SearchWindow(xbmcgui.WindowXML):
from specials.search import save_search
save_search(self.item.text)
def getActions(self):
logger.debug()
count = 0
@@ -144,9 +147,12 @@ class SearchWindow(xbmcgui.WindowXML):
if self.item.mode == 'movie':
title = result['title']
result['mode'] = 'movie'
else:
elif self.item.mode == 'tvshow':
title = result['name']
result['mode'] = 'tvshow'
else:
title = result.get('title', '')
result['mode'] = result['media_type'].replace('tv', 'tvshow')
thumbnail = result.get('thumbnail', '')
noThumb = 'Infoplus/' + result['mode'].replace('show','') + '.png'
@@ -304,16 +310,12 @@ class SearchWindow(xbmcgui.WindowXML):
logger.debug('end search for:', searchAction.channel)
def get_channel_results(self, searchAction):
logger.debug()
channel = searchAction.channel
results = []
valid = []
other = []
try:
results = self.moduleDict[channel].search(searchAction, self.item.text)
def search(text):
valid = []
other = []
results = self.moduleDict[channel].search(searchAction, text)
if len(results) == 1:
if not results[0].action or config.get_localized_string(70006).lower() in results[0].title.lower():
if not results[0].action or results[0].nextPage:
results = []
if self.item.mode != 'all':
@@ -324,6 +326,23 @@ class SearchWindow(xbmcgui.WindowXML):
valid.append(elem)
else:
other.append(elem)
return results, valid, other
logger.debug()
channel = searchAction.channel
results = []
valid = []
other = []
try:
results, valid, other = search(self.item.text)
# if we are on movie search but no valid results is found, and there's a lot of results (more pages), try
# to add year to search text for better filtering
if self.item.contentType == 'movie' and not valid and other and other[-1].nextPage \
and self.item.infoLabels['year']:
logger.debug('retring adding year on channel ' + channel)
dummy, valid, dummy = search(self.item.text + " " + str(self.item.infoLabels['year']))
except:
pass
@@ -424,9 +443,15 @@ class SearchWindow(xbmcgui.WindowXML):
self.channels = []
self.moduleDict = {}
self.searchActions = []
if percent == 100 and not self.results:
self.PROGRESS.setVisible(False)
self.NORESULTS.setVisible(True)
# if no results
total = 0
for num in self.results.values():
total += num
if not total:
self.PROGRESS.setVisible(False)
self.NORESULTS.setVisible(True)
self.setFocusId(CLOSE)
def onInit(self):
self.time = time.time()
@@ -453,7 +478,9 @@ class SearchWindow(xbmcgui.WindowXML):
if self.type:
self.type = None
if self.item.mode in ['all', 'search']:
if self.item.type: self.item.mode = self.item.type
if self.item.type:
self.item.mode = self.item.type
self.item.text = title_unify(self.item.text)
self.thread = Thread(target=self.search)
self.thread.start()
elif self.item.mode in ['movie', 'tvshow', 'person_']:
@@ -507,9 +534,12 @@ class SearchWindow(xbmcgui.WindowXML):
elif self.EPISODES.isVisible(): self.setFocusId(EPISODESLIST)
elif self.RESULTS.isVisible(): self.setFocusId(RESULTS)
elif focus in [RESULTS] and self.item.mode == 'all':
elif focus in [RESULTS]:
pos = self.RESULTS.getSelectedPosition()
self.CHANNELS.getSelectedItem().setProperty('position', str(pos))
try:
self.CHANNELS.getSelectedItem().setProperty('position', str(pos))
except:
pass
elif action == ENTER and focus in [CHANNELS]:
self.setFocusId(RESULTS)
@@ -559,25 +589,14 @@ class SearchWindow(xbmcgui.WindowXML):
self.actors()
elif search == 'persons':
item = self.item.clone(mode='person_', discovery=self.persons[pos])
# self.close()
Search(item, self.moduleDict, self.searchActions)
if close_action:
self.close
self.close()
else:
item = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item'))
if self.item.mode == 'movie': item.contentTitle = self.RESULTS.getSelectedItem().getLabel()
else: item.contentSerieName = self.RESULTS.getSelectedItem().getLabel()
self.RESULTS.reset()
self.RESULTS.setVisible(False)
self.PROGRESS.setVisible(True)
self.selected = True
self.thActions.join()
self.RESULTS.addItems(self.items)
self.RESULTS.setVisible(True)
self.PROGRESS.setVisible(False)
# self.close()
Search(item, self.moduleDict, self.searchActions)
if close_action:
self.close()
@@ -589,7 +608,6 @@ class SearchWindow(xbmcgui.WindowXML):
self.pos = self.RESULTS.getSelectedPosition()
item = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item'))
else:
self.eppos = self.EPISODESLIST.getSelectedPosition()
item_url = self.EPISODESLIST.getSelectedItem().getProperty('item')
if item_url:
item = Item().fromurl(item_url)
@@ -706,8 +724,6 @@ class SearchWindow(xbmcgui.WindowXML):
self.Focus(SEARCH)
self.setFocusId(RESULTS)
self.RESULTS.selectItem(self.pos)
elif self.item.mode in ['person']:
self.actors()
else:
self.Close()
@@ -746,3 +762,26 @@ class SearchWindow(xbmcgui.WindowXML):
server.globalsearch = True
return run(server)
def title_unify(title):
import unicodedata
u_title = ''
if type(title) == str: title = u'' + title
for c in unicodedata.normalize('NFD', title):
cat = unicodedata.category(c)
if cat != 'Mn':
if cat == 'Pd':
c_new = '-'
elif cat in ['Ll', 'Lu'] or c == ':':
c_new = c
else:
c_new = ' '
u_title += c_new
if (u_title.count(':') + u_title.count('-')) == 1:
# subtitle, split but only if there's one, it might be part of title
spl = u_title.replace(':', '-').split('-')
u_title = spl[0] if len(spl[0]) > 5 else spl[1]
return u_title.strip()

View File

@@ -13,7 +13,6 @@ from core import filetools, scrapertools, videolibrarytools
from core.support import typo, thumb
from core.item import Item
from platformcode import config, logger, platformtools
from distutils import dir_util
if PY3:
from concurrent import futures
else:
@@ -202,14 +201,14 @@ def configure_update_videolibrary(item):
# Select Dialog
ret = platformtools.dialog_multiselect(config.get_localized_string(60601), lista, preselect=preselect, useDetails=True)
if ret < 0:
if ret is None:
return False # order cancel
seleccionados = [ids[i] for i in ret]
selection = [ids[i] for i in ret]
for tvshow in ids:
if tvshow not in seleccionados:
if tvshow not in selection:
tvshow.active = 0
elif tvshow in seleccionados:
elif tvshow in selection:
tvshow.active = 1
mark_tvshow_as_updatable(tvshow, silent=True)
@@ -416,124 +415,129 @@ def findvideos(item):
itemlist = []
all_videolibrary = []
for nom_canal, json_path in list(list_canales.items()):
if filtro_canal and filtro_canal != nom_canal.capitalize():
continue
item_canal = Item()
# We import the channel of the selected part
try:
if nom_canal == 'community':
channel = __import__('specials.%s' % nom_canal, fromlist=["channels.%s" % nom_canal])
else:
channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal])
except ImportError:
exec("import channels." + nom_canal + " as channel")
except:
dead_list = []
zombie_list = []
if nom_canal not in dead_list and nom_canal not in zombie_list: confirm = platformtools.dialog_yesno(config.get_localized_string(30131), config.get_localized_string(30132) % nom_canal.upper() + '\n' + config.get_localized_string(30133))
elif nom_canal in zombie_list: confirm = False
else: confirm = True
if confirm:
# delete the channel from all movie and tvshow
from past.utils import old_div
num_enlaces = 0
dialog = platformtools.dialog_progress(config.get_localized_string(30131), config.get_localized_string(60005) % nom_canal)
if not all_videolibrary:
all_videolibrary = list_movies(Item()) + list_tvshows(Item())
for n, it in enumerate(all_videolibrary):
if nom_canal in it.library_urls:
dead_item = Item(multichannel=len(it.library_urls) > 1,
contentType=it.contentType,
dead=nom_canal,
path=filetools.split(it.nfo)[0],
nfo=it.nfo,
library_urls=it.library_urls,
infoLabels={'title': it.contentTitle})
num_enlaces += delete(dead_item)
dialog.update(old_div(100*n, len(all_videolibrary)))
dialog.close()
msg_txt = config.get_localized_string(70087) % (num_enlaces, nom_canal)
logger.info(msg_txt)
platformtools.dialog_notification(config.get_localized_string(30131), msg_txt)
platformtools.itemlist_refresh()
if nom_canal not in dead_list:
dead_list.append(nom_canal)
ch_results = []
with futures.ThreadPoolExecutor() as executor:
for nom_canal, json_path in list(list_canales.items()):
if filtro_canal and filtro_canal != nom_canal.capitalize():
continue
else:
if nom_canal not in zombie_list:
zombie_list.append(nom_canal)
if len(dead_list) > 0:
for nom_canal in dead_list:
if nom_canal in item.library_urls:
del item.library_urls[nom_canal]
# We import the channel of the selected part
try:
if nom_canal == 'community':
channel = __import__('specials.%s' % nom_canal, fromlist=["channels.%s" % nom_canal])
else:
channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal])
except ImportError:
exec("import channels." + nom_canal + " as channel")
except:
dead_list = []
zombie_list = []
item_json = Item().fromjson(filetools.read(json_path))
list_servers = []
if nom_canal not in dead_list and nom_canal not in zombie_list: confirm = platformtools.dialog_yesno(config.get_localized_string(30131), config.get_localized_string(30132) % nom_canal.upper() + '\n' + config.get_localized_string(30133))
elif nom_canal in zombie_list: confirm = False
else: confirm = True
try:
# FILTERTOOLS
# if the channel has a filter, the name it has saved is passed to it so that it filters correctly.
if "list_language" in item_json:
# if it comes from the addon video library
if "library_filter_show" in item:
item_json.show = item.library_filter_show.get(nom_canal, "")
if confirm:
# delete the channel from all movie and tvshow
from past.utils import old_div
num_enlaces = 0
dialog = platformtools.dialog_progress(config.get_localized_string(30131), config.get_localized_string(60005) % nom_canal)
if not all_videolibrary:
all_videolibrary = list_movies(Item()) + list_tvshows(Item())
for n, it in enumerate(all_videolibrary):
if nom_canal in it.library_urls:
dead_item = Item(multichannel=len(it.library_urls) > 1,
contentType=it.contentType,
dead=nom_canal,
path=filetools.split(it.nfo)[0],
nfo=it.nfo,
library_urls=it.library_urls,
infoLabels={'title': it.contentTitle})
num_enlaces += delete(dead_item)
dialog.update(old_div(100*n, len(all_videolibrary)))
# We run find_videos, from the channel or common
item_json.contentChannel = 'videolibrary'
item_json.play_from = item.play_from
item_json.nfo = item.nfo
item_json.strm_path = item.strm_path
if hasattr(channel, 'findvideos'):
from core import servertools
if item_json.videolibray_emergency_urls:
del item_json.videolibray_emergency_urls
list_servers = getattr(channel, 'findvideos')(item_json)
elif item_json.action == 'play':
from platformcode import platformtools
# autoplay.set_status(True)
item_json.contentChannel = item_json.channel
item_json.channel = "videolibrary"
platformtools.play_video(item_json)
return ''
else:
from core import servertools
list_servers = servertools.find_video_items(item_json)
except Exception as ex:
logger.error("The findvideos function for the channel %s failed" % nom_canal)
template = "An exception of type %s occured. Arguments:\n%r"
message = template % (type(ex).__name__, ex.args)
logger.error(message)
logger.error(traceback.format_exc())
dialog.close()
msg_txt = config.get_localized_string(70087) % (num_enlaces, nom_canal)
logger.info(msg_txt)
platformtools.dialog_notification(config.get_localized_string(30131), msg_txt)
platformtools.itemlist_refresh()
# Change the title to the servers adding the name of the channel in front and the infoLabels and the images of the item if the server does not have
for server in list_servers:
server.contentChannel = server.channel
server.channel = "videolibrary"
server.nfo = item.nfo
server.strm_path = item.strm_path
server.play_from = item.play_from
if nom_canal not in dead_list:
dead_list.append(nom_canal)
continue
else:
if nom_canal not in zombie_list:
zombie_list.append(nom_canal)
# Kodi 18 Compatibility - Prevents wheel from spinning around in Direct Links
if server.action == 'play':
server.folder = False
if len(dead_list) > 0:
for nom_canal in dead_list:
if nom_canal in item.library_urls:
del item.library_urls[nom_canal]
# Channel name is added if desired
if config.get_setting("quit_channel_name", "videolibrary") == 0:
server.title = "%s: %s" % (nom_canal.capitalize(), server.title)
item_json = Item().fromjson(filetools.read(json_path))
list_servers = []
if not server.thumbnail:
server.thumbnail = item.thumbnail
try:
# FILTERTOOLS
# if the channel has a filter, the name it has saved is passed to it so that it filters correctly.
if "list_language" in item_json:
# if it comes from the addon video library
if "library_filter_show" in item:
item_json.show = item.library_filter_show.get(nom_canal, "")
# logger.debug("server:\n%s" % server.tostring('\n'))
itemlist.append(server)
# We run find_videos, from the channel or common
item_json.contentChannel = 'videolibrary'
item_json.play_from = item.play_from
item_json.nfo = item.nfo
item_json.strm_path = item.strm_path
if hasattr(channel, 'findvideos'):
from core import servertools
if item_json.videolibray_emergency_urls:
del item_json.videolibray_emergency_urls
ch_results.append(executor.submit(getattr(channel, 'findvideos'), item_json))
elif item_json.action == 'play':
from platformcode import platformtools
# autoplay.set_status(True)
item_json.contentChannel = item_json.channel
item_json.channel = "videolibrary"
platformtools.play_video(item_json)
return ''
else:
from core import servertools
ch_results.append(executor.submit(servertools.find_video_items, item_json))
except Exception as ex:
logger.error("The findvideos function for the channel %s failed" % nom_canal)
template = "An exception of type %s occured. Arguments:\n%r"
message = template % (type(ex).__name__, ex.args)
logger.error(message)
logger.error(traceback.format_exc())
for ris in futures.as_completed(ch_results):
list_servers.extend(ris.result())
# Change the title to the servers adding the name of the channel in front and the infoLabels and the images of the item if the server does not have
for server in list_servers:
server.contentChannel = server.channel
server.channel = "videolibrary"
server.nfo = item.nfo
server.strm_path = item.strm_path
server.play_from = item.play_from
# Kodi 18 Compatibility - Prevents wheel from spinning around in Direct Links
if server.action == 'play':
server.folder = False
# Channel name is added if desired
if config.get_setting("quit_channel_name", "videolibrary") == 0:
server.title = "%s: %s" % (server.contentChannel.capitalize(), server.title)
if not server.thumbnail:
server.thumbnail = item.thumbnail
# logger.debug("server:\n%s" % server.tostring('\n'))
itemlist.append(server)
if autoplay.play_multi_channel(item, itemlist): # hideserver
return []
@@ -605,6 +609,8 @@ def update_videolibrary(item=''):
def move_videolibrary(current_path, new_path, current_movies_folder, new_movies_folder, current_tvshows_folder, new_tvshows_folder):
from distutils import dir_util
logger.debug()
backup_current_path = current_path