def rmdirtree(path): """ Elimina un directorio y su contenido @param path: ruta a eliminar @type path: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) try: if path.lower().startswith("smb://"): for raiz, subcarpetas, ficheros in samba.walk(path, topdown=False): for f in ficheros: samba.remove(join(decode(raiz),decode(f))) for s in subcarpetas: samba.rmdir(join(decode(raiz),decode(s))) samba.rmdir(path) else: import shutil shutil.rmtree(path, ignore_errors=True) except: logger.error("ERROR al eliminar el directorio: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Error al eliminar el directorio", path) return False else: return not exists(path)
def rmdir(path): """ Elimina un directorio @param path: ruta a eliminar @type path: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) if path.lower().startswith("smb://"): try: samba.delete_directory(os.path.basename(path), os.path.dirname(path)) except: import traceback logger.info("pelisalacarta.core.filetools mkdir: Error al eliminar el directorio " + traceback.format_exc()) platformtools.dialog_notification("Error al eliminar el directorio", path) return False else: try: os.rmdir(path) except OSError: import traceback logger.info("pelisalacarta.core.filetools mkdir: Error al eliminar el directorio " + traceback.format_exc()) platformtools.dialog_notification("Error al eliminar el directorio", path) return False return True
def eliminar(item): def eliminar_todo(item): filetools.rmdirtree(item.path) if config.is_xbmc(): import xbmc # esperamos 3 segundos para dar tiempo a borrar los ficheros xbmc.sleep(3000) # TODO mirar por qué no funciona al limpiar en la biblioteca de Kodi al añadirle un path # limpiamos la biblioteca de Kodi library.clean() logger.info("Eliminados todos los enlaces") platformtools.itemlist_refresh() logger.info(item.contentTitle) #logger.debug(item.tostring('\n')) if item.contentType == 'movie': heading = "Eliminar película" else: heading = "Eliminar serie" if item.multicanal: # Obtener listado de canales opciones = ["Eliminar solo los enlaces de %s" % k.capitalize() for k in item.library_urls.keys() if k !="descargas"] opciones.insert(0, heading) index = platformtools.dialog_select(config.get_localized_string(30163), opciones) if index == 0: # Seleccionado Eliminar pelicula/serie eliminar_todo(item) elif index > 0: # Seleccionado Eliminar canal X canal = opciones[index].replace("Eliminar solo los enlaces de ", "").lower() num_enlaces= 0 for fd in filetools.listdir(item.path): if fd.endswith(canal + '].json'): if filetools.remove(filetools.join(item.path, fd)): num_enlaces += 1 if num_enlaces > 0: # Actualizar .nfo head_nfo, item_nfo = library.read_nfo(item.nfo) del item_nfo.library_urls[canal] filetools.write(item.nfo, head_nfo + item_nfo.tojson()) msg_txt = "Eliminados %s enlaces del canal %s" % (num_enlaces, canal) logger.info(msg_txt) platformtools.dialog_notification(heading, msg_txt) platformtools.itemlist_refresh() else: if platformtools.dialog_yesno(heading, "¿Realmente desea eliminar '%s' de su biblioteca?" % item.infoLabels['title']): eliminar_todo(item)
def rename(path, new_name): """ Renombra un archivo o carpeta @param path: ruta del fichero o carpeta a renombrar @type path: str @param new_name: nuevo nombre @type new_name: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) try: if path.lower().startswith("smb://"): new_name = encode(new_name, True) samba.rename(path, join(dirname(path), new_name)) else: new_name = encode(new_name, False) os.rename(path, os.path.join(os.path.dirname(path), new_name)) except: logger.error("ERROR al renombrar el archivo: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Error al renombrar", path) return False else: return True
def rename(path, new_name): """ Renombra un archivo o carpeta @param path: ruta del fichero o carpeta a renombrar @type path: str @param new_name: nuevo nombre @type new_name: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) if path.lower().startswith("smb://"): new_name = encode(new_name, True) try: samba.rename(os.path.basename(path), new_name, os.path.dirname(path)) except: import traceback logger.info( "pelisalacarta.core.filetools mkdir: Error al renombrar el archivo o carpeta" + traceback.format_exc()) platformtools.dialog_notification("Error al renombrar", path) return False else: new_name = encode(new_name, False) try: os.rename(path, os.path.join(os.path.dirname(path), new_name)) except OSError: import traceback logger.info( "pelisalacarta.core.filetools mkdir: Error al renombrar el archivo o carpeta" + traceback.format_exc()) platformtools.dialog_notification("Error al renombrar", path) return False return True
def borrar_filtro(item): logger.info() if item: # OBTENEMOS LOS DATOS DEL JSON dict_series = get_tvshows(item.from_channel) tvshow = item.show.strip().lower() heading = "¿Está seguro que desea eliminar el filtro?" line1 = "Pulse 'Si' para eliminar el filtro de [COLOR blue]{0}[/COLOR], pulse 'No' o cierre la ventana para " \ "no hacer nada.".format(item.show.strip()) if platformtools.dialog_yesno(heading, line1) == 1: lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, "") dict_series.pop(tvshow, None) fname, json_data = update_json_data(dict_series, item.from_channel) result = filetools.write(fname, json_data) if result: message = "FILTRO ELIMINADO" else: message = "Error al guardar en disco" heading = "{0} [{1}]".format(item.show.strip(), lang_selected) platformtools.dialog_notification(heading, message)
def acciones_playlist(item): logger.info("pelisalacarta.channels.documaniatv acciones_playlist") itemlist = [] if item.title == "Crear una nueva playlist y añadir el documental": from platformcode import platformtools texto = platformtools.dialog_input(heading="Introduce el título de la nueva playlist") if texto is not None: post= "p=playlists&do=create-playlist&title=%s&visibility=1&video-id=%s&ui=video-watch" % (texto, item.id) data = scrapertools.cachePage(item.url, headers=headers, post=post) else: return elif item.title != "Me gusta": if "Eliminar" in item.title: action = "remove-from-playlist" else: action = "add-to-playlist" post = "p=playlists&do=%s&playlist-id=%s&video-id=%s" % (action, item.list_id, item.id) data = scrapertools.cachePage(item.url, headers=headers, post=post) else: item.url = "http://www.documaniatv.com/ajax.php?vid=%s&p=video&do=like" % item.id data = scrapertools.cachePage(item.url, headers=headers) try: import xbmc from platformcode import platformtools platformtools.dialog_notification(item.title, "Se ha añadido/eliminado correctamente") xbmc.executebuiltin("Container.Refresh") except: itemlist.append(item.clone(action="", title="Se ha añadido/eliminado correctamente")) return itemlist
def onClick(self, control): if control == 10003: self.result = None self.close() elif control == 10004: self.result = {} self.close() elif control == 10002: self.result = [int(k) for k in range(9) if self.result.get(k, False) == True] post = "c=%s" % self.token for r in self.result: post += "&response=%s" % r data = httptools.downloadpage(self.url, post, headers=self.headers).data self.result = scrapertools.find_single_match(data, '<div class="fbc-verification-token">.*?>([^<]+)<') if self.result: platformtools.dialog_notification("Captcha corretto", "Verifica terminata") self.close() else: self.result = {} self.close() else: self.result[control - 10005] = not self.result.get(control - 10005, False)
def write_data(channel, show, data): # OBTENEMOS LOS DATOS DEL JSON dict_series = get_tvshows(channel) tvshow = show.strip() list_season_episode = dict_series.get(tvshow, {}).get(TAG_SEASON_EPISODE, []) logger.debug("data {0}".format(list_season_episode)) if data: # cambiamos el orden para que se vea en orden descendente y usarse bien en el _data.json data.sort(key=lambda el: int(el[0]), reverse=True) dict_renumerate = {TAG_SEASON_EPISODE: data} dict_series[tvshow] = dict_renumerate else: # hemos borrado todos los elementos, por lo que se borra la serie del fichero del dict_series[tvshow] fname, json_data = update_json_data(dict_series, channel) result = filetools.write(fname, json_data) if result: if data: message = "FILTRO GUARDADO" else: message = "FILTRO BORRADO" else: message = "Error al guardar en disco" heading = show.strip() platformtools.dialog_notification(heading, message)
def mkdir(path): """ Crea un directorio @param path: ruta a crear @type path: str @rtype: bool @return: devuelve False en caso de error """ logger.info("pelisalacarta.core.filetools mkdir " + path) path = encode(path) if path.lower().startswith("smb://"): try: samba.create_directory(os.path.basename(path), os.path.dirname(path)) except gaierror: import traceback logger.info("pelisalacarta.core.filetools mkdir: Error al crear la ruta " + traceback.format_exc()) platformtools.dialog_notification("Error al crear la ruta", path) return False else: try: # path = normalize(path, respect) os.mkdir(path) except OSError: import traceback logger.info("pelisalacarta.core.filetools mkdir: Error al crear la ruta " + traceback.format_exc()) platformtools.dialog_notification("Error al crear la ruta", path) return False return True
def channel_status(item, dict_values): try: for v in dict_values: if v == "all_channels": import channelselector from core import channeltools logger.info("Todos los canales | Estado seleccionado: %s" % str(dict_values[v]).lower()) if str(dict_values[v]) != "0": channel_list = channelselector.filterchannels("allchannelstatus") excluded_channels = ['tengourl', 'buscador', 'libreria', 'configuracion', 'novedades', 'personal', 'ayuda', 'descargas'] for channel in channel_list: if channel.channel not in excluded_channels: channel_parameters = channeltools.get_channel_parameters(channel.channel) new_status_all_default = None new_status_all = None new_status_all_default = channel_parameters["active"] # Opcion Activar todos if str(dict_values[v]) == "1": new_status_all = "true" # Opcion Desactivar todos if str(dict_values[v]) == "2": new_status_all = "false" # Opcion Recuperar estado por defecto if str(dict_values[v]) == "3": # Si tiene "enabled" en el json es porque el estado no es el del xml if config.get_setting("enabled", channel.channel): new_status_all = new_status_all_default # Si el canal no tiene "enabled" en el json no se guarda, se pasa al siguiente else: continue # Se guarda el estado del canal if new_status_all is not None: config.set_setting("enabled", new_status_all, channel.channel) break else: continue else: logger.info("Canal: %s | Estado: %s" % (v, str(dict_values[v]).lower())) config.set_setting("enabled", str(dict_values[v]).lower(), v) platformtools.itemlist_update(Item(channel=CHANNELNAME, action="mainlist")) except: import traceback logger.info("Detalle del error: %s" % traceback.format_exc()) platformtools.dialog_notification("Error", "Se ha producido un error al guardar")
def seguir(item): logger.info() data = httptools.downloadpage(item.url, item.post) message = "Colección seguida" if "Dejar" in item.title: message = "La colección ya no se sigue" if data.sucess and config.get_platform() != "plex": from platformcode import platformtools platformtools.dialog_notification("Acción correcta", message)
def update_from_conf(): """ Se trata de una funcion que tiene como objetivo evitar el loop infinito al hacer la llamada desde ayuda.py """ if platformtools.dialog_yesno("pelisalacarta", "Seguro que desea actualizar los enlaces y la biblioteca?") == 1: main() platformtools.dialog_ok("pelisalacarta", "Proceso completado") # TODO: Mejorarlo else: platformtools.dialog_notification("Plugin", "Proceso abortado")
def move(path, dest): """ Mueve un archivo @param path: ruta del fichero a mover @type path: str @param dest: ruta donde mover @type dest: str @rtype: bool @return: devuelve False en caso de error """ # samba/samba if path.lower().startswith("smb://") and dest.lower().startswith("smb://"): try: dest = encode(dest, True) path = encode(path, True) # Calculamos la ruta de destino relativa a la ruta de origen tipo "../../Carpeta/archivo.mp4" new_file = "/".join( os.path.relpath(os.path.dirname(dest), os.path.dirname(path)).split(os.sep) + [os.path.basename(dest)] ) samba.rename(os.path.basename(path), new_file, os.path.dirname(path)) return True except: import traceback logger.info("pelisalacarta.core.filetools mkdir: Error al mover el archivo" + traceback.format_exc()) platformtools.dialog_notification("Error al mover", path) return False # local/local elif not path.lower().startswith("smb://") and not dest.lower().startswith("smb://"): dest = encode(dest) path = encode(path) try: os.rename(path, dest) return True except OSError: import traceback logger.info("pelisalacarta.core.filetools move: Error al mover el archivo" + traceback.format_exc()) platformtools.dialog_notification("Error al mover", path) return False # mixto En este caso se copia el archivo y luego se elimina el de origen else: if copy(path, dest) == True and remove(path) == True: return True else: return False
def save_filter(item): """ salva el filtro a través del menú contextual :param item: item :type item: item """ logger.info("[filtertools.py] save_filter") dict_series = get_filtered_tvshows(item.from_channel) name = item.show.lower().strip() logger.info("[filtertools.py] config_filter name {0}".format(name)) open_tag_idioma = (0, item.title.find("[")+1)[item.title.find("[") >= 0] close_tag_idioma = (0, item.title.find("]"))[item.title.find("]") >= 0] idioma = item.title[open_tag_idioma: close_tag_idioma] open_tag_calidad = (0, item.title.find("[", item.title.find("[") + 1)+1)[item.title.find("[", item.title.find("[") + 1) >= 0] close_tag_calidad = (0, item.title.find("]", item.title.find("]") + 1))[item.title.find("]", item.title.find("]") + 1) >= 0] calidad_no_permitida = "" # item.title[open_tag_calidad: close_tag_calidad] # filter_idioma = "" # logger.info("idioma {0}".format(idioma)) # if idioma != "": # filter_idioma = [key for key, value in dict_idiomas.iteritems() if value == idioma][0] list_calidad = list() dict_filter = {TAG_NAME: item.show, TAG_ACTIVE: True, TAG_LANGUAGE: idioma, TAG_QUALITY_NOT_ALLOWED: list_calidad} dict_series[name] = dict_filter # filter_list = item.extra.split("##") # dict_series = eval(filter_list[0]) # dict_filter = eval(filter_list[2]) # dict_series[filter_list[1].strip().lower()] = dict_filter # logger.info("categoria {0}".format(item.from_channel)) fname, json_data = update_json_data(dict_series, item.from_channel) result = filetools.write(fname, json_data) if result: message = "FILTRO GUARDADO" else: message = "Error al guardar en disco" heading = "{0} [1]".format(item.show.strip(), idioma) platformtools.dialog_notification(heading, message)
def sync_trakt(silent=True): # Para que la sincronizacion no sea silenciosa vale con silent=False if xbmc.getCondVisibility('System.HasAddon("script.trakt")'): notificacion = True if (not config.get_setting("sync_trakt_notification", "biblioteca") and platformtools.is_playing()): notificacion = False xbmc.executebuiltin('RunScript(script.trakt,action=sync,silent=%s)' % silent) logger.info("Sincronizacion con Trakt iniciada") if notificacion: platformtools.dialog_notification("streamondemand", "Sincronizzazione con trakt iniziata", icon=0, time=2000)
def del_filter(item): """ elimina el filtro a través del menú contextual :param item: item :type item: item """ logger.info("[filtertools.py] del_filter") dict_series = get_filtered_tvshows(item.from_channel) dict_series.pop(library.title_to_filename(item.show.lower().strip()), None) fname, json_data = update_json_data(dict_series, item.from_channel) message = save_file(json_data, fname, "FILTRO Borrado") heading = "{0}".format(item.show.strip()) platformtools.dialog_notification(heading, message)
def guardar_valores(item, dict_data_saved): """ Guarda los valores configurados en la ventana :param item: item :type item: Item :param dict_data_saved: diccionario con los datos salvados :type dict_data_saved: dict """ logger.info() # Aqui tienes q gestionar los datos obtenidos del cuadro de dialogo if item and dict_data_saved: logger.debug('item: {0}\ndatos: {1}'.format(item.tostring(), dict_data_saved)) # OBTENEMOS LOS DATOS DEL JSON if item.from_channel == "biblioteca": item.from_channel = item.contentChannel dict_series = get_tvshows(item.from_channel) tvshow = item.show.strip().lower() logger.info("Se actualiza los datos") list_quality = [] for _id, value in dict_data_saved.items(): if _id in item.list_calidad and value: list_quality.append(_id.lower()) lang_selected = item.list_idiomas[dict_data_saved[TAG_LANGUAGE]] dict_filter = {TAG_NAME: item.show, TAG_ACTIVE: dict_data_saved.get(TAG_ACTIVE, True), TAG_LANGUAGE: lang_selected, TAG_QUALITY_NOT_ALLOWED: list_quality} dict_series[tvshow] = dict_filter fname, json_data = update_json_data(dict_series, item.from_channel) result = filetools.write(fname, json_data) if result: message = "FILTRO GUARDADO" else: message = "Error al guardar en disco" heading = "{0} [{1}]".format(item.show.strip(), lang_selected) platformtools.dialog_notification(heading, message) if config.get_platform() == "mediaserver": platformtools.itemlist_refresh()
def path_exists(path): """ comprueba si la ruta existe, samba necesita la raíz para conectar y la carpeta @type path: str @param path: la ruta del fichero @rtype: str @return: devuelve si existe la ruta. """ if not samba.usingsamba(path): return os.path.exists(path) else: try: path_samba, folder_samba = path.rsplit('/', 1) return samba.folder_exists(folder_samba, path_samba) except gaierror: logger.info("pelisalacarta.platformcode.library path_exists: No es posible conectar con la ruta") platformtools.dialog_notification("No es posible conectar con la ruta", path) return True
def exists(path): """ Comprueba si existe una carpeta o fichero @param path: ruta @type path: str @rtype: bool @return: Retorna True si la ruta existe, tanto si es una carpeta como un archivo """ path = encode(path) if path.lower().startswith("smb://"): try: return samba.file_exists(os.path.basename(path), os.path.dirname(path)) or \ samba.folder_exists(os.path.basename(path), os.path.dirname(path)) except gaierror: logger.info("pelisalacarta.core.filetools exists: No es posible conectar con la ruta") platformtools.dialog_notification("No es posible conectar con la ruta", path) return True else: return os.path.exists(path)
def open_for_reading(path): """ Abre un archivo para leerlo @param path: ruta @type path: str @rtype: str @return: datos del fichero """ path = encode(path) try: if path.lower().startswith("smb://"): return samba.get_file_handle_for_reading(os.path.basename(path), os.path.dirname(path)) else: return open(path, "rb") except: import traceback logger.info("pelisalacarta.core.open_for_reading mkdir: Error al abrir el archivo " + traceback.format_exc()) platformtools.dialog_notification("Error al abrir", path) return False
def file_open(path, mode="r"): """ Abre un archivo @param path: ruta @type path: str @rtype: str @return: objeto file """ path = encode(path) try: if path.lower().startswith("smb://"): return samba.smb_open(path, mode) else: return open(path, mode) except: logger.error("ERROR al abrir el archivo: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Error al abrir", path) return False
def borrar_filtro(item): logger.info("[filtertools.py] borrar_filtro") if item: # OBTENEMOS LOS DATOS DEL JSON dict_series = get_filtered_tvshows(item.from_channel) tvshow = library.title_to_filename(item.show.strip().lower()) heading = "¿Está seguro que desea eliminar el filtro?" line1 = "Pulse 'Si' para eliminar el filtro de [COLOR blue]{0}[/COLOR], pulse 'No' o cierre la ventana para " \ "no hacer nada.".format(item.show.strip()) if platformtools.dialog_yesno(heading, line1) == 1: lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, "") dict_series.pop(tvshow, None) message = "FILTRO ELIMINADO" fname, json_data = update_json_data(dict_series, item.from_channel) message = save_file(json_data, fname, message) heading = "{0} [{1}]".format(item.show.strip(), lang_selected) platformtools.dialog_notification(heading, message)
def borrar(channel, show): logger.info() heading = "¿Está seguro que desea eliminar renumeración?" line1 = "Pulse 'Si' para eliminar la renumeración de [COLOR blue]{0}[/COLOR], pulse 'No' o cierre la ventana " \ "para no hacer nada.".format(show.strip()) if platformtools.dialog_yesno(heading, line1) == 1: dict_series = get_tvshows(channel) dict_series.pop(show, None) fname, json_data = update_json_data(dict_series, channel) result = filetools.write(fname, json_data) if result: message = "FILTRO ELIMINADO" else: message = "Error al guardar en disco" heading = show.strip() platformtools.dialog_notification(heading, message)
def make_dir(path): """ crea un directorio, samba necesita la raíz para conectar y la carpeta @type path: str @param path: la ruta del fichero """ logger.info("pelisalacarta.platformcode.library make_dir") if not samba.usingsamba(path): try: os.mkdir(path) except OSError: logger.info("pelisalacarta.platformcode.library make_dir: Error al crear la ruta") platformtools.dialog_notification("Error al crear la ruta", path) else: try: path_samba, folder_samba = path.rsplit('/', 1) samba.create_directory(folder_samba, path_samba) except gaierror: logger.info("pelisalacarta.platformcode.library make_dir: Error al crear la ruta") platformtools.dialog_notification("Error al crear la ruta", path)
def rmdir(path): """ Elimina un directorio @param path: ruta a eliminar @type path: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) try: if path.lower().startswith("smb://"): samba.rmdir(path) else: os.rmdir(path) except: logger.error("ERROR al eliminar el directorio: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Impossibile rimuovere la directory.", path) return False else: return True
def mkdir(path): """ Crea un directorio @param path: ruta a crear @type path: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) try: if path.lower().startswith("smb://"): samba.mkdir(path) else: os.mkdir(path) except: logger.error("ERROR al crear el directorio: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Error al crear el directorio", path) return False else: return True
def remove(path): """ Elimina un archivo @param path: ruta del fichero a eliminar @type path: str @rtype: bool @return: devuelve False en caso de error """ path = encode(path) try: if path.lower().startswith("smb://"): samba.remove(path) else: os.remove(path) except: logger.error("ERROR al eliminar el archivo: %s" %(path)) logger.error(traceback.format_exc()) platformtools.dialog_notification("Error al eliminar el archivo", path) return False else: return True
def __init__(self, **kwargs): self.__check_token() self.result = {} self.list_results = [] self.lang = "" self.search_name = kwargs['search'] = \ re.sub('\[\\\?(B|I|COLOR)\s?[^\]]*\]', '', kwargs.get('search', '')) self.list_episodes = {} self.episodes = {} if kwargs.get('tvdb_id', ''): # Busqueda por identificador tvdb self.__get_by_id(kwargs.get('tvdb_id', '')) if not self.list_results and config.get_setting("tvdb_retry_eng", "biblioteca"): from platformcode import platformtools platformtools.dialog_notification("No se ha encontrado en idioma '%s'" % DEFAULT_LANG, "Se busca en idioma 'en'") self.__get_by_id(kwargs.get('tvdb_id', ''), "en") self.lang = "en" elif self.search_name: # Busqueda por texto self.__search(kwargs.get('search', ''), kwargs.get('imdb_id', ''), kwargs.get('zap2it_id', '')) if not self.list_results and config.get_setting("tvdb_retry_eng", "biblioteca"): from platformcode import platformtools platformtools.dialog_notification("No se ha encontrado en idioma '%s'" % DEFAULT_LANG, "Se busca en idioma 'en'") self.__search(kwargs.get('search', ''), kwargs.get('imdb_id', ''), kwargs.get('zap2it_id', ''), "en") self.lang = "en" if not self.result: # No hay resultados de la busqueda if kwargs.get('tvdb_id', ''): buscando = kwargs.get('tvdb_id', '') else: buscando = kwargs.get('search', '') msg = "La busqueda de %s no dio resultados." % buscando logger.debug(msg)
def add_season(data=None): logger.debug("data {0}".format(data)) heading = "Introduzca el número de la temporada" # default = 2 # se reordena la lista list_season_episode = data if list_season_episode: list_season_episode.sort(key=lambda el: int(el[0]), reverse=False) # if list_season_episode: # # mostrar temporada + 1 de la lista # # TODO buscar la primera posicion libre # default = list_season_episode[0][0]+1 season = platformtools.dialog_numeric(0, heading) # , str(default)) for element in list_season_episode: if int(season) == element[0]: platformtools.dialog_notification("No se añade la temporada", "Ya existe, edíte la existente") return # si hemos insertado un valor en la temporada if season != "" and int(season) > 0: heading = "Introduzca el número de episodio desde que empieza la temporada" # default = 0 # if list_season_episode: # for e in list_season_episode: # # mostrar suma episodios de la lista # # sumar hasta el indice del primer libre encontrado # default += e[1] episode = platformtools.dialog_numeric(0, heading) # , str(default)) # si hemos insertado un valor en el episodio if episode != "": if list_season_episode: list_season_episode.insert(0, [int(season), int(episode)]) new_list_season_episode = list_season_episode[:] return new_list_season_episode else: return [[int(season), int(episode)]]
def run(item=None): logger.debug() # Extract item from sys.argv if not item: item = makeItem() # Load or Repare Settings if not config.get_setting('show_once'): showOnce() # Acrions logger.debug(item.tostring()) try: # Active tmdb if not config.get_setting('tmdb_active'): config.set_setting('tmdb_active', True) # If item has no action, stops here if item.action == '': logger.debug('Item without action') return # Channel Selector if item.channel == 'channelselector': itemlist = [] import channelselector if item.action == 'getmainlist': # Action for main menu in channelselector itemlist = channelselector.getmainlist() elif item.action == 'getchanneltypes': # Action for channel types on channelselector: movies, series, etc. itemlist = channelselector.getchanneltypes() elif item.action == 'filterchannels': # Action for channel listing on channelselector itemlist = channelselector.filterchannels(item.channel_type) platformtools.render_items(itemlist, item) # Special action for playing a video from the library elif item.action == 'play_from_library': return playFromLibrary(item) # Special play action elif item.action == 'play': play(item) # Special findvideos Action elif item.action == 'findvideos': findvideos(item) # Special action for searching, first asks for the words then call the "search" function elif item.action == 'search': search(item) ######## Following shares must be improved ######## # Special itemInfo Action elif item.action == "itemInfo": platformtools.dialog_textviewer('Item info', item.parent) # Special action for open item.url in browser elif item.action == "open_browser": import webbrowser if not webbrowser.open(item.url): import xbmc if xbmc.getCondVisibility('system.platform.linux') and xbmc.getCondVisibility('system.platform.android'): # android xbmc.executebuiltin('StartAndroidActivity("", "android.intent.action.VIEW", "", "%s")' % item.url) else: platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(70740) % "\n".join([item.url[j:j+57] for j in range(0, len(item.url), 57)])) # Special gotopage Action elif item.action == "gotopage": page = platformtools.dialog_numeric(0, config.get_localized_string(70513)) if page: import xbmc item.action = item.real_action if item.page: item.page = int(page) else: import re item.url = re.sub('([=/])[0-9]+(/?)$', '\g<1>' + page + '\g<2>', item.url) xbmc.executebuiltin("Container.Update(%s?%s)" % (sys.argv[0], item.tourl())) # Special action for adding a movie to the library elif item.action == "add_pelicula_to_library": from core import videolibrarytools videolibrarytools.add_movie(item) # Special action for adding a serie to the library elif item.action == "add_serie_to_library": channel = importChannel(item) from core import videolibrarytools videolibrarytools.add_tvshow(item, channel) # Special action for adding a undefined to the library elif item.action == "add_to_library": channel = importChannel(item) from core import videolibrarytools videolibrarytools.add_to_videolibrary(item, channel) # Special action for downloading all episodes from a serie elif item.action == "download_all_episodes": from specials import downloads item.action = item.extra del item.extra downloads.save_download(item) # keymaptools special actions elif item.action == "keymap": from platformcode import keymaptools if item.open: return keymaptools.open_shortcut_menu() else: return keymaptools.set_key() elif item.action == "delete_key": from platformcode import keymaptools return keymaptools.delete_key() # delete tmdb cache elif item.action == "script": from core import tmdb tmdb.clean_cache() platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False) ################################################ # For all other actions else: actions(item) except WebErrorException as e: import traceback from core import scrapertools logger.error(traceback.format_exc()) platformtools.dialog_ok( config.get_localized_string(59985) % e.channel, config.get_localized_string(60013) % e.url) except Exception as e: import traceback from core import scrapertools logger.error(traceback.format_exc()) patron = r'File "{}([^.]+)\.py"'.format(filetools.join(config.get_runtime_path(), 'channels', '').replace('\\', '\\\\')) Channel = scrapertools.find_single_match(traceback.format_exc(), patron) if Channel or e.__class__ == logger.ChannelScraperException: if item.url: if platformtools.dialog_yesno(config.get_localized_string(60087) % Channel, config.get_localized_string(60014), nolabel='ok', yeslabel=config.get_localized_string(70739)): run(Item(action='open_browser', url=item.url)) else: platformtools.dialog_ok(config.get_localized_string(60087) % Channel, config.get_localized_string(60014)) else: if platformtools.dialog_yesno(config.get_localized_string(60038), config.get_localized_string(60015)): platformtools.itemlist_update(Item(channel='setting', action='report_menu'), True) finally: # db need to be closed when not used, it will cause freezes from core import db db.close() import threading logger.debug(threading.enumerate())
def install_alfa_assistant(update=False, remote='', verbose=False): if update: logger.info('update=%s' % str(update)) # Si ya está instalada, devolvemos el control app_name = 'com.alfa.alfamobileassistant' if not verbose: verbose = config.get_setting('addon_update_message') # Verbose en la actualización/instalación assistant_flag_install = config.get_setting('assistant_flag_install', default=True) addonid = 'alfa-mobile-assistant' download = addonid + '.apk' package = addonid + '.apk' version = addonid + '.version' forced_menu = False respuesta = False alfa_s = True addons_path = config.get_runtime_path() if filetools.exists(filetools.join(addons_path, 'channels', 'custom.py')): alfa_s = False if not remote: ANDROID_STORAGE = os.getenv('ANDROID_STORAGE') if not ANDROID_STORAGE: ANDROID_STORAGE = '/storage' else: # Remote es la url de un servidor FTP o SMB activo que apunta a la ruta "/storage" del dispositivo Android ANDROID_STORAGE = remote if ANDROID_STORAGE.endswith('/'): ANDROID_STORAGE = ANDROID_STORAGE[:-1] apk_files = '%s/%s/%s/%s/%s/%s' % (ANDROID_STORAGE, 'emulated', '0', 'Android', 'data', app_name) if ASSISTANT_MODE == 'este' and not filetools.exists(filetools.dirname(apk_files)): apk_files_alt = scrapertools.find_single_match(os.getenv('HOME'), '(.*?)\/\w*.\w*.\w*\/files') logger.info('HOME: ' + apk_files_alt) if apk_files_alt and filetools.exists(apk_files_alt): apk_files = '%s/%s' % (apk_files_alt, app_name) version_path = filetools.join(config.get_data_path(), version) version_act = filetools.read(version_path, silent=True) if not version_act: version_act = '0.0.0' # Averiguamos si es instalacción, update, o forzado desde el Menú de Ajustes if not update and ASSISTANT_MODE == 'este' and filetools.exists(apk_files): return version_act, app_name if ASSISTANT_MODE == 'este' and not update: check_permissions_alfa_assistant() # activamos la app por si no se ha inicializado time.sleep(1) if filetools.exists(apk_files): return version_act, app_name # Mirarmos si la app está activa y obtenemos el nº de versión version_dict = get_generic_call('getWebViewInfo', timeout=2-EXTRA_TIMEOUT, alfa_s=True) if isinstance(version_dict, dict): version_app = version_dict.get('assistantVersion', '') try: android_version = int(scrapertools.find_single_match(version_dict.get('userAgent', ''), r"Android\s*(\d+)")) except: android_version = 8 else: version_app = version_dict android_version = 8 if version_app and not update: return version_app, app_name if version_app: app_active = True else: app_active = False if ASSISTANT_MODE == "este": execute_in_alfa_assistant_with_cmd('open') # activamos la app por si no se ha inicializado time.sleep(5) version_dict = get_generic_call('getWebViewInfo', timeout=2-EXTRA_TIMEOUT, alfa_s=True) if isinstance(version_dict, dict): version_app = version_dict.get('assistantVersion', '') try: android_version = int(scrapertools.find_single_match(version_dict.get('userAgent', ''), r"Android\s*(\d+)")) except: android_version = 8 else: version_app = version_dict android_version = 8 version_actual = filetools.read(version_path, silent=True) if not version_actual and version_app: version_actual = version_app filetools.write(version_path, version_actual, mode='wb', silent=True) elif not version_actual: version_actual = '0.0.0' if ASSISTANT_MODE != 'este': if not version_app: if verbose or (update and not isinstance(update, bool)): platformtools.dialog_notification("Active Alfa Assistant", "o Instale manualmente desde [COLOR yellow]https://bit.ly/2Zwpfzq[/COLOR]") logger.info("Active Alfa Assistant, o Instale manualmente desde [COLOR yellow]https://bit.ly/2Zwpfzq[/COLOR]", force=True) config.set_setting('assistant_flag_install', False) return version_app, app_name else: config.set_setting('assistant_flag_install', True) if not update: return version_app, app_name elif not update and not assistant_flag_install and not filetools.exists(apk_files): logger.info('NO está instalada. El usuario no quiere instalaciñon automática: %s' % app_name) return False, app_name elif update and isinstance(update, bool) and not filetools.exists(apk_files): logger.info('NO está instalada. No se va a actualizar: %s' % app_name) return False, app_name elif update and not isinstance(update, bool) and not filetools.exists(apk_files): logger.info('NO está instalada. Viene del Menú y se va a instalar: %s' % app_name) update = False forced_menu = True elif not remote and not xbmc.getCondVisibility("system.platform.android"): logger.info('El sistema local no es Android: %s' % app_name) return False, app_name logger.info('assistant_mode=%s, update=%s, forced_menu=%s, assistant_flag_install=%s, version_actual=%s, version_app=%s, android=%s, app_active=%s' \ % (ASSISTANT_MODE, str(update), str(forced_menu), str(assistant_flag_install), version_actual, \ version_app, str(android_version), str(app_active))) # Si no está instalada, o se quiere actualizar, empezamos el proceso alfa_assistant_pwd = '' assistant_urls = ['https://github.com/alfa-addon/alfa-repo/raw/master/downloads/assistant/%s' % version, \ 'https://bitbucket.org/alfa_addon/alfa-repo/raw/master/downloads/assistant/%s' % version] apk_updated = filetools.join(addons_path, 'tools') apk_path = filetools.join(apk_updated, download) apk_apk = filetools.join(apk_updated, package) upk_install_path = filetools.join('special://xbmc/', 'files').replace('/cache/apk/assets', '') if not remote: apk_install = filetools.join(ANDROID_STORAGE, 'emulated', '0', 'Download') apk_install_SD = filetools.join(apk_install, package) else: apk_install = '%s/%s/%s/%s' % (ANDROID_STORAGE, 'emulated', '0', 'Download') apk_install_SD = '%s/%s' % (apk_install, package) if not update and not remote and not forced_menu: # Probamos a iniciar por si se ha instalado manualmente y no se ha iniciado la estrucutra de archivos check_permissions_alfa_assistant() try: command = ['pm', 'list', 'packages'] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) PM_LIST, error_cmd = p.communicate() if PY3 and isinstance(label_a, bytes): PM_LIST = PM_LIST.decode() if app_name in PM_LIST: logger.info('Ya instalada. Volvemos: %s' % app_name) return version_actual, app_name except: logger.error(traceback.format_exc(1)) if not update and not forced_menu and not platformtools.dialog_yesno("Instalación Alfa Assistant", \ "¿Desea instalar la App [COLOR yellow][B]%s[/B][/COLOR]\n" % app_name + " como ayuda para acceder a ciertos canales y servidores?"): config.set_setting('assistant_flag_install', False) return respuesta, app_name elif update and not isinstance(update, bool): platformtools.dialog_notification("Instalación Alfa Assistant", "Comienza la actualización") elif forced_menu: platformtools.dialog_notification("Instalación Alfa Assistant", "Comienza la instalación") # Comprobamos si el dispositivo está rooteado is_rooted = config.is_rooted(silent=True) # ¡OJO! puede pedir permisos root en algunos dispositivos if is_rooted == 'rooted' and ASSISTANT_MODE == 'este': # El dispositivo esta rooteado? update_install = 'py' # Se actualiza desde esta función else: update_install = 'app' # Se actualiza desde la app cmd = 'update' # Comando de la app para auto actualizarse dataURI = 'Version:%s' # Versión a actualizar # Comprobamos si hay acceso a Github o BitBucket for assistant_rar in assistant_urls: response = httptools.downloadpage(assistant_rar, timeout=5, ignore_response_code=True, alfa_s=alfa_s, json_to_utf8=False) if response.sucess: break # Descargamos el archivo de version. Si hay error avisamos, pero continuamos if not response.sucess: if update and isinstance(update, bool): logger.error("Error en la descarga de control de versión. No se puede actualizar: %s" % str(response.code)) return respuesta, app_name platformtools.dialog_notification("Instalación Alfa Assistant", "Error en la descarga de control de versión. Seguimos") logger.error("Error en la descarga de control de versión. Seguimos...: %s" % str(response.code)) #Si es una actualización programada, comprobamos las versiones de Github y de lo instalado if update and isinstance(update, bool): if version_actual != response.data: if version_app: version_actual = version_app filetools.write(version_path, version_actual, mode='wb', silent=True) if version_actual == response.data: if verbose: platformtools.dialog_notification("Instalación Alfa Assistant", "Ya está actualizado a version %s" % response.data) logger.info("Alfa Assistant ya actualizado a versión: %s" % response.data) if not app_active and ASSISTANT_MODE == "este": execute_in_alfa_assistant_with_cmd('quit') # desactivamos la app si no estaba iniciada return version_actual, app_name # Guardamos archivo de versión if remote: version_path = '%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s' % (ANDROID_STORAGE, 'emulated', '0', 'Android', 'data', 'org.xbmc.kodi', 'files', '.kodi', 'addons', 'plugin.video.alfa', 'tools', version) if not filetools.exists(filetools.dirname(version_path)): logger.error("Ruta a carpeta remota de versión no es estándar: %s" % version_path) version_path = '' version_old = version_actual version_actual = response.data if version_path: res = filetools.write(version_path, response.data, mode='wb', silent=True) if not res: if not update: platformtools.dialog_notification("Instalación Alfa Assistant", \ "Error en la escritura de control de versión. Seguimos...") logger.error("Error en la escritura de control de versión. Seguimos...: %s" % assistant_rar) # Descargamos y guardamos el .APK assistant_rar = assistant_rar.replace(version, download) # Sustituir en la url la versión por el apk res = False if not update: platformtools.dialog_notification("Instalación Alfa Assistant", "Descargando APK") logger.info('Descargando de_ %s' % assistant_rar) response = httptools.downloadpage(assistant_rar, timeout=5, ignore_response_code=True, alfa_s=alfa_s, json_to_utf8=False) if not response.sucess: if not update or verbose: platformtools.dialog_notification("Instalación Alfa Assistant", "Error en la descarga del .apk") response.data = '' logger.error("Error en la descarga del .apk: %s" % str(response.code)) else: # Guardamos archivo descargado de APK res = filetools.write(apk_path, response.data, mode='wb', silent=True) if not res: if not update or verbose: platformtools.dialog_notification("Instalación Alfa Assistant", "Error en la escritura del APK") logger.error("Error en la escritura del APK: %s" % apk_path) else: if '.rar' in download: # Empezando la extracción del .rar del APK try: import rarfile archive = rarfile.RarFile(apk_path) if alfa_assistant_pwd: archive.setpassword(alfa_assistant_pwd) archive.extractall(apk_updated) except: logger.error(traceback.format_exc(1)) elif '.zip' in download: # Empezando la extracción del .rar del APK try: import ziptools archive = ziptools.ziptools() #if alfa_assistant_pwd: archive.setpassword(alfa_assistant_pwd) # No hay password en .zip archive.extract(filetools.basename(apk_updated), filetools.dirname(apk_updated)) except: xbmc.executebuiltin('Extract("%s","%s")' % (filetools.basename(apk_updated), filetools.dirname(apk_updated))) time.sleep(1) # Verificado si está el APK, y si está y es LOCAL lo instalamos if ASSISTANT_MODE == "este": res = filetools.copy(apk_apk, apk_install_SD, silent=True) if not res or not filetools.exists(apk_install_SD): if not update or verbose: platformtools.dialog_notification("Instalación Alfa Assistant", "Error de Extracción o Copia %s" % package) logger.error("Error de Extracción o copia %s" % package) # Si está rooteado se instala/actualiza directamente elif update_install == 'py' and res and filetools.exists(apk_install_SD): # Instalamos: nueva o actualización. if not update: platformtools.dialog_notification("Instalación Alfa Assistant", "Installando %s" % package) logger.info("Installing %s" % package) # Instalación Remota if remote: filetools.remove(apk_apk, silent=True) platformtools.dialog_notification("Alfa Assistant: Descarga Remota terminada", "Instale manualmente desde: %s" % apk_install_SD) logger.info("Alfa Assistant: Descarga Remota terminada. Instale manualmente desde: %s" % apk_install_SD) return version_actual, app_name # Instalación Local if not filetools.exists(upk_install_path): filetools.mkdir(upk_install_path) upk_install_path = filetools.join(upk_install_path, package) res = filetools.copy(apk_install_SD, upk_install_path, ch_mod='777') # Copiamos APK a la partición del Sistema, y cambiamos permisos if not res: if not update or verbose: platformtools.dialog_notification("Instalación Alfa Assistant", "Error de Copia %s" % package) logger.error(str(filetools.listdir(apk_install))) logger.error(filetools.file_info(filetools.dirname(upk_install_path))) logger.error(str(filetools.listdir(filetools.dirname(upk_install_path), file_inf=True))) else: # Intenta la instalación vía ROOT y si no funciona como NO ROOT # Marcamos la opción de instalación, -r si es actualización, -g (todos los permisos granted) si es instalación if filetools.exists(apk_files): pm_opt = '-r' else: pm_opt = '-g' # Listamos todas las opciones de comandos, según las variantes de Android command_list = [ ['adb', 'install', '%s' % upk_install_path], ['su', '-c', 'pm install %s %s' % (pm_opt, upk_install_path)], ['su', '-c', 'pm', 'install', pm_opt, '%s' % upk_install_path], ['su', '-0', 'pm install %s %s' % (pm_opt, upk_install_path)], ['su', '-0', 'pm', 'install', pm_opt, '%s' % upk_install_path] ] for command in command_list: try: logger.info(command, force=True) p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() if error_cmd: if error_cmd.startswith('su:'): continue if update: ver_upd = get_generic_call('ping', timeout=2-EXTRA_TIMEOUT, alfa_s=True) if not ver_upd: execute_in_alfa_assistant_with_cmd('open') # activamos la app por si no se ha inicializado time.sleep(5) ver_upd = get_generic_call('ping', timeout=2-EXTRA_TIMEOUT, alfa_s=True) execute_in_alfa_assistant_with_cmd('quit') if ver_upd == version_actual: logger.debug(str(error_cmd), force=True) error_cmd = '' else: check_permissions_alfa_assistant() time.sleep(1) if filetools.exists(apk_files): logger.debug(str(error_cmd), force=True) error_cmd = '' if error_cmd: logger.error(str(error_cmd)) else: respuesta = version_actual break else: respuesta = version_actual break except Exception as e: if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") logger.error('Command ERROR: %s, %s' % (str(command), str(e))) continue # Ùltimo resorte: instalación manual desde GitHub o actualización desde la app if not respuesta and update: # Si hay que actualizar se verifica el vehículo de instalación logger.info("Instalación Alfa Assistant. Actualización desde la app de %s a %s" % (version_old, version_actual)) version_mod = version_actual if not isinstance(update, bool): version_mod = '9.9.999' # Intenta forzar la actualización si viene desde el Menú if ASSISTANT_MODE == "este": if android_version >= 10: app_active = False respuesta = execute_in_alfa_assistant_with_cmd(cmd, dataURI=dataURI % version_mod) else: if not app_active: execute_in_alfa_assistant_with_cmd('openAndQuit') # activamos la app por si no se ha inicializado time.sleep(5) app_active = False respuesta = get_generic_call(cmd, version=version_mod, alfa_s=alfa_s) else: if app_active: respuesta = get_generic_call(cmd, version=version_mod, alfa_s=alfa_s) if not respuesta and ASSISTANT_MODE != "este": if verbose or not isinstance(update, bool): platformtools.dialog_notification("Instalación Alfa Assistant", "Intente la actualización manualmente %s" % version_actual) logger.info("Instalación Alfa Assistant. Intente la actualización manualmente %s" % version_actual) return False, app_name elif not respuesta: # Update local #respuesta = execute_in_alfa_assistant_with_cmd(cmd, dataURI=dataURI % version_mod) if not respuesta: if verbose or not isinstance(update, bool): platformtools.dialog_notification("Instalación Alfa Assistant", "Actualización en error %s. REINTENTANDO" % version_actual) logger.info("Instalación Alfa Assistant. Actualización en error %s. REINTENTANDO" % version_actual) else: respuesta = version_actual if not respuesta: config.set_setting('assistant_flag_install', False) # No vuelve a intentar la instalación try: #xbmc.executebuiltin('StartAndroidActivity("","android.intent.action.VIEW","application/vnd.android.package-archive","file:%s")' % apk_install_SD) if ASSISTANT_MODE == "este": from lib import generictools assistant_rar = assistant_rar.replace('/raw/', '/tree/') # Apuntar a la web de descargas browser, res = generictools.call_browser(assistant_rar, lookup=True) if browser: filetools.remove(apk_install_SD, silent=True) platformtools.dialog_ok("Alfa Assistant: Instale desde [COLOR yellow]%s[/COLOR]" % browser.capitalize(), "O Instale manualmente desde: [COLOR yellow]%s[/COLOR]" % apk_install_SD) logger.info('Browser: %s, Ruta: %s' % (browser.capitalize(), apk_install_SD)) time.sleep(5) browser, res = generictools.call_browser(assistant_rar, dataType='application/vnd.android.package-archive') filetools.remove(apk_path, silent=True) filetools.remove(upk_install_path, silent=True) else: logger.error('Error de Instalación: NO Browser, Ruta: %s' % apk_install_SD) raise else: logger.error('Error de Instalación: no se puede instalar en remoto: %s' % ASSISTANT_SERVER) raise except: if ASSISTANT_MODE == "este": platformtools.dialog_ok("Alfa Assistant: Error", "Instale manualmente desde: [COLOR yellow]%s[/COLOR]" % apk_install_SD) logger.error("Alfa Assistant: Error. Instale manualmente desde: [COLOR yellow]%s[/COLOR]" % apk_install_SD) filetools.remove(apk_path, silent=True) filetools.remove(upk_install_path, silent=True) else: platformtools.dialog_ok("Alfa Assistant: Error", "Copie a Android manualmente desde: [COLOR yellow]%s[/COLOR]" % apk_apk) logger.error("Alfa Assistant: Error. Copie a Android manualmente desde: [COLOR yellow]%s[/COLOR]" % apk_apk) logger.error(traceback.format_exc(1)) if respuesta: if update: if verbose or not isinstance(update, bool): platformtools.dialog_notification("Alfa Assistant", \ "Actualización con exito: %s" % respuesta) logger.info("Actualización terminada con éxito: %s" % respuesta) else: platformtools.dialog_notification("Alfa Assistant", "Instalación con exito: %s" % respuesta) logger.info("Instalación terminada con éxito: %s" % respuesta) filetools.remove(apk_path, silent=True) filetools.remove(apk_install_SD, silent=True) filetools.remove(upk_install_path, silent=True) if not update and not forced_menu: time.sleep(1) check_permissions_alfa_assistant() time.sleep(1) if app_active and ASSISTANT_MODE == "este": execute_in_alfa_assistant_with_cmd('open') # re-activamos la app para dejarla como estaba return respuesta, app_name
def play(item): itemlist = [] data = httptools.downloadpage(item.url).data url = scrapertools.find_single_match(data, '<iframe.*?src="([^"]+)"') if not url: platformtools.dialog_notification( "Stream not available", "It is not possible to connect to the broadcast") return [] elif "/matras.jpg" in data: platformtools.dialog_notification("Stream error", "Try again after a few minutes") return [] h = HTMLParser() url = h.unescape(url) data = httptools.downloadpage(url).data f = scrapertools.find_single_match(data, 'name="f" value="([^"]+)"') d = scrapertools.find_single_match(data, 'name="d" value="([^"]+)"') r = scrapertools.find_single_match(data, 'name="r" value="([^"]+)"') url_post = scrapertools.find_single_match(data, "'action',\s*'([^']+)'") if not url_post: platformtools.dialog_notification( "Stream not available", "It is not possible to connect to the broadcast") return [] post = {'r': r, 'd': d, 'f': f} post = urllib.urlencode(post) data = httptools.downloadpage(url_post, post).data try: get_links(data) except: pass key_save = config.get_setting("key_cryp", "sport365") if not key_save: key = getkey() else: key = base64.b64decode(key_save) data_crypto = scrapertools.find_single_match( data, "\};[A-z0-9]{43}\(.*?,.*?,\s*'([^']+)'") url = jsontools.load_json(base64.b64decode(data_crypto)) try: url = jscrypto.decode(url["ct"], key, url["s"].decode("hex")) except: key = getkey(True) url = jscrypto.decode(url["ct"], key, url["s"].decode("hex")) url = url.replace('\\/', '/').replace("\\", "").replace('"', "") headers_test = { 'Referer': url_post, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0' } response = httptools.downloadpage(url, headers=headers_test, follow_redirects=False, only_headers=True, replace_headers=True) if response.code == 406: response = httptools.downloadpage(url, headers=headers_test, follow_redirects=False, only_headers=True, replace_headers=True, cookies=False) if response.code == 406: platformtools.dialog_notification( "Stream not available", "It is not possible to connect to the broadcast") return [] url += "ndex.m3u8|Referer=%s&User-Agent=Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0" % url_post itemlist.append([".m3u8 [Sport365]", url]) return itemlist
def establecer_contenido(content_type, silent=False): if config.is_xbmc(): continuar = False librarypath = config.get_setting("librarypath") if librarypath == "": continuar = True if content_type == FOLDER_MOVIES: if not xbmc.getCondVisibility( 'System.HasAddon(metadata.themoviedb.org)'): if not silent: # Preguntar si queremos instalar metadata.themoviedb.org install = platformtools.dialog_yesno( "The Movie Database", "No se ha encontrado el Scraper de películas de TheMovieDB.", "¿Desea instalarlo ahora?") else: install = True if install: try: # Instalar metadata.themoviedb.org xbmc.executebuiltin( 'xbmc.installaddon(metadata.themoviedb.org)', True) logger.info( "Instalado el Scraper de películas de TheMovieDB" ) except: pass continuar = (install and xbmc.getCondVisibility( 'System.HasAddon(metadata.themoviedb.org)')) else: if not xbmc.getCondVisibility( 'System.HasAddon(metadata.tvshows.themoviedb.org)'): if not silent: # Preguntar si queremos instalar metadata.tvshows.themoviedb.org install = platformtools.dialog_yesno( "The Movie Database", "No se ha encontrado el Scraper de series de TheMovieDB.", "¿Desea instalarlo ahora?") else: install = True if install: try: # Instalar metadata.tvshows.themoviedb.org xbmc.executebuiltin( 'xbmc.installaddon(metadata.tvshows.themoviedb.org)', True) logger.info( "Instalado el Scraper de series de TheMovieDB") except: pass continuar = (install and xbmc.getCondVisibility( 'System.HasAddon(metadata.tvshows.themoviedb.org)')) idPath = 0 idParentPath = 0 strPath = "" if continuar: continuar = False librarypath = "special://home/userdata/addon_data/plugin.video." + config.PLUGIN_NAME + "/library/" # Buscamos el idPath sql = 'SELECT MAX(idPath) FROM path' nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idPath = records[0][0] + 1 # Buscamos el idParentPath sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % \ librarypath.replace('/profile/', '/%/').replace('/home/userdata/', '/%/') nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idParentPath = records[0][0] librarypath = records[0][1] continuar = True else: # No existe librarypath en la BD: la insertamos sql = 'INSERT INTO path (idPath, strPath, scanRecursive, useFolderNames, noUpdate, exclude) VALUES ' \ '(%s, "%s", 0, 0, 0, 0)' % (idPath, librarypath) nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True idParentPath = idPath idPath += 1 if continuar: continuar = False # Fijamos strContent, strScraper, scanRecursive y strSettings if content_type == FOLDER_MOVIES: strContent = 'movies' strScraper = 'metadata.themoviedb.org' scanRecursive = 2147483647 strSettings = "<settings><setting id='RatingS' value='TMDb' /><setting id='certprefix' value='Rated ' />" \ "<setting id='fanart' value='true' /><setting id='keeporiginaltitle' value='false' />" \ "<setting id='language' value='es' /><setting id='tmdbcertcountry' value='us' />" \ "<setting id='trailer' value='true' /></settings>" else: strContent = 'tvshows' strScraper = 'metadata.tvshows.themoviedb.org' scanRecursive = 0 strSettings = "<settings><setting id='fanart' value='true' />" \ "<setting id='keeporiginaltitle' value='false' />" \ "<setting id='language' value='es' /></settings>" # Fijamos strPath strPath = librarypath + content_type + "/" logger.info("%s: %s" % (content_type, strPath)) # Comprobamos si ya existe strPath en la BD para evitar duplicados sql = 'SELECT idPath FROM path where strPath="%s"' % strPath nun_records, records = execute_sql_kodi(sql) sql = "" if nun_records == 0: # Insertamos el scraper sql = 'INSERT INTO path (idPath, strPath, strContent, strScraper, scanRecursive, useFolderNames, ' \ 'strSettings, noUpdate, exclude, idParentPath) VALUES (%s, "%s", "%s", "%s", %s, 0, ' \ '"%s", 0, 0, %s)' % ( idPath, strPath, strContent, strScraper, scanRecursive, strSettings, idParentPath) else: if not silent: # Preguntar si queremos configurar themoviedb.org como opcion por defecto actualizar = platformtools.dialog_yesno( "The Movie Database", "¿Desea configurar este Scraper en español " "como opción por defecto?") else: actualizar = True if actualizar: # Actualizamos el scraper idPath = records[0][0] sql = 'UPDATE path SET strContent="%s", strScraper="%s", scanRecursive=%s, strSettings="%s" ' \ 'WHERE idPath=%s' % (strContent, strScraper, scanRecursive, strSettings, idPath) if sql: nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True logger.info("Biblioteca %s configurada" % content_type) if not continuar: heading = "Biblioteca no configurada" msg_text = "Asegurese de tener instalado el scraper de The Movie Database" platformtools.dialog_notification(heading, msg_text, icon=1, time=8000) logger.info("%s: %s" % (heading, msg_text))
video_file = _video_file video_size = _size_file _video_file_ext = os.path.splitext(_video_file)[1] log("##### _video_file_ext ## %s ##" % _video_file_ext) dp_cerrado = True rar = False if _video_file_ext == ".rar": rar = True filename = video_file if "/" in filename: filename = filename.split("/")[1] if RAR: platformtools.dialog_notification( "Encontrado archivo rar... ", "Tamaño: %.2f MB. Cancelar en menú Descargas" % (video_size / 1048576.0)) dialog = True else: dialog = xbmcgui.Dialog().yesno( "Encontrado archivo rar...", "Nombre: %s" % filename, "Tamaño: %.2f MB" % (video_size / 1048576.0), "¿Descargar en segundo plano? Cancelar en menú Descargas") if dialog: dp_cerrado = False dp = xbmcgui.DialogProgressBG() dp.create('Alfa-MCT') if (_video_file_ext == ".avi" or _video_file_ext == ".mp4") and allocate: log("##### storage_mode_t.storage_mode_allocate (" + _video_file_ext + ") #####")
def run(item=None): logger.info() if not item: # Extract item from sys.argv if sys.argv[2]: item = Item().fromurl(sys.argv[2]) # If no item, this is mainlist else: if config.get_setting("start_page"): if not config.get_setting("custom_start"): category = config.get_setting("category").lower() item = Item(channel="news", action="novedades", extra=category, mode = 'silent') else: from channels import side_menu item= Item() item = side_menu.check_user_home(item) item.start = True; else: item = Item(channel="channelselector", action="getmainlist", viewmode="movie") if not config.get_setting('show_once'): from platformcode import xbmc_videolibrary xbmc_videolibrary.ask_set_content(1) config.set_setting('show_once', True) logger.info(item.tostring()) try: if not config.get_setting('tmdb_active'): config.set_setting('tmdb_active', True) # If item has no action, stops here if item.action == "": logger.info("Item sin accion") return # Action for main menu in channelselector elif item.action == "getmainlist": import channelselector itemlist = channelselector.getmainlist() platformtools.render_items(itemlist, item) # Action for channel types on channelselector: movies, series, etc. elif item.action == "getchanneltypes": import channelselector itemlist = channelselector.getchanneltypes() platformtools.render_items(itemlist, item) # Action for channel listing on channelselector elif item.action == "filterchannels": import channelselector itemlist = channelselector.filterchannels(item.channel_type) platformtools.render_items(itemlist, item) # Special action for playing a video from the library elif item.action == "play_from_library": play_from_library(item) return elif item.action == "keymap": from platformcode import keymaptools if item.open: return keymaptools.open_shortcut_menu() else: return keymaptools.set_key() elif item.action == "script": from core import tmdb if tmdb.drop_bd(): platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False) # Action in certain channel specified in "action" and "channel" parameters else: # Entry point for a channel is the "mainlist" action, so here we check parental control if item.action == "mainlist": # Parental control # If it is an adult channel, and user has configured pin, asks for it if channeltools.is_adult(item.channel) and config.get_setting("adult_request_password"): tecleado = platformtools.dialog_input("", config.get_localized_string(60334), True) if tecleado is None or tecleado != config.get_setting("adult_password"): return # # Actualiza el canal individual # if (item.action == "mainlist" and item.channel != "channelselector" and # config.get_setting("check_for_channel_updates") == True): # from core import updater # updater.update_channel(item.channel) # Checks if channel exists channel_file = os.path.join(config.get_runtime_path(), 'channels', item.channel + ".py") logger.info("channel_file=%s" % channel_file) channel = None if os.path.exists(channel_file): try: channel = __import__('channels.%s' % item.channel, None, None, ["channels.%s" % item.channel]) except ImportError: exec("import channels." + item.channel + " as channel") logger.info("Running channel %s | %s" % (channel.__name__, channel.__file__)) # Special play action if item.action == "play": #define la info para trakt try: trakt_tools.set_trakt_info(item) except: pass logger.info("item.action=%s" % item.action.upper()) # logger.debug("item_toPlay: " + "\n" + item.tostring('\n')) # First checks if channel has a "play" function if hasattr(channel, 'play'): logger.info("Executing channel 'play' method") itemlist = channel.play(item) b_favourite = item.isFavourite # Play should return a list of playable URLS if len(itemlist) > 0 and isinstance(itemlist[0], Item): item = itemlist[0] if b_favourite: item.isFavourite = True platformtools.play_video(item) # Permitir varias calidades desde play en el canal elif len(itemlist) > 0 and isinstance(itemlist[0], list): item.video_urls = itemlist platformtools.play_video(item) # If not, shows user an error message else: platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(60339)) # If player don't have a "play" function, not uses the standard play from platformtools else: logger.info("Executing core 'play' method") platformtools.play_video(item) # Special action for findvideos, where the plugin looks for known urls elif item.action == "findvideos": # First checks if channel has a "findvideos" function if hasattr(channel, 'findvideos'): itemlist = getattr(channel, item.action)(item) itemlist = servertools.filter_servers(itemlist) # If not, uses the generic findvideos function else: logger.info("No channel 'findvideos' method, " "executing core method") itemlist = servertools.find_video_items(item) if config.get_setting("max_links", "videolibrary") != 0: itemlist = limit_itemlist(itemlist) from platformcode import subtitletools subtitletools.saveSubtitleName(item) platformtools.render_items(itemlist, item) # Special action for adding a movie to the library elif item.action == "add_pelicula_to_library": videolibrarytools.add_movie(item) # Special action for adding a serie to the library elif item.action == "add_serie_to_library": videolibrarytools.add_tvshow(item, channel) # Special action for downloading all episodes from a serie elif item.action == "download_all_episodes": from channels import downloads item.action = item.extra del item.extra downloads.save_download(item) # Special action for searching, first asks for the words then call the "search" function elif item.action == "search": logger.info("item.action=%s" % item.action.upper()) # last_search = "" # last_search_active = config.get_setting("last_search", "search") # if last_search_active: # try: # current_saved_searches_list = list(config.get_setting("saved_searches_list", "search")) # last_search = current_saved_searches_list[0] # except: # pass last_search = channeltools.get_channel_setting('Last_searched', 'search', '') tecleado = platformtools.dialog_input(last_search) if tecleado is not None: channeltools.set_channel_setting('Last_searched', tecleado, 'search') itemlist = channel.search(item, tecleado) else: return platformtools.render_items(itemlist, item) # For all other actions else: logger.info("Executing channel '%s' method" % item.action) itemlist = getattr(channel, item.action)(item) if config.get_setting('trakt_sync'): token_auth = config.get_setting("token_trakt", "trakt") if not token_auth: trakt_tools.auth_trakt() else: import xbmc if not xbmc.getCondVisibility('System.HasAddon(script.trakt)') and config.get_setting( 'install_trakt'): trakt_tools.ask_install_script() itemlist = trakt_tools.trakt_check(itemlist) else: config.set_setting('install_trakt', True) platformtools.render_items(itemlist, item) except urllib2.URLError as e: import traceback logger.error(traceback.format_exc()) # Grab inner and third party errors if hasattr(e, 'reason'): logger.error("Razon del error, codigo: %s | Razon: %s" % (str(e.reason[0]), str(e.reason[1]))) texto = config.get_localized_string(30050) # "No se puede conectar con el sitio web" platformtools.dialog_ok("alfa", texto) # Grab server response errors elif hasattr(e, 'code'): logger.error("Codigo de error HTTP : %d" % e.code) # "El sitio web no funciona correctamente (error http %d)" platformtools.dialog_ok("alfa", config.get_localized_string(30051) % e.code) except WebErrorException as e: import traceback logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + '([^.]+)\.py"' canal = scrapertools.find_single_match(traceback.format_exc(), patron) platformtools.dialog_ok( config.get_localized_string(59985) + canal, config.get_localized_string(60013) %(e)) except: import traceback logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + '([^.]+)\.py"' canal = scrapertools.find_single_match(traceback.format_exc(), patron) try: import xbmc if config.get_platform(True)['num_version'] < 14: log_name = "xbmc.log" else: log_name = "kodi.log" log_message = config.get_localized_string(50004) + xbmc.translatePath("special://logpath") + log_name except: log_message = "" if canal: platformtools.dialog_ok( config.get_localized_string(60087) %canal, config.get_localized_string(60014), log_message) else: platformtools.dialog_ok( config.get_localized_string(60038), config.get_localized_string(60015), log_message)
def set_content(content_type, silent=False): """ Procedimiento para auto-configurar la videoteca de kodi con los valores por defecto @type content_type: str ('movie' o 'tvshow') @param content_type: tipo de contenido para configurar, series o peliculas """ continuar = True msg_text = "" videolibrarypath = config.get_setting("videolibrarypath") if content_type == 'movie': if not xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)'): if not silent: # Preguntar si queremos instalar metadata.themoviedb.org install = platformtools.dialog_yesno("The Movie Database", "No se ha encontrado el Scraper de películas de TheMovieDB.", "¿Desea instalarlo ahora?") else: install = True if install: try: # Instalar metadata.themoviedb.org xbmc.executebuiltin('xbmc.installaddon(metadata.themoviedb.org)', True) logger.info("Instalado el Scraper de películas de TheMovieDB") except: pass continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)')) if not continuar: msg_text = "The Movie Database no instalado." else: # SERIES # Instalar The TVDB if not xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)'): if not silent: # Preguntar si queremos instalar metadata.tvdb.com install = platformtools.dialog_yesno("The TVDB", "No se ha encontrado el Scraper de series de The TVDB.", "¿Desea instalarlo ahora?") else: install = True if install: try: # Instalar metadata.tvdb.com xbmc.executebuiltin('xbmc.installaddon(metadata.tvdb.com)', True) logger.info("Instalado el Scraper de series de The TVDB") except: pass continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)')) if not continuar: msg_text = "The TVDB no instalado." # Instalar TheMovieDB if continuar and not xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'): continuar = False if not silent: # Preguntar si queremos instalar metadata.tvshows.themoviedb.org install = platformtools.dialog_yesno("The Movie Database", "No se ha encontrado el Scraper de series de TheMovieDB.", "¿Desea instalarlo ahora?") else: install = True if install: try: # Instalar metadata.tvshows.themoviedb.org # 1º Probar desde el repositorio ... xbmc.executebuiltin('xbmc.installaddon(metadata.tvshows.themoviedb.org)', True) if not xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'): # ...si no funciona descargar e instalar desde la web url = "http://mirrors.kodi.tv/addons/jarvis/metadata.tvshows.themoviedb.org/metadata.tvshows.themoviedb.org-1.3.1.zip" path_down = xbmc.translatePath( "special://home/addons/packages/metadata.tvshows.themoviedb.org-1.3.1.zip") path_unzip = xbmc.translatePath("special://home/addons/") header = ("User-Agent", "Kodi/15.2 (Windows NT 10.0; WOW64) App_Bitness/32 Version/15.2-Git:20151019-02e7013") from core import downloadtools from core import ziptools downloadtools.downloadfile(url, path_down, continuar=True, headers=[header]) unzipper = ziptools.ziptools() unzipper.extract(path_down, path_unzip) xbmc.executebuiltin('UpdateLocalAddons') strSettings = '<settings>\n' \ ' <setting id="fanart" value="true" />\n' \ ' <setting id="keeporiginaltitle" value="false" />\n' \ ' <setting id="language" value="es" />\n' \ '</settings>' path_settings = xbmc.translatePath( "special://profile/addon_data/metadata.tvshows.themoviedb.org/settings.xml") tv_themoviedb_addon_path = filetools.dirname(path_settings) if not filetools.exists(tv_themoviedb_addon_path): filetools.mkdir(tv_themoviedb_addon_path) if filetools.write(path_settings, strSettings): continuar = True except: pass continuar = (install and continuar) if not continuar: msg_text = "The Movie Database no instalado." idPath = 0 idParentPath = 0 if continuar: continuar = False # Buscamos el idPath sql = 'SELECT MAX(idPath) FROM path' nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idPath = records[0][0] + 1 sql_videolibrarypath = videolibrarypath if sql_videolibrarypath.startswith("special://"): sql_videolibrarypath = sql_videolibrarypath.replace('/profile/', '/%/').replace('/home/userdata/', '/%/') sep = '/' elif sql_videolibrarypath.startswith("smb://"): sep = '/' else: sep = os.sep if not sql_videolibrarypath.endswith(sep): sql_videolibrarypath += sep # Buscamos el idParentPath sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_videolibrarypath nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idParentPath = records[0][0] videolibrarypath = records[0][1][:-1] continuar = True else: # No existe videolibrarypath en la BD: la insertamos sql_videolibrarypath = videolibrarypath if not sql_videolibrarypath.endswith(sep): sql_videolibrarypath += sep sql = 'INSERT INTO path (idPath, strPath, scanRecursive, useFolderNames, noUpdate, exclude) VALUES ' \ '(%s, "%s", 0, 0, 0, 0)' % (idPath, sql_videolibrarypath) nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True idParentPath = idPath idPath += 1 else: msg_text = "Error al fijar videolibrarypath en BD" if continuar: continuar = False # Fijamos strContent, strScraper, scanRecursive y strSettings if content_type == 'movie': strContent = 'movies' strScraper = 'metadata.themoviedb.org' scanRecursive = 2147483647 strSettings = "<settings><setting id='RatingS' value='TMDb' /><setting id='certprefix' value='Rated ' />" \ "<setting id='fanart' value='true' /><setting id='keeporiginaltitle' value='false' />" \ "<setting id='language' value='es' /><setting id='tmdbcertcountry' value='us' />" \ "<setting id='trailer' value='true' /></settings>" strActualizar = "¿Desea configurar este Scraper en español como opción por defecto para películas?" if not videolibrarypath.endswith(sep): videolibrarypath += sep strPath = videolibrarypath + config.get_setting("folder_movies") + sep else: strContent = 'tvshows' strScraper = 'metadata.tvdb.com' scanRecursive = 0 strSettings = "<settings><setting id='RatingS' value='TheTVDB' />" \ "<setting id='absolutenumber' value='false' />" \ "<setting id='dvdorder' value='false' />" \ "<setting id='fallback' value='true' />" \ "<setting id='fanart' value='true' />" \ "<setting id='language' value='es' /></settings>" strActualizar = "¿Desea configurar este Scraper en español como opción por defecto para series?" if not videolibrarypath.endswith(sep): videolibrarypath += sep strPath = videolibrarypath + config.get_setting("folder_tvshows") + sep logger.info("%s: %s" % (content_type, strPath)) # Comprobamos si ya existe strPath en la BD para evitar duplicados sql = 'SELECT idPath FROM path where strPath="%s"' % strPath nun_records, records = execute_sql_kodi(sql) sql = "" if nun_records == 0: # Insertamos el scraper sql = 'INSERT INTO path (idPath, strPath, strContent, strScraper, scanRecursive, useFolderNames, ' \ 'strSettings, noUpdate, exclude, idParentPath) VALUES (%s, "%s", "%s", "%s", %s, 0, ' \ '"%s", 0, 0, %s)' % ( idPath, strPath, strContent, strScraper, scanRecursive, strSettings, idParentPath) else: if not silent: # Preguntar si queremos configurar themoviedb.org como opcion por defecto actualizar = platformtools.dialog_yesno("The TVDB", strActualizar) else: actualizar = True if actualizar: # Actualizamos el scraper idPath = records[0][0] sql = 'UPDATE path SET strContent="%s", strScraper="%s", scanRecursive=%s, strSettings="%s" ' \ 'WHERE idPath=%s' % (strContent, strScraper, scanRecursive, strSettings, idPath) if sql: nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True if not continuar: msg_text = "Error al configurar el scraper en la BD." if not continuar: heading = "Videoteca %s no configurada" % content_type elif content_type == 'SERIES' and not xbmc.getCondVisibility( 'System.HasAddon(metadata.tvshows.themoviedb.org)'): heading = "Videoteca %s configurada" % content_type msg_text = "Es necesario reiniciar Kodi para que los cambios surtan efecto." else: heading = "Videoteca %s configurada" % content_type msg_text = "Felicidades la videoteca de Kodi ha sido configurada correctamente." platformtools.dialog_notification(heading, msg_text, icon=1, time=10000) logger.info("%s: %s" % (heading, msg_text))
def error(itemlist): message = config.get_localized_string(70713) heading = itemlist[0].fulltitle.strip() platformtools.dialog_notification(heading, message) return itemlist
def acciones_cuenta(item): logger.info() itemlist = [] if "Tus fichas" in item.title: itemlist.append(item.clone(title="Capítulos", url="tf_block_c a", contentType="tvshow")) itemlist.append(item.clone(title="Series", url="tf_block_s", contentType="tvshow")) itemlist.append(item.clone(title="Películas", url="tf_block_p")) itemlist.append(item.clone(title="Documentales", url="tf_block_d")) return itemlist elif "Añadir a una lista" in item.title: data = httptools.downloadpage(host + "/c_listas.php?apikey=%s&sid=%s" % (apikey, sid)).data data = json.Xml2Json(data).result itemlist.append(item.clone(title="Crear nueva lista", folder=False)) if data["Data"]["TusListas"] != "\t": import random data = data["Data"]["TusListas"]["Item"] if type(data) is not list: data = [data] for child in data: image = "" title = "%s (%s fichas)" % (child["Title"], child["FichasInList"]) images = [] for i in range(1, 5): if "sinimagen.png" not in child["Poster%s" % i]: images.append(child["Poster%s" % i].replace("/100/", "/400/")) if images: image = images[random.randint(0, len(images) - 1)] url = host + "/data.php?mode=add_listas&apikey=%s&sid=%s&ficha_id=%s" % (apikey, sid, item.ficha) post = "lista_id[]=%s" % child["Id"] itemlist.append(item.clone(title=title, url=url, post=post, thumbnail=image, folder=False)) return itemlist elif "Crear nueva lista" in item.title: from platformcode import platformtools nombre = platformtools.dialog_input("", "Introduce un nombre para la lista") if nombre: dict_priv = {0: 'Pública', 1: 'Privada'} priv = platformtools.dialog_select("Privacidad de la lista", ['Pública', 'Privada']) if priv != -1: url = host + "/data.php?mode=create_list&apikey=%s&sid=%s" % (apikey, sid) post = "name=%s&private=%s" % (nombre, priv) data = httptools.downloadpage(url, post) platformtools.dialog_notification("Lista creada correctamente", "Nombre: %s - %s" % (nombre, dict_priv[priv])) platformtools.itemlist_refresh() return elif re.search(r"(?i)Seguir Lista", item.title): from platformcode import platformtools data = httptools.downloadpage(item.url) platformtools.dialog_notification("Operación realizada con éxito", "Lista: %s" % item.lista) return elif item.post: from platformcode import platformtools data = httptools.downloadpage(item.url, item.post).data platformtools.dialog_notification("Ficha añadida a la lista", "Lista: %s" % item.title) platformtools.itemlist_refresh() return data = httptools.downloadpage("https://playmax.mx/tusfichas.php").data data = re.sub(r"\n|\r|\t|\s{2}| |<br>", "", data) bloque = scrapertools.find_single_match(data, item.url + '">(.*?)(?:<div class="tf_blocks|<div class="tf_o_move">)') matches = scrapertools.find_multiple_matches(bloque, '<div class="tf_menu_mini">([^<]+)<(.*?)<cb></cb></div>') for category, contenido in matches: itemlist.append(item.clone(action="", title=category, text_color=color3)) patron = '<div class="c_fichas_image">.*?href="\.([^"]+)".*?src="\.([^"]+)".*?serie="([^"]*)".*?' \ '<div class="c_fichas_title">(?:<div class="c_fichas_episode">([^<]+)</div>|)([^<]+)</div>' entradas = scrapertools.find_multiple_matches(contenido, patron) for scrapedurl, scrapedthumbnail, serie, episodio, scrapedtitle in entradas: tipo = "movie" scrapedurl = host + scrapedurl scrapedthumbnail = host + scrapedthumbnail action = "findvideos" if __menu_info__: action = "menu_info" if serie: tipo = "tvshow" if episodio: title = " %s - %s" % (episodio.replace("X", "x"), scrapedtitle) else: title = " " + scrapedtitle new_item = Item(channel=item.channel, action=action, title=title, url=scrapedurl, thumbnail=scrapedthumbnail, contentTitle=scrapedtitle, contentType=tipo, text_color=color2) if new_item.contentType == "tvshow": new_item.show = scrapedtitle if not __menu_info__: new_item.action = "episodios" itemlist.append(new_item) return itemlist
def semiautomatic_config_item(item): log() # Configurazione Semi Automatica, utile in caso la numerazione automatica fallisca tvdb.find_and_set_infoLabels(item) item.channel = item.from_channel dict_series = load(item) title = item.fulltitle.rstrip() # Trova l'ID della serie while not item.infoLabels['tvdb_id']: try: item.show = platformtools.dialog_input( default=item.show, heading=config.get_localized_string( 30112)) # <- Enter title to search tvdb.find_and_set_infoLabels(item) except: heading = config.get_localized_string( 70704) # <- TMDB ID (0 to cancel) info = platformtools.dialog_numeric(0, heading) item.infoLabels['tvdb_id'] = '0' if info == '' else info if item.infoLabels['tvdb_id']: ID = item.infoLabels['tvdb_id'] dict_renumerate = {TAG_ID: ID} dict_series[title] = dict_renumerate # Trova la Stagione if any(word in title.lower() for word in ['specials', 'speciali']): heading = config.get_localized_string( 70686 ) # <- Enter the number of the starting season (for specials) season = platformtools.dialog_numeric(0, heading, '0') dict_renumerate[TAG_SEASON] = season elif RepresentsInt(title.split()[-1]): heading = config.get_localized_string( 70686 ) # <- Enter the number of the starting season (for season > 1) season = platformtools.dialog_numeric(0, heading, title.split()[-1]) dict_renumerate[TAG_SEASON] = season else: heading = config.get_localized_string( 70686 ) # <- Enter the number of the starting season (for season 1) season = platformtools.dialog_numeric(0, heading, '1') dict_renumerate[TAG_SEASON] = season mode = platformtools.dialog_yesno( config.get_localized_string(70687), config.get_localized_string(70688), nolabel=config.get_localized_string(30023), yeslabel=config.get_localized_string(30022)) if mode == True: dict_renumerate[TAG_MODE] = False if TAG_SPECIAL in dict_series[title]: specials = dict_renumerate[TAG_SPECIAL] else: specials = [] write(item, dict_series) _list = [] itemlist = find_episodes(item) for item in itemlist: Title = re.sub(r'\d+x\d+ - ', '', item.title) if item.action == 'findvideos': _list.append(Title) selected = platformtools.dialog_multiselect( config.get_localized_string(70734), _list) # if len(selected) > 0: for select in selected: specials.append( int(scrapertools.find_single_match(_list[select], r'(\d+)'))) dict_renumerate[TAG_SPECIAL] = specials dict_renumerate[TAG_MODE] = False dict_renumerate[TAG_TYPE] = 'auto' dict_renumerate[TAG_EPISODE] = '' write(item, dict_series) # xbmc.executebuiltin("Container.Refresh") else: message = config.get_localized_string(60444) heading = item.fulltitle.strip() platformtools.dialog_notification(heading, message)
def get_video_url(page_url, premium=False, user="", password="", video_password=""): logger.info("url=" + page_url) pfxfx = "" data = flashx_data data = data.replace("\n", "") cgi_counter = scrapertools.find_single_match(data, """(?is)src=.(https://www.flashx.../counter.cgi.*?[^(?:'|")]+)""") cgi_counter = cgi_counter.replace("%0A", "").replace("%22", "") playnow = scrapertools.find_single_match(data, 'https://www.flashx.../dl[^"]+') # Para obtener el f y el fxfx js_fxfx = "https://www." + scrapertools.find_single_match(data.replace("//", "/"), """(?is)(flashx.../js\w+/c\w+.*?[^(?:'|")]+)""") if len(js_fxfx) > 15: data_fxfx = httptools.downloadpage(js_fxfx).data mfxfx = scrapertools.find_single_match(data_fxfx, 'get.*?({.*?})').replace("'", "").replace(" ", "") matches = scrapertools.find_multiple_matches(mfxfx, '(\w+):(\w+)') for f, v in matches: pfxfx += f + "=" + v + "&" logger.info("mfxfxfx1= %s" % js_fxfx) logger.info("mfxfxfx2= %s" % pfxfx) if pfxfx == "": pfxfx = "f=fail&fxfx=6" coding_url = 'https://www.flashx.co/flashx.php?%s' % pfxfx # Obligatorio descargar estos 2 archivos, porque si no, muestra error httptools.downloadpage(coding_url, cookies=False) httptools.downloadpage(cgi_counter, cookies=False) ts = int(time.time()) flash_ts = scrapertools.find_single_match(flashx_hash_f, '-(\d{10})-') wait_time = int(flash_ts) - ts platformtools.dialog_notification('Cargando flashx', 'Espera de %s segundos requerida' % wait_time) try: time.sleep(wait_time) except: time.sleep(6) data = httptools.downloadpage(playnow, post = flashx_post).data # Si salta aviso, se carga la pagina de comprobacion y luego la inicial # LICENSE GPL3, de alfa-addon: https://github.com/alfa-addon/ ES OBLIGATORIO AÑADIR ESTAS LÍNEAS if "You try to access this video with Kodi" in data: url_reload = scrapertools.find_single_match(data, 'try to reload the page.*?href="([^"]+)"') try: data = httptools.downloadpage(url_reload).data data = httptools.downloadpage(playnow, post = flashx_post).data # LICENSE GPL3, de alfa-addon: https://github.com/alfa-addon/ ES OBLIGATORIO AÑADIR ESTAS LÍNEAS except: pass matches = scrapertools.find_multiple_matches(data, "(eval\(function\(p,a,c,k.*?)\s+</script>") video_urls = [] for match in matches: try: match = jsunpack.unpack(match) match = match.replace("\\'", "'") media_urls = scrapertools.find_multiple_matches(match, "{src:'([^']+)'.*?,label:'([^']+)'") subtitle = "" for media_url, label in media_urls: if media_url.endswith(".srt") and label == "Spanish": try: from core import filetools data = httptools.downloadpage(media_url) subtitle = os.path.join(config.get_data_path(), 'sub_flashx.srt') filetools.write(subtitle, data) except: import traceback logger.info("Error al descargar el subtítulo: " + traceback.format_exc()) for media_url, label in media_urls: if not media_url.endswith("png") and not media_url.endswith(".srt"): video_urls.append(["." + media_url.rsplit('.', 1)[1] + " [flashx]", media_url, 0, subtitle]) for video_url in video_urls: logger.info("%s - %s" % (video_url[0], video_url[1])) except: pass return video_urls
def set_content(content_type, silent=False): """ Procedimiento para auto-configurar la videoteca de kodi con los valores por defecto @type content_type: str ('movie' o 'tvshow') @param content_type: tipo de contenido para configurar, series o peliculas """ continuar = True msg_text = "" videolibrarypath = config.get_setting("videolibrarypath") if content_type == 'movie': scraper = [config.get_localized_string(70093), config.get_localized_string(70096)] seleccion = platformtools.dialog_select(config.get_localized_string(70094), scraper) # Instalar The Movie Database if seleccion == -1 or seleccion == 0: if not xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)'): if not silent: # Preguntar si queremos instalar metadata.themoviedb.org install = platformtools.dialog_yesno(config.get_localized_string(60046)) else: install = True if install: try: # Instalar metadata.themoviedb.org xbmc.executebuiltin('InstallAddon(metadata.themoviedb.org)', True) logger.info("Instalado el Scraper de películas de TheMovieDB") except: pass continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)')) if not continuar: msg_text = config.get_localized_string(60047) if continuar: xbmc.executebuiltin('Addon.OpenSettings(metadata.themoviedb.org)', True) # Instalar Universal Movie Scraper elif seleccion == 1: if continuar and not xbmc.getCondVisibility('System.HasAddon(metadata.universal)'): continuar = False if not silent: # Preguntar si queremos instalar metadata.universal install = platformtools.dialog_yesno(config.get_localized_string(70095)) else: install = True if install: try: xbmc.executebuiltin('InstallAddon(metadata.universal)', True) if xbmc.getCondVisibility('System.HasAddon(metadata.universal)'): continuar = True except: pass continuar = (install and continuar) if not continuar: msg_text = config.get_localized_string(70097) if continuar: xbmc.executebuiltin('Addon.OpenSettings(metadata.universal)', True) else: # SERIES scraper = [config.get_localized_string(70098), config.get_localized_string(70093)] seleccion = platformtools.dialog_select(config.get_localized_string(70107), scraper) # Instalar The TVDB if seleccion == -1 or seleccion == 0: if not xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)'): if not silent: # Preguntar si queremos instalar metadata.tvdb.com install = platformtools.dialog_yesno(config.get_localized_string(60048)) else: install = True if install: try: # Instalar metadata.tvdb.com xbmc.executebuiltin('InstallAddon(metadata.tvdb.com)', True) logger.info("Instalado el Scraper de series de The TVDB") except: pass continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)')) if not continuar: msg_text = config.get_localized_string(70099) if continuar: xbmc.executebuiltin('Addon.OpenSettings(metadata.tvdb.com)', True) # Instalar The Movie Database elif seleccion == 1: if continuar and not xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'): continuar = False if not silent: # Preguntar si queremos instalar metadata.tvshows.themoviedb.org install = platformtools.dialog_yesno(config.get_localized_string(70100)) else: install = True if install: try: # Instalar metadata.tvshows.themoviedb.org xbmc.executebuiltin('InstallAddon(metadata.tvshows.themoviedb.org)', True) if xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'): continuar = True except: pass continuar = (install and continuar) if not continuar: msg_text = config.get_localized_string(60047) if continuar: xbmc.executebuiltin('Addon.OpenSettings(metadata.tvshows.themoviedb.org)', True) idPath = 0 idParentPath = 0 if continuar: continuar = False # Buscamos el idPath sql = 'SELECT MAX(idPath) FROM path' nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idPath = records[0][0] + 1 sql_videolibrarypath = videolibrarypath if sql_videolibrarypath.startswith("special://"): sql_videolibrarypath = sql_videolibrarypath.replace('/profile/', '/%/').replace('/home/userdata/', '/%/') sep = '/' elif scrapertools.find_single_match(sql_videolibrarypath, '(^\w+:\/\/)'): sep = '/' else: sep = os.sep if not sql_videolibrarypath.endswith(sep): sql_videolibrarypath += sep # Buscamos el idParentPath sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_videolibrarypath nun_records, records = execute_sql_kodi(sql) if nun_records == 1: idParentPath = records[0][0] videolibrarypath = records[0][1][:-1] continuar = True else: # No existe videolibrarypath en la BD: la insertamos sql_videolibrarypath = videolibrarypath if not sql_videolibrarypath.endswith(sep): sql_videolibrarypath += sep sql = 'INSERT INTO path (idPath, strPath, scanRecursive, useFolderNames, noUpdate, exclude) VALUES ' \ '(%s, "%s", 0, 0, 0, 0)' % (idPath, sql_videolibrarypath) nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True idParentPath = idPath idPath += 1 else: msg_text = config.get_localized_string(70101) if continuar: continuar = False # Fijamos strContent, strScraper, scanRecursive y strSettings if content_type == 'movie': strContent = 'movies' scanRecursive = 2147483647 useFolderNames = 1 if seleccion == -1 or seleccion == 0: strScraper = 'metadata.themoviedb.org' path_settings = filetools.translatePath("special://profile/addon_data/metadata.themoviedb.org/settings.xml") elif seleccion == 1: strScraper = 'metadata.universal' path_settings = filetools.translatePath("special://profile/addon_data/metadata.universal/settings.xml") settings_data = filetools.read(path_settings) strSettings = ' '.join(settings_data.split()).replace("> <", "><") strSettings = strSettings.replace("\"","\'") strActualizar = "¿Desea configurar este Scraper en español como opción por defecto para películas?" if not videolibrarypath.endswith(sep): videolibrarypath += sep strPath = videolibrarypath + config.get_setting("folder_movies") + sep else: strContent = 'tvshows' scanRecursive = 0 useFolderNames = 0 if seleccion == -1 or seleccion == 0: strScraper = 'metadata.tvdb.com' path_settings = filetools.translatePath("special://profile/addon_data/metadata.tvdb.com/settings.xml") elif seleccion == 1: strScraper = 'metadata.tvshows.themoviedb.org' path_settings = filetools.translatePath("special://profile/addon_data/metadata.tvshows.themoviedb.org/settings.xml") settings_data = filetools.read(path_settings) strSettings = ' '.join(settings_data.split()).replace("> <", "><") strSettings = strSettings.replace("\"","\'") strActualizar = "¿Desea configurar este Scraper en español como opción por defecto para series?" if not videolibrarypath.endswith(sep): videolibrarypath += sep strPath = videolibrarypath + config.get_setting("folder_tvshows") + sep logger.info("%s: %s" % (content_type, strPath)) # Comprobamos si ya existe strPath en la BD para evitar duplicados sql = 'SELECT idPath FROM path where strPath="%s"' % strPath nun_records, records = execute_sql_kodi(sql) sql = "" if nun_records == 0: # Insertamos el scraper sql = 'INSERT INTO path (idPath, strPath, strContent, strScraper, scanRecursive, useFolderNames, ' \ 'strSettings, noUpdate, exclude, idParentPath) VALUES (%s, "%s", "%s", "%s", %s, %s, ' \ '"%s", 0, 0, %s)' % ( idPath, strPath, strContent, strScraper, scanRecursive, useFolderNames, strSettings, idParentPath) else: if not silent: # Preguntar si queremos configurar themoviedb.org como opcion por defecto actualizar = platformtools.dialog_yesno(config.get_localized_string(70098), strActualizar) else: actualizar = True if actualizar: # Actualizamos el scraper idPath = records[0][0] sql = 'UPDATE path SET strContent="%s", strScraper="%s", scanRecursive=%s, useFolderNames=%s, strSettings="%s" ' \ 'WHERE idPath=%s' % (strContent, strScraper, scanRecursive, useFolderNames, strSettings, idPath) if sql: nun_records, records = execute_sql_kodi(sql) if nun_records == 1: continuar = True if not continuar: msg_text = config.get_localized_string(60055) if not continuar: heading = config.get_localized_string(70102) % content_type elif content_type == 'SERIES' and not xbmc.getCondVisibility( 'System.HasAddon(metadata.tvshows.themoviedb.org)'): heading = config.get_localized_string(70103) % content_type msg_text = config.get_localized_string(60058) else: heading = config.get_localized_string(70103) % content_type msg_text = config.get_localized_string(70104) platformtools.dialog_notification(heading, msg_text, icon=1, time=3000) logger.info("%s: %s" % (heading, msg_text))
def delete(item): def delete_all(_item): for file in filetools.listdir(_item.path): if file.endswith(".strm") or file.endswith( ".nfo") or file.endswith(".json") or file.endswith( ".torrent"): filetools.remove(filetools.join(_item.path, file)) raiz, carpeta_serie, ficheros = filetools.walk(_item.path).next() if ficheros == []: filetools.rmdir(_item.path) if config.is_xbmc(): import xbmc # esperamos 3 segundos para dar tiempo a borrar los ficheros xbmc.sleep(3000) # TODO mirar por qué no funciona al limpiar en la videoteca de Kodi al añadirle un path # limpiamos la videoteca de Kodi from platformcode import xbmc_videolibrary xbmc_videolibrary.clean() logger.info("Eliminados todos los enlaces") platformtools.itemlist_refresh() # logger.info(item.contentTitle) # logger.debug(item.tostring('\n')) if item.contentType == 'movie': heading = config.get_localized_string(70084) else: heading = config.get_localized_string(70085) if item.multicanal: # Obtener listado de canales if item.dead == '': opciones = [ config.get_localized_string(70086) % k.capitalize() for k in item.library_urls.keys() if k != "downloads" ] opciones.insert(0, heading) index = platformtools.dialog_select( config.get_localized_string(30163), opciones) if index == 0: # Seleccionado Eliminar pelicula/serie delete_all(item) elif index > 0: # Seleccionado Eliminar canal X canal = opciones[index].replace( config.get_localized_string(70079), "").lower() else: return else: canal = item.dead num_enlaces = 0 for fd in filetools.listdir(item.path): if fd.endswith(canal + '].json') or scrapertools.find_single_match( fd, '%s]_\d+.torrent' % canal): if filetools.remove(filetools.join(item.path, fd)): num_enlaces += 1 if num_enlaces > 0: # Actualizar .nfo head_nfo, item_nfo = videolibrarytools.read_nfo(item.nfo) del item_nfo.library_urls[canal] if item_nfo.emergency_urls and item_nfo.emergency_urls.get( canal, False): del item_nfo.emergency_urls[canal] filetools.write(item.nfo, head_nfo + item_nfo.tojson()) msg_txt = config.get_localized_string(70087) % (num_enlaces, canal) logger.info(msg_txt) platformtools.dialog_notification(heading, msg_txt) platformtools.itemlist_refresh() else: if platformtools.dialog_yesno( heading, config.get_localized_string(70088) % item.infoLabels['title']): delete_all(item)
def check_addon_updates(verbose=False): logger.info() # Forzamos la actualización de los repos para facilitar la actualización del addon Alfa xbmc.executebuiltin('UpdateAddonRepos') ADDON_UPDATES_JSON = 'https://extra.alfa-addon.com/addon_updates/updates.json' ADDON_UPDATES_ZIP = 'https://extra.alfa-addon.com/addon_updates/updates.zip' try: get_ua_list() except: pass try: last_fix_json = os.path.join(config.get_runtime_path(), 'last_fix.json') # información de la versión fixeada del usuario # Se guarda en get_runtime_path en lugar de get_data_path para que se elimine al cambiar de versión try: localfilename = os.path.join(config.get_data_path(), 'temp_updates.zip') if os.path.exists(localfilename): os.remove(localfilename) except: pass # Descargar json con las posibles actualizaciones # ----------------------------------------------- data = httptools.downloadpage(ADDON_UPDATES_JSON, timeout=5).data if data == '': logger.info('No se encuentran actualizaciones del addon') if verbose: dialog_notification('Alfa ya está actualizado', 'No hay ninguna actualización urgente') check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return False data = jsontools.load(data) if 'addon_version' not in data or 'fix_version' not in data: logger.info('No hay actualizaciones del addon') if verbose: dialog_notification('Alfa ya está actualizado', 'No hay ninguna actualización urgente') check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return False # Comprobar versión que tiene instalada el usuario con versión de la actualización # -------------------------------------------------------------------------------- current_version = config.get_addon_version(with_fix=False, from_xml=True) if current_version != data['addon_version']: logger.info('No hay actualizaciones para la versión %s del addon' % current_version) if verbose: dialog_notification('Alfa ya está actualizado', 'No hay ninguna actualización urgente') check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return False if os.path.exists(last_fix_json): try: lastfix = {} lastfix = jsontools.load(open(last_fix_json, "r").read()) if lastfix['addon_version'] == data['addon_version'] and lastfix['fix_version'] == data['fix_version']: logger.info('Ya está actualizado con los últimos cambios. Versión %s.fix%d' % (data['addon_version'], data['fix_version'])) if verbose: dialog_notification('Alfa ya está actualizado', 'Versión %s.fix%d' % (data['addon_version'], data['fix_version'])) check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return False except: if lastfix: logger.error('last_fix.json: ERROR en: ' + str(lastfix)) else: logger.error('last_fix.json: ERROR desconocido') lastfix = {} # Descargar zip con las actualizaciones # ------------------------------------- downloadtools.downloadfile(ADDON_UPDATES_ZIP, localfilename, silent=True) # Descomprimir zip dentro del addon # --------------------------------- try: unzipper = ziptools.ziptools() unzipper.extract(localfilename, config.get_runtime_path()) except: xbmc.executebuiltin('Extract("%s", "%s")' % (localfilename, config.get_runtime_path())) time.sleep(1) # Borrar el zip descargado # ------------------------ try: os.remove(localfilename) except: pass # Si es PY3 se actualizan los módulos marshal if PY3: from platformcode.custom_code import marshal_check marshal_check() # Guardar información de la versión fixeada # ----------------------------------------- if 'files' in data: data.pop('files', None) open(last_fix_json, "w").write(jsontools.dump(data)) logger.info('Addon actualizado correctamente a %s.fix%d' % (data['addon_version'], data['fix_version'])) if verbose: dialog_notification('Alfa actualizado a', 'Versión %s.fix%d' % (data['addon_version'], data['fix_version'])) check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return True except: logger.error('Error al comprobar actualizaciones del addon!') logger.error(traceback.format_exc()) if verbose: dialog_notification('Alfa actualizaciones', 'Error al comprobar actualizaciones') check_update_to_others(verbose=verbose) # Comprueba las actualuzaciones de otros productos return False
def channel_status(item, dict_values): try: for k in dict_values: if k == "all_channels": logger.info("Todos los canales | Estado seleccionado: %s" % dict_values[k]) if dict_values[k] != 0: excluded_channels = [ 'url', 'search', 'videolibrary', 'setting', 'news', 'help', 'downloads' ] for channel in item.channel_list: if channel.channel not in excluded_channels: from core import channeltools channel_parameters = channeltools.get_channel_parameters( channel.channel) new_status_all = None new_status_all_default = channel_parameters[ "active"] # Opcion Activar todos if dict_values[k] == 1: new_status_all = True # Opcion Desactivar todos if dict_values[k] == 2: new_status_all = False # Opcion Recuperar estado por defecto if dict_values[k] == 3: # Si tiene "enabled" en el _data.json es porque el estado no es el del channel.json if config.get_setting("enabled", channel.channel): new_status_all = new_status_all_default # Si el canal no tiene "enabled" en el _data.json no se guarda, se pasa al siguiente else: continue # Se guarda el estado del canal if new_status_all is not None: config.set_setting("enabled", new_status_all, channel.channel) break else: continue else: logger.info("Canal: %s | Estado: %s" % (k, dict_values[k])) config.set_setting("enabled", dict_values[k], k) logger.info("el valor esta como %s " % config.get_setting("enabled", k)) platformtools.itemlist_update( Item(channel=CHANNELNAME, action="mainlist")) except: import traceback logger.error("Detalle del error: %s" % traceback.format_exc()) platformtools.dialog_notification(config.get_localized_string(60579), config.get_localized_string(60580))
def init(channel, list_servers, list_quality, reset=False): ''' Comprueba la existencia de canal en el archivo de configuracion de Autoplay y si no existe lo añade. Es necesario llamar a esta funcion al entrar a cualquier canal que incluya la funcion Autoplay. :param channel: (str) id del canal :param list_servers: (list) lista inicial de servidores validos para el canal. No es necesario incluirlos todos, ya que la lista de servidores validos se ira actualizando dinamicamente. :param list_quality: (list) lista inicial de calidades validas para el canal. No es necesario incluirlas todas, ya que la lista de calidades validas se ira actualizando dinamicamente. :return: (bool) True si la inicializacion ha sido correcta. ''' logger.info() change = False result = True if not config.is_xbmc(): # platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi') result = False else: autoplay_path = os.path.join(config.get_data_path(), "settings_channels", 'autoplay_data.json') if os.path.exists(autoplay_path): autoplay_node = jsontools.get_node_from_file( 'autoplay', "AUTOPLAY") else: change = True autoplay_node = {"AUTOPLAY": {}} if channel not in autoplay_node or reset: change = True # Se comprueba que no haya calidades ni servidores duplicados if 'default' not in list_quality: list_quality.append('default') # list_servers = list(set(list_servers)) # list_quality = list(set(list_quality)) # Creamos el nodo del canal y lo añadimos channel_node = { "servers": list_servers, "quality": list_quality, "settings": { "active": False, "plan_b": True, "custom_servers": False, "custom_quality": False, "priority": 0 } } for n in range(1, 4): s = c = 0 if len(list_servers) >= n: s = n - 1 if len(list_quality) >= n: c = n - 1 channel_node["settings"]["server_%s" % n] = s channel_node["settings"]["quality_%s" % n] = c autoplay_node[channel] = channel_node if change: result, json_data = jsontools.update_node(autoplay_node, 'autoplay', 'AUTOPLAY') if not result: heading = config.get_localized_string(60077) msj = config.get_localized_string(60078) icon = 1 platformtools.dialog_notification(heading, msj, icon, sound=False) return result
def init(): logger.info() """ Todo el código añadido al add-on se borra con cada actualización. Esta función permite restaurarlo automáticamente con cada actualización. Esto permite al usuario tener su propio código, bajo su responsabilidad, y restaurarlo al add-on cada vez que se actualiza. El mecanismo funciona copiando el contenido de la carpeta-arbol "./userdata/addon_data/plugin.video.alfa/custom_code/..." sobre las carpetas de código del add-on. No verifica el contenido, solo vuelca(reemplaza) el contenido de "custom_code". El usuario almacenará en las subcarpetas de "custom_code" su código actualizado y listo para ser copiado en cualquier momento. Si no se desea que copie algo, simplemente se borra de "custom_code" y ya no se copiará en la próxima actualización. Los pasos que sigue esta función, son los siguientes: 1.- La función se llama desde videolibrary_service.py, desde la función inicial: # Copia Custom code a las carpetas de Alfa desde la zona de Userdata from platformcode import custom_code custom_code.init() 2.- En el inicio de Kodi, comprueba si existe la carpeta "custom_code" en "./userdata/addon_data/plugin.video.alfa/". Si no existe, la crea y sale sin más, dando al ususario la posibilidad de copiar sobre esa estructura su código, y que la función la vuelque sobre el add-on en el próximo inicio de Kodi. 3.- En el siguiente inicio de Kodi, comprueba si existe el custom_code.json en la carpeta root del add-on. Si no existe, lo crea con el número de versión del add-on vacío, para permitir que se copien los archivos en esta pasada. 4.- Verifica que el número de versión del add-on es diferente de el de custom_code.json. Si es la misma versión, se sale porque ya se realizo la copia anteriormente. Si la versión es distinta, se realiza el volcado de todos los archivos de la carpeta-árbol "custom_code" sobre el add-on. Si la carpeta de destino no existe, dará un error y se cancelará la copia. Se considera que no tienen sentido nuevas carpetas. 5.- Si la copia ha terminado con éxito, se actualiza el custom_code.json con el número de versión del add-on, para que en inicios sucesivos de Kodi no se realicen las copias, hasta que el add-on cambie de versión. En el número de versión del add-on no se considera el número de fix. Tiempos: Copiando 7 archivos de prueba, el proceso ha tardado una décima de segundo. """ try: #Se realizan algunas funciones con cada nueva versión de Alfa if not filetools.exists( filetools.join(config.get_runtime_path(), 'custom_code.json')): config.set_setting( 'cf_assistant_ua', '') # Se limpia CF_UA. Mejora de rendimiento en httptools CF #Comprime la BD de cache de TMDB para evitar que crezca demasiado bd_tmdb_maintenance() if config.get_setting('tmdb_cache_expire', default=4) == 4: config.set_setting('tmdb_cache_expire', 2) #Verifica si es necsario instalar script.alfa-update-helper verify_script_alfa_update_helper() #Borra el .zip de instalación de Alfa de la carpeta Packages, por si está corrupto, y que así se pueda descargar de nuevo version = 'plugin.video.alfa-%s.zip' % config.get_addon_version( with_fix=False) filetools.remove( filetools.join('special://home', 'addons', 'packages', version), True) #Borrar contenido de carpeta de Torrents y de Subtitles filetools.rmdirtree(filetools.join(config.get_videolibrary_path(), 'temp_torrents_Alfa'), silent=True) subtitle_path = config.get_kodi_setting("subtitles.custompath") if subtitle_path and filetools.exists(subtitle_path): for file in filetools.listdir(subtitle_path): if not file.endswith('.srt'): continue file_path = filetools.join(subtitle_path, file) ret = filetools.remove(file_path, silent=True) if not ret: logger.error('ERROR on REMOVING subtitle: ' + file_path) #Verifica si Kodi tiene algún achivo de Base de Datos de Vídeo de versiones anteriores, entonces los borra verify_Kodi_video_DB() #Verifica si la Base de Datos de Vídeo tiene la fuente de CINE con useFolderNames=1 set_Kodi_video_DB_useFolderNames() #LIBTORRENT: se descarga el binario de Libtorrent cada vez que se actualiza Alfa try: threading.Thread(target=update_libtorrent).start( ) # Creamos un Thread independiente, hasta el fin de Kodi time.sleep(2) # Dejamos terminar la inicialización... except: # Si hay problemas de threading, nos vamos logger.error(traceback.format_exc()) #QUASAR: Preguntamos si se hacen modificaciones a Quasar if not filetools.exists(filetools.join(config.get_data_path(), "quasar.json")) \ and not config.get_setting('addon_quasar_update', default=False): question_update_external_addon("quasar") #QUASAR: Hacemos las modificaciones a Quasar, si está permitido, y si está instalado if config.get_setting('addon_quasar_update', default=False) or \ (filetools.exists(filetools.join(config.get_data_path(), \ "quasar.json")) and not xbmc.getCondVisibility('System.HasAddon("plugin.video.quasar")')): if not update_external_addon("quasar"): platformtools.dialog_notification( "Actualización Quasar", "Ha fallado. Consulte el log") #Existe carpeta "custom_code" ? Si no existe se crea y se sale custom_code_dir = filetools.join(config.get_data_path(), 'custom_code') if not filetools.exists(custom_code_dir): create_folder_structure(custom_code_dir) return else: #Existe "custom_code.json" ? Si no existe se crea custom_code_json_path = config.get_runtime_path() custom_code_json = filetools.join(custom_code_json_path, 'custom_code.json') if not filetools.exists(custom_code_json): create_json(custom_code_json_path) #Se verifica si la versión del .json y del add-on son iguales. Si es así se sale. Si no se copia "custom_code" al add-on verify_copy_folders(custom_code_dir, custom_code_json_path) #Si se han quedado "colgadas" descargas con archivos .RAR, se intenta identificarlos y reactivar el UnRar reactivate_unrar(init=True, mute=True) #Inicia un rastreo de vídeos decargados desde .torrent: marca los VISTOS y elimina los controles de los BORRADOS from servers import torrent try: threading.Thread(target=torrent.mark_torrent_as_watched).start( ) # Creamos un Thread independiente, hasta el fin de Kodi time.sleep(2) # Dejamos terminar la inicialización... except: # Si hay problemas de threading, nos vamos logger.error(traceback.format_exc()) except: logger.error(traceback.format_exc())
from channels import filtertools from core import config from core import logger from core import scrapertools from core import servertools from core.item import Item from core import httptools from channelselector import get_thumb from core import tmdb if config.is_xbmc(): from channels import renumbertools if not config.is_xbmc(): from platformcode import platformtools platformtools.dialog_notification( "¡ALERTA!", "El renumerado no funciona " "en la version Plex o Mediaserver") host = "https://serieslan.com" def mainlist(item): logger.info() thumb_series = get_thumb("squares", "thumb_canales_series.png") itemlist = list() itemlist.append( Item(channel=item.channel, action="lista", title="Series",
def start(itemlist, item): ''' Metodo principal desde donde se reproduce automaticamente los enlaces - En caso la opcion de personalizar activa utilizara las opciones definidas por el usuario. - En caso contrario intentara reproducir cualquier enlace que cuente con el idioma preferido. :param itemlist: list (lista de items listos para reproducir, o sea con action='play') :param item: item (el item principal del canal) :return: intenta autoreproducir, en caso de fallar devuelve el itemlist que recibio en un principio ''' logger.info() if not config.is_xbmc(): #platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi') return itemlist global autoplay_node if not autoplay_node: # Obtiene el nodo AUTOPLAY desde el json autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') if not item.channel in autoplay_node: return itemlist # Agrega servidores y calidades que no estaban listados a autoplay_node new_options = check_value(item.channel, itemlist) # Obtiene el nodo del canal desde autoplay_node channel_node = autoplay_node.get(item.channel, {}) # Obtiene los ajustes des autoplay para este canal settings_node = channel_node.get('settings', {}) if settings_node['active']: url_list_valid = [] autoplay_list = [] favorite_servers = [] favorite_quality = [] # Guarda el valor actual de "Accion y Player Mode" en preferencias user_config_setting_action = config.get_setting("default_action") user_config_setting_player = config.get_setting("player_mode") # Habilita la accion "Ver en calidad alta" (si el servidor devuelve más de una calidad p.e. gdrive) if user_config_setting_action != 2: config.set_setting("default_action", 2) if user_config_setting_player != 0: config.set_setting("player_mode", 0) # Informa que AutoPlay esta activo platformtools.dialog_notification('AutoPlay Activo', '', sound=False) # Prioridades a la hora de ordenar itemlist: # 0: Servidores y calidades # 1: Calidades y servidores # 2: Solo servidores # 3: Solo calidades # 4: No ordenar if settings_node['custom_servers'] and settings_node['custom_quality']: priority = settings_node[ 'priority'] # 0: Servidores y calidades o 1: Calidades y servidores elif settings_node['custom_servers']: priority = 2 # Solo servidores elif settings_node['custom_quality']: priority = 3 # Solo calidades else: priority = 4 # No ordenar # Obtiene las listas servidores, calidades disponibles desde el nodo del json de AutoPlay server_list = channel_node.get('servers', []) quality_list = channel_node.get('quality', []) # Se guardan los textos de cada servidor y calidad en listas p.e. favorite_servers = ['openload', # 'streamcloud'] for num in range(1, 4): favorite_servers.append( channel_node['servers'][settings_node['server_%s' % num]]) favorite_quality.append( channel_node['quality'][settings_node['quality_%s' % num]]) # Se filtran los enlaces de itemlist y que se correspondan con los valores de autoplay for item in itemlist: autoplay_elem = dict() # Comprobamos q se trata de un item de video if 'server' not in item: continue # Agrega la opcion configurar AutoPlay al menu contextual if 'context' not in item: item.context = list() if not filter(lambda x: x['action'] == 'autoplay_config', context): item.context.append({ "title": "Configurar AutoPlay", "action": "autoplay_config", "channel": "autoplay", "from_channel": item.channel }) # Si no tiene calidad definida le asigna calidad 'default' if item.quality == '': item.quality = 'default' # Se crea la lista para configuracion personalizada if priority < 2: # 0: Servidores y calidades o 1: Calidades y servidores # si el servidor y la calidad no se encuentran en las listas de favoritos o la url esta repetida, # descartamos el item if item.server not in favorite_servers or item.quality not in favorite_quality \ or item.url in url_list_valid: continue autoplay_elem["indice_server"] = favorite_servers.index( item.server) autoplay_elem["indice_quality"] = favorite_quality.index( item.quality) elif priority == 2: # Solo servidores # si el servidor no se encuentra en la lista de favoritos o la url esta repetida, # descartamos el item if item.server not in favorite_servers or item.url in url_list_valid: continue autoplay_elem["indice_server"] = favorite_servers.index( item.server) elif priority == 3: # Solo calidades # si la calidad no se encuentra en la lista de favoritos o la url esta repetida, # descartamos el item if item.quality not in favorite_quality or item.url in url_list_valid: continue autoplay_elem["indice_quality"] = favorite_quality.index( item.quality) else: # No ordenar # si la url esta repetida, descartamos el item if item.url in url_list_valid: continue # Si el item llega hasta aqui lo añadimos al listado de urls validas y a autoplay_list url_list_valid.append(item.url) autoplay_elem['videoitem'] = item # autoplay_elem['server'] = item.server # autoplay_elem['quality'] = item.quality autoplay_list.append(autoplay_elem) # Ordenamos segun la prioridad if priority == 0: # Servidores y calidades autoplay_list.sort(key=lambda orden: (orden['indice_server'], orden['indice_quality'])) elif priority == 1: # Calidades y servidores autoplay_list.sort(key=lambda orden: (orden['indice_quality'], orden['indice_server'])) elif priority == 2: # Solo servidores autoplay_list.sort(key=lambda orden: orden['indice_server']) elif priority == 3: # Solo calidades autoplay_list.sort(key=lambda orden: orden['indice_quality']) # Si hay elementos en la lista de autoplay se intenta reproducir cada elemento, hasta encontrar uno # funcional o fallen todos if autoplay_list: played = False max_intentos = 5 max_intentos_servers = {} # Si se esta reproduciendo algo detiene la reproduccion if platformtools.is_playing(): platformtools.stop_video() for autoplay_elem in autoplay_list: if not platformtools.is_playing() and not played: videoitem = autoplay_elem['videoitem'] if videoitem.server not in max_intentos_servers: max_intentos_servers[videoitem.server] = max_intentos # Si se han alcanzado el numero maximo de intentos de este servidor saltamos al siguiente if max_intentos_servers[videoitem.server] == 0: continue lang = " " if hasattr(videoitem, 'language') and videoitem.language != "": lang = " '%s' " % videoitem.language platformtools.dialog_notification( "AutoPlay", "%s%s%s" % (videoitem.server.upper(), lang, videoitem.quality.upper()), sound=False) # TODO videoitem.server es el id del server, pero podria no ser el nombre!!! # Intenta reproducir los enlaces # Si el canal tiene metodo play propio lo utiliza channel = __import__('channels.%s' % item.channel, None, None, ["channels.%s" % item.channel]) if hasattr(channel, 'play'): resolved_item = getattr(channel, 'play')(videoitem) if len(resolved_item) > 0: if isinstance(resolved_item[0], list): videoitem.video_urls = resolved_item else: videoitem = resolved_item[0] # si no directamente reproduce platformtools.play_video(videoitem) try: if platformtools.is_playing(): played = True break except: # TODO evitar el informe de que el conector fallo o el video no se encuentra logger.debug(str(len(autoplay_list))) # Si hemos llegado hasta aqui es por q no se ha podido reproducir max_intentos_servers[videoitem.server] -= 1 # Si se han alcanzado el numero maximo de intentos de este servidor # preguntar si queremos seguir probando o lo ignoramos if max_intentos_servers[videoitem.server] == 0: text = "Parece que los enlaces de %s no estan funcionando." % videoitem.server.upper( ) if not platformtools.dialog_yesno( "AutoPlay", text, "¿Desea ignorar todos los enlaces de este servidor?" ): max_intentos_servers[ videoitem.server] = max_intentos else: platformtools.dialog_notification('AutoPlay No Fue Posible', 'No Hubo Coincidencias') if new_options: platformtools.dialog_notification( "AutoPlay", "Nueva Calidad/Servidor disponible en la " "configuracion", sound=False) # Restaura si es necesario el valor previo de "Accion y Player Mode" en preferencias if user_config_setting_action != 2: config.set_setting("default_action", user_config_setting_action) if user_config_setting_player != 0: config.set_setting("player_mode", user_config_setting_player) # devuelve la lista de enlaces para la eleccion manual return itemlist
def check(background=False): if not addon.getSetting('addon_update_enabled'): return False, False logger.info('Cerco aggiornamenti..') commits = loadCommits() if not commits: return False, False try: localCommitFile = open(os.path.join(addonDir, trackingFile), 'r+') except: calcCurrHash() localCommitFile = open(os.path.join(addonDir, trackingFile), 'r+') localCommitSha = localCommitFile.read() localCommitSha = localCommitSha.replace('\n', '') # da testare logger.info('Commit locale: ' + localCommitSha) updated = False serviceChanged = False pos = None for n, c in enumerate(commits): if c['sha'] == localCommitSha: pos = n break else: # evitiamo che dia errore perchè il file è già in uso localCommitFile.close() calcCurrHash() return True, False if pos > 0: changelog = '' poFilesChanged = False try: for c in reversed(commits[:pos]): commit = urllib.urlopen(c['url']).read() commitJson = json.loads(commit) # evitiamo di applicare i merge commit if 'Merge' in commitJson['commit']['message']: continue logger.info('aggiornando a ' + commitJson['sha']) # major update if len(commitJson['files']) > 50: localCommitFile.close() c['sha'] = updateFromZip('Aggiornamento in corso...') localCommitFile = open( os.path.join( xbmc.translatePath("special://home/addons/"), 'plugin.video.kod', trackingFile), 'w') # il file di tracking viene eliminato, lo ricreo changelog += commitJson['commit']['message'] + "\n" poFilesChanged = True serviceChanged = True break patch_url = commitJson['html_url'] + '.patch' logger.info('applicando ' + patch_url) from lib import patch patchOk = patch.fromurl(patch_url).apply(root=addonDir) for file in commitJson['files']: if file["filename"] == trackingFile: # il file di tracking non si modifica continue else: logger.info(file["filename"]) if 'resources/language' in file["filename"]: poFilesChanged = True if 'service.py' in file["filename"]: serviceChanged = True if (file['status'] == 'modified' and 'patch' not in file) or file['status'] == 'added' or ( file['status'] == 'modified' and not patchOk): # è un file NON testuale che è stato modificato, oppure è un file nuovo (la libreria non supporta la creazione di un nuovo file) # lo devo scaricare filename = os.path.join(addonDir, file['filename']) dirname = os.path.dirname(filename) if not (filetools.isfile( os.path.join(addonDir, file['filename'])) and getSha(filename) == file['sha']): logger.info('scaricando ' + file['raw_url']) if not os.path.exists(dirname): os.makedirs(dirname) urllib.urlretrieve(file['raw_url'], filename) elif file['status'] == 'removed': remove(os.path.join(addonDir, file["filename"])) elif file['status'] == 'renamed': # se non è già applicato if not (filetools.isfile( os.path.join(addonDir, file['filename'])) and getSha( os.path.join(addonDir, file['filename'])) == file['sha']): dirs = file['filename'].split('/') for d in dirs[:-1]: if not filetools.isdir( os.path.join(addonDir, d)): filetools.mkdir( os.path.join(addonDir, d)) filetools.move( os.path.join(addonDir, file['previous_filename']), os.path.join(addonDir, file['filename'])) changelog += commitJson['commit']['message'] + "\n" except: import traceback logger.error(traceback.format_exc()) # fallback localCommitFile.close() c['sha'] = updateFromZip('Aggiornamento in corso...') localCommitFile = open( os.path.join(xbmc.translatePath("special://home/addons/"), 'plugin.video.kod', trackingFile), 'w') # il file di tracking viene eliminato, lo ricreo localCommitFile.seek(0) localCommitFile.truncate() localCommitFile.writelines(c['sha']) localCommitFile.close() xbmc.executebuiltin("UpdateLocalAddons") if poFilesChanged: refreshLang() xbmc.sleep(1000) updated = True if addon.getSetting("addon_update_message"): if background: platformtools.dialog_notification( config.get_localized_string(20000), config.get_localized_string(80040) % commits[0]['sha'][:7], time=3000, sound=False) try: with open(config.changelogFile, 'a+') as fileC: fileC.write(changelog) except: import traceback logger.error(traceback.format_exc()) elif changelog: platformtools.dialog_ok( config.get_localized_string(20000), config.get_localized_string(80041) + changelog) else: logger.info('Nessun nuovo aggiornamento') return updated, serviceChanged
def start(itemlist, item): ''' Metodo principal desde donde se reproduce automaticamente los enlaces - En caso la opcion de personalizar activa utilizara las opciones definidas por el usuario. - En caso contrario intentara reproducir cualquier enlace que cuente con el idioma preferido. :param itemlist: list (lista de items listos para reproducir, o sea con action='play') :param item: item (el item principal del canal) :return: intenta autoreproducir, en caso de fallar devuelve el itemlist que recibio en un principio ''' logger.info() global PLAYED global autoplay_node PLAYED = False base_item = item if not config.is_xbmc(): # platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi') return itemlist if not autoplay_node: # Obtiene el nodo AUTOPLAY desde el json autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') channel_id = item.channel if item.channel == 'videolibrary': autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') channel_id = item.contentChannel try: active = autoplay_node['status'] except: active = is_active(item.channel) if not channel_id in autoplay_node or not active: return itemlist # Agrega servidores y calidades que no estaban listados a autoplay_node new_options = check_value(channel_id, itemlist) # Obtiene el nodo del canal desde autoplay_node channel_node = autoplay_node.get(channel_id, {}) # Obtiene los ajustes des autoplay para este canal settings_node = channel_node.get('settings', {}) if get_setting('autoplay') or settings_node['active']: url_list_valid = [] autoplay_list = [] autoplay_b = [] favorite_langs = [] favorite_servers = [] favorite_quality = [] # 2nd lang, vemos si se quiere o no filtrar status_language = config.get_setting("filter_languages", channel_id) # Guarda el valor actual de "Accion y Player Mode" en preferencias user_config_setting_action = config.get_setting("default_action") user_forced_action = config.get_setting("autoplay_qlty") user_config_setting_player = config.get_setting("player_mode") # Habilita la accion "Ver en calidad alta o baja"(si el servidor devuelve más de una calidad p.e. gdrive) forced = {"Baja": 1, "Alta": 2} config.set_setting("default_action", forced[user_forced_action]) if user_config_setting_player != 0: config.set_setting("player_mode", 0) # Informa que AutoPlay esta activo # platformtools.dialog_notification('AutoPlay Activo', '', sound=False) # Prioridades a la hora de ordenar itemlist: # 0: Servidores y calidades # 1: Calidades y servidores # 2: Solo servidores # 3: Solo calidades # 4: No ordenar if (settings_node['custom_servers'] and settings_node['custom_quality']): priority = settings_node[ 'priority'] # 0: Servidores y calidades o 1: Calidades y servidores elif settings_node['custom_servers']: priority = 2 # Solo servidores elif settings_node['custom_quality']: priority = 3 # Solo calidades else: priority = 4 # No ordenar # Obtiene las listas servidores, calidades disponibles desde el nodo del json de AutoPlay server_list = channel_node.get('servers', []) for server in server_list: server = server.lower() quality_list = channel_node.get('quality', []) # Si no se definen calidades la se asigna default como calidad unica if len(quality_list) == 0: quality_list = ['default'] # Se guardan los textos de cada servidor y calidad en listas p.e. favorite_servers = ['openload', # 'streamcloud'] for num in range(1, 4): favorite_servers.append( channel_node['servers'][settings_node['server_%s' % num]].lower()) favorite_quality.append( channel_node['quality'][settings_node['quality_%s' % num]]) # Se filtran los enlaces de itemlist y que se correspondan con los valores de autoplay for n, item in enumerate(itemlist): autoplay_elem = dict() b_dict = dict() # Comprobamos q se trata de un item de video if 'server' not in item: continue # 2nd lang lista idiomas if item.language not in favorite_langs: favorite_langs.append(item.language) # Agrega la opcion configurar AutoPlay al menu contextual if 'context' not in item: item.context = list() if not filter(lambda x: x['action'] == 'autoplay_config', context): item.context.append({ "title": config.get_localized_string(60071), "action": "autoplay_config", "channel": "autoplay", "from_channel": channel_id }) # Si no tiene calidad definida le asigna calidad 'default' if item.quality == '': item.quality = 'default' # Se crea la lista para configuracion personalizada if priority < 2: # 0: Servidores y calidades o 1: Calidades y servidores # si el servidor y la calidad no se encuentran en las listas de favoritos o la url esta repetida, # descartamos el item if item.server.lower() not in favorite_servers or item.quality not in favorite_quality \ or item.url in url_list_valid: item.type_b = True b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_lang"] = favorite_langs.index( item.language) autoplay_elem["indice_server"] = favorite_servers.index( item.server.lower()) autoplay_elem["indice_quality"] = favorite_quality.index( item.quality) elif priority == 2: # Solo servidores # si el servidor no se encuentra en la lista de favoritos o la url esta repetida, # descartamos el item if item.server.lower( ) not in favorite_servers or item.url in url_list_valid: item.type_b = True b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_lang"] = favorite_langs.index( item.language) autoplay_elem["indice_server"] = favorite_servers.index( item.server.lower()) elif priority == 3: # Solo calidades # si la calidad no se encuentra en la lista de favoritos o la url esta repetida, # descartamos el item if item.quality not in favorite_quality or item.url in url_list_valid: item.type_b = True b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_lang"] = favorite_langs.index( item.language) autoplay_elem["indice_quality"] = favorite_quality.index( item.quality) # else: # No ordenar # # # si la url esta repetida, descartamos el item # if item.url in url_list_valid: # continue # Si el item llega hasta aqui lo añadimos al listado de urls validas y a autoplay_list url_list_valid.append(item.url) item.plan_b = True autoplay_elem['videoitem'] = item # autoplay_elem['server'] = item.server # autoplay_elem['quality'] = item.quality autoplay_list.append(autoplay_elem) # Ordenamos segun la prioridad if priority == 0: # Servidores y calidades autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden[ 'indice_server'], orden['indice_quality'])) elif priority == 1: # Calidades y servidores autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden[ 'indice_quality'], orden['indice_server'])) elif priority == 2: # Solo servidores autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_server'])) elif priority == 3: # Solo calidades autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_quality'])) # Se prepara el plan b, en caso de estar activo se agregan los elementos no favoritos al final try: plan_b = settings_node['plan_b'] except: plan_b = True text_b = '' if plan_b: autoplay_list.extend(autoplay_b) # Si hay elementos en la lista de autoplay se intenta reproducir cada elemento, hasta encontrar uno # funcional o fallen todos if autoplay_list or (plan_b and autoplay_b): # played = False max_intentos = 5 max_intentos_servers = {} # Si se esta reproduciendo algo detiene la reproduccion if platformtools.is_playing(): platformtools.stop_video() tried = list() for autoplay_elem in autoplay_list: play_item = Item # Si no es un elemento favorito si agrega el texto plan b if autoplay_elem['videoitem'].type_b: text_b = '(Plan B)' if not platformtools.is_playing() and not PLAYED: videoitem = autoplay_elem['videoitem'] if videoitem.server.lower() not in max_intentos_servers: max_intentos_servers[ videoitem.server.lower()] = max_intentos # Si se han alcanzado el numero maximo de intentos de este servidor saltamos al siguiente if max_intentos_servers[videoitem.server.lower()] == 0: continue lang = " " if hasattr(videoitem, 'language') and videoitem.language != "": lang = " '%s' " % videoitem.language platformtools.dialog_notification( "AutoPlay %s" % text_b, "%s%s%s" % (videoitem.server.upper(), lang, videoitem.quality.upper()), sound=False) # TODO videoitem.server es el id del server, pero podria no ser el nombre!!! # Intenta reproducir los enlaces # Si el canal tiene metodo play propio lo utiliza channel = __import__('channels.%s' % channel_id, None, None, ["channels.%s" % channel_id]) if hasattr(channel, 'play'): resolved_item = getattr(channel, 'play')(videoitem) if len(resolved_item) > 0: if isinstance(resolved_item[0], list): videoitem.video_urls = resolved_item else: videoitem = resolved_item[0] # Comprueba si el enlace ya fue probado if videoitem.url not in tried: tried.append(videoitem.url) else: continue # Si no directamente reproduce y marca como visto # Verifica si el item viene de la videoteca try: if base_item.contentChannel == 'videolibrary': # Marca como visto from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_auto_as_watched(base_item) # Rellena el video con los datos del item principal y reproduce play_item = base_item.clone(url=videoitem) platformtools.play_video(play_item.url, autoplay=True) else: # Si no viene de la videoteca solo reproduce platformtools.play_video(videoitem, autoplay=True) except: pass sleep(3) try: if platformtools.is_playing(): PLAYED = True break except: logger.debug(str(len(autoplay_list))) # Si hemos llegado hasta aqui es por q no se ha podido reproducir max_intentos_servers[videoitem.server.lower()] -= 1 # Si se han alcanzado el numero maximo de intentos de este servidor # preguntar si queremos seguir probando o lo ignoramos if max_intentos_servers[videoitem.server.lower()] == 0: text = config.get_localized_string( 60072) % videoitem.server.upper() if not platformtools.dialog_yesno( "AutoPlay", text, config.get_localized_string(60073)): max_intentos_servers[ videoitem.server.lower()] = max_intentos # Si no quedan elementos en la lista se informa if autoplay_elem == autoplay_list[-1]: platformtools.dialog_notification( 'AutoPlay', config.get_localized_string(60072) % videoitem.server.upper()) else: platformtools.dialog_notification( config.get_localized_string(60074), config.get_localized_string(60075)) if new_options: platformtools.dialog_notification( "AutoPlay", config.get_localized_string(60076), sound=False) # Restaura si es necesario el valor previo de "Accion y Player Mode" en preferencias if user_config_setting_action != 2: config.set_setting("default_action", user_config_setting_action) if user_config_setting_player != 0: config.set_setting("player_mode", user_config_setting_player) return itemlist
def start(itemlist, item): ''' Main method from which the links are automatically reproduced - In case the option to activate it will use the options defined by the user. - Otherwise it will try to reproduce any link that has the preferred language. :param itemlist: list (list of items ready to play, ie with action = 'play') :param item: item (the main item of the channel) :return: try to auto-reproduce, in case of failure it returns the itemlist that it received in the beginning ''' if item.global_search: return itemlist logger.debug() global PLAYED PLAYED = False base_item = item if not config.is_xbmc(): return itemlist if config.get_setting('autoplay'): url_list_valid = [] autoplay_list = [] autoplay_b = [] favorite_quality = [] favorite_servers = [] blacklisted_servers = config.get_setting("black_list", server='servers') if not blacklisted_servers: blacklisted_servers = [] from core import servertools servers_list = list(servertools.get_servers_list().items()) for server, server_parameters in servers_list: if config.get_setting('favorites_servers_list', server=server): favorite_servers.append(server.lower()) if not favorite_servers: config.set_setting('favorites_servers_list', [], server='servers') favorite_servers = [] else: favorite_servers = list( set(favorite_servers) - set(blacklisted_servers)) # Save the current value of "Action and Player Mode" in preferences user_config_setting_action = config.get_setting("default_action") user_config_setting_player = config.get_setting("player_mode") # 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) # Priorities when ordering itemlist: # 0: Servers and qualities # 1: Qualities and servers # 2: Servers only # 3: Only qualities # 4: Do not order if config.get_setting('favorites_servers' ) and favorite_servers and config.get_setting( 'default_action'): priority = 0 # 0: Servers and qualities or 1: Qualities and servers elif config.get_setting('favorites_servers') and favorite_servers: priority = 2 # Servers only elif config.get_setting('default_action'): priority = 3 # Only qualities else: priority = 4 # Do not order if config.get_setting('default_action') == 1: quality_list.reverse() favorite_quality = quality_list for item in itemlist: autoplay_elem = dict() b_dict = dict() # We check that it is a video item if 'server' not in item: continue if item.server.lower() in blacklisted_servers: continue # If it does not have a defined quality, it assigns a 'default' quality. if item.quality.lower() not in quality_list: item.quality = 'default' # The list for custom settings is created if priority < 2: # 0: Servers and qualities or 1: Qualities and servers # if the server and the quality are not in the favorites lists or the url is repeated, we discard the item if item.server.lower( ) not in favorite_servers or item.quality.lower( ) not in favorite_quality or item.url in url_list_valid: item.type_b = True item.play_from = base_item.play_from b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_server"] = favorite_servers.index( item.server.lower()) autoplay_elem["indice_quality"] = favorite_quality.index( item.quality.lower()) elif priority == 2: # Servers only # if the server is not in the favorites list or the url is repeated, we discard the item if item.server.lower( ) not in favorite_servers or item.url in url_list_valid: item.type_b = True item.play_from = base_item.play_from b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_server"] = favorite_servers.index( item.server.lower()) elif priority == 3: # Only qualities # if the quality is not in the favorites list or the url is repeated, we discard the item if item.quality.lower( ) not in favorite_quality or item.url in url_list_valid: item.type_b = True item.play_from = base_item.play_from b_dict['videoitem'] = item autoplay_b.append(b_dict) continue autoplay_elem["indice_quality"] = favorite_quality.index( item.quality.lower()) else: # Do not order # if the url is repeated, we discard the item item.play_from = base_item.play_from if item.url in url_list_valid: continue # If the item reaches here we add it to the list of valid urls and to autoplay_list url_list_valid.append(item.url) item.plan_b = True item.play_from = base_item.play_from autoplay_elem['videoitem'] = item autoplay_list.append(autoplay_elem) # We order according to priority if priority == 0: autoplay_list.sort(key=lambda orden: (orden['indice_quality'], orden['indice_server'] )) # Servers and qualities elif priority == 1: autoplay_list.sort(key=lambda orden: (orden['indice_quality'], orden['indice_server'] )) # Qualities and servers elif priority == 2: autoplay_list.sort(key=lambda orden: (orden['indice_server'])) # Servers only elif priority == 3: autoplay_list.sort(key=lambda orden: (orden['indice_quality'])) # Only qualities # if quality priority is active if priority == 0 and config.get_setting('quality_priority'): max_quality = autoplay_list[0][ "indice_quality"] if autoplay_list and "indice_quality" in autoplay_list[ 0] else 0 for n, item in enumerate(itemlist): if 'server' not in item: continue if item.server.lower() in blacklisted_servers: continue # If it does not have a defined quality, it assigns a 'default' quality. if item.quality == '': item.quality = 'default' if favorite_quality.index(item.quality.lower()) < max_quality: item.type_b = False autoplay_elem["indice_server"] = n autoplay_elem["indice_quality"] = favorite_quality.index( item.quality.lower()) autoplay_elem['videoitem'] = item autoplay_list.append(autoplay_elem) autoplay_list.sort(key=lambda orden: (orden['indice_quality'], orden['indice_server'])) # Plan b is prepared, in case it is active the non-favorite elements are added at the end # try: plan_b = settings_node['plan_b'] # except: plan_b = True text_b = '' if plan_b: autoplay_list.extend(autoplay_b) # If there are elements in the autoplay list, an attempt is made to reproduce each element, until one is found or all fail. if autoplay_list or (plan_b and autoplay_b): max_intentos = 5 max_intentos_servers = {} # If something is playing it stops playing if platformtools.is_playing(): platformtools.stop_video() for autoplay_elem in autoplay_list: play_item = Item channel_id = autoplay_elem['videoitem'].channel if autoplay_elem['videoitem'].channel == 'videolibrary': channel_id = autoplay_elem['videoitem'].contentChannel # If it is not a favorite element if you add the text plan b if autoplay_elem['videoitem'].type_b: text_b = '(Plan B)' if not platformtools.is_playing() and not PLAYED: videoitem = autoplay_elem['videoitem'] if videoitem.server.lower() not in max_intentos_servers: max_intentos_servers[ videoitem.server.lower()] = max_intentos # If the maximum number of attempts of this server have been reached, we jump to the next if max_intentos_servers[videoitem.server.lower()] == 0: continue lang = " " if hasattr(videoitem, 'language') and videoitem.language != "": lang = " '%s' " % videoitem.language name = servername(videoitem.server) platformtools.dialog_notification( "AutoPlay %s" % text_b, "%s%s%s" % (name, lang, videoitem.quality.upper()), sound=False) # Try to play the links If the channel has its own play method, use it try: channel = __import__('channels.%s' % channel_id, None, None, ["channels.%s" % channel_id]) except: channel = __import__('specials.%s' % channel_id, None, None, ["specials.%s" % channel_id]) if hasattr(channel, 'play'): resolved_item = getattr(channel, 'play')(videoitem) if len(resolved_item) > 0: 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: if base_item.contentChannel == 'videolibrary' or base_item.nfo: # Fill the video with the data of the main item and play play_item = base_item.clone(**videoitem.__dict__) platformtools.play_video(play_item, autoplay=True) else: # If it doesn't come from the video library, just play platformtools.play_video(videoitem, autoplay=True) except: pass sleep(3) try: if platformtools.is_playing(): PLAYED = True break except: logger.debug(str(len(autoplay_list))) # If we have come this far, it is because it could not be reproduced max_intentos_servers[videoitem.server.lower()] -= 1 # If the maximum number of attempts of this server has been reached, ask if we want to continue testing or ignore it. if max_intentos_servers[videoitem.server.lower()] == 0: text = config.get_localized_string(60072) % name if not platformtools.dialog_yesno( "AutoPlay", text, config.get_localized_string(60073)): max_intentos_servers[ videoitem.server.lower()] = max_intentos # If there are no items in the list, it is reported if autoplay_elem == autoplay_list[-1]: platformtools.dialog_notification( 'AutoPlay', config.get_localized_string(60072) % name) else: platformtools.dialog_notification( config.get_localized_string(60074), config.get_localized_string(60075)) # Restore if necessary the previous value of "Action and Player Mode" in preferences if not user_config_setting_action: config.set_setting("default_action", user_config_setting_action) if user_config_setting_player != 0: config.set_setting("player_mode", user_config_setting_player) return itemlist
def run(item=None): logger.info() if not item: # Extract item from sys.argv if sys.argv[2]: sp = sys.argv[2].split('&') url = sp[0] item = Item().fromurl(url) if len(sp) > 1: for e in sp[1:]: key, val = e.split('=') item.__setattr__(key, val) # If no item, this is mainlist else: if config.get_setting("start_page"): if not config.get_setting("custom_start"): dictCategory = { config.get_localized_string(70137): 'peliculas', config.get_localized_string(30123): 'series', config.get_localized_string(30124): 'anime', config.get_localized_string(60513): 'documentales', config.get_localized_string(70171): 'torrent', } if not config.get_setting( "category") in dictCategory.keys(): config.set_setting('category', config.get_localized_string(70137)) category = dictCategory[config.get_setting("category")] item = Item(channel="news", action="novedades", extra=category, mode='silent') else: from platformcode import side_menu item = Item() item = side_menu.check_user_home(item) item.start = True else: item = Item(channel="channelselector", action="getmainlist", viewmode="movie") if not config.get_setting('show_once'): from platformcode import xbmc_videolibrary xbmc_videolibrary.ask_set_content(silent=False) config.set_setting('show_once', True) logger.info(item.tostring()) try: if not config.get_setting('tmdb_active'): config.set_setting('tmdb_active', True) # If item has no action, stops here if item.action == "": logger.info("Item without action") return # Action for main menu in channelselector elif item.action == "getmainlist": import channelselector itemlist = channelselector.getmainlist() platformtools.render_items(itemlist, item) # Action for channel types on channelselector: movies, series, etc. elif item.action == "getchanneltypes": import channelselector itemlist = channelselector.getchanneltypes() platformtools.render_items(itemlist, item) # Action for channel listing on channelselector elif item.action == "filterchannels": import channelselector itemlist = channelselector.filterchannels(item.channel_type) platformtools.render_items(itemlist, item) # Special action for playing a video from the library elif item.action == "play_from_library": play_from_library(item) return elif item.action == "keymap": from platformcode import keymaptools if item.open: return keymaptools.open_shortcut_menu() else: return keymaptools.set_key() elif item.channel == "infoplus": from platformcode import infoplus return infoplus.Main(item) elif item.channel == "shortcuts": from platformcode import shortcuts return getattr(shortcuts, item.action)(item) elif item.action == "delete_key": from platformcode import keymaptools return keymaptools.delete_key() elif item.action == "script": from core import tmdb if tmdb.drop_bd(): platformtools.dialog_notification( config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False) elif item.action == "itemInfo": platformtools.dialog_textviewer('Item info', item.parent) elif item.action == "open_browser": import webbrowser if not webbrowser.open(item.url): import xbmc if xbmc.getCondVisibility( 'system.platform.linux') and xbmc.getCondVisibility( 'system.platform.android'): # android xbmc.executebuiltin( 'StartAndroidActivity("", "android.intent.action.VIEW", "", "%s")' % (item.url)) else: try: import urllib.request as urllib except ImportError: import urllib short = urllib.urlopen( 'https://u.nu/api.php?action=shorturl&format=simple&url=' + item.url).read().decode('utf-8') platformtools.dialog_ok( config.get_localized_string(20000), config.get_localized_string(70740) % short) # Action in certain channel specified in "action" and "channel" parameters else: # Checks if channel exists if os.path.isfile( os.path.join(config.get_runtime_path(), 'channels', item.channel + ".py")): CHANNELS = 'channels' else: CHANNELS = 'specials' channel_file = os.path.join(config.get_runtime_path(), CHANNELS, item.channel + ".py") logger.info("channel_file= " + channel_file + ' - ' + CHANNELS + ' - ' + item.channel) channel = None if os.path.exists(channel_file): try: channel = __import__('%s.%s' % (CHANNELS, item.channel), None, None, ['%s.%s' % (CHANNELS, item.channel)]) except ImportError: exec("import " + CHANNELS + "." + item.channel + " as channel") logger.info("Running channel %s | %s" % (channel.__name__, channel.__file__)) # Special play action if item.action == "play": # define la info para trakt try: from core import trakt_tools trakt_tools.set_trakt_info(item) except: pass logger.info("item.action=%s" % item.action.upper()) # logger.debug("item_toPlay: " + "\n" + item.tostring('\n')) # First checks if channel has a "play" function if hasattr(channel, 'play'): logger.info("Executing channel 'play' method") itemlist = channel.play(item) b_favourite = item.isFavourite # Play should return a list of playable URLS if len(itemlist) > 0 and isinstance(itemlist[0], Item): item = itemlist[0] if b_favourite: item.isFavourite = True platformtools.play_video(item) # Permitir varias calidades desde play en el Channel elif len(itemlist) > 0 and isinstance(itemlist[0], list): item.video_urls = itemlist platformtools.play_video(item) # If not, shows user an error message else: platformtools.dialog_ok( config.get_localized_string(20000), config.get_localized_string(60339)) # If player don't have a "play" function, not uses the standard play from platformtools else: logger.info("Executing core 'play' method") platformtools.play_video(item) # Special action for findvideos, where the plugin looks for known urls elif item.action == "findvideos": from core import servertools # First checks if channel has a "findvideos" function if hasattr(channel, 'findvideos'): itemlist = getattr(channel, item.action)(item) # If not, uses the generic findvideos function else: logger.info("No channel 'findvideos' method, " "executing core method") itemlist = servertools.find_video_items(item) if config.get_setting("max_links", "videolibrary") != 0: itemlist = limit_itemlist(itemlist) from platformcode import subtitletools subtitletools.saveSubtitleName(item) platformtools.render_items(itemlist, item) # Special action for adding a movie to the library elif item.action == "add_pelicula_to_library": from core import videolibrarytools videolibrarytools.add_movie(item) # Special action for adding a serie to the library elif item.action == "add_serie_to_library": from core import videolibrarytools videolibrarytools.add_tvshow(item, channel) # Special action for downloading all episodes from a serie elif item.action == "download_all_episodes": from specials import downloads item.action = item.extra del item.extra downloads.save_download(item) # Special action for searching, first asks for the words then call the "search" function elif item.action == "search": # from core.support import dbg;dbg() if filetools.isfile(temp_search_file) and config.get_setting( 'videolibrary_kodi'): itemlist = [] f = filetools.read(temp_search_file) strList = f.split(',') if strList[0] == '[V]' and strList[1] == item.channel: for it in strList: if it and it not in ['[V]', item.channel]: itemlist.append(Item().fromurl(it)) filetools.write(temp_search_file, f[4:]) return platformtools.render_items(itemlist, item) else: filetools.remove(temp_search_file) logger.info("item.action=%s" % item.action.upper()) from core import channeltools if config.get_setting('last_search'): last_search = channeltools.get_channel_setting( 'Last_searched', 'search', '') else: last_search = '' search_text = platformtools.dialog_input(last_search) if search_text is not None: channeltools.set_channel_setting('Last_searched', search_text, 'search') itemlist = new_search(item.clone(text=search_text), channel) else: return platformtools.render_items(itemlist, item) # For all other actions else: # import web_pdb; web_pdb.set_trace() logger.info("Executing channel '%s' method" % item.action) itemlist = getattr(channel, item.action)(item) if config.get_setting('trakt_sync'): from core import trakt_tools token_auth = config.get_setting("token_trakt", "trakt") if not token_auth: trakt_tools.auth_trakt() else: import xbmc if not xbmc.getCondVisibility( 'System.HasAddon(script.trakt)' ) and config.get_setting('install_trakt'): trakt_tools.ask_install_script() itemlist = trakt_tools.trakt_check(itemlist) else: config.set_setting('install_trakt', True) platformtools.render_items(itemlist, item) except WebErrorException as e: import traceback from core import scrapertools logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + r'([^.]+)\.py"' Channel = scrapertools.find_single_match(traceback.format_exc(), patron) platformtools.dialog_ok( config.get_localized_string(59985) + Channel, config.get_localized_string(60013) % (e)) except: import traceback from core import scrapertools logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + r'([^.]+)\.py"' Channel = scrapertools.find_single_match(traceback.format_exc(), patron) try: import xbmc if config.get_platform(True)['num_version'] < 14: log_name = "xbmc.log" else: log_name = "kodi.log" log_message = config.get_localized_string( 50004) + xbmc.translatePath("special://logpath") + log_name except: log_message = "" if Channel: if item.url: if platformtools.dialog_yesno( config.get_localized_string(60087) % Channel, config.get_localized_string(60014) + '\n' + log_message, nolabel='ok', yeslabel=config.get_localized_string(70739)): run(Item(action="open_browser", url=item.url)) else: platformtools.dialog_ok( config.get_localized_string(60087) % Channel, config.get_localized_string(60014) + '\n' + log_message) else: platformtools.dialog_ok( config.get_localized_string(60038), config.get_localized_string(60015) + '\n' + log_message)
def check_addon_init(): if not addon.getSetting('addon_update_enabled'): return False logger.info('Cerco aggiornamenti..') commits = loadCommits() try: localCommitFile = open(addonDir + trackingFile, 'r+') except: calcCurrHash() localCommitFile = open(addonDir + trackingFile, 'r+') localCommitSha = localCommitFile.read() localCommitSha = localCommitSha.replace('\n', '') # da testare logger.info('Commit locale: ' + localCommitSha) updated = False pos = None for n, c in enumerate(commits): if c['sha'] == localCommitSha: pos = n break else: # evitiamo che dia errore perchè il file è già in uso localCommitFile.close() updateFromZip() return True if pos > 0: changelog = '' nCommitApplied = 0 for c in reversed(commits[:pos]): commit = httptools.downloadpage(c['url']).data commitJson = json.loads(commit) logger.info('aggiornando a' + commitJson['sha']) alreadyApplied = True for file in commitJson['files']: if file["filename"] == trackingFile: # il file di tracking non si modifica continue else: logger.info(file["filename"]) if file['status'] == 'modified' or file[ 'status'] == 'added': if 'patch' in file: text = "" try: localFile = open(addonDir + file["filename"], 'r+') for line in localFile: text += line except IOError: # nuovo file localFile = open(addonDir + file["filename"], 'w') patched = apply_patch(text, (file['patch'] + '\n').encode('utf-8')) if patched != text: # non eseguo se già applicata (es. scaricato zip da github) if getSha(patched) == file['sha']: localFile.seek(0) localFile.truncate() localFile.writelines(patched) localFile.close() alreadyApplied = False else: # nel caso ci siano stati problemi logger.info( 'lo sha non corrisponde, scarico il file' ) downloadtools.downloadfile( file['raw_url'], addonDir + file['filename'], silent=True, continuar=True) else: # è un file NON testuale, lo devo scaricare # se non è già applicato if not (filetools.isfile(addonDir + file['filename']) and getSha( filetools.read(addonDir + file['filename']) == file['sha'])): downloadtools.downloadfile(file['raw_url'], addonDir + file['filename'], silent=True, continuar=True) alreadyApplied = False elif file['status'] == 'removed': try: filetools.remove(addonDir + file["filename"]) alreadyApplied = False except: pass elif file['status'] == 'renamed': # se non è già applicato if not (filetools.isfile(addonDir + file['filename']) and getSha( filetools.read(addonDir + file['filename']) == file['sha'])): dirs = file['filename'].split('/') for d in dirs[:-1]: if not filetools.isdir(addonDir + d): filetools.mkdir(addonDir + d) filetools.move( addonDir + file['previous_filename'], addonDir + file['filename']) alreadyApplied = False if not alreadyApplied: # non mando notifica se già applicata (es. scaricato zip da github) changelog += commitJson['commit']['message'] + " | " nCommitApplied += 1 if addon.getSetting("addon_update_message"): time = nCommitApplied * 2000 if nCommitApplied < 10 else 20000 platformtools.dialog_notification('Kodi on Demand', changelog, time) localCommitFile.seek(0) localCommitFile.truncate() localCommitFile.writelines(c['sha']) localCommitFile.close() else: logger.info('Nessun nuovo aggiornamento') return updated
def get_generic_call(endpoint, url=None, timeout=None, jsCode=None, jsDirectCodeNoReturn=None, jsDirectCode2NoReturn=None, extraPostDelay=None, userAgent=None, debug=None, headers=None, malwareWhiteList=None, disableCache = None, closeAfter = None, getData = None, postData = None, getCookies = None, update = None, alfa_s = False, version = None, clearWebCache = False, removeAllCookies = False, hardResetWebView = False, keep_alive = False): if endpoint not in ['ping', 'getWebViewInfo', 'update', 'quit']: res = open_alfa_assistant(closeAfter) logger.info('##Assistant Endpoint: %s, Status: %s' % (endpoint, str(res))) if not res: return False if url: logger.info('##Assistant URL: %s' % url) else: url = 'about:blank' if timeout and endpoint not in ['ping', 'getWebViewInfo', 'update', 'quit']: logger.info('##Assistant delay-after-html-load: %s' % str(timeout*1000)) elif not timeout: timeout = 0 if endpoint == 'getWebViewInfo': serverCall = '%s:48884/%s' % (ASSISTANT_SERVER, 'ping') else: serverCall = '%s:48884/%s' % (ASSISTANT_SERVER, endpoint) if endpoint == 'update': serverCall += '?version=%s' % version if endpoint not in ['ping', 'getWebViewInfo', 'update', 'quit']: serverCall += '?url=%s&time=%s' % (base64.b64encode(url.encode('utf8')).decode('utf8'), str(timeout*1000)) if jsCode: serverCall += '&jsCode=%s' % base64.b64encode(jsCode.encode('utf8')).decode('utf8') logger.info('##Assistant js-to-run-directly-with-return: %s' % jsCode) if jsDirectCodeNoReturn: serverCall += '&jsDirectCodeNoReturn=%s' % base64.b64encode(jsDirectCodeNoReturn.encode('utf8')).decode('utf8') logger.info('##Assistant js-to-run-directly-with-no-return(type I): %s' % jsDirectCodeNoReturn) if jsDirectCode2NoReturn: serverCall += '&jsDirectCode2NoReturn=%s' % base64.b64encode(jsDirectCode2NoReturn.encode('utf8')).decode('utf8') logger.info('##Assistant js-to-run-directly-with-no-return(type II): %s' % jsDirectCode2NoReturn) if extraPostDelay: timeout += extraPostDelay serverCall += '&extraPostDelay=%s' % (extraPostDelay*1000) logger.info('##Assistant delay-after-js-load: %s' % str(extraPostDelay*1000)) if userAgent: serverCall += '&userAgent=%s' % base64.b64encode(userAgent.encode('utf8')).decode('utf8') logger.info('##Assistant user-agent: %s' % userAgent) ## Por defecto "debug" es False y debe serlo siempre en Producción if debug: serverCall += '&debug=%s' % debug logger.info('##Assistant debug-mode: %s' % str(debug)) ## Por defecto "getCookies" es False if getCookies: serverCall += '&getCookies=%s' % getCookies logger.info('##Assistant get-cookies: %s' % str(getCookies) ) ## Por defecto "cache" es True pero en casos como mixdrop es mejor no usarla if disableCache: serverCall += '&cache=False' logger.info('##Assistant disableCache: %s' % str(disableCache)) if headers: serverCall += '&headers=%s' % base64.b64encode(headers.encode('utf8')).decode('utf8') logger.info('##Assistant headers: %s' % headers) if malwareWhiteList: serverCall += '&malwareWhiteList=%s' % base64.b64encode(malwareWhiteList.encode('utf8')).decode('utf8') logger.info('##Assistant malware-white-list: %s' % malwareWhiteList) if getData: serverCall += '&getData=%s' % base64.b64encode(getData.encode('utf8')).decode('utf8') logger.info('##Assistant get-data: %s' % getData) if postData: serverCall += '&postData=%s' % base64.b64encode(postData.encode('utf8')).decode('utf8') logger.info('##Assistant post-data: %s' % postData) if clearWebCache: serverCall += '&clearWebCache=%s' % clearWebCache logger.info('##Assistant clearWebCache: %s' % str(clearWebCache)) if removeAllCookies: serverCall += '&removeAllCookies=%s' % removeAllCookies logger.info('##Assistant removeAllCookies: %s' % str(removeAllCookies)) if hardResetWebView: serverCall += '&hardResetWebView=%s' % hardResetWebView logger.info('##Assistant hardResetWebView: %s' % str(hardResetWebView)) if endpoint not in ['ping', 'getWebViewInfo', 'update', 'quit']: logger.info('##Assistant URL: ' + serverCall) response = httptools.downloadpage(serverCall, timeout=timeout+EXTRA_TIMEOUT, alfa_s=alfa_s, ignore_response_code=True, keep_alive=keep_alive) if not response.sucess and endpoint in ['ping', 'getWebViewInfo']: logger.info('##Assistant "%s" FALSE, timeout %s: %s' % (endpoint, timeout+EXTRA_TIMEOUT, serverCall), force=True) if not (response.sucess or response.data) and endpoint not in ['ping', 'getWebViewInfo', 'quit']: close_alfa_assistant() time.sleep(2) res = open_alfa_assistant(closeAfter, retry=True) if not res: time.sleep(10) res = get_generic_call('ping', timeout=2-EXTRA_TIMEOUT+10, alfa_s=True) if res: serverCall = serverCall.replace('&cache=False', '&cache=True') logger.info('##Assistant retrying URL: ' + serverCall) response = httptools.downloadpage(serverCall, timeout=timeout+EXTRA_TIMEOUT, alfa_s=alfa_s, ignore_response_code=True, keep_alive=keep_alive) else: platformtools.dialog_notification("ACTIVE Alfa Assistant en ", "%s" % ASSISTANT_SERVER) data = response.data #if closeAfter: # close_alfa_assistant() if data: if endpoint in ['update']: return data try: data_ret = jsontools.load(data) if endpoint in ['ping', 'getWebViewInfo']: if endpoint in ['ping']: data_ret = data_ret.get('assistantVersion', '') logger.info('##Assistant "%s" TRUE, timeout %s: %s' % (endpoint, timeout+EXTRA_TIMEOUT, str(data_ret))) except: data_ret = data logger.error('##Assistant "%s" ERROR, timeout %s: %s' % (endpoint, timeout+EXTRA_TIMEOUT, str(data_ret))) return data_ret else: data = '' return data
def run(item): itemlist = [] # Muestra el item en el log: print_items(item) # Control Parental, comprueba si es adulto o no if item.action == "mainlist": # Parental control if channeltools.is_adult( item.channel) and config.get_setting("adult_request_password"): tecleado = platformtools.dialog_input( "", config.get_localized_string(60334), True) if tecleado is None or tecleado != config.get_setting( "adult_password"): platformtools.render_items(None, item) return channelmodule = None # Importa el canal para el item, todo item debe tener un canal, sino sale de la función if item.channel: channelmodule = import_channel(item) # If item has no action, stops here if item.action == "": logger.info("Item sin accion") itemlist = None # Action Play, para mostrar el menú con las opciones de reproduccion. elif item.action == "play": logger.info("play") # Si el canal tiene una acción "play" tiene prioridad if hasattr(channelmodule, 'play'): logger.info("executing channel 'play' method") itemlist = channelmodule.play(item) b_favourite = item.isFavourite if len(itemlist) > 0 and isinstance(itemlist[0], Item): item = itemlist[0] if b_favourite: item.isFavourite = True play_menu(item) elif len(itemlist) > 0 and isinstance(itemlist[0], list): item.video_urls = itemlist play_menu(item) else: platformtools.dialog_ok("plugin", "No hay nada para reproducir") else: logger.info("no channel 'play' method, executing core method") play_menu(item) itemlist = None # Action Search, para mostrar el teclado y lanzar la busqueda con el texto indicado. elif item.action == "search": logger.info("search") tecleado = platformtools.dialog_input() if tecleado: itemlist = channelmodule.search(item, tecleado) else: itemlist = [] elif item.channel == "channelselector": import channelselector if item.action == "mainlist": itemlist = channelselector.getmainlist("banner_") if item.action == "getchanneltypes": itemlist = channelselector.getchanneltypes("banner_") if item.action == "filterchannels": itemlist = channelselector.filterchannels(item.channel_type, "banner_") elif item.action == "script": from core import tmdb if tmdb.drop_bd(): platformtools.dialog_notification("Alfa", "caché eliminada", time=2000, sound=False) # Todas las demas las intenta ejecturaren el siguiente orden: # 1. En el canal # 2. En el launcher # 3. Si no existe en el canal ni en el launcher guarda un error en el log else: # Si existe la funcion en el canal la ejecuta if hasattr(channelmodule, item.action): logger.info("Ejectuando accion: " + item.channel + "." + item.action + "(item)") exec "itemlist = channelmodule." + item.action + "(item)" # Si existe la funcion en el launcher la ejecuta elif hasattr(sys.modules[__name__], item.action): logger.info("Ejectuando accion: " + item.action + "(item)") exec "itemlist =" + item.action + "(item)" # Si no existe devuelve un error else: logger.info("No se ha encontrado la accion [" + item.action + "] en el canal [" + item.channel + "] ni en el launcher") # Llegados a este punto ya tenemos que tener el itemlist con los resultados correspondientes # Pueden darse 3 escenarios distintos: # 1. la función ha generado resultados y estan en el itemlist # 2. la función no ha generado resultados y por tanto el itemlist contiene 0 items, itemlist = [] # 3. la función realiza alguna accion con la cual no se generan nuevos items, en ese caso el resultado deve ser: itemlist = None para que no modifique el listado # A partir de aquí ya se ha ejecutado la funcion en el lugar adecuado, si queremos realizar alguna acción sobre los resultados, este es el lugar. # Filtrado de Servers if item.action == "findvideos": itemlist = servertools.filter_servers(itemlist) # Si la accion no ha devuelto ningún resultado, añade un item con el texto "No hay elementos para mostrar" if type(itemlist) == list: if len(itemlist) == 0: from channelselector import get_thumb itemlist = [ Item(title="No hay elementos para mostrar", thumbnail=get_thumb("error.png")) ] # Imprime en el log el resultado print_items(itemlist) # Muestra los resultados en pantalla platformtools.render_items(itemlist, item)
def token_trakt(item): from platformcode import platformtools headers = { 'Content-Type': 'application/json', 'trakt-api-key': client_id, 'trakt-api-version': '2' } try: if item.extra == "renew": refresh = config.get_setting("refresh_token_trakt", "trakt") url = "http://api-v2launch.trakt.tv/oauth/device/token" post = { 'refresh_token': refresh, 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'refresh_token' } post = jsontools.dump(post) data = httptools.downloadpage(url, post, headers, replace_headers=True).data data = jsontools.load(data) elif item.action == "token_trakt": url = "http://api-v2launch.trakt.tv/oauth/device/token" post = "code=%s&client_id=%s&client_secret=%s" % ( item.device_code, client_id, client_secret) data = httptools.downloadpage(url, post, headers, replace_headers=True).data data = jsontools.load(data) else: import time dialog_auth = platformtools.dialog_progress( config.get_localized_string(60251), config.get_localized_string(60252) % item.verify_url, config.get_localized_string(60253) % item.user_code, config.get_localized_string(60254)) # Generalmente cada 5 segundos se intenta comprobar si el usuario ha introducido el código while True: time.sleep(item.intervalo) try: if dialog_auth.iscanceled(): config.set_setting("trakt_sync", False) return url = "http://api-v2launch.trakt.tv/oauth/device/token" post = { 'code': item.device_code, 'client_id': client_id, 'client_secret': client_secret } post = jsontools.dump(post) data = httptools.downloadpage(url, post, headers, replace_headers=True).data data = jsontools.load(data) if "access_token" in data: # Código introducido, salimos del bucle break except: pass try: dialog_auth.close() except: pass token = data["access_token"] refresh = data["refresh_token"] config.set_setting("token_trakt", token, "trakt") config.set_setting("refresh_token_trakt", refresh, "trakt") if not item.folder: platformtools.dialog_notification( config.get_localized_string(60255), config.get_localized_string(60256)) if config.is_xbmc(): import xbmc xbmc.executebuiltin("Container.Refresh") return except: import traceback logger.error(traceback.format_exc()) if not item.folder: return platformtools.dialog_notification( config.get_localized_string(60527), config.get_localized_string(60258)) token = "" itemlist = [] if token: itemlist.append( item.clone(config.get_localized_string(60256), action="")) else: itemlist.append( item.clone(config.get_localized_string(60260), action="")) return itemlist
def search_trailers(item): logger.info() from core.tmdb import Tmdb import xbmcgui, xbmc tipo = 'movie' if item.contentType == 'movie' else 'tv' nombre = item.contentTitle if item.contentType == 'movie' else item.contentSerieName if item.infoLabels['tmdb_id']: tmdb_search = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], tipo=tipo, idioma_busqueda='es') else: anyo = item.infoLabels['year'] if item.infoLabels['year'] else '-' tmdb_search = Tmdb(texto_buscado=nombre, tipo=tipo, year=anyo, idioma_busqueda='es') opciones = [] resultados = tmdb_search.get_videos() for res in resultados: # ~ logger.debug(res) it = xbmcgui.ListItem(res['name'], '[%sp] (%s)' % (res['size'], res['language'])) if item.thumbnail: it.setArt({'thumb': item.thumbnail}) opciones.append(it) if len(resultados) == 0: platformtools.dialog_ok(nombre, 'No se encuentra ningún tráiler en TMDB') else: while not xbmc.Monitor().abortRequested(): # (while True) ret = xbmcgui.Dialog().select('Tráilers para %s' % nombre, opciones, useDetails=True) if ret == -1: break platformtools.dialog_notification(resultados[ret]['name'], 'Cargando tráiler ...', time=3000, sound=False) from core import servertools if 'youtube' in resultados[ret]['url']: video_urls, puedes, motivo = servertools.resolve_video_urls_for_playing( 'youtube', resultados[ret]['url']) else: video_urls = [] #TODO si no es youtube ... logger.debug(resultados[ret]) if len(video_urls) > 0: # ~ logger.debug(video_urls) xbmc.Player().play( video_urls[-1][1]) # el último es el de más calidad xbmc.sleep(1000) while not xbmc.Monitor().abortRequested() and xbmc.Player( ).isPlaying(): xbmc.sleep(1000) else: platformtools.dialog_notification( resultados[ret]['name'], 'No se puede reproducir el tráiler', time=3000, sound=False) if len(resultados) == 1: break # si sólo hay un vídeo no volver al diálogo de tráilers
def convert_old_to_v4(): logger.info() path_series_xml = filetools.join(config.get_data_path(), "series.xml") path_series_json = filetools.join(config.get_data_path(), "series.json") series_insertadas = 0 series_fallidas = 0 version = 'v?' # Renombrar carpeta Series y crear una vacia import time new_name = "SERIES_OLD_" + str(time.time()) path_series_old = filetools.join(library.LIBRARY_PATH, new_name) if filetools.rename(library.TVSHOWS_PATH, new_name): if not filetools.mkdir(library.TVSHOWS_PATH): logger.error( "ERROR, no se ha podido crear la nueva carpeta de SERIES") return False else: logger.error( "ERROR, no se ha podido renombrar la antigua carpeta de SERIES") return False # Convertir libreria de v1(xml) a v4 if filetools.exists(path_series_xml): try: data = filetools.read(path_series_xml) for line in data.splitlines(): try: aux = line.rstrip('\n').split(",") tvshow = aux[0].strip() url = aux[1].strip() channel = aux[2].strip() serie = Item(contentSerieName=tvshow, url=url, channel=channel, action="episodios", title=tvshow, active=True) patron = "^(.+)[\s]\((\d{4})\)$" matches = re.compile(patron, re.DOTALL).findall( serie.contentSerieName) if matches: serie.infoLabels['title'] = matches[0][0] serie.infoLabels['year'] = matches[0][1] else: serie.infoLabels['title'] = tvshow insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 filetools.rename(path_series_xml, "series.xml.old") version = 'v4' except EnvironmentError: logger.error("ERROR al leer el archivo: %s" % path_series_xml) return False # Convertir libreria de v2(json) a v4 if filetools.exists(path_series_json): try: data = jsontools.load_json(filetools.read(path_series_json)) for tvshow in data: for channel in data[tvshow]["channels"]: try: serie = Item( contentSerieName=data[tvshow]["channels"][channel] ["tvshow"], url=data[tvshow]["channels"][channel]["url"], channel=channel, action="episodios", title=data[tvshow]["name"], active=True) if not tvshow.startswith("t_"): serie.infoLabels["tmdb_id"] = tvshow insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 filetools.rename(path_series_json, "series.json.old") version = 'v4' except EnvironmentError: logger.error("ERROR al leer el archivo: %s" % path_series_json) return False # Convertir libreria de v3 a v4 if version != 'v4': # Obtenemos todos los tvshow.json de la biblioteca de SERIES_OLD recursivamente for raiz, subcarpetas, ficheros in filetools.walk(path_series_old): for f in ficheros: if f == "tvshow.json": try: serie = Item().fromjson( filetools.read(filetools.join(raiz, f))) insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 config.set_setting("library_version", 'v4') platformtools.dialog_notification( "Biblioteca actualizada al nuevo formato", "%s series convertidas y %s series descartadas. A continuación se va a " "obtener la información de todos los episodios" % (series_insertadas, series_fallidas), time=12000) # Por ultimo limpia la libreria, por que las rutas anteriores ya no existen xbmc_library.clean() return True
def add_channel(item): support.log() channel_to_add = {} json_file = '' result = platformtools.dialog_select(config.get_localized_string(70676), [ config.get_localized_string(70678), config.get_localized_string(70679) ]) if result == -1: return if result == 0: file_path = xbmcgui.Dialog().browseSingle( 1, config.get_localized_string(70680), 'files') try: channel_to_add['path'] = file_path json_file = jsontools.load(open(file_path, "r").read()) channel_to_add['channel_name'] = json_file['channel_name'] except: pass elif result == 1: url = platformtools.dialog_input("", config.get_localized_string(70681), False) try: if url[:4] != 'http': url = 'http://' + url channel_to_add['path'] = url json_file = jsontools.load(httptools.downloadpage(url).data) except: pass if len(json_file) == 0: return if "episodes_list" in json_file: platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(70682)) return channel_to_add['channel_name'] = json_file['channel_name'] if 'thumbnail' in json_file: channel_to_add['thumbnail'] = json_file['thumbnail'] if 'fanart' in json_file: channel_to_add['fanart'] = json_file['fanart'] path = filetools.join(config.get_data_path(), 'community_channels.json') community_json = open(path, "r") community_json = jsontools.load(community_json.read()) id = 1 while str(id) in community_json['channels']: id += 1 community_json['channels'][str(id)] = (channel_to_add) with open(path, "w") as file: file.write(jsontools.dump(community_json)) file.close() platformtools.dialog_notification( config.get_localized_string(20000), config.get_localized_string(70683) % json_file['channel_name']) import xbmc xbmc.sleep(1000) platformtools.itemlist_refresh() return