diff --git a/addon.xml b/addon.xml index 7dde268d..39a5c1ff 100644 --- a/addon.xml +++ b/addon.xml @@ -1,4 +1,4 @@ - + @@ -26,9 +26,8 @@ resources/media/themes/ss/2.png resources/media/themes/ss/3.png - - completato il supporto al futuro Kodi 19 -- ridisegnato infoplus -- fix vari ed eventuali + - ridisegnata la finestra della scelta film/serietv quando si aggiunge in videoteca +- modifiche minori, qualche fix ai canali/server ed alla ricerca alternativa Naviga velocemente sul web e guarda i contenuti presenti [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] diff --git a/channels.json b/channels.json index c8a30e83..ff664006 100644 --- a/channels.json +++ b/channels.json @@ -1,48 +1,57 @@ { - "altadefinizione01": "https://www.altadefinizione01.green", - "altadefinizione01_link": "https://altadefinizione01.energy", - "altadefinizioneclick": "https://altadefinizione.vote", - "animealtadefinizione": "https://www.animealtadefinizione.it", - "animeforce": "https://ww1.animeforce.org", - "animeleggendari": "https://animeora.com", - "animesaturn": "https://www.animesaturn.it", - "animestream": "https://www.animeworld.tv", - "animesubita": "http://www.animesubita.org", - "animetubeita": "http://www.animetubeita.com", - "animeunity": "https://www.animeunity.it", - "animeuniverse": "https://www.animeuniverse.it/", - "animeworld": "https://www.animeworld.tv", - "casacinema": "https://www.casacinema.page", - "cb01anime": "https://www.cineblog01.red", - "cinemalibero": "https://www.cinemalibero.space", - "cinetecadibologna": "http://cinestore.cinetecadibologna.it", - "dreamsub": "https://dreamsub.stream", - "dsda": "https://www.dsda.press", - "fastsubita": "https://fastsubita.online", - "filmgratis": "https://www.filmaltadefinizione.tv", - "filmigratis": "https://filmigratis.org", - "filmpertutti": "https://www.filmpertutti.fun", - "filmsenzalimiticc": "https://www.filmsenzalimiti01.casa", - "filmstreaming01": "https://filmstreaming01.com", - "guardaserie_stream": "https://guardaserie.host", - "guardaseriecam": "https://guardaserie.cam", - "guardaserieclick": "https://www.guardaserie.blue", - "guardaserieicu": "https://guardaserie.us", - "hd4me": "https://hd4me.net", - "ilgeniodellostreaming": "https://ilgeniodellostreaming.fi", - "ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.tel", - "italiaserie": "https://italiaserie.org", - "mondoserietv": "https://mondoserietv.fun", - "piratestreaming": "https://www.piratestreaming.buzz", - "polpotv": "https://polpotv.life", - "raiplay": "https://www.raiplay.it", - "seriehd": "https://seriehd.group", - "serietvonline": "https://serietvonline.biz", - "serietvsubita": "http://serietvsubita.xyz", - "serietvu": "https://www.serietvu.link", - "streamingcommunity": "https://streamingcommunity.to", - "streamtime": "https://t.me/s/StreamTime", - "tantifilm": "https://www.tantifilm.tel", - "toonitalia": "https://toonitalia.org", - "vvvvid": "https://www.vvvvid.it" + "findhost": { + "altadefinizione01": "https://altadefinizione01-nuovo.info", + "altadefinizioneclick": "https://altadefinizione-nuovo.me", + "animealtadefinizione": "https://www.animealtadefinizione.it", + "cineblog01": "https://cb01.uno", + "eurostreaming": "https://eurostreaming.link", + "ilcorsaronero": "https://lagazzettadelcorsaro.com", + "seriehd": "https://nuovoindirizzo.info/seriehd/", + "serietvonline": "https://serietvonline.online", + "tantifilm": "https://www.tantifilm.wiki", + "film4k": "https://film4k-nuovo.link" + }, + "direct": { + "altadefinizione01_link": "https://altadefinizione01.energy", + "animealtadefinizione": "https://www.animealtadefinizione.it", + "animeforce": "https://ww1.animeforce.org", + "animeleggendari": "https://animeora.com", + "animesaturn": "https://www.animesaturn.it", + "animestream": "https://www.animeworld.tv", + "animesubita": "http://www.animesubita.org", + "animetubeita": "http://www.animetubeita.com", + "animeunity": "https://www.animeunity.it", + "animeuniverse": "https://www.animeuniverse.it/", + "animeworld": "https://www.animeworld.tv", + "casacinema": "https://www.casacinema.page", + "cb01anime": "https://www.cineblog01.red", + "cinemalibero": "https://www.cinemalibero.space", + "cinetecadibologna": "http://cinestore.cinetecadibologna.it", + "dreamsub": "https://dreamsub.stream", + "dsda": "https://www.dsda.press", + "fastsubita": "https://fastsubita.online", + "filmgratis": "https://www.filmaltadefinizione.tv", + "filmigratis": "https://filmigratis.org", + "filmpertutti": "https://www.filmpertutti.fun", + "filmsenzalimiticc": "https://www.filmsenzalimiti01.casa", + "filmstreaming01": "https://filmstreaming01.com", + "guardaserie_stream": "https://guardaserie.host", + "guardaseriecam": "https://guardaserie.cam", + "guardaserieclick": "https://www.guardaserie.blue", + "guardaserieicu": "https://guardaserie.us", + "hd4me": "https://hd4me.net", + "ilgeniodellostreaming": "https://ilgeniodellostreaming.fi", + "ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.tel", + "italiaserie": "https://italiaserie.org", + "mondoserietv": "https://mondoserietv.fun", + "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" + } } \ No newline at end of file diff --git a/channels/0example.py.txt b/channels/0example.py.txt index 7ee29078..e09fca3c 100644 --- a/channels/0example.py.txt +++ b/channels/0example.py.txt @@ -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 # la funzione deve ritornare l'indirizzo corretto, verrà chiamata solo se necessario (link primario irraggiungibile) -def findhost(): - def findhost(): - permUrl = httptools.downloadpage('https://www.cb01.uno/', follow_redirects=False).headers +def findhost(url): + permUrl = httptools.downloadpage(url, follow_redirects=False).headers if 'google' in permUrl['location']: host = permUrl['location'].replace('https://www.google.it/search?q=site:', '') else: host = permUrl['location'] 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) -# 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() headers = [['Referer', host]] diff --git a/channels/altadefinizione01.py b/channels/altadefinizione01.py index 19d2396d..2d5c351c 100644 --- a/channels/altadefinizione01.py +++ b/channels/altadefinizione01.py @@ -17,10 +17,9 @@ from core import scrapertools, httptools, support from core.item import Item from platformcode import config, logger -#impostati dinamicamente da findhost() -def findhost(): - data = httptools.downloadpage('https://altadefinizione01-nuovo.info/').data +def findhost(url): + data = httptools.downloadpage(url).data host = scrapertools.find_single_match(data, '
]+>]+>\s*cliccando qui').matches[-1] +def findhost(url): + host = support.match(url, patron=r'href="([^"]+)">\s*cliccando qui').matches[-1] return host host = config.get_channel_url(findhost) diff --git a/channels/streamingaltadefinizione.py b/channels/streamingaltadefinizione.py index 8e5df681..f0685434 100644 --- a/channels/streamingaltadefinizione.py +++ b/channels/streamingaltadefinizione.py @@ -13,8 +13,8 @@ else: from urllib import unquote -def findhost(): - data = httptools.downloadpage('https://www.popcornstream-nuovo-indirizzo.online/').data +def findhost(url): + data = httptools.downloadpage(url).data return support.scrapertools.find_single_match(data, '= 3 else xbmc.LOGNOTICE @@ -28,6 +37,10 @@ def error(*args): def log(*args, **kwargs): msg = '' for arg in args: msg += ' ' + str(arg) + if testMode and record: + global recordedLog + recordedLog += msg + '\n' + return frame = inspect.currentframe().f_back.f_back filename = frame.f_code.co_filename filename = os.path.basename(filename).split('.')[0] diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index 1e6c24a1..2372a28b 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -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=''): + 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) return dialog @@ -1274,68 +1338,3 @@ def get_platform(): ret["arch"] = "arm" 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() \ No newline at end of file diff --git a/platformcode/shortcuts.py b/platformcode/shortcuts.py index 2334d60d..d5effcf2 100644 --- a/platformcode/shortcuts.py +++ b/platformcode/shortcuts.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from platformcode import logger, side_menu +from platformcode import logger def context(): @@ -18,6 +18,7 @@ def context(): return context def Side_menu(item): + from platformcode import side_menu side_menu.open_menu(item) def shortcut_menu(item): diff --git a/platformcode/updater.py b/platformcode/updater.py index 674a95e2..3e70d698 100644 --- a/platformcode/updater.py +++ b/platformcode/updater.py @@ -161,8 +161,12 @@ def check(background=False): if addon.getSetting("addon_update_message"): if background: 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: - fileC.write(changelog) + try: + with open(xbmc.translatePath(changelogFile), 'a+') as fileC: + fileC.write(changelog) + except: + import traceback + logger.error(traceback.format_exc()) elif changelog: platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80041) + changelog) else: @@ -175,7 +179,8 @@ def showSavedChangelog(): try: with open(xbmc.translatePath(changelogFile), 'r') as fileC: 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)) except: pass diff --git a/platformcode/xbmc_info_window.py b/platformcode/xbmc_info_window.py index 19148fa2..a4452cd3 100644 --- a/platformcode/xbmc_info_window.py +++ b/platformcode/xbmc_info_window.py @@ -4,332 +4,52 @@ import xbmcgui from core.tmdb import Tmdb from platformcode import config, logger +from core import filetools -ID_BUTTON_CLOSE = 10003 -ID_BUTTON_PREVIOUS = 10025 -ID_BUTTON_NEXT = 10026 -ID_BUTTON_CANCEL = 10027 -ID_BUTTON_OK = 10028 +BACKGROUND = 30000 +LOADING = 30001 +SELECT = 30002 +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): - otmdb = None - item_title = "" - item_serie = "" - item_temporada = 0 - item_episodio = 0 - 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 + def start(self, results, caption="", item=None, scraper=Tmdb): + self.items = [] + self.response = None + self.results = results self.item = item - self.indexList = -1 - self.listData = None - self.return_value = None 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() - return self.return_value - - def __init__(self, *args): - self.caption = "" - self.item = None - self.listData = None - self.indexList = 0 - self.return_value = None - self.scraper = Tmdb + logger.info('RESPONSE',self.response) + return self.response def onInit(self): - #### Kodi 18 compatibility #### if config.get_platform(True)['num_version'] < 18: - if xbmcgui.__version__ == "1.2": - self.setCoordinateResolution(1) - else: - self.setCoordinateResolution(5) + self.setCoordinateResolution(2) - # We put the title and the images - self.getControl(10002).setLabel(self.caption) - self.getControl(10004).setImage(self.result.get("fanart", "")) - self.getControl(10005).setImage(self.result.get("thumbnail", "images/img_no_disponible.png")) + for result in self.results: + infoLabels = self.scraper().get_infoLabels(origen=result) + it = xbmcgui.ListItem(infoLabels['title']) + 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 - if self.result.get("mediatype", "movie") == "movie": - self.getControl(10006).setLabel(config.get_localized_string(60377)) - self.getControl(10007).setLabel(self.result.get("title", "N/A")) - 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")) + self.getControl(SELECT).addItems(self.items) + self.getControl(BACKGROUND).setImage(self.items[0].getProperty('fanart')) + self.getControl(LOADING).setVisible(False) + self.setFocusId(SELECT) - # We load the data for the serial format - else: - self.getControl(10006).setLabel(config.get_localized_string(60383)) - self.getControl(10007).setLabel(self.result.get("title", "N/A")) - 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")) + def onClick(self, control_id): + if control_id == SELECT: + self.response = self.results[self.getControl(SELECT).getSelectedPosition()] + self.close() - 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) diff --git a/resources/settings.xml b/resources/settings.xml index c317b4ec..6edd64e5 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -3,7 +3,7 @@ - + diff --git a/resources/skins/Default/720p/InfoWindow.xml b/resources/skins/Default/720p/InfoWindow.xml index 93137c24..6c3d099d 100644 --- a/resources/skins/Default/720p/InfoWindow.xml +++ b/resources/skins/Default/720p/InfoWindow.xml @@ -1,375 +1,124 @@ - + - false - - - - - - - - - - - 0 - 0 + 0.52 + + 0 + 0 + + + + + 0 + 0 + 100% + 100% + white.png + white.png + WindowOpen + WindowClose + Action(close) + + + + 0 + 0 + + + + + + + + + + + + 1280 + 720 + + + + + + 355 + 490 + 300 + 10 + white.png + Conditional + + + + + 40 100% - 100% - - 100% - 100% - white.png - - - - 0 - 0 - 100% - 100% - - 33FFFFFF - - - - 20 - 0 - 34 - 100% - font30_title - FFFFFFFF - center - center - - - - - 30 - 25 - 30 - 30 - close.png - close.png - - - - 30 - 110 - 349 - 500 - - keep - - - - - - - - - - - - 100 - 60 - 30 - 200 - font13 - FFFFFFFF - black - left - top - - - - 100 - 250 - 30 - 365 - font13 - | - true - FFFFFFFF - black - left - top - - - - 130 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 130 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 160 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 160 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 190 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 190 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 220 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 220 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 250 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 250 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 280 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 280 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 310 - 60 - 30 - 200 - font13 - 0xFFFFFFFF - black - left - top - - - - 310 - 250 - 30 - 365 - font13 - | - true - 0xFFFFFFFF - black - left - top - - - - 330 - 60 - 30 - 505 - font13 - 0xFFFFFFFF - black - left - top - - - - 330 - 250 - 250 - 550 - font13 - 0xFFFFFFFF - black - true - true - justify - top - - - - - 60 - 40 - 760 - 30 - - - 0 + 640 + wrap + horizontal + 300 + + + + 0 0 - 200 - 50 - 110 - white.png - white.png - center - center - + 180 + 270 + $INFO[ListItem.Property(thumbnail)] + scale + 10 - - 0 - 210 - 200 - 50 - 110 - white.png - white.png - center - center - - - - 0 - 420 - 200 - 50 - 110 - white.png - white.png - center - center - - - - 0 - 640 - 200 - 50 - 110 - white.png - white.png - center - center - - - + + + + + 500 10 - 1080 + 730 + 30 + font30_title + FFFFFFFF + 00000000 + + left + center + + + + 500 + 50 + 730 30 - 110 font13 FFFFFFFF - black - right - center - + 00000000 + + left - + + + 500 + 90 + 730 + 250 + font13 + FFFFFFFF + 00000000 + + True + left + + + + 0 + 0 + 480 + 640 + $INFO[ListItem.Property(thumbnail)] + scale + 10 + + - + + diff --git a/resources/skins/Default/720p/SearchWindow.xml b/resources/skins/Default/720p/SearchWindow.xml index 4f82354b..5e33ff22 100644 --- a/resources/skins/Default/720p/SearchWindow.xml +++ b/resources/skins/Default/720p/SearchWindow.xml @@ -39,12 +39,12 @@ - 310 - 590 - 100 - 100 - Infoplus/loading.png - Conditional + 355 + 490 + 300 + 10 + white.png + Conditional @@ -90,7 +90,7 @@ font30_title FFFFFFFF 00000000 - + left center diff --git a/resources/skins/Default/720p/ServersWindow.xml b/resources/skins/Default/720p/ServersWindow.xml index bd3ec155..ecac85eb 100644 --- a/resources/skins/Default/720p/ServersWindow.xml +++ b/resources/skins/Default/720p/ServersWindow.xml @@ -39,12 +39,12 @@ - 310 - 590 - 100 - 100 - Infoplus/loading.png - Conditional + 355 + 490 + 300 + 10 + white.png + Conditional diff --git a/servers/akvideo.py b/servers/akvideo.py index 14ff3836..346b3ff3 100644 --- a/servers/akvideo.py +++ b/servers/akvideo.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- -import urllib +try: + import urllib.parse as urllib +except ImportError: + import urllib from core import httptools, support 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']] + def test_video_exists(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) diff --git a/servers/nowvideo.py b/servers/nowvideo.py index 170b3f94..95271e63 100644 --- a/servers/nowvideo.py +++ b/servers/nowvideo.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- -import urllib +try: + import urllib.parse as urllib +except ImportError: + import urllib from core import httptools from core import scrapertools diff --git a/servers/onlystream.py b/servers/onlystream.py index 12d68cd1..2deef1a7 100644 --- a/servers/onlystream.py +++ b/servers/onlystream.py @@ -8,7 +8,8 @@ from platformcode import config, logger def test_video_exists(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: 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=""): logger.info("url=" + page_url) - data = httptools.downloadpage(page_url).data + global data # logger.info(data) video_urls = support.get_jwplayer_mediaurl(data, 'Onlystream') return video_urls diff --git a/servers/streamtape.py b/servers/streamtape.py index 5bc74691..d4fcf845 100644 --- a/servers/streamtape.py +++ b/servers/streamtape.py @@ -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 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): logger.info("(page_url='%s')" % page_url) 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: - return False, config.get_localized_string(70449) % "Streamtape" + return False, "[streamtape] El archivo no existe o ha sido borrado" + return True, "" def get_video_url(page_url, premium=False, user="", password="", video_password=""): logger.info("url=" + page_url) + video_urls = [] - global data - - url = scrapertools.find_single_match(data, 'id="videolink"[^>]+>\n?\s*//(.*?)<') - if url: - media_url = 'https://' + url + '&stream=1' - video_urls.append([".mp4 [Streamtape]", media_url]) - - return video_urls + url = "https:" + scrapertools.find_single_match(data, 'innerHTML = "([^"]+)') + url = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers.get("location", "") + video_urls.append(['MP4 [streamtape]', url]) + return video_urls \ No newline at end of file diff --git a/servers/turbovid.py b/servers/turbovid.py index 8353df9b..4bb6b993 100644 --- a/servers/turbovid.py +++ b/servers/turbovid.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- import time -import urllib +try: + import urllib.parse as urllib +except ImportError: + import urllib from core import httptools, support from core import scrapertools diff --git a/servers/vupplayer.py b/servers/vupplayer.py index 432b0d14..4b228eb6 100644 --- a/servers/vupplayer.py +++ b/servers/vupplayer.py @@ -9,7 +9,7 @@ def test_video_exists(page_url): page = httptools.downloadpage(page_url) global 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 True, "" diff --git a/service.py b/service.py index 12db63fc..ada1b043 100644 --- a/service.py +++ b/service.py @@ -8,6 +8,12 @@ import traceback import xbmc import xbmcgui 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')) sys.path.insert(0, librerias) @@ -396,6 +402,12 @@ class AddonMonitor(xbmc.Monitor): if __name__ == "__main__": 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() # mark as stopped all downloads (if we are here, probably kodi just started) diff --git a/specials/community.py b/specials/community.py index dafccfda..0c587ba9 100644 --- a/specials/community.py +++ b/specials/community.py @@ -137,7 +137,11 @@ def search(item, text): json = load_json(item) if 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 diff --git a/specials/favorites.py b/specials/favorites.py index b6fe9720..d7c885bc 100644 --- a/specials/favorites.py +++ b/specials/favorites.py @@ -138,7 +138,10 @@ def renameFavourite(item): # Features to migrate old favorites (.txt) def readbookmark(filepath): logger.info() - import urllib + try: + import urllib.parse as urllib + except ImportError: + import urllib bookmarkfile = filetools.file_open(filepath) diff --git a/specials/filmontv.py b/specials/filmontv.py index 47f1c0dc..5def299e 100644 --- a/specials/filmontv.py +++ b/specials/filmontv.py @@ -4,8 +4,10 @@ # ------------------------------------------------------------ import re -import urllib -from channelselector import get_thumb +try: + import urllib.parse as urllib +except ImportError: + import urllib from core import httptools, scrapertools, support, tmdb, filetools from core.item import Item from platformcode import logger, config, platformtools diff --git a/specials/search.py b/specials/search.py index ae6e1719..a1a3ca4b 100644 --- a/specials/search.py +++ b/specials/search.py @@ -174,10 +174,10 @@ def channel_search(item): mode = item.mode if item.infoLabels['tvshowtitle']: - item.text = item.infoLabels['tvshowtitle'].split('-')[0] + item.text = item.infoLabels['tvshowtitle'].split(' - ')[0] item.title = item.text elif item.infoLabels['title']: - item.text = item.infoLabels['title'].split('-')[0] + item.text = item.infoLabels['title'].split(' - ')[0] item.title = item.text temp_search_file = config.get_temp_file('temp-search') @@ -235,6 +235,8 @@ def channel_search(item): if channel not in ch_list: ch_list[channel] = [] ch_list[channel].extend(res.result()[1]) + if res.result()[2]: + valid.extend(res.result()[2]) if progress.iscanceled(): break @@ -261,21 +263,7 @@ def channel_search(item): ch_name = channel_titles[channel_list.index(key)] grouped = list() cnt += 1 - progress.update(old_div((cnt * 100), len(ch_list)), config.get_localized_string(60295) + '\n' + config.get_localized_string(60293)) - 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) + progress.update(old_div((cnt * 100), len(ch_list)), config.get_localized_string(60295)) for it in value: if it.channel == item.channel: @@ -355,24 +343,38 @@ def channel_search(item): def get_channel_results(item, module_dict, search_action): ch = search_action.channel - max_results = 10 results = list() + valid = list() module = module_dict[ch] + searched_id = item.infoLabels['tmdb_id'] try: 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: - 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] + return [search_action, results, valid] except: - return [search_action, results] + return [search_action, results, valid] def get_servers(item, module_dict): diff --git a/specials/setting.py b/specials/setting.py index 895ffc27..cf7b9fa0 100644 --- a/specials/setting.py +++ b/specials/setting.py @@ -15,50 +15,8 @@ from channelselector import get_thumb from core import filetools, servertools from core.item import Item from platformcode import config, logger, platformtools -import xbmcgui 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): @@ -96,15 +54,6 @@ def channel_config(item): 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): # logger.info() diff --git a/specials/tvmoviedb.py b/specials/tvmoviedb.py index baa0124a..a181f044 100644 --- a/specials/tvmoviedb.py +++ b/specials/tvmoviedb.py @@ -5,7 +5,7 @@ from core.tmdb import Tmdb from core.scrapertools import htmlclean, decodeHtmlentities from core.support import thumb, typo, match, Item 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 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")] if langt == 'auto': langt = def_lang langt_alt = langs[config.get_setting('tmdb_alternativo', "tvmoviedb")] -langs = ['auto', 'co', 'cl', 'ar', 'mx', 'en', 'es'] -langf = langs[config.get_setting('filmaff', "tvmoviedb")] -if langf == 'auto': langf = 'en' +# langs = ['auto', 'co', 'cl', 'ar', 'mx', 'en', 'es'] +# langf = langs[config.get_setting('filmaff', "tvmoviedb")] +# if langf == 'auto': langf = 'en' langs = ['auto', 'de-de', 'fr-fr', 'pt-pt', 'it-it', 'es-MX', 'ca-es', 'en', 'es'] langi = langs[config.get_setting('imdb', "tvmoviedb")] if langi == 'auto': langi = def_lang @@ -28,7 +28,7 @@ default_fan = filetools.join(config.get_runtime_path(), "fanart.jpg") def mainlist(item): - info() + logger.info() itemlist = [ # TMDB # item.clone(title=typo(config.get_localized_string(70021), 'bold'), action=""), @@ -55,7 +55,7 @@ def configuracion(item): return ret def search_star(item): - info() + logger.info() itemlist = [] item.type='movie' @@ -97,7 +97,7 @@ def search_(item): def searcing(item): - info() + logger.info() 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) except: import traceback - error(traceback.format_exc()) + logger.error(traceback.format_exc()) if orden: itemlist.sort(key=lambda item: item.infoLabels["year"], reverse=True) @@ -625,7 +625,7 @@ def indices_tmdb(item): def filter(item): - info() + logger.info() from datetime import datetime list_controls = [] @@ -705,7 +705,7 @@ def filtered(item, values): def musica_movie(item): - info() + logger.info() itemlist = [] data = match(item).data matches = match(data, patron=r'([^<]+)
([^<]+).*?(\d+:\d+).*?
(.*?)
.*?
(.*?).*?
\s*(.*?)\s*-.*?(\d{4}).*?title="Score">\s*(N/A|\d\.\d+)' + patron = r'([^<]+).*?(\? ep|\d+ ep).*?
(.*?)
.*?
(.*?).*?
\s*(.*?)\s*-.*?(\d{4}).*?title="Score">\s*(N/A|\d\.\d+)' matches = match(data, patron=patron).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: @@ -2413,7 +2414,7 @@ def season_mal(item): else: args = "tv" 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, thumbnail=thumbnail, infoLabels=infoLabels, args=args, tipo=tipo, contentTitle=scrapedtitle, contentType=contentType, @@ -2487,7 +2488,7 @@ def detail_staff(item): patron_bio = r'(.*?)' bio = match(data, patron=patron_bio).match bio = htmlclean(bio.replace("
", "\n")) - info(bio) + logger.info(bio) infoLabels = {'plot': bio} 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)) @@ -2550,7 +2551,7 @@ def searching_mal(item): title += " (%s)" % year except: import traceback - error(traceback.format_exc()) + logger.error(traceback.format_exc()) if tipo == "Movie" or tipo == "OVA": infolabels["mediatype"] = "movie" @@ -2625,7 +2626,7 @@ def info_anidb(item, itemlist, url): def filter_mal(item): - info() + logger.info() list_controls = [] valores = {} @@ -2703,7 +2704,7 @@ def callback_mal(item, values): def musica_anime(item): # List available anime and songs similar to the anime title - info() + logger.info() itemlist = [] 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): - info() + logger.info() from core import httptools 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) if not re.search(r'(?i)' + user, response.data): - error("Login failed") + logger.error("Login failed") return False, config.get_localized_string(70330), user else: if generic: return False, config.get_localized_string(70393), user - info("Correct login") + logger.info("Correct login") return True, "", user except: import traceback - error(traceback.format_exc()) + logger.error(traceback.format_exc()) return False, config.get_localized_string(70331) , '' @@ -2799,7 +2800,7 @@ def cuenta_mal(item): def items_mal(item): # Scraper for personal lists - info() + logger.info() itemlist = [] data = match(item.url).data diff --git a/tests/run.sh b/tests/run.sh new file mode 100755 index 00000000..2e866511 --- /dev/null +++ b/tests/run.sh @@ -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 \ No newline at end of file diff --git a/tests/test_generic.py b/tests/test_generic.py index 5ec5e91a..befde289 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -120,7 +120,7 @@ chNumRis = { 'Serie TV': 12 }, 'serietvonline': { - 'Film': 50, + 'Film': 25, 'Serie TV': 35 }, '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")] logger.info(channel_list) ret = [] + +logger.record = True for chItem in channel_list: try: ch = chItem.channel @@ -143,6 +145,7 @@ for chItem in channel_list: hasChannelConfig = False mainlist = module.mainlist(Item()) menuItemlist = {} + logMenu = {} serversFound = {} for it in mainlist: @@ -155,6 +158,8 @@ for chItem in channel_list: continue itemlist = getattr(module, it.action)(it) 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 for resIt in itemlist: @@ -165,16 +170,22 @@ for chItem in channel_list: serversFound[it.title] = [resIt] if serversFound[it.title]: + if hasattr(module, 'play'): + serversFound[it.title] = [getattr(module, 'play')(resIt)[0] for srv in serversFound[it.title]] servers.extend( {'name': srv.server.lower(), 'server': srv} for srv in serversFound[it.title] if srv.server) break channels.append( {'ch': ch, 'hasChannelConfig': hasChannelConfig, 'mainlist': mainlist, 'menuItemlist': menuItemlist, - 'serversFound': serversFound, 'module': module}) + 'serversFound': serversFound, 'module': module, 'logMenu': logMenu}) except: import traceback logger.error(traceback.format_exc()) + print(logger.recordedLog) + logger.recordedLog = '' + +logger.record = False from specials import news dictNewsChannels, any_active = news.get_channels_list() @@ -203,12 +214,26 @@ class GenericChannelTest(unittest.TestCase): 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( - [{'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 - title, itemlist in ch['menuItemlist'].items()]) + [{'ch': ch['ch'], 'title': title, 'itemlist': itemlist, + '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): def test_menu(self): 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.itemlist, 'channel ' + self.ch + ' -> ' + self.title + ' is empty') self.assertTrue(self.serversFound, @@ -217,7 +242,7 @@ class GenericChannelMenuItemTest(unittest.TestCase): if self.ch in chNumRis: # i know how much results should be for content in chNumRis[self.ch]: 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, 'channel ' + self.ch + ' -> ' + self.title + ' returned wrong number of results
' + str(risNum) + ' but should be ' + str(chNumRis[self.ch][content]) + '
' + @@ -246,48 +271,46 @@ class GenericChannelMenuItemTest(unittest.TestCase): self.assertTrue(nextPageItemlist, 'channel ' + self.ch + ' -> ' + self.title + ' has nextpage not working') - print('
test passed') + print('test passed') -@parameterized.parameterized_class(serversFinal) +@parameterized.parameterized_class(serversFinal, class_name_func=testnameSrv) class GenericServerTest(unittest.TestCase): def test_get_video_url(self): module = __import__('servers.%s' % self.name, fromlist=["servers.%s" % self.name]) page_url = self.server.url print('testing ' + page_url) self.assert_(hasattr(module, 'test_video_exists'), self.name + ' has no test_video_exists') - try: - if module.test_video_exists(page_url)[0]: - urls = module.get_video_url(page_url) - server_parameters = servertools.get_server_parameters(self.name) - self.assertTrue(urls or server_parameters.get("premium"), - self.name + ' scraper did not return direct urls for ' + page_url) - print(urls) - for u in urls: - spl = u[1].split('|') - if len(spl) == 2: - directUrl, headersUrl = spl - else: - directUrl, headersUrl = spl[0], '' - headers = {} - if headersUrl: - for name in headersUrl.split('&'): - h, v = name.split('=') - h = str(h) - headers[h] = str(v) - print(headers) - if 'magnet:?' in directUrl: # check of magnet links not supported - continue - page = downloadpage(directUrl, headers=headers, only_headers=True, use_requests=True) - 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') - contentType = page.headers['Content-Type'] - self.assert_(contentType.startswith( - '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 + '
Direct url: ' + directUrl + '
Content-Type: ' + contentType) - except: - import traceback - logger.error(traceback.format_exc()) + + if module.test_video_exists(page_url)[0]: + urls = module.get_video_url(page_url) + server_parameters = servertools.get_server_parameters(self.name) + self.assertTrue(urls or server_parameters.get("premium"), + self.name + ' scraper did not return direct urls for ' + page_url) + print(urls) + for u in urls: + spl = u[1].split('|') + if len(spl) == 2: + directUrl, headersUrl = spl + else: + directUrl, headersUrl = spl[0], '' + headers = {} + if headersUrl: + for name in headersUrl.split('&'): + h, v = name.split('=') + h = str(h) + headers[h] = str(v) + print(headers) + if 'magnet:?' in directUrl: # check of magnet links not supported + continue + 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.assertLess(page.code, 400, self.name + ' scraper returned a ' + str(page.code) + ' link') + contentType = page.headers['Content-Type'] + self.assert_(contentType.startswith( + '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 + '
Direct url: ' + directUrl + '
Content-Type: ' + contentType) + print('test passed') if __name__ == '__main__':