From de5a65d77a6341349f585f9588b0f1bafe009de3 Mon Sep 17 00:00:00 2001 From: marco <10120390+mac12m99@users.noreply.github.com> Date: Thu, 17 Dec 2020 18:41:54 +0100 Subject: [PATCH] KoD 1.5.1 - corretta e migliorata la nuova ricerca globale\n- salvataggio punto di visione basato sull'id tmdb (disponibile su qualunque canale / server anche senza salvare in videoteca)\n- alcuni fix e migliore\n --- addon.xml | 9 +- channels.json | 100 ++-- channels/animeunity.py | 5 +- channels/cinemalibero.py | 2 +- channels/filmpertutti.py | 8 +- channels/paramount.py | 5 +- channels/raiplay.py | 4 +- channels/streamingcommunity.py | 24 +- channels/vvvvid.py | 11 +- core/autoplay.py | 3 +- core/httptools.py | 2 +- core/scraper.py | 7 +- core/support.py | 13 +- platformcode/launcher.py | 24 +- platformcode/platformtools.py | 157 +++--- platformcode/xbmc_videolibrary.py | 40 +- resources/settings.xml | 1 + resources/skins/Default/720p/GlobalSearch.xml | 230 +++++---- .../skins/Default/720p/NextDialogExtended.xml | 1 + .../skins/Default/720p/ResumePlayback.xml | 28 +- resources/skins/Default/media/valid.png | Bin 0 -> 16687 bytes servers/akvideo.json | 2 +- servers/anavids.json | 2 +- servers/animeid.json | 2 +- servers/anonfile.json | 2 +- servers/archiveorg.json | 2 +- servers/backin.json | 2 +- servers/badshare.json | 2 +- servers/bdupload.json | 2 +- servers/cinemaupload.json | 2 +- servers/clicknupload.json | 2 +- servers/clipwatching.json | 2 +- servers/cloudvideo.json | 2 +- servers/crunchyroll.json | 2 +- servers/dailymotion.json | 2 +- servers/deltabit.json | 2 +- servers/directo.json | 2 +- servers/doodstream.json | 2 +- servers/dostream.json | 2 +- servers/downace.json | 2 +- servers/facebook.json | 2 +- servers/fastplay.json | 2 +- servers/fembed.json | 2 +- servers/fex.json | 2 +- servers/filefactory.json | 2 +- servers/filepup.json | 2 +- servers/filescdn.json | 2 +- servers/filesmonster.json | 2 +- servers/flashx.json | 2 +- servers/fourshared.json | 2 +- servers/gamovideo.json | 2 +- servers/gigasize.json | 2 +- servers/googlevideo.json | 2 +- servers/gounlimited.json | 2 +- servers/gvideo.json | 2 +- servers/hdload.json | 2 +- servers/hdmario.json | 2 +- servers/hugefiles.json | 2 +- servers/idtbox.json | 2 +- servers/jawcloud.json | 2 +- servers/jetload.json | 2 +- servers/mailru.json | 2 +- servers/mediafire.json | 2 +- servers/mega.json | 2 +- servers/mixdrop.json | 2 +- servers/mp4upload.json | 2 +- servers/mydaddy.json | 2 +- servers/mystream.json | 4 +- servers/myupload.json | 2 +- servers/netutv.json | 2 +- servers/nowvideo.json | 2 +- servers/okru.json | 2 +- servers/onefichier.json | 2 +- servers/onlystream.json | 2 +- servers/rapidgator.json | 2 +- servers/rcdnme.json | 2 +- servers/rutube.json | 2 +- servers/samaup.json | 2 +- servers/sendvid.json | 2 +- servers/speedvideo.json | 2 +- servers/streamtape.json | 2 +- servers/streamz.json | 2 +- servers/supervideo.json | 2 +- servers/thevid.json | 2 +- servers/thevideobee.json | 2 +- servers/torrent.json | 2 +- servers/turbobit.json | 2 +- servers/turbovid.json | 2 +- servers/tusfiles.json | 2 +- servers/unsupported.json | 2 +- servers/uploadedto.json | 2 +- servers/uppom.json | 2 +- servers/upstream.json | 2 +- servers/uptobox.json | 2 +- servers/upvid.json | 2 +- servers/uqload.json | 2 +- servers/userscloud.json | 2 +- servers/vevio.json | 2 +- servers/vidcloud.json | 2 +- servers/videobin.json | 2 +- servers/videomega.json | 2 +- servers/vidfast.json | 2 +- servers/vidlox.json | 2 +- servers/vidmoly.json | 2 +- servers/vidoza.json | 2 +- servers/vidtodo.json | 2 +- servers/vidtome.json | 2 +- servers/vidup.json | 2 +- servers/vimeo.json | 2 +- servers/vimpleru.json | 2 +- servers/vivo.json | 2 +- servers/vk.json | 2 +- servers/vshare.json | 2 +- servers/vudeo.json | 2 +- servers/vupplayer.json | 2 +- servers/vupplayer.py | 2 +- servers/vvvvid.json | 2 +- servers/watchanimestream.json | 2 +- servers/watchvideo.json | 2 +- servers/wstream.json | 2 +- servers/youdbox.json | 2 +- servers/yourupload.json | 2 +- servers/youtube.json | 2 +- servers/youwatch.json | 2 +- servers/zippyshare.json | 2 +- service.py | 31 +- {platformcode => specials}/globalsearch.py | 458 ++++++++++++------ specials/search.py | 22 +- specials/setting.py | 9 +- specials/videolibrary.py | 2 +- 130 files changed, 853 insertions(+), 553 deletions(-) create mode 100644 resources/skins/Default/media/valid.png rename {platformcode => specials}/globalsearch.py (55%) diff --git a/addon.xml b/addon.xml index 309038d7..d83941d5 100644 --- a/addon.xml +++ b/addon.xml @@ -1,4 +1,4 @@ - + @@ -26,10 +26,9 @@ resources/media/themes/ss/2.png resources/media/themes/ss/3.png - -Nuova Ricerca Globale --Nuova Rinumerazione --Messaggi di Errore più chiari --Fix var + - corretta e migliorata la nuova ricerca globale +- salvataggio punto di visione basato sull'id tmdb (disponibile su qualunque canale / server anche senza salvare in videoteca) +- alcuni fix e migliore 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 f727a4bf..553da4dc 100644 --- a/channels.json +++ b/channels.json @@ -1,57 +1,57 @@ { "direct": { - "altadefinizione01_link": "https://altadefinizione01.tips", - "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://cinemalibero.store", - "cinetecadibologna": "http://cinestore.cinetecadibologna.it", - "dreamsub": "https://dreamsub.stream", - "dsda": "https://www.dsda.press", - "eurostreaming": "https://eurostreaming.wiki", - "fastsubita": "https://fastsubita.xyz", - "filmgratis": "https://www.filmaltadefinizione.me", - "filmigratis": "https://filmigratis.org", - "filmsenzalimiticc": "https://www.filmsenzalimiti01.online", - "filmstreaming01": "https://filmstreaming01.com", - "guardaserie_stream": "https://guardaserie.host", - "guardaseriecam": "https://guardaserie.cam", - "guardaserieclick": "https://www.guardaserie.date", - "guardaserieicu": "https://guardaserie.today", - "hd4me": "https://hd4me.net", - "ilgeniodellostreaming": "https://ilgeniodellostreaming.cat", - "ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.gold", - "ilcorsaronero": "https://ilcorsaronero.link", - "italiaserie": "https://italiaserie.best", - "mondoserietv": "https://mondoserietv.fun", - "piratestreaming": "https://www.piratestreaming.date", - "polpotv": "https://roma.polpo.tv", - "raiplay": "https://www.raiplay.it", - "serietvonline": "https://serietvonline.cam", - "serietvsubita": "http://serietvsubita.xyz", - "serietvu": "https://www.serietvu.link", - "streamingcommunity": "https://streamingcommunity.net", - "streamtime": "https://t.me/s/StreamTime", - "toonitalia": "https://toonitalia.org", + "altadefinizione01_link": "https://altadefinizione01.tips", + "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://cinemalibero.store", + "cinetecadibologna": "http://cinestore.cinetecadibologna.it", + "dreamsub": "https://dreamsub.stream", + "dsda": "https://www.dsda.press", + "eurostreaming": "https://eurostreaming.wiki", + "fastsubita": "https://fastsubita.xyz", + "filmgratis": "https://www.filmaltadefinizione.me", + "filmigratis": "https://filmigratis.org", + "filmsenzalimiticc": "https://www.filmsenzalimiti01.online", + "filmstreaming01": "https://filmstreaming01.com", + "guardaserie_stream": "https://guardaserie.host", + "guardaseriecam": "https://guardaserie.cam", + "guardaserieclick": "https://www.guardaserie.date", + "guardaserieicu": "https://guardaserie.today", + "hd4me": "https://hd4me.net", + "ilcorsaronero": "https://ilcorsaronero.link", + "ilgeniodellostreaming": "https://ilgeniodellostreaming.cat", + "ilgeniodellostreaming_cam": "https://ilgeniodellostreaming.gold", + "italiaserie": "https://italiaserie.best", + "mondoserietv": "https://mondoserietv.fun", + "piratestreaming": "https://www.piratestreaming.date", + "polpotv": "https://roma.polpo.tv", + "raiplay": "https://www.raiplay.it", + "serietvonline": "https://serietvonline.cam", + "serietvsubita": "http://serietvsubita.xyz", + "serietvu": "https://www.serietvu.link", + "streamingcommunity": "https://streamingcommunity.net", + "streamtime": "https://t.me/s/StreamTime", + "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", - "film4k": "https://film4k-nuovo.link", - "filmpertutti": "https://filmpertutti.nuovo.live", - "seriehd": "https://nuovoindirizzo.info/seriehd/", + "altadefinizione01": "https://altadefinizione01-nuovo.info", + "altadefinizioneclick": "https://altadefinizione-nuovo.me", + "animealtadefinizione": "https://www.animealtadefinizione.it", + "cineblog01": "https://cb01.uno", + "film4k": "https://film4k-nuovo.link", + "filmpertutti": "https://filmpertutti.nuovo.live", + "seriehd": "https://nuovoindirizzo.info/seriehd/", "tantifilm": "https://www.tantifilm.wiki" } } \ No newline at end of file diff --git a/channels/animeunity.py b/channels/animeunity.py index a434acea..91248922 100644 --- a/channels/animeunity.py +++ b/channels/animeunity.py @@ -3,7 +3,7 @@ # Canale per AnimeUnity # ------------------------------------------------------------ -import requests, json, copy +import requests, json, copy, inspect from core import support from platformcode import autorenumber @@ -212,7 +212,8 @@ def episodios(item): contentType='episode', url=it['link'])) - autorenumber.start(itemlist, item) + if inspect.stack()[1][3] not in ['find_episodes']: + autorenumber.start(itemlist, item) support.videolibrary(itemlist, item) support.download(itemlist, item) return itemlist diff --git a/channels/cinemalibero.py b/channels/cinemalibero.py index 285106cc..b935f3ee 100644 --- a/channels/cinemalibero.py +++ b/channels/cinemalibero.py @@ -95,7 +95,7 @@ def episodios(item): item.contentType = 'tvshow' else:# item.extra == 'serie': support.info("Serie :", item) - patron = r'(?:>| )(?P\d+(?:x|×|×)\d+)[;]?[ ]?(?:(?P[^<–-]+)(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br /|</a></p|$)' + patron = r'(?:>| )(?P<episode>\d+(?:x|×|×)\d+)[;]?[ ]?(?:(?P<title>[^<–-]+)(?P<data>.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br /|</a></p|$)' patronBlock = r'>(?:[^<]+[Ss]tagione\s|[Ss]tagione [Uu]nica)(?:(?P<lang>iTA|ITA|Sub-ITA|Sub-iTA))?.*?</strong>(?P<block>.+?)(?:<strong|<div class="at-below)' item.contentType = 'tvshow' def itemHook(item): diff --git a/channels/filmpertutti.py b/channels/filmpertutti.py index 0f5d2016..ffc098b9 100644 --- a/channels/filmpertutti.py +++ b/channels/filmpertutti.py @@ -68,10 +68,10 @@ def episodios(item): data = support.match(item.url, headers=headers).data if 'accordion-item' in data: patronBlock = r'<span class="season[^>]*>\d+[^>]+>[^>]+>[^>]+>[^>]+>\D*(?:STAGIONE|Stagione)[ -]+(?P<lang>[a-zA-Z\- ]+)[^<]*</span>(?P<block>.*?)<div id="(?:season|disqus)' - patron = r'<img src="(?P<thumb>[^"]+)">.*?<li class="season-no">(?P<season>\d+)(?:×|×|x)(?P<episode>\d+)[^<0-9]*<\/li>(?P<url>.*?javascript:;">(?P<title>[^<]+).*?</tbody>)' + patron = r'<img src="(?P<thumb>[^"]+)">.*?<li class="season-no">(?P<season>\d+)(?:×|×|x)(?P<episode>\d+)[^<0-9]*<\/li>(?P<data>.*?javascript:;">(?P<title>[^<]+).*?</tbody>)' else: patronBlock = r'(?:STAGIONE|Stagione)(?:<[^>]+>)?\s*(?:(?P<lang>[A-Za-z- ]+))?(?P<block>.*?)(?: |<strong>|<div class="addtoany)' - patron = r'(?:/>|p>)\s*(?P<season>\d+)(?:×|×|x)(?P<episode>\d+)[^<]+(?P<other>.*?)(?:<br|</p)' + patron = r'(?:/>|p>)\s*(?P<season>\d+)(?:×|×|x)(?P<episode>\d+)[^<]+(?P<data>.*?)(?:<br|</p)' def itemHook(i): i.url = item.url @@ -156,7 +156,7 @@ def newest(categoria): def findvideos(item): if item.contentType == 'movie': - data = httptools.downloadpage(item.url).data + data = support.match(item.url, patron=r'<a target="_blank" rel="nofollow" href="([^"]+)">').matches return support.server(item, data=data, patronTag='Versione: <[^>]+>([^<]+)') else: - return support.server(item, item.other) + return support.server(item, item.data) diff --git a/channels/paramount.py b/channels/paramount.py index 024618cf..cf2bf192 100644 --- a/channels/paramount.py +++ b/channels/paramount.py @@ -105,7 +105,7 @@ def peliculas(item): if pagination and len(itemlist) >= item.page * pagination and not item.search: itlist.append(item.clone(channel=item.channel, action = 'peliculas', title=support.typo(support.config.get_localized_string(30992), 'color kod bold'), page=item.page + 1, thumbnail=support.thumb())) itemlist = itlist - autorenumber.renumber(itemlist, item, 'bold') + autorenumber.start(itemlist) return itemlist @@ -156,7 +156,8 @@ def episodios(item): action='findvideos')) itemlist.sort(key=lambda item: (item.season, item.episode)) - autorenumber.renumber(itemlist, item, 'bold') + if inspect.stack()[1][3] not in ['find_episodes']: + autorenumber.start(itemlist, item) return support.videolibrary(itemlist, item) diff --git a/channels/raiplay.py b/channels/raiplay.py index 66a0ae2a..73c90a7e 100644 --- a/channels/raiplay.py +++ b/channels/raiplay.py @@ -3,7 +3,7 @@ # Canale per Rai Play # ------------------------------------------------------------ -import requests, sys +import requests, sys, inspect from core import support from platformcode import autorenumber if sys.version_info[0] >= 3: @@ -297,7 +297,7 @@ def episodios(item): it.title = support.typo(item.season + 'x' + episode, 'bold') + (' - ' + it.title) if itemlist and itemlist[0].VL: support.videolibrary(itemlist, item) - if itemlist and not support.match(itemlist[0].title, patron=r'[Ss]?(\d+)(?:x|_|\.|\s+)[Ee]?[Pp]?(\d+)').match: + if itemlist and not support.match(itemlist[0].title, patron=r'[Ss]?(\d+)(?:x|_|\.|\s+)[Ee]?[Pp]?(\d+)').match and inspect.stack()[1][3] not in ['find_episodes']: autorenumber.start(itemlist, item) return itemlist diff --git a/channels/streamingcommunity.py b/channels/streamingcommunity.py index d34b916e..1888efbe 100644 --- a/channels/streamingcommunity.py +++ b/channels/streamingcommunity.py @@ -8,13 +8,18 @@ from core import support host = support.config.get_channel_url() -session = requests.Session() -response = session.get(host) -csrf_token = support.match(response.text, patron='name="csrf-token" content="([^"]+)"').match -headers = {'content-type': 'application/json;charset=UTF-8', - 'Referer': host, - 'x-csrf-token': csrf_token, - 'Cookie': '; '.join([x.name + '=' + x.value for x in response.cookies])} +headers = {} + +def getHeaders(): + global headers + if not headers: + session = requests.Session() + response = session.get(host) + csrf_token = support.match(response.text, patron='name="csrf-token" content="([^"]+)"').match + headers = {'content-type': 'application/json;charset=UTF-8', + 'Referer': host, + 'x-csrf-token': csrf_token, + 'Cookie': '; '.join([x.name + '=' + x.value for x in response.cookies])} @support.menu @@ -34,6 +39,7 @@ def mainlist(item): def genres(item): + getHeaders() support.info() itemlist = [] data = support.scrapertools.decodeHtmlentities(support.match(item).data) @@ -85,6 +91,7 @@ def newest(category): def peliculas(item): + getHeaders() support.info() itemlist = [] videoType = 'movie' if item.contentType == 'movie' else 'tv' @@ -145,6 +152,7 @@ def peliculas(item): return itemlist def episodios(item): + getHeaders() support.info() itemlist = [] @@ -172,7 +180,7 @@ def episodios(item): def findvideos(item): - + getHeaders() support.info() itemlist=[] url = support.match(support.match(item).data.replace('"','"').replace('\\',''), patron=r'video_url"\s*:\s*"([^"]+)"').match diff --git a/channels/vvvvid.py b/channels/vvvvid.py index 20b0248a..9828fa8a 100644 --- a/channels/vvvvid.py +++ b/channels/vvvvid.py @@ -2,9 +2,9 @@ # ------------------------------------------------------------ # Canale per vvvvid # ---------------------------------------------------------- -import requests, sys +import requests, sys, inspect from core import support, tmdb -from platformcode import autorenumber, logger +from platformcode import autorenumber, logger, config host = support.config.get_channel_url() @@ -170,7 +170,8 @@ def episodios(item): url= host + show_id + '/season/' + str(key['season_id']), action= 'findvideos', video_id= key['video_id'])) - autorenumber.start(itemlist, item) + if inspect.stack()[1][3] not in ['find_episodes']: + autorenumber.start(itemlist, item) if autorenumber.check(item) == True \ or support.match(itemlist[0].title, patron=r"(\d+x\d+)").match: support.videolibrary(itemlist,item) @@ -196,7 +197,7 @@ def findvideos(item): url = url.split()[-1] itemlist.append( item.clone(action= 'play', - title='direct', + title=config.get_localized_string(30137), url= 'https://or01.top-ix.org/videomg/_definst_/mp4:' + item.url + '/' + url, server= 'directo') ) @@ -206,7 +207,7 @@ def findvideos(item): itemlist.append( item.clone(action= 'play', - title='direct', + title=config.get_localized_string(30137), url= item.url + '?' + key, server= 'directo') ) diff --git a/core/autoplay.py b/core/autoplay.py index a8d141d6..b346bb3b 100644 --- a/core/autoplay.py +++ b/core/autoplay.py @@ -67,7 +67,7 @@ def start(itemlist, item): # Enable the "View in high quality" action (if the server returns more than one quality, eg gdrive) if not user_config_setting_action: config.set_setting("default_action", 2) - if user_config_setting_player != 0: config.set_setting("player_mode", 0) + # if user_config_setting_player != 0: config.set_setting("player_mode", 0) # Priorities when ordering itemlist: # 0: Servers and qualities @@ -230,6 +230,7 @@ def start(itemlist, item): if isinstance(resolved_item[0], list): videoitem.video_urls = resolved_item else: videoitem = resolved_item[0] + play_item.autoplay = True # If not directly reproduce and mark as seen # Check if the item comes from the video library try: diff --git a/core/httptools.py b/core/httptools.py index 76b04f9d..6f814769 100755 --- a/core/httptools.py +++ b/core/httptools.py @@ -30,7 +30,7 @@ cookies_file = os.path.join(config.get_data_path(), "cookies.dat") # Headers by default, if nothing is specified default_headers = dict() -default_headers["User-Agent"] = "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" +default_headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36" % config.get_setting("chrome_ua_version") default_headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" default_headers["Accept-Language"] = "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3" default_headers["Accept-Charset"] = "UTF-8" diff --git a/core/scraper.py b/core/scraper.py index d5aa9ac2..c2951fc7 100644 --- a/core/scraper.py +++ b/core/scraper.py @@ -224,7 +224,12 @@ def get_nfo(item): return info_nfo else: - return scraper.get_nfo(item) + try: return scraper.get_nfo(item) + except: + if item.contentType == "movie": scraper_actual = ['tmdb'][config.get_setting("scraper_movies", "videolibrary")] + else: scraper_actual = ['tmdb', 'tvdb'][config.get_setting("scraper_tvshows", "videolibrary")] + scraper = __import__('core.%s' % scraper_actual, fromlist=["core.%s" % scraper_actual]) + return scraper.get_nfo(item) def sort_episode_list(episodelist): diff --git a/core/support.py b/core/support.py index b91566f9..f232a7e7 100755 --- a/core/support.py +++ b/core/support.py @@ -95,11 +95,14 @@ def search(channel, item, texto): def dbg(): if config.dev_mode(): - import web_pdb - if not web_pdb.WebPdb.active_instance: - import webbrowser - webbrowser.open('http://127.0.0.1:5555') - web_pdb.set_trace() + try: + import web_pdb + if not web_pdb.WebPdb.active_instance: + import webbrowser + webbrowser.open('http://127.0.0.1:5555') + web_pdb.set_trace() + except: + pass def regexDbg(item, patron, headers, data=''): diff --git a/platformcode/launcher.py b/platformcode/launcher.py index efe5cc19..0dc5110f 100644 --- a/platformcode/launcher.py +++ b/platformcode/launcher.py @@ -37,6 +37,7 @@ def start(): updater.showSavedChangelog() def run(item=None): + # from core.support import dbg;dbg() logger.debug() if not item: # Extract item from sys.argv @@ -135,12 +136,6 @@ def run(item=None): from platformcode import infoplus return infoplus.Main(item) - elif config.get_setting('new_search') and item.channel == "search" and item.action == 'new_search': - from platformcode.globalsearch import Search - item.contextual = True - Search(item) - return - elif item.channel == "backup": from platformcode import backup return getattr(backup, item.action)(item) @@ -489,17 +484,24 @@ def play_from_library(item): item.play_from = 'window' itemlist = videolibrary.findvideos(item) p_dialog.update(100, ''); sleep(0.5); p_dialog.close() - # while platformtools.is_playing(): # Conventional window - # sleep(100) - play_time = platformtools.resume_playback(item, True) - if not play_time and config.get_setting('autoplay'): + while platformtools.is_playing(): sleep(1) + # from core.support import dbg;dbg() + if item.contentType == 'movie': nfo_path = item.nfo + else: nfo_path = item.strm_path.replace('strm','nfo') + if nfo_path and filetools.isfile(nfo_path): + from core import videolibrarytools + head_nfo, item_nfo = videolibrarytools.read_nfo(nfo_path) + played_time = platformtools.get_played_time(item_nfo) + else: played_time = 0 + + if not played_time and config.get_setting('autoplay'): return # The number of links to show is limited if config.get_setting("max_links", "videolibrary") != 0: itemlist = limit_itemlist(itemlist) # The list of links is slightly "cleaned" if config.get_setting("replace_VD", "videolibrary") == 1: itemlist = reorder_itemlist(itemlist) - + # from core.support import dbg;dbg() if len(itemlist) > 0: while not xbmc.Monitor().abortRequested(): # The user chooses the mirror diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index f22e828a..25882fa6 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -547,7 +547,7 @@ def set_context_commands(item, item_url, parent_item, **kwargs): context_commands.append(("InfoPlus", "RunPlugin(%s?%s&%s)" % (sys.argv[0], item_url, 'channel=infoplus&action=Main&from_channel=' + item.channel))) # Go to the Main Menu (channel.mainlist) - if parent_item.channel not in ["news", "channelselector", "downloads"] and item.action != "mainlist": + if parent_item.channel not in ["news", "channelselector", "downloads", "search"] and item.action != "mainlist" and not parent_item.noMainMenu: if parent_item.action != "mainlist": context_commands.insert(0, (config.get_localized_string(60349), "Container.Refresh (%s?%s)" % (sys.argv[0], Item(channel=item.channel, action="mainlist").tourl()))) context_commands.insert(1, (config.get_localized_string(70739), "Container.Update (%s?%s)" % (sys.argv[0], Item(action="open_browser", url=item.url).tourl()))) @@ -556,7 +556,7 @@ def set_context_commands(item, item_url, parent_item, **kwargs): if item.channel not in ["favorites", "videolibrary", "help", ""] and parent_item.channel != "favorites": context_commands.append( (config.get_localized_string(70557), "RunPlugin(%s?%s&%s)" % (sys.argv[0], item_url, urllib.urlencode({'channel': "kodfavorites", 'action': "addFavourite", 'from_channel': item.channel, 'from_action': item.action})))) # Search in other channels - if item.contentTitle and item.contentType in ['movie', 'tvshow'] and item.channel != 'search' and item.action not in ['play'] and parent_item.action != 'mainlist': + if item.contentTitle and item.contentType in ['movie', 'tvshow'] and parent_item.channel != 'search' and item.action not in ['play'] and parent_item.action != 'mainlist': # Search in other channels if item.contentSerieName != '': @@ -586,7 +586,7 @@ def set_context_commands(item, item_url, parent_item, **kwargs): elif item.action in ["detail", "findvideos"] and item.contentType == 'movie' and item.contentTitle: context_commands.append((config.get_localized_string(60353), "RunPlugin(%s?%s&%s)" % (sys.argv[0], item_url, 'action=add_pelicula_to_library&from_action=' + item.action))) - if not item.local and item.channel not in ["downloads", "filmontv"] and item.server != 'torrent' and parent_item.action != 'mainlist' and config.get_setting('downloadenabled'): + if not item.local and item.channel not in ["downloads", "filmontv", "search"] and item.server != 'torrent' and parent_item.action != 'mainlist' and config.get_setting('downloadenabled'): # Download movie if item.contentType == "movie": context_commands.append((config.get_localized_string(60354), "RunPlugin(%s?%s&%s)" % (sys.argv[0], item_url, 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' + item.action))) @@ -679,9 +679,7 @@ def play_video(item, strm=False, force_direct=False, autoplay=False): if force_direct: item.play_from = 'window' - - item, nfo_path, head_nfo, item_nfo = resume_playback(item) - set_player(item, xlistitem, mediaurl, view, strm, nfo_path, head_nfo, item_nfo) + set_player(item, xlistitem, mediaurl, view, strm) def stop_video(): @@ -1009,9 +1007,17 @@ def get_video_seleccionado(item, seleccion, video_urls): return mediaurl, view, mpd -def set_player(item, xlistitem, mediaurl, view, strm, nfo_path=None, head_nfo=None, item_nfo=None): +def set_player(item, xlistitem, mediaurl, view, strm): logger.debug() + item.options = {'strm':False, 'continue':False} # logger.debug("item:\n" + item.tostring('\n')) + + # Prevent Busy + if not item.autoplay: + if item.globalsearch: xbmc.executebuiltin("PlayMedia(" + os.path.join(config.get_runtime_path(), "resources", "kod.mp4") + ")") + else: xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, xbmcgui.ListItem(path=os.path.join(config.get_runtime_path(), "resources", "kod.mp4"))) + xbmc.Player().stop() + # Moved del conector "torrent" here if item.server == "torrent": play_torrent(item, xlistitem, mediaurl) @@ -1028,29 +1034,26 @@ def set_player(item, xlistitem, mediaurl, view, strm, nfo_path=None, head_nfo=No player_mode = item.player_mode else: player_mode = config.get_setting("player_mode") - if (player_mode == 3 and mediaurl.startswith("rtmp")) or item.play_from == 'window' or item.nfo: player_mode = 0 + if (player_mode == 3 and mediaurl.startswith("rtmp")): player_mode = 0 elif "megacrypter.com" in mediaurl: player_mode = 3 logger.info("mediaurl=" + mediaurl) - if player_mode == 0: - logger.info('Player Mode: Direct') + if player_mode in [0,1]: + logger.info('Player Mode:' + ['Direct', 'Bookmark'][player_mode]) # Add the listitem to a playlist playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist.clear() playlist.add(mediaurl, xlistitem) + # played_time = resume_playback(get_played_time(item)) + # Reproduce xbmc_player.play(playlist, xlistitem) + # viewed(item, played_time) if config.get_setting('trakt_sync'): from core import trakt_tools trakt_tools.wait_for_update_trakt() - elif player_mode == 1: - logger.info('Player Mode: setResolvedUrl') - xlistitem.setPath(mediaurl) - xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, xlistitem) - # xbmc.sleep(2500) - elif player_mode == 2: logger.info('Player Mode: Built-In') xbmc.executebuiltin("PlayMedia(" + mediaurl + ")") @@ -1068,13 +1071,14 @@ def set_player(item, xlistitem, mediaurl, view, strm, nfo_path=None, head_nfo=No xbmc_player.setSubtitles(item.subtitle) # if it is a video library file send to mark as seen - if strm or item.strm_path: - from platformcode import xbmc_videolibrary - xbmc_videolibrary.mark_auto_as_watched(item, nfo_path, head_nfo, item_nfo) + if strm or item.strm_path: item.options['strm'] = True + if player_mode == 1: item.options['continue'] = True + from platformcode import xbmc_videolibrary + xbmc_videolibrary.mark_auto_as_watched(item) # for cases where the audio playback window appears in place of the video one if item.focusOnVideoPlayer: - while is_playing and xbmcgui.getCurrentWindowId() != 12006: + while is_playing() and xbmcgui.getCurrentWindowId() != 12006: continue xbmc.sleep(500) xbmcgui.Window(12005).show() @@ -1136,16 +1140,16 @@ def play_torrent(item, xlistitem, mediaurl): time.sleep(3) -def resume_playback(item, return_played_time=False): +def resume_playback(played_time): class ResumePlayback(xbmcgui.WindowXMLDialog): Close = False Resume = False def __init__(self, *args, **kwargs): - self.action_exitkeys_id = [xbmcgui.ACTION_BACKSPACE, xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK] + self.action_exitkeys_id = [92, 10] self.progress_control = None - self.item = kwargs.get('item') - m, s = divmod(float(self.item.played_time), 60) + played_time = kwargs.get('played_time') + m, s = divmod(played_time, 60) h, m = divmod(m, 60) self.setProperty("time", '%02d:%02d:%02d' % (h, m, s)) @@ -1168,38 +1172,17 @@ def resume_playback(item, return_played_time=False): if action in self.action_exitkeys_id: self.set_values(False) self.close() - - - from core import videolibrarytools, filetools - - # Read NFO FILE - if item.contentType == 'movie': - nfo_path = item.nfo - else: - nfo_path = item.strm_path.replace('strm','nfo') - - if filetools.isfile(nfo_path): - head_nfo, item_nfo = videolibrarytools.read_nfo(nfo_path) - - if return_played_time: - return item_nfo.played_time - # Show Window - elif (config.get_setting("player_mode") not in [3] or item.play_from == 'window') and item_nfo.played_time and item_nfo.played_time >= 120: - Dialog = ResumePlayback('ResumePlayback.xml', config.get_runtime_path(), item=item_nfo) - Dialog.show() - t = 0 - while not Dialog.is_close() and t < 100: - t += 1 - xbmc.sleep(100) - if not Dialog.Resume: item_nfo.played_time = 0 - else: - item_nfo.played_time = 0 - - return item, nfo_path, head_nfo, item_nfo - else: - item.nfo = item.strm_path = "" - return item, None, None, None - + if played_time: + Dialog = ResumePlayback('ResumePlayback.xml', config.get_runtime_path(), played_time=played_time) + Dialog.show() + t = 0 + while not Dialog.is_close() and t < 100: + t += 1 + xbmc.sleep(100) + if not Dialog.Resume: played_time = 0 + else: played_time = 0 + xbmc.sleep(300) + return played_time ##### INPUTSTREM ##### @@ -1396,3 +1379,65 @@ def get_platform(): ret["arch"] = "arm" return ret + + + +def get_played_time(item): + import sqlite3 + from core import filetools + db_name = filetools.join(config.get_data_path(), "kod_db.sqlite") + ID = item.infoLabels['tmdb_id'] + conn = sqlite3.connect(db_name, timeout=15) + c = conn.cursor() + c.execute('CREATE TABLE IF NOT EXISTS viewed (tmdb_id TEXT, season INT, episode INT, played_time REAL)') + conn.commit() + if ID: + if item.contentType == 'movie': c.execute("SELECT played_time FROM viewed WHERE tmdb_id=?", (ID,)) + elif 'season' in item.infoLabels: + S = item.infoLabels['season'] + E = item.infoLabels['episode'] + c.execute("SELECT played_time FROM viewed WHERE tmdb_id=? AND season=? AND episode=?", (ID, S, E)) + elif 'episode' in item.infoLabels: + E = item.infoLabels['episode'] + c.execute("SELECT played_time FROM viewed WHERE tmdb_id=? AND episode=?", (ID, E)) + result = c.fetchone() + if not result: played_time = 0 + else: played_time = result[0] + else: played_time = 0 + conn.close() + return played_time + +def set_played_time(item): + import sqlite3 + from core import filetools + ID = item.infoLabels['tmdb_id'] + played_time = item.played_time + db_name = filetools.join(config.get_data_path(), "kod_db.sqlite") + conn = sqlite3.connect(db_name, timeout=15) + c = conn.cursor() + if item.contentType == 'movie': + c.execute("SELECT played_time FROM viewed WHERE tmdb_id=?", (ID,)) + result = c.fetchone() + if result: + if played_time > 0: c.execute("UPDATE viewed SET played_time=? WHERE tmdb_id=?", (item.played_time, ID)) + else: c.execute("DELETE from viewed WHERE tmdb_id=?", (ID,)) + else: c.execute("INSERT INTO viewed (tmdb_id, played_time) VALUES (?, ?)", (ID, item.played_time)) + elif 'season' in item.infoLabels: + S = item.infoLabels['season'] + E = item.infoLabels['episode'] + c.execute("SELECT played_time FROM viewed WHERE tmdb_id=? AND season = ? AND episode=?", (ID, S, E)) + result = c.fetchone() + if result: + if played_time > 0: c.execute("UPDATE viewed SET played_time=? WHERE tmdb_id=? AND season=? AND episode=?", (item.played_time, ID, S, E)) + else: c.execute("DELETE from viewed WHERE tmdb_id=? AND season=? AND episode=?", (ID, S, E)) + else: c.execute("INSERT INTO viewed (tmdb_id, season, episode, played_time) VALUES (?, ?, ?, ?)", (ID, S, E, item.played_time)) + elif 'episode' in item.infoLabels: + E = item.infoLabels['episode'] + c.execute("SELECT played_time FROM viewed WHERE tmdb_id=? AND episode=?", (ID, E)) + result = c.fetchone() + if result: + if played_time > 0: c.execute("UPDATE viewed SET played_time=? WHERE tmdb_id=? AND episode=?", (item.played_time, ID, E)) + else: c.execute("DELETE from viewed WHERE tmdb_id=? AND episode=?", (ID, E)) + else: c.execute("INSERT INTO viewed (tmdb_id, episode, played_time) VALUES (?, ?, ?)", (ID, E, item.played_time)) + conn.commit() + conn.close() diff --git a/platformcode/xbmc_videolibrary.py b/platformcode/xbmc_videolibrary.py index 96d9c6da..92ec039e 100644 --- a/platformcode/xbmc_videolibrary.py +++ b/platformcode/xbmc_videolibrary.py @@ -20,15 +20,19 @@ from core import scrapertools from xml.dom import minidom -def mark_auto_as_watched(item, nfo_path=None, head_nfo=None, item_nfo=None): - def mark_as_watched_subThread(item, nfo_path, head_nfo, item_nfo): +def mark_auto_as_watched(item): + def mark_as_watched_subThread(item): logger.debug() + actual_time = 0 + total_time = 0 # logger.debug("item:\n" + item.tostring('\n')) + if item.options['continue']: item.played_time = platformtools.resume_playback(platformtools.get_played_time(item)) time_limit = time.time() + 30 while not platformtools.is_playing() and time.time() < time_limit: time.sleep(1) + marked = False next_episode = None show_server = True @@ -39,14 +43,15 @@ def mark_auto_as_watched(item, nfo_path=None, head_nfo=None, item_nfo=None): next_dialogs = ['NextDialog.xml', 'NextDialogExtended.xml', 'NextDialogCompact.xml'] next_ep_type = config.get_setting('next_ep_type') ND = next_dialogs[next_ep_type] - next_episode = next_ep(item) + try: next_episode = next_ep(item) + except: next_episode = False while platformtools.is_playing(): actual_time = xbmc.Player().getTime() total_time = xbmc.Player().getTotalTime() - if item_nfo.played_time and xbmcgui.getCurrentWindowId() == 12005: - xbmc.Player().seekTime(item_nfo.played_time) - item_nfo.played_time = 0 # Fix for Slow Devices + if item.played_time and xbmcgui.getCurrentWindowId() == 12005: + xbmc.Player().seekTime(item.played_time) + item.played_time = 0 # Fix for Slow Devices mark_time = total_time * percentage difference = total_time - actual_time @@ -55,7 +60,7 @@ def mark_auto_as_watched(item, nfo_path=None, head_nfo=None, item_nfo=None): if actual_time > mark_time and not marked: logger.info("Marked as Watched") item.playcount = 1 - marked = True + if item.options['strm'] : marked = True show_server = False from specials import videolibrary videolibrary.mark_content_as_watched2(item) @@ -75,9 +80,11 @@ def mark_auto_as_watched(item, nfo_path=None, head_nfo=None, item_nfo=None): break xbmc.sleep(1000) - # Set played time - item_nfo.played_time = int(actual_time) if not marked else 0 - filetools.write(nfo_path, head_nfo + item_nfo.tojson()) + if item.options['continue']: + if 120 < actual_time < (total_time / 100) * 80: + item.played_time = actual_time + else: item.played_time = 0 + platformtools.set_played_time(item) # Silent sync with Trakt if marked and config.get_setting("trakt_sync"): sync_trakt_kodi() @@ -94,7 +101,7 @@ def mark_auto_as_watched(item, nfo_path=None, head_nfo=None, item_nfo=None): # If it is configured to mark as seen if config.get_setting("mark_as_watched", "videolibrary"): - threading.Thread(target=mark_as_watched_subThread, args=[item, nfo_path, head_nfo, item_nfo]).start() + threading.Thread(target=mark_as_watched_subThread, args=[item]).start() @@ -1340,12 +1347,11 @@ class NextDialog(xbmcgui.WindowXMLDialog): f.close() full_info = "".join(full_info) info = jsontools.load(full_info) - if "thumbnail" in info: - img = info["thumbnail"] - else: - img = filetools.join(config.get_runtime_path(), "resources", "noimage.png") - self.setProperty("next_img", img) info = info["infoLabels"] + if "fanart" in info: img = info["fanart"] + elif "thumbnail" in info: img = info["thumbnail"] + else: img = filetools.join(config.get_runtime_path(), "resources", "noimage.png") + self.setProperty("next_img", img) self.setProperty("title", info["tvshowtitle"]) self.setProperty("ep_title", "%dx%02d - %s" % (info["season"], info["episode"], info["title"])) @@ -1381,4 +1387,4 @@ class NextDialog(xbmcgui.WindowXMLDialog): if action in self.action_exitkeys_id: self.set_exit(True) self.set_continue_watching(False) - self.close() \ No newline at end of file + self.close() diff --git a/resources/settings.xml b/resources/settings.xml index 49a1f180..d97a9c3d 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -13,6 +13,7 @@ <setting id="checkdns" type="bool" default="true" visible="false"/> <setting label="70788" type="lsep"/> <setting id="debug" type="bool" label="30003" default="false"/> + <setting id="chrome_ua_version" type="text" default="87.0.4280.88" visible="False"/> </category> <!-- Playback --> diff --git a/resources/skins/Default/720p/GlobalSearch.xml b/resources/skins/Default/720p/GlobalSearch.xml index 82af6ac5..2b2a769f 100644 --- a/resources/skins/Default/720p/GlobalSearch.xml +++ b/resources/skins/Default/720p/GlobalSearch.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <window> - <depth>0.52</depth> + <zorder>0.52</zorder> <coordinates> <left>0</left> <top>0</top> @@ -73,7 +73,7 @@ <!-- <font>font30_title</font> --> <textcolor>FFFFFFFF</textcolor> <shadowcolor>00000000</shadowcolor> - <label>$INFO[Container(102).ListItem.Label] [B][COLOR FFAAAAAA]$INFO[Container(102).ListItem.Property(year)] [CR]$INFO[Container(101).ListItem.Label][/COLOR][/B]</label> + <label>$INFO[Container(102).ListItem.Label][B][COLOR FFAAAAAA]$INFO[Container(102).ListItem.Property(year)]$INFO[Container(102).ListItem.Property(rating)][CR]$INFO[Container(102).ListItem.Property(channel)][/COLOR][/B]</label> <align>left</align> <aligny>center</aligny> </control> @@ -117,69 +117,110 @@ <orientation>horizontal</orientation> <scrolltime tween="cubic" easing="out">300</scrolltime> <itemlayout height="570" width="180"> - <control type="image"> - <description>Item Poster</description> + <control type="group"> <top>300</top> - <left>0</left> - <width>180</width> - <height>270</height> - <texture colordiffuse="AAFFFFFF">$INFO[ListItem.Property(thumb)]</texture> - <visible>!Control.HasFocus(102)</visible> - <bordersize>10</bordersize> - <aspectratio>scale</aspectratio> + <visible>String.IsEmpty(ListItem.Property(channelthumb))</visible> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>180</width> + <height>270</height> + <texture colordiffuse="FF999999">$INFO[ListItem.Property(thumb)]</texture> + <visible>!Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>180</width> + <height>270</height> + <texture>$INFO[ListItem.Property(thumb)]</texture> + <visible>Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> </control> - <control type="image"> - <description>Item Poster</description> - <top>300</top> - <left>0</left> - <width>180</width> - <height>270</height> - <texture>$INFO[ListItem.Property(thumb)]</texture> - <visible>Control.HasFocus(102)</visible> - <bordersize>10</bordersize> - <aspectratio>scale</aspectratio> - </control> - <control type="image"> - <description>Item Verified</description> - <top>315</top> - <left>145</left> - <width>20</width> - <height>20</height> - <texture colordiffuse="FF0082C2">$INFO[ListItem.Property(verified)]</texture> - <aspectratio>scale</aspectratio> + <control type="group"> + <top>390</top> + <visible>!String.IsEmpty(ListItem.Property(channelthumb))</visible> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>180</width> + <height>180</height> + <texture colordiffuse="FF999999">$INFO[ListItem.Property(channelthumb)]</texture> + <visible>!Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>180</width> + <height>180</height> + <texture>$INFO[ListItem.Property(channelthumb)]</texture> + <visible>Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> </control> </itemlayout> <focusedlayout height="570" width="380"> - <control type="image"> - <description>Item Poster</description> - <top>0</top> - <left>0</left> - <width>380</width> - <height>570</height> - <texture colordiffuse="AAFFFFFF">$INFO[ListItem.Property(thumb)]</texture> - <visible>!Control.HasFocus(102)</visible> - <bordersize>10</bordersize> - <aspectratio>scale</aspectratio> + <control type="group"> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>380</width> + <height>570</height> + <texture colordiffuse="FF999999">$INFO[ListItem.Property(thumb)]</texture> + <visible>!Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>380</width> + <height>570</height> + <texture>$INFO[ListItem.Property(thumb)]</texture> + <visible>Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> </control> - <control type="image"> - <description>Item Poster</description> - <top>0</top> - <left>0</left> - <width>380</width> - <height>570</height> - <texture>$INFO[ListItem.Property(thumb)]</texture> - <visible>Control.HasFocus(102)</visible> - <bordersize>10</bordersize> - <aspectratio>scale</aspectratio> - </control> - <control type="image"> - <description>Item Verified</description> - <top>15</top> - <left>330</left> - <width>40</width> - <height>40</height> - <texture colordiffuse="FF0082C2">$INFO[ListItem.Property(verified)]</texture> - <aspectratio>scale</aspectratio> + <control type="group"> + <top>420</top> + <left>230</left> + <visible>!String.IsEmpty(ListItem.Property(channelthumb))</visible> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>150</width> + <height>150</height> + <texture colordiffuse="FF999999">$INFO[ListItem.Property(channelthumb)]</texture> + <visible>!Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> + <control type="image"> + <description>Item Poster</description> + <top>0</top> + <left>0</left> + <width>150</width> + <height>150</height> + <texture>$INFO[ListItem.Property(channelthumb)]</texture> + <visible>Control.HasFocus(102)</visible> + <bordersize>10</bordersize> + <aspectratio>scale</aspectratio> + </control> </control> </focusedlayout> </control> @@ -248,10 +289,10 @@ </control> <control type="textbox"> <description>Results Count</description> - <right>5</right> - <top>5</top> - <width>30</width> - <height>30</height> + <left>110</left> + <top>0</top> + <width>40</width> + <height>40</height> <!-- <font>font30_title</font> --> <textcolor>22FFFFFF</textcolor> <shadowcolor>00000000</shadowcolor> @@ -259,15 +300,6 @@ <align>center</align> <aligny>center</aligny> </control> - <control type="image"> - <description>Verified</description> - <top>5</top> - <left>5</left> - <width>30</width> - <height>30</height> - <texture colordiffuse="880082C2">$INFO[ListItem.Property(verified)]</texture> - <aspectratio>scale</aspectratio> - </control> </itemlayout> <focusedlayout height="150" width="150"> <control type="image"> @@ -288,22 +320,12 @@ <texture colordiffuse="880082C2">white.png</texture> <aspectratio>scale</aspectratio> </control> - <control type="image"> - <description>Results Count</description> - <top>5</top> - <left>5</left> - <width>30</width> - <height>30</height> - <texture colordiffuse="FF0082C2">$INFO[ListItem.Property(verified)]</texture> - <aspectratio>scale</aspectratio> - </control> <control type="textbox"> - <description>Verified</description> - <right>5</right> - <top>5</top> - <width>30</width> - <height>30</height> - <!-- <font>font30_title</font> --> + <description>Results Count</description> + <left>110</left> + <top>0</top> + <width>40</width> + <height>40</height> <textcolor>FFFFFFFF</textcolor> <shadowcolor>00000000</shadowcolor> <label>[B]$INFO[ListItem.Property(results)][/B]</label> @@ -346,7 +368,7 @@ <control type="list" id="200"> <!-- Episodes List --> <description>Episodes List</description> - <bottom>40</bottom> + <top>110</top> <left>520</left> <width>700</width> <height>570</height> @@ -359,7 +381,6 @@ <left>20</left> <width>660</width> <height>60</height> - <!-- <font>font30_title</font> --> <textcolor>FFFFFFFF</textcolor> <shadowcolor>00000000</shadowcolor> <align>left</align> @@ -370,6 +391,8 @@ <focusedlayout height="60" width="700"> <control type="image"> <description>Selected Background</description> + <top>0</top> + <left>0</left> <width>700</width> <height>60</height> <texture colordiffuse="88000000">white.png</texture> @@ -380,7 +403,6 @@ <left>20</left> <width>660</width> <height>60</height> - <!-- <font>font30_title</font> --> <textcolor>FFFFFFFF</textcolor> <shadowcolor>00000000</shadowcolor> <align>left</align> @@ -476,6 +498,20 @@ <aligny>center</aligny> <label>[B][COLOR FFAAAAAA]$INFO[ListItem.Property(servername)][/COLOR][/B]</label> </control> + <control type="textbox"> + <description>No Server Title</description> + <left>150</left> + <top>35</top> + <width>450</width> + <height>60</height> + <!-- <font>font30_title</font> --> + <textcolor>FFFFFFFF</textcolor> + <shadowcolor>00000000</shadowcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Label]</label> + <visible>!ListItem.Property(servername)</visible> + </control> </itemlayout> <focusedlayout height="140" width="700"> <control type="image"> @@ -543,6 +579,20 @@ <aligny>center</aligny> <label>[B][COLOR FFAAAAAA]$INFO[ListItem.Property(servername)][/COLOR][/B]</label> </control> + <control type="textbox"> + <description>No Server Title</description> + <left>150</left> + <top>35</top> + <width>450</width> + <height>60</height> + <!-- <font>font30_title</font> --> + <textcolor>FFFFFFFF</textcolor> + <shadowcolor>00000000</shadowcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Label]</label> + <visible>!ListItem.Property(servername)</visible> + </control> </focusedlayout> </control> <!-- END Servers List --> </control> <!-- END SERVERS GROUP --> diff --git a/resources/skins/Default/720p/NextDialogExtended.xml b/resources/skins/Default/720p/NextDialogExtended.xml index 54b8d906..898d6eaa 100644 --- a/resources/skins/Default/720p/NextDialogExtended.xml +++ b/resources/skins/Default/720p/NextDialogExtended.xml @@ -25,6 +25,7 @@ <width>326</width> <height>180</height> <texture>$INFO[Window.Property(next_img)]</texture> + <aspectratio>scale</aspectratio> </control> <control type="grouplist" id="20"> <orientation>vertical</orientation> diff --git a/resources/skins/Default/720p/ResumePlayback.xml b/resources/skins/Default/720p/ResumePlayback.xml index 3f6830cb..1042e326 100644 --- a/resources/skins/Default/720p/ResumePlayback.xml +++ b/resources/skins/Default/720p/ResumePlayback.xml @@ -6,26 +6,26 @@ <controls> <control type="group"> <animation type="WindowOpen" reversible="false"> - <effect type="fade" start="0" end="100" time="300" /> + <effect type="fade" start="0" end="100" time="100" /> </animation> <animation type="WindowClose" reversible="false"> - <effect type="fade" start="100" end="0" time="300" /> + <effect type="fade" start="100" end="0" time="100" /> </animation> - <right>440</right> - <top>320</top> + <right>490</right> + <top>300</top> <height>40</height> - <width>400</width> + <width>300</width> <control type="grouplist" id="20"> <orientation>vertical</orientation> - <height>80</height> + <height>120</height> <itemgap>0</itemgap> <align>center</align> <control type="button" id="3012"> - <label>$ADDON[plugin.video.kod 30045] $INFO[Window.Property(time)]</label> + <label>[B]$ADDON[plugin.video.kod 30045] $INFO[Window.Property(time)][/B]</label> <onclick>SendClick(3012)</onclick> - <height>40</height> - <width>400</width> - <font>font30_title</font> + <height>60</height> + <width>300</width> + <!-- <font>font30_title</font> --> <textoffsetx>20</textoffsetx> <textcolor>FFFFFFFF</textcolor> <aligny>center</aligny> @@ -35,10 +35,10 @@ <pulseonselect>no</pulseonselect> </control> <control type="button" id="3013"> - <label>$ADDON[plugin.video.kod 30046]</label> - <height>40</height> - <width>400</width> - <font>font30_title</font> + <label>[B]$ADDON[plugin.video.kod 30046][/B]</label> + <height>60</height> + <width>300</width> + <!-- <font>font30_title</font> --> <textoffsetx>20</textoffsetx> <textcolor>FFFFFFFF</textcolor> <aligny>center</aligny> diff --git a/resources/skins/Default/media/valid.png b/resources/skins/Default/media/valid.png new file mode 100644 index 0000000000000000000000000000000000000000..d12f4eb5a0bc950dc39314dcb23440651e29ec8d GIT binary patch literal 16687 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 NI>!t&i`8u}{T~>U0hIs% literal 0 HcmV?d00001 diff --git a/servers/akvideo.json b/servers/akvideo.json index c8305d65..fe7575a3 100644 --- a/servers/akvideo.json +++ b/servers/akvideo.json @@ -22,7 +22,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "$ADDON[plugin.video.kod 60654]", + "label": "$ADDON[plugin.video.kod 70708]", "type": "bool", "visible": true }, diff --git a/servers/anavids.json b/servers/anavids.json index bdc73b86..4b7fc58c 100644 --- a/servers/anavids.json +++ b/servers/anavids.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/animeid.json b/servers/animeid.json index 21086eba..dd665438 100644 --- a/servers/animeid.json +++ b/servers/animeid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/anonfile.json b/servers/anonfile.json index 5a7cd15a..ec27fd8b 100644 --- a/servers/anonfile.json +++ b/servers/anonfile.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/archiveorg.json b/servers/archiveorg.json index ef60d243..7f38cbb4 100644 --- a/servers/archiveorg.json +++ b/servers/archiveorg.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/backin.json b/servers/backin.json index 050a3e71..c751c943 100644 --- a/servers/backin.json +++ b/servers/backin.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/badshare.json b/servers/badshare.json index ae4265e9..079cab25 100644 --- a/servers/badshare.json +++ b/servers/badshare.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/bdupload.json b/servers/bdupload.json index c9708b6b..50eea6ce 100644 --- a/servers/bdupload.json +++ b/servers/bdupload.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/cinemaupload.json b/servers/cinemaupload.json index 448525a8..c7627a01 100644 --- a/servers/cinemaupload.json +++ b/servers/cinemaupload.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/clicknupload.json b/servers/clicknupload.json index 068bd3e5..2d2d8889 100644 --- a/servers/clicknupload.json +++ b/servers/clicknupload.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/clipwatching.json b/servers/clipwatching.json index 87c03421..d84e2fe8 100644 --- a/servers/clipwatching.json +++ b/servers/clipwatching.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/cloudvideo.json b/servers/cloudvideo.json index 6016fbdd..ee4c442d 100644 --- a/servers/cloudvideo.json +++ b/servers/cloudvideo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/crunchyroll.json b/servers/crunchyroll.json index 895e132e..1eee02ca 100644 --- a/servers/crunchyroll.json +++ b/servers/crunchyroll.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/dailymotion.json b/servers/dailymotion.json index 25e8b935..d454aeaa 100644 --- a/servers/dailymotion.json +++ b/servers/dailymotion.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/deltabit.json b/servers/deltabit.json index f392a7d1..ed0e8e07 100644 --- a/servers/deltabit.json +++ b/servers/deltabit.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/directo.json b/servers/directo.json index 7fb11746..0e74446c 100644 --- a/servers/directo.json +++ b/servers/directo.json @@ -50,7 +50,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/doodstream.json b/servers/doodstream.json index 165628c4..3743c7f5 100644 --- a/servers/doodstream.json +++ b/servers/doodstream.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/dostream.json b/servers/dostream.json index 4c9745bd..9435b1c2 100644 --- a/servers/dostream.json +++ b/servers/dostream.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/downace.json b/servers/downace.json index 721dd84e..decdc6d8 100644 --- a/servers/downace.json +++ b/servers/downace.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/facebook.json b/servers/facebook.json index 9a6f54f1..a37b6f6b 100644 --- a/servers/facebook.json +++ b/servers/facebook.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/fastplay.json b/servers/fastplay.json index 411c2f40..291307bb 100755 --- a/servers/fastplay.json +++ b/servers/fastplay.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/fembed.json b/servers/fembed.json index a5f53139..de73ab15 100644 --- a/servers/fembed.json +++ b/servers/fembed.json @@ -14,7 +14,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/fex.json b/servers/fex.json index a22348de..2ccc5997 100644 --- a/servers/fex.json +++ b/servers/fex.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/filefactory.json b/servers/filefactory.json index 99b7b565..ed63f53b 100644 --- a/servers/filefactory.json +++ b/servers/filefactory.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/filepup.json b/servers/filepup.json index 945f5994..d2c5c0f9 100644 --- a/servers/filepup.json +++ b/servers/filepup.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/filescdn.json b/servers/filescdn.json index c1810508..7448aebc 100644 --- a/servers/filescdn.json +++ b/servers/filescdn.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/filesmonster.json b/servers/filesmonster.json index 19408a7f..d2e4f40b 100644 --- a/servers/filesmonster.json +++ b/servers/filesmonster.json @@ -20,7 +20,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/flashx.json b/servers/flashx.json index b1a9e13d..231c65f7 100644 --- a/servers/flashx.json +++ b/servers/flashx.json @@ -24,7 +24,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/fourshared.json b/servers/fourshared.json index 4b60a6e5..1efd7f51 100644 --- a/servers/fourshared.json +++ b/servers/fourshared.json @@ -31,7 +31,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/gamovideo.json b/servers/gamovideo.json index 5432f2fc..eee03921 100755 --- a/servers/gamovideo.json +++ b/servers/gamovideo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/gigasize.json b/servers/gigasize.json index 0b2b0576..29a1c02a 100644 --- a/servers/gigasize.json +++ b/servers/gigasize.json @@ -25,7 +25,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/googlevideo.json b/servers/googlevideo.json index 8886b7d5..1ca06c9b 100644 --- a/servers/googlevideo.json +++ b/servers/googlevideo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/gounlimited.json b/servers/gounlimited.json index d2b5fec0..dfaad755 100644 --- a/servers/gounlimited.json +++ b/servers/gounlimited.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/gvideo.json b/servers/gvideo.json index 22fc4bb3..b2839bc7 100644 --- a/servers/gvideo.json +++ b/servers/gvideo.json @@ -37,7 +37,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/hdload.json b/servers/hdload.json index 167caf95..58635ef0 100644 --- a/servers/hdload.json +++ b/servers/hdload.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/hdmario.json b/servers/hdmario.json index bb80a103..649515b7 100644 --- a/servers/hdmario.json +++ b/servers/hdmario.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/hugefiles.json b/servers/hugefiles.json index 6be802b5..6fde0486 100644 --- a/servers/hugefiles.json +++ b/servers/hugefiles.json @@ -20,7 +20,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/idtbox.json b/servers/idtbox.json index 0dea7d55..6f143dd9 100644 --- a/servers/idtbox.json +++ b/servers/idtbox.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/jawcloud.json b/servers/jawcloud.json index 975bc12e..8fcef964 100644 --- a/servers/jawcloud.json +++ b/servers/jawcloud.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/jetload.json b/servers/jetload.json index 447cbe94..bc46f8c0 100644 --- a/servers/jetload.json +++ b/servers/jetload.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mailru.json b/servers/mailru.json index 624d731d..b3925c44 100644 --- a/servers/mailru.json +++ b/servers/mailru.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mediafire.json b/servers/mediafire.json index 8abc34ee..46ff6665 100644 --- a/servers/mediafire.json +++ b/servers/mediafire.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mega.json b/servers/mega.json index af59ebaf..c7f8c4c5 100644 --- a/servers/mega.json +++ b/servers/mega.json @@ -36,7 +36,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mixdrop.json b/servers/mixdrop.json index b63ebd24..dc33cd93 100644 --- a/servers/mixdrop.json +++ b/servers/mixdrop.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mp4upload.json b/servers/mp4upload.json index d46b4135..f2ced1e7 100644 --- a/servers/mp4upload.json +++ b/servers/mp4upload.json @@ -19,7 +19,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mydaddy.json b/servers/mydaddy.json index 671b9418..ca0becd0 100644 --- a/servers/mydaddy.json +++ b/servers/mydaddy.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/mystream.json b/servers/mystream.json index 46f8c4cf..2549ee09 100644 --- a/servers/mystream.json +++ b/servers/mystream.json @@ -1,7 +1,7 @@ { "active": true, "find_videos": { - "ignore_urls": [], + "ignore_urls": ["https://embed.mystream.to/span"], "patterns": [ { "pattern": "my?stream\\.(?:\\w+\\.)?[^/]+/(?:external|watch/|embed-)?([0-9a-zA-Z_]+)", @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/myupload.json b/servers/myupload.json index fdd2bcc8..3ddbf417 100644 --- a/servers/myupload.json +++ b/servers/myupload.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/netutv.json b/servers/netutv.json index c8124fc6..49cda818 100755 --- a/servers/netutv.json +++ b/servers/netutv.json @@ -36,7 +36,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/nowvideo.json b/servers/nowvideo.json index 5a39d41c..3beb9b3e 100644 --- a/servers/nowvideo.json +++ b/servers/nowvideo.json @@ -26,7 +26,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/okru.json b/servers/okru.json index dcc42f28..0ed2c3bd 100644 --- a/servers/okru.json +++ b/servers/okru.json @@ -22,7 +22,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/onefichier.json b/servers/onefichier.json index 1f0b14d2..f0dec829 100644 --- a/servers/onefichier.json +++ b/servers/onefichier.json @@ -26,7 +26,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/onlystream.json b/servers/onlystream.json index 4129e9cd..72fb3e77 100644 --- a/servers/onlystream.json +++ b/servers/onlystream.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/rapidgator.json b/servers/rapidgator.json index 3448d62f..a208a349 100644 --- a/servers/rapidgator.json +++ b/servers/rapidgator.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/rcdnme.json b/servers/rcdnme.json index 6f8f4771..5dd14287 100644 --- a/servers/rcdnme.json +++ b/servers/rcdnme.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/rutube.json b/servers/rutube.json index 1079f56a..496f6005 100644 --- a/servers/rutube.json +++ b/servers/rutube.json @@ -20,7 +20,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/samaup.json b/servers/samaup.json index d1c2187b..dfe9063d 100644 --- a/servers/samaup.json +++ b/servers/samaup.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/sendvid.json b/servers/sendvid.json index 5dff7072..e1e1ac64 100755 --- a/servers/sendvid.json +++ b/servers/sendvid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/speedvideo.json b/servers/speedvideo.json index c91a0a27..55bf2d00 100644 --- a/servers/speedvideo.json +++ b/servers/speedvideo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/streamtape.json b/servers/streamtape.json index 5e6cb39e..b735c997 100644 --- a/servers/streamtape.json +++ b/servers/streamtape.json @@ -14,7 +14,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/streamz.json b/servers/streamz.json index 5c1f3ed5..129f8d4d 100644 --- a/servers/streamz.json +++ b/servers/streamz.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/supervideo.json b/servers/supervideo.json index 0434ee84..fabccac0 100644 --- a/servers/supervideo.json +++ b/servers/supervideo.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/thevid.json b/servers/thevid.json index 0da109c9..e723747b 100644 --- a/servers/thevid.json +++ b/servers/thevid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/thevideobee.json b/servers/thevideobee.json index 45ccb4da..c6a24f4f 100644 --- a/servers/thevideobee.json +++ b/servers/thevideobee.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/torrent.json b/servers/torrent.json index 12b59037..7b0bb703 100644 --- a/servers/torrent.json +++ b/servers/torrent.json @@ -62,7 +62,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/turbobit.json b/servers/turbobit.json index 693b9a81..2e206895 100644 --- a/servers/turbobit.json +++ b/servers/turbobit.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/turbovid.json b/servers/turbovid.json index 54cc8057..564868e0 100644 --- a/servers/turbovid.json +++ b/servers/turbovid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/tusfiles.json b/servers/tusfiles.json index 0dcf9cd5..92c13339 100644 --- a/servers/tusfiles.json +++ b/servers/tusfiles.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/unsupported.json b/servers/unsupported.json index 066467c3..16cda209 100644 --- a/servers/unsupported.json +++ b/servers/unsupported.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": false }, diff --git a/servers/uploadedto.json b/servers/uploadedto.json index 5097d423..4934da71 100644 --- a/servers/uploadedto.json +++ b/servers/uploadedto.json @@ -34,7 +34,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/uppom.json b/servers/uppom.json index fe9b3bea..f7509b04 100644 --- a/servers/uppom.json +++ b/servers/uppom.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/upstream.json b/servers/upstream.json index 0172432b..8bd05840 100644 --- a/servers/upstream.json +++ b/servers/upstream.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/uptobox.json b/servers/uptobox.json index c30d430d..a54c62c2 100644 --- a/servers/uptobox.json +++ b/servers/uptobox.json @@ -25,7 +25,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/upvid.json b/servers/upvid.json index b5122e69..00aaf9c2 100644 --- a/servers/upvid.json +++ b/servers/upvid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/uqload.json b/servers/uqload.json index 505e4d85..9a361b42 100644 --- a/servers/uqload.json +++ b/servers/uqload.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/userscloud.json b/servers/userscloud.json index 3205bd9c..8a72bd45 100644 --- a/servers/userscloud.json +++ b/servers/userscloud.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vevio.json b/servers/vevio.json index d8bd1f45..9ad090be 100644 --- a/servers/vevio.json +++ b/servers/vevio.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidcloud.json b/servers/vidcloud.json index 3e974588..21882336 100644 --- a/servers/vidcloud.json +++ b/servers/vidcloud.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/videobin.json b/servers/videobin.json index 57209c51..f7ec3af0 100644 --- a/servers/videobin.json +++ b/servers/videobin.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/videomega.json b/servers/videomega.json index 5dd00bec..2f97d68a 100644 --- a/servers/videomega.json +++ b/servers/videomega.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidfast.json b/servers/vidfast.json index 9bfee90e..693b50ce 100644 --- a/servers/vidfast.json +++ b/servers/vidfast.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidlox.json b/servers/vidlox.json index d4f6a88d..f3b386eb 100644 --- a/servers/vidlox.json +++ b/servers/vidlox.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidmoly.json b/servers/vidmoly.json index c1b5c1c0..e8d4d984 100644 --- a/servers/vidmoly.json +++ b/servers/vidmoly.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidoza.json b/servers/vidoza.json index 05c1a3a8..997832ff 100644 --- a/servers/vidoza.json +++ b/servers/vidoza.json @@ -20,7 +20,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidtodo.json b/servers/vidtodo.json index 6ceeedf0..fa25c7cd 100755 --- a/servers/vidtodo.json +++ b/servers/vidtodo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidtome.json b/servers/vidtome.json index b404034a..82ff9685 100644 --- a/servers/vidtome.json +++ b/servers/vidtome.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vidup.json b/servers/vidup.json index e1297257..3a44c83c 100755 --- a/servers/vidup.json +++ b/servers/vidup.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vimeo.json b/servers/vimeo.json index 2b0d433a..04053b66 100644 --- a/servers/vimeo.json +++ b/servers/vimeo.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vimpleru.json b/servers/vimpleru.json index d89ce595..479ce5c7 100644 --- a/servers/vimpleru.json +++ b/servers/vimpleru.json @@ -22,7 +22,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vivo.json b/servers/vivo.json index 58ac6202..5f653935 100644 --- a/servers/vivo.json +++ b/servers/vivo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vk.json b/servers/vk.json index e50928ef..885ffc0d 100755 --- a/servers/vk.json +++ b/servers/vk.json @@ -39,7 +39,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vshare.json b/servers/vshare.json index e1488ee6..a4e2f676 100644 --- a/servers/vshare.json +++ b/servers/vshare.json @@ -26,7 +26,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vudeo.json b/servers/vudeo.json index 9a6b4731..6bf6630c 100644 --- a/servers/vudeo.json +++ b/servers/vudeo.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vupplayer.json b/servers/vupplayer.json index fe4e5c6f..6df012d8 100644 --- a/servers/vupplayer.json +++ b/servers/vupplayer.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/vupplayer.py b/servers/vupplayer.py index b1eaf15e..6df91c7f 100644 --- a/servers/vupplayer.py +++ b/servers/vupplayer.py @@ -10,7 +10,7 @@ def test_video_exists(page_url): global data data = page.data 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) % "VUP" return True, "" diff --git a/servers/vvvvid.json b/servers/vvvvid.json index 42be33e2..f20d6bd1 100644 --- a/servers/vvvvid.json +++ b/servers/vvvvid.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/watchanimestream.json b/servers/watchanimestream.json index 8fe58ba7..badc9617 100644 --- a/servers/watchanimestream.json +++ b/servers/watchanimestream.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/watchvideo.json b/servers/watchvideo.json index a6bc4c1b..c090e484 100644 --- a/servers/watchvideo.json +++ b/servers/watchvideo.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/wstream.json b/servers/wstream.json index f9668a6a..86f20526 100644 --- a/servers/wstream.json +++ b/servers/wstream.json @@ -26,7 +26,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "$ADDON[plugin.video.kod 60654]", + "label": "$ADDON[plugin.video.kod 70708]", "type": "bool", "visible": true }, diff --git a/servers/youdbox.json b/servers/youdbox.json index ab9e3263..aff46ba7 100644 --- a/servers/youdbox.json +++ b/servers/youdbox.json @@ -17,7 +17,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/yourupload.json b/servers/yourupload.json index 9c61f454..0d978bb1 100755 --- a/servers/yourupload.json +++ b/servers/yourupload.json @@ -27,7 +27,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/youtube.json b/servers/youtube.json index 34a81972..d8235284 100755 --- a/servers/youtube.json +++ b/servers/youtube.json @@ -25,7 +25,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/youwatch.json b/servers/youwatch.json index 1c4bc87a..ffea3ec2 100644 --- a/servers/youwatch.json +++ b/servers/youwatch.json @@ -20,7 +20,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/servers/zippyshare.json b/servers/zippyshare.json index 48df2b5a..4d136ce6 100644 --- a/servers/zippyshare.json +++ b/servers/zippyshare.json @@ -21,7 +21,7 @@ "default": false, "enabled": true, "id": "black_list", - "label": "@60654", + "label": "@70708", "type": "bool", "visible": true }, diff --git a/service.py b/service.py index 5ab5e931..1a69cbbc 100644 --- a/service.py +++ b/service.py @@ -8,6 +8,11 @@ import traceback import xbmc import xbmcgui from platformcode import config + +try: + from urllib.parse import urlsplit +except ImportError: + from urlparse import urlsplit # on kodi 18 its xbmc.translatePath, on 19 xbmcvfs.translatePath try: import xbmcvfs @@ -17,7 +22,7 @@ except: librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib')) sys.path.insert(0, librerias) -from core import videolibrarytools, filetools, channeltools +from core import videolibrarytools, filetools, channeltools, httptools, scrapertools from lib import schedule from platformcode import logger, platformtools, updater from specials import videolibrary @@ -38,6 +43,8 @@ def update(path, p_dialog, i, t, serie, overwrite): # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in serie.library_urls.items(): serie.channel = channel + module = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) + url = module.host + urlsplit(url).path serie.url = url ###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial @@ -297,6 +304,23 @@ def updaterCheck(): exit(0) +def get_ua_list(): + # https://github.com/alfa-addon/addon/blob/master/plugin.video.alfa/platformcode/updater.py#L273 + logger.info() + url = "http://omahaproxy.appspot.com/all?csv=1" + current_ver = config.get_setting("chrome_ua_version", default="").split(".") + data = httptools.downloadpage(url, alfa_s=True).data + new_ua_ver = scrapertools.find_single_match(data, "win64,stable,([^,]+),") + + if not current_ver: + config.set_setting("chrome_ua_version", new_ua_ver) + else: + for pos, val in enumerate(new_ua_ver.split('.')): + if int(val) > int(current_ver[pos]): + config.set_setting("chrome_ua_version", new_ua_ver) + break + + def run_threaded(job_func, args): job_thread = threading.Thread(target=job_func, args=args) job_thread.start() @@ -311,6 +335,7 @@ class AddonMonitor(xbmc.Monitor): self.update_hour = None self.scheduleScreenOnJobs() self.scheduleUpdater() + self.scheduleUA() # videolibrary wait update_wait = [0, 10000, 20000, 30000, 60000] @@ -383,6 +408,10 @@ class AddonMonitor(xbmc.Monitor): schedule.every(self.updaterPeriod).hours.do(updaterCheck).tag('updater') logger.debug('scheduled updater every ' + str(self.updaterPeriod) + ' hours') + def scheduleUA(self): + get_ua_list() + schedule.every(1).day.do(get_ua_list) + def scheduleVideolibrary(self): self.update_setting = config.get_setting("update", "videolibrary") # 2= daily 3=daily and when kodi starts diff --git a/platformcode/globalsearch.py b/specials/globalsearch.py similarity index 55% rename from platformcode/globalsearch.py rename to specials/globalsearch.py index a54f3bd6..75eaf0e4 100644 --- a/platformcode/globalsearch.py +++ b/specials/globalsearch.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -import xbmc, xbmcgui, sys, channelselector, time +import xbmc, xbmcgui, sys, channelselector, time, gc from core.support import dbg, typo, tmdb from core.item import Item from core import channeltools, servertools, scrapertools @@ -13,6 +13,7 @@ else: from concurrent_py2 import futures info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json def_lang = info_language[config.get_setting("info_language", "videolibrary")] +close_action = False def busy(state): @@ -23,10 +24,10 @@ def set_workers(): workers = config.get_setting('thread_number') if config.get_setting('thread_number') > 0 else None return workers -def Search(item): - xbmc.executebuiltin('Dialog.Close(all,true)') - SearchWindow('GlobalSearch.xml', config.get_runtime_path()).start(item) - xbmc.sleep(600) +def Search(*args): + w = SearchWindow('GlobalSearch.xml', config.get_runtime_path()) + w.start(*args) + del w # Actions LEFT = 1 @@ -38,6 +39,8 @@ EXIT = 10 BACKSPACE = 92 SWIPEUP = 531 CONTEXT = 117 +MOUSEMOVE = 107 +FULLSCREEN = 18 # Container SEARCH = 1 @@ -62,42 +65,71 @@ QUALITYTAG = 505 EPISODESLIST = 200 SERVERLIST = 300 -class SearchWindow(xbmcgui.WindowXML): - def start(self, item): +class SearchWindow(xbmcgui.WindowXMLDialog): + def start(self, item, moduleDict={}, searchActions=[]): logger.debug() self.exit = False self.item = item - self.lastSearch() - if not self.item.text: return self.type = self.item.mode self.channels = [] - self.find = [] self.persons = [] self.episodes = [] self.servers = [] self.results = {} - self.channelsList = self.get_channels() self.focus = SEARCH self.process = True self.page = 1 - self.moduleDict = {} - self.searchActions = [] + self.moduleDict = moduleDict + self.searchActions = searchActions self.thread = None + self.selected = False + self.items = [] + + if not searchActions: + self.thActions = Thread(target=self.getActions) + self.thActions.start() + else: + self.thActions = None + + self.lastSearch() + if not self.item.text: return + self.doModal() def lastSearch(self): logger.debug() if not self.item.text: - if config.get_setting('last_search'): last_search = channeltools.get_channel_setting('Last_searched', 'search', '') - else: last_search = '' - if not self.item.text: self.item.text = platformtools.dialog_input(default=last_search, heading='') - if self.item.text: channeltools.set_channel_setting('Last_searched', self.item.text, 'search') + if self.item.contentTitle: + self.item.text = self.item.contentTitle + elif self.item.contentSerieName: + self.item.text = self.item.contentSerieName + + if not self.item.text: + if config.get_setting('last_search'): last_search = channeltools.get_channel_setting('Last_searched', 'search', '') + else: last_search = '' + if not self.item.text: self.item.text = platformtools.dialog_input(default=last_search, heading='') + if self.item.text: + channeltools.set_channel_setting('Last_searched', self.item.text, 'search') + from specials.search import save_search + save_search(self.item.text) + + def getActions(self): + logger.debug() + count = 0 + self.channelsList = self.get_channels() + for channel in self.channelsList: + self.getModule(channel) + count += 1 + percent = (float(count) / len(self.channelsList)) * 100 + if self.thread or self.selected: # window started + self.PROGRESS.setPercent(percent) + self.COUNT.setText('%s/%s' % (count, len(self.channelsList))) def select(self): logger.debug() self.PROGRESS.setVisible(False) - items = [] - if self.persons: + self.items = [] + if self.item.mode == 'person_': tmdb_info = tmdb.discovery(self.item, dict_=self.item.discovery) results = tmdb_info.results.get('cast',[]) else: @@ -105,32 +137,50 @@ class SearchWindow(xbmcgui.WindowXML): results = tmdb_info.results for result in results: - logger.info(result) result = tmdb_info.get_infoLabels(result, origen=result) - movie = result.get('title','') - tvshow = result.get('name','') - title = tvshow if tvshow else movie - result['mode'] = 'tvshow' if tvshow else 'movie' - self.find.append(result) - thumb = 'Infoplus/' + result['mode'].replace('show','') + '.png' - it = xbmcgui.ListItem(title) - it.setProperty('thumb', result.get('thumbnail', thumb)) - it.setProperty('fanart', result.get('fanart','')) - it.setProperty('plot', result.get('overview', '')) - it.setProperty('search','search') - year = result.get('release_date','') - if year: it.setProperty('year','[' + year.split('/')[-1] + ']') + if self.item.mode == 'movie': + title = result['title'] + result['mode'] = 'movie' else: - year = result.get('first_air_date','') - if year: it.setProperty('year','[' + year.split('-')[0] + ']') - items.append(it) + title = result['name'] + result['mode'] = 'tvshow' - if items: + thumbnail = result.get('thumbnail', '') + noThumb = 'Infoplus/' + result['mode'].replace('show','') + '.png' + fanart = result.get('fanart', '') + year = result.get('release_date', '') + rating = str(result.get('vote_average', '')) + + new_item = Item(channel='search', + action=True, + title=title, + thumbnail=thumbnail, + fanart=fanart, + mode='search', + type=result['mode'], + contentType=result['mode'], + text=title, + infoLabels=result) + + if self.item.mode == 'movie': + new_item.contentTitle = result['title'] + else: + new_item.contentSerieName = result['name'] + + it = xbmcgui.ListItem(title) + it.setProperties({'thumb': result.get('thumbnail', noThumb), 'fanart': result.get('fanart', ''), 'rating': ' [' + rating + ']' if rating else '', + 'plot': result.get('overview', ''), 'search': 'search', 'release_date': '', 'item': new_item.tourl(), + 'year': ' [' + year.split('/')[-1] + ']' if year else ' [' + result.get('first_air_date','').split('-')[0] + ']'}) + self.items.append(it) + + if self.items: self.RESULTS.reset() - self.RESULTS.addItems(items) + self.RESULTS.addItems(self.items) self.setFocusId(RESULTS) else: + self.RESULTS.setVisible(False) self.NORESULTS.setVisible(True) + self.setFocusId(CLOSE) def actors(self): logger.debug() @@ -161,10 +211,15 @@ class SearchWindow(xbmcgui.WindowXML): discovery = {'url': 'person/%s/combined_credits' % cast_id, 'page': '1', 'sort_by': 'primary_release_date.desc', 'language': def_lang} self.persons.append(discovery) + + new_item = Item(channel='search', + action=True, + title=name, + thumbnail=thumb, + mode='search') + it = xbmcgui.ListItem(name) - it.setProperty('thumb', thumb) - it.setProperty('plot', plot) - it.setProperty('search','persons') + it.setProperties({'thumb': thumb, 'plot': plot, 'search': 'persons', 'item': new_item.tourl()}) items.append(it) if len(results) > 19: it = xbmcgui.ListItem(config.get_localized_string(70006)) @@ -182,7 +237,9 @@ class SearchWindow(xbmcgui.WindowXML): self.RESULTS.addItems(items) self.setFocusId(RESULTS) else: + self.RESULTS.setVisible(False) self.NORESULTS.setVisible(True) + self.setFocusId(CLOSE) def get_channels(self): logger.debug() @@ -203,7 +260,7 @@ class SearchWindow(xbmcgui.WindowXML): n = list_cat.index('anime') list_cat[n] = 'tvshow' - if self.item.mode == 'all' or self.item.type in list_cat: + if self.item.mode == 'all' or self.item.mode in list_cat or self.item.type in list_cat: if config.get_setting("include_in_global_search", channel) and ch_param.get("active", False): channels_list.append(channel) @@ -217,68 +274,50 @@ class SearchWindow(xbmcgui.WindowXML): module = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) mainlist = getattr(module, 'mainlist')(Item(channel=channel, global_search=True)) action = [elem for elem in mainlist if elem.action == "search" and (self.item.mode == 'all' or elem.contentType in [self.item.mode, 'undefined'])] - return module, action + self.moduleDict[channel] = module + self.searchActions += action except: import traceback logger.error('error importing/getting search items of ' + channel) logger.error(traceback.format_exc()) - return None, None + + def timer(self): + while self.searchActions: + self.COUNT.setText('%s/%s [%s"]' % (self.count, len(self.searchActions), int(time.time() - self.time) )) + time.sleep(1) def search(self): - count = 0 + logger.debug() self.count = 0 self.LOADING.setVisible(True) - with futures.ThreadPoolExecutor() as executor: - results = [] - for channel in self.channelsList: - if self.exit: return - results.append(executor.submit(self.getModule, channel)) - - for res in futures.as_completed(results): - if self.exit: return - module, action = res.result() - if module and action: - channel = action[0].channel - self.moduleDict[channel] = module - self.searchActions += action - count += 1 - percent = (float(count) / len(self.channelsList)) * 100 - self.PROGRESS.setPercent(percent) - self.COUNT.setText('%s/%s' % (count, len(self.channelsList))) - self.channelsList = [] + if self.thActions: + self.thActions.join() + Thread(target=self.timer).start() with futures.ThreadPoolExecutor(max_workers=set_workers()) as executor: for searchAction in self.searchActions: if self.exit: return - executor.submit(self.get_channel_results, self.item, self.moduleDict, searchAction) - self.moduleDict = {} - self.searchActions = [] + executor.submit(self.get_channel_results, searchAction) + logger.debug('end search for:', searchAction.channel) - def get_channel_results(self, item, module_dict, search_action): + def get_channel_results(self, searchAction): logger.debug() - channel = search_action.channel + channel = searchAction.channel results = [] valid = [] other = [] - module = module_dict[channel] - searched_id = item.infoLabels['tmdb_id'] try: - results.extend(module.search(search_action, item.text)) + results = self.moduleDict[channel].search(searchAction, self.item.text) if len(results) == 1: if not results[0].action or config.get_localized_string(70006).lower() in results[0].title.lower(): results = [] if self.item.mode != 'all': for elem in results: - if self.exit: - return - if not elem.infoLabels.get('year', ""): - elem.infoLabels['year'] = '-' - tmdb.set_infoLabels_item(elem) - if elem.infoLabels['tmdb_id'] == searched_id: + if elem.infoLabels['tmdb_id'] == self.item.infoLabels['tmdb_id']: elem.from_channel = channel - elem.verified ='ok.png' + elem.verified = 1 valid.append(elem) else: other.append(elem) @@ -286,60 +325,102 @@ class SearchWindow(xbmcgui.WindowXML): pass self.count += 1 - if self.item.mode == 'all': self.update(channel, results) - else: self.update(channel, valid + other) + return self.update(channel, valid, other if other else results) - def makeItem(self, item): - logger.debug() - thumb = item.thumbnail if item.thumbnail else 'Infoplus/' + item.contentType.replace('show','') + 'png' + def makeItem(self, url): + item = Item().fromurl(url) + logger.debug(item) + channelParams = channeltools.get_channel_parameters(item.channel) + thumb = item.thumbnail if item.thumbnail else 'Infoplus/' + item.contentType.replace('show', '') + '.png' logger.info('THUMB', thumb) it = xbmcgui.ListItem(item.title) - it.setProperty('year', '[' + str(item.year if item.year else item.infoLabels.get('year','')) + ']') - it.setProperty('thumb', thumb) - it.setProperty('fanart', item.fanart) - it.setProperty('plot', item.plot) - it.setProperty('verified', item.verified) + year = str(item.year if item.year else item.infoLabels.get('year', '')) + rating = str(item.infoLabels.get('rating', '')) + it.setProperties({'thumb': thumb, 'fanart': item.fanart, 'plot': item.plot, + 'year': ' [' + year + ']' if year else '', 'rating':' [' + rating + ']' if rating else '', + 'item': url, 'verified': item.verified, 'channel':channelParams['title'], 'channelthumb': channelParams['thumbnail'] if item.verified else ''}) if item.server: color = scrapertools.find_single_match(item.alive, r'(FF[^\]]+)') - it.setProperty('channel', channeltools.get_channel_parameters(item.channel).get('title','')) - it.setProperty('thumb', "https://raw.githubusercontent.com/kodiondemand/media/master/resources/servers/%s.png" % item.server.lower()) - it.setProperty('servername', servertools.get_server_parameters(item.server.lower()).get('name',item.server)) - it.setProperty('color', color if color else 'FF0082C2') + it.setProperties({'channel': channeltools.get_channel_parameters(item.channel).get('title', ''), + 'thumb': "https://raw.githubusercontent.com/kodiondemand/media/master/resources/servers/%s.png" % item.server.lower(), + 'servername': servertools.get_server_parameters(item.server.lower()).get('name', item.server), + 'color': color if color else 'FF0082C2'}) + return it - def update(self, channel, results): + def update(self, channel, valid, results): if self.exit: return logger.debug('Search on channel', channel) + if self.item.mode != 'all' and 'valid' not in self.results: + self.results['valid'] = 0 + item = xbmcgui.ListItem('valid') + item.setProperties({'thumb': 'valid.png', + 'position': '0', + 'results': '0'}) + self.channels.append(item) + pos = self.CHANNELS.getSelectedPosition() + self.CHANNELS.addItems(self.channels) + self.CHANNELS.selectItem(pos) + self.setFocusId(CHANNELS) + if valid: + item = self.CHANNELS.getListItem(0) + resultsList = item.getProperty('items') + for result in valid: + resultsList += result.tourl() + '|' + item.setProperty('items', resultsList) + self.channels[0].setProperty('results', str(len(resultsList.split('|')))) + if self.CHANNELS.getSelectedPosition() == 0: + items = [] + for result in valid: + if result: items.append(self.makeItem(result.tourl())) + pos = self.RESULTS.getSelectedPosition() + self.RESULTS.addItems(items) + self.RESULTS.selectItem(pos) if results: + resultsList = '' channelParams = channeltools.get_channel_parameters(channel) name = channelParams['title'] if name not in self.results: - self.results[name] = [results, len(self.channels)] item = xbmcgui.ListItem(name) - item.setProperty('thumb', channelParams['thumbnail']) - item.setProperty('position', '0') - item.setProperty('results', str(len(results))) - item.setProperty('verified', results[0].verified) + item.setProperties({'thumb': channelParams['thumbnail'], + 'position': '0', + 'results': str(len(results)) + }) + for result in results: + resultsList += result.tourl() + '|' + item.setProperty('items',resultsList) + self.results[name] = len(self.results) self.channels.append(item) else: - self.results[name].append([results, len(self.channels)]) - self.channels[int(self.results[name][1])].setProperty('results', str(len(results))) + item = self.CHANNELS.getListItem(self.results[name]) + resultsList = item.getProperty('items') + for result in results: + resultsList += result.tourl() + '|' + item.setProperty('items',resultsList) + self.channels[int(self.results[name])].setProperty('results', str(len(resultsList).split('|') - 1)) pos = self.CHANNELS.getSelectedPosition() self.CHANNELS.reset() self.CHANNELS.addItems(self.channels) self.CHANNELS.selectItem(pos) + if len(self.channels) == 1: self.setFocusId(CHANNELS) + channelResults = self.CHANNELS.getListItem(self.results[name]).getProperty('items').split('|') items = [] - for result in self.results[name][0]: - items.append(self.makeItem(result)) + for result in channelResults: + if result: items.append(self.makeItem(result)) self.RESULTS.reset() self.RESULTS.addItems(items) + percent = (float(self.count) / len(self.searchActions)) * 100 self.LOADING.setVisible(False) self.PROGRESS.setPercent(percent) self.COUNT.setText('%s/%s [%s"]' % (self.count, len(self.searchActions), int(time.time() - self.time) )) + if percent == 100: + self.channels = [] + self.moduleDict = {} + self.searchActions = [] if percent == 100 and not self.results: self.PROGRESS.setVisible(False) self.NORESULTS.setVisible(True) @@ -353,7 +434,7 @@ class SearchWindow(xbmcgui.WindowXML): self.PROGRESS = self.getControl(PROGRESS) self.COUNT = self.getControl(COUNT) self.MAINTITLE = self.getControl(MAINTITLE) - self.MAINTITLE.setText(typo(config.get_localized_string(30993).replace('...','') % '"%s"' % self.item.text, 'bold')) + self.MAINTITLE.setText(typo(config.get_localized_string(30993).replace('...', '') % '"%s"' % self.item.text, 'bold')) self.SEARCH = self.getControl(SEARCH) self.EPISODES = self.getControl(EPISODES) self.EPISODESLIST = self.getControl(EPISODESLIST) @@ -372,7 +453,7 @@ class SearchWindow(xbmcgui.WindowXML): if self.item.type: self.item.mode = self.item.type self.thread = Thread(target=self.search) self.thread.start() - elif self.item.mode in ['movie', 'tvshow']: + elif self.item.mode in ['movie', 'tvshow', 'person_']: self.select() elif self.item.mode in ['person']: self.actors() @@ -395,8 +476,11 @@ class SearchWindow(xbmcgui.WindowXML): self.SERVERS.setVisible(True) def onAction(self, action): + global close_action action = action.getId() focus = self.getFocusId() + if action in [FULLSCREEN]: + self.playmonitor() if action in [CONTEXT] and focus in [RESULTS, EPISODESLIST, SERVERLIST]: self.context() @@ -405,12 +489,13 @@ class SearchWindow(xbmcgui.WindowXML): pos = self.CHANNELS.getSelectedPosition() self.CHANNELS.selectItem(pos) - elif action in [LEFT, RIGHT] and focus in [CHANNELS] and self.CHANNELS.isVisible(): + elif action in [LEFT, RIGHT, MOUSEMOVE] and focus in [CHANNELS] and self.CHANNELS.isVisible(): items = [] name = self.CHANNELS.getSelectedItem().getLabel() subpos = int(self.CHANNELS.getSelectedItem().getProperty('position')) - for result in self.results[name][0]: - items.append(self.makeItem(result)) + channelResults = self.CHANNELS.getListItem(self.results[name]).getProperty('items').split('|') + for result in channelResults: + if result: items.append(self.makeItem(result)) self.RESULTS.reset() self.RESULTS.addItems(items) self.RESULTS.selectItem(subpos) @@ -418,7 +503,7 @@ class SearchWindow(xbmcgui.WindowXML): elif action in [DOWN] and focus in [BACK, CLOSE, MENU]: if self.SERVERS.isVisible(): self.setFocusId(SERVERLIST) elif self.EPISODES.isVisible(): self.setFocusId(EPISODESLIST) - else: self.setFocusId(RESULTS) + elif self.RESULTS.isVisible(): self.setFocusId(RESULTS) elif focus in [RESULTS] and self.item.mode == 'all': pos = self.RESULTS.getSelectedPosition() @@ -432,16 +517,20 @@ class SearchWindow(xbmcgui.WindowXML): elif action in [EXIT]: self.Close() + close_action = True def onClick(self, control_id): + global close_action + if self.RESULTS.getSelectedItem(): search = self.RESULTS.getSelectedItem().getProperty('search') else: search = None if control_id in [CHANNELS]: items = [] name = self.CHANNELS.getSelectedItem().getLabel() subpos = int(self.CHANNELS.getSelectedItem().getProperty('position')) - for result in self.results[name][0]: - items.append(self.makeItem(result)) + channelResults = self.CHANNELS.getListItem(self.results[name]).getProperty('items').split('|') + for result in channelResults: + if result: items.append(self.makeItem(result)) self.RESULTS.reset() self.RESULTS.addItems(items) self.RESULTS.selectItem(subpos) @@ -452,6 +541,7 @@ class SearchWindow(xbmcgui.WindowXML): elif control_id in [CLOSE]: self.Close() + close_action = True elif control_id in [MENU]: self.context() @@ -465,25 +555,50 @@ class SearchWindow(xbmcgui.WindowXML): self.page -= 1 self.actors() elif search == 'persons': - self.item.discovery = self.persons[pos] - self.select() + item = self.item.clone(mode='person_', discovery=self.persons[pos]) + self.close() + Search(item, self.moduleDict, self.searchActions) + if not close_action: + self.doModal() else: - result = self.find[pos] - name = self.RESULTS.getSelectedItem().getLabel() - item = Item(mode='search', type=result['mode'], contentType=result['mode'], infoLabels=result, selected = True, text=name) + item = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item')) if self.item.mode == 'movie': item.contentTitle = self.RESULTS.getSelectedItem().getLabel() else: item.contentSerieName = self.RESULTS.getSelectedItem().getLabel() - return Search(item) + + self.RESULTS.reset() + self.RESULTS.setVisible(False) + self.PROGRESS.setVisible(True) + self.selected = True + self.thActions.join() + self.RESULTS.addItems(self.items) + self.RESULTS.setVisible(True) + self.PROGRESS.setVisible(False) + + self.close() + Search(item, self.moduleDict, self.searchActions) + if not close_action: + self.doModal() elif control_id in [RESULTS, EPISODESLIST]: busy(True) if control_id in [RESULTS]: name = self.CHANNELS.getSelectedItem().getLabel() self.pos = self.RESULTS.getSelectedPosition() - item = self.results[name][0][self.pos] + item = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item')) else: self.pos = self.EPISODESLIST.getSelectedPosition() - item = self.episodes[self.pos] + item_url = self.EPISODESLIST.getSelectedItem().getProperty('item') + if item_url: + item = Item().fromurl(item_url) + else: # no results item + busy(False) + return + + if item.action not in ['findvideos', 'episodios']: # special items (add to videolibrary, download ecc.) + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item_url + ")") + busy(False) + return + try: self.channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel]) self.itemsResult = getattr(self.channel, item.action)(item) @@ -497,16 +612,17 @@ class SearchWindow(xbmcgui.WindowXML): if config.get_setting('checklinks') and not config.get_setting('autoplay'): self.itemsResult = servertools.check_list_links(self.itemsResult, config.get_setting('checklinks_number')) - self.servers = self.itemsResult + servers = self.itemsResult if self.itemsResult else [] self.itemsResult = [] uhd = [] fhd = [] hd = [] sd = [] unknown = [] - for i, item in enumerate(self.servers): + other = [] + for i, item in enumerate(servers): if item.server: - it = self.makeItem(item) + it = self.makeItem(item.tourl()) it.setProperty('index', str(i)) if item.quality in ['4k', '2160p', '2160', '4k2160p', '4k2160', '4k 2160p', '4k 2160', '2k']: it.setProperty('quality', 'uhd.png') @@ -525,7 +641,9 @@ class SearchWindow(xbmcgui.WindowXML): unknown.append(it) elif not item.action: self.getControl(QUALITYTAG).setText(item.fulltitle) - + else: + it = self.makeItem(item.tourl()) + other.append(it) uhd.sort(key=lambda it: it.getProperty('index')) fhd.sort(key=lambda it: it.getProperty('index')) @@ -533,34 +651,46 @@ class SearchWindow(xbmcgui.WindowXML): sd.sort(key=lambda it: it.getProperty('index')) unknown.sort(key=lambda it: it.getProperty('index')) - serverlist = uhd + fhd + hd + sd + unknown + serverlist = uhd + fhd + hd + sd + unknown + other + if not serverlist: + serverlist = [xbmcgui.ListItem(config.get_localized_string(60347))] + serverlist[0].setProperty('thumb', channelselector.get_thumb('nofolder.png')) self.Focus(SERVERS) self.SERVERLIST.reset() self.SERVERLIST.addItems(serverlist) self.setFocusId(SERVERLIST) + if config.get_setting('autoplay'): + busy(False) + self.playmonitor() + else: - self.episodes = self.itemsResult + episodes = self.itemsResult if self.itemsResult else [] self.itemsResult = [] - episodes = [] - for item in self.episodes: - if item.action == 'findvideos': - it = xbmcgui.ListItem(item.title) - episodes.append(it) + ep = [] + for item in episodes: + # if item.action == 'findvideos': + it = xbmcgui.ListItem(item.title) + it.setProperty('item', item.tourl()) + ep.append(it) + + if not ep: + ep = [xbmcgui.ListItem(config.get_localized_string(60347))] + ep[0].setProperty('thumb', channelselector.get_thumb('nofolder.png')) self.Focus(EPISODES) self.EPISODESLIST.reset() - self.EPISODESLIST.addItems(episodes) + self.EPISODESLIST.addItems(ep) self.setFocusId(EPISODESLIST) busy(False) elif control_id in [SERVERLIST]: - index = int(self.getControl(control_id).getSelectedItem().getProperty('index')) - server = self.servers[index] - server.player_mode = 0 - run(server) + server = Item().fromurl(self.getControl(control_id).getSelectedItem().getProperty('item')) + return self.playmonitor(server) + # server.globalsearch = True + # return run(server) def Back(self): self.getControl(QUALITYTAG).setText('') @@ -577,8 +707,7 @@ class SearchWindow(xbmcgui.WindowXML): self.Focus(SEARCH) self.setFocusId(RESULTS) self.RESULTS.selectItem(self.pos) - elif self.item.mode in ['person'] and self.find: - self.find = [] + elif self.item.mode in ['person']: self.actors() else: self.Close() @@ -592,30 +721,39 @@ class SearchWindow(xbmcgui.WindowXML): self.close() def context(self): - pos = self.RESULTS.getSelectedPosition() - name = self.CHANNELS.getSelectedItem().getLabel() - item = self.results[name][0][pos] - context = [config.get_localized_string(70739), config.get_localized_string(70557), config.get_localized_string(30155), config.get_localized_string(60359)] - context_commands = ["RunPlugin(%s?%s)" % (sys.argv[0], 'action=open_browser&url=' + item.url), - "RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=kodfavorites&action=addFavourite&from_channel=' + item.channel + '&from_action=' + item.action), - "RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=favorites&action=addFavourite&from_channel=' + item.channel + '&from_action=' + item.action), - "RunPlugin(%s?%s)" % (sys.argv[0], 'channel=trailertools&action=buscartrailer&contextual=True&search_title=' + item.contentTitle if item.contentTitle else item.fulltitle)] - if item.contentType == 'movie': - context += [config.get_localized_string(60353), config.get_localized_string(60354)] - context_commands += ["RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'action=add_pelicula_to_library&from_action=' + item.action), - "RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' +item.action)] - + focus = self.getFocusId() + if focus == EPISODESLIST: # context on episode + item_url = self.EPISODESLIST.getSelectedItem().getProperty('item') + parent = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item')) + elif focus == SERVERLIST: + item_url = self.SERVERLIST.getSelectedItem().getProperty('item') + parent = Item().fromurl(self.RESULTS.getSelectedItem().getProperty('item')) else: - context += [config.get_localized_string(60352), config.get_localized_string(60355), config.get_localized_string(60357)] - context_commands += ["RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'action=add_serie_to_library&from_action=' + item.action), - "RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' + item.action), - "RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=downloads&action=save_download&download=season&from_channel=' + item.channel +'&from_action=' + item.action)] - - if self.EPISODES.isVisible() or self.SERVERS.isVisible(): - pos = self.EPISODESLIST.getSelectedPosition() - item = self.episodes[pos] - context += [config.get_localized_string(60356)] - context_commands += ["RunPlugin(%s?%s&%s)" % (sys.argv[0], item.tourl(), 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' +item.action)] + item_url = self.RESULTS.getSelectedItem().getProperty('item') + parent = self.item + item = Item().fromurl(item_url) + parent.noMainMenu = True + commands = platformtools.set_context_commands(item, item_url, parent) + context = [c[0] for c in commands] + context_commands = [c[1].replace('Container.Refresh', 'RunPlugin').replace('Container.Update', 'RunPlugin') for c in commands] index = xbmcgui.Dialog().contextmenu(context) - if index > 0: xbmc.executebuiltin(context_commands[index]) \ No newline at end of file + if index > 0: xbmc.executebuiltin(context_commands[index]) + + + def playmonitor(self, server=None): + if server: + server.globalsearch = True + run(server) + try: + while not xbmc.Player().getTime() > 0: + xbmc.sleep(500) + self.close() + while xbmcgui.getCurrentWindowId() in [12005, 12006]: + xbmc.sleep(500) + if platformtools.is_playing(): + xbmc.sleep(300) + xbmc.executebuiltin('Action(Fullscreen)') + self.doModal() + except: + return diff --git a/specials/search.py b/specials/search.py index 1968dc9b..79bb6d07 100644 --- a/specials/search.py +++ b/specials/search.py @@ -38,11 +38,18 @@ def_lang = info_language[config.get_setting("info_language", "videolibrary")] def mainlist(item): logger.debug() - itemlist = [Item(channel=item.channel, title=config.get_localized_string(70276), action='new_search', mode='all', thumbnail=get_thumb("search.png")), - Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(30122), action='new_search', mode='movie', thumbnail=get_thumb("search_movie.png")), - Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(30123), action='new_search', mode='tvshow', thumbnail=get_thumb("search_tvshow.png")), - Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(70314), action='new_search', page=1, mode='person', thumbnail=get_thumb("search_star.png")), - Item(channel=item.channel, title=config.get_localized_string(59995), action='saved_search', thumbnail=get_thumb('search.png')), + if config.get_setting('new_search'): + itemlist = [Item(channel='globalsearch', title=config.get_localized_string(70276), action='Search', mode='all', thumbnail=get_thumb("search.png"), folder=False), + Item(channel='globalsearch', title=config.get_localized_string(70741) % config.get_localized_string(30122), action='Search', mode='movie', thumbnail=get_thumb("search_movie.png"),folder=False), + Item(channel='globalsearch', title=config.get_localized_string(70741) % config.get_localized_string(30123), action='Search', mode='tvshow', thumbnail=get_thumb("search_tvshow.png"), folder=False), + Item(channel='globalsearch', title=config.get_localized_string(70741) % config.get_localized_string(70314), action='Search', page=1, mode='person', thumbnail=get_thumb("search_star.png"), folder=False)] + else: + itemlist = [Item(channel=item.channel, title=config.get_localized_string(70276), action='new_search', mode='all', thumbnail=get_thumb("search.png")), + Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(30122), action='new_search', mode='movie', thumbnail=get_thumb("search_movie.png")), + Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(30123), action='new_search', mode='tvshow', thumbnail=get_thumb("search_tvshow.png")), + Item(channel=item.channel, title=config.get_localized_string(70741) % config.get_localized_string(70314), action='new_search', page=1, mode='person', thumbnail=get_thumb("search_star.png"))] + + itemlist += [Item(channel=item.channel, title=config.get_localized_string(59995), action='saved_search', thumbnail=get_thumb('search.png')), Item(channel=item.channel, title=config.get_localized_string(60420), action='sub_menu', thumbnail=get_thumb('search.png')), Item(channel="tvmoviedb", title=config.get_localized_string(70274), action="mainlist", thumbnail=get_thumb("search.png")), Item(channel=item.channel, title=typo(config.get_localized_string(59994), 'color kod bold'), action='setting_channel_new', thumbnail=get_thumb('setting_0.png')), @@ -79,10 +86,11 @@ def saved_search(item): for saved_search_text in saved_searches_list: itemlist.append( - Item(channel=item.channel, - action="new_search", + Item(channel=item.channel if not config.get_setting('new_search') else 'globalsearch', + action="new_search" if not config.get_setting('new_search') else 'Search', title=typo(saved_search_text.split('{}')[0], 'bold'), search_text=saved_search_text.split('{}')[0], + text=saved_search_text.split('{}')[0], mode='all', thumbnail=get_thumb('search.png'))) diff --git a/specials/setting.py b/specials/setting.py index 2de2882e..78755a20 100644 --- a/specials/setting.py +++ b/specials/setting.py @@ -241,6 +241,7 @@ def server_debrid_config(item): def servers_blacklist(item): server_list = servertools.get_servers_list() + black_list = config.get_setting("black_list", server='servers') blacklisted = [] list_controls = [] @@ -252,10 +253,10 @@ def servers_blacklist(item): control = server_parameters["name"] # control.setArt({'thumb:': server_parameters['thumb'] if 'thumb' in server_parameters else config.get_online_server_thumb(server)}) - if defaults.get("black_list", False) or config.get_setting("black_list", server=server): - blacklisted.append(i) - - list_controls.append(control) + if not config.get_setting("black_list", server=server): + list_controls.append(control) + if defaults.get("black_list", False) or server in black_list: + blacklisted.append(i) list_servers.append(server) ris = platformtools.dialog_multiselect(config.get_localized_string(60550), list_controls, preselect=blacklisted) if ris is not None: diff --git a/specials/videolibrary.py b/specials/videolibrary.py index b543b98e..d379f9dc 100644 --- a/specials/videolibrary.py +++ b/specials/videolibrary.py @@ -344,7 +344,7 @@ def get_episodes(item): head_nfo, epi = videolibrarytools.read_nfo(nfo_path) # Set the chapter title if possible - if epi.contentTitle: + if epi.contentTitle and epi.contentTitle != epi.fulltitle: title_episodie = epi.contentTitle.strip() else: title_episodie = config.get_localized_string(60031) % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2))