# -*- coding: utf-8 -*- import glob import os import re import time from threading import Thread from channelselector import get_thumb from core import channeltools from core import scrapertools from core.item import Item from platformcode import config, logger from platformcode import platformtools from core import tmdb link_list = [] max_links = 30 def mainlist(item): logger.info() item.channel = "search" itemlist = [] context = [{"title": config.get_localized_string(60412), "action": "setting_channel", "channel": item.channel}] itemlist.append(Item(channel=item.channel, action="sub_menu", title=config.get_localized_string(70305), context=context, thumbnail=get_thumb("search.png"))) itemlist.append(Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70306), type='movie', thumbnail=get_thumb("genres.png"))) itemlist.append (Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70307), context=context, search_type='list', list_type='movie/popular', thumbnail=get_thumb("popular.png"))) itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70308), context=context, search_type='list', list_type='movie/top_rated', thumbnail=get_thumb("top_rated.png"))) itemlist.append( Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70309), context=context, search_type='list', list_type='movie/now_playing', thumbnail=get_thumb("now_playing.png"))) itemlist.append(Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70310), type='tv', thumbnail=get_thumb("genres.png"))) itemlist.append( Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70311), context=context, search_type='list',list_type='tv/popular', thumbnail=get_thumb("popular.png"))) itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70312), context=context, search_type='list', list_type='tv/on_the_air', thumbnail=get_thumb("on_the_air.png"))) itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70313), context=context, search_type='list', list_type='tv/top_rated', thumbnail=get_thumb("top_rated.png"))) return itemlist def genres_menu(item): itemlist = [] genres = tmdb.get_genres(item.type) logger.debug(genres) logger.debug(genres[item.type]) for key, value in genres[item.type].items(): itemlist.append(item.clone(title=value, action='discover_list', search_type='discover', list_type=key, page='1')) return sorted(itemlist, key=lambda it: it.title) def sub_menu(item): logger.info() item.channel = "search" itemlist = list() context = [{"title": config.get_localized_string(70273), "action": "setting_channel", "channel": item.channel}] itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(30980), context=context, thumbnail=get_thumb("search.png"))) thumbnail = get_thumb("search_star.png") itemlist.append(Item(channel='tvmoviedb', title=config.get_localized_string(70036), action="search_", search={'url': 'search/person', 'language': 'es', 'page': 1}, star=True, thumbnail=thumbnail)) itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(59998), extra="categorias", context=context, thumbnail=get_thumb("search.png"))) itemlist.append(Item(channel=item.channel, action="opciones", title=config.get_localized_string(59997), thumbnail=get_thumb("search.png"))) itemlist.append(Item(channel="tvmoviedb", action="mainlist", title=config.get_localized_string(70274), thumbnail=get_thumb("search.png"))) saved_searches_list = get_saved_searches() context2 = context[:] context2.append({"title": config.get_localized_string(59996), "action": "clear_saved_searches", "channel": item.channel}) logger.info("saved_searches_list=%s" % saved_searches_list) if saved_searches_list: itemlist.append(Item(channel=item.channel, action="", title=config.get_localized_string(59995), context=context2, thumbnail=get_thumb("search.png"))) for saved_search_text in saved_searches_list: itemlist.append(Item(channel=item.channel, action="do_search", title=' "' + saved_search_text + '"', extra=saved_search_text, context=context2, category=saved_search_text, thumbnail=get_thumb("search.png"))) return itemlist def opciones(item): itemlist = list() itemlist.append(Item(channel=item.channel, action="setting_channel", title=config.get_localized_string(59994), folder=False, thumbnail=get_thumb("search.png"))) itemlist.append(Item(channel=item.channel, action="clear_saved_searches", title=config.get_localized_string(59996), folder=False, thumbnail=get_thumb("search.png"))) itemlist.append(Item(channel=item.channel, action="settings", title=config.get_localized_string(60531), folder=False, thumbnail=get_thumb("search.png"))) return itemlist def settings(item): return platformtools.show_channel_settings(caption=config.get_localized_string(59993)) def setting_channel(item): channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json') channel_language = config.get_setting("channel_language", default="all") list_controls = [] for infile in sorted(glob.glob(channels_path)): channel_name = os.path.basename(infile)[:-5] channel_parameters = channeltools.get_channel_parameters(channel_name) # No incluir si es un canal inactivo if not channel_parameters["active"]: continue # No incluir si es un canal para adultos, y el modo adulto está desactivado if channel_parameters["adult"] and config.get_setting("adult_mode") == 0: continue # No incluir si el canal es en un idioma filtrado if channel_language != "all" and channel_language not in channel_parameters["language"] \ and "*" not in channel_parameters["language"]: continue # No incluir si en la configuracion del canal no existe "include_in_global_search" include_in_global_search = channel_parameters["include_in_global_search"] if not include_in_global_search: continue else: # Se busca en la configuración del canal el valor guardado include_in_global_search = config.get_setting("include_in_global_search", channel_name) control = {'id': channel_name, 'type': "bool", 'label': channel_parameters["title"], 'default': include_in_global_search, 'enabled': True, 'visible': True} list_controls.append(control) if config.get_setting("custom_button_value", item.channel): custom_button_label = config.get_localized_string(59992) else: custom_button_label = config.get_localized_string(59991) return platformtools.show_channel_settings(list_controls=list_controls, caption=config.get_localized_string(59990), callback="save_settings", item=item, custom_button={'visible': True, 'function': "cb_custom_button", 'close': False, 'label': custom_button_label}) def save_settings(item, dict_values): progreso = platformtools.dialog_progress(config.get_localized_string(59988), config.get_localized_string(59989)) n = len(dict_values) for i, v in enumerate(dict_values): progreso.update((i * 100) / n, config.get_localized_string(59988)) config.set_setting("include_in_global_search", dict_values[v], v) progreso.close() def cb_custom_button(item, dict_values): value = config.get_setting("custom_button_value", item.channel) if value == "": value = False for v in dict_values.keys(): dict_values[v] = not value if config.set_setting("custom_button_value", not value, item.channel) == True: return {"label": config.get_localized_string(59992)} else: return {"label": config.get_localized_string(59991)} def searchbycat(item): # Only in xbmc/kodi # Abre un cuadro de dialogo con las categorías en las que hacer la búsqueda categories = [config.get_localized_string(30122), config.get_localized_string(30123), config.get_localized_string(30124), config.get_localized_string(30125), config.get_localized_string(59975), config.get_localized_string(59976)] categories_id = ["movie", "tvshow", "anime", "documentary", "vos", "latino"] list_controls = [] for i, category in enumerate(categories): control = {'id': categories_id[i], 'type': "bool", 'label': category, 'default': False, 'enabled': True, 'visible': True} list_controls.append(control) control = {'id': "separador", 'type': "label", 'label': '', 'default': "", 'enabled': True, 'visible': True} list_controls.append(control) control = {'id': "torrent", 'type': "bool", 'label': config.get_localized_string(70275), 'default': True, 'enabled': True, 'visible': True} list_controls.append(control) return platformtools.show_channel_settings(list_controls=list_controls, caption=config.get_localized_string(59974), callback="search_cb", item=item) def search_cb(item, values=""): cat = [] for c in values: if values[c]: cat.append(c) if not len(cat): return None else: logger.info(item.tostring()) logger.info(str(cat)) return do_search(item, cat) # Al llamar a esta función, el sistema pedirá primero el texto a buscar # y lo pasará en el parámetro "tecleado" def search(item, tecleado): logger.info() tecleado = tecleado.replace("+", " ") item.category = tecleado if tecleado != "": save_search(tecleado) if item.extra == "categorias": item.extra = tecleado itemlist = searchbycat(item) else: item.extra = tecleado itemlist = do_search(item, []) return itemlist def show_result(item): tecleado = None if item.adult and config.get_setting("adult_request_password"): # Solicitar contraseña tecleado = platformtools.dialog_input("", config.get_localized_string(60334), True) if tecleado is None or tecleado != config.get_setting("adult_password"): return [] item.channel = item.__dict__.pop('from_channel') item.action = item.__dict__.pop('from_action') if item.__dict__.has_key('tecleado'): tecleado = item.__dict__.pop('tecleado') try: channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel]) except: import traceback logger.error(traceback.format_exc()) return [] if tecleado: # Mostrar resultados: agrupados por canales return channel.search(item, tecleado) else: # Mostrar resultados: todos juntos try: from platformcode import launcher launcher.run(item) except ImportError: return getattr(channel, item.action)(item) def channel_search(search_results, channel_parameters, tecleado): try: exec "from channels import " + channel_parameters["channel"] + " as module" mainlist = module.mainlist(Item(channel=channel_parameters["channel"])) search_items = [item for item in mainlist if item.action == "search"] if not search_items: search_items = [Item(channel=channel_parameters["channel"], action="search")] for item in search_items: result = module.search(item.clone(), tecleado) if result is None: result = [] if len(result): if not channel_parameters["title"].capitalize() in search_results: search_results[channel_parameters["title"].capitalize()] = [] search_results[channel_parameters["title"].capitalize()].append({"item": item, "itemlist": result, "adult": channel_parameters["adult"]}) except: logger.error("No se puede buscar en: %s" % channel_parameters["title"]) import traceback logger.error(traceback.format_exc()) # Esta es la función que realmente realiza la búsqueda def do_search(item, categories=None): logger.info("blaa categorias %s" % categories) if item.contextual==True: categories = ["Películas"] setting_item = Item(channel=item.channel, title=config.get_localized_string(59994), folder=False, thumbnail=get_thumb("search.png")) setting_channel(setting_item) if categories is None: categories = [] multithread = config.get_setting("multithread", "search") result_mode = config.get_setting("result_mode", "search") if item.wanted!='': tecleado=item.wanted else: tecleado = item.extra itemlist = [] channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json') logger.info("channels_path=%s" % channels_path) channel_language = config.get_setting("channel_language", default="all") logger.info("channel_language=%s" % channel_language) # Para Kodi es necesario esperar antes de cargar el progreso, de lo contrario # el cuadro de progreso queda "detras" del cuadro "cargando..." y no se le puede dar a cancelar time.sleep(0.5) progreso = platformtools.dialog_progress(config.get_localized_string(30993) % tecleado, "") channel_files = sorted(glob.glob(channels_path), key=lambda x: os.path.basename(x)) import math # fix float porque la division se hace mal en python 2.x number_of_channels = float(100) / len(channel_files) threads = [] search_results = {} start_time = time.time() for index, infile in enumerate(channel_files): try: percentage = int(math.ceil((index + 1) * number_of_channels)) basename = os.path.basename(infile) basename_without_extension = basename[:-5] logger.info("%s..." % basename_without_extension) channel_parameters = channeltools.get_channel_parameters(basename_without_extension) # No busca si es un canal inactivo if not channel_parameters["active"]: logger.info("%s -no activo-" % basename_without_extension) continue # En caso de búsqueda por categorias if categories: # Si no se ha seleccionado torrent no se muestra if "torrent" not in categories: if "torrent" in channel_parameters["categories"]: logger.info("%s -torrent-" % basename_without_extension) continue for cat in categories: if cat not in channel_parameters["categories"]: logger.info("%s -no en %s-" % (basename_without_extension, cat)) continue # No busca si es un canal para adultos, y el modo adulto está desactivado if channel_parameters["adult"] and config.get_setting("adult_mode") == 0: logger.info("%s -adulto-" % basename_without_extension) continue # No busca si el canal es en un idioma filtrado if channel_language != "all" and channel_language not in channel_parameters["language"] \ and "*" not in channel_parameters["language"]: logger.info("%s -idioma no válido-" % basename_without_extension) continue # No busca si es un canal excluido de la búsqueda global include_in_global_search = channel_parameters["include_in_global_search"] if include_in_global_search: # Buscar en la configuracion del canal include_in_global_search = config.get_setting("include_in_global_search", basename_without_extension) if not include_in_global_search: logger.info("%s -no incluido en lista a buscar-" % basename_without_extension) continue if progreso.iscanceled(): progreso.close() logger.info("Búsqueda cancelada") return itemlist # Modo Multi Thread if multithread: t = Thread(target=channel_search, args=[search_results, channel_parameters, tecleado], name=channel_parameters["title"]) t.setDaemon(True) t.start() threads.append(t) # Modo single Thread else: logger.info("Intentado búsqueda en %s de %s " % (basename_without_extension, tecleado)) channel_search(search_results, channel_parameters, tecleado) logger.info("%s incluido en la búsqueda" % basename_without_extension) progreso.update(percentage, config.get_localized_string(60520) % channel_parameters["title"]) except: logger.error("No se puede buscar en: %s" % channel_parameters["title"]) import traceback logger.error(traceback.format_exc()) continue # Modo Multi Thread # Usando isAlive() no es necesario try-except, # ya que esta funcion (a diferencia de is_alive()) # es compatible tanto con versiones antiguas de python como nuevas if multithread: pendent = [a for a in threads if a.isAlive()] t = float(100) / len(pendent) while pendent: index = (len(threads) - len(pendent)) + 1 percentage = int(math.ceil(index * t)) list_pendent_names = [a.getName() for a in pendent] mensaje = config.get_localized_string(70282) % (", ".join(list_pendent_names)) progreso.update(percentage, config.get_localized_string(60521) % (len(threads) - len(pendent), len(threads)), mensaje) logger.debug(mensaje) if progreso.iscanceled(): logger.info("Búsqueda cancelada") break time.sleep(0.5) pendent = [a for a in threads if a.isAlive()] total = 0 for channel in sorted(search_results.keys()): for element in search_results[channel]: total += len(element["itemlist"]) title = channel # resultados agrupados por canales if item.contextual == True or item.action == 'search_tmdb': result_mode = 1 if result_mode == 0: if len(search_results[channel]) > 1: title += " -%s" % element["item"].title.strip() title += " (%s)" % len(element["itemlist"]) title = re.sub("\[COLOR [^\]]+\]", "", title) title = re.sub("\[/COLOR]", "", title) itemlist.append(Item(title=title, channel="search", action="show_result", url=element["item"].url, extra=element["item"].extra, folder=True, adult=element["adult"], from_action="search", from_channel=element["item"].channel, tecleado=tecleado)) # todos los resultados juntos, en la misma lista else: title = " [ Resultados del canal %s ] " % channel itemlist.append(Item(title=title, channel="search", action="", folder=False, text_bold=True, from_channel=channel)) for i in element["itemlist"]: if i.action: title = " " + i.title itemlist.append(i.clone(title=title, from_action=i.action, from_channel=i.channel, channel="search", action="show_result", adult=element["adult"])) title = config.get_localized_string(59972) % ( tecleado, total, time.time() - start_time) itemlist.insert(0, Item(title=title, text_color='yellow')) progreso.close() #Para opcion Buscar en otros canales if item.contextual == True: return exact_results(itemlist, tecleado) else: return itemlist def exact_results(results, wanted): logger.info() itemlist =[] for item in results: if item.action=='': channel=item.from_channel if item.action != '' and item.contentTitle==wanted: item.title = '%s [%s]' % (item.title, channel) itemlist.append(item) return itemlist def save_search(text): saved_searches_limit = int((10, 20, 30, 40,)[int(config.get_setting("saved_searches_limit", "search"))]) current_saved_searches_list = config.get_setting("saved_searches_list", "search") if current_saved_searches_list is None: saved_searches_list = [] else: saved_searches_list = list(current_saved_searches_list) if text in saved_searches_list: saved_searches_list.remove(text) saved_searches_list.insert(0, text) config.set_setting("saved_searches_list", saved_searches_list[:saved_searches_limit], "search") def clear_saved_searches(item): config.set_setting("saved_searches_list", list(), "search") platformtools.dialog_ok(config.get_localized_string(60329), config.get_localized_string(60424)) def get_saved_searches(): current_saved_searches_list = config.get_setting("saved_searches_list", "search") if current_saved_searches_list is None: saved_searches_list = [] else: saved_searches_list = list(current_saved_searches_list) return saved_searches_list def discover_list(item): from platformcode import unify itemlist = [] result = tmdb.discovery(item) tvshow = False logger.debug(item) for elem in result: elem['tmdb_id']=elem['id'] if 'title' in elem: title = unify.normalize(elem['title']).capitalize() elem['year'] = scrapertools.find_single_match(elem['release_date'], '(\d{4})-\d+-\d+') else: title = unify.normalize(elem['name']).capitalize() tvshow = True new_item = Item(channel='search', title=title, infoLabels=elem, action='search_tmdb', extra=title, category='Resultados', context ='') if tvshow: new_item.contentSerieName = title else: new_item.contentTitle = title itemlist.append(new_item) tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) if item.page != '' and len(itemlist)>0: next_page = str(int(item.page)+1) #if not 'similar' in item.list_type: # itemlist.append(item.clone(title='Pagina Siguente', page=next_page)) #else: itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70065), search_type=item.search_type, list_type=item.list_type, type=item.type, page=next_page)) return itemlist def search_tmdb(item): logger.debug(item) itemlist = [] threads = [] logger.debug(item) wanted = item.contentTitle search = do_search(item) if item.contentSerieName == '': results = exact_results(search, wanted) for result in results: logger.debug(result) t = Thread(target=get_links, args=[result]) t.start() threads.append(t) for thread in threads: thread.join() # try: # get_links(result) # except: # pass for link in link_list: if link.action == 'play' and not 'trailer' in link.title.lower() and len(itemlist) < max_links: itemlist.append(link) return sorted(itemlist, key=lambda it: it.server) else: for item in search: if item.contentSerieName != '' and item.contentSerieName == wanted: logger.debug(item) itemlist.append(item) return itemlist def get_links (item): logger.info() results =[] channel = __import__('channels.%s' % item.from_channel, None, None, ["channels.%s" % item.from_channel]) if len(link_list) <= max_links: link_list.extend(getattr(channel, item.from_action)(item))