def start(self, list_controls=None, dict_values=None, caption="", callback=None, item=None, custom_button=None, channelpath=None): info() # Media Path self.mediapath = os.path.join(config.get_runtime_path(), 'resources', 'skins', 'Default', 'media') # Params self.list_controls = list_controls self.values = dict_values self.caption = caption self.callback = callback self.item = item if isinstance(custom_button, dict): self.custom_button = {} self.custom_button["label"] = custom_button.get("label", "") self.custom_button["function"] = custom_button.get("function", "") self.custom_button["visible"] = bool(custom_button.get("visible", True)) self.custom_button["close"] = bool(custom_button.get("close", False)) else: self.custom_button = None # Load Channel Settings if not channelpath: channelpath = inspect.currentframe().f_back.f_back.f_code.co_filename self.channel = os.path.basename(channelpath).replace(".py", "") self.ch_type = os.path.basename(os.path.dirname(channelpath)) # If list_controls does not exist, it is removed from the channel json if not self.list_controls: # If the channel path is in the "channels" folder, we get the controls and values using chaneltools if os.path.join(config.get_runtime_path(), "channels") in channelpath or os.path.join(config.get_runtime_path(), "specials") in channelpath: # The call is made from a channel self.list_controls, default_values = channeltools.get_channel_controls_settings(self.channel) self.kwargs = {"channel": self.channel} self.channelName = channeltools.get_channel_json(self.channel)['name'] # If the channel path is in the "servers" folder, we get the controls and values through servertools elif os.path.join(config.get_runtime_path(), "servers") in channelpath: # The call is made from a channel self.list_controls, default_values = servertools.get_server_controls_settings(self.channel) self.kwargs = {"server": self.channel} self.channelName = servertools.get_server_parameters(self.channel)['name'] # Else Exit else: return None # If dict_values are not passed, create a blank dict if self.values is None: self.values = {} # Make title if self.caption == "": self.caption = str(config.get_localized_string(30100)) + ' - ' + self.channelName matches = match(self.caption, patron=r'@(\d+)').matches if matches: for m in matches: self.caption = self.caption.replace('@' + match, config.get_localized_string(int(m))) # Show Window self.return_value = None self.doModal() return self.return_value
# -*- coding: utf-8 -*- # ------------------------------------------------------------ # XBMC entry point # ------------------------------------------------------------ import os import sys from platformcode import config, logger logger.info("init...") librerias = os.path.join(config.get_runtime_path(), 'lib') sys.path.append(librerias) from platformcode import launcher if sys.argv[2] == "": launcher.start() launcher.run() else: launcher.run()
def editar_enlace_thumbnail(item): logger.info() alfav = KodfavouritesData() if not alfav.user_favorites[item.i_perfil]: return False if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False it = Item().fromurl( alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]) # A partir de Kodi 17 se puede usar xbmcgui.Dialog().select con thumbnails (ListItem & useDetails=True) is_kodi17 = (config.get_platform(True)['num_version'] >= 17.0) if is_kodi17: import xbmcgui # Diálogo para escoger thumbnail (el del canal o iconos predefinidos) opciones = [] ids = [] try: from core import channeltools channel_parameters = channeltools.get_channel_parameters(it.channel) if channel_parameters['thumbnail'] != '': nombre = 'Canal %s' % it.channel if is_kodi17: it_thumb = xbmcgui.ListItem(nombre) it_thumb.setArt({'thumb': channel_parameters['thumbnail']}) opciones.append(it_thumb) else: opciones.append(nombre) ids.append(channel_parameters['thumbnail']) except: pass resource_path = os.path.join(config.get_runtime_path(), 'resources', 'media', 'themes', 'default') for f in sorted(os.listdir(resource_path)): if f.startswith('thumb_') and not f.startswith( 'thumb_intervenido') and f != 'thumb_back.png': nombre = f.replace('thumb_', '').replace('_', ' ').replace('.png', '') if is_kodi17: it_thumb = xbmcgui.ListItem(nombre) it_thumb.setArt({'thumb': os.path.join(resource_path, f)}) opciones.append(it_thumb) else: opciones.append(nombre) ids.append(os.path.join(resource_path, f)) if is_kodi17: ret = xbmcgui.Dialog().select('Seleccionar thumbnail:', opciones, useDetails=True) else: ret = platformtools.dialog_select('Seleccionar thumbnail:', opciones) if ret == -1: return False # pedido cancel it.thumbnail = ids[ret] alfav.user_favorites[item.i_perfil]['items'][item.i_enlace] = it.tourl() alfav.save() platformtools.itemlist_refresh() return True
# -*- coding: utf-8 -*- import os import re from core import httptools from core import servertools from core.item import Item from platformcode import config, logger IMAGES_PATH = os.path.join(config.get_runtime_path(), 'resources', 'images', 'cinetemagay') def strip_tags(value): return re.sub(r'<[^>]*?>', '', value) def mainlist(item): logger.info() itemlist = [] itemlist.append( Item( channel=item.channel, action="lista", title="Cine gay latinoamericano", url= "http://cinegaylatinoamericano.blogspot.com.es/feeds/posts/default/?max-results=100&start-index=1", thumbnail= "http://www.americaeconomia.com/sites/default/files/imagecache/foto_nota/homosexual1.jpg"
def searchSubtitle(item): if config.get_setting("subtitle_type") == 0: subtitlepath = config.get_setting("subtitlepath_folder") if subtitlepath == "": subtitlepath = filetools.join(config.get_data_path(), "subtitles") config.set_setting("subtitlepath_folder", subtitlepath) elif config.get_setting("subtitle_type") == 1: subtitlepath = config.get_setting("subtitlepath_keyboard") if subtitlepath == "": subtitlepath = filetools.join(config.get_data_path(), "subtitles") config.set_setting("subtitlepathkeyboard", subtitlepath) elif subtitlepath.startswith("http"): subtitlepath = config.get_setting("subtitlepath_folder") else: subtitlepath = config.get_setting("subtitlepath_folder") if subtitlepath == "": subtitlepath = filetools.join(config.get_data_path(), "subtitles") config.set_setting("subtitlepath_folder", subtitlepath) if not filetools.exists(subtitlepath): try: filetools.mkdir(subtitlepath) except: logger.error("error no se pudo crear path subtitulos") return path_movie_subt = xbmc.translatePath(filetools.join(subtitlepath, "Movies")) if not filetools.exists(path_movie_subt): try: filetools.mkdir(path_movie_subt) except: logger.error("error no se pudo crear el path Movies") return full_path_tvshow = "" path_tvshow_subt = xbmc.translatePath(filetools.join(subtitlepath, "Tvshows")) if not filetools.exists(path_tvshow_subt): try: filetools.mkdir(path_tvshow_subt) except: logger.error("error no pudo crear el path Tvshows") return if item.show in item.title: title_new = title = urllib.unquote_plus(item.title) else: title_new = title = urllib.unquote_plus(item.show + " - " + item.title) path_video_temp = xbmc.translatePath(filetools.join(config.get_runtime_path(), "resources", "subtitle.mp4")) if not filetools.exists(path_video_temp): logger.error("error : no existe el video temporal de subtitulos") return # path_video_temp = xbmc.translatePath(filetools.join( ,video_temp + ".mp4" )) title_new = _normalize(title_new) tvshow_title, season, episode = regex_tvshow(False, title_new) if episode != "": full_path_tvshow = xbmc.translatePath(filetools.join(path_tvshow_subt, tvshow_title)) if not filetools.exists(full_path_tvshow): filetools.mkdir(full_path_tvshow) # title_new + ".mp4" full_path_video_new = xbmc.translatePath( filetools.join(full_path_tvshow, "%s %sx%s.mp4" % (tvshow_title, season, episode))) logger.info(full_path_video_new) listitem = xbmcgui.ListItem(title_new, iconImage="DefaultVideo.png", thumbnailImage="") listitem.setInfo("video", {"Title": title_new, "Genre": "Tv shows", "episode": int(episode), "season": int(season), "tvshowtitle": tvshow_title}) else: full_path_video_new = xbmc.translatePath(filetools.join(path_movie_subt, title_new + ".mp4")) listitem = xbmcgui.ListItem(title, iconImage="DefaultVideo.png", thumbnailImage="") listitem.setInfo("video", {"Title": title_new, "Genre": "Movies"}) import time try: filetools.copy(path_video_temp, full_path_video_new) copy = True logger.info("nuevo path =" + full_path_video_new) time.sleep(2) playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist.clear() playlist.add(full_path_video_new, listitem) # xbmcPlayer = xbmc.Player( xbmc.PLAYER_CORE_AUTO ) xbmcPlayer = xbmc.Player() xbmcPlayer.play(playlist) # xbmctools.launchplayer(full_path_video_new,listitem) except: copy = False logger.error("Error : no se pudo copiar") time.sleep(1) if copy: if xbmc.Player().isPlayingVideo(): xbmc.executebuiltin("RunScript(script.xbmc.subtitles)") while xbmc.Player().isPlayingVideo(): continue time.sleep(1) filetools.remove(full_path_video_new) try: if full_path_tvshow != "": filetools.rmdir(full_path_tvshow) except OSError: pass
def update_libtorrent(): logger.info() if not config.get_setting("mct_buffer", server="torrent", default=""): default = config.get_setting("torrent_client", server="torrent", default=0) config.set_setting("torrent_client", default, server="torrent") config.set_setting("mct_buffer", "50", server="torrent") if config.get_setting("mct_download_path", server="torrent", default=config.get_setting("downloadpath")): config.set_setting("mct_download_path", config.get_setting("downloadpath"), server="torrent") config.set_setting("mct_background_download", True, server="torrent") config.set_setting("mct_rar_unpack", True, server="torrent") config.set_setting("bt_buffer", "50", server="torrent") if config.get_setting("bt_download_path", server="torrent", default=config.get_setting("downloadpath")): config.set_setting("bt_download_path", config.get_setting("downloadpath"), server="torrent") config.set_setting("mct_download_limit", "", server="torrent") config.set_setting("magnet2torrent", False, server="torrent") if not filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) or not \ config.get_setting("unrar_path", server="torrent", default=""): path = filetools.join(config.get_runtime_path(), 'lib', 'rarfiles') creationflags = '' sufix = '' unrar = '' for device in filetools.listdir(path): if xbmc.getCondVisibility( "system.platform.android") and 'android' not in device: continue if xbmc.getCondVisibility( "system.platform.windows") and 'windows' not in device: continue if not xbmc.getCondVisibility("system.platform.windows") and not xbmc.getCondVisibility("system.platform.android") \ and ('android' in device or 'windows' in device): continue if 'windows' in device: creationflags = 0x08000000 sufix = '.exe' else: creationflags = '' sufix = '' unrar = filetools.join(path, device, 'unrar%s') % sufix if not filetools.exists(unrar): unrar = '' if unrar: if not xbmc.getCondVisibility("system.platform.windows"): try: if xbmc.getCondVisibility("system.platform.android"): # Para Android copiamos el binario a la partición del sistema unrar_org = unrar unrar = filetools.join( xbmc.translatePath('special://xbmc/'), 'files').replace('/cache/apk/assets', '') if not filetools.exists(unrar): filetools.mkdir(unrar) unrar = filetools.join(unrar, 'unrar') filetools.copy(unrar_org, unrar, silent=True) command = ['chmod', '777', '%s' % unrar] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() command = ['ls', '-l', unrar] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() xbmc.log('######## UnRAR file: %s' % str(output_cmd), xbmc.LOGNOTICE) except: xbmc.log( '######## UnRAR ERROR in path: %s' % str(unrar), xbmc.LOGNOTICE) logger.error(traceback.format_exc(1)) try: if xbmc.getCondVisibility("system.platform.windows"): p = subprocess.Popen(unrar, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=creationflags) else: p = subprocess.Popen(unrar, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() if p.returncode != 0 or error_cmd: xbmc.log('######## UnRAR returncode in module %s: %s, %s in %s' % \ (device, str(p.returncode), str(error_cmd), unrar), xbmc.LOGNOTICE) unrar = '' else: xbmc.log( '######## UnRAR OK in %s: %s' % (device, unrar), xbmc.LOGNOTICE) break except: xbmc.log( '######## UnRAR ERROR in module %s: %s' % (device, unrar), xbmc.LOGNOTICE) logger.error(traceback.format_exc(1)) unrar = '' if unrar: config.set_setting("unrar_path", unrar, server="torrent") if filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) and \ config.get_setting("libtorrent_path", server="torrent", default="") : return try: from lib.python_libtorrent.python_libtorrent import get_libtorrent except Exception as e: logger.error(traceback.format_exc(1)) if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") config.set_setting("libtorrent_path", "", server="torrent") if not config.get_setting( "libtorrent_error", server="torrent", default=''): config.set_setting("libtorrent_error", str(e), server="torrent") return
def get_channel_parameters(channel_name): global dict_channels_parameters if channel_name not in dict_channels_parameters: try: channel_parameters = get_channel_json(channel_name) # logger.debug(channel_parameters) if channel_parameters: # cambios de nombres y valores por defecto channel_parameters["title"] = channel_parameters.pop("name") channel_parameters["channel"] = channel_parameters.pop("id") # si no existe el key se declaran valor por defecto para que no de fallos en las funciones que lo llaman channel_parameters["update_url"] = channel_parameters.get( "update_url", DEFAULT_UPDATE_URL) channel_parameters["language"] = channel_parameters.get( "language", ["all"]) channel_parameters["adult"] = channel_parameters.get( "adult", False) channel_parameters["active"] = channel_parameters.get( "active", False) channel_parameters[ "include_in_global_search"] = channel_parameters.get( "include_in_global_search", False) channel_parameters["categories"] = channel_parameters.get( "categories", list()) channel_parameters["thumbnail"] = channel_parameters.get( "thumbnail", "") channel_parameters["banner"] = channel_parameters.get( "banner", "") channel_parameters["fanart"] = channel_parameters.get( "fanart", "") # Imagenes: se admiten url y archivos locales dentro de "resources/images" if channel_parameters.get( "thumbnail" ) and "://" not in channel_parameters["thumbnail"]: channel_parameters["thumbnail"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "thumb", channel_parameters["thumbnail"]) if channel_parameters.get( "banner" ) and "://" not in channel_parameters["banner"]: channel_parameters["banner"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "banner", channel_parameters["banner"]) if channel_parameters.get( "fanart" ) and "://" not in channel_parameters["fanart"]: channel_parameters["fanart"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "fanart", channel_parameters["fanart"]) # Obtenemos si el canal tiene opciones de configuración channel_parameters["has_settings"] = False if 'settings' in channel_parameters: # if not isinstance(channel_parameters['settings'], list): # channel_parameters['settings'] = [channel_parameters['settings']] # if "include_in_global_search" in channel_parameters['settings']: # channel_parameters["include_in_global_search"] = channel_parameters['settings'] # ["include_in_global_search"].get('default', False) # # found = False # for el in channel_parameters['settings']: # for key in el.items(): # if 'include_in' not in key: # channel_parameters["has_settings"] = True # found = True # break # if found: # break for s in channel_parameters['settings']: if 'id' in s: if s['id'] == "include_in_global_search": channel_parameters[ "include_in_global_search"] = True elif not s['id'].startswith("include_in_") and \ (s.get('enabled', False) or s.get('visible', False)): channel_parameters["has_settings"] = True del channel_parameters['settings'] # Compatibilidad if 'compatible' in channel_parameters: # compatible python python_compatible = True if 'python' in channel_parameters["compatible"]: import sys python_condition = channel_parameters["compatible"][ 'python'] if sys.version_info < tuple( map(int, (python_condition.split(".")))): python_compatible = False # compatible addon_version addon_version_compatible = True if 'addon_version' in channel_parameters["compatible"]: import versiontools addon_version_condition = channel_parameters[ "compatible"]['addon_version'] addon_version = int( addon_version_condition.replace(".", "").ljust( len( str(versiontools. get_current_plugin_version())), '0')) if versiontools.get_current_plugin_version( ) < addon_version: addon_version_compatible = False channel_parameters[ "compatible"] = python_compatible and addon_version_compatible else: channel_parameters["compatible"] = True dict_channels_parameters[channel_name] = channel_parameters else: # para evitar casos donde canales no están definidos como configuración # lanzamos la excepcion y asi tenemos los valores básicos raise Exception except Exception, ex: logger.error(channel_name + ".json error \n%s" % ex) channel_parameters = dict() channel_parameters["channel"] = "" channel_parameters["adult"] = False channel_parameters['active'] = False channel_parameters["compatible"] = True channel_parameters["language"] = "" channel_parameters["update_url"] = DEFAULT_UPDATE_URL return channel_parameters
def addchannel(item): import os import time logger.info() tecleado = platformtools.dialog_input("", "Introduzca la URL") if not tecleado: return logger.info("url=%s" % tecleado) local_folder = config.get_runtime_path() if "canal" in item.title: local_folder = filetools.join(local_folder, 'channels') folder_to_extract = "channels" info_accion = "canal" else: local_folder = filetools.join(local_folder, 'servers') folder_to_extract = "servers" info_accion = "conector" # Detecta si es un enlace a un .py o .xml (pensado sobre todo para enlaces de github) try: extension = tecleado.rsplit(".", 1)[1] except: extension = "" files = [] zip = False if extension == "py" or extension == "xml": filename = tecleado.rsplit("/", 1)[1] localfilename = filetools.join(local_folder, filename) files.append([tecleado, localfilename, filename]) else: import re from core import scrapertools # Comprueba si la url apunta a una carpeta completa (channels o servers) de github if re.search(r'https://github.com/[^\s]+/' + folder_to_extract, tecleado): try: data = scrapertools.downloadpage(tecleado) matches = scrapertools.find_multiple_matches(data, '<td class="content">.*?href="([^"]+)".*?title="([^"]+)"') for url, filename in matches: url = "https://raw.githubusercontent.com" + url.replace("/blob/", "/") localfilename = filetools.join(local_folder, filename) files.append([url, localfilename, filename]) except: import traceback logger.error("Detalle del error: %s" % traceback.format_exc()) platformtools.dialog_ok("Error", "La url no es correcta o no está disponible") return else: filename = 'new%s.zip' % info_accion localfilename = filetools.join(config.get_data_path(), filename) files.append([tecleado, localfilename, filename]) zip = True logger.info("localfilename=%s" % localfilename) logger.info("descarga fichero...") try: if len(files) > 1: lista_opciones = ["No", "Sí", "Sí (Sobrescribir todos)"] overwrite_all = False from core import downloadtools for url, localfilename, filename in files: result = downloadtools.downloadfile(url, localfilename, continuar=False, resumir=False) if result == -3: if len(files) == 1: dyesno = platformtools.dialog_yesno("El archivo ya existe", "Ya existe el %s %s. " "¿Desea sobrescribirlo?" % (info_accion, filename)) else: if not overwrite_all: dyesno = platformtools.dialog_select("El archivo %s ya existe, ¿desea sobrescribirlo?" % filename, lista_opciones) else: dyesno = 1 # Diálogo cancelado if dyesno == -1: return # Caso de carpeta github, opción sobrescribir todos elif dyesno == 2: overwrite_all = True elif dyesno: hora_folder = "Copia seguridad [%s]" % time.strftime("%d-%m_%H-%M", time.localtime()) backup = filetools.join(config.get_data_path(), 'backups', hora_folder, folder_to_extract) if not filetools.exists(backup): os.makedirs(backup) import shutil shutil.copy2(localfilename, filetools.join(backup, filename)) downloadtools.downloadfile(url, localfilename, continuar=True, resumir=False) else: if len(files) == 1: return else: continue except: import traceback logger.error("Detalle del error: %s" % traceback.format_exc()) return if zip: try: # Lo descomprime logger.info("descomprime fichero...") from core import ziptools unzipper = ziptools.ziptools() logger.info("destpathname=%s" % local_folder) unzipper.extract(localfilename, local_folder, folder_to_extract, True, True) except: import traceback logger.error("Detalle del error: %s" % traceback.format_exc()) # Borra el zip descargado filetools.remove(localfilename) platformtools.dialog_ok("Error", "Se ha producido un error extrayendo el archivo") return # Borra el zip descargado logger.info("borra fichero...") filetools.remove(localfilename) logger.info("...fichero borrado") platformtools.dialog_ok("Éxito", "Actualización/Instalación realizada correctamente")
from platformcode import config from platformcode import logger from platformcode import platformtools from core import jsontools from core import filetools ACTION_SHOW_FULLSCREEN = 36 ACTION_GESTURE_SWIPE_LEFT = 511 ACTION_SELECT_ITEM = 7 ACTION_PREVIOUS_MENU = 10 ACTION_MOVE_LEFT = 1 ACTION_MOVE_RIGHT = 2 ACTION_MOVE_DOWN = 4 ACTION_MOVE_UP = 3 media_path = os.path.join(config.get_runtime_path(), "resources/skins/Default/media/Controls/") styles_path = os.path.join(config.get_runtime_path(), 'resources', 'color_styles.json') def color_selector(): logger.info() list_colors = list() data = filetools.read("special://xbmc/system/colors.xml") colors = re.compile('name="([^"]+)"', re.DOTALL).findall(data) for color in colors: list_colors.append("[COLOR %s]%s[/COLOR]" % (color, color.title()))
def findvideos(item): logger.info() itemlist = [] list_opciones = [] IDIOMAS = { "banderita1": "Español", "banderita2": "VOSE", "banderita3": "Latino" } url = "http://estrenosli.org/ver-online-" + item.url data = httptools.downloadpage(url).data data = re.sub(r"\n|\r|\t|\s{2}| ", "", data) patron = '<div class="content"><a href="([^"]+).*?' patron += '<div class="content_mini"><span class="([^"]+)' matches = re.compile(patron, re.DOTALL).findall(data) for url, banderita in matches: idioma = "" if banderita in IDIOMAS: idioma = " [%s]" % IDIOMAS[banderita] data = httptools.downloadpage(url).data data = re.sub(r"\n|\r|\t|\s{2}| ", "", data) if item.extra == 'multi-episodie': patron = '<div class="linksDescarga"><span class="titulo">Video Online:([^<]+).*?<a href="([^"]+)' matches = re.compile(patron, re.DOTALL).findall(data) for capitulo, url in matches: s = servertools.findvideos(url, skip=True) if s: itemlist.append( item.clone( url=s[0][1], action="play", folder=False, server=s[0][2], title="Ver %s en %s%s" % (capitulo.strip(), s[0][2].capitalize(), idioma), thumbnail2=item.thumbnail, thumbnail=get_thumb("server_" + s[0][2] + ".png"), language=idioma)) else: import os for s in servertools.findvideos(data): itemlist.append( item.clone( url=s[1], action="play", folder=False, server=s[2], title="Ver en %s%s" % (s[2].capitalize(), idioma), thumbnail2=item.thumbnail, thumbnail=os.path.join(config.get_runtime_path(), "resources", "media", "servers", "server_" + s[2] + ".png"), language=idioma)) # Insertar items "Buscar trailer" y "Añadir a la videoteca" if itemlist and item.extra == "movie": if item.contentQuality: title = "%s [%s]" % (item.contentTitle, item.contentQuality) else: title = item.contentTitle itemlist.insert( 0, item.clone(channel="trailertools", action="buscartrailer", text_color=color3, title=title, viewmode="list")) if config.get_videolibrary_support(): itemlist.append( Item(channel=item.channel, title="Añadir película a la videoteca", action="add_pelicula_to_library", url=item.url, text_color="green", contentTitle=item.contentTitle, extra="library", thumbnail=thumbnail_host)) return itemlist
def server_config(item): return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "servers", item.config))
def channel_config(item): return platformtools.show_channel_settings(channelpath=os.path.join(config.get_runtime_path(), "channels", item.channel), caption="configuración -- Videoteca")
def play_from_library(item): """ The .strm files when played from kodi, this expects it to be a "playable" file so it cannot contain more items, at most a selection dialog can be placed. We solve this by "cheating kodi" and making him believe that something has been reproduced, so later by "Container.Update ()" we load the strm as if an item from inside the addon were treated, removing all the limitations and allowing to reproduce through the general function without having to create new methods to the video library. @type item: item @param item: item with information """ import xbmcgui, xbmcplugin, xbmc from time import sleep itemlist = [] item.fromLibrary = True logger.debug() # logger.debug("item: \n" + item.tostring('\n')) # Try to reproduce an image (this does nothing and also does not give an error) xbmcplugin.setResolvedUrl( int(sys.argv[1]), True, xbmcgui.ListItem(path=os.path.join(config.get_runtime_path(), "resources", "kod.mp4"))) xbmc.Player().stop() # Modify the action (currently the video library needs "findvideos" since this is where the sources are searched item.action = "findvideos" window_type = config.get_setting("window_type", "videolibrary") # and launch kodi again if xbmc.getCondVisibility('Window.IsMedia') and not window_type == 1: # Conventional window xbmc.executebuiltin("Container.Update(" + sys.argv[0] + "?" + item.tourl() + ")") else: # Pop-up window from specials import videolibrary p_dialog = platformtools.dialog_progress_bg( config.get_localized_string(20000), config.get_localized_string(60683)) p_dialog.update(0, '') item.play_from = 'window' itemlist = videolibrary.findvideos(item) p_dialog.update(100, '') sleep(0.5) p_dialog.close() # while platformtools.is_playing(): # Conventional window # sleep(100) play_time = platformtools.resume_playback(item, True) if not play_time and config.get_setting('autoplay'): return # The number of links to show is limited if config.get_setting("max_links", "videolibrary") != 0: itemlist = limit_itemlist(itemlist) # The list of links is slightly "cleaned" if config.get_setting("replace_VD", "videolibrary") == 1: itemlist = reorder_itemlist(itemlist) if len(itemlist) > 0: while not xbmc.Monitor().abortRequested(): # The user chooses the mirror options = [] selection_implementation = 0 for item in itemlist: item.thumbnail = config.get_online_server_thumb( item.server) quality = '[B][' + item.quality + '][/B]' if item.quality else '' if item.server: path = filetools.join(config.get_runtime_path(), 'servers', item.server.lower() + '.json') name = jsontools.load(open(path, "r").read())['name'] if name.startswith('@'): name = config.get_localized_string( int(name.replace('@', ''))) it = xbmcgui.ListItem( '\n[B]%s[/B] %s - %s' % (name, quality, item.contentTitle)) it.setArt({'thumb': item.thumbnail}) options.append(it) else: selection_implementation += 1 # The selection window opens if (item.contentSerieName and item.contentSeason and item.contentEpisodeNumber): head = ("%s - %sx%s | %s" % (item.contentSerieName, item.contentSeason, item.contentEpisodeNumber, config.get_localized_string(30163))) else: head = config.get_localized_string(30163) selection = platformtools.dialog_select(head, options, preselect=-1, useDetails=True) if selection == -1: return else: item = videolibrary.play( itemlist[selection + selection_implementation])[0] platformtools.play_video(item) if (platformtools.is_playing() and item.action ) or item.server == 'torrent' or config.get_setting( 'autoplay'): break
def run(item=None): logger.debug() 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'): if not config.get_all_settings_addon(): logger.error('corrupted settings.xml!!') settings_xml = os.path.join(config.get_data_path(), "settings.xml") settings_bak = os.path.join(config.get_data_path(), "settings.bak") if filetools.exists(settings_bak): filetools.copy(settings_bak, settings_xml, True) logger.info('restored settings.xml from backup') else: filetools.write(settings_xml, '<settings version="2">\n</settings>' ) # resetted settings else: 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.debug("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 config.get_setting( 'new_search' ) and item.channel == "search" and item.action == 'new_search': from platformcode.globalsearch import Search item.contextual = True Search(item) return elif item.channel == "backup": from platformcode import backup return getattr(backup, item.action)(item) elif item.channel == "elementum_download": from platformcode import elementum_download return getattr(elementum_download, item.action)(item) elif item.channel == "shortcuts": from platformcode import shortcuts return getattr(shortcuts, item.action)(item) elif item.channel == "autorenumber": from platformcode import autorenumber return getattr(autorenumber, 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 elif item.action == "check_channels": from platformcode import checkhost checkhost.check_channels() 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.debug("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.debug("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.debug("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.debug("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.debug("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.debug("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.debug("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()) 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 = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + r'([^.]+)\.py"' 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)): run(Item(channel="setting", action="report_menu"))
def get_server_parameters(server): """ Obtiene los datos del servidor @param server: Nombre del servidor @type server: str @return: datos del servidor @rtype: dict """ # logger.info("server %s" % server) global dict_servers_parameters server = server.split('.')[0] if not server: return {} if server not in dict_servers_parameters: try: # Servers if filetools.isfile( filetools.join(config.get_runtime_path(), "servers", server + ".json")): path = filetools.join(config.get_runtime_path(), "servers", server + ".json") # Debriders elif filetools.isfile( filetools.join(config.get_runtime_path(), "servers", "debriders", server + ".json")): path = filetools.join(config.get_runtime_path(), "servers", "debriders", server + ".json") # #Cuando no está bien definido el server en el canal (no existe conector), muestra error por no haber "path" y se tiene que revisar el canal # dict_server = jsontools.load(filetools.read(path)) # Imagenes: se admiten url y archivos locales dentro de "resources/images" if dict_server.get( "thumbnail") and "://" not in dict_server["thumbnail"]: dict_server["thumbnail"] = filetools.join( config.get_runtime_path(), "resources", "media", "servers", dict_server["thumbnail"]) for k in ['premium', 'id']: dict_server[k] = dict_server.get(k, list()) if isinstance(dict_server[k], str): dict_server[k] = [dict_server[k]] if "find_videos" in dict_server: dict_server['find_videos']["patterns"] = dict_server[ 'find_videos'].get("patterns", list()) dict_server['find_videos']["ignore_urls"] = dict_server[ 'find_videos'].get("ignore_urls", list()) if "settings" in dict_server: dict_server['has_settings'] = True else: dict_server['has_settings'] = False dict_servers_parameters[server] = dict_server except: mensaje = config.get_localized_string(59986) % server import traceback logger.error(mensaje + traceback.format_exc()) return {} return dict_servers_parameters[server]
def show_window(item=None): main = Main('colors.xml', config.get_runtime_path()) main.doModal() del main
def update_external_addon(addon_name): logger.info(addon_name) try: #Verificamos que el addon está instalado if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name): #Path de actualizaciones de Alfa alfa_addon_updates_mig = filetools.join(config.get_runtime_path(), "lib") alfa_addon_updates = filetools.join(alfa_addon_updates_mig, addon_name) #Path de destino en addon externo __settings__ = xbmcaddon.Addon(id="plugin.video." + addon_name) if addon_name.lower() in ['quasar', 'elementum']: addon_path_mig = filetools.join(xbmc.translatePath(__settings__.getAddonInfo('Path')), \ filetools.join("resources", "site-packages")) addon_path = filetools.join(addon_path_mig, addon_name) else: addon_path_mig = '' addon_path = '' #Hay modificaciones en Alfa? Las copiamos al addon, incuidas las carpetas de migración a PY3 if filetools.exists(alfa_addon_updates) and filetools.exists( addon_path): for root, folders, files in filetools.walk( alfa_addon_updates_mig): if ('future' in root or 'past' in root) and not 'concurrent' in root: for file in files: alfa_addon_updates_mig_folder = root.replace( alfa_addon_updates_mig, addon_path_mig) if not filetools.exists( alfa_addon_updates_mig_folder): filetools.mkdir(alfa_addon_updates_mig_folder) if file.endswith('.pyo') or file.endswith('.pyd'): continue input_file = filetools.join(root, file) output_file = input_file.replace( alfa_addon_updates_mig, addon_path_mig) if not filetools.copy( input_file, output_file, silent=True): logger.error( 'Error en la copia de MIGRACIÓN: Input: %s o Output: %s' % (input_file, output_file)) return False for root, folders, files in filetools.walk(alfa_addon_updates): for file in files: input_file = filetools.join(root, file) output_file = input_file.replace( alfa_addon_updates, addon_path) if not filetools.copy( input_file, output_file, silent=True): logger.error( 'Error en la copia: Input: %s o Output: %s' % (input_file, output_file)) return False return True else: logger.error('Alguna carpeta no existe: Alfa: %s o %s: %s' % (alfa_addon_updates, addon_name, addon_path)) # Se ha desinstalado Quasar, reseteamos la opción else: config.set_setting('addon_quasar_update', False) if filetools.exists( filetools.join(config.get_data_path(), "%s.json" % addon_name)): filetools.remove( filetools.join(config.get_data_path(), "%s.json" % addon_name)) return True except: logger.error(traceback.format_exc()) return False
def filterchannels(category, view="thumb_"): logger.info() channelslist = [] # Si category = "allchannelstatus" es que estamos activando/desactivando canales appenddisabledchannels = False if category == "allchannelstatus": category = "all" appenddisabledchannels = True # Lee la lista de canales channel_path = os.path.join(config.get_runtime_path(), "channels", '*.json') logger.info("channel_path=%s" % channel_path) channel_files = glob.glob(channel_path) logger.info("channel_files encontrados %s" % (len(channel_files))) channel_language = config.get_setting("channel_language", default="all") logger.info("channel_language=%s" % channel_language) for channel_path in channel_files: logger.info("channel=%s" % channel_path) channel = os.path.basename(channel_path).replace(".json", "") try: channel_parameters = channeltools.get_channel_parameters(channel) # si el canal no es compatible, no se muestra if not channel_parameters["compatible"]: continue # Si no es un canal lo saltamos if not channel_parameters["channel"]: continue logger.info("channel_parameters=%s" % repr(channel_parameters)) # Si prefiere el banner y el canal lo tiene, cambia ahora de idea if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] # si el canal está desactivado no se muestra el canal en la lista if not channel_parameters["active"]: continue # Se salta el canal si no está activo y no estamos activando/desactivando los canales channel_status = config.get_setting("enabled", channel_parameters["channel"]) if channel_status is None: # si channel_status no existe es que NO HAY valor en _data.json. # como hemos llegado hasta aquí (el canal está activo en channel.json), se devuelve True channel_status = True if not channel_status: # si obtenemos el listado de canales desde "activar/desactivar canales", y el canal está desactivado # lo mostramos, si estamos listando todos los canales desde el listado general y está desactivado, # no se muestra if not appenddisabledchannels: continue # Se salta el canal para adultos si el modo adultos está desactivado if channel_parameters["adult"] and config.get_setting( "adult_mode") == 0: continue # Se salta el canal si está en un idioma filtrado # Se muestran todos los canales si se elige "all" en el filtrado de idioma # Se muestran sólo los idiomas filtrados, cast o lat # Los canales de adultos se mostrarán siempre que estén activos if channel_language != "all" and channel_language not in channel_parameters["language"] \ and "*" not in channel_parameters["language"]: continue # Se salta el canal si está en una categoria filtrado if category != "all" and category not in channel_parameters[ "categories"]: continue # Si tiene configuración añadimos un item en el contexto context = [] if channel_parameters["has_settings"]: context.append({ "title": "Configurar canal", "channel": "setting", "action": "channel_config", "config": channel_parameters["channel"] }) # Si ha llegado hasta aquí, lo añade channelslist.append( Item(title=channel_parameters["title"], channel=channel_parameters["channel"], action="mainlist", thumbnail=channel_parameters["thumbnail"], fanart=channel_parameters["fanart"], category=channel_parameters["title"], language=channel_parameters["language"], viewmode="list", context=context)) except: logger.error( "Se ha producido un error al leer los datos del canal '%s'" % channel) import traceback logger.error(traceback.format_exc()) channelslist.sort(key=lambda item: item.title.lower().strip()) if category == "all": channel_parameters = channeltools.get_channel_parameters('url') # Si prefiere el banner y el canal lo tiene, cambia ahora de idea if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] channelslist.insert( 0, Item(title="Tengo una URL", action="mainlist", channel="url", thumbnail=channel_parameters["thumbnail"], type="generic", viewmode="list")) return channelslist
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: #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(xbmc.translatePath('special://home'), 'addons', 'packages', version), True) #Borrar contenido de carpeta de Torrents filetools.rmdirtree(filetools.join(config.get_videolibrary_path(), 'temp_torrents_Alfa'), silent=True) #Verifica si Kodi tiene algún achivo de Base de Datos de Vídeo de versiones anteriores, entonces los borra verify_Kodi_video_DB() #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) except: logger.error(traceback.format_exc())
def update(path, p_dialog, i, t, serie, overwrite, redir=True): logger.info("Actualizando " + path) from core import filetools from core import channeltools, videolibrarytools from platformcode import platformtools from channels import videolibrary from lib import generictools if config.is_xbmc(): from platformcode import xbmc_videolibrary insertados_total = 0 insertados = 0 sobreescritos = 0 fallidos = 0 overwrite_back = overwrite head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') category = serie.category # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in list(serie.library_urls.items()): serie.channel = channel serie.url = url ###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial if redir: try: head_nfo, it = videolibrarytools.read_nfo( path + '/tvshow.nfo' ) #Refresca el .nfo para recoger actualizaciones if not it: logger.error('.nfo erroneo en ' + str(path)) continue if it.emergency_urls: serie.emergency_urls = it.emergency_urls serie.category = category serie, it, overwrite = generictools.redirect_clone_newpct1( serie, head_nfo, it, path, overwrite) except: logger.error(traceback.format_exc()) channel_enabled = channeltools.is_enabled(serie.channel) if channel_enabled: heading = config.get_localized_string(60389) p_dialog.update( int(math.ceil((i + 1) * t)), heading, "%s: %s" % (serie.contentSerieName, serie.channel.capitalize())) try: pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py') logger.info("Cargando canal: " + pathchannels + " " + serie.channel) if serie.library_filter_show: serie.show = serie.library_filter_show.get( channel, serie.contentSerieName) if redir: serie = videolibrarytools.redirect_url(serie) obj = __import__('channels.%s' % serie.channel, fromlist=["channels.%s" % serie.channel]) itemlist = getattr(obj, 'episodios')( serie) #... se procesa Episodios para ese canal try: if int(overwrite_back) == 3: # Sobrescribir todos los archivos (tvshow.nfo, 1x01.nfo, 1x01 [canal].json, 1x01.strm, etc...) insertados, sobreescritos, fallidos, notusedpath = videolibrarytools.save_tvshow( serie, itemlist, silent=True, overwrite=overwrite_back) #serie= videolibrary.check_season_playcount(serie, serie.contentSeason) #if videolibrarytools.write_nfo(path + '/tvshow.nfo', head_nfo, it): # serie.infoLabels['playcount'] = serie.playcount else: insertados, sobreescritos, fallidos = videolibrarytools.save_episodes( path, itemlist, serie, silent=True, overwrite=overwrite) #it = videolibrary.check_season_playcount(it, it.contentSeason) #if videolibrarytools.write_nfo(path + '/tvshow.nfo', head_nfo, it): # serie.infoLabels['playcount'] = serie.playcount insertados_total += insertados except Exception as ex: logger.error("Error al guardar los capitulos de la serie") template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) logger.error(traceback.format_exc()) continue except Exception as ex: logger.error("Error al obtener los episodios de: %s" % serie.show) template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) logger.error(traceback.format_exc()) continue #Si el canal lo permite, se comienza el proceso de descarga de los nuevos episodios descargados serie.channel = generictools.verify_channel(serie.channel) if insertados > 0 and config.get_setting( 'auto_download_new', serie.channel, default=False) and int(overwrite_back) != 3: config.set_setting( "search_new_content", 1, "videolibrary") # Escaneamos a final todas la series serie.sub_action = 'auto' serie.category = itemlist[0].category from channels import downloads downloads.save_download(serie, silent=True) if serie.sub_action: del serie.sub_action else: logger.debug("Canal %s no activo no se actualiza" % serie.channel) #Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc() and not config.get_setting('cleanlibrary', 'videolibrary', default=False) \ and int(overwrite_back) != 3: #Si es Kodi, lo hacemos xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) return insertados_total > 0
def do_search(item, categories=None): logger.info("blaa categorias %s" % categories) if item.contextual==True: categories = ["Películas"] setting_item = Item(channel=item.channel, title="Elegir canales incluidos en la búsqueda", folder=False, thumbnail=get_thumb("search.png")) setting_channel(setting_item) if categories is None: categories = [] multithread = config.get_setting("multithread", "search") result_mode = config.get_setting("result_mode", "search") if item.wanted!='': tecleado=item.wanted else: tecleado = item.extra itemlist = [] channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json') logger.info("channels_path=%s" % channels_path) channel_language = config.get_setting("channel_language", default="all") logger.info("channel_language=%s" % channel_language) # Para Kodi es necesario esperar antes de cargar el progreso, de lo contrario # el cuadro de progreso queda "detras" del cuadro "cargando..." y no se le puede dar a cancelar time.sleep(0.5) progreso = platformtools.dialog_progress("Buscando '%s'..." % tecleado, "") channel_files = sorted(glob.glob(channels_path), key=lambda x: os.path.basename(x)) import math # fix float porque la division se hace mal en python 2.x number_of_channels = float(100) / len(channel_files) threads = [] search_results = {} start_time = time.time() for index, infile in enumerate(channel_files): try: percentage = int(math.ceil((index + 1) * number_of_channels)) basename = os.path.basename(infile) basename_without_extension = basename[:-5] logger.info("%s..." % basename_without_extension) channel_parameters = channeltools.get_channel_parameters(basename_without_extension) # No busca si es un canal inactivo if not channel_parameters["active"]: logger.info("%s -no activo-" % basename_without_extension) continue # En caso de búsqueda por categorias if categories: # Si no se ha seleccionado torrent no se muestra if "torrent" not in categories: if "torrent" in channel_parameters["categories"]: logger.info("%s -torrent-" % basename_without_extension) continue for cat in categories: if cat not in channel_parameters["categories"]: logger.info("%s -no en %s-" % (basename_without_extension, cat)) continue # No busca si es un canal para adultos, y el modo adulto está desactivado if channel_parameters["adult"] and config.get_setting("adult_mode") == 0: logger.info("%s -adulto-" % basename_without_extension) continue # No busca si el canal es en un idioma filtrado if channel_language != "all" and channel_language not in channel_parameters["language"] \ and "*" not in channel_parameters["language"]: logger.info("%s -idioma no válido-" % basename_without_extension) continue # No busca si es un canal excluido de la búsqueda global include_in_global_search = channel_parameters["include_in_global_search"] if include_in_global_search: # Buscar en la configuracion del canal include_in_global_search = config.get_setting("include_in_global_search", basename_without_extension) if not include_in_global_search: logger.info("%s -no incluido en lista a buscar-" % basename_without_extension) continue if progreso.iscanceled(): progreso.close() logger.info("Búsqueda cancelada") return itemlist # Modo Multi Thread if multithread: t = Thread(target=channel_search, args=[search_results, channel_parameters, tecleado], name=channel_parameters["title"]) t.setDaemon(True) t.start() threads.append(t) # Modo single Thread else: logger.info("Intentado búsqueda en %s de %s " % (basename_without_extension, tecleado)) channel_search(search_results, channel_parameters, tecleado) logger.info("%s incluido en la búsqueda" % basename_without_extension) progreso.update(percentage, "Buscando en %s..." % channel_parameters["title"]) except: logger.error("No se puede buscar en: %s" % channel_parameters["title"]) import traceback logger.error(traceback.format_exc()) continue # Modo Multi Thread # Usando isAlive() no es necesario try-except, # ya que esta funcion (a diferencia de is_alive()) # es compatible tanto con versiones antiguas de python como nuevas if multithread: pendent = [a for a in threads if a.isAlive()] t = float(100) / len(pendent) while pendent: index = (len(threads) - len(pendent)) + 1 percentage = int(math.ceil(index * t)) list_pendent_names = [a.getName() for a in pendent] mensaje = "Buscando en %s" % (", ".join(list_pendent_names)) progreso.update(percentage, "Finalizado en %d/%d canales..." % (len(threads) - len(pendent), len(threads)), mensaje) logger.debug(mensaje) if progreso.iscanceled(): logger.info("Búsqueda cancelada") break time.sleep(0.5) pendent = [a for a in threads if a.isAlive()] total = 0 for channel in sorted(search_results.keys()): for element in search_results[channel]: total += len(element["itemlist"]) title = channel # resultados agrupados por canales if item.contextual == True: result_mode = 1 if result_mode == 0: if len(search_results[channel]) > 1: title += " [%s]" % element["item"].title.strip() title += " (%s)" % len(element["itemlist"]) title = re.sub("\[COLOR [^\]]+\]", "", title) title = re.sub("\[/COLOR]", "", title) itemlist.append(Item(title=title, channel="search", action="show_result", url=element["item"].url, extra=element["item"].extra, folder=True, adult=element["adult"], from_action="search", from_channel=element["item"].channel, tecleado=tecleado)) # todos los resultados juntos, en la misma lista else: title = " [ Resultados del canal %s ] " % channel itemlist.append(Item(title=title, channel="search", action="", folder=False, text_bold=True, from_channel=channel)) for i in element["itemlist"]: if i.action: title = " " + i.title itemlist.append(i.clone(title=title, from_action=i.action, from_channel=i.channel, channel="search", action="show_result", adult=element["adult"])) title = "Buscando: '%s' | Encontrado: %d vídeos | Tiempo: %2.f segundos" % ( tecleado, total, time.time() - start_time) itemlist.insert(0, Item(title=title, text_color='yellow')) progreso.close() #Para opcion Buscar en otros canales if item.contextual == True: return exact_results(itemlist, tecleado) else: return itemlist
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, 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)
def check_addon_updates(verbose=False): logger.info() ADDON_UPDATES_JSON = 'http://extra.alfa-addon.com/addon_updates/updates.json' ADDON_UPDATES_ZIP = 'http://extra.alfa-addon.com/addon_updates/updates.zip' 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 # Descargar json con las posibles actualizaciones # ----------------------------------------------- data = httptools.downloadpage(ADDON_UPDATES_JSON, timeout=2).data if data == '': logger.info('No se encuentran actualizaciones del addon') if verbose: platformtools.dialog_notification( 'Alfa ya está actualizado', 'No hay ninguna actualización urgente') 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: platformtools.dialog_notification( 'Alfa ya está actualizado', 'No hay ninguna actualización urgente') 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) if current_version != data['addon_version']: logger.info('No hay actualizaciones para la versión %s del addon' % current_version) if verbose: platformtools.dialog_notification( 'Alfa ya está actualizado', 'No hay ninguna actualización urgente') return False if os.path.exists(last_fix_json): lastfix = jsontools.load(filetools.read(last_fix_json)) 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: platformtools.dialog_notification( 'Alfa ya está actualizado', 'Versión %s.fix%d' % (data['addon_version'], data['fix_version'])) return False # Descargar zip con las actualizaciones # ------------------------------------- localfilename = os.path.join(config.get_data_path(), 'temp_updates.zip') if os.path.exists(localfilename): os.remove(localfilename) downloadtools.downloadfile(ADDON_UPDATES_ZIP, localfilename, silent=True) # Descomprimir zip dentro del addon # --------------------------------- unzipper = ziptools.ziptools() unzipper.extract(localfilename, config.get_runtime_path()) # Borrar el zip descargado # ------------------------ os.remove(localfilename) # Guardar información de la versión fixeada # ----------------------------------------- if 'files' in data: data.pop('files', None) filetools.write(last_fix_json, jsontools.dump(data)) logger.info('Addon actualizado correctamente a %s.fix%d' % (data['addon_version'], data['fix_version'])) if verbose: platformtools.dialog_notification( 'Alfa actualizado a', 'Versión %s.fix%d' % (data['addon_version'], data['fix_version'])) return True except: logger.error('Error al comprobar actualizaciones del addon!') if verbose: platformtools.dialog_notification( 'Alfa actualizaciones', 'Error al comprobar actualizaciones') return False
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, 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)
def open_shortcut_menu(): main = Main('ShortCutMenu.xml', config.get_runtime_path()) main.doModal() del main
def play_from_library(item): """ Los .strm al reproducirlos desde kodi, este espera que sea un archivo "reproducible" asi que no puede contener más items, como mucho se puede colocar un dialogo de seleccion. Esto lo solucionamos "engañando a kodi" y haciendole creer que se ha reproducido algo, asi despues mediante "Container.Update()" cargamos el strm como si un item desde dentro del addon se tratara, quitando todas las limitaciones y permitiendo reproducir mediante la funcion general sin tener que crear nuevos métodos para la videoteca. @type item: item @param item: elemento con información """ logger.info() #logger.debug("item: \n" + item.tostring('\n')) import xbmcgui import xbmcplugin import xbmc from time import sleep # Intentamos reproducir una imagen (esto no hace nada y ademas no da error) xbmcplugin.setResolvedUrl( int(sys.argv[1]), True, xbmcgui.ListItem(path=os.path.join(config.get_runtime_path(), "resources", "subtitle.mp4"))) # Por si acaso la imagen hiciera (en futuras versiones) le damos a stop para detener la reproduccion sleep(0.5) ### Si no se pone esto se bloquea Kodi xbmc.Player().stop() # modificamos el action (actualmente la videoteca necesita "findvideos" ya que es donde se buscan las fuentes item.action = "findvideos" window_type = config.get_setting("window_type", "videolibrary") # y volvemos a lanzar kodi if xbmc.getCondVisibility('Window.IsMedia') and not window_type == 1: # Ventana convencional xbmc.executebuiltin("Container.Update(" + sys.argv[0] + "?" + item.tourl() + ")") else: # Ventana emergente from channels import videolibrary p_dialog = platformtools.dialog_progress_bg( config.get_localized_string(20000), config.get_localized_string(70004)) p_dialog.update(0, '') itemlist = videolibrary.findvideos(item) while platformtools.is_playing(): # Ventana convencional sleep(5) p_dialog.update(50, '') '''# Se filtran los enlaces segun la lista negra if config.get_setting('filter_servers', "servers"): itemlist = servertools.filter_servers(itemlist)''' # Se limita la cantidad de enlaces a mostrar if config.get_setting("max_links", "videolibrary") != 0: itemlist = limit_itemlist(itemlist) # Se "limpia" ligeramente la lista de enlaces if config.get_setting("replace_VD", "videolibrary") == 1: itemlist = reorder_itemlist(itemlist) import time p_dialog.update(100, '') time.sleep(0.5) p_dialog.close() if len(itemlist) > 0: while not xbmc.Monitor().abortRequested(): # El usuario elige el mirror opciones = [] for item in itemlist: opciones.append(item.title) # Se abre la ventana de seleccion if (item.contentSerieName != "" and item.contentSeason != "" and item.contentEpisodeNumber != ""): cabecera = ("%s - %sx%s -- %s" % (item.contentSerieName, item.contentSeason, item.contentEpisodeNumber, config.get_localized_string(30163))) else: cabecera = config.get_localized_string(30163) seleccion = platformtools.dialog_select(cabecera, opciones) if seleccion == -1: return else: item = videolibrary.play(itemlist[seleccion])[0] platformtools.play_video(item) from channels import autoplay if (platformtools.is_playing() and item.action ) or item.server == 'torrent' or autoplay.is_active( item.contentChannel): break
def get_channel_parameters(channel_name): global dict_channels_parameters if channel_name not in dict_channels_parameters: try: channel_parameters = get_channel_json(channel_name) # logger.debug(channel_parameters) if channel_parameters: # cambios de nombres y valores por defecto channel_parameters["title"] = channel_parameters.pop("name") channel_parameters["channel"] = channel_parameters.pop("id") # si no existe el key se declaran valor por defecto para que no de fallos en las funciones que lo llaman channel_parameters["update_url"] = channel_parameters.get( "update_url", DEFAULT_UPDATE_URL) channel_parameters["language"] = channel_parameters.get( "language", ["all"]) channel_parameters["adult"] = channel_parameters.get( "adult", False) channel_parameters["active"] = channel_parameters.get( "active", False) channel_parameters[ "include_in_global_search"] = channel_parameters.get( "include_in_global_search", False) channel_parameters["categories"] = channel_parameters.get( "categories", list()) channel_parameters["thumbnail"] = channel_parameters.get( "thumbnail", "") channel_parameters["banner"] = channel_parameters.get( "banner", "") channel_parameters["fanart"] = channel_parameters.get( "fanart", "") # Imagenes: se admiten url y archivos locales dentro de "resources/images" if channel_parameters.get( "thumbnail" ) and "://" not in channel_parameters["thumbnail"]: channel_parameters["thumbnail"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "thumb", channel_parameters["thumbnail"]) if channel_parameters.get( "banner" ) and "://" not in channel_parameters["banner"]: channel_parameters["banner"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "banner", channel_parameters["banner"]) if channel_parameters.get( "fanart" ) and "://" not in channel_parameters["fanart"]: channel_parameters["fanart"] = os.path.join( config.get_runtime_path(), "resources", "media", "channels", "fanart", channel_parameters["fanart"]) # Obtenemos si el canal tiene opciones de configuración channel_parameters["has_settings"] = False if 'settings' in channel_parameters: for s in channel_parameters['settings']: if 'id' in s: if s['id'] == "include_in_global_search": channel_parameters[ "include_in_global_search"] = True elif s['id'] == "filter_languages": channel_parameters["filter_languages"] = s.get( 'lvalues', []) elif not s['id'].startswith("include_in_") and \ (s.get('enabled', False) or s.get('visible', False)): channel_parameters["has_settings"] = True del channel_parameters['settings'] dict_channels_parameters[channel_name] = channel_parameters else: # para evitar casos donde canales no están definidos como configuración # lanzamos la excepcion y asi tenemos los valores básicos raise Exception except Exception, ex: logger.error(channel_name + ".json error \n%s" % ex) channel_parameters = dict() channel_parameters["channel"] = "" channel_parameters["adult"] = False channel_parameters['active'] = False channel_parameters["language"] = "" channel_parameters["update_url"] = DEFAULT_UPDATE_URL return channel_parameters
def filterchannels(category, view="thumb_"): logger.info('Filter Channels ' + category) channelslist = [] # If category = "allchannelstatus" is that we are activating / deactivating channels appenddisabledchannels = False if category == "allchannelstatus": category = "all" appenddisabledchannels = True channel_path = os.path.join(config.get_runtime_path(), 'channels', '*.json') logger.info("channel_path = %s" % channel_path) channel_files = glob.glob(channel_path) logger.info("channel_files found %s" % (len(channel_files))) # Channel Language channel_language = auto_filter() logger.info("channel_language=%s" % channel_language) for channel_path in channel_files: logger.info("channel in for = %s" % channel_path) channel = os.path.basename(channel_path).replace(".json", "") try: channel_parameters = channeltools.get_channel_parameters(channel) if channel_parameters["channel"] == 'community': continue # If it's not a channel we skip it if not channel_parameters["channel"]: continue logger.info("channel_parameters=%s" % repr(channel_parameters)) # If you prefer the banner and the channel has it, now change your mind if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] # if the channel is deactivated the channel is not shown in the list if not channel_parameters["active"]: continue # The channel is skipped if it is not active and we are not activating / deactivating the channels channel_status = config.get_setting("enabled", channel_parameters["channel"]) if channel_status is None: # if channel_status does not exist, there is NO value in _data.json. # as we got here (the channel is active in channel.json), True is returned channel_status = True if not channel_status: # if we get the list of channels from "activate / deactivate channels", and the channel is deactivated # we show it, if we are listing all the channels from the general list and it is deactivated, it is not shown if not appenddisabledchannels: continue if channel_language != "all" and "*" not in channel_parameters["language"] \ and channel_language not in str(channel_parameters["language"]): continue # The channel is skipped if it is in a filtered category if category != "all" and category not in channel_parameters[ "categories"]: continue # If you have configuration we add an item in the context context = [] if channel_parameters["has_settings"]: context.append({ "title": config.get_localized_string(70525), "channel": "setting", "action": "channel_config", "config": channel_parameters["channel"] }) channel_info = set_channel_info(channel_parameters) # If it has come this far, add it channelslist.append( Item(title=channel_parameters["title"], channel=channel_parameters["channel"], action="mainlist", thumbnail=channel_parameters["thumbnail"], fanart=channel_parameters["fanart"], plot=channel_info, category=channel_parameters["title"], language=channel_parameters["language"], viewmode="list", context=context)) except: logger.error( "An error occurred while reading the channel data '%s'" % channel) import traceback logger.error(traceback.format_exc()) channelslist.sort(key=lambda item: item.title.lower().strip()) if not config.get_setting("only_channel_icons"): if category == "all": channel_parameters = channeltools.get_channel_parameters('url') # If you prefer the banner and the channel has it, now change your mind if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] channelslist.insert( 0, Item(title=config.get_localized_string(60088), action="mainlist", channel="url", thumbnail=channel_parameters["thumbnail"], type="generic", viewmode="list")) # Special Category if category in ['movie', 'tvshow']: titles = [ config.get_localized_string(70028), config.get_localized_string(30985), config.get_localized_string(70559), config.get_localized_string(60264), config.get_localized_string(70560) ] ids = ['popular', 'top_rated', 'now_playing', 'on_the_air'] for x in range(0, 3): if x == 2 and category != 'movie': title = titles[x + 1] id = ids[x + 1] else: title = titles[x] id = ids[x] channelslist.insert( x, Item(channel='search', action='discover_list', title=title, search_type='list', list_type='%s/%s' % (category.replace('show', ''), id), mode=category, thumbnail=get_thumb(id + ".png"))) channelslist.insert( 3, Item(channel='search', action='genres_menu', title=config.get_localized_string(30987), type=category.replace('show', ''), mode=category, thumbnail=get_thumb("genres.png"))) return channelslist
def filterchannels(category, view="thumb_"): logger.info() channelslist = [] # Si category = "allchannelstatus" es que estamos activando/desactivando canales appenddisabledchannels = False if category == "allchannelstatus": category = "all" appenddisabledchannels = True # Lee la lista de canales channel_path = os.path.join(config.get_runtime_path(), "channels", '*.json') logger.info("channel_path=%s" % channel_path) channel_files = glob.glob(channel_path) logger.info("channel_files encontrados %s" % (len(channel_files))) # channel_language = config.get_setting("channel_language", default="all") channel_language = auto_filter() logger.info("channel_language=%s" % channel_language) for channel_path in channel_files: logger.info("channel=%s" % channel_path) channel = os.path.basename(channel_path).replace(".json", "") try: channel_parameters = channeltools.get_channel_parameters(channel) if channel_parameters["channel"] == 'community': continue # si el canal no es compatible, no se muestra if not channel_parameters["compatible"]: continue # Si no es un canal lo saltamos if not channel_parameters["channel"]: continue logger.info("channel_parameters=%s" % repr(channel_parameters)) # Si prefiere el banner y el canal lo tiene, cambia ahora de idea if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] # si el canal está desactivado no se muestra el canal en la lista if not channel_parameters["active"]: continue # Se salta el canal si no está activo y no estamos activando/desactivando los canales channel_status = config.get_setting("enabled", channel_parameters["channel"]) if channel_status is None: # si channel_status no existe es que NO HAY valor en _data.json. # como hemos llegado hasta aquí (el canal está activo en channel.json), se devuelve True channel_status = True if not channel_status: # si obtenemos el listado de canales desde "activar/desactivar canales", y el canal está desactivado # lo mostramos, si estamos listando todos los canales desde el listado general y está desactivado, # no se muestra if not appenddisabledchannels: continue # Se salta el canal para adultos si el modo adultos está desactivado if channel_parameters["adult"] and config.get_setting("adult_mode") == 0: continue # Se salta el canal si está en un idioma filtrado # Se muestran todos los canales si se elige "all" en el filtrado de idioma # Se muestran sólo los idiomas filtrados, cast o lat # Los canales de adultos se mostrarán siempre que estén activos if channel_language != "all" and channel_language not in channel_parameters["language"] \ and "*" not in channel_parameters["language"]: continue # Se salta el canal si está en una categoria filtrado if category != "all" and category not in channel_parameters["categories"]: continue # Si tiene configuración añadimos un item en el contexto context = [] if channel_parameters["has_settings"]: context.append({"title": config.get_localized_string(70525), "channel": "setting", "action": "channel_config", "config": channel_parameters["channel"]}) channel_info = set_channel_info(channel_parameters) # Si ha llegado hasta aquí, lo añade channelslist.append(Item(title=channel_parameters["title"], channel=channel_parameters["channel"], action="mainlist", thumbnail=channel_parameters["thumbnail"], fanart=channel_parameters["fanart"], plot=channel_info, category=channel_parameters["title"], language=channel_parameters["language"], viewmode="list", context=context)) except: logger.error("Se ha producido un error al leer los datos del canal '%s'" % channel) import traceback logger.error(traceback.format_exc()) channelslist.sort(key=lambda item: item.title.lower().strip()) if category == "all": channel_parameters = channeltools.get_channel_parameters('url') # Si prefiere el banner y el canal lo tiene, cambia ahora de idea if view == "banner_" and "banner" in channel_parameters: channel_parameters["thumbnail"] = channel_parameters["banner"] channelslist.insert(0, Item(title=config.get_localized_string(60088), action="mainlist", channel="url", thumbnail=channel_parameters["thumbnail"], type="generic", viewmode="list")) if category in ['movie', 'tvshow']: titles = [config.get_localized_string(70028), config.get_localized_string(30985), config.get_localized_string(70559), config.get_localized_string(60264), config.get_localized_string(70560)] ids = ['popular', 'top_rated', 'now_playing', 'on_the_air'] for x in range(0,3): if x == 2 and category != 'movie': title=titles[x+1] id = ids[x+1] else: title=titles[x] id = ids[x] channelslist.insert(x, Item(channel='search', action='discover_list', title=title, search_type='list', list_type='%s/%s' % (category.replace('show',''), id), thumbnail=get_thumb(id+".png"))) channelslist.insert(3, Item(channel='search', action='genres_menu', title=config.get_localized_string(30987), type=category.replace('show',''), thumbnail=get_thumb("genres.png"))) return channelslist
def mark_season_as_watched_on_kodi(item, value=1): """ marca toda la temporada como vista o no vista en la libreria de Kodi @type item: item @param item: elemento a marcar @type value: int @param value: >0 para visto, 0 para no visto """ logger.info() # logger.debug("item:\n" + item.tostring('\n')) # Solo podemos marcar la temporada como vista en la BBDD de Kodi si la BBDD es local, # en caso de compartir BBDD esta funcionalidad no funcionara if config.get_setting("db_mode", "videolibrary"): return if value == 0: value = 'Null' request_season = '' if item.contentSeason: request_season = ' and c12= %s' % item.contentSeason request_episode = '' if item.contentSeason and item.contentEpisodeNumber: season_episode = '%sx%s.strm' % (str( item.contentSeason), str(item.contentEpisodeNumber).zfill(2)) request_episode = ' and strFileName= "%s"' % season_episode if item.video_path: path = item.video_path else: path = item.path if item.contentType == 'movie': video_path = filetools.join(config.get_videolibrary_path(), config.get_setting("folder_movies")) view = 'movie' else: video_path = filetools.join(config.get_videolibrary_path(), config.get_setting("folder_tvshows")) view = 'episode' item_path1 = "%" + path.replace("\\\\", "\\").replace(video_path, "") if item_path1[:-1] != "\\": item_path1 += "\\" item_path2 = item_path1.replace("\\", "/") while xbmc.getCondVisibility( 'Library.IsScanningVideo()'): # Por si la DB está Scanning time.sleep(1) sql = 'update files set playCount= %s where idFile in ' \ '(select idfile from %s_view where (strPath like "%s" or strPath like "%s")%s%s)' % \ (value, view, item_path1, item_path2, request_season, request_episode) nun_records, records = execute_sql_kodi(sql) if not nun_records: return # Lanzamos un scan de la Videoteca de Kodi contra un directorio vacío para forzar el refresco de los widgets de pelis y series payload = { "jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1, "params": { "directory": filetools.join(config.get_runtime_path(), 'tools') } } while xbmc.getCondVisibility('Library.IsScanningVideo()'): return # Ya está actualizando try: data = get_data(payload) """ # Recargamos el Skin para que actualice los widgets. Dejamos un tiempo para que termine la actualización xbmc.executebuiltin('ReloadSkin()') time.sleep(1) """ except: pass