KoD 1.4.1

- ridisegnata la finestra della scelta film/serietv quando si aggiunge in videoteca\n- modifiche minori, qualche fix ai canali/server ed alla ricerca alternativa\n
This commit is contained in:
marco
2020-10-19 18:33:08 +02:00
parent e0802264f3
commit 384f06ded9
54 changed files with 610 additions and 1087 deletions

View File

@@ -1,4 +1,4 @@
<addon id="plugin.video.kod" name="Kodi on Demand" version="1.4" provider-name="KoD Team"> <addon id="plugin.video.kod" name="Kodi on Demand" version="1.4.1" provider-name="KoD Team">
<requires> <requires>
<!-- <import addon="script.module.libtorrent" optional="true"/> --> <!-- <import addon="script.module.libtorrent" optional="true"/> -->
<import addon="metadata.themoviedb.org"/> <import addon="metadata.themoviedb.org"/>
@@ -26,9 +26,8 @@
<screenshot>resources/media/themes/ss/2.png</screenshot> <screenshot>resources/media/themes/ss/2.png</screenshot>
<screenshot>resources/media/themes/ss/3.png</screenshot> <screenshot>resources/media/themes/ss/3.png</screenshot>
</assets> </assets>
<news>- completato il supporto al futuro Kodi 19 <news>- ridisegnata la finestra della scelta film/serietv quando si aggiunge in videoteca
- ridisegnato infoplus - modifiche minori, qualche fix ai canali/server ed alla ricerca alternativa</news>
- fix vari ed eventuali</news>
<description lang="it">Naviga velocemente sul web e guarda i contenuti presenti</description> <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] <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> [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

@@ -1,48 +1,57 @@
{ {
"altadefinizione01": "https://www.altadefinizione01.green", "findhost": {
"altadefinizione01_link": "https://altadefinizione01.energy", "altadefinizione01": "https://altadefinizione01-nuovo.info",
"altadefinizioneclick": "https://altadefinizione.vote", "altadefinizioneclick": "https://altadefinizione-nuovo.me",
"animealtadefinizione": "https://www.animealtadefinizione.it", "animealtadefinizione": "https://www.animealtadefinizione.it",
"animeforce": "https://ww1.animeforce.org", "cineblog01": "https://cb01.uno",
"animeleggendari": "https://animeora.com", "eurostreaming": "https://eurostreaming.link",
"animesaturn": "https://www.animesaturn.it", "ilcorsaronero": "https://lagazzettadelcorsaro.com",
"animestream": "https://www.animeworld.tv", "seriehd": "https://nuovoindirizzo.info/seriehd/",
"animesubita": "http://www.animesubita.org", "serietvonline": "https://serietvonline.online",
"animetubeita": "http://www.animetubeita.com", "tantifilm": "https://www.tantifilm.wiki",
"animeunity": "https://www.animeunity.it", "film4k": "https://film4k-nuovo.link"
"animeuniverse": "https://www.animeuniverse.it/", },
"animeworld": "https://www.animeworld.tv", "direct": {
"casacinema": "https://www.casacinema.page", "altadefinizione01_link": "https://altadefinizione01.energy",
"cb01anime": "https://www.cineblog01.red", "animealtadefinizione": "https://www.animealtadefinizione.it",
"cinemalibero": "https://www.cinemalibero.space", "animeforce": "https://ww1.animeforce.org",
"cinetecadibologna": "http://cinestore.cinetecadibologna.it", "animeleggendari": "https://animeora.com",
"dreamsub": "https://dreamsub.stream", "animesaturn": "https://www.animesaturn.it",
"dsda": "https://www.dsda.press", "animestream": "https://www.animeworld.tv",
"fastsubita": "https://fastsubita.online", "animesubita": "http://www.animesubita.org",
"filmgratis": "https://www.filmaltadefinizione.tv", "animetubeita": "http://www.animetubeita.com",
"filmigratis": "https://filmigratis.org", "animeunity": "https://www.animeunity.it",
"filmpertutti": "https://www.filmpertutti.fun", "animeuniverse": "https://www.animeuniverse.it/",
"filmsenzalimiticc": "https://www.filmsenzalimiti01.casa", "animeworld": "https://www.animeworld.tv",
"filmstreaming01": "https://filmstreaming01.com", "casacinema": "https://www.casacinema.page",
"guardaserie_stream": "https://guardaserie.host", "cb01anime": "https://www.cineblog01.red",
"guardaseriecam": "https://guardaserie.cam", "cinemalibero": "https://www.cinemalibero.space",
"guardaserieclick": "https://www.guardaserie.blue", "cinetecadibologna": "http://cinestore.cinetecadibologna.it",
"guardaserieicu": "https://guardaserie.us", "dreamsub": "https://dreamsub.stream",
"hd4me": "https://hd4me.net", "dsda": "https://www.dsda.press",
"ilgeniodellostreaming": "https://ilgeniodellostreaming.fi", "fastsubita": "https://fastsubita.online",
"ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.tel", "filmgratis": "https://www.filmaltadefinizione.tv",
"italiaserie": "https://italiaserie.org", "filmigratis": "https://filmigratis.org",
"mondoserietv": "https://mondoserietv.fun", "filmpertutti": "https://www.filmpertutti.fun",
"piratestreaming": "https://www.piratestreaming.buzz", "filmsenzalimiticc": "https://www.filmsenzalimiti01.casa",
"polpotv": "https://polpotv.life", "filmstreaming01": "https://filmstreaming01.com",
"raiplay": "https://www.raiplay.it", "guardaserie_stream": "https://guardaserie.host",
"seriehd": "https://seriehd.group", "guardaseriecam": "https://guardaserie.cam",
"serietvonline": "https://serietvonline.biz", "guardaserieclick": "https://www.guardaserie.blue",
"serietvsubita": "http://serietvsubita.xyz", "guardaserieicu": "https://guardaserie.us",
"serietvu": "https://www.serietvu.link", "hd4me": "https://hd4me.net",
"streamingcommunity": "https://streamingcommunity.to", "ilgeniodellostreaming": "https://ilgeniodellostreaming.fi",
"streamtime": "https://t.me/s/StreamTime", "ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.tel",
"tantifilm": "https://www.tantifilm.tel", "italiaserie": "https://italiaserie.org",
"toonitalia": "https://toonitalia.org", "mondoserietv": "https://mondoserietv.fun",
"vvvvid": "https://www.vvvvid.it" "piratestreaming": "https://www.piratestreaming.buzz",
"polpotv": "https://polpotv.life",
"raiplay": "https://www.raiplay.it",
"serietvsubita": "http://serietvsubita.xyz",
"serietvu": "https://www.serietvu.link",
"streamingcommunity": "https://streamingcommunity.to",
"streamtime": "https://t.me/s/StreamTime",
"toonitalia": "https://toonitalia.org",
"vvvvid": "https://www.vvvvid.it"
}
} }

View File

@@ -54,18 +54,17 @@ from core.item import Item # per newest
# se il sito ha un link per ottenere l'url corretto in caso di oscuramenti # se il sito ha un link per ottenere l'url corretto in caso di oscuramenti
# la funzione deve ritornare l'indirizzo corretto, verrà chiamata solo se necessario (link primario irraggiungibile) # la funzione deve ritornare l'indirizzo corretto, verrà chiamata solo se necessario (link primario irraggiungibile)
def findhost(): def findhost(url):
def findhost(): permUrl = httptools.downloadpage(url, follow_redirects=False).headers
permUrl = httptools.downloadpage('https://www.cb01.uno/', follow_redirects=False).headers
if 'google' in permUrl['location']: if 'google' in permUrl['location']:
host = permUrl['location'].replace('https://www.google.it/search?q=site:', '') host = permUrl['location'].replace('https://www.google.it/search?q=site:', '')
else: else:
host = permUrl['location'] host = permUrl['location']
return host return host
# se si usa findhost # se si usa findhost metti in channels.json l'url del sito che contiene sempre l'ultimo dominio
host = config.get_channel_url(findhost) host = config.get_channel_url(findhost)
# se non si usa (metti l'url in channels.json) # se non si usa metti direttamente l'url finale in channels.json
host = config.get_channel_url() host = config.get_channel_url()
headers = [['Referer', host]] headers = [['Referer', host]]

View File

@@ -17,10 +17,9 @@ from core import scrapertools, httptools, support
from core.item import Item from core.item import Item
from platformcode import config, logger from platformcode import config, logger
#impostati dinamicamente da findhost()
def findhost(): def findhost(url):
data = httptools.downloadpage('https://altadefinizione01-nuovo.info/').data data = httptools.downloadpage(url).data
host = scrapertools.find_single_match(data, '<div class="elementor-button-wrapper"> <a href="([^"]+)"') host = scrapertools.find_single_match(data, '<div class="elementor-button-wrapper"> <a href="([^"]+)"')
return host return host

View File

@@ -21,8 +21,8 @@ from core import support
from core.item import Item from core.item import Item
from platformcode import config from platformcode import config
def findhost(): def findhost(url):
data = support.httptools.downloadpage('https://altadefinizione-nuovo.me/').data data = support.httptools.downloadpage(url).data
host = support.scrapertools.find_single_match(data, '<div class="elementor-button-wrapper"> <a href="([^"]+)"') host = support.scrapertools.find_single_match(data, '<div class="elementor-button-wrapper"> <a href="([^"]+)"')
return host return host

View File

@@ -11,8 +11,8 @@ from lib import unshortenit
from platformcode import logger, config from platformcode import logger, config
def findhost(): def findhost(url):
host = httptools.downloadpage('https://cb01.uno/', follow_redirect=True).url host = httptools.downloadpage(url, follow_redirect=True).url
if host == 'https://cb01.uno/': if host == 'https://cb01.uno/':
host = support.match(host, patron=r'<a href="([^"]+)', debug=True).match host = support.match(host, patron=r'<a href="([^"]+)', debug=True).match
return host return host

View File

@@ -5,7 +5,7 @@
"active": true, "active": true,
"thumbnail": "cinemalibero.png", "thumbnail": "cinemalibero.png",
"banner": "cinemalibero.png", "banner": "cinemalibero.png",
"categories": ["movie","tvshow"], "categories": ["movie","tvshow","anime"],
"not_active": ["include_in_newest_anime", "include_in_newest_peliculas"], "not_active": ["include_in_newest_anime", "include_in_newest_peliculas"],
"settings": [] "settings": []
} }

View File

@@ -11,7 +11,7 @@ from platformcode import config
# rimanda a .today che contiene tutti link a .plus # rimanda a .today che contiene tutti link a .plus
# def findhost(): # def findhost(url):
# permUrl = httptools.downloadpage('https://www.cinemalibero.online/', follow_redirects=False).headers # permUrl = httptools.downloadpage('https://www.cinemalibero.online/', follow_redirects=False).headers
# try: # try:
# import urlparse # import urlparse

View File

@@ -7,8 +7,8 @@
from core import httptools, support from core import httptools, support
from core.item import Item from core.item import Item
def findhost(): def findhost(url):
permUrl = httptools.downloadpage('https://eurostreaming.link/', follow_redirects=False, only_headers=True).headers permUrl = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers
host = 'https://'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') host = 'https://'+permUrl['location'].replace('https://www.google.it/search?q=site:', '')
return host return host

View File

@@ -7,8 +7,8 @@ from core import support
from platformcode import logger, config from platformcode import logger, config
def findhost(): def findhost(url):
return support.httptools.downloadpage('https://film4k-nuovo.link').url return support.httptools.downloadpage(url).url
host = config.get_channel_url(findhost) host = config.get_channel_url(findhost)

View File

@@ -7,7 +7,7 @@ from core import httptools, support
from core.item import Item from core.item import Item
from platformcode import config from platformcode import config
# def findhost(): # def findhost(url):
# page = httptools.downloadpage("https://filmpertutti.nuovo.live/").data # page = httptools.downloadpage("https://filmpertutti.nuovo.live/").data
# url = scrapertools.find_single_match(page, 'Il nuovo indirizzo di FILMPERTUTTI è <a href="([^"]+)') # url = scrapertools.find_single_match(page, 'Il nuovo indirizzo di FILMPERTUTTI è <a href="([^"]+)')
# return url # return url

View File

@@ -5,8 +5,8 @@
from core import support from core import support
def findhost(): def findhost(url):
data = support.httptools.downloadpage('https://lagazzettadelcorsaro.com/').data data = support.httptools.downloadpage(url).data
url = support.scrapertools.find_single_match(data, '<li><a href="([^"]+)') url = support.scrapertools.find_single_match(data, '<li><a href="([^"]+)')
return url[:-1] if url.endswith('/') else url return url[:-1] if url.endswith('/') else url

View File

@@ -4,17 +4,9 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
from core import support from core import support
from core.item import Item
from platformcode import config
from xml.dom import minidom
#impostati dinamicamente da findhost()
host = 'https://metalvideo.com' host = 'https://metalvideo.com'
headers={'X-Requested-With': 'XMLHttpRequest'} headers = {'X-Requested-With': 'XMLHttpRequest'}
@support.scrape @support.scrape

View File

@@ -7,7 +7,7 @@ from core import support
from core.item import Item from core.item import Item
from platformcode import logger, config from platformcode import logger, config
# def findhost(): # def findhost(url):
# return 'https://' + support.match('https://netfreex.uno/', patron='value="site:([^"]+)"').match # return 'https://' + support.match('https://netfreex.uno/', patron='value="site:([^"]+)"').match
host = config.get_channel_url() host = config.get_channel_url()

View File

@@ -7,15 +7,13 @@
from core import support, jsontools from core import support, jsontools
from core.item import Item from core.item import Item
from platformcode import config from platformcode import config
import json, datetime import datetime
host = config.get_channel_url() host = config.get_channel_url()
headers = [['Accept', 'application/ld+json']] headers = [['Accept', 'application/ld+json']]
@support.menu @support.menu
def mainlist(item): def mainlist(item):
# menu = [ # menu = [
@@ -57,8 +55,9 @@ def peliculas(item):
item.contentType='movie' item.contentType='movie'
else: else:
item.contentType='tvshow' item.contentType='tvshow'
itemlist.extend(get_itemlist_element(element, item)) itemlist.append(get_itemlist_element(element, item))
support.tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
try: try:
if support.inspect.stack()[1][3] not in ['newest']: if support.inspect.stack()[1][3] not in ['newest']:
support.nextPage(itemlist, item, next_page=json_object['hydra:view']['hydra:next']) support.nextPage(itemlist, item, next_page=json_object['hydra:view']['hydra:next'])
@@ -106,13 +105,14 @@ def search(item, texto):
json_object = jsontools.load(data) json_object = jsontools.load(data)
for movie in json_object['hydra:member']: for movie in json_object['hydra:member']:
item.contentType='movie' item.contentType='movie'
itemlist.extend(get_itemlist_element(movie,item)) itemlist.append(get_itemlist_element(movie,item))
item.url = host + "/api/shows?originalTitle="+texto+"&translations.name=" +texto item.url = host + "/api/shows?originalTitle="+texto+"&translations.name=" +texto
data = support.match(item.url, headers=headers).data data = support.match(item.url, headers=headers).data
json_object = jsontools.load(data) json_object = jsontools.load(data)
for tvshow in json_object['hydra:member']: for tvshow in json_object['hydra:member']:
item.contentType='tvshow' item.contentType='tvshow'
itemlist.extend(get_itemlist_element(tvshow,item)) itemlist.append(get_itemlist_element(tvshow,item))
support.tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
return itemlist return itemlist
# Continua la ricerca in caso di errore # Continua la ricerca in caso di errore
except: except:
@@ -121,6 +121,7 @@ def search(item, texto):
support.logger.error("%s" % line) support.logger.error("%s" % line)
return [] return []
def search_movie_by_genre(item): def search_movie_by_genre(item):
support.info() support.info()
itemlist = [] itemlist = []
@@ -134,6 +135,7 @@ def search_movie_by_genre(item):
url="%s/api/movies?genres.id=%s" %(host,genre['id']))) url="%s/api/movies?genres.id=%s" %(host,genre['id'])))
return support.thumb(itemlist, True) return support.thumb(itemlist, True)
def search_movie_by_year(item): def search_movie_by_year(item):
support.info() support.info()
now = datetime.datetime.now() now = datetime.datetime.now()
@@ -149,6 +151,7 @@ def search_movie_by_year(item):
action="peliculas")) action="peliculas"))
return itemlist return itemlist
def findvideos(item): def findvideos(item):
support.info() support.info()
itemlist = [] itemlist = []
@@ -170,9 +173,9 @@ def findvideos(item):
pass pass
return support.server(item, itemlist=itemlist) return support.server(item, itemlist=itemlist)
def get_itemlist_element(element,item): def get_itemlist_element(element,item):
support.info() support.info()
itemlist=[]
contentSerieName = '' contentSerieName = ''
contentTitle ='' contentTitle =''
try: try:
@@ -189,13 +192,13 @@ def get_itemlist_element(element,item):
except: except:
scrapedplot = "" scrapedplot = ""
try: try:
scrapedthumbnail="http://"+element['posterPath'] scrapedthumbnail="https:"+element['bestPosters'].values()[0]
except: except:
scrapedthumbnail="" scrapedthumbnail=""
try: # try:
scrapedfanart="http://"+element['backdropPath'] # scrapedfanart="http:"+element['backdropPath']
except: # except:
scrapedfanart="" # scrapedfanart=""
infoLabels = {} infoLabels = {}
if item.contentType=='movie': if item.contentType=='movie':
@@ -210,20 +213,15 @@ def get_itemlist_element(element,item):
quality='' quality=''
url="%s%s" url="%s%s"
if item.contentType=='movie': return item.clone(action=next_action,
support.tmdb.set_infoLabels_itemlist(itemlist)
itemlist.append(
item.clone(action=next_action,
title=support.typo(scrapedtitle, 'bold') + quality, title=support.typo(scrapedtitle, 'bold') + quality,
fulltitle=scrapedtitle, fulltitle=scrapedtitle,
show=scrapedtitle, show=scrapedtitle,
plot=scrapedplot, plot=scrapedplot,
fanart=scrapedfanart, # fanart=scrapedfanart,
thumbnail=scrapedthumbnail, thumbnail=scrapedthumbnail,
contentTitle=contentTitle, contentTitle=contentTitle,
contentSerieName=contentSerieName, contentSerieName=contentSerieName,
contentType=item.contentType, contentType=item.contentType,
url=url % (host, element['@id']), url=url % (host, element['@id']),
infoLabels=infoLabels)) infoLabels=infoLabels)
return itemlist

View File

@@ -5,8 +5,8 @@
from core import support from core import support
def findhost(): def findhost(url):
return support.match('https://nuovoindirizzo.info/seriehd/', patron=r'<h2[^>]+><a href="([^"]+)"').match return support.match(url, patron=r'<h2[^>]+><a href="([^"]+)"').match
host = support.config.get_channel_url(findhost) host = support.config.get_channel_url(findhost)
headers = [['Referer', host]] headers = [['Referer', host]]
@@ -31,7 +31,7 @@ def search(item, texto):
item.contentType = 'tvshow' item.contentType = 'tvshow'
item.url = host + "/?s=" + texto item.url = host + "/search/" + texto
try: try:
return peliculas(item) return peliculas(item)
# Continua la ricerca in caso di errore . # Continua la ricerca in caso di errore .

View File

@@ -21,8 +21,8 @@ from platformcode import config
from core.item import Item from core.item import Item
def findhost(): def findhost(url):
host = support.match('https://serietvonline.online', patron=r'href="([^"]+)">\s*cliccando qui').matches[-1] host = support.match(url, patron=r'href="([^"]+)">\s*cliccando qui').matches[-1]
return host return host
host = config.get_channel_url(findhost) host = config.get_channel_url(findhost)

View File

@@ -13,8 +13,8 @@ else:
from urllib import unquote from urllib import unquote
def findhost(): def findhost(url):
data = httptools.downloadpage('https://www.popcornstream-nuovo-indirizzo.online/').data data = httptools.downloadpage(url).data
return support.scrapertools.find_single_match(data, '<a href="([^"]+)') return support.scrapertools.find_single_match(data, '<a href="([^"]+)')
host = config.get_channel_url(findhost) host = config.get_channel_url(findhost)

View File

@@ -12,8 +12,8 @@ from platformcode import logger
from platformcode import config, unify from platformcode import config, unify
def findhost(): def findhost(url):
permUrl = httptools.downloadpage('https://www.tantifilm.wiki/').data permUrl = httptools.downloadpage(url).data
host = scrapertools.find_single_match(permUrl, r'Nuovo indirizzo: <a href="([^"]+)') host = scrapertools.find_single_match(permUrl, r'Nuovo indirizzo: <a href="([^"]+)')
return host return host

View File

@@ -4,18 +4,11 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
from core import support from core import support
from core.item import Item
from platformcode import config
from xml.dom import minidom
#impostati dinamicamente da findhost()
host = 'http://api.radiotime.com' host = 'http://api.radiotime.com'
headers = [['Referer', host]] headers = [['Referer', host]]
@support.scrape @support.scrape
def mainlist(item): def mainlist(item):
item.url = host item.url = host

View File

@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import urllib try:
import urllib.parse as urllib
except ImportError:
import urllib
from core import jsontools from core import jsontools, httptools
from core.item import Item from core.item import Item
from platformcode import logger from platformcode import logger
from platformcode import config
CHANNELNAME = "youtube_channel" CHANNELNAME = "youtube_channel"
YOUTUBE_V3_API_KEY = "AIzaSyCjsmBT0JZy1RT-PLwB-Zkfba87sa2inyI" YOUTUBE_V3_API_KEY = "AIzaSyCjsmBT0JZy1RT-PLwB-Zkfba87sa2inyI"

View File

@@ -11,13 +11,15 @@ try:
except ImportError: except ImportError:
import urllib, urlparse, cookielib import urllib, urlparse, cookielib
import os, time, json import os, time, json
from threading import Lock from threading import Lock
from core.jsontools import to_utf8 from core.jsontools import to_utf8
from platformcode import config, logger from platformcode import config, logger
from core import scrapertools from core import scrapertools
# to surpress InsecureRequestWarning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Get the addon version # Get the addon version
__version = config.get_addon_version() __version = config.get_addon_version()

View File

@@ -82,7 +82,6 @@ def color(text, color):
def search(channel, item, texto): def search(channel, item, texto):
info(item.url + " search " + texto) info(item.url + " search " + texto)
if 'findhost' in dir(channel): channel.findhost()
item.url = channel.host + "/?s=" + texto item.url = channel.host + "/?s=" + texto
try: try:
return channel.peliculas(item) return channel.peliculas(item)
@@ -318,7 +317,8 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t
longtitle += s + parsedTitle.get('episode_title') longtitle += s + parsedTitle.get('episode_title')
item.contentEpisodeTitle = parsedTitle.get('episode_title') item.contentEpisodeTitle = parsedTitle.get('episode_title')
except: except:
logger.debug('Error') import traceback
logger.error(traceback.format_exc())
longtitle = typo(longtitle, 'bold') longtitle = typo(longtitle, 'bold')
lang1, longtitle = scrapeLang(scraped, lang, longtitle) lang1, longtitle = scrapeLang(scraped, lang, longtitle)
@@ -479,10 +479,10 @@ def scrape(func):
# if url may be changed and channel has findhost to update # if url may be changed and channel has findhost to update
if 'findhost' in func.__globals__ and not itemlist: if 'findhost' in func.__globals__ and not itemlist:
info('running findhost ' + func.__module__) info('running findhost ' + func.__module__)
host = func.__globals__['findhost']() ch = func.__module__.split('.')[-1]
host = config.get_channel_url(func.__globals__['findhost'], ch, True)
parse = list(urlparse.urlparse(item.url)) parse = list(urlparse.urlparse(item.url))
from core import jsontools
jsontools.update_node(host, func.__module__.split('.')[-1], 'url')
parse[1] = scrapertools.get_domain_from_url(host) parse[1] = scrapertools.get_domain_from_url(host)
item.url = urlparse.urlunparse(parse) item.url = urlparse.urlunparse(parse)
data = None data = None
@@ -491,6 +491,9 @@ def scrape(func):
else: else:
break break
if action != 'play' and function != 'episodios' and 'patronMenu' not in args and item.contentType in ['movie', 'tvshow', 'episode', 'undefined'] and not disabletmdb:
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
if (pagination and len(matches) <= pag * pagination) or not pagination: # next page with pagination if (pagination and len(matches) <= pag * pagination) or not pagination: # next page with pagination
if patronNext and inspect.stack()[1][3] not in ['newest']: if patronNext and inspect.stack()[1][3] not in ['newest']:
nextPage(itemlist, item, data, patronNext, function) nextPage(itemlist, item, data, patronNext, function)
@@ -509,8 +512,6 @@ def scrape(func):
args=item.args, args=item.args,
page=pag + 1, page=pag + 1,
thumbnail=thumb())) thumbnail=thumb()))
if action != 'play' and function != 'episodios' and 'patronMenu' not in args and item.contentType in ['movie', 'tvshow', 'episode', 'undefined'] and not disabletmdb:
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
if anime: if anime:
from platformcode import autorenumber from platformcode import autorenumber

View File

@@ -92,7 +92,7 @@ def cache_response(fn):
# import time # import time
# start_time = time.time() # start_time = time.time()
def wrapper(*args): def wrapper(*args, **kwargs):
import base64 import base64
def check_expired(ts): def check_expired(ts):
@@ -143,7 +143,8 @@ def cache_response(fn):
try: try:
# cache is not active # cache is not active
if not config.get_setting("tmdb_cache", default=False): if not config.get_setting("tmdb_cache", default=False) or not kwargs.get('cache', True):
logger.debug('no cache')
result = fn(*args) result = fn(*args)
else: else:
@@ -861,8 +862,7 @@ class Tmdb(object):
@staticmethod @staticmethod
@cache_response @cache_response
def get_json(url): def get_json(url, cache=True):
try: try:
result = httptools.downloadpage(url, cookies=False, ignore_response_code=True) result = httptools.downloadpage(url, cookies=False, ignore_response_code=True)
@@ -1045,7 +1045,7 @@ class Tmdb(object):
% (type_search, "&".join(params))) % (type_search, "&".join(params)))
logger.info("[Tmdb.py] Searcing %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, cache=False)
if not isinstance(resultado, dict): if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8')) resultado = ast.literal_eval(resultado.decode('utf-8'))

View File

@@ -7,6 +7,13 @@ import os
import sys import sys
import xbmc import xbmc
# on kodi 18 its xbmc.translatePath, on 19 xbmcvfs.translatePath
try:
import xbmcvfs
xbmc.translatePath = xbmcvfs.translatePath
except:
pass
from platformcode import config, logger from platformcode import config, logger
logger.info("init...") logger.info("init...")

View File

@@ -24,7 +24,7 @@ else:
_urlopen = urllib2.urlopen _urlopen = urllib2.urlopen
_Request = urllib2.Request _Request = urllib2.Request
def query(name, type='A', server=DOH_SERVER, path="/dns-query", fallback=True,): def query(name, type='A', server=DOH_SERVER, path="/dns-query", fallback=True):
""" """
Returns domain name query results retrieved by using DNS over HTTPS protocol Returns domain name query results retrieved by using DNS over HTTPS protocol
# Reference: https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/ # Reference: https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/

View File

@@ -544,8 +544,7 @@ class UnshortenIt(object):
if uri == prev_uri: if uri == prev_uri:
logger.info('Use Cloudscraper') logger.info('Use Cloudscraper')
uri = httptools.downloadpage(uri, timeout=self._timeout, headers=headers, follow_redirects=False, cf=True).headers['location'] uri = httptools.downloadpage(uri, timeout=self._timeout, headers=headers, follow_redirects=False, cf=True).headers['location']
# from core import support
# support.dbg()
if "snip." in uri: if "snip." in uri:
if 'out_generator' in uri: if 'out_generator' in uri:
uri = re.findall('url=(.*)$', uri)[0] uri = re.findall('url=(.*)$', uri)[0]

View File

@@ -72,7 +72,6 @@ def import_videolibrary(item):
if config.is_xbmc() and config.get_setting("videolibrary_kodi"): if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
xbmc_videolibrary.clean() xbmc_videolibrary.clean()
p_dialog.update(30) p_dialog.update(30)
xbmc.sleep(1000)
shutil.rmtree(videolibrary_movies_path) shutil.rmtree(videolibrary_movies_path)
shutil.rmtree(videolibrary_tvshows_path) shutil.rmtree(videolibrary_tvshows_path)
p_dialog.update(50) p_dialog.update(50)
@@ -102,7 +101,7 @@ def zip(dir, file):
temp = file temp = file
file = filetools.join(temp_path, os.path.split(file)[-1]) file = filetools.join(temp_path, os.path.split(file)[-1])
smb = True smb = True
with ZipFile(file, "w") as zf: with ZipFile(filetools.file_open(file, 'wb', vfs=False), "w") as zf:
abs_src = os.path.abspath(dir) abs_src = os.path.abspath(dir)
for dirname, subdirs, files in os.walk(dir): for dirname, subdirs, files in os.walk(dir):
for filename in files: for filename in files:
@@ -119,5 +118,5 @@ def unzip(dir, file):
filetools.copy(file, temp) filetools.copy(file, temp)
file = temp file = temp
with ZipFile(file, 'r') as zf: with ZipFile(filetools.file_open(file, 'rb', vfs=False), 'r') as zf:
zf.extractall(dir) zf.extractall(dir)

View File

@@ -258,10 +258,10 @@ def check_channels(inutile=''):
risultato = {} risultato = {}
for chann, host in sorted(data.items()): for chann, host in sorted(data['direct'].items()):
ris = [] ris = []
# to get an idea of the timing # to get an idea of the timing
# useful only if you control all channels # useful only if you control all channels
# for channels with error 522 about 40 seconds are lost ... # for channels with error 522 about 40 seconds are lost ...
logger.info("check #### INIZIO #### channel - host :%s - %s " % (chann, host)) logger.info("check #### INIZIO #### channel - host :%s - %s " % (chann, host))
@@ -290,6 +290,7 @@ def check_channels(inutile=''):
logger.info("check #### FINE #### rslt :%s " % (rslt)) logger.info("check #### FINE #### rslt :%s " % (rslt))
risultato = {'findhost': data['findhost'], 'direct': risultato}
fileJson_test = 'channels-test.json' fileJson_test = 'channels-test.json'
# I write the updated file # I write the updated file
with open(folderJson+'/'+fileJson_test, 'w') as f: with open(folderJson+'/'+fileJson_test, 'w') as f:

View File

@@ -15,7 +15,7 @@ __language__ = __settings__.getLocalizedString
__version_fix = None __version_fix = None
__dev_mode = None __dev_mode = None
channels_data = list() channels_data = dict()
def get_addon_core(): def get_addon_core():
return __settings__ return __settings__
@@ -101,27 +101,29 @@ def is_xbmc():
def get_videolibrary_support(): def get_videolibrary_support():
return True return True
def get_channel_url(findhostMethod=None, name=None):
def get_channel_url(findhostMethod=None, name=None, forceFindhost=False):
from core import jsontools from core import jsontools
import inspect import inspect
LOCAL_FILE = os.path.join(get_runtime_path(), "channels.json")
global channels_data
if not channels_data:
with open(LOCAL_FILE) as f:
channels_data = jsontools.load(f.read())
frame = inspect.stack()[1] frame = inspect.stack()[1]
if not name: if not name:
name = os.path.basename(frame[0].f_code.co_filename).replace('.py', '') name = os.path.basename(frame[0].f_code.co_filename).replace('.py', '')
if findhostMethod: if findhostMethod:
url = jsontools.get_node_from_file(name, 'url') url = jsontools.get_node_from_file(name, 'url')
if not url or 'web.archive.org' in url: # per eliminare tutti i webarchive salvati causa bug httptools CF, eliminare in futuro if not url or 'web.archive.org' in url or forceFindhost: # per eliminare tutti i webarchive salvati causa bug httptools CF, eliminare in futuro
url = findhostMethod() url = findhostMethod(channels_data['findhost'][name])
jsontools.update_node(url, name, 'url') jsontools.update_node(url, name, 'url')
return url return url
else: else:
ROOT_DIR = xbmc.translatePath(__settings__.getAddonInfo('Path')) return channels_data['direct'][name]
LOCAL_FILE = os.path.join(ROOT_DIR, "channels.json")
global channels_data
if not channels_data:
with open(LOCAL_FILE) as f:
channels_data = jsontools.load(f.read())
return channels_data[name]
def get_system_platform(): def get_system_platform():
""" function: to recover the platform that xbmc is running """ """ function: to recover the platform that xbmc is running """
@@ -147,7 +149,7 @@ def is_autorun_enabled():
def enable_disable_autorun(is_enabled): def enable_disable_autorun(is_enabled):
# using autoexec.py and not service.py to force autorun # old method, now using service.py
path = os.path.join(xbmc.translatePath('special://userdata'),'autoexec.py') path = os.path.join(xbmc.translatePath('special://userdata'),'autoexec.py')
append_write = 'a' if os.path.exists(path) else 'w' append_write = 'a' if os.path.exists(path) else 'w'
@@ -163,7 +165,7 @@ def enable_disable_autorun(is_enabled):
file.close() file.close()
with open(path, "w") as file: with open(path, "w") as file:
file.write(new_content) file.write(new_content)
set_setting('autostart', 'Off') set_setting('autostart', True)
return True return True
def get_all_settings_addon(): def get_all_settings_addon():

View File

@@ -6,6 +6,15 @@ from __future__ import unicode_literals
import inspect, os, xbmc, sys import inspect, os, xbmc, sys
from platformcode import config from platformcode import config
# for test suite
try:
xbmc.KodiStub()
testMode = True
record = False
recordedLog = ''
import html
except:
testMode = False
LOG_FORMAT = '{addname}[{filename}.{function}:{line}]{sep} {message}' LOG_FORMAT = '{addname}[{filename}.{function}:{line}]{sep} {message}'
DEBUG_ENABLED = config.get_setting("debug") DEBUG_ENABLED = config.get_setting("debug")
DEF_LEVEL = xbmc.LOGINFO if sys.version_info[0] >= 3 else xbmc.LOGNOTICE DEF_LEVEL = xbmc.LOGINFO if sys.version_info[0] >= 3 else xbmc.LOGNOTICE
@@ -28,6 +37,10 @@ def error(*args):
def log(*args, **kwargs): def log(*args, **kwargs):
msg = '' msg = ''
for arg in args: msg += ' ' + str(arg) for arg in args: msg += ' ' + str(arg)
if testMode and record:
global recordedLog
recordedLog += msg + '\n'
return
frame = inspect.currentframe().f_back.f_back frame = inspect.currentframe().f_back.f_back
filename = frame.f_code.co_filename filename = frame.f_code.co_filename
filename = os.path.basename(filename).split('.')[0] filename = os.path.basename(filename).split('.')[0]

View File

@@ -111,6 +111,70 @@ def dialog_browse(_type, heading, shares="files", mask="", useThumbs=False, trea
def dialog_register(heading, user=False, email=False, password=False, user_default='', email_default='', password_default='', captcha_img=''): def dialog_register(heading, user=False, email=False, password=False, user_default='', email_default='', password_default='', captcha_img=''):
class Register(xbmcgui.WindowXMLDialog):
def Start(self, heading, user, email, password, user_default, email_default, password_default, captcha_img):
self.result = {}
self.heading = heading
self.user = user
self.email = email
self.password = password
self.user_default = user_default
self.email_default = email_default
self.password_default = password_default
self.captcha_img = captcha_img
self.doModal()
return self.result
def __init__(self, *args, **kwargs):
self.mensaje = kwargs.get("mensaje")
self.imagen = kwargs.get("imagen")
def onInit(self):
#### Kodi 18 compatibility ####
if config.get_platform(True)['num_version'] < 18:
self.setCoordinateResolution(2)
height = 90
self.getControl(10002).setText(self.heading)
if self.user:
self.getControl(10003).setText(self.user_default)
height += 70
else:
self.getControl(10003).setVisible(False)
if self.email:
self.getControl(10004).setText(self.email_default)
height += 70
else:
self.getControl(10004).setVisible(False)
if self.password:
self.getControl(10005).setText(self.password_default)
height += 70
else:
self.getControl(10005).setVisible(False)
if self.captcha_img:
self.getControl(10007).setImage(self.captcha_img)
height += 240
else:
self.getControl(10005).setVisible(False)
height += 40
if height < 250: height = 250
self.getControl(10000).setHeight(height)
self.getControl(10001).setHeight(height)
self.getControl(10000).setPosition(255, (720 - height) / 2)
self.setFocusId(30000)
def onClick(self, control):
if control in [10010]:
self.close()
elif control in [10009]:
if self.user: self.result['user'] = self.getControl(10003).getText()
if self.email: self.result['email'] = self.getControl(10004).getText()
if self.password: self.result['password'] = self.getControl(10005).getText()
if self.captcha_img: self.result['captcha'] = self.getControl(10006).getText()
self.close()
dialog = Register('Register.xml', config.get_runtime_path()).Start(heading, user, email, password, user_default, email_default, password_default, captcha_img) dialog = Register('Register.xml', config.get_runtime_path()).Start(heading, user, email, password, user_default, email_default, password_default, captcha_img)
return dialog return dialog
@@ -1274,68 +1338,3 @@ def get_platform():
ret["arch"] = "arm" ret["arch"] = "arm"
return ret return ret
class Register(xbmcgui.WindowXMLDialog):
def Start(self, heading, user, email, password, user_default, email_default, password_default, captcha_img):
self.result = {}
self.heading = heading
self.user = user
self.email = email
self.password = password
self.user_default = user_default
self.email_default = email_default
self.password_default = password_default
self.captcha_img = captcha_img
self.doModal()
return self.result
def __init__(self, *args, **kwargs):
self.mensaje = kwargs.get("mensaje")
self.imagen = kwargs.get("imagen")
def onInit(self):
#### Kodi 18 compatibility ####
if config.get_platform(True)['num_version'] < 18:
self.setCoordinateResolution(2)
height = 90
self.getControl(10002).setText(self.heading)
if self.user:
self.getControl(10003).setText(self.user_default)
height+=70
else:
self.getControl(10003).setVisible(False)
if self.email:
self.getControl(10004).setText(self.email_default)
height+=70
else:
self.getControl(10004).setVisible(False)
if self.password:
self.getControl(10005).setText(self.password_default)
height+=70
else:
self.getControl(10005).setVisible(False)
if self.captcha_img:
self.getControl(10007).setImage(self.captcha_img)
height+=240
else:
self.getControl(10005).setVisible(False)
height +=40
if height < 250: height = 250
self.getControl(10000).setHeight(height)
self.getControl(10001).setHeight(height)
self.getControl(10000).setPosition(255, (720-height)/2)
self.setFocusId(30000)
def onClick(self, control):
if control in [10010]:
self.close()
elif control in [10009]:
if self.user: self.result['user'] = self.getControl(10003).getText()
if self.email: self.result['email'] = self.getControl(10004).getText()
if self.password: self.result['password'] = self.getControl(10005).getText()
if self.captcha_img: self.result['captcha'] = self.getControl(10006).getText()
self.close()

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from platformcode import logger, side_menu from platformcode import logger
def context(): def context():
@@ -18,6 +18,7 @@ def context():
return context return context
def Side_menu(item): def Side_menu(item):
from platformcode import side_menu
side_menu.open_menu(item) side_menu.open_menu(item)
def shortcut_menu(item): def shortcut_menu(item):

View File

@@ -161,8 +161,12 @@ def check(background=False):
if addon.getSetting("addon_update_message"): if addon.getSetting("addon_update_message"):
if background: if background:
platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80040) % commits[0]['sha'][:7], time=3000, sound=False) platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80040) % commits[0]['sha'][:7], time=3000, sound=False)
with open(xbmc.translatePath(changelogFile), 'a+') as fileC: try:
fileC.write(changelog) with open(xbmc.translatePath(changelogFile), 'a+') as fileC:
fileC.write(changelog)
except:
import traceback
logger.error(traceback.format_exc())
elif changelog: elif changelog:
platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80041) + changelog) platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80041) + changelog)
else: else:
@@ -175,7 +179,8 @@ def showSavedChangelog():
try: try:
with open(xbmc.translatePath(changelogFile), 'r') as fileC: with open(xbmc.translatePath(changelogFile), 'r') as fileC:
changelog = fileC.read() changelog = fileC.read()
platformtools.dialog_ok('Kodi on Demand', 'Aggiornamenti applicati:\n' + changelog) if changelog.strip():
platformtools.dialog_ok('Kodi on Demand', 'Aggiornamenti applicati:\n' + changelog)
os.remove(xbmc.translatePath(changelogFile)) os.remove(xbmc.translatePath(changelogFile))
except: except:
pass pass

View File

@@ -4,332 +4,52 @@ import xbmcgui
from core.tmdb import Tmdb from core.tmdb import Tmdb
from platformcode import config, logger from platformcode import config, logger
from core import filetools
ID_BUTTON_CLOSE = 10003 BACKGROUND = 30000
ID_BUTTON_PREVIOUS = 10025 LOADING = 30001
ID_BUTTON_NEXT = 10026 SELECT = 30002
ID_BUTTON_CANCEL = 10027
ID_BUTTON_OK = 10028
def imagepath(image):
if len(image.split('.')) == 1: image += '.png'
path = filetools.join(config.get_runtime_path(), 'resources', 'skins' , 'Default', 'media', 'Infoplus', image)
return path
class InfoWindow(xbmcgui.WindowXMLDialog): class InfoWindow(xbmcgui.WindowXMLDialog):
otmdb = None
item_title = "" def start(self, results, caption="", item=None, scraper=Tmdb):
item_serie = "" self.items = []
item_temporada = 0 self.response = None
item_episodio = 0 self.results = results
result = {}
# PARA TMDB
@staticmethod
def get_language(lng):
# Cambiamos el formato del Idioma
languages = {
'aa': 'Afar', 'ab': 'Abkhazian', 'af': 'Afrikaans', 'ak': 'Akan', 'sq': 'Albanian', 'am': 'Amharic',
'ar': 'Arabic', 'an': 'Aragonese', 'as': 'Assamese', 'av': 'Avaric', 'ae': 'Avestan', 'ay': 'Aymara',
'az': 'Azerbaijani', 'ba': 'Bashkir', 'bm': 'Bambara', 'eu': 'Basque', 'be': 'Belarusian', 'bn': 'Bengali',
'bh': 'Bihari languages', 'bi': 'Bislama', 'bo': 'Tibetan', 'bs': 'Bosnian', 'br': 'Breton',
'bg': 'Bulgarian', 'my': 'Burmese', 'ca': 'Catalan; Valencian', 'cs': 'Czech', 'ch': 'Chamorro',
'ce': 'Chechen', 'zh': 'Chinese',
'cu': 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', 'cv': 'Chuvash',
'kw': 'Cornish', 'co': 'Corsican', 'cr': 'Cree', 'cy': 'Welsh', 'da': 'Danish', 'de': 'German',
'dv': 'Divehi; Dhivehi; Maldivian', 'nl': 'Dutch; Flemish', 'dz': 'Dzongkha', 'en': 'English',
'eo': 'Esperanto', 'et': 'Estonian', 'ee': 'Ewe', 'fo': 'Faroese', 'fa': 'Persian', 'fj': 'Fijian',
'fi': 'Finnish', 'fr': 'French', 'fy': 'Western Frisian', 'ff': 'Fulah', 'Ga': 'Georgian',
'gd': 'Gaelic; Scottish Gaelic', 'ga': 'Irish', 'gl': 'Galician', 'gv': 'Manx',
'el': 'Greek, Modern (1453-)', 'gn': 'Guarani', 'gu': 'Gujarati', 'ht': 'Haitian; Haitian Creole',
'ha': 'Hausa', 'he': 'Hebrew', 'hz': 'Herero', 'hi': 'Hindi', 'ho': 'Hiri Motu', 'hr': 'Croatian',
'hu': 'Hungarian', 'hy': 'Armenian', 'ig': 'Igbo', 'is': 'Icelandic', 'io': 'Ido',
'ii': 'Sichuan Yi; Nuosu', 'iu': 'Inuktitut', 'ie': 'Interlingue; Occidental',
'ia': 'Interlingua (International Auxiliary Language Association)', 'id': 'Indonesian', 'ik': 'Inupiaq',
'it': 'Italian', 'jv': 'Javanese', 'ja': 'Japanese', 'kl': 'Kalaallisut; Greenlandic', 'kn': 'Kannada',
'ks': 'Kashmiri', 'ka': 'Georgian', 'kr': 'Kanuri', 'kk': 'Kazakh', 'km': 'Central Khmer',
'ki': 'Kikuyu; Gikuyu', 'rw': 'Kinyarwanda', 'ky': 'Kirghiz; Kyrgyz', 'kv': 'Komi', 'kg': 'Kongo',
'ko': 'Korean', 'kj': 'Kuanyama; Kwanyama', 'ku': 'Kurdish', 'lo': 'Lao', 'la': 'Latin', 'lv': 'Latvian',
'li': 'Limburgan; Limburger; Limburgish', 'ln': 'Lingala', 'lt': 'Lithuanian',
'lb': 'Luxembourgish; Letzeburgesch', 'lu': 'Luba-Katanga', 'lg': 'Ganda', 'mk': 'Macedonian',
'mh': 'Marshallese', 'ml': 'Malayalam', 'mi': 'Maori', 'mr': 'Marathi', 'ms': 'Malay', 'Mi': 'Micmac',
'mg': 'Malagasy', 'mt': 'Maltese', 'mn': 'Mongolian', 'na': 'Nauru', 'nv': 'Navajo; Navaho',
'nr': 'Ndebele, South; South Ndebele', 'nd': 'Ndebele, North; North Ndebele', 'ng': 'Ndonga',
'ne': 'Nepali', 'nn': 'Norwegian Nynorsk; Nynorsk, Norwegian', 'nb': 'Bokmål, Norwegian; Norwegian Bokmål',
'no': 'Norwegian', 'oc': 'Occitan (post 1500)', 'oj': 'Ojibwa', 'or': 'Oriya', 'om': 'Oromo',
'os': 'Ossetian; Ossetic', 'pa': 'Panjabi; Punjabi', 'pi': 'Pali', 'pl': 'Polish', 'pt': 'Portuguese',
'ps': 'Pushto; Pashto', 'qu': 'Quechua', 'ro': 'Romanian; Moldavian; Moldovan', 'rn': 'Rundi',
'ru': 'Russian', 'sg': 'Sango', 'rm': 'Romansh', 'sa': 'Sanskrit', 'si': 'Sinhala; Sinhalese',
'sk': 'Slovak', 'sl': 'Slovenian', 'se': 'Northern Sami', 'sm': 'Samoan', 'sn': 'Shona', 'sd': 'Sindhi',
'so': 'Somali', 'st': 'Sotho, Southern', 'es': 'Spanish', 'sc': 'Sardinian', 'sr': 'Serbian', 'ss': 'Swati',
'su': 'Sundanese', 'sw': 'Swahili', 'sv': 'Swedish', 'ty': 'Tahitian', 'ta': 'Tamil', 'tt': 'Tatar',
'te': 'Telugu', 'tg': 'Tajik', 'tl': 'Tagalog', 'th': 'Thai', 'ti': 'Tigrinya',
'to': 'Tonga (Tonga Islands)', 'tn': 'Tswana', 'ts': 'Tsonga', 'tk': 'Turkmen', 'tr': 'Turkish',
'tw': 'Twi', 'ug': 'Uighur; Uyghur', 'uk': 'Ukrainian', 'ur': 'Urdu', 'uz': 'Uzbek', 've': 'Venda',
'vi': 'Vietnamese', 'vo': 'Volapük', 'wa': 'Walloon', 'wo': 'Wolof', 'xh': 'Xhosa', 'yi': 'Yiddish',
'yo': 'Yoruba', 'za': 'Zhuang; Chuang', 'zu': 'Zulu'}
return languages.get(lng, lng)
def get_scraper_data(self, data_in):
self.otmdb = None
# logger.debug(str(data_in))
if self.listData:
# Data common to all listings
infoLabels = self.scraper().get_infoLabels(origen=data_in)
if "original_language" in infoLabels:
infoLabels["language"] = self.get_language(infoLabels["original_language"])
infoLabels["puntuacion"] = "%s/10 (%s)" % (infoLabels.get("rating", "?"), infoLabels.get("votes", "N/A"))
self.result = infoLabels
def start(self, data, caption="Información del vídeo", item=None, scraper=Tmdb):
"""
It shows a window with the info of the video. Optionally, the title of the window can be indicated by means of the argument 'caption'.
If an item is passed as the 'data' argument use the Tmdb scrapper to find the video info
In case of movies:
Take the title from the following fields (in this order)
1. contentTitle (this has priority 1)
2. title (this has priority 2)
The first one containing "something" interprets it as the title (it is important to make sure that the title is in
your site)
In case of series:
1. Find the season and episode in the contentSeason and contentEpisodeNumber fields
2. Try to remove it from the video title (format: 1x01)
Here are two possible options:
1. We have Season and episode
Shows the information of the specific chapter
2. We DO NOT have Season and episode
In this case it shows the generic information of the series
If an InfoLabels object (see item.py) is passed as an argument 'data' it shows in the window directly
the past information (without using the scrapper)
Format:
In case of movies:
infoLabels ({
"type" : "movie",
"title": "Title of the movie",
"original_title": "Original movie title",
"date": "Release date",
"language": "Original language of the movie",
"rating": "Rating of the movie",
"votes": "Number of votes",
"genres": "Genres of the movie",
"thumbnail": "Path for the thumbnail",
"fanart": "Route for the fanart",
"plot": "Synopsis of the movie"
}
In case of series:
infoLabels ({
"type" : "tv",
"title": "Title of the series",
"episode_title": "Episode title",
"date": "Date of issue",
"language": "Original language of the series",
"rating": "Punctuation of the series",
"votes": "Number of votes",
"genres": "Genres of the series",
"thumbnail": "Path for the thumbnail",
"fanart": "Route for the fanart",
"plot": "Synopsis of the episode or series",
"seasons": "Number of Seasons",
"season": "Season",
"episodes": "Number of episodes of the season",
"episode": "Episode"
}
If a list of InfoLabels () with the previous structure is passed as the 'data' argument, it shows the buttons
'Previous' and 'Next' to scroll through the list. It also shows the 'Accept' and 'Cancel' buttons that
call the function 'callback' of the channel from where the call is made, passing the element as parameters
current (InfoLabels ()) or None respectively.
@param data: information to get scraper data.
@type data: item, InfoLabels, list(InfoLabels)
@param caption: window title.
@type caption: str
@param item: item for which the information window is to be displayed
@type item: Item
@param scraper: scraper that has the data of the movies or series to show in the window.
@type scraper: Scraper
"""
# We capture the parameters
self.caption = caption
self.item = item self.item = item
self.indexList = -1
self.listData = None
self.return_value = None
self.scraper = scraper self.scraper = scraper
logger.debug(data)
if type(data) == list:
self.listData = data
self.indexList = 0
data = self.listData[self.indexList]
self.get_scraper_data(data)
# Show window
self.doModal() self.doModal()
return self.return_value logger.info('RESPONSE',self.response)
return self.response
def __init__(self, *args):
self.caption = ""
self.item = None
self.listData = None
self.indexList = 0
self.return_value = None
self.scraper = Tmdb
def onInit(self): def onInit(self):
#### Kodi 18 compatibility ####
if config.get_platform(True)['num_version'] < 18: if config.get_platform(True)['num_version'] < 18:
if xbmcgui.__version__ == "1.2": self.setCoordinateResolution(2)
self.setCoordinateResolution(1)
else:
self.setCoordinateResolution(5)
# We put the title and the images for result in self.results:
self.getControl(10002).setLabel(self.caption) infoLabels = self.scraper().get_infoLabels(origen=result)
self.getControl(10004).setImage(self.result.get("fanart", "")) it = xbmcgui.ListItem(infoLabels['title'])
self.getControl(10005).setImage(self.result.get("thumbnail", "images/img_no_disponible.png")) it.setProperty('fanart', infoLabels.get('fanart', ''))
it.setProperty('thumbnail', infoLabels.get('thumbnail', imagepath('movie' if infoLabels['mediatype'] == 'movie' else 'tv')))
it.setProperty('genre', infoLabels.get('genre', 'N/A'))
it.setProperty('rating', str(infoLabels.get('rating', 'N/A')))
it.setProperty('plot', str(infoLabels.get('plot', '')))
it.setProperty('year', str(infoLabels.get('year', '')))
self.items.append(it)
# We load the data for the movie format self.getControl(SELECT).addItems(self.items)
if self.result.get("mediatype", "movie") == "movie": self.getControl(BACKGROUND).setImage(self.items[0].getProperty('fanart'))
self.getControl(10006).setLabel(config.get_localized_string(60377)) self.getControl(LOADING).setVisible(False)
self.getControl(10007).setLabel(self.result.get("title", "N/A")) self.setFocusId(SELECT)
self.getControl(10008).setLabel(config.get_localized_string(60378))
self.getControl(10009).setLabel(self.result.get("originaltitle", "N/A"))
self.getControl(100010).setLabel(config.get_localized_string(60379))
self.getControl(100011).setLabel(self.result.get("language", "N/A"))
self.getControl(100012).setLabel(config.get_localized_string(60380))
self.getControl(100013).setLabel(self.result.get("puntuacion", "N/A"))
self.getControl(100014).setLabel(config.get_localized_string(60381))
self.getControl(100015).setLabel(self.result.get("release_date", "N/A"))
self.getControl(100016).setLabel(config.get_localized_string(60382))
self.getControl(100017).setLabel(self.result.get("genre", "N/A"))
# We load the data for the serial format def onClick(self, control_id):
else: if control_id == SELECT:
self.getControl(10006).setLabel(config.get_localized_string(60383)) self.response = self.results[self.getControl(SELECT).getSelectedPosition()]
self.getControl(10007).setLabel(self.result.get("title", "N/A")) self.close()
self.getControl(10008).setLabel(config.get_localized_string(60379))
self.getControl(10009).setLabel(self.result.get("language", "N/A"))
self.getControl(100010).setLabel(config.get_localized_string(60380))
self.getControl(100011).setLabel(self.result.get("puntuacion", "N/A"))
self.getControl(100012).setLabel(config.get_localized_string(60382))
self.getControl(100013).setLabel(self.result.get("genre", "N/A"))
if self.result.get("season"):
self.getControl(100014).setLabel(config.get_localized_string(60384))
self.getControl(100015).setLabel(self.result.get("temporada_nombre", "N/A"))
self.getControl(100016).setLabel(config.get_localized_string(60385))
self.getControl(100017).setLabel(self.result.get("season", "N/A") + " de " + self.result.get("seasons", "N/A"))
if self.result.get("episode"):
self.getControl(100014).setLabel(config.get_localized_string(60377))
self.getControl(100015).setLabel(self.result.get("episode_title", "N/A"))
self.getControl(100018).setLabel(config.get_localized_string(60386))
self.getControl(100019).setLabel(self.result.get("episode", "N/A") + " de " + self.result.get("episodes", "N/A"))
self.getControl(100020).setLabel(config.get_localized_string(60387))
self.getControl(100021).setLabel(self.result.get("date", "N/A"))
# Synopsis
if self.result['plot']:
self.getControl(100022).setLabel(config.get_localized_string(60388))
self.getControl(100023).setText(self.result.get("plot", "N/A"))
else:
self.getControl(100022).setLabel("")
self.getControl(100023).setText("")
# We load the buttons if necessary
self.getControl(10024).setVisible(self.indexList > -1) # Button group
self.getControl(ID_BUTTON_PREVIOUS).setEnabled(self.indexList > 0) # Previous
if self.listData:
m = len(self.listData)
else:
m = 1
self.getControl(ID_BUTTON_NEXT).setEnabled(self.indexList + 1 != m) # Following
self.getControl(100029).setLabel("(%s/%s)" % (self.indexList + 1, m)) # x/m
# We put the focus in the Group of buttons, if "Previous" was deactivated the focus would go to the "Next" button
# if "Next" tb is deactivated it will pass the focus to the "Cancel" button
self.setFocus(self.getControl(10024))
return self.return_value
def onClick(self, _id):
logger.info("onClick id=" + repr(_id))
if _id == ID_BUTTON_PREVIOUS and self.indexList > 0:
self.indexList -= 1
self.get_scraper_data(self.listData[self.indexList])
self.onInit()
elif _id == ID_BUTTON_NEXT and self.indexList < len(self.listData) - 1:
self.indexList += 1
self.get_scraper_data(self.listData[self.indexList])
self.onInit()
elif _id == ID_BUTTON_OK or _id == ID_BUTTON_CLOSE or _id == ID_BUTTON_CANCEL:
self.close()
if _id == ID_BUTTON_OK:
self.return_value = self.listData[self.indexList]
else:
self.return_value = None
def onAction(self, action):
logger.info("action=" + repr(action.getId()))
action = action.getId()
# Find Focus
focus = self.getFocusId()
# Left
if action == 1:
if focus == ID_BUTTON_OK:
self.setFocus(self.getControl(ID_BUTTON_CANCEL))
elif focus == ID_BUTTON_CANCEL:
if self.indexList + 1 != len(self.listData):
# Next
self.setFocus(self.getControl(ID_BUTTON_NEXT))
elif self.indexList > 0:
# Previous
self.setFocus(self.getControl(ID_BUTTON_PREVIOUS))
elif focus == ID_BUTTON_NEXT:
if self.indexList > 0:
# Next
self.setFocus(self.getControl(ID_BUTTON_PREVIOUS))
# Right
elif action == 2:
if focus == ID_BUTTON_PREVIOUS:
if self.indexList + 1 != len(self.listData):
# Next
self.setFocus(self.getControl(ID_BUTTON_NEXT))
else:
# Cancel
self.setFocus(self.getControl(ID_BUTTON_CANCEL))
elif focus == ID_BUTTON_NEXT:
self.setFocus(self.getControl(ID_BUTTON_CANCEL))
elif focus == ID_BUTTON_CANCEL:
self.setFocus(self.getControl(ID_BUTTON_OK))
# Up
elif action == 3:
self.setFocus(self.getControl(ID_BUTTON_CLOSE))
# Down
elif action == 4:
self.setFocus(self.getControl(ID_BUTTON_OK))
# Press ESC or Back, simulate click on cancel button
if action in [10, 92]:
self.onClick(ID_BUTTON_CANCEL)

View File

@@ -3,7 +3,7 @@
<!-- General --> <!-- General -->
<category label="70168"> <category label="70168">
<setting label="70786" type="lsep"/> <setting label="70786" type="lsep"/>
<setting id="autostart" type="action" label="70706" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiYXV0b3N0YXJ0IiwNCiAgICAiY2hhbm5lbCI6ICJzZXR0aW5nIg0KfQ==)" default="Off"/> <setting id="autostart" type="bool" label="70706" default="false"/>
<setting label="70579" type="lsep"/> <setting label="70579" type="lsep"/>
<setting id="addon_update_enabled" type="bool" label="70581" default="true"/> <setting id="addon_update_enabled" type="bool" label="70581" default="true"/>
<setting id="addon_update_message" type="bool" label="70582" visible="eq(-1,true)" default="true"/> <setting id="addon_update_message" type="bool" label="70582" visible="eq(-1,true)" default="true"/>

View File

@@ -1,375 +1,124 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<window> <window>
<allowoverlays>false</allowoverlays> <depth>0.52</depth>
<animation type="WindowOpen" reversible="false"> <coordinates>
<effect type="slide" start="0,200" end="0,0" center="640,225" delay="160" tween="cubic" time="200" /> <left>0</left>
<effect type="fade" delay="160" end="100" time="240" /> <top>0</top>
</animation> </coordinates>
<animation type="WindowClose" reversible="false"> <controls>
<effect type="slide" start="0,0" end="0,200" center="640,225" easing="in" tween="cubic" time="200" /> <!-- CLOSE BUTTON / BACKGROUND -->
<effect type="fade" start="100" end="0" time="240" /> <control type="button">
</animation> <left>0</left>
<controls> <top>0</top>
<control type="group" id="10001"> <width>100%</width>
<left>0</left> <height>100%</height>
<top>0</top> <texturefocus colordiffuse="FF232323">white.png</texturefocus>
<texturenofocus colordiffuse="FF232323">white.png</texturenofocus>
<animation effect="fade" time="200">WindowOpen</animation>
<animation effect="fade" time="200">WindowClose</animation>
<onclick>Action(close)</onclick>
</control>
<!-- GROUP CONTROLS -->
<control type="group">
<left>0</left>
<top>0</top>
<animation type="WindowOpen" reversible="false">
<effect type="slide" start="0,100" end="0,0" delay="160" time="160" />
<effect type="fade" delay="160" end="100" time="100" />
</animation>
<animation type="WindowClose" reversible="false">
<effect type="slide" start="0,0" end="0,100" delay="160" time="160" />
<effect type="fade" delay="160" start="100" end="0" time="100" />
</animation>
<!-- BACKGROUND -->
<control type="image" id='30000'>
<width>1280</width>
<height>720</height>
<texture colordiffuse="FF555555"></texture>
</control>
<!-- LOADING -->
<control type="image" id='30001'>
<top>355</top>
<left>490</left>
<width>300</width>
<height>10</height>
<texture>white.png</texture>
<animation effect="zoom" pulse ="true" center="auto" start="0,100" end="100,100" time="1000" condition="Control.IsVisible(30001)">Conditional</animation>
</control>
<!-- SELECTION -->
<control type="fixedlist" id="30002">
<top>40</top>
<width>100%</width> <width>100%</width>
<height>100%</height> <height>640</height>
<control type="image"> <viewtype>wrap</viewtype>
<width>100%</width> <orientation>horizontal</orientation>
<height>100%</height> <scrolltime tween="cubic" easing="out">300</scrolltime>
<texture colordiffuse="FF232323">white.png</texture> <itemlayout height="640" width="180">
</control> <!-- Poster -->
<!-- FANART --> <control type="image">
<control type="image" id="10004"> <bottom>0</bottom>
<left>0</left>
<top>0</top>
<width>100%</width>
<height>100%</height>
<texture></texture>
<colordiffuse>33FFFFFF</colordiffuse>
</control>
<!-- Header -->
<control type="label" id="10002">
<top>20</top>
<left>0</left>
<height>34</height>
<width>100%</width>
<font>font30_title</font>
<textcolor>FFFFFFFF</textcolor>
<align>center</align>
<aligny>center</aligny>
<label>$ADDON[plugin.video.kod 70000]</label>
</control>
<!-- Close -->
<control type="button" id="10003">
<right>30</right>
<top>25</top>
<width>30</width>
<height>30</height>
<texturefocus colordiffuse="FFFFFFFF">close.png</texturefocus>
<texturenofocus colordiffuse="55FFFFFF">close.png</texturenofocus>
</control>
<!-- LOCANDINA -->
<control type="image" id="10005">
<right>30</right>
<top>110</top>
<width>349</width>
<height>500</height>
<texture></texture>
<aspectratio>keep</aspectratio>
<animation type="WindowOpen" reversible="false">
<effect type="slide" start="200,0" end="0,0" delay="300" tween="cubic" time="200" />
<effect type="fade" delay="300" end="100" time="240" />
</animation>
<animation type="WindowClose" reversible="false">
<effect type="slide" start="0,0" end="200,0" easing="in" tween="cubic" time="200" />
<effect type="fade" start="100" end="0" time="240" />
</animation>
</control>
<!-- Serie -->
<control type="label" id="10006">
<top>100</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>FFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="10007">
<top>100</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>FFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="10008"> <!-- Lingua Originale -->
<top>130</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="10009">
<top>130</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100010"> <!-- Punteggio -->
<top>160</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100011">
<top>160</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100012"> <!-- Generi -->
<top>190</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100013">
<top>190</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100014">
<top>220</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100015">
<top>220</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100016">
<top>250</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100017">
<top>250</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100018">
<top>280</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100019">
<top>280</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100020">
<top>310</top>
<left>60</left>
<height>30</height>
<width>200</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100021">
<top>310</top>
<left>250</left>
<height>30</height>
<width>365</width>
<font>font13</font>
<scrollsuffix> | </scrollsuffix>
<scroll>true</scroll>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="label" id="100022"> <!-- Trama -->
<top>330</top>
<left>60</left>
<height>30</height>
<width>505</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<align>left</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="textbox" id="100023">
<top>330</top>
<left>250</left>
<height>250</height>
<width>550</width>
<font>font13</font>
<textcolor>0xFFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor>
<wrapmultiline>true</wrapmultiline>
<autoscroll delay="2000" time="1500" repeat="2000">true</autoscroll>
<align>justify</align>
<aligny>top</aligny>
<label></label>
</control>
<control type="group" id="10024">
<bottom>60</bottom>
<left>40</left>
<width>760</width>
<height>30</height>
<control type="button" id="10025">
<top>0</top>
<left>0</left> <left>0</left>
<width>200</width> <width>180</width>
<height>50</height> <height>270</height>
<textwidth>110</textwidth> <texture>$INFO[ListItem.Property(thumbnail)]</texture>
<texturefocus colordiffuse="FF0081C2">white.png</texturefocus> <aspectratio>scale</aspectratio>
<texturenofocus colordiffuse="000081C2">white.png</texturenofocus> <bordersize>10</bordersize>
<align>center</align>
<aligny>center</aligny>
<label>$ADDON[plugin.video.kod 70005]</label>
</control> </control>
<control type="button" id="10026"> </itemlayout>
<top>0</top> <focusedlayout height="640" width="480">
<left>210</left> <!-- Title -->
<width>200</width> <control type="textbox">
<height>50</height> <left>500</left>
<textwidth>110</textwidth>
<texturefocus colordiffuse="FF0081C2">white.png</texturefocus>
<texturenofocus colordiffuse="000081C2">white.png</texturenofocus>
<align>center</align>
<aligny>center</aligny>
<label>$ADDON[plugin.video.kod 70006]</label>
</control>
<control type="button" id="10027">
<top>0</top>
<left>420</left>
<width>200</width>
<height>50</height>
<textwidth>110</textwidth>
<texturefocus colordiffuse="FF0081C2">white.png</texturefocus>
<texturenofocus colordiffuse="000081C2">white.png</texturenofocus>
<align>center</align>
<aligny>center</aligny>
<label>$ADDON[plugin.video.kod 70002]</label>
</control>
<control type="button" id="10028">
<top>0</top>
<left>640</left>
<width>200</width>
<height>50</height>
<textwidth>110</textwidth>
<texturefocus colordiffuse="FF0081C2">white.png</texturefocus>
<texturenofocus colordiffuse="000081C2">white.png</texturenofocus>
<align>center</align>
<aligny>center</aligny>
<label>$ADDON[plugin.video.kod 70007]</label>
</control>
<control type="label" id="100029">
<top>10</top> <top>10</top>
<left>1080</left> <width>730</width>
<height>30</height>
<font>font30_title</font>
<textcolor>FFFFFFFF</textcolor>
<shadowcolor>00000000</shadowcolor>
<label>[B]$INFO[ListItem.Label] [COLOR FFAAAAAA] $INFO[ListItem.Property(year)][/COLOR][/B] </label>
<align>left</align>
<aligny>center</aligny>
</control>
<!-- info -->
<control type="textbox">
<left>500</left>
<top>50</top>
<width>730</width>
<height>30</height> <height>30</height>
<width>110</width>
<font>font13</font> <font>font13</font>
<textcolor>FFFFFFFF</textcolor> <textcolor>FFFFFFFF</textcolor>
<shadowcolor>black</shadowcolor> <shadowcolor>00000000</shadowcolor>
<align>right</align> <label>$ADDON[plugin.video.kod 60382] $INFO[ListItem.Property(genre)] | $ADDON[plugin.video.kod 60380] [B]$INFO[ListItem.Property(rating)][/B]</label>
<aligny>center</aligny> <align>left</align>
<label></label>
</control> </control>
</control> <!-- Plot -->
<control type="textbox">
<left>500</left>
<top>90</top>
<width>730</width>
<height>250</height>
<font>font13</font>
<textcolor>FFFFFFFF</textcolor>
<shadowcolor>00000000</shadowcolor>
<label>$INFO[ListItem.Property(plot)]</label>
<autoscroll time="3000" delay="3000" repeat="3000">True</autoscroll>
<align>left</align>
</control>
<!-- Poster -->
<control type="image">
<bottom>0</bottom>
<left>0</left>
<width>480</width>
<height>640</height>
<texture>$INFO[ListItem.Property(thumbnail)]</texture>
<aspectratio>scale</aspectratio>
<bordersize>10</bordersize>
</control>
</focusedlayout>
</control> </control>
</controls> </control> <!-- GROUP CONTROLS END -->
</controls>
</window> </window>

View File

@@ -39,12 +39,12 @@
</control> </control>
<!-- LOADING --> <!-- LOADING -->
<control type="image" id='30011'> <control type="image" id='30011'>
<top>310</top> <top>355</top>
<left>590</left> <left>490</left>
<width>100</width> <width>300</width>
<height>100</height> <height>10</height>
<texture>Infoplus/loading.png</texture> <texture>white.png</texture>
<animation effect="rotate" center="640,360" start="0" end="-360" time="5000" loop="true" condition="Control.IsVisible(30011)">Conditional</animation> <animation effect="zoom" pulse ="true" center="auto" start="0,100" end="100,100" time="1000" condition="Control.IsVisible(30011)">Conditional</animation>
</control> </control>
<!-- TITLE --> <!-- TITLE -->
<control type="textbox" id='30001'> <control type="textbox" id='30001'>
@@ -90,7 +90,7 @@
<font>font30_title</font> <font>font30_title</font>
<textcolor>FFFFFFFF</textcolor> <textcolor>FFFFFFFF</textcolor>
<shadowcolor>00000000</shadowcolor> <shadowcolor>00000000</shadowcolor>
<label>[B]$INFO[ListItem.Label] [COLOR FFAAAAAA]($INFO[ListItem.Property(year)])[/COLOR][/B] </label> <label>[B]$INFO[ListItem.Label] [COLOR FFAAAAAA]$INFO[ListItem.Property(year)][/COLOR][/B] </label>
<align>left</align> <align>left</align>
<aligny>center</aligny> <aligny>center</aligny>
</control> </control>

View File

@@ -39,12 +39,12 @@
</control> </control>
<!-- LOADING --> <!-- LOADING -->
<control type="image" id='30011'> <control type="image" id='30011'>
<top>310</top> <top>355</top>
<left>590</left> <left>490</left>
<width>100</width> <width>300</width>
<height>100</height> <height>10</height>
<texture>Infoplus/loading.png</texture> <texture>white.png</texture>
<animation effect="rotate" center="640,360" start="0" end="-360" time="5000" loop="true" condition="Control.IsVisible(30011)">Conditional</animation> <animation effect="zoom" pulse ="true" center="auto" start="0,100" end="100,100" time="1000" condition="Control.IsVisible(30011)">Conditional</animation>
</control> </control>
<!-- TITLE --> <!-- TITLE -->
<control type="textbox" id='30001'> <control type="textbox" id='30001'>

View File

@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import urllib try:
import urllib.parse as urllib
except ImportError:
import urllib
from core import httptools, support from core import httptools, support
from core import scrapertools from core import scrapertools
@@ -8,6 +11,7 @@ from platformcode import logger, config
headers = [['User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0']] headers = [['User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0']]
def test_video_exists(page_url): def test_video_exists(page_url):
logger.info("(page_url='%s')" % page_url) logger.info("(page_url='%s')" % page_url)
# page_url = re.sub('akvideo.stream/(?:video/|video\\.php\\?file_code=)?(?:embed-)?([a-zA-Z0-9]+)','akvideo.stream/video/\\1',page_url) # page_url = re.sub('akvideo.stream/(?:video/|video\\.php\\?file_code=)?(?:embed-)?([a-zA-Z0-9]+)','akvideo.stream/video/\\1',page_url)

View File

@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import urllib try:
import urllib.parse as urllib
except ImportError:
import urllib
from core import httptools from core import httptools
from core import scrapertools from core import scrapertools

View File

@@ -8,7 +8,8 @@ from platformcode import config, logger
def test_video_exists(page_url): def test_video_exists(page_url):
logger.info("(page_url='%s')" % page_url) logger.info("(page_url='%s')" % page_url)
data = httptools.downloadpage(page_url, cookies=False).data global data
data = httptools.downloadpage(page_url).data
if 'File you are looking for is not found.' in data: if 'File you are looking for is not found.' in data:
return False, config.get_localized_string(70449) % "Onlystream" return False, config.get_localized_string(70449) % "Onlystream"
@@ -17,7 +18,7 @@ def test_video_exists(page_url):
def get_video_url(page_url, premium=False, user="", password="", video_password=""): def get_video_url(page_url, premium=False, user="", password="", video_password=""):
logger.info("url=" + page_url) logger.info("url=" + page_url)
data = httptools.downloadpage(page_url).data global data
# logger.info(data) # logger.info(data)
video_urls = support.get_jwplayer_mediaurl(data, 'Onlystream') video_urls = support.get_jwplayer_mediaurl(data, 'Onlystream')
return video_urls return video_urls

View File

@@ -1,27 +1,38 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# --------------------------------------------------------
# Conector streamtape By Alfa development Group
# --------------------------------------------------------
import re
from core import httptools from core import httptools
from core import scrapertools from core import scrapertools
from platformcode import logger, config from platformcode import logger
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
def test_video_exists(page_url): def test_video_exists(page_url):
logger.info("(page_url='%s')" % page_url) logger.info("(page_url='%s')" % page_url)
global data global data
data = httptools.downloadpage(page_url).data
referer = {"Referer": page_url}
data = httptools.downloadpage(page_url, headers=referer).data
if "Video not found" in data: if "Video not found" in data:
return False, config.get_localized_string(70449) % "Streamtape" return False, "[streamtape] El archivo no existe o ha sido borrado"
return True, "" return True, ""
def get_video_url(page_url, premium=False, user="", password="", video_password=""): def get_video_url(page_url, premium=False, user="", password="", video_password=""):
logger.info("url=" + page_url) logger.info("url=" + page_url)
video_urls = [] video_urls = []
global data url = "https:" + scrapertools.find_single_match(data, 'innerHTML = "([^"]+)')
url = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers.get("location", "")
url = scrapertools.find_single_match(data, 'id="videolink"[^>]+>\n?\s*//(.*?)<') video_urls.append(['MP4 [streamtape]', url])
if url: return video_urls
media_url = 'https://' + url + '&stream=1'
video_urls.append([".mp4 [Streamtape]", media_url])
return video_urls

View File

@@ -1,7 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time import time
import urllib try:
import urllib.parse as urllib
except ImportError:
import urllib
from core import httptools, support from core import httptools, support
from core import scrapertools from core import scrapertools

View File

@@ -9,7 +9,7 @@ def test_video_exists(page_url):
page = httptools.downloadpage(page_url) page = httptools.downloadpage(page_url)
global data global data
data = page.data data = page.data
if page.code == 404: if page.code == 404 or 'File is no longer available' in data:
return False, config.get_localized_string(70449) return False, config.get_localized_string(70449)
return True, "" return True, ""

View File

@@ -8,6 +8,12 @@ import traceback
import xbmc import xbmc
import xbmcgui import xbmcgui
from platformcode import config from platformcode import config
# on kodi 18 its xbmc.translatePath, on 19 xbmcvfs.translatePath
try:
import xbmcvfs
xbmc.translatePath = xbmcvfs.translatePath
except:
pass
librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib')) librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib'))
sys.path.insert(0, librerias) sys.path.insert(0, librerias)
@@ -396,6 +402,12 @@ class AddonMonitor(xbmc.Monitor):
if __name__ == "__main__": if __name__ == "__main__":
logger.info('Starting KoD service') logger.info('Starting KoD service')
if config.get_setting('autostart'):
xbmc.executebuiltin('RunAddon(plugin.video.' + config.PLUGIN_NAME + ')')
# handling old autoexec method
if config.is_autorun_enabled():
config.enable_disable_autorun(True)
monitor = AddonMonitor() monitor = AddonMonitor()
# mark as stopped all downloads (if we are here, probably kodi just started) # mark as stopped all downloads (if we are here, probably kodi just started)

View File

@@ -137,7 +137,11 @@ def search(item, text):
json = load_json(item) json = load_json(item)
if json: if json:
for key in json: for key in json:
peliculas(item, json, key, itemlist) if key not in ['sort']:
if item.custom_search and key == 'menu':
get_menu(item, json, key, itemlist)
else:
peliculas(item, json, key, itemlist)
return itemlist return itemlist

View File

@@ -138,7 +138,10 @@ def renameFavourite(item):
# Features to migrate old favorites (.txt) # Features to migrate old favorites (.txt)
def readbookmark(filepath): def readbookmark(filepath):
logger.info() logger.info()
import urllib try:
import urllib.parse as urllib
except ImportError:
import urllib
bookmarkfile = filetools.file_open(filepath) bookmarkfile = filetools.file_open(filepath)

View File

@@ -4,8 +4,10 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
import re import re
import urllib try:
from channelselector import get_thumb import urllib.parse as urllib
except ImportError:
import urllib
from core import httptools, scrapertools, support, tmdb, filetools from core import httptools, scrapertools, support, tmdb, filetools
from core.item import Item from core.item import Item
from platformcode import logger, config, platformtools from platformcode import logger, config, platformtools

View File

@@ -174,10 +174,10 @@ def channel_search(item):
mode = item.mode mode = item.mode
if item.infoLabels['tvshowtitle']: if item.infoLabels['tvshowtitle']:
item.text = item.infoLabels['tvshowtitle'].split('-')[0] item.text = item.infoLabels['tvshowtitle'].split(' - ')[0]
item.title = item.text item.title = item.text
elif item.infoLabels['title']: elif item.infoLabels['title']:
item.text = item.infoLabels['title'].split('-')[0] item.text = item.infoLabels['title'].split(' - ')[0]
item.title = item.text item.title = item.text
temp_search_file = config.get_temp_file('temp-search') temp_search_file = config.get_temp_file('temp-search')
@@ -235,6 +235,8 @@ def channel_search(item):
if channel not in ch_list: if channel not in ch_list:
ch_list[channel] = [] ch_list[channel] = []
ch_list[channel].extend(res.result()[1]) ch_list[channel].extend(res.result()[1])
if res.result()[2]:
valid.extend(res.result()[2])
if progress.iscanceled(): if progress.iscanceled():
break break
@@ -261,21 +263,7 @@ def channel_search(item):
ch_name = channel_titles[channel_list.index(key)] ch_name = channel_titles[channel_list.index(key)]
grouped = list() grouped = list()
cnt += 1 cnt += 1
progress.update(old_div((cnt * 100), len(ch_list)), config.get_localized_string(60295) + '\n' + config.get_localized_string(60293)) progress.update(old_div((cnt * 100), len(ch_list)), config.get_localized_string(60295))
if item.mode != 'all':
if len(value) == 1:
if not value[0].action or config.get_localized_string(70006).lower() in value[0].title.lower():
continue
for elem in value:
if not elem.infoLabels.get('year', ""):
elem.infoLabels['year'] = '-'
tmdb.set_infoLabels_itemlist(value, True, forced=True)
for elem in value:
if elem.infoLabels['tmdb_id'] == searched_id:
elem.from_channel = key
if not config.get_setting('unify'):
elem.title += ' [%s]' % key
valid.append(elem)
for it in value: for it in value:
if it.channel == item.channel: if it.channel == item.channel:
@@ -355,24 +343,38 @@ def channel_search(item):
def get_channel_results(item, module_dict, search_action): def get_channel_results(item, module_dict, search_action):
ch = search_action.channel ch = search_action.channel
max_results = 10
results = list() results = list()
valid = list()
module = module_dict[ch] module = module_dict[ch]
searched_id = item.infoLabels['tmdb_id']
try: try:
results.extend(module.search(search_action, item.text)) results.extend(module.search(search_action, item.text))
if len(results) == 1:
if not results[0].action or config.get_localized_string(70006).lower() in results[0].title.lower():
results.clear()
elif item.mode != 'all':
for elem in results:
if not elem.infoLabels.get('year', ""):
elem.infoLabels['year'] = '-'
tmdb.set_infoLabels_item(elem)
if elem.infoLabels['tmdb_id'] == searched_id:
elem.from_channel = ch
if not config.get_setting('unify'):
elem.title += ' [%s]' % ch
valid.append(elem)
if len(results) < 0 and len(results) < max_results and item.mode != 'all': # if len(results) < 0 and len(results) < max_results and item.mode != 'all':
#
# if len(results) == 1:
# if not results[0].action or config.get_localized_string(30992).lower() in results[0].title.lower():
# return [ch, []]
#
# results = get_info(results)
if len(results) == 1: return [search_action, results, valid]
if not results[0].action or config.get_localized_string(30992).lower() in results[0].title.lower():
return [ch, []]
results = get_info(results)
return [search_action, results]
except: except:
return [search_action, results] return [search_action, results, valid]
def get_servers(item, module_dict): def get_servers(item, module_dict):

View File

@@ -15,50 +15,8 @@ from channelselector import get_thumb
from core import filetools, servertools from core import filetools, servertools
from core.item import Item from core.item import Item
from platformcode import config, logger, platformtools from platformcode import config, logger, platformtools
import xbmcgui
CHANNELNAME = "setting" CHANNELNAME = "setting"
AUTOSTART = config.is_autorun_enabled()
def mainlist(item):
logger.info()
itemlist = list()
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60535), action="settings", folder=False,
thumbnail=get_thumb("setting_0.png")))
if AUTOSTART is False:
autostart_mode = config.get_localized_string(70707)
else:
autostart_mode = config.get_localized_string(70708)
itemlist.append(Item(channel=CHANNELNAME, title=autostart_mode + " " + config.get_localized_string(70706), action="autostart", folder=False, thumbnail=get_thumb("setting_0.png")))
#itemlist.append(Item(channel=CHANNELNAME, title="", action="", folder=False, thumbnail=get_thumb("setting_0.png")))
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60536) + ":", text_bold=True, action="", folder=False,
thumbnail=get_thumb("setting_0.png")))
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60537), action="menu_channels", folder=True,
thumbnail=get_thumb("channels.png")))
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60538), action="menu_servers", folder=True,
thumbnail=get_thumb("channels.png")))
itemlist.append(Item(channel="news", title=" " + config.get_localized_string(60539), action="menu_opciones",
folder=True, thumbnail=get_thumb("news.png")))
itemlist.append(Item(channel="search", title=" " + config.get_localized_string(60540), action="opciones", folder=True,
thumbnail=get_thumb("search.png")))
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60541), action="channel_config",
config="downloads", folder=True, thumbnail=get_thumb("downloads.png")))
if config.get_videolibrary_support():
itemlist.append(Item(channel="videolibrary", title=" " + config.get_localized_string(60542), action="channel_config",
folder=True, thumbnail=get_thumb("videolibrary.png")))
if config.is_xbmc():
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(70253), action="setting_torrent",
folder=True, thumbnail=get_thumb("channels_torrent.png")))
#itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False, thumbnail=get_thumb("setting_0.png")))
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60544), action="submenu_tools", folder=True,
thumbnail=get_thumb("setting_0.png")))
return itemlist
def menu_channels(item): def menu_channels(item):
@@ -96,15 +54,6 @@ def channel_config(item):
return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "channels", item.config)) return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "channels", item.config))
def autostart(item): # item required launcher.py line 265
if config.enable_disable_autorun(AUTOSTART):
logger.info('AUTOSTART ENABLED')
# xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70709))
else:
logger.info('AUTOSTART ENABLED')
# xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70710))
# def setting_torrent(item): # def setting_torrent(item):
# logger.info() # logger.info()

View File

@@ -5,7 +5,7 @@ from core.tmdb import Tmdb
from core.scrapertools import htmlclean, decodeHtmlentities from core.scrapertools import htmlclean, decodeHtmlentities
from core.support import thumb, typo, match, Item from core.support import thumb, typo, match, Item
from platformcode import config, platformtools from platformcode import config, platformtools
from platformcode.logger import info, error from platformcode import logger
info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json
def_lang = info_language[config.get_setting("info_language", "videolibrary")] def_lang = info_language[config.get_setting("info_language", "videolibrary")]
@@ -14,9 +14,9 @@ langs = ['auto', 'de', 'fr', 'pt', 'it', 'es-MX', 'ca', 'en', 'es']
langt = langs[config.get_setting('tmdb', "tvmoviedb")] langt = langs[config.get_setting('tmdb', "tvmoviedb")]
if langt == 'auto': langt = def_lang if langt == 'auto': langt = def_lang
langt_alt = langs[config.get_setting('tmdb_alternativo', "tvmoviedb")] langt_alt = langs[config.get_setting('tmdb_alternativo', "tvmoviedb")]
langs = ['auto', 'co', 'cl', 'ar', 'mx', 'en', 'es'] # langs = ['auto', 'co', 'cl', 'ar', 'mx', 'en', 'es']
langf = langs[config.get_setting('filmaff', "tvmoviedb")] # langf = langs[config.get_setting('filmaff', "tvmoviedb")]
if langf == 'auto': langf = 'en' # if langf == 'auto': langf = 'en'
langs = ['auto', 'de-de', 'fr-fr', 'pt-pt', 'it-it', 'es-MX', 'ca-es', 'en', 'es'] langs = ['auto', 'de-de', 'fr-fr', 'pt-pt', 'it-it', 'es-MX', 'ca-es', 'en', 'es']
langi = langs[config.get_setting('imdb', "tvmoviedb")] langi = langs[config.get_setting('imdb', "tvmoviedb")]
if langi == 'auto': langi = def_lang if langi == 'auto': langi = def_lang
@@ -28,7 +28,7 @@ default_fan = filetools.join(config.get_runtime_path(), "fanart.jpg")
def mainlist(item): def mainlist(item):
info() logger.info()
itemlist = [ itemlist = [
# TMDB # TMDB
# item.clone(title=typo(config.get_localized_string(70021), 'bold'), action=""), # item.clone(title=typo(config.get_localized_string(70021), 'bold'), action=""),
@@ -55,7 +55,7 @@ def configuracion(item):
return ret return ret
def search_star(item): def search_star(item):
info() logger.info()
itemlist = [] itemlist = []
item.type='movie' item.type='movie'
@@ -97,7 +97,7 @@ def search_(item):
def searcing(item): def searcing(item):
info() logger.info()
new_item = Item(title=item.contentTitle, text=item.contentTitle.replace("+", " "), mode=item.contentType, infoLabels=item.infoLabels) new_item = Item(title=item.contentTitle, text=item.contentTitle.replace("+", " "), mode=item.contentType, infoLabels=item.infoLabels)
@@ -351,7 +351,7 @@ def list_tmdb(item):
itemlist.append(new_item) itemlist.append(new_item)
except: except:
import traceback import traceback
error(traceback.format_exc()) logger.error(traceback.format_exc())
if orden: if orden:
itemlist.sort(key=lambda item: item.infoLabels["year"], reverse=True) itemlist.sort(key=lambda item: item.infoLabels["year"], reverse=True)
@@ -625,7 +625,7 @@ def indices_tmdb(item):
def filter(item): def filter(item):
info() logger.info()
from datetime import datetime from datetime import datetime
list_controls = [] list_controls = []
@@ -705,7 +705,7 @@ def filtered(item, values):
def musica_movie(item): def musica_movie(item):
info() logger.info()
itemlist = [] itemlist = []
data = match(item).data data = match(item).data
matches = match(data, patron=r'<td class="left">([^<]+)<br><small>([^<]+)</small>.*?<td>(\d+:\d+).*?<p id="([^"]+)"').matches matches = match(data, patron=r'<td class="left">([^<]+)<br><small>([^<]+)</small>.*?<td>(\d+:\d+).*?<p id="([^"]+)"').matches
@@ -729,7 +729,7 @@ def list_imdb(item):
url = 'http://www.imdb.com/search/title?' + item.url url = 'http://www.imdb.com/search/title?' + item.url
# data = httptools.downloadpage(url, headers=headers, replace_headers=True).data # data = httptools.downloadpage(url, headers=headers, replace_headers=True).data
data = match(url, headers=headers).data data = match(url, headers=headers).data
info(data) logger.info(data)
# data = re.sub(r"\n|\r|\t|&nbsp;", "", data) # data = re.sub(r"\n|\r|\t|&nbsp;", "", data)
# data = re.sub(r"\s{2}", " ", data) # data = re.sub(r"\s{2}", " ", data)
@@ -812,7 +812,7 @@ def list_imdb(item):
def filter_imdb(item): def filter_imdb(item):
info() logger.info()
from datetime import datetime from datetime import datetime
list_controls = [] list_controls = []
@@ -1392,7 +1392,7 @@ def indices_imdb(item):
# def filter_fa(item): # def filter_fa(item):
# info() # logger.info()
# from datetime import datetime # from datetime import datetime
# list_controls = [] # list_controls = []
@@ -1494,7 +1494,7 @@ def indices_imdb(item):
# def login_fa(): # def login_fa():
# info() # logger.info()
# try: # try:
# user = config.get_setting("usuariofa", "tvmoviedb") # user = config.get_setting("usuariofa", "tvmoviedb")
@@ -1510,7 +1510,7 @@ def indices_imdb(item):
# data = httptools.downloadpage("https://m.filmaffinity.com/%s/account.ajax.php?action=login" % langf, post=post).data # data = httptools.downloadpage("https://m.filmaffinity.com/%s/account.ajax.php?action=login" % langf, post=post).data
# if "Invalid username" in data: # if "Invalid username" in data:
# error("Error en el login") # logger.error("Error en el login")
# return False, config.get_localized_string(70330) # return False, config.get_localized_string(70330)
# else: # else:
# post = "name=user-menu&url=http://m.filmaffinity.com/%s/main.php" % langf # post = "name=user-menu&url=http://m.filmaffinity.com/%s/main.php" % langf
@@ -1519,11 +1519,11 @@ def indices_imdb(item):
# userid = scrapertools.find_single_match(data, 'id-user=(\d+)') # userid = scrapertools.find_single_match(data, 'id-user=(\d+)')
# if userid: # if userid:
# config.set_setting("userid", userid, "tvmoviedb") # config.set_setting("userid", userid, "tvmoviedb")
# info("Login correcto") # logger.info("Login correcto")
# return True, "" # return True, ""
# except: # except:
# import traceback # import traceback
# error(traceback.format_exc()) # logger.error(traceback.format_exc())
# return False, config.get_localized_string(70331) # return False, config.get_localized_string(70331)
@@ -1644,7 +1644,7 @@ def indices_imdb(item):
# def votar_fa(item): # def votar_fa(item):
# # Window to select the vote # # Window to select the vote
# info() # logger.info()
# list_controls = [] # list_controls = []
# valores = {} # valores = {}
@@ -1752,6 +1752,7 @@ def imagenes(item):
# return itemlist # return itemlist
elif "Imdb" in item.title: elif "Imdb" in item.title:
try: try:
from core import httptools
data = jsontools.load(httptools.downloadpage(item.images["imdb"]["url"], cookies=False).data) data = jsontools.load(httptools.downloadpage(item.images["imdb"]["url"], cookies=False).data)
item.images["imdb"].pop("url") item.images["imdb"].pop("url")
if data.get("allImages"): if data.get("allImages"):
@@ -1920,7 +1921,7 @@ def acciones_trakt(item):
ratings = [] ratings = []
try: try:
for i, entry in enumerate(data): for i, entry in enumerate(data):
info('ENTRY:',entry) logger.info('ENTRY:',entry)
if i <= item.pagina: continue if i <= item.pagina: continue
# try: entry = entry[item.args] # try: entry = entry[item.args]
# except: pass # except: pass
@@ -1974,7 +1975,7 @@ def acciones_trakt(item):
if ratings[i]: new_item.title += typo("Trakt: %.2f | Tmdb: %.2f" % (ratings[i], new_item.infoLabels["rating"]), '_ [] color kod') if ratings[i]: new_item.title += typo("Trakt: %.2f | Tmdb: %.2f" % (ratings[i], new_item.infoLabels["rating"]), '_ [] color kod')
except: except:
import traceback import traceback
error(traceback.format_exc()) logger.error(traceback.format_exc())
if "page" in item.url and len(itemlist) == 20: if "page" in item.url and len(itemlist) == 20:
page = match(item.url, patron=r'page=(\d+)').match page = match(item.url, patron=r'page=(\d+)').match
@@ -1996,7 +1997,7 @@ def acciones_trakt(item):
def order_list(item): def order_list(item):
info() logger.info()
list_controls = [] list_controls = []
valores1 = ['rating', 'added', 'title', 'released', 'runtime', 'popularity', 'percentage', 'votes'] valores1 = ['rating', 'added', 'title', 'released', 'runtime', 'popularity', 'percentage', 'votes']
@@ -2338,7 +2339,7 @@ def indices_mal(item):
matches = match("https://myanimelist.net/anime.php", cookies=False, patronBlock=patronBlock, patron=patron).matches matches = match("https://myanimelist.net/anime.php", cookies=False, patronBlock=patronBlock, patron=patron).matches
for url, title in matches: for url, title in matches:
genero = title.split(" (", 1)[0] genero = title.split(" (", 1)[0]
info(url_base, genero) logger.info(url_base, genero)
thumbnail = url_base + genero.lower().replace(" ", "%20") thumbnail = url_base + genero.lower().replace(" ", "%20")
if genero in ["Hentai", "Yaoi", "Yuri"] and not adult_mal: if genero in ["Hentai", "Yaoi", "Yuri"] and not adult_mal:
continue continue
@@ -2387,7 +2388,7 @@ def season_mal(item):
thumb = thumb.replace("r/167x242/", "") + "l.jpg" thumb = thumb.replace("r/167x242/", "") + "l.jpg"
itemlist.append(Item(channel=item.channel, action="details_mal", url=url, title=title, thumbnail=thumb, infoLabels=infoLabels, args=args, tipo=tipo, contentTitle=scrapedtitle, contentType=contentType, fanart=default_fan)) itemlist.append(Item(channel=item.channel, action="details_mal", url=url, title=title, thumbnail=thumb, infoLabels=infoLabels, args=args, tipo=tipo, contentTitle=scrapedtitle, contentType=contentType, fanart=default_fan))
else: else:
patron = r'<a href="([^"]+)" class="link-title">(.*?)</a>.*?<span>(\? ep|\d+ ep).*?<div class="genres-inner js-genre-inner">(.*?)</div>.*?<div class="image".*?src="(.*?).jpg.*?<span class="preline">(.*?)</span>.*?<div class="info">\s*(.*?)\s*-.*?(\d{4}).*?title="Score">\s*(N/A|\d\.\d+)' patron = r'<a href="([^"]+)" class="link-title">([^<]+)</a>.*?<span>(\? ep|\d+ ep).*?<div class="genres-inner js-genre-inner">(.*?)</div>.*?<div class="image".*?src="([^"]+).*?<span class="preline">(.*?)</span>.*?<div class="info">\s*(.*?)\s*-.*?(\d{4}).*?title="Score">\s*(N/A|\d\.\d+)'
matches = match(data, patron=patron).matches matches = match(data, patron=patron).matches
for url, scrapedtitle, epis, scrapedgenres, thumbnail, plot, tipo, year, score in matches: for url, scrapedtitle, epis, scrapedgenres, thumbnail, plot, tipo, year, score in matches:
if ("Hentai" in scrapedgenres or "Yaoi" in scrapedgenres or "Yuri" in scrapedgenres) and not adult_mal: if ("Hentai" in scrapedgenres or "Yaoi" in scrapedgenres or "Yuri" in scrapedgenres) and not adult_mal:
@@ -2413,7 +2414,7 @@ def season_mal(item):
else: else:
args = "tv" args = "tv"
contentType = "tvshow" contentType = "tvshow"
thumbnail = thumbnail.replace("r/167x242/", "") + "l.jpg" thumbnail = thumbnail.replace(".webp", ".jpg")
itemlist.append(Item(channel=item.channel, action="details_mal", url=url, title=title, itemlist.append(Item(channel=item.channel, action="details_mal", url=url, title=title,
thumbnail=thumbnail, infoLabels=infoLabels, args=args, tipo=tipo, thumbnail=thumbnail, infoLabels=infoLabels, args=args, tipo=tipo,
contentTitle=scrapedtitle, contentType=contentType, contentTitle=scrapedtitle, contentType=contentType,
@@ -2487,7 +2488,7 @@ def detail_staff(item):
patron_bio = r'<?<div class="spaceit_pad">(.*?)</td>' patron_bio = r'<?<div class="spaceit_pad">(.*?)</td>'
bio = match(data, patron=patron_bio).match bio = match(data, patron=patron_bio).match
bio = htmlclean(bio.replace("</div>", "\n")) bio = htmlclean(bio.replace("</div>", "\n"))
info(bio) logger.info(bio)
infoLabels = {'plot': bio} infoLabels = {'plot': bio}
if not "No voice acting roles" in data: if not "No voice acting roles" in data:
itemlist.append(Item(channel=item.channel, title=typo(config.get_localized_string(70374),'bold bullet'), action="", thumbnail=item.thumbnail, infoLabels=infoLabels)) itemlist.append(Item(channel=item.channel, title=typo(config.get_localized_string(70374),'bold bullet'), action="", thumbnail=item.thumbnail, infoLabels=infoLabels))
@@ -2550,7 +2551,7 @@ def searching_mal(item):
title += " (%s)" % year title += " (%s)" % year
except: except:
import traceback import traceback
error(traceback.format_exc()) logger.error(traceback.format_exc())
if tipo == "Movie" or tipo == "OVA": if tipo == "Movie" or tipo == "OVA":
infolabels["mediatype"] = "movie" infolabels["mediatype"] = "movie"
@@ -2625,7 +2626,7 @@ def info_anidb(item, itemlist, url):
def filter_mal(item): def filter_mal(item):
info() logger.info()
list_controls = [] list_controls = []
valores = {} valores = {}
@@ -2703,7 +2704,7 @@ def callback_mal(item, values):
def musica_anime(item): def musica_anime(item):
# List available anime and songs similar to the anime title # List available anime and songs similar to the anime title
info() logger.info()
itemlist = [] itemlist = []
data = match("http://www.freeanimemusic.org/song_search.php", post=item.post).data data = match("http://www.freeanimemusic.org/song_search.php", post=item.post).data
@@ -2738,7 +2739,7 @@ def musica_anime(item):
def login_mal(from_list=False): def login_mal(from_list=False):
info() logger.info()
from core import httptools from core import httptools
from base64 import b64decode as bdec from base64 import b64decode as bdec
@@ -2762,16 +2763,16 @@ def login_mal(from_list=False):
response = httptools.downloadpage("https://myanimelist.net/login.php?from=%2F", post=post) response = httptools.downloadpage("https://myanimelist.net/login.php?from=%2F", post=post)
if not re.search(r'(?i)' + user, response.data): if not re.search(r'(?i)' + user, response.data):
error("Login failed") logger.error("Login failed")
return False, config.get_localized_string(70330), user return False, config.get_localized_string(70330), user
else: else:
if generic: if generic:
return False, config.get_localized_string(70393), user return False, config.get_localized_string(70393), user
info("Correct login") logger.info("Correct login")
return True, "", user return True, "", user
except: except:
import traceback import traceback
error(traceback.format_exc()) logger.error(traceback.format_exc())
return False, config.get_localized_string(70331) , '' return False, config.get_localized_string(70331) , ''
@@ -2799,7 +2800,7 @@ def cuenta_mal(item):
def items_mal(item): def items_mal(item):
# Scraper for personal lists # Scraper for personal lists
info() logger.info()
itemlist = [] itemlist = []
data = match(item.url).data data = match(item.url).data

16
tests/run.sh Executable file
View File

@@ -0,0 +1,16 @@
rm tests/home/userdata/addon_data/plugin.video.kod/settings_channels/*.json
rm tests/home/userdata/addon_data/plugin.video.kod/settings_servers/*.json
rm tests/home/userdata/addon_data/plugin.video.kod/cookies.dat
rm tests/home/userdata/addon_data/plugin.video.kod/kod_db.sqlite
python -m pip install --upgrade pip
pip install sakee
pip install html-testRunner
pip install parameterized
export PYTHONPATH=$PWD
export KODI_INTERACTIVE=0
export KODI_HOME=$PWD/tests/home
if (( $# >= 1 ))
then
export KOD_TST_CH=$1
fi
python tests/test_generic.py

View File

@@ -120,7 +120,7 @@ chNumRis = {
'Serie TV': 12 'Serie TV': 12
}, },
'serietvonline': { 'serietvonline': {
'Film': 50, 'Film': 25,
'Serie TV': 35 'Serie TV': 35
}, },
'tantifilm': { 'tantifilm': {
@@ -135,6 +135,8 @@ channels = []
channel_list = channelselector.filterchannels("all") if 'KOD_TST_CH' not in os.environ else [Item(channel=os.environ['KOD_TST_CH'], action="mainlist")] channel_list = channelselector.filterchannels("all") if 'KOD_TST_CH' not in os.environ else [Item(channel=os.environ['KOD_TST_CH'], action="mainlist")]
logger.info(channel_list) logger.info(channel_list)
ret = [] ret = []
logger.record = True
for chItem in channel_list: for chItem in channel_list:
try: try:
ch = chItem.channel ch = chItem.channel
@@ -143,6 +145,7 @@ for chItem in channel_list:
hasChannelConfig = False hasChannelConfig = False
mainlist = module.mainlist(Item()) mainlist = module.mainlist(Item())
menuItemlist = {} menuItemlist = {}
logMenu = {}
serversFound = {} serversFound = {}
for it in mainlist: for it in mainlist:
@@ -155,6 +158,8 @@ for chItem in channel_list:
continue continue
itemlist = getattr(module, it.action)(it) itemlist = getattr(module, it.action)(it)
menuItemlist[it.title] = itemlist menuItemlist[it.title] = itemlist
logMenu[it.title] = logger.recordedLog
logger.recordedLog = ''
# some sites might have no link inside, but if all results are without servers, there's something wrong # some sites might have no link inside, but if all results are without servers, there's something wrong
for resIt in itemlist: for resIt in itemlist:
@@ -165,16 +170,22 @@ for chItem in channel_list:
serversFound[it.title] = [resIt] serversFound[it.title] = [resIt]
if serversFound[it.title]: if serversFound[it.title]:
if hasattr(module, 'play'):
serversFound[it.title] = [getattr(module, 'play')(resIt)[0] for srv in serversFound[it.title]]
servers.extend( servers.extend(
{'name': srv.server.lower(), 'server': srv} for srv in serversFound[it.title] if srv.server) {'name': srv.server.lower(), 'server': srv} for srv in serversFound[it.title] if srv.server)
break break
channels.append( channels.append(
{'ch': ch, 'hasChannelConfig': hasChannelConfig, 'mainlist': mainlist, 'menuItemlist': menuItemlist, {'ch': ch, 'hasChannelConfig': hasChannelConfig, 'mainlist': mainlist, 'menuItemlist': menuItemlist,
'serversFound': serversFound, 'module': module}) 'serversFound': serversFound, 'module': module, 'logMenu': logMenu})
except: except:
import traceback import traceback
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
print(logger.recordedLog)
logger.recordedLog = ''
logger.record = False
from specials import news from specials import news
dictNewsChannels, any_active = news.get_channels_list() dictNewsChannels, any_active = news.get_channels_list()
@@ -203,12 +214,26 @@ class GenericChannelTest(unittest.TestCase):
break break
def testnameCh(cls, num, params_dict):
return 'channels.' + params_dict['ch'] + ' -> ' + params_dict['title']
def testnameSrv(cls, num, params_dict):
return 'servers.' + params_dict['name']
@parameterized.parameterized_class( @parameterized.parameterized_class(
[{'ch': ch['ch'], 'title': title, 'itemlist': itemlist, 'serversFound': ch['serversFound'][title] if title in ch['serversFound'] else True, 'module': ch['module']} for ch in channels for [{'ch': ch['ch'], 'title': title, 'itemlist': itemlist,
title, itemlist in ch['menuItemlist'].items()]) 'serversFound': ch['serversFound'][title] if title in ch['serversFound'] else True,
'module': ch['module'], 'log': ch['logMenu'][title]}
for ch in channels
for title, itemlist in ch['menuItemlist'].items()], class_name_func=testnameCh)
class GenericChannelMenuItemTest(unittest.TestCase): class GenericChannelMenuItemTest(unittest.TestCase):
def test_menu(self): def test_menu(self):
print('testing ' + self.ch + ' --> ' + self.title) print('testing ' + self.ch + ' --> ' + self.title)
logger.info(self.log)
self.assertTrue(self.module.host, 'channel ' + self.ch + ' has not a valid hostname') self.assertTrue(self.module.host, 'channel ' + self.ch + ' has not a valid hostname')
self.assertTrue(self.itemlist, 'channel ' + self.ch + ' -> ' + self.title + ' is empty') self.assertTrue(self.itemlist, 'channel ' + self.ch + ' -> ' + self.title + ' is empty')
self.assertTrue(self.serversFound, self.assertTrue(self.serversFound,
@@ -217,7 +242,7 @@ class GenericChannelMenuItemTest(unittest.TestCase):
if self.ch in chNumRis: # i know how much results should be if self.ch in chNumRis: # i know how much results should be
for content in chNumRis[self.ch]: for content in chNumRis[self.ch]:
if content in self.title: if content in self.title:
risNum = len([i for i in self.itemlist if not i.nextPage]) # not count nextpage risNum = len([i for i in self.itemlist if i.title != typo(config.get_localized_string(30992), 'color kod bold')]) # not count nextpage
self.assertEqual(chNumRis[self.ch][content], risNum, self.assertEqual(chNumRis[self.ch][content], risNum,
'channel ' + self.ch + ' -> ' + self.title + ' returned wrong number of results<br>' 'channel ' + self.ch + ' -> ' + self.title + ' returned wrong number of results<br>'
+ str(risNum) + ' but should be ' + str(chNumRis[self.ch][content]) + '<br>' + + str(risNum) + ' but should be ' + str(chNumRis[self.ch][content]) + '<br>' +
@@ -246,48 +271,46 @@ class GenericChannelMenuItemTest(unittest.TestCase):
self.assertTrue(nextPageItemlist, self.assertTrue(nextPageItemlist,
'channel ' + self.ch + ' -> ' + self.title + ' has nextpage not working') 'channel ' + self.ch + ' -> ' + self.title + ' has nextpage not working')
print('<br>test passed') print('test passed')
@parameterized.parameterized_class(serversFinal) @parameterized.parameterized_class(serversFinal, class_name_func=testnameSrv)
class GenericServerTest(unittest.TestCase): class GenericServerTest(unittest.TestCase):
def test_get_video_url(self): def test_get_video_url(self):
module = __import__('servers.%s' % self.name, fromlist=["servers.%s" % self.name]) module = __import__('servers.%s' % self.name, fromlist=["servers.%s" % self.name])
page_url = self.server.url page_url = self.server.url
print('testing ' + page_url) print('testing ' + page_url)
self.assert_(hasattr(module, 'test_video_exists'), self.name + ' has no test_video_exists') self.assert_(hasattr(module, 'test_video_exists'), self.name + ' has no test_video_exists')
try:
if module.test_video_exists(page_url)[0]: if module.test_video_exists(page_url)[0]:
urls = module.get_video_url(page_url) urls = module.get_video_url(page_url)
server_parameters = servertools.get_server_parameters(self.name) server_parameters = servertools.get_server_parameters(self.name)
self.assertTrue(urls or server_parameters.get("premium"), self.assertTrue(urls or server_parameters.get("premium"),
self.name + ' scraper did not return direct urls for ' + page_url) self.name + ' scraper did not return direct urls for ' + page_url)
print(urls) print(urls)
for u in urls: for u in urls:
spl = u[1].split('|') spl = u[1].split('|')
if len(spl) == 2: if len(spl) == 2:
directUrl, headersUrl = spl directUrl, headersUrl = spl
else: else:
directUrl, headersUrl = spl[0], '' directUrl, headersUrl = spl[0], ''
headers = {} headers = {}
if headersUrl: if headersUrl:
for name in headersUrl.split('&'): for name in headersUrl.split('&'):
h, v = name.split('=') h, v = name.split('=')
h = str(h) h = str(h)
headers[h] = str(v) headers[h] = str(v)
print(headers) print(headers)
if 'magnet:?' in directUrl: # check of magnet links not supported if 'magnet:?' in directUrl: # check of magnet links not supported
continue continue
page = downloadpage(directUrl, headers=headers, only_headers=True, use_requests=True) page = downloadpage(directUrl, headers=headers, only_headers=True, use_requests=True, verify=False)
self.assertTrue(page.success, self.name + ' scraper returned an invalid link') self.assertTrue(page.success, self.name + ' scraper returned an invalid link')
self.assertLess(page.code, 400, self.name + ' scraper returned a ' + str(page.code) + ' link') self.assertLess(page.code, 400, self.name + ' scraper returned a ' + str(page.code) + ' link')
contentType = page.headers['Content-Type'] contentType = page.headers['Content-Type']
self.assert_(contentType.startswith( self.assert_(contentType.startswith(
'video') or 'mpegurl' in contentType or 'octet-stream' in contentType or 'dash+xml' in contentType, 'video') or 'mpegurl' in contentType or 'octet-stream' in contentType or 'dash+xml' in contentType,
self.name + ' scraper did not return valid url for link ' + page_url + '<br>Direct url: ' + directUrl + '<br>Content-Type: ' + contentType) self.name + ' scraper did not return valid url for link ' + page_url + '<br>Direct url: ' + directUrl + '<br>Content-Type: ' + contentType)
except: print('test passed')
import traceback
logger.error(traceback.format_exc())
if __name__ == '__main__': if __name__ == '__main__':