Merge remote-tracking branch 'origin/master'

# Conflicts:
#	core/httptools.py
This commit is contained in:
marco
2020-01-13 21:12:53 +01:00
9 changed files with 261 additions and 482 deletions
+3 -3
View File
@@ -6,14 +6,14 @@
"animestream": "https://www.animeworld.it", "animestream": "https://www.animeworld.it",
"animesubita": "http://www.animesubita.org", "animesubita": "http://www.animesubita.org",
"animetubeita": "http://www.animetubeita.com", "animetubeita": "http://www.animetubeita.com",
"animeworld": "https://www1.animeworld.tv", "animeworld": "https://www.animeworld.cc",
"casacinema": "https://www.casacinema.cloud", "casacinema": "https://www.casacinema.biz",
"casacinemaInfo": "https://casacinema.kim", "casacinemaInfo": "https://casacinema.kim",
"cb01anime": "https://www.cineblog01.ink", "cb01anime": "https://www.cineblog01.ink",
"cinemalibero": "https://www.cinemalibero.live", "cinemalibero": "https://www.cinemalibero.live",
"cinetecadibologna": "http://cinestore.cinetecadibologna.it", "cinetecadibologna": "http://cinestore.cinetecadibologna.it",
"documentaristreamingda": "https://documentari-streaming-da.com", "documentaristreamingda": "https://documentari-streaming-da.com",
"dreamsub": "https://www.dreamsub.stream", "dreamsub": "https://dreamsub.stream",
"fastsubita": "https://fastsubita.com", "fastsubita": "https://fastsubita.com",
"filmgratis": "https://www.filmaltadefinizione.org", "filmgratis": "https://www.filmaltadefinizione.org",
"filmigratis": "https://filmigratis.org", "filmigratis": "https://filmigratis.org",
+1 -1
View File
@@ -10,7 +10,7 @@ headers = [['Referer', host]]
__channel__ = 'animeworld' __channel__ = 'animeworld'
list_servers = ['animeworld', 'verystream', 'streamango', 'openload', 'directo'] list_servers = ['directo', 'animeworld', 'vvvvid']
list_quality = ['default', '480p', '720p', '1080p'] list_quality = ['default', '480p', '720p', '1080p']
+88 -141
View File
@@ -2,34 +2,12 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
# Canale per 'casacinema' # Canale per 'casacinema'
# ------------------------------------------------------------ # ------------------------------------------------------------
"""
Problemi noti che non superano il test del canale:
- Nella ricerca globale non sono presenti le voci:
- "Aggiungi in videoteca"
- "Scarica film/serie"
presenti però quando si entra nella pagina
Avvisi:
Novità:
- Film, SerieTv
Ulteriori info:
"""
import re
from core import support from core import support
from platformcode import config
# in caso di necessità
from core import scrapertools, httptools
from core.item import Item
##### fine import host = support.config.get_channel_url()
host = config.get_channel_url()
headers = [['Referer', host]] headers = [['Referer', host]]
list_servers = ['verystream', 'openload', 'wstream', 'speedvideo'] list_servers = ['verystream', 'openload', 'wstream', 'speedvideo']
@@ -37,9 +15,6 @@ list_quality = ['HD', 'SD']
@support.menu @support.menu
def mainlist(item): def mainlist(item):
support.log(item)
## support.dbg()
film = ['/category/film', film = ['/category/film',
('Generi', ['', 'genres', 'genres']), ('Generi', ['', 'genres', 'genres']),
('Sub-ITA', ['/category/sub-ita/', 'peliculas', 'sub']) ('Sub-ITA', ['/category/sub-ita/', 'peliculas', 'sub'])
@@ -53,24 +28,90 @@ def mainlist(item):
return locals() return locals()
@support.scrape
def genres(item):
action = 'peliculas'
blacklist = ['PRIME VISIONI', 'ULTIME SERIE TV', 'ULTIMI FILM']
patronMenu = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a></li>'
patronBlock = r'<div class="container home-cats">(?P<block>.*?)<div class="clear">'
return locals()
def select(item):
item.data = support.match(item)[1]
if 'continua con il video' in item.data.lower():
support.log('select = ### è un film ###')
item.contentType = 'movie'
return findvideos(item)
else:
support.log('select = ### è una serie ###')
item.contentType = 'tvshow'
return episodios(item)
def search(item, text):
support.log(text)
text = text.replace(' ', '+')
item.url = host + '/?s=' + text
item.args = 'search'
try:
item.contentType = '' # non fa uscire le voci nel context menu
return peliculas(item)
except:
import sys
for line in sys.exc_info():
support.log('search log:', line)
return []
def newest(categoria):
itemlist = []
item = support.Item()
item.args = 'newest'
try:
if categoria == 'series':
item.contentType = 'tvshow'
item.url = host+'/aggiornamenti-serie-tv'
else:
item.contentType = 'movie'
item.url = host+'/category/film'
item.action = 'peliculas'
itemlist = peliculas(item)
if itemlist[-1].action == 'peliculas':
itemlist.pop()
# Continua la ricerca in caso di errore
except:
import sys
for line in sys.exc_info():
support.log('newest log: ', {0}.format(line))
return []
return itemlist
@support.scrape @support.scrape
def peliculas(item): def peliculas(item):
support.log(item)
## support.dbg() # decommentare per attivare web_pdb
if item.contentType == 'movie': if item.contentType == 'movie':
action = 'findvideos' action = 'findvideos'
elif item.contentType == 'tvshow': elif item.contentType == 'tvshow':
action = 'episodios' action = 'episodios'
pagination = '' pagination = ''
else: else:
# è una ricerca
action = 'select' action = 'select'
blacklist = ['']
patron = r'<li><a href="(?P<url>[^"]+)"[^=]+="(?P<thumb>[^"]+)"><div> <div[^>]+>(?P<title>.*?)[ ]?(?:\[(?P<quality1>HD)\])?[ ]?(?:\(|\[)?(?P<lang>Sub-ITA)?(?:\)|\])?[ ]?(?:\[(?P<quality>.+?)\])?[ ]?(?:\((?P<year>\d+)\))?<(?:[^>]+>.+?(?:title="Nuovi episodi">(?P<episode>\d+x\d+)[ ]?(?P<lang2>Sub-Ita)?|title="IMDb">(?P<rating>[^<]+)))?' if item.args == 'newest':
patronBlock = r'<h1>.+?</h1>(?P<block>.*?)<aside>' patron = r'<li><a href="(?P<url>[^"]+)"[^=]+="(?P<thumb>[^"]+)"><div> <div[^>]+>(?P<title>[^\(\[<]+)(?:\[(?P<quality1>HD)\])?[ ]?(?:\(|\[)?(?P<lang>Sub-ITA)?(?:\)|\])?[ ]?(?:\[(?P<quality>.+?)\])?[ ]?(?:\((?P<year>\d+)\))?<(?:[^>]+>.+?(?:title="Nuovi episodi">(?P<episode>\d+x\d+)[ ]?(?P<lang2>Sub-Ita)?|title="IMDb">(?P<rating>[^<]+)))?'
patronNext = '<a href="([^"]+)" >Pagina' else:
patron = r'<li><a href="(?P<url>[^"]+)"[^=]+="(?P<thumb>[^"]+)"><div> <div[^>]+>(?P<title>[^\(\[<]+)(?:\[(?P<quality1>HD)\])?[ ]?(?:\(|\[)?(?P<lang>Sub-ITA)?(?:\)|\])?[ ]?(?:\[(?P<quality>.+?)\])?[ ]?(?:\((?P<year>\d+)\))?<'
patronNext = r'<a href="([^"]+)" >Pagina'
def itemHook(item): def itemHook(item):
if item.quality1: if item.quality1:
@@ -82,125 +123,31 @@ def peliculas(item):
if item.args == 'novita': if item.args == 'novita':
item.title = item.title item.title = item.title
return item return item
## debug = True # True per testare le regex sul sito
return locals() return locals()
@support.scrape @support.scrape
def episodios(item): def episodios(item):
support.log(item) if item.data:
#dbg data = item.data
if item.data1:
data = item.data1
action = 'findvideos' action = 'findvideos'
item.contentType = 'tvshow' item.contentType = 'tvshow'
blacklist = [''] blacklist = ['']
patron = r'(?P<episode>\d+(?:&#215;|×)?\d+\-\d+|\d+(?:&#215;|×)\d+)[;]?(?:(?P<title>[^<]+)<(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:<br />|</p>)' patron = r'(?P<episode>\d+(?:&#215;|×)?\d+\-\d+|\d+(?:&#215;|×)\d+)[;]?(?:(?P<title>[^<]+)<(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:<br />|</p>)'
patronBlock = r'<strong>(?P<block>(?:.+?Stagione*.+?(?P<lang>[Ii][Tt][Aa]|[Ss][Uu][Bb][\-]?[iI][tT][aA]))?(?:.+?|</strong>)(/?:</span>)?</p>.*?</p>)' patronBlock = r'<strong>(?P<block>(?:.+?Stagione*.+?(?P<lang>[Ii][Tt][Aa]|[Ss][Uu][Bb][\-]?[iI][tT][aA]))?(?:.+?|</strong>)(/?:</span>)?</p>.*?</p>)'
## debug = True
return locals() return locals()
# Questa def è utilizzata per generare il menu 'Generi' del canale
# per genere, per anno, per lettera, per qualità ecc ecc
@support.scrape
def genres(item):
support.log(item)
#dbg
action = 'peliculas'
blacklist = ['PRIME VISIONI', 'ULTIME SERIE TV', 'ULTIMI FILM']
patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a></li>'
patronBlock = r'<div class="container home-cats">(?P<block>.*?)<div class="clear">'
#debug = True
return locals()
def select(item):
support.log('select --->', item)
## debug = True
#support.dbg()
data = httptools.downloadpage(item.url, headers=headers).data
data = re.sub('\n|\t', ' ', data)
data = re.sub(r'>\s+<', '> <', data)
if 'continua con il video' in data.lower():
## block = scrapertools.find_single_match(data, r'<div class="col-md-8 bg-white rounded-left p-5"><div>(.*?)<div style="margin-left: 0.5%; color: #FFF;">')
## if re.findall('rel="category tag">serie', data, re.IGNORECASE):
support.log('select = ### è un film ###')
return findvideos(Item(channel=item.channel,
title=item.title,
fulltitle=item.fulltitle,
url=item.url,
#args='serie',
contentType='movie',
data1 = data
))
else:
support.log('select = ### è una serie ###')
return episodios(Item(channel=item.channel,
title=item.title,
fulltitle=item.fulltitle,
url=item.url,
#args='serie',
contentType='tvshow',
data1 = data
))
############## Fondo Pagina
def search(item, text):
support.log('search ->', item)
itemlist = []
text = text.replace(' ', '+')
item.url = host + '/?s=' + text
item.args = 'search'
try:
item.contentType = 'episode' # non fa uscire le voci nel context menu
return peliculas(item)
# Se captura la excepcion, para no interrumpir al buscador global si un canal falla
except:
import sys
for line in sys.exc_info():
support.log('search log:', line)
return []
def newest(categoria):
support.log('newest ->', categoria)
itemlist = []
item = Item()
try:
if categoria == 'series':
item.contentType = 'tvshow'
item.url = host+'/aggiornamenti-serie-tv'
item.args = 'novita'
else:
item.contentType = 'movie'
item.url = host+'/category/film'
item.action = 'peliculas'
itemlist = peliculas(item)
if itemlist[-1].action == 'peliculas':
itemlist.pop()
# Continua la ricerca in caso di errore
except:
import sys
for line in sys.exc_info():
support.log('newest log: ', {0}.format(line))
return []
return itemlist
def findvideos(item): def findvideos(item):
support.log('findvideos ->', item)
itemlist = []
if item.contentType != 'movie': if item.contentType != 'movie':
return support.server(item, item.url) links = support.match(item.url, r'href="([^"]+)"')[0]
else: else:
links = str(support.match(item, r'SRC="([^"]+)"', patronBlock=r'<div class="col-md-10">(.+?)<div class="swappable" id="links">')[0]) matchData = item.data if item.data else item
if links: links = support.match(matchData, r'(?:SRC|href)="([^"]+)"', patronBlock=r'<div class="col-md-10">(.+?)<div class="ads">')[0]
links = links.replace('#', 'speedvideo.net') data = ''
return support.server(item, links) from lib.unshortenit import unshorten_only
else: for link in links:
return support.server(item) support.log('URL=',link)
url, c = unshorten_only(link.replace('#', 'speedvideo.net'))
data += url + '\n'
return support.server(item, data)
-1
View File
@@ -7,6 +7,5 @@
"thumbnail": "dreamsub.png", "thumbnail": "dreamsub.png",
"banner": "dreamsub.png", "banner": "dreamsub.png",
"categories": ["anime", "vos"], "categories": ["anime", "vos"],
"not_active": ["include_in_newest"],
"settings": [] "settings": []
} }
+82 -238
View File
@@ -2,214 +2,53 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
# Canale per 'dreamsub' # Canale per 'dreamsub'
# ------------------------------------------------------------ # ------------------------------------------------------------
# ------------------------------------------------------------
"""
Problemi noti che non superano il test del canale:
- Nessuno noto!
Avvisi per i tester:
1. Gli episodi sono divisi per pagine di 20
2. In Novità->Anime, cliccare sulla home il bottone "Ultime inserite"
Se avete più titoli in KOD, ridimensiona il browser in modo che si vedano i titoli
a gruppi di 3 e ricontrollare, è un problema del sito.
3.Passaggi per Aggiungere in videoteca e/o scaricare Serie:
1. sul titolo -> menu contestuale -> Rinumerazione
Solo dopo questo passaggio appariranno le voci, sul titolo -> menu contestuale ->:
- Aggiungi in videoteca (senza rinumerazione non appare
la voce)
- Scarica Serie e Scarica Stagione ( Se download Abilitato! )
4. ### PIù IMPORTANTE!!! ###
#### NON E' DA CONSIDERARE ERRORE NEL TEST QUANTO RIPORTATO DI SEGUITO!!!! ####
1. Il sito permette un filtro tra anime e film, tramite url.
Se nell'url c'è /anime/, sul titolo e proseguendo fino alla pagina del video, saranno
presenti le voci:
- 'Rinumerazione', prima, e dopo: 'Aggiungi in videoteca', 'Scarica Serie' etc...
Tutto il resto è trattato come film e si avranno le voci solite:
AD eccezione per quei "FILM" che hanno 2 o più titoli all'interno, in questo caso:
1. Non apparirà nessuna voce tra "Aggiungi in videoteca" e "Scarica Film" e nemmeno "rinumerazione"
2. Dopo essere entrato nella pagina del Titolo Principale, troverai una lista di titoli dove sarà possibile scaricare
il filmato (chiamato EPISODIO) stessa cosa accedendo alla pagina ultima del video
3. Questi TITOLI NON POSSONO ESSERE AGGIUNTI IN VIDEOTECA
le voci "Scarica FILM" si avranno dopo.
Es:
https://www.dreamsub.stream/movie/5-centimetri-al-secondo -> film ma ha 3 titoli
Il Canale NON è presente nelle novità(globale) -> Anime
"""
# Qui gli import
import re
from core import support from core import support
from platformcode import config
from core import scrapertools, httptools, servertools, tmdb
from core.item import Item
##### fine import host = support.config.get_channel_url()
host = config.get_channel_url()
headers = [['Referer', host]] headers = [['Referer', host]]
# server di esempio...
list_servers = ['directo', 'verystream', 'streamango', 'openload']
# quality di esempio
list_quality = ['default']
#### Inizio delle def principali ###
@support.menu @support.menu
def mainlist(item): def mainlist(item):
support.log(item) support.log(item)
anime = ['/anime', anime = ['/search?typeY=tv',
## ('Novità', ['']), ('Movie', ['/search?typeY=movie', 'peliculas', '', 'movie']),
## ('OAV', ['/search/oav', 'peliculas', 'oav']), ('OAV', ['/search?typeY=oav', 'peliculas', '', 'tvshow']),
## ('OVA', ['/search/ova', 'peliculas', 'ova']), ('Spinoff', ['/search?typeY=spinoff', 'peliculas', '', 'tvshow']),
('Movie', ['/search/movie', 'peliculas', '', 'movie']), ('Generi', ['','menu','Generi']),
('Film', ['/search/film', 'peliculas', '', 'movie']), ('Stato', ['','menu','Stato']),
('Categorie', ['/filter?genere=','genres']), ('Ultimi Episodi', ['', 'peliculas', ['last', 'episodiRecenti']]),
## ('Ultimi Episodi', ['', 'last']) ('Ultimi Aggiornamenti', ['', 'peliculas', ['last', 'episodiNuovi']])
] ]
return locals() return locals()
@support.scrape
def peliculas(item):
support.log(item)
#dbg # decommentare per attivare web_pdb
anime = True
if item.args == 'newest':
patronBlock = r'<div class="showRoomGoLeft" sr="ultime"></div>(?P<block>.*?)<div class="showRoomGoRight" sr="ultime">'
else:
patronBlock = r'<input type="submit" value="Vai!" class="blueButton">(?P<block>.*?)<div class="footer">'
## patron = r'<div class="showStreaming"> <b>(?P<title>[^<]+).+?Stato streaming: '\
## '(?:[^<]+)<.*?Lingua:[ ](?P<lang1>ITA\/JAP|ITA|JAP)?(?:[ ])?'\
## '(?P<lang2>SUB ITA)?<br>.+?href="(?P<url>[^"]+)".+?'\
## 'background: url\((?P<thumb>[^"]+)\).+?<div class="tvTitle">.+?'\
## '<strong>Anno di inizio</strong>: (?P<year>\d+)<br>'
patron = r'<div class="showStreaming"> <b>(?P<title>[^<]+).+?Stato streaming: (?:[^<]+)<.*?Lingua:[ ](?P<lang1>ITA\/JAP|ITA|JAP)?(?:[ ])?(?P<lang2>SUB ITA)?<br>.+?href="(?P<url>[^"]+)".+?background: url\((?P<thumb>[^"]+)\).+?<div class="tvTitle">.+?Episodi[^>]+>.\s?(?P<nep>\d+).+?<strong>Anno di inizio</strong>: (?P<year>\d+)<br>'
patronNext = '<li class="currentPage">[^>]+><li[^<]+<a href="([^"]+)">'
def itemHook(item):
support.log("ITEMHOOK -> ", item)
item = language(item)
if 'anime' in item.url:
item.contentType = 'tvshow'
item.action = 'episodios'
#item.args = 'anime'
else:
if item.nep == '1':
item.contentType = 'movie'
item.action = 'findvideos'
else:
item.contentType = 'episode'
item.args = ''
item.nep = item.nep
item.action = 'findmovie'
return item
#debug = True
return locals()
@support.scrape @support.scrape
def episodios(item): def menu(item):
support.log(item)
#support.dbg()
action = 'findvideos'
patronBlock = r'<div class="seasonEp">(?P<block>.*?)<div class="footer">'
patron = r'<li><a href="(?P<url>[^"]+)"[^<]+<b>(?:.+?)[ ](?P<episode>\d+)<\/b>[^>]+>(?P<title>[^<]+)<\/i>[ ]\(?(?P<lang1>ITA|Sub ITA)?\s?.?\s?(?P<lang2>Sub ITA)?.+?\)?<\/a>'
def itemHook(item):
item = language(item)
return item
pagination = ''
#debug = True
return locals()
@support.scrape
def genres(item):
support.log(item)
#dbg
item.contentType = '' item.contentType = ''
action = 'peliculas' action = 'peliculas'
blacklist = ['tutti']
patron = r'<option value="(?P<title>[^"]+)">' patronBlock = r'<div class="filter-header"><b>%s</b>(?P<block>.*?)<div class="filter-box">' % item.args
patronBlock = r'<select name="genere" id="genere" class="selectInput">(?P<block>.*?)</select>' patronMenu = r'<a class="[^"]+" data-state="[^"]+" (?P<url>[^>]+)>[^>]+></i>[^>]+></i>[^>]+></i>(?P<title>[^>]+)</a>'
def itemHook(item): def itemHook(item):
item.contentTitle = item.contentTitle.replace(' ', '+') for Type, ID in support.match(item.url, r'data-type="([^"]+)" data-id="([^"]+)"')[0]:
item.url = host+'/filter?genere='+item.contentTitle item.url = host + '/search?' + Type + 'Y=' + ID
return item return item
#debug = True
return locals() return locals()
@support.scrape
def findmovie(item):
support.log(item)
patronBlock = r'<div class="seasonEp">(?P<block>.*?)<div class="footer">'
item.contentType = 'episode'
item.nep = 2
patron = r'<li><a href="(?P<url>[^"]+)"[^>]+>.(?P<title2>.+?)-.+?-[ ]<b>(?P<title>.+?)</b>\s+\(?(?P<lang1>ITA)?\s?(?P<lang2>Sub ITA)?.+?\)?'
def itemHook(item):
item = language(item)
return item
#debug = True
return locals()
def language(item):
lang = []
if item.lang1:
if item.lang1.lower() == 'ita/jap' or item.lang1.lower() == 'ita':
lang.append('ITA')
if item.lang1.lower() == 'jap' and item.lang1.lower() == 'sub ita':
lang.append('Sub-ITA')
if item.lang2:
if item.lang2.lower() == 'sub ita':
lang.append('Sub-ITA')
item.contentLanguage = lang
if len(lang) ==2:
item.title += support.typo(lang[0], '_ [] color kod') + support.typo(lang[1], '_ [] color kod')
#item.show += support.typo(lang[0], '_ [] color kod') + support.typo(lang[1], '_ [] color kod')
elif len(lang) == 1:
item.title += support.typo(lang[0], '_ [] color kod')
#item.show += support.typo(lang[0], '_ [] color kod')
return item
def search(item, text): def search(item, text):
support.log('search', item) support.log(text)
itemlist = []
text = text.replace(' ', '+') text = text.replace(' ', '+')
item.url = host + '/search/' + text item.url = host + '/search/' + text
item.args = 'search' item.args = 'search'
try: try:
return peliculas(item) return peliculas(item)
# Se captura la excepcion, para no interrumpir al buscador global si un canal falla # Continua la ricerca in caso di errore
except: except:
import sys import sys
for line in sys.exc_info(): for line in sys.exc_info():
@@ -217,77 +56,82 @@ def search(item, text):
return [] return []
# da adattare... ( support.server ha vari parametri ) def newest(categoria):
#support.server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True) support.log(categoria)
item = support.Item()
try:
if categoria == "anime":
item.url = host
item.args = ['last', 'episodiNuovi']
return peliculas(item)
# Continua la ricerca in caso di errore
except:
import sys
for line in sys.exc_info():
support.logger.error("{0}".format(line))
return []
@support.scrape
def peliculas(item):
anime = True
if 'movie' in item.url:
item.contentType = 'movie'
action = 'findvideos'
else:
item.contentType = 'tvshow'
action = 'episodios'
if len(item.args) > 1 and item.args[0] == 'last':
patronBlock = r'<div id="%s"[^>]+>(?P<block>.*?)<div class="vistaDettagliata"' % item.args[1]
patron = r'<li>\s*<a href="(?P<url>[^"]+)" title="(?P<title>[^"]+)" class="thumb">[^>]+>[^>]+>[^>]+>\s*[EePp]+\s*(?P<episode>\d+)[^>]+>[^>]+>[^>]+>(?P<lang>[^<]*)<[^>]+>[^>]+>\s<img src="(?P<thumb>[^"]+)"'
else:
patron = r'<div class="showStreaming"> <b>(?P<title>[^<]+)[^>]+>[^>]+>\s*Stato streaming: (?:[^<]+)<[^>]+>[^>]+>\s*Lingua:[ ](?P<lang>ITA\/JAP|ITA|JAP|SUB ITA)?[^>]+>[^>]+>\s*<a href="(?P<url>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>\s*<div class="[^"]+" style="background: url\((?P<thumb>[^\)]+)\)'
patronNext = '<li class="currentPage">[^>]+><li[^<]+<a href="([^"]+)">'
return locals()
@support.scrape
def episodios(item):
anime = True
pagination = 100
if item.data:
data = item.data
patron = r'<div class="sli-name">\s*<a href="(?P<url>[^"]+)"[^>]+>(?P<title>[^<]+)<'
return locals()
def findvideos(item): def findvideos(item):
support.log("ITEM ---->", item)
itemlist = [] itemlist = []
support.log()
data = httptools.downloadpage(item.url).data matches, data = support.match(item, r'<a href="([^"]+)"', r'<div style="white-space: (.*?)<div id="main-content"')
data = re.sub(r'\n|\t', ' ', data)
data = re.sub(r'>\s\s*<', '><', data)
patronBlock = r'LINK STREAMING(?P<block>.*?)LINK DOWNLOAD'
patron = r'href="(.+?)"'
block = scrapertools.find_single_match(data, patronBlock)
urls = scrapertools.find_multiple_matches(block, patron)
#support.regexDbg(item, patron, headers, data=data)
for url in urls: if not matches:
titles = item.infoLabels['title'] item.data = data
lang = '' item.contentType = 'tvshow'
if 'sub_ita' in url.lower(): return episodios(item)
lang = 'Sub-ITA'
else:
lang = 'ITA'
if 'keepem.online' in data: matches.sort()
urls = scrapertools.find_multiple_matches(data, r'(https://keepem\.online/f/[^"]+)"')
for url in urls:
url = httptools.downloadpage(url).url
itemlist += servertools.find_video_items(data=url)
elif 'keepsetsu' in url.lower() or 'woof' in url.lower(): for url in matches:
if 'keepsetsu' in url.lower(): lang = url.split('/')[-2]
support.log("keepsetsu url -> ", url ) quality = url.split('/')[-1]
data = httptools.downloadpage(url).url
support.log("LINK-DATA :", data)
data = httptools.downloadpage(data).data
support.log("LINK-DATA2 :", data)
video_urls = scrapertools.find_single_match(data, r'<meta name="description" content="([^"]+)"')
else:
data = httptools.downloadpage(url).data
#host_video = scrapertools.find_single_match(data, r'var thisPageUrl = "(http[s]\:\/\/[^\/]+).+?"')
host_video = scrapertools.find_single_match(data, r'(?:let|var) thisPageUrl = "(http[s]\:\/\/[^\/]+).+?"')
link = scrapertools.find_single_match(data, r'<video src="([^"]+)"')
video_urls = host_video+link
title_show = support.typo(titles,'_ bold') + support.typo(lang,'_ [] color kod')
itemlist.append( itemlist.append(
support.Item(channel=item.channel, support.Item(channel=item.channel,
action="play", action="play",
contentType=item.contentType, contentType=item.contentType,
title=title_show, title=lang,
fulltitle=item.fulltitle, url=url,
show=item.fulltitle, contentLanguage = lang,
url=link if 'http' in link else video_urls, quality = quality,
infoLabels = item.infoLabels,
thumbnail=item.thumbnail,
contentSerieName= item.fulltitle,
contentTitle=title_show,
contentLanguage = 'ITA' if lang == [] else lang,
args=item.args,
server='directo', server='directo',
)) ))
if item.contentType != 'episode' and int(item.nep) < 2 : return support.server(item, itemlist=itemlist)
# Link Aggiungi alla Libreria
if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findservers':
support.videolibrary(itemlist, item)
# link per scaricare
if config.get_setting('downloadenabled'):
support.download(itemlist, item)
return itemlist
+1 -1
View File
@@ -253,7 +253,7 @@ def downloadpage(url, **opt):
load_cookies() load_cookies()
domain = urlparse.urlparse(url).netloc domain = urlparse.urlparse(url).netloc
CF = False CF = False
if domain in ['www.guardaserie.media', 'casacinema.space', 'wstream.video', 'akvideo.stream', 'backin.net']: if domain in ['www.guardaserie.media', 'casacinema.space', 'wstream.video', 'akvideo.stream', 'backin.net', 'dreamsub.stream']:
from lib import cloudscraper from lib import cloudscraper
session = cloudscraper.create_scraper() session = cloudscraper.create_scraper()
CF = True CF = True
+26 -25
View File
@@ -160,7 +160,7 @@ def cache_response(fn):
conn = sqlite3.connect(fname, timeout=15) conn = sqlite3.connect(fname, timeout=15)
c = conn.cursor() c = conn.cursor()
url = re.sub('&year=-', '', args[0]) url = re.sub('&year=-', '', args[0])
logger.error('la url %s' % url) # logger.error('la url %s' % url)
url_base64 = base64.b64encode(url) url_base64 = base64.b64encode(url)
c.execute("SELECT response, added FROM tmdb_cache WHERE url=?", (url_base64,)) c.execute("SELECT response, added FROM tmdb_cache WHERE url=?", (url_base64,))
row = c.fetchone() row = c.fetchone()
@@ -185,7 +185,7 @@ def cache_response(fn):
# error al obtener los datos # error al obtener los datos
except Exception, ex: except Exception, ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args)) message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message) logger.error("error in: %s" % message)
return result return result
@@ -214,10 +214,10 @@ def set_infoLabels(source, seekTmdb=True, idioma_busqueda=def_lang, forced=False
start_time = time.time() start_time = time.time()
if type(source) == list: if type(source) == list:
ret = set_infoLabels_itemlist(source, seekTmdb, idioma_busqueda) ret = set_infoLabels_itemlist(source, seekTmdb, idioma_busqueda)
logger.debug("Se han obtenido los datos de %i enlaces en %f segundos" % (len(source), time.time() - start_time)) logger.debug("The data of %i links were obtained in %f seconds" % (len(source), time.time() - start_time))
else: else:
ret = set_infoLabels_item(source, seekTmdb, idioma_busqueda) ret = set_infoLabels_item(source, seekTmdb, idioma_busqueda)
logger.debug("Se han obtenido los datos del enlace en %f segundos" % (time.time() - start_time)) logger.debug("The data of %i links were obtained in %f seconds" % (time.time() - start_time))
return ret return ret
@@ -242,6 +242,7 @@ def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda=def_lang,
negativo en caso contrario. negativo en caso contrario.
@rtype: list @rtype: list
""" """
if not config.get_setting('tmdb_active') and not forced: if not config.get_setting('tmdb_active') and not forced:
return return
import threading import threading
@@ -314,7 +315,7 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None
try: try:
numtemporada = int(item.infoLabels['season']) numtemporada = int(item.infoLabels['season'])
except ValueError: except ValueError:
logger.debug("El numero de temporada no es valido") logger.debug("The season number is not valid.")
return -1 * len(item.infoLabels) return -1 * len(item.infoLabels)
if lock: if lock:
@@ -340,7 +341,7 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None
try: try:
episode = int(item.infoLabels['episode']) episode = int(item.infoLabels['episode'])
except ValueError: except ValueError:
logger.debug("El número de episodio (%s) no es valido" % repr(item.infoLabels['episode'])) logger.debug("The episode number (%s) is not valid" % repr(item.infoLabels['episode']))
return -1 * len(item.infoLabels) return -1 * len(item.infoLabels)
# Tenemos numero de temporada y numero de episodio validos... # Tenemos numero de temporada y numero de episodio validos...
@@ -847,7 +848,7 @@ class Tmdb(object):
self.__discover() self.__discover()
else: else:
logger.debug("Creado objeto vacio") logger.debug("Created empty object")
@staticmethod @staticmethod
@cache_response @cache_response
@@ -879,7 +880,7 @@ class Tmdb(object):
# error al obtener los datos # error al obtener los datos
except Exception, ex: except Exception, ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args)) message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message) logger.error("error in: %s" % message)
dict_data = {} dict_data = {}
return dict_data return dict_data
@@ -895,7 +896,7 @@ class Tmdb(object):
url = ('http://api.themoviedb.org/3/genre/%s/list?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s' url = ('http://api.themoviedb.org/3/genre/%s/list?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s'
% (tipo, idioma)) % (tipo, idioma))
try: try:
logger.info("[Tmdb.py] Rellenando dicionario de generos") logger.info("[Tmdb.py] Filling in dictionary of genres")
resultado = cls.get_json(url) resultado = cls.get_json(url)
lista_generos = resultado["genres"] lista_generos = resultado["genres"]
@@ -903,7 +904,7 @@ class Tmdb(object):
for i in lista_generos: for i in lista_generos:
cls.dic_generos[idioma][tipo][str(i["id"])] = i["name"] cls.dic_generos[idioma][tipo][str(i["id"])] = i["name"]
except: except:
logger.error("Error generando diccionarios") logger.error("Error generating dictionaries")
def __by_id(self, source='tmdb'): def __by_id(self, source='tmdb'):
@@ -923,7 +924,7 @@ class Tmdb(object):
'&language=%s' % (self.busqueda_id, source, self.busqueda_idioma)) '&language=%s' % (self.busqueda_id, source, self.busqueda_idioma))
buscando = "%s: %s" % (source.capitalize(), self.busqueda_id) buscando = "%s: %s" % (source.capitalize(), self.busqueda_id)
logger.info("[Tmdb.py] Buscando %s:\n%s" % (buscando, url)) logger.info("[Tmdb.py] Searching %s:\n%s" % (buscando, url))
resultado = self.get_json(url) resultado = self.get_json(url)
if resultado: if resultado:
@@ -940,8 +941,8 @@ class Tmdb(object):
else: else:
# No hay resultados de la busqueda # No hay resultados de la busqueda
msg = "La busqueda de %s no dio resultados." % buscando msg = "The search of %s gave no results" % buscando
logger.debug(msg) # logger.debug(msg)
def __search(self, index_results=0, page=1): def __search(self, index_results=0, page=1):
self.result = ResultDictDefault() self.result = ResultDictDefault()
@@ -963,7 +964,7 @@ class Tmdb(object):
url += '&year=%s' % self.busqueda_year url += '&year=%s' % self.busqueda_year
buscando = self.busqueda_texto.capitalize() buscando = self.busqueda_texto.capitalize()
logger.info("[Tmdb.py] Buscando %s en pagina %s:\n%s" % (buscando, page, url)) logger.info("[Tmdb.py] Searching %s on page %s:\n%s" % (buscando, page, url))
resultado = self.get_json(url) resultado = self.get_json(url)
total_results = resultado.get("total_results", 0) total_results = resultado.get("total_results", 0)
@@ -984,7 +985,7 @@ class Tmdb(object):
if index_results >= len(results): if index_results >= len(results):
# Se ha solicitado un numero de resultado mayor de los obtenidos # Se ha solicitado un numero de resultado mayor de los obtenidos
logger.error( logger.error(
"La busqueda de '%s' dio %s resultados para la pagina %s\nImposible mostrar el resultado numero %s" "The search for '%s' gave %s results for the page %s \n It is impossible to show the result number %s"
% (buscando, len(results), page, index_results)) % (buscando, len(results), page, index_results))
return 0 return 0
@@ -997,7 +998,7 @@ class Tmdb(object):
else: else:
# No hay resultados de la busqueda # No hay resultados de la busqueda
msg = "La busqueda de '%s' no dio resultados para la pagina %s" % (buscando, page) msg = "The search for '%s' gave no results for page %s" % (buscando, page)
logger.error(msg) logger.error(msg)
return 0 return 0
@@ -1021,7 +1022,7 @@ class Tmdb(object):
url = ('http://api.themoviedb.org/3/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&%s' url = ('http://api.themoviedb.org/3/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&%s'
% (type_search, "&".join(params))) % (type_search, "&".join(params)))
logger.info("[Tmdb.py] Buscando %s:\n%s" % (type_search, url)) logger.info("[Tmdb.py] Searcing %s:\n%s" % (type_search, url))
resultado = self.get_json(url) resultado = self.get_json(url)
total_results = resultado.get("total_results", -1) total_results = resultado.get("total_results", -1)
@@ -1045,7 +1046,7 @@ class Tmdb(object):
if index_results >= len(results): if index_results >= len(results):
logger.error( logger.error(
"La busqueda de '%s' no dio %s resultados" % (type_search, index_results)) "The search for '%s' did not give %s results" % (type_search, index_results))
return 0 return 0
# Retornamos el numero de resultados de esta pagina # Retornamos el numero de resultados de esta pagina
@@ -1061,7 +1062,7 @@ class Tmdb(object):
return len(self.results) return len(self.results)
else: else:
# No hay resultados de la busqueda # No hay resultados de la busqueda
logger.error("La busqueda de '%s' no dio resultados" % type_search) logger.error("The search for '%s' gave no results" % type_search)
return 0 return 0
def load_resultado(self, index_results=0, page=1): def load_resultado(self, index_results=0, page=1):
@@ -1311,20 +1312,20 @@ class Tmdb(object):
url = "http://api.themoviedb.org/3/tv/%s/season/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s" \ url = "http://api.themoviedb.org/3/tv/%s/season/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s" \
"&append_to_response=credits" % (self.result["id"], numtemporada, self.busqueda_idioma) "&append_to_response=credits" % (self.result["id"], numtemporada, self.busqueda_idioma)
buscando = "id_Tmdb: " + str(self.result["id"]) + " temporada: " + str(numtemporada) + "\nURL: " + url buscando = "id_Tmdb: " + str(self.result["id"]) + " season: " + str(numtemporada) + "\nURL: " + url
logger.info("[Tmdb.py] Buscando " + buscando) logger.info("[Tmdb.py] Searcing " + buscando)
try: try:
self.temporada[numtemporada] = self.get_json(url) self.temporada[numtemporada] = self.get_json(url)
except: except:
logger.error("No se ha podido obtener la temporada") logger.error("Unable to get the season")
self.temporada[numtemporada] = {"status_code": 15, "status_message": "Failed"} self.temporada[numtemporada] = {"status_code": 15, "status_message": "Failed"}
self.temporada[numtemporada] = {"episodes": {}} self.temporada[numtemporada] = {"episodes": {}}
if "status_code" in self.temporada[numtemporada]: if "status_code" in self.temporada[numtemporada]:
#Se ha producido un error #Se ha producido un error
msg = config.get_localized_string(70496) + buscando + config.get_localized_string(70497) msg = config.get_localized_string(70496) + buscando + config.get_localized_string(70497)
msg += "\nError de tmdb: %s %s" % ( msg += "\nTmdb error: %s %s" % (
self.temporada[numtemporada]["status_code"], self.temporada[numtemporada]["status_message"]) self.temporada[numtemporada]["status_code"], self.temporada[numtemporada]["status_message"])
logger.debug(msg) logger.debug(msg)
self.temporada[numtemporada] = {} self.temporada[numtemporada] = {}
@@ -1351,7 +1352,7 @@ class Tmdb(object):
capitulo = int(capitulo) capitulo = int(capitulo)
numtemporada = int(numtemporada) numtemporada = int(numtemporada)
except ValueError: except ValueError:
logger.debug("El número de episodio o temporada no es valido") logger.debug("The episode or season number is not valid")
return {} return {}
temporada = self.get_temporada(numtemporada) temporada = self.get_temporada(numtemporada)
@@ -1361,7 +1362,7 @@ class Tmdb(object):
if len(temporada["episodes"]) == 0 or len(temporada["episodes"]) < capitulo: if len(temporada["episodes"]) == 0 or len(temporada["episodes"]) < capitulo:
# Se ha producido un error # Se ha producido un error
logger.error("Episodio %d de la temporada %d no encontrado." % (capitulo, numtemporada)) logger.error("Episode %d of the season %d not found." % (capitulo, numtemporada))
return {} return {}
ret_dic = dict() ret_dic = dict()
+57 -13
View File
@@ -1,4 +1,3 @@
# https://github.com/VeNoMouS/cloudscraper
import logging import logging
import re import re
import sys import sys
@@ -38,7 +37,7 @@ except ImportError:
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
__version__ = '1.2.16' __version__ = '1.2.19'
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
@@ -163,7 +162,6 @@ class CloudScraper(Session):
def request(self, method, url, *args, **kwargs): def request(self, method, url, *args, **kwargs):
# pylint: disable=E0203 # pylint: disable=E0203
if kwargs.get('proxies') and kwargs.get('proxies') != self.proxies: if kwargs.get('proxies') and kwargs.get('proxies') != self.proxies:
self.proxies = kwargs.get('proxies') self.proxies = kwargs.get('proxies')
@@ -198,6 +196,7 @@ class CloudScraper(Session):
else: else:
if not resp.is_redirect and resp.status_code not in [429, 503]: if not resp.is_redirect and resp.status_code not in [429, 503]:
self._solveDepthCnt = 0 self._solveDepthCnt = 0
return resp return resp
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
@@ -243,7 +242,7 @@ class CloudScraper(Session):
return False return False
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
# check if the response contains a valid Cloudflare reCaptcha challenge # check if the response contains Firewall 1020 Error
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
@staticmethod @staticmethod
@@ -270,10 +269,7 @@ class CloudScraper(Session):
def is_Challenge_Request(self, resp): def is_Challenge_Request(self, resp):
if self.is_Firewall_Blocked(resp): if self.is_Firewall_Blocked(resp):
sys.tracebacklimit = 0 sys.tracebacklimit = 0
raise RuntimeError( raise RuntimeError('Cloudflare has blocked this request (Code 1020 Detected).')
'Cloudflare has a restriction on your IP (Code 1020 Detected), '
'you are BLOCKED.'
)
if self.is_reCaptcha_Challenge(resp) or self.is_IUAM_Challenge(resp): if self.is_reCaptcha_Challenge(resp) or self.is_IUAM_Challenge(resp):
return True return True
@@ -434,6 +430,7 @@ class CloudScraper(Session):
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
if submit_url: if submit_url:
def updateAttr(obj, name, newValue): def updateAttr(obj, name, newValue):
try: try:
obj[name].update(newValue) obj[name].update(newValue)
@@ -450,13 +447,18 @@ class CloudScraper(Session):
'data', 'data',
submit_url['data'] submit_url['data']
) )
urlParsed = urlparse(resp.url)
cloudflare_kwargs['headers'] = updateAttr( cloudflare_kwargs['headers'] = updateAttr(
cloudflare_kwargs, cloudflare_kwargs,
'headers', 'headers',
{'Referer': resp.url} {
'Origin': '{}://{}'.format(urlParsed.scheme, urlParsed.netloc),
'Referer': resp.url
}
) )
ret = self.request( challengeSubmitResponse = self.request(
'POST', 'POST',
submit_url['url'], submit_url['url'],
**cloudflare_kwargs **cloudflare_kwargs
@@ -464,13 +466,44 @@ class CloudScraper(Session):
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
# Return response if Cloudflare is doing content pass through instead of 3xx # Return response if Cloudflare is doing content pass through instead of 3xx
# else request with redirect URL also handle protocol scheme change http -> https
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
if not ret.is_redirect: if not challengeSubmitResponse.is_redirect:
return ret return challengeSubmitResponse
else:
cloudflare_kwargs = deepcopy(kwargs)
if not urlparse(challengeSubmitResponse.headers['Location']).netloc:
cloudflare_kwargs['headers'] = updateAttr(
cloudflare_kwargs,
'headers',
{'Referer': '{}://{}'.format(urlParsed.scheme, urlParsed.netloc)}
)
return self.request(
resp.request.method,
'{}://{}{}'.format(
urlParsed.scheme,
urlParsed.netloc,
challengeSubmitResponse.headers['Location']
),
**cloudflare_kwargs
)
else:
redirectParsed = urlparse(challengeSubmitResponse.headers['Location'])
cloudflare_kwargs['headers'] = updateAttr(
cloudflare_kwargs,
'headers',
{'Referer': '{}://{}'.format(redirectParsed.scheme, redirectParsed.netloc)}
)
return self.request(
resp.request.method,
challengeSubmitResponse.headers['Location'],
**cloudflare_kwargs
)
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
# Cloudflare is doing http 3xx instead of pass through again.... # We shouldn't be here...
# Re-request the original query and/or process again.... # Re-request the original query and/or process again....
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
@@ -554,6 +587,17 @@ class CloudScraper(Session):
# ------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------- #
if ssl.OPENSSL_VERSION_INFO < (1, 1, 1):
print(
"DEPRECATION: The OpenSSL being used by this python install ({}) does not meet the minimum supported "
"version (>= OpenSSL 1.1.1) in order to support TLS 1.3 required by Cloudflare, "
"You may encounter an unexpected reCaptcha or cloudflare 1020 blocks.".format(
ssl.OPENSSL_VERSION
)
)
# ------------------------------------------------------------------------------- #
create_scraper = CloudScraper.create_scraper create_scraper = CloudScraper.create_scraper
get_tokens = CloudScraper.get_tokens get_tokens = CloudScraper.get_tokens
get_cookie_string = CloudScraper.get_cookie_string get_cookie_string = CloudScraper.get_cookie_string
+2 -58
View File
@@ -77,61 +77,8 @@
<setting id="custom_theme" type="folder" label="70565" default="" visible="eq(-1,true)"/> <setting id="custom_theme" type="folder" label="70565" default="" visible="eq(-1,true)"/>
<setting id="infoplus_set" type="labelenum" label="70128" lvalues="70129|70130" default="70129"/> <setting id="infoplus_set" type="labelenum" label="70128" lvalues="70129|70130" default="70129"/>
<setting id="video_thumbnail_type" type="enum" label="70131" lvalues="70132|70133" default="0"/> <setting id="video_thumbnail_type" type="enum" label="70131" lvalues="70132|70133" default="0"/>
<!-- <setting label="70167" type="lsep"/>
<setting id="unify" type="bool" label="70134" default="false"/>
<setting id="title_color" type="bool" label="70135" default="false" visible="eq(-1,true)"/>
<setting id="movie_color" type="labelenum" label="70137"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-1,true)+eq(-2,true)"/>
<setting id="tvshow_color" type="labelenum" label="30123"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-2,true)+eq(-3,true)"/>
<setting id="year_color" type="labelenum" label="60232"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-3,true)+eq(-4,true)"/>
<setting id="rating_1_color" type="labelenum" label="70138"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-4,true)+eq(-5,true)"/>
<setting id="rating_2_color" type="labelenum" label="70139"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-5,true)+eq(-6,true)"/>
<setting id="rating_3_color" type="labelenum" label="70140"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-6,true)+eq(-7,true)"/>
<setting id="quality_color" type="labelenum" label="70141"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-7,true)+eq(-8,true)"/>
<setting id="cast_color" type="labelenum" label="59980"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-8,true)+eq(-9,true)"/>
<setting id="lat_color" type="labelenum" label="59981"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-9,true)+eq(-10,true)"/>
<setting id="vose_color" type="labelenum" label="70142"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-10,true)+eq(-11,true)"/>
<setting id="sub-ita_color" type="labelenum" label="70566"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-11,true)+eq(-12,true)"/>
<setting id="vos_color" type="labelenum" label="70143"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-12,true)+eq(-13,true)"/>
<setting id="vo_color" type="labelenum" label="70144"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-13,true)+eq(-14,true)"/>
<setting id="server_color" type="labelenum" label="70145"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-14,true)+eq(-15,true)"/>
<setting id="library_color" type="labelenum" label="70146"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-15,true)+eq(-16,true)"/>
<setting id="update_color" type="labelenum" label="70147"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-16,true)+eq(-17,true)"/>
<setting id="no_update_color" type="labelenum" label="70148"
values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]"
default="white" visible="eq(-17,true)+eq(-18,true)"/> -->
</category> </category>
<!-- Other --> <!-- Other -->
<category label="70149"> <category label="70149">
<setting label="70150" type="lsep"/> <setting label="70150" type="lsep"/>
@@ -144,6 +91,7 @@
<setting type="sep"/> <setting type="sep"/>
<setting label="70154" type="lsep"/> <setting label="70154" type="lsep"/>
<setting id="tmdb_active" default="true" visible="false"/>
<setting id="tmdb_threads" type="labelenum" values="5|10|15|20|25|30" label="70155" default="20"/> <setting id="tmdb_threads" type="labelenum" values="5|10|15|20|25|30" label="70155" default="20"/>
<setting id="tmdb_plus_info" type="bool" label="70156" default="false"/> <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" type="bool" label="70157" default="true"/>
@@ -162,9 +110,6 @@
<setting label="Lista activa" type="text" id="lista_activa" default="kodfavorites-default.json" visible="false"/> <setting label="Lista activa" type="text" id="lista_activa" default="kodfavorites-default.json" visible="false"/>
<!-- <setting type="sep"/>
<setting label="70583" type="lsep"/>
<setting id="addon_quasar_update" type="bool" label="70584" default="false"/> -->
</category> </category>
<!-- Custom Start --> <!-- Custom Start -->
<category label="70121"> <category label="70121">
@@ -179,5 +124,4 @@
</category> </category>
</settings> </settings>