def move_to_libray(item): try: from platformcode import library except: return # Copiamos el archivo a la biblioteca origen = filetools.join(config.get_setting("downloadpath"), item.downloadFilename) destino = filetools.join(config.get_library_path(), *filetools.split(item.downloadFilename)) if not filetools.isdir(filetools.dirname(destino)): filetools.mkdir(filetools.dirname(destino)) if filetools.isfile(destino) and filetools.isfile(origen) : filetools.remove(destino) if filetools.isfile(origen): filetools.move(origen, destino) if len(filetools.listdir(filetools.dirname(origen))) == 0: filetools.rmdir(filetools.dirname(origen)) else: logger.error("No se ha encontrado el archivo: %s" % origen) if filetools.isfile(destino): if item.contentType == "movie" and item.infoLabels["tmdb_id"]: library_item = Item(title="Descargado: %s" % item.downloadFilename, channel= "descargas", action="findvideos", infoLabels=item.infoLabels, url=destino) library.save_library_movie(library_item) elif item.contentType == "episode" and item.infoLabels["tmdb_id"]: library_item = Item(title="Descargado: %s" % item.downloadFilename, channel= "descargas", action="findvideos", infoLabels=item.infoLabels, url=destino) tvshow = Item(channel= "descargas", contentType="tvshow", infoLabels = {"tmdb_id": item.infoLabels["tmdb_id"]}) library.save_library_tvshow(tvshow, [library_item])
def check_bookmark(readpath): # Crea un listado con las entradas de favoritos itemlist = [] if readpath.startswith("special://") and config.is_xbmc(): import xbmc readpath = xbmc.translatePath(readpath) for fichero in sorted(filetools.listdir(readpath)): # Ficheros antiguos (".txt") if fichero.endswith(".txt"): # Esperamos 0.1 segundos entre ficheros, para que no se solapen los nombres de archivo time.sleep(0.1) # Obtenemos el item desde el .txt canal, titulo, thumbnail, plot, server, url, fulltitle = readbookmark(filetools.join(readpath, fichero)) if canal == "": canal = "favoritos" item = Item(channel=canal, action="play", url=url, server=server, title=fulltitle, thumbnail=thumbnail, plot=plot, fanart=thumbnail, fulltitle=fulltitle, folder=False) filetools.rename(filetools.join(readpath, fichero),fichero[:-4] + ".old") itemlist.append(item) # Si hay Favoritos q guardar if itemlist: favourites_list = read_favourites() for item in itemlist: data = "ActivateWindow(10025,"plugin://plugin.video.pelisalacarta/?" + item.tourl() + "",return)" favourites_list.append((item.title, item.thumbnail, data)) if save_favourites(favourites_list): logger.debug("Conversion de txt a xml correcta")
def save_library_tvshow(item, episodelist): """ guarda en la libreria de series la serie con todos los capitulos incluidos en la lista episodelist @type item: item @param item: item que representa la serie a guardar @type episodelist: list @param episodelist: listado de items que representan los episodios que se van a guardar. @rtype insertados: int @return: el número de episodios insertados @rtype sobreescritos: int @return: el número de episodios sobreescritos @rtype fallidos: int @return: el número de episodios fallidos o -1 si ha fallado toda la serie """ logger.info() # logger.debug(item.tostring('\n')) path = "" # Si llegados a este punto no tenemos titulo o tmdb_id, salimos if not (item.contentSerieName or item.infoLabels['tmdb_id']) or not item.channel: logger.debug("NO ENCONTRADO contentSerieName NI tmdb_id") return 0, 0, -1 # Salimos sin guardar # TODO configurar para segun el scraper se llame a uno u otro scraper_return = scraper.find_and_set_infoLabels(item) # Llegados a este punto podemos tener: # scraper_return = True: Un item con infoLabels con la información actualizada de la serie # scraper_return = False: Un item sin información de la peli (se ha dado a cancelar en la ventana) # item.infoLabels['code'] == "" : No se ha encontrado el identificador de IMDB necesario para continuar, salimos if not scraper_return or not item.infoLabels['code']: # TODO de momento si no hay resultado no añadimos nada, # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano logger.debug("NO ENCONTRADO EN SCRAPER O NO TIENE IMDB_ID") return 0, 0, -1 _id = item.infoLabels['code'] if config.get_setting("original_title_folder", "biblioteca") == 1 and item.infoLabels['originaltitle']: base_name = item.infoLabels['originaltitle'] elif item.infoLabels['title']: base_name = item.infoLabels['title'] else: base_name = item.contentSerieName base_name = filetools.validate_path(base_name.replace('/', '-')).lower() for raiz, subcarpetas, ficheros in filetools.walk(TVSHOWS_PATH): for c in subcarpetas: if c.endswith("[%s]" % _id): path = filetools.join(raiz, c) break if not path: path = filetools.join(TVSHOWS_PATH, ("%s [%s]" % (base_name, _id)).strip()) logger.info("Creando directorio serie: " + path) try: filetools.mkdir(path) except OSError, exception: if exception.errno != errno.EEXIST: raise
def peliculas(item): logger.info() itemlist = [] for raiz, subcarpetas, ficheros in filetools.walk(library.MOVIES_PATH): for f in ficheros: if f.endswith(".nfo"): nfo_path = filetools.join(raiz, f) head_nfo, new_item = library.read_nfo(nfo_path) new_item.nfo = nfo_path new_item.path = raiz new_item.thumbnail = new_item.contentThumbnail new_item.text_color = "blue" if not filetools.exists(filetools.join(new_item.path, filetools.basename(new_item.strm_path))): # Si se ha eliminado el strm desde la bilbioteca de kodi, no mostrarlo continue # Menu contextual: Marcar como visto/no visto visto = new_item.library_playcounts.get(os.path.splitext(f)[0], 0) new_item.infoLabels["playcount"] = visto if visto > 0: texto_visto = "Segna film come non visto" contador = 0 else: texto_visto = "Segna film come visto" contador = 1 # Menu contextual: Eliminar serie/canal num_canales = len(new_item.library_urls) if "descargas" in new_item.library_urls: num_canales -= 1 if num_canales > 1: texto_eliminar = "Elimina film/canale" multicanal = True else: texto_eliminar = "Elimina questo film" multicanal = False new_item.context = [{"title": texto_visto, "action": "mark_content_as_watched", "channel": "biblioteca", "playcount": contador}, {"title": texto_eliminar, "action": "eliminar", "channel": "biblioteca", "multicanal": multicanal}] # ,{"title": "Cambiar contenido (PENDIENTE)", # "action": "", # "channel": "biblioteca"}] #logger.debug("new_item: " + new_item.tostring('\n')) itemlist.append(new_item) return sorted(itemlist, key=lambda it: it.title.lower())
def browser(item): logger.info() itemlist = [] for file in filetools.listdir(item.url): if filetools.isdir(filetools.join(item.url, file)) and not file == "list": itemlist.append(Item(channel=item.channel, title=file, action=item.action, url= filetools.join(item.url, file))) else: itemlist.append(Item(channel=item.channel, title=file, action="play", url= filetools.join(item.url, file))) return itemlist
def get_episodios(item): logger.info("pelisalacarta.channels.biblioteca get_episodios") itemlist = [] # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = filetools.walk(item.path).next() # Crear un item en la lista para cada strm encontrado for i in ficheros: # strm if i.endswith(".strm"): season, episode = scrapertools.get_season_and_episode(i).split("x") # Si hay q filtrar por temporada, ignoramos los capitulos de otras temporadas if item.filtrar_season and int(season) != int(item.contentSeason): continue epi = Item().fromurl(filetools.read(filetools.join(raiz, i))) epi.contentChannel = item.contentChannel epi.path = filetools.join(raiz, i) epi.title = i epi.channel = "biblioteca" epi.action = "findvideos" epi.contentEpisodeNumber = episode epi.contentSeason = season # fix sobreescribe el color del texto si viene pasado en el strm epi.text_color = "" # fix para que no se ejecute el método de play para la biblioteca de Kodi epi.strm = False itemlist.append(epi) # videos elif not i.endswith(".nfo") and not i.endswith(".json") and not i.endswith(".srt"): season, episode = scrapertools.get_season_and_episode(i).split("x") # Si hay q filtrar por temporada, ignoramos los capitulos de otras temporadas if item.filtrar_season and int(season) != int(item.contentSeason): continue epi = Item() epi.contentChannel = "local" epi.path = filetools.join(raiz, i) epi.title = i epi.channel = "biblioteca" epi.action = "play" epi.contentEpisodeNumber = episode epi.contentSeason = season itemlist.append(epi) library.set_infolabels_from_library(itemlist, tipo="Episodes") return sorted(itemlist, key=get_sort_temp_epi)
def get_episodios(item): logger.info() # logger.debug("item:\n" + item.tostring('\n')) itemlist = [] # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = filetools.walk(item.path).next() # Menu contextual: Releer tvshow.nfo head_nfo, item_nfo = library.read_nfo(item.nfo) # Crear un item en la lista para cada strm encontrado for i in ficheros: if i.endswith('.strm'): season_episode = scrapertools.get_season_and_episode(i) if not season_episode: # El fichero no incluye el numero de temporada y episodio continue season, episode = season_episode.split("x") # Si hay q filtrar por temporada, ignoramos los capitulos de otras temporadas if item.filtrar_season and int(season) != int(item.contentSeason): continue # Obtener los datos del season_episode.nfo nfo_path = filetools.join(raiz, i).replace('.strm', '.nfo') head_nfo, epi = library.read_nfo(nfo_path) # Fijar el titulo del capitulo si es posible if epi.contentTitle: title_episodie = epi.contentTitle.strip() else: title_episodie = "Stagione %s Episodio %s" % \ (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2)) epi.contentTitle = "%sx%s" % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2)) epi.title = "%sx%s - %s" % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2), title_episodie) if item_nfo.library_filter_show: epi.library_filter_show = item_nfo.library_filter_show # Menu contextual: Marcar episodio como visto o no visto = item_nfo.library_playcounts.get(season_episode, 0) epi.infoLabels["playcount"] = visto if visto > 0: texto = "Segna episodio come non visto" value = 0 else: texto = "Segna episodio come visto" value = 1 epi.context = [{"title": texto, "action": "mark_content_as_watched", "channel": "biblioteca", "playcount": value, "nfo": item.nfo}] # logger.debug("epi:\n" + epi.tostring('\n')) itemlist.append(epi) return sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber)))
def play(item): logger.info() itemlist = [] try: from core import filetools ficherosubtitulo = filetools.join( config.get_data_path(), 'subtitulo_areadocu.srt' ) if filetools.exists(ficherosubtitulo): try: filetools.remove(ficherosubtitulo) except IOError: logger.info("Error al eliminar el archivo "+ficherosubtitulo) raise data = httptools.downloadpage(item.subtitle, headers={'Referer': item.extra}).data filetools.write(ficherosubtitulo, data) subtitle = ficherosubtitulo except: subtitle = "" logger.info("Error al descargar el subtítulo") extension = item.url.rsplit("|", 1)[0][-4:] itemlist.append(['%s %s [directo]' % (extension, item.calidad), item.url, 0, subtitle]) #itemlist.append(item.clone(subtitle=subtitle)) return itemlist
def update(content_type=FOLDER_TVSHOWS, folder=""): """ Actualiza la libreria dependiendo del tipo de contenido y la ruta que se le pase. @type content_type: str @param content_type: tipo de contenido para actualizar, series o peliculas @type folder: str @param folder: nombre de la carpeta a escanear. """ logger.info("pelisalacarta.platformcode.library update") librarypath = config.get_setting("librarypath") if librarypath == "": librarypath = "special://home/userdata/addon_data/plugin.video." + config.PLUGIN_NAME + "/library/" + \ content_type + "/" else: if folder == "": librarypath = "" else: librarypath = filetools.join(librarypath, content_type, folder) # logger.info("la ruta es " + librarypath) _path = librarypath # Se comenta la llamada normal para reutilizar 'payload' dependiendo del modo cliente # xbmc.executebuiltin('UpdateLibrary(video)') if _path: payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "params": {"directory": _path}, "id": 1} else: payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1} data = get_data(payload) logger.info("pelisalacarta.platformcode.library update data: %s" % data)
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("library_mode", "biblioteca"): return if value == 0: value = 'Null' request_season = '' if item.contentSeason > -1: request_season = ' and c12= %s' % item.contentSeason tvshows_path = filetools.join(config.get_library_path(), FOLDER_TVSHOWS) item_path1 = "%" + item.path.replace("\\\\", "\\").replace(tvshows_path, "") if item_path1[:-1] != "\\": item_path1 += "\\" item_path2 = item_path1.replace("\\", "/") sql = 'update files set playCount= %s where idFile in ' \ '(select idfile from episode_view where strPath like "%s" or strPath like "%s"%s)' % \ (value, item_path1, item_path2, request_season) execute_sql_kodi(sql)
def backups(item): from platformcode import platformtools logger.info("pelisalacarta.channel.configuracion backups") ruta = filetools.join(config.get_data_path(), "backups") ruta_split = "" if "ruta" in item.title: heading = "Ruta de copias de seguridad" if not filetools.exists(ruta): folders = "Carpeta no creada" else: folders = str(len(filetools.listdir(ruta))) + " copia/s de seguridad guardadas" if len(ruta) > 55: ruta_split = ruta[55:] ruta = ruta[:55] platformtools.dialog_ok(heading, ruta, ruta_split, folders) else: if not filetools.exists(ruta): platformtools.dialog_ok("La carpeta no existe", "No hay copias de seguridad guardadas") else: dyesno = platformtools.dialog_yesno("Las copias de seguridad se eliminarán", "¿Está seguro?") if dyesno: import shutil shutil.rmtree(ruta, ignore_errors=True)
def mainlist(item): logger.info() itemlist = [] item.text_color = color1 logueado, error_message = login("copiapop.com") if not logueado: itemlist.append(item.clone(title=error_message, action="configuracion", folder=False)) else: item.extra = "http://copiapop.com" itemlist.append(item.clone(title="Copiapop", action="", text_color=color2)) itemlist.append(item.clone(title=" Búsqueda", action="search", url="http://copiapop.com/action/SearchFiles")) itemlist.append(item.clone(title=" Colecciones", action="colecciones", url="http://copiapop.com/action/home/MoreNewestCollections?pageNumber=1")) itemlist.append(item.clone(title=" Búsqueda personalizada", action="filtro", url="http://copiapop.com/action/SearchFiles")) itemlist.append(item.clone(title=" Mi cuenta", action="cuenta")) item.extra = "http://diskokosmiko.mx/" itemlist.append(item.clone(title="DiskoKosmiko", action="", text_color=color2)) itemlist.append(item.clone(title=" Búsqueda", action="search", url="http://diskokosmiko.mx/action/SearchFiles")) itemlist.append(item.clone(title=" Colecciones", action="colecciones", url="http://diskokosmiko.mx/action/home/MoreNewestCollections?pageNumber=1")) itemlist.append(item.clone(title=" Búsqueda personalizada", action="filtro", url="http://diskokosmiko.mx/action/SearchFiles")) itemlist.append(item.clone(title=" Mi cuenta", action="cuenta")) itemlist.append(item.clone(action="", title="")) folder_thumb = filetools.join(config.get_data_path(), 'thumbs_copiapop') files = filetools.listdir(folder_thumb) if files: itemlist.append(item.clone(title="Eliminar caché de imágenes (%s)" % len(files), action="delete_cache", text_color="red")) itemlist.append(item.clone(title="Configuración del canal", action="configuracion", text_color="gold")) return itemlist
def eliminar(item): def eliminar_todo(item): filetools.rmdirtree(item.path) if config.is_xbmc(): import xbmc # esperamos 3 segundos para dar tiempo a borrar los ficheros xbmc.sleep(3000) # TODO mirar por qué no funciona al limpiar en la biblioteca de Kodi al añadirle un path # limpiamos la biblioteca de Kodi library.clean() logger.info("Eliminados todos los enlaces") platformtools.itemlist_refresh() logger.info(item.contentTitle) #logger.debug(item.tostring('\n')) if item.contentType == 'movie': heading = "Eliminar película" else: heading = "Eliminar serie" if item.multicanal: # Obtener listado de canales opciones = ["Eliminar solo los enlaces de %s" % k.capitalize() for k in item.library_urls.keys() if k !="descargas"] opciones.insert(0, heading) index = platformtools.dialog_select(config.get_localized_string(30163), opciones) if index == 0: # Seleccionado Eliminar pelicula/serie eliminar_todo(item) elif index > 0: # Seleccionado Eliminar canal X canal = opciones[index].replace("Eliminar solo los enlaces de ", "").lower() num_enlaces= 0 for fd in filetools.listdir(item.path): if fd.endswith(canal + '].json'): if filetools.remove(filetools.join(item.path, fd)): num_enlaces += 1 if num_enlaces > 0: # Actualizar .nfo head_nfo, item_nfo = library.read_nfo(item.nfo) del item_nfo.library_urls[canal] filetools.write(item.nfo, head_nfo + item_nfo.tojson()) msg_txt = "Eliminados %s enlaces del canal %s" % (num_enlaces, canal) logger.info(msg_txt) platformtools.dialog_notification(heading, msg_txt) platformtools.itemlist_refresh() else: if platformtools.dialog_yesno(heading, "¿Realmente desea eliminar '%s' de su biblioteca?" % item.infoLabels['title']): eliminar_todo(item)
def menu(item): logger.info() # Opciones disponibles para el menu op = ["Descargar", "Eliminar de la lista", "Reiniciar descarga", "Descargar desde...", "Reproducir"] opciones = [] # Opciones para el menu if item.downloadStatus == 0: # Sin descargar opciones.append(op[0]) # Descargar opciones.append(op[3]) # Descargar desde... opciones.append(op[1]) # Eliminar de la lista if item.downloadStatus == 1: # descarga parcial opciones.append(op[0]) # Descargar opciones.append(op[2]) # Reiniciar descarga opciones.append(op[1]) # Eliminar de la lista if item.downloadStatus == 2: # descarga completada opciones.append(op[4]) # Reproducir opciones.append(op[1]) # Eliminar de la lista opciones.append(op[2]) # Reiniciar descarga if item.downloadStatus == 3: # descarga con error opciones.append(op[2]) # Reiniciar descarga opciones.append(op[1]) # Eliminar de la lista # Mostramos el dialogo seleccion = platformtools.dialog_select("Scegliere un'opzione", opciones) # -1 es cancelar if seleccion == -1: return logger.info("opcion=%s" % (opciones[seleccion])) # Opcion Eliminar if opciones[seleccion] == op[1]: filetools.remove(item.path) # Opcion inicaiar descarga if opciones[seleccion] == op[0]: start_download(item) # Opcion inicaiar descarga desde... if opciones[seleccion] == op[3]: start_download(item, ask=True) # Reiniciar descarga if opciones[seleccion] == op[2]: if filetools.isfile(os.path.join(config.get_setting("downloadpath"), item.downloadFilename)): filetools.remove(os.path.join(config.get_setting("downloadpath"), item.downloadFilename)) update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0}) # Reproducir if opciones[seleccion] == op[4]: item.url = filetools.join(DOWNLOAD_PATH, item.downloadFilename) return platformtools.play_video(item) platformtools.itemlist_refresh()
def create_tvshows_from_json(_actualizado): logger.info("pelisalacarta.platformcode.library_service create_tvshows_from_json") fname = filetools.join(config.get_data_path(), library.TVSHOW_FILE) if filetools.exists(fname): if not _actualizado: platformtools.dialog_ok("Biblioteca: Actualizando formato", "Espere por favor mientras se completa el proceso") try: data = jsontools.loads(filetools.read(fname)) for tvshow in data: for channel in data[tvshow]["channels"]: serie = Item(contentSerieName=data[tvshow]["channels"][channel]["tvshow"], url=data[tvshow]["channels"][channel]["url"], channel=channel, action="episodios", title=data[tvshow]["name"], active=True) if not tvshow.startswith("t_"): serie.infoLabels["tmdb_id"] = tvshow library.save_library_tvshow(serie, list()) filetools.rename(fname, "series.json.old") except EnvironmentError: logger.info("ERROR al leer el archivo: {0}".format(fname))
def __init__(self, url, path, filename=None, headers=[], resume = True, max_connections = 10, part_size = 2097152): #Parametros self._resume = resume self._path = path self._filename = filename self._max_connections = max_connections self._part_size = part_size self.states = type('states', (), {"stopped":0, "connecting": 1, "downloading": 2, "completed": 3, "error": 4}) self._block_size = 1024*100 self._state = self.states.stopped self._write_lock = Lock() self._download_lock = Lock() self._headers = {"User-Agent":"Kodi/15.2 (Windows NT 10.0; WOW64) App_Bitness/32 Version/15.2-Git:20151019-02e7013"} self._speed = 0 self._threads = [Thread(target= self.__start_part__) for x in range(self._max_connections)] self._speed_thread = Thread(target= self.__speed_metter__) #Actualizamos los headers self._headers.update(dict(headers)) #Separamos los headers de la url self.__url_to_headers__(url) #Obtenemos la info del servidor self.__get_download_headers__() self._file_size = int(self.response_headers.get("content-length", "0")) if not self.response_headers.get("accept-ranges") == "bytes" or self._file_size == 0: self._max_connections = 1 self._part_size = 0 self._resume = False #Obtenemos el nombre del archivo self.__get_download_filename__() #Abrimos en modo "a+" para que cree el archivo si no existe, luego en modo "r+b" para poder hacer seek() self.file = filetools.file_open(filetools.join(self._path, self._filename), "a+") self.file = filetools.file_open(filetools.join(self._path, self._filename), "r+b") self.__get_download_info__()
def update(content_type=FOLDER_TVSHOWS, folder=""): """ Actualiza la libreria dependiendo del tipo de contenido y la ruta que se le pase. @type content_type: str @param content_type: tipo de contenido para actualizar, series o peliculas @type folder: str @param folder: nombre de la carpeta a escanear. """ logger.info() librarypath = config.get_setting("librarypath") if librarypath == "": librarypath = "special://home/userdata/addon_data/plugin.video." + config.PLUGIN_NAME + "/library/" + \ content_type + "/" # Si termina en "/" lo eliminamos if librarypath.endswith("/"): librarypath = librarypath[:-1] if librarypath.startswith("special:"): if not librarypath.endswith(content_type): librarypath += "/" + content_type if folder: librarypath += "/" + folder else: if not librarypath.endswith(content_type): librarypath = filetools.join(librarypath, content_type) if folder: librarypath = filetools.join(librarypath, folder) # Añadimos el caracter finalizador if not librarypath.endswith("/"): librarypath += "/" # Comprobar que no se esta buscando contenido en la biblioteca de Kodi while xbmc.getCondVisibility('Library.IsScanningVideo()'): xbmc.sleep(500) payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "params": {"directory": librarypath}, "id": 1} data = get_data(payload) logger.info("data: %s" % data)
def findvideos(item): from core import servertools if item.infoLabels["tmdb_id"]: tmdb.set_infoLabels_item(item, __modo_grafico__) itemlist = servertools.find_video_items(item) library_path = config.get_library_path() if config.get_library_support(): title = "Añadir película a la biblioteca" if item.infoLabels["imdb_id"] and not library_path.lower().startswith("smb://"): try: from core import filetools movie_path = filetools.join(config.get_library_path(), 'CINE') files = filetools.walk(movie_path) for dirpath, dirname, filename in files: for f in filename: if item.infoLabels["imdb_id"] in f and f.endswith(".nfo"): from core import library head_nfo, it = library.read_nfo(filetools.join(dirpath, dirname, f)) canales = it.library_urls.keys() canales.sort() if "clasicofilm" in canales: canales.pop(canales.index("clasicofilm")) canales.insert(0, "[COLOR red]clasicofilm[/COLOR]") title = "Película ya en tu biblioteca. [%s] ¿Añadir?" % ",".join(canales) break except: import traceback logger.info(traceback.format_exc()) pass itemlist.append(item.clone(action="add_pelicula_to_library", title=title)) token_auth = config.get_setting("token_trakt", "tvmoviedb") if token_auth and item.infoLabels["tmdb_id"]: itemlist.append(item.clone(channel="tvmoviedb", title="[Trakt] Gestionar con tu cuenta", action="menu_trakt", extra="movie")) return itemlist
def create_tvshows_from_xml(): logger.info("pelisalacarta.platformcode.library_service create_tvshows_from_xml") fname = filetools.join(config.get_data_path(), library.TVSHOW_FILE_OLD) if filetools.exists(fname): platformtools.dialog_ok("Biblioteca: Se va a actualizar al nuevo formato", "Seleccione el nombre correcto de cada serie, si no está seguro pulse 'Cancelar'.", "Hay nuevas opciones en 'Biblioteca' y en la 'configuración' del addon.") filetools.rename(library.TVSHOWS_PATH, "SERIES_OLD") if not filetools.exists(library.TVSHOWS_PATH): filetools.mkdir(library.TVSHOWS_PATH) if filetools.exists(library.TVSHOWS_PATH): try: data = filetools.read(fname) for line in data.splitlines(): aux = line.rstrip('\n').split(",") tvshow = aux[0].strip() url = aux[1].strip() channel = aux[2].strip() serie = Item(contentSerieName=tvshow, url=url, channel=channel, action="episodios", title=tvshow, active=True) patron = "^(.+)[\s]\((\d{4})\)$" matches = re.compile(patron, re.DOTALL).findall(serie.contentSerieName) if matches: serie.infoLabels['title'] = matches[0][0] serie.infoLabels['year'] = matches[0][1] else: serie.infoLabels['title'] = tvshow library.save_library_tvshow(serie, list()) filetools.rename(fname, "series.xml.old") # Por ultimo limpia la libreria, por que las rutas anteriores ya no existen library.clean() except EnvironmentError: logger.info("ERROR al leer el archivo: {0}".format(fname)) else: logger.info("ERROR, no se ha podido crear la nueva carpeta de SERIES") else: logger.info("ERROR, no se ha podido renombrar la antigua carpeta de SERIES") return True return False
def create_tvshows_from_xml(): logger.info("fusionse.platformcode.library_service create_tvshows_from_xml") fname = filetools.join(config.get_data_path(), library.TVSHOW_FILE_OLD) if filetools.exists(fname): platformtools.dialog_ok("Libreria: Si aggiornerà al nuovo formato", "Selezionare il nome corretto di ogni serie, se non siete sicuri potete 'Annulla'.", "Ci sono nuove opzioni per la 'Libreria' in 'configurazione'.") filetools.rename(library.TVSHOWS_PATH, "SERIES_OLD") if not filetools.exists(library.TVSHOWS_PATH): filetools.mkdir(library.TVSHOWS_PATH) if filetools.exists(library.TVSHOWS_PATH): try: data = filetools.read(fname) for line in data.splitlines(): aux = line.rstrip('\n').split(",") tvshow = aux[0].strip() url = aux[1].strip() channel = aux[2].strip() serie = Item(contentSerieName=tvshow, url=url, channel=channel, action="episodios", title=tvshow, active=True) patron = "^(.+)[\s]\((\d{4})\)$" matches = re.compile(patron, re.DOTALL).findall(serie.contentSerieName) if matches: serie.infoLabels['title'] = matches[0][0] serie.infoLabels['year'] = matches[0][1] else: serie.infoLabels['title'] = tvshow library.save_library_tvshow(serie, list()) filetools.rename(fname, "series.xml.old") # Por ultimo limpia la libreria, por que las rutas anteriores ya no existen library.clean() except EnvironmentError: logger.info("ERROR al leer el archivo: {0}".format(fname)) else: logger.info("ERROR, no se ha podido crear la nueva carpeta de SERIES") else: logger.info("ERROR, no se ha podido renombrar la antigua carpeta de SERIES") return True return False
def verify_directories_created(): from core import logger from core import filetools from platformcode import xbmc_library config_paths = [["librarypath", "library"], ["downloadpath", "downloads"], ["downloadlistpath", "downloads/list"], ["settings_path", "settings_channels"]] for path, default in config_paths: saved_path = get_setting(path) # Biblioteca if path == "librarypath": set_setting("library_version", "v4") if not saved_path: saved_path = xbmc_library.search_library_path() if saved_path: set_setting(path, saved_path) if not saved_path: saved_path = "special://profile/addon_data/plugin.video." + PLUGIN_NAME + "/" + default set_setting(path, saved_path) if get_setting("library_set_content")== "true" and path in ["librarypath","downloadpath"]: xbmc_library.add_sources(saved_path) saved_path = xbmc.translatePath(saved_path) if not filetools.exists(saved_path): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) config_paths = [["folder_movies", "CINE"], ["folder_tvshows", "SERIES"]] for path, default in config_paths: saved_path = get_setting(path) if not saved_path: saved_path = default set_setting(path, saved_path) content_path = filetools.join(get_library_path(), saved_path) if not filetools.exists(content_path): logger.debug("Creating %s: %s" % (path, content_path)) if filetools.mkdir(content_path) and get_setting("library_set_content")== "true": xbmc_library.set_content(default) elif get_setting("library_ask_set_content") == "active": xbmc_library.set_content(default)
def file_cine_library(item,url_targets): import os from core import filetools librarypath = os.path.join(config.get_library_path(),"CINE") archivo = item.show.strip() strmfile = archivo+".strm" strmfilepath = filetools.join(librarypath,strmfile) if not os.path.exists(strmfilepath): itemlist = [] itemlist.append( Item(channel=item.channel, title=">> Añadir a la biblioteca...", url=url_targets, action="add_file_cine_library", extra="episodios", show=archivo) ) return itemlist
def mark_season_as_watched(item): logger.info("pelisalacarta.channels.biblioteca mark_season_as_watched") # logger.debug("item:\n" + item.tostring('\n')) # Obtener el diccionario de episodios marcados f = filetools.join(item.path, "tvshow.nfo") url_scraper = filetools.read(f, 0, 1) it = Item().fromjson(filetools.read(f, 1)) if not hasattr(it, "library_playcounts"): it.library_playcounts = {} # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = filetools.walk(item.path).next() # Marcamos cada uno de los episodios encontrados de esta temporada episodios_marcados = 0 for i in ficheros: if i.endswith(".strm"): season_episode = scrapertools.get_season_and_episode(i) if not season_episode: # El fichero no incluye el numero de temporada y episodio continue season, episode = season_episode.split("x") if int(item.contentSeason) == -1 or int(season) == int(item.contentSeason): name_file = os.path.splitext(os.path.basename(i))[0] it.library_playcounts[name_file] = item.playcount episodios_marcados += 1 if episodios_marcados: if int(item.contentSeason) == -1: # Añadimos todas las temporadas al diccionario item.library_playcounts for k in it.library_playcounts.keys(): if k.startswith("season"): it.library_playcounts[k] = item.playcount else: # Añadimos la temporada al diccionario item.library_playcounts it.library_playcounts["season %s" % item.contentSeason] = item.playcount # se comprueba que si todas las temporadas están vistas, se marque la serie como vista it = check_tvshow_playcount(it, item.contentSeason) # Guardamos los cambios en tvshow.nfo filetools.write(f, url_scraper + it.tojson()) item.infoLabels["playcount"] = item.playcount if config.is_xbmc(): # Actualizamos la BBDD de Kodi library.mark_season_as_watched_on_kodi(item, item.playcount) platformtools.itemlist_refresh()
def download_thumb(filename, url): from core import downloadtools lock = threading.Lock() lock.acquire() folder = filetools.join(config.get_data_path(), 'thumbs_copiapop') if not filetools.exists(folder): filetools.mkdir(folder) lock.release() if not filetools.exists(filename): downloadtools.downloadfile(url, filename, silent=True) return filename
def update(folder_content=FOLDER_TVSHOWS, folder=""): """ Actualiza la libreria dependiendo del tipo de contenido y la ruta que se le pase. @type folder_content: str @param folder_content: tipo de contenido para actualizar, series o peliculas @type folder: str @param folder: nombre de la carpeta a escanear. """ logger.info(folder) if not folder: # Actualizar toda la coleccion while xbmc.getCondVisibility('Library.IsScanningVideo()'): xbmc.sleep(500) xbmc.executebuiltin('UpdateLibrary(video)') else: # Actualizar una sola carpeta en un hilo independiente def update_multi_threads(update_path, lock): lock.acquire() #logger.debug("%s\nINICIO" % update_path) payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "params": {"directory": update_path}, "id": 1} data = get_data(payload) lock.release() #logger.debug("%s\nFIN data: %s" % (update_path, data)) librarypath = config.get_library_config_path() if folder.endswith('/') or folder.endswith('\\'): folder = folder[:-1] if librarypath.startswith("special:"): if librarypath.endswith('/'): librarypath = librarypath [:-1] update_path = librarypath + "/" + folder_content + "/" + folder + "/" else: update_path = filetools.join(librarypath, folder_content, folder) + "/" t = threading.Thread(target=update_multi_threads, args=[update_path, threading.Lock()]) t.setDaemon(True) t.start()
def stop(self, erase=False): if self._state == self.states.downloading: #Detenemos la descarga self._state = self.states.stopped for t in self._threads: if t.isAlive(): t.join() #Guardamos la info al final del archivo self.file.seek(0,2) offset = self.file.tell() self.file.write(str(self._download_info)) self.file.write("%0.16d" % offset) self.file.close() if erase: os.remove(filetools.join(self._path, self._filename))
def update(path, p_dialog, i, t, serie, overwrite): logger.info("Actualizando " + path) insertados_total = 0 # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in serie.library_urls.items(): serie.channel = channel serie.url = url heading = 'Actualizando biblioteca....' 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) obj = imp.load_source(serie.channel, pathchannels) itemlist = obj.episodios(serie) try: if int(overwrite) == 3: # Sobrescribir todos los archivos (tvshow.nfo, 1x01.nfo, 1x01 [canal].json, 1x01.strm, etc...) insertados, sobreescritos, fallidos = library.save_library_tvshow(serie, itemlist) else: insertados, sobreescritos, fallidos = library.save_library_episodes(path, itemlist, serie, silent=True, overwrite=overwrite) 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) 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) return insertados_total > 0
def decrypt_subs(iv, data, id): from Crypto.Cipher import AES data = base64.b64decode(data.encode('utf-8')) iv = base64.b64decode(iv.encode('utf-8')) id = int(id) def obfuscate_key_aux(count, modulo, start): output = list(start) for _ in range(count): output.append(output[-1] + output[-2]) # cut off start values output = output[2:] output = list(map(lambda x: x % modulo + 33, output)) return output def obfuscate_key(key): from math import pow, sqrt, floor num1 = int(floor(pow(2, 25) * sqrt(6.9))) num2 = (num1 ^ key) << 5 num3 = key ^ num1 num4 = num3 ^ (num3 >> 3) ^ num2 prefix = obfuscate_key_aux(20, 97, (1, 2)) prefix = struct.pack('B' * len(prefix), *prefix) shaHash = sha1(prefix + str(num4).encode('ascii')).digest() decshaHash = [] for char in shaHash: decshaHash.append(ord(char)) # Extend 160 Bit hash to 256 Bit return decshaHash + [0] * 12 key = obfuscate_key(id) key = struct.pack('B' * len(key), *key) decryptor = AES.new(key, AES.MODE_CBC, iv) decrypted_data = decryptor.decrypt(data) data = zlib.decompress(decrypted_data) import xml.etree.ElementTree as ET raiz = ET.fromstring(data) ass_sub = convert_to_ass(raiz) file_sub = filetools.join(config.get_data_path(), 'crunchyroll_sub.ass') filetools.write(file_sub, ass_sub) return file_sub
def save_library_tvshow(item, episodelist): """ guarda en la libreria de series la serie con todos los capitulos incluidos en la lista episodelist @type item: item @param item: item que representa la serie a guardar @type episodelist: list @param episodelist: listado de items que representan los episodios que se van a guardar. @rtype insertados: int @return: el número de episodios insertados @rtype sobreescritos: int @return: el número de episodios sobreescritos @rtype fallidos: int @return: el número de episodios fallidos o -1 si ha fallado toda la serie """ logger.info("streamondemand.platformcode.library save_library_tvshow") # Itentamos obtener el titulo correcto: # 1. contentSerieName: Este deveria ser el sitio correcto # 2. show titulo = item.contentSerieName if not titulo: titulo = item.show # Colocamos el titulo en su sitio para que tmdb lo localize item.contentSerieName = titulo # establecemos "active" para que se actualice cuando se llame a library_service item.active = True # Si llegados a este punto no tenemos titulo, salimos if not item.contentSerieName or not item.channel: return 0, 0, -1 # Salimos sin guardar # TODO configurar para segun el scraper se llame a uno u otro tmdb.find_and_set_infoLabels_tmdb(item, config.get_setting("scrap_ask_name") == "true") path = filetools.join(TVSHOWS_PATH, "{0} [{1}]".format(item.contentSerieName.strip().lower(), item.channel).lower()) if not filetools.exists(path): logger.info("streamondemand.platformcode.library save_library_tvshow Creando directorio serie:" + path) try: filetools.mkdir(path) except OSError, exception: if exception.errno != errno.EEXIST: raise
def elenco_file(item): logger.info("[biblioteca.py] elenco_file") itemlist=[] lista=filetools.listdir(config.get_library_path()) for list in lista: if list.endswith(tuple(['.flv','.mp4','.avi','.mkv'])): itemlist.append(Item(channel=item.channel, action="file", title="[COLOR azure]" + list + "[/COLOR]", url=filetools.join(config.get_library_path(), list), thumbnail="", fanart="", fulltitle=list, show="", folder=False )) return itemlist
def get_server_setting(name, server, default=None, caching_var=True): global alfa_caching, alfa_servers """ Retorna el valor de configuracion del parametro solicitado. Devuelve el valor del parametro 'name' en la configuracion propia del servidor 'server'. Busca en la ruta \addon_data\plugin.video.addon\settings_servers el archivo server_data.json y lee el valor del parametro 'name'. Si el archivo server_data.json no existe busca en la carpeta servers el archivo server.json y crea un archivo server_data.json antes de retornar el valor solicitado. Si el parametro 'name' tampoco existe en el el archivo server.json se devuelve el parametro default. @param name: nombre del parametro @type name: str @param server: nombre del servidor @type server: str @param default: valor devuelto en caso de que no exista el parametro name @type default: any @return: El valor del parametro 'name' @rtype: any """ # Creamos la carpeta si no existe if not filetools.exists( filetools.join(config.get_data_path(), "settings_servers")): filetools.mkdir( filetools.join(config.get_data_path(), "settings_servers")) file_settings = filetools.join(config.get_data_path(), "settings_servers", server + "_data.json") dict_settings = {} dict_file = {} if kodi and caching_var: alfa_caching = bool(window.getProperty("alfa_caching")) alfa_servers = json.loads(window.getProperty("alfa_servers")) if alfa_caching and caching_var and alfa_servers.get(server): dict_settings = alfa_servers[server].copy() if dict_settings.get(name, ''): dict_settings[name] = config.decode_var(dict_settings[name]) #logger.error('%s, %s: A: %s - D: %s' % (name, server, [alfa_servers[server][name]], [config.decode_var(dict_settings[name])])) elif filetools.exists(file_settings): # Obtenemos configuracion guardada de ../settings/channel_data.json try: dict_file = jsontools.load(filetools.read(file_settings)) if isinstance(dict_file, dict) and 'settings' in dict_file: dict_settings = dict_file['settings'] if alfa_caching and caching_var: alfa_servers[server] = dict_settings.copy() window.setProperty("alfa_servers", json.dumps(alfa_servers)) except EnvironmentError: logger.info("ERROR al leer el archivo: %s" % file_settings) if not dict_settings or name not in dict_settings: # Obtenemos controles del archivo ../servers/server.json try: list_controls, default_settings = get_server_controls_settings( server) except: default_settings = {} if name in default_settings: # Si el parametro existe en el server.json creamos el server_data.json default_settings.update(dict_settings) dict_settings = default_settings if alfa_caching and caching_var: alfa_servers[server] = dict_settings.copy() window.setProperty("alfa_servers", json.dumps(alfa_servers)) dict_file['settings'] = dict_settings # Creamos el archivo ../settings/channel_data.json if not filetools.write(file_settings, jsontools.dump(dict_file)): logger.info("ERROR al salvar el archivo: %s" % file_settings) # Devolvemos el valor del parametro local 'name' si existe, si no se devuelve default return dict_settings.get(name, default)
def check_for_update(overwrite=True): logger.debug("Update Series...") p_dialog = None serie_actualizada = False update_when_finished = False hoy = datetime.date.today() estado_verify_playcount_series = False local_ended = True try: if config.get_setting("update", "videolibrary") != 0 or overwrite: config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "videolibrary") heading = config.get_localized_string(60389) p_dialog = platformtools.dialog_progress_bg( config.get_localized_string(20000), heading) p_dialog.update(0, '') show_list = [] for path, folders, files in filetools.walk( videolibrarytools.TVSHOWS_PATH): show_list.extend([ filetools.join(path, f) for f in files if f == "tvshow.nfo" ]) if show_list: t = float(100) / len(show_list) for i, tvshow_file in enumerate(show_list): head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) if serie.local_episodes_path: local_ended = True if serie.infoLabels[ 'number_of_episodes'] == len( serie.local_episodes_list) else False if serie.infoLabels['status'].lower( ) == 'ended' and local_ended: serie.active = 0 filetools.write(tvshow_file, head_nfo + serie.tojson()) path = filetools.dirname(tvshow_file) logger.debug("serie=" + serie.contentSerieName) p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName) # Check the status of the series.library_playcounts of the Series in case it is incomplete try: estado = False # If we have not done the verification or do not have a playcount, we enter estado = config.get_setting("verify_playcount", "videolibrary") if not estado or estado == False or not serie.library_playcounts: # If it hasn't happened before, we do it now serie, estado = videolibrary.verify_playcount_series( serie, path ) # Also happens if a PlayCount is missing completely except: logger.error(traceback.format_exc()) else: if estado: # If the update was successful ... estado_verify_playcount_series = True # ... is checked to change the Video Library option interval = int(serie.active) # Could be the bool type if not serie.active: # if the series is not active discard if not overwrite: # Synchronize the episodes seen from the Kodi video library with that of Alpha, even if the series is deactivated try: if config.is_xbmc(): # If it's Kodi, we do it from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_content_as_watched_on_kod( filetools.join(path, 'tvshow.nfo')) except: logger.error(traceback.format_exc()) continue # Obtain the update date and the next scheduled for this series update_next = serie.update_next if update_next: y, m, d = update_next.split('-') update_next = datetime.date(int(y), int(m), int(d)) else: update_next = hoy update_last = serie.update_last if update_last: y, m, d = update_last.split('-') update_last = datetime.date(int(y), int(m), int(d)) else: update_last = hoy # if the series is active ... if overwrite or config.get_setting("updatetvshows_interval", "videolibrary") == 0: # ... force update regardless of interval serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next = hoy + datetime.timedelta(days=interval) elif interval == 1 and update_next <= hoy: # ...daily update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada and update_last <= hoy - datetime.timedelta( days=7): # if it hasn't been updated for a week, change the interval to weekly interval = 7 update_next = hoy + datetime.timedelta(days=interval) elif interval == 7 and update_next <= hoy: # ... weekly update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: if update_last <= hoy - datetime.timedelta(days=14): # if it has not been updated for 2 weeks, change the interval to monthly interval = 30 update_next += datetime.timedelta(days=interval) elif interval == 30 and update_next <= hoy: # ... monthly update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next += datetime.timedelta(days=interval) if serie_actualizada: update_last = hoy update_next = hoy + datetime.timedelta(days=interval) head_nfo, serie = videolibrarytools.read_nfo( tvshow_file) # Reread the .nfo, which has been modified if interval != int(serie.active) or update_next.strftime( '%Y-%m-%d' ) != serie.update_next or update_last.strftime( '%Y-%m-%d') != serie.update_last: serie.update_last = update_last.strftime('%Y-%m-%d') if update_next > hoy: serie.update_next = update_next.strftime('%Y-%m-%d') serie.active = interval serie.channel = "videolibrary" serie.action = "get_seasons" filetools.write(tvshow_file, head_nfo + serie.tojson()) if serie_actualizada: if config.get_setting("search_new_content", "videolibrary") == 0: # We update the Kodi video library: Find content in the series folder if config.is_xbmc() and config.get_setting( "videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update( folder=filetools.basename(path)) else: update_when_finished = True if estado_verify_playcount_series: # If any playcount has been changed, ... estado = config.set_setting( "verify_playcount", True, "videolibrary") # ... we update the Videolibrary option if config.get_setting( "search_new_content", "videolibrary") == 1 and update_when_finished: # We update the Kodi video library: Find content in all series if config.is_xbmc() and config.get_setting( "videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update() p_dialog.close() else: logger.debug("Not update the video library, it is disabled") except Exception as ex: logger.error("An error occurred while updating the series") template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) if p_dialog: p_dialog.close() from core.item import Item item_dummy = Item() videolibrary.list_movies(item_dummy, silent=True) if config.get_setting('trakt_sync'): from core import trakt_tools trakt_tools.update_all()
def save_library_episodes(path, episodelist, serie, silent=False, overwrite=True): """ guarda en la ruta indicada todos los capitulos incluidos en la lista episodelist @type path: str @param path: ruta donde guardar los episodios @type episodelist: list @param episodelist: listado de items que representan los episodios que se van a guardar. @type serie: item @param serie: serie de la que se van a guardar los episodios @type silent: bool @param silent: establece si se muestra la notificación @param overwrite: permite sobreescribir los ficheros existentes @type overwrite: bool @rtype insertados: int @return: el número de episodios insertados @rtype sobreescritos: int @return: el número de episodios sobreescritos @rtype fallidos: int @return: el número de episodios fallidos """ logger.info() # No hay lista de episodios, no hay nada que guardar if not len(episodelist): logger.info("No hay lista de episodios, salimos sin crear strm") return 0, 0, 0 insertados = 0 sobreescritos = 0 fallidos = 0 news_in_playcounts = {} # Listamos todos los ficheros de la serie, asi evitamos tener que comprobar si existe uno por uno ficheros = os.listdir(path) ficheros = [filetools.join(path, f) for f in ficheros] # Silent es para no mostrar progreso (para library_service) if not silent: # progress dialog p_dialog = platformtools.dialog_progress('mitvspain', 'Añadiendo episodios...') p_dialog.update(0, 'Añadiendo episodio...') new_episodelist = [] # Obtenemos el numero de temporada y episodio y descartamos los q no lo sean for e in episodelist: try: season_episode = scrapertools.get_season_and_episode(e.title) e.infoLabels = serie.infoLabels e.contentSeason, e.contentEpisodeNumber = season_episode.split("x") new_episodelist.append(e) except: continue # No hay lista de episodios, no hay nada que guardar if not len(new_episodelist): logger.info("No hay lista de episodios, salimos sin crear strm") return 0, 0, 0 # fix float porque la division se hace mal en python 2.x t = float(100) / len(new_episodelist) for i, e in enumerate(scraper.sort_episode_list(new_episodelist)): if not silent: p_dialog.update(int(math.ceil((i + 1) * t)), 'Añadiendo episodio...', e.title) season_episode = "%sx%s" % (e.contentSeason, str(e.contentEpisodeNumber).zfill(2)) strm_path = filetools.join(path, "%s.strm" % season_episode) nfo_path = filetools.join(path, "%s.nfo" % season_episode) json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) strm_exists = strm_path in ficheros nfo_exists = nfo_path in ficheros json_exists = json_path in ficheros if not strm_exists: # Si no existe season_episode.strm añadirlo item_strm = Item(action='play_from_library', channel='biblioteca', strm_path=strm_path.replace(TVSHOWS_PATH, ""), infoLabels={}) item_strm.contentSeason = e.contentSeason item_strm.contentEpisodeNumber = e.contentEpisodeNumber item_strm.contentType = e.contentType item_strm.contentTitle = season_episode # FILTERTOOLS if item_strm.list_language: # si tvshow.nfo tiene filtro se le pasa al item_strm que se va a generar if "library_filter_show" in serie: item_strm.library_filter_show = serie.library_filter_show if item_strm.library_filter_show == "": logger.error("Se ha producido un error al obtener el nombre de la serie a filtrar") # logger.debug("item_strm" + item_strm.tostring('\n')) # logger.debug("serie " + serie.tostring('\n')) strm_exists = filetools.write(strm_path, '%s?%s' % (addon_name, item_strm.tourl())) item_nfo = None if not nfo_exists and e.infoLabels["code"]: # Si no existe season_episode.nfo añadirlo scraper.find_and_set_infoLabels(e) head_nfo = scraper.get_nfo(e) item_nfo = e.clone(channel="biblioteca", url="", action='findvideos', strm_path=strm_path.replace(TVSHOWS_PATH, "")) nfo_exists = filetools.write(nfo_path, head_nfo + item_nfo.tojson()) # Solo si existen season_episode.nfo y season_episode.strm continuamos if nfo_exists and strm_exists: if not json_exists or overwrite: # Obtenemos infoLabel del episodio if not item_nfo: head_nfo, item_nfo = read_nfo(nfo_path) e.infoLabels = item_nfo.infoLabels if filetools.write(json_path, e.tojson()): if not json_exists: logger.info("Insertado: %s" % json_path) insertados += 1 # Marcamos episodio como no visto news_in_playcounts[season_episode] = 0 # Marcamos la temporada como no vista news_in_playcounts["season %s" % e.contentSeason] = 0 # Marcamos la serie como no vista # logger.debug("serie " + serie.tostring('\n')) news_in_playcounts[serie.contentTitle] = 0 else: logger.info("Sobreescrito: %s" % json_path) sobreescritos += 1 else: logger.info("Fallido: %s" % json_path) fallidos += 1 else: logger.info("Fallido: %s" % json_path) fallidos += 1 if not silent and p_dialog.iscanceled(): break if not silent: p_dialog.close() if news_in_playcounts: # Si hay nuevos episodios los marcamos como no vistos en tvshow.nfo ... tvshow_path = filetools.join(path, "tvshow.nfo") try: import datetime head_nfo, tvshow_item = read_nfo(tvshow_path) tvshow_item.library_playcounts.update(news_in_playcounts) if tvshow_item.active == 30: tvshow_item.active = 1 update_last = datetime.date.today() tvshow_item.update_last = update_last.strftime('%Y-%m-%d') update_next = datetime.date.today() + datetime.timedelta(days=int(tvshow_item.active)) tvshow_item.update_next = update_next.strftime('%Y-%m-%d') filetools.write(tvshow_path, head_nfo + tvshow_item.tojson()) except: logger.error("Error al actualizar tvshow.nfo") fallidos = -1 else: # ... si ha sido correcto actualizamos la biblioteca de Kodi if config.is_xbmc() and not silent: from platformcode import xbmc_library xbmc_library.update(FOLDER_TVSHOWS, filetools.basename(path)) if fallidos == len(episodelist): fallidos = -1 logger.debug("%s [%s]: insertados= %s, sobreescritos= %s, fallidos= %s" % (serie.contentSerieName, serie.channel, insertados, sobreescritos, fallidos)) return insertados, sobreescritos, fallidos
def convert_old_to_v4(): logger.info() path_series_xml = filetools.join(config.get_data_path(), "series.xml") path_series_json = filetools.join(config.get_data_path(), "series.json") series_insertadas = 0 series_fallidas = 0 version = 'v?' # Renombrar carpeta Series y crear una vacia import time new_name = str(time.time()) path_series_old = filetools.join(library.LIBRARY_PATH, "SERIES_OLD_" + new_name) if filetools.rename(library.TVSHOWS_PATH, "SERIES_OLD_" + new_name): if not filetools.mkdir(library.TVSHOWS_PATH): logger.error( "ERROR, no se ha podido crear la nueva carpeta de SERIES") return False else: logger.error( "ERROR, no se ha podido renombrar la antigua carpeta de SERIES") return False path_cine_old = filetools.join(library.LIBRARY_PATH, "CINE_OLD_" + new_name) if filetools.rename(library.MOVIES_PATH, "CINE_OLD_" + new_name): if not filetools.mkdir(library.MOVIES_PATH): logger.error( "ERROR, no se ha podido crear la nueva carpeta de CINE") return False else: logger.error( "ERROR, no se ha podido renombrar la antigua carpeta de CINE") return False # Convertir libreria de v1(xml) a v4 if filetools.exists(path_series_xml): try: data = filetools.read(path_series_xml) for line in data.splitlines(): try: aux = line.rstrip('\n').split(",") tvshow = aux[0].strip() url = aux[1].strip() channel = aux[2].strip() serie = Item(contentSerieName=tvshow, url=url, channel=channel, action="episodios", title=tvshow, active=True) patron = "^(.+)[\s]\((\d{4})\)$" matches = re.compile(patron, re.DOTALL).findall( serie.contentSerieName) if matches: serie.infoLabels['title'] = matches[0][0] serie.infoLabels['year'] = matches[0][1] else: serie.infoLabels['title'] = tvshow insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 filetools.rename(path_series_xml, "series.xml.old") version = 'v4' except EnvironmentError: logger.error("ERROR al leer el archivo: %s" % path_series_xml) return False # Convertir libreria de v2(json) a v4 if filetools.exists(path_series_json): try: data = jsontools.load_json(filetools.read(path_series_json)) for tvshow in data: for channel in data[tvshow]["channels"]: try: serie = Item( contentSerieName=data[tvshow]["channels"][channel] ["tvshow"], url=data[tvshow]["channels"][channel]["url"], channel=channel, action="episodios", title=data[tvshow]["name"], active=True) if not tvshow.startswith("t_"): serie.infoLabels["tmdb_id"] = tvshow insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 filetools.rename(path_series_json, "series.json.old") version = 'v4' except EnvironmentError: logger.error("ERROR al leer el archivo: %s" % path_series_json) return False # Convertir libreria de v3 a v4 if version != 'v4': # Obtenemos todos los tvshow.json de la biblioteca de SERIES_OLD recursivamente for raiz, subcarpetas, ficheros in filetools.walk(path_series_old): for f in ficheros: if f == "tvshow.json": try: serie = Item().fromjson( filetools.read(filetools.join(raiz, f))) insertados, sobreescritos, fallidos = library.save_library_tvshow( serie, list()) if fallidos == 0: series_insertadas += 1 platformtools.dialog_notification( "Serie actualizada", serie.infoLabels['title']) else: series_fallidas += 1 except: series_fallidas += 1 movies_insertadas = 0 movies_fallidas = 0 for raiz, subcarpetas, ficheros in filetools.walk(path_cine_old): for f in ficheros: if f.endswith(".strm.json"): try: movie = Item().fromjson( filetools.read(filetools.join(raiz, f))) insertados, sobreescritos, fallidos = library.save_library_movie( movie) if fallidos == 0: movies_insertadas += 1 platformtools.dialog_notification( "Película actualizada", movie.infoLabels['title']) else: movies_fallidas += 1 except: movies_fallidas += 1 config.set_setting("library_version", 'v4') platformtools.dialog_notification( "Biblioteca actualizada al nuevo formato", "%s series convertidas y %s series descartadas.\n" "%s peliculas convertidas y %s peliculas descartadas." "A continuación se va a obtener la información de todos los episodios" % (series_insertadas, series_fallidas, movies_insertadas, movies_fallidas), time=12000) # Por ultimo limpia la libreria, por que las rutas anteriores ya no existen xbmc_library.clean() return True
def eliminar(item): def eliminar_todo(item): filetools.rmdirtree(item.path) if config.is_xbmc(): import xbmc # esperamos 3 segundos para dar tiempo a borrar los ficheros xbmc.sleep(3000) # TODO mirar por qué no funciona al limpiar en la biblioteca de Kodi al añadirle un path # limpiamos la biblioteca de Kodi from platformcode import xbmc_library xbmc_library.clean() logger.info("Eliminados todos los enlaces") platformtools.itemlist_refresh() logger.info(item.contentTitle) #logger.debug(item.tostring('\n')) if item.contentType == 'movie': heading = "Rimuovere film" else: heading = "Rimuovere serie" if item.multicanal: # Obtener listado de canales opciones = ["Rimuovere solo i link dei %s" % k.capitalize() for k in item.library_urls.keys() if k !="descargas"] opciones.insert(0, heading) index = platformtools.dialog_select(config.get_localized_string(30163), opciones) if index == 0: # Seleccionado Eliminar pelicula/serie eliminar_todo(item) elif index > 0: # Seleccionado Eliminar canal X canal = opciones[index].replace("Rimuovere solo i link dei ", "").lower() num_enlaces= 0 for fd in filetools.listdir(item.path): if fd.endswith(canal + '].json'): if filetools.remove(filetools.join(item.path, fd)): num_enlaces += 1 if num_enlaces > 0: # Actualizar .nfo head_nfo, item_nfo = library.read_nfo(item.nfo) del item_nfo.library_urls[canal] filetools.write(item.nfo, head_nfo + item_nfo.tojson()) msg_txt = "Cancellati %s collegamenti del canale %s" % (num_enlaces, canal) logger.info(msg_txt) platformtools.dialog_notification(heading, msg_txt) platformtools.itemlist_refresh() else: if platformtools.dialog_yesno(heading, "Vuoi davvero eliminare '%s' dalla tua libreria?" % item.infoLabels['title']): eliminar_todo(item)
import errno import math import traceback from core import filetools from core import scraper from core import scrapertools from core.item import Item from platformcode import config, logger from platformcode import platformtools from lib import generictools FOLDER_MOVIES = config.get_setting("folder_movies") FOLDER_TVSHOWS = config.get_setting("folder_tvshows") VIDEOLIBRARY_PATH = config.get_videolibrary_path() MOVIES_PATH = filetools.join(VIDEOLIBRARY_PATH, FOLDER_MOVIES) TVSHOWS_PATH = filetools.join(VIDEOLIBRARY_PATH, FOLDER_TVSHOWS) if not FOLDER_MOVIES or not FOLDER_TVSHOWS or not VIDEOLIBRARY_PATH \ or not filetools.exists(MOVIES_PATH) or not filetools.exists(TVSHOWS_PATH): config.verify_directories_created() addon_name = "plugin://plugin.video.%s/" % config.PLUGIN_NAME def read_nfo(path_nfo, item=None): """ Metodo para leer archivos nfo. Los arcivos nfo tienen la siguiente extructura: url_scraper | xml + item_json [url_scraper] y [xml] son opcionales, pero solo uno de ellos ha de existir siempre. @param path_nfo: ruta absoluta al archivo nfo
def check_for_update(overwrite=True): logger.info("Aggiornamento series...") p_dialog = None serie_actualizada = False update_when_finished = False hoy = datetime.date.today() try: if config.get_setting("updatelibrary", "biblioteca") != 0 or overwrite: config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "biblioteca") heading = 'Aggiornamento della libreria...' p_dialog = platformtools.dialog_progress_bg('streamondemand', heading) p_dialog.update(0, '') import glob show_list = glob.glob(filetools.join(library.TVSHOWS_PATH, u'/*/tvshow.nfo')) if show_list: t = float(100) / len(show_list) for i, tvshow_file in enumerate(show_list): head_nfo, serie = library.read_nfo(tvshow_file) path = filetools.dirname(tvshow_file) logger.info("serie=" + serie.contentSerieName) p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName) interval = int(serie.active) # Can be bool type if not serie.active: # Unload if the Serie is not active continue # Update next update_next = serie.update_next if update_next: y, m, d = update_next.split('-') update_next = datetime.date(int(y), int(m), int(d)) else: update_next = hoy update_last = serie.update_last if update_last: y, m, d = update_last.split('-') update_last = datetime.date(int(y), int(m), int(d)) else: update_last = hoy # if the Serie is active ... if overwrite or config.get_setting("updatetvshows_interval", "biblioteca") == 0: # ... force autonomus update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) elif interval == 1 and update_next <= hoy: # ...weekly update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada and update_last <= hoy - datetime.timedelta(days=7): # raise the interval interval = 7 update_next = hoy + datetime.timedelta(days=interval) elif interval == 7 and update_next <= hoy: # ...14days update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: if update_last <= hoy - datetime.timedelta(days=14): # raise the interval interval = 30 update_next += datetime.timedelta(days=interval) elif interval == 30 and update_next <= hoy: # ...monthly update serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next += datetime.timedelta(days=interval) if interval != int(serie.active) or update_next.strftime('%Y-%m-%d') != serie.update_next: serie.active = interval serie.update_next = update_next.strftime('%Y-%m-%d') serie.channel = "biblioteca" serie.action = "get_temporadas" filetools.write(tvshow_file, head_nfo + serie.tojson()) if serie_actualizada: if config.get_setting("search_new_content", "biblioteca") == 0: # Update Kodi library: Search contents in the Serie directory if config.is_xbmc(): from platformcode import xbmc_library xbmc_library.update(folder=filetools.basename(path)) else: update_when_finished = True if config.get_setting("search_new_content", "biblioteca") == 1 and update_when_finished: # Update Kodi library: Search contents for every Serie if config.is_xbmc(): from platformcode import xbmc_library xbmc_library.update() p_dialog.close() else: logger.info("Libreria non aggiornata, opzione disattiva nella configurazione di streamondemand") except Exception as ex: logger.error("Si è verificato un errore nell'aggiornamento") template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) if p_dialog: p_dialog.close()
def emergency_urls(item, channel=None, path=None): logger.info() import re """ Llamamos a Findvideos del canal con la variable "item.videolibray_emergency_urls = True" para obtener la variable "item.emergency_urls" con la lista de listas de tuplas de los enlaces torrent y de servidores directos para ese episodio o película En la lista [0] siempre deben ir los enlaces torrents, si los hay. Si se desea cachear los .torrents, la búsqueda va contra esa lista. En la lista dos irán los enlaces de servidores directos, pero también pueden ir enlaces magnet (que no son cacheables) """ #lanazamos un "lookup" en el "findvideos" del canal para obtener los enlaces de emergencia try: if channel == None: #Si el llamador no ha aportado la estructura de channel, se crea channel = generictools.verify_channel( item.channel ) #Se verifica si es un clon, que devuelva "newpct1" channel = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) if hasattr(channel, 'findvideos'): #Si el canal tiene "findvideos"... item.videolibray_emergency_urls = True #... se marca como "lookup" channel_save = item.channel #... guarda el canal original por si hay fail-over en Newpct1 item_res = getattr(channel, 'findvideos')(item) #... se procesa Findvideos item_res.channel = channel_save #... restaura el canal original por si hay fail-over en Newpct1 item_res.category = channel_save.capitalize() #... y la categoría del item_res.videolibray_emergency_urls #... y se borra la marca de lookup except: logger.error('ERROR al procesar el título en Findvideos del Canal: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) item_res = item.clone( ) #Si ha habido un error, se devuelve el Item original #Si el usuario ha activado la opción "emergency_urls_torrents", se descargarán los archivos .torrent de cada título else: #Si se han cacheado con éxito los enlaces... try: channel_bis = generictools.verify_channel(item.channel) if config.get_setting( "emergency_urls_torrents", channel_bis) and item_res.emergency_urls and path != None: videolibrary_path = config.get_videolibrary_path( ) #detectamos el path absoluto del título movies = config.get_setting("folder_movies") series = config.get_setting("folder_tvshows") if movies in path: folder = movies else: folder = series videolibrary_path = filetools.join(videolibrary_path, folder) i = 1 for url in item_res.emergency_urls[ 0]: #Recorremos las urls de emergencia... torrents_path = re.sub(r'(?:\.\w+$)', '_%s.torrent' % str(i).zfill(2), path) path_real = caching_torrents( url, torrents_path=torrents_path ) #... para descargar los .torrents if path_real: #Si ha tenido éxito... item_res.emergency_urls[0][i - 1] = path_real.replace( videolibrary_path, '') #se guarda el "path" relativo i += 1 except: logger.error('ERROR al cachear el .torrent de: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) item_res = item.clone( ) #Si ha habido un error, se devuelve el Item original #logger.debug(item_res.emergency_urls) return item_res #Devolvemos el Item actualizado con los enlaces de emergencia
def verify_directories_created(): from platformcode import logger from core import filetools from platformcode import xbmc_videolibrary config_paths = [["videolibrarypath", "videolibrary"], ["downloadpath", "downloads"], ["downloadlistpath", "downloads/list"], ["settings_path", "settings_channels"]] for path, default in config_paths: saved_path = get_setting(path) # video store if path == "videolibrarypath": if not saved_path: saved_path = xbmc_videolibrary.search_library_path() if saved_path: set_setting(path, saved_path) if not saved_path: saved_path = "special://profile/addon_data/plugin.video." + PLUGIN_NAME + "/" + default set_setting(path, saved_path) saved_path = xbmc.translatePath(saved_path) if not filetools.exists(saved_path): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) config_paths = [["folder_movies", "Film"], ["folder_tvshows", "Serie TV"]] for path, default in config_paths: saved_path = get_setting(path) if not saved_path: saved_path = default set_setting(path, saved_path) content_path = filetools.join(get_videolibrary_path(), saved_path) if not filetools.exists(content_path): logger.debug("Creating %s: %s" % (path, content_path)) # if the directory is created filetools.mkdir(content_path) from platformcode import xbmc_videolibrary xbmc_videolibrary.update_sources(get_setting("videolibrarypath")) xbmc_videolibrary.update_sources(get_setting("downloadpath")) try: from core import scrapertools # We look for the addon.xml file of the active skin skindir = filetools.join(xbmc.translatePath("special://home"), 'addons', xbmc.getSkinDir(), 'addon.xml') if not os.path.isdir(skindir): return # No need to show error in log if folder doesn't exist # We extract the name of the default resolution folder folder = "" data = filetools.read(skindir) res = scrapertools.find_multiple_matches(data, '(<res .*?>)') for r in res: if 'default="true"' in r: folder = scrapertools.find_single_match(r, 'folder="([^"]+)"') break # We check if it exists in the addon and if not, we create it default = filetools.join(get_runtime_path(), 'resources', 'skins', 'Default') if folder and not filetools.exists(filetools.join(default, folder)): filetools.mkdir(filetools.join(default, folder)) # We copy the file to said folder from the 720p folder if it does not exist or if the size is different if folder and folder != '720p': for root, folders, files in filetools.walk( filetools.join(default, '720p')): for f in files: if not filetools.exists(filetools.join( default, folder, f)) or (filetools.getsize( filetools.join( default, folder, f)) != filetools.getsize( filetools.join(default, '720p', f))): filetools.copy(filetools.join(default, '720p', f), filetools.join(default, folder, f), True) except: import traceback logger.error("When checking or creating the resolution folder") logger.error(traceback.format_exc())
def __init__(self, url, path, filename=None, headers=[], resume=True, max_connections=10, block_size=2**17, part_size=2**24, max_buffer=10): # Parametros self._resume = resume self._path = path self._filename = filename self._max_connections = max_connections self._block_size = block_size self._part_size = part_size self._max_buffer = max_buffer try: import xbmc self.tmp_path = xbmc.translatePath("special://temp/") except: self.tmp_path = os.getenv("TEMP") or os.getenv("TMP") or os.getenv( "TMPDIR") self.states = type( 'states', (), { "stopped": 0, "connecting": 1, "downloading": 2, "completed": 3, "error": 4, "saving": 5 }) self._state = self.states.stopped self._download_lock = Lock() self._headers = { "User-Agent": "Kodi/15.2 (Windows NT 10.0; WOW64) App_Bitness/32 Version/15.2-Git:20151019-02e7013" } self._speed = 0 self._buffer = {} self._seekable = True self._threads = [ Thread(target=self.__start_part__, name="Downloader %s/%s" % (x + 1, self._max_connections)) for x in range(self._max_connections) ] self._speed_thread = Thread(target=self.__speed_metter__, name="Speed Meter") self._save_thread = Thread(target=self.__save_file__, name="File Writer") # Actualizamos los headers self._headers.update(dict(headers)) # Separamos los headers de la url self.__url_to_headers__(url) # Obtenemos la info del servidor self.__get_download_headers__() self._file_size = int(self.response_headers.get("content-length", "0")) if not self.response_headers.get( "accept-ranges") == "bytes" or self._file_size == 0: self._max_connections = 1 self._part_size = 0 self._resume = False # Obtenemos el nombre del archivo self.__get_download_filename__() # Abrimos en modo "a+" para que cree el archivo si no existe, luego en modo "r+b" para poder hacer seek() self.file = filetools.file_open( filetools.join(self._path, self._filename), "a+") self.file = filetools.file_open( filetools.join(self._path, self._filename), "r+b") if self._file_size >= 2**31 or not self._file_size: try: self.file.seek(2**31) except OverflowError: self._seekable = False logger.info( "No se puede hacer seek() ni tell() en ficheros mayores de 2GB" ) self.__get_download_info__() logger.info( "Descarga inicializada: Partes: %s | Ruta: %s | Archivo: %s | Tamaño: %s" % (len(self._download_info["parts"]), self._path, self._filename, self._download_info["size"]))
def fullpath(self): return os.path.abspath(filetools.join(self._path, self._filename))
def get_episodios(item): logger.info() #logger.debug("item:\n" + item.tostring('\n')) itemlist = [] # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = filetools.walk(item.path).next() # Menu contextual: Releer tvshow.nfo head_nfo, item_nfo = library.read_nfo(item.nfo) # Crear un item en la lista para cada strm encontrado for i in ficheros: if i.endswith('.strm'): season_episode = scrapertools.get_season_and_episode(i) if not season_episode: # El fichero no incluye el numero de temporada y episodio continue season, episode = season_episode.split("x") # Si hay q filtrar por temporada, ignoramos los capitulos de otras temporadas if item.filtrar_season and int(season) != int(item.contentSeason): continue # Obtener los datos del season_episode.nfo nfo_path = filetools.join(raiz, i).replace('.strm', '.nfo') head_nfo, epi = library.read_nfo(nfo_path) # Fijar el titulo del capitulo si es posible if epi.contentTitle: title_episodie = epi.contentTitle.strip() else: title_episodie = "Temporada %s Episodio %s" % \ (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2)) epi.contentTitle = "%sx%s" % ( epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2)) epi.title = "%sx%s - %s" % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2), title_episodie) if item_nfo.library_filter_show: epi.library_filter_show = item_nfo.library_filter_show # Menu contextual: Marcar episodio como visto o no visto = item_nfo.library_playcounts.get(season_episode, 0) epi.infoLabels["playcount"] = visto if visto > 0: texto = "Marcar episodio como no visto" value = 0 else: texto = "Marcar episodio como visto" value = 1 epi.context = [{ "title": texto, "action": "mark_content_as_watched", "channel": "biblioteca", "playcount": value, "nfo": item.nfo }] # logger.debug("epi:\n" + epi.tostring('\n')) itemlist.append(epi) return sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber)))
def caching_torrents(url, torrents_path=None, timeout=10, lookup=False, data_torrent=False): if torrents_path != None: logger.info("path = " + torrents_path) else: logger.info() import urllib import re from core import httptools torrent_file = '' """ Descarga en el path recibido el .torrent de la url recibida, y pasa el decode Devuelve el path real del .torrent, o el path vacío si la operación no ha tenido éxito """ if torrents_path == None: videolibrary_path = config.get_videolibrary_path( ) #Calculamos el path absoluto a partir de la Videoteca if not videolibrary_path: torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío torrents_path = filetools.join( videolibrary_path, 'temp_torrents_Alfa', 'cliente_torrent_Alfa.torrent') #path de descarga temporal if '.torrent' not in torrents_path: torrents_path += '.torrent' #path para dejar el .torrent torrents_path_encode = filetools.encode( torrents_path) #encode utf-8 del path if url.endswith(".rar") or url.startswith( "magnet:"): #No es un archivo .torrent logger.error('No es un archivo Torrent: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío try: response = httptools.downloadpage( url, timeout=timeout) #Descargamos el .torrent if not response.sucess: logger.error('Archivo .torrent no encontrado: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío torrent_file = response.data if "used CloudFlare" in torrent_file: #Si tiene CloudFlare, usamos este proceso response = httptools.downloadpage( "http://anonymouse.org/cgi-bin/anon-www.cgi/" + url.strip(), timeout=timeout) if not response.sucess: logger.error('Archivo .torrent no encontrado: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío torrent_file = response.data if not scrapertools.find_single_match( torrent_file, '^d\d+:.*?\d+:' ): #No es un archivo .torrent (RAR, ZIP, HTML,..., vacío) logger.error('No es un archivo Torrent: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío if not lookup: if not filetools.write(torrents_path_encode, torrent_file): #Salvamos el .torrent logger.error('ERROR: Archivo .torrent no escrito: ' + torrents_path_encode) torrents_path = '' #Si hay un error, devolvemos el "path" vacío torrent_file = '' #... y el buffer del .torrent if data_torrent: return (torrents_path, torrent_file) return torrents_path except: torrents_path = '' #Si hay un error, devolvemos el "path" vacío torrent_file = '' #... y el buffer del .torrent logger.error('Error en el proceso de descarga del .torrent: ' + url + ' / ' + torrents_path_encode) logger.error(traceback.format_exc()) #logger.debug(torrents_path) if data_torrent: return (torrents_path, torrent_file) return torrents_path
def save_episodes(path, episodelist, serie, silent=False, overwrite=True): """ guarda en la ruta indicada todos los capitulos incluidos en la lista episodelist @type path: str @param path: ruta donde guardar los episodios @type episodelist: list @param episodelist: listado de items que representan los episodios que se van a guardar. @type serie: item @param serie: serie de la que se van a guardar los episodios @type silent: bool @param silent: establece si se muestra la notificación @param overwrite: permite sobreescribir los ficheros existentes @type overwrite: bool @rtype insertados: int @return: el número de episodios insertados @rtype sobreescritos: int @return: el número de episodios sobreescritos @rtype fallidos: int @return: el número de episodios fallidos """ logger.info() # No hay lista de episodios, no hay nada que guardar if not len(episodelist): logger.info("No hay lista de episodios, salimos sin crear strm") return 0, 0, 0 insertados = 0 sobreescritos = 0 fallidos = 0 news_in_playcounts = {} # Listamos todos los ficheros de la serie, asi evitamos tener que comprobar si existe uno por uno raiz, carpetas_series, ficheros = filetools.walk(path).next() ficheros = [filetools.join(path, f) for f in ficheros] nostrm_episodelist = [] for root, folders, files in filetools.walk(path): for file in files: season_episode = scrapertools.get_season_and_episode(file) if season_episode == "" or filetools.exists( filetools.join(path, "%s.strm" % season_episode)): continue nostrm_episodelist.append(season_episode) nostrm_episodelist = sorted(set(nostrm_episodelist)) # Silent es para no mostrar progreso (para videolibrary_service) if not silent: # progress dialog p_dialog = platformtools.dialog_progress( config.get_localized_string(20000), config.get_localized_string(60064)) p_dialog.update(0, config.get_localized_string(60065)) channel_alt = generictools.verify_channel( serie.channel) #Preparamos para añadir las urls de emergencia emergency_urls_stat = config.get_setting( "emergency_urls", channel_alt) #El canal quiere urls de emergencia? emergency_urls_succ = False channel = __import__('channels.%s' % channel_alt, fromlist=["channels.%s" % channel_alt]) if serie.torrent_caching_fail: #Si el proceso de conversión ha fallado, no se cachean emergency_urls_stat = 0 del serie.torrent_caching_fail new_episodelist = [] # Obtenemos el numero de temporada y episodio y descartamos los q no lo sean tags = [] if config.get_setting("enable_filter", "videolibrary"): tags = [ x.strip() for x in config.get_setting( "filters", "videolibrary").lower().split(",") ] for e in episodelist: if tags != [] and tags != None and any(tag in e.title.lower() for tag in tags): continue try: season_episode = scrapertools.get_season_and_episode(e.title) # Si se ha marcado la opción de url de emergencia, se añade ésta a cada episodio después de haber ejecutado Findvideos del canal if e.emergency_urls and isinstance(e.emergency_urls, dict): del e.emergency_urls #Borramos trazas anteriores json_path = filetools.join( path, ("%s [%s].json" % (season_episode, e.channel) ).lower()) #Path del .json del episodio if emergency_urls_stat == 1 and not e.emergency_urls and e.contentType == 'episode': #Guardamos urls de emergencia? if not silent: p_dialog.update(0, 'Cacheando enlaces y archivos .torrent...', e.title) #progress dialog if json_path in ficheros: #Si existe el .json sacamos de ahí las urls if overwrite: #pero solo si se se sobrescriben los .json json_epi = Item().fromjson( filetools.read(json_path)) #Leemos el .json if json_epi.emergency_urls: #si existen las urls de emergencia... e.emergency_urls = json_epi.emergency_urls #... las copiamos else: #y si no... e = emergency_urls(e, channel, json_path) #... las generamos else: e = emergency_urls( e, channel, json_path ) #Si el episodio no existe, generamos las urls if e.emergency_urls: #Si ya tenemos urls... emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo elif emergency_urls_stat == 2 and e.contentType == 'episode': #Borramos urls de emergencia? if e.emergency_urls: del e.emergency_urls emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo elif emergency_urls_stat == 3 and e.contentType == 'episode': #Actualizamos urls de emergencia? if not silent: p_dialog.update(0, 'Cacheando enlaces y archivos .torrent...', e.title) #progress dialog e = emergency_urls(e, channel, json_path) #generamos las urls if e.emergency_urls: #Si ya tenemos urls... emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo e.infoLabels = serie.infoLabels e.contentSeason, e.contentEpisodeNumber = season_episode.split("x") new_episodelist.append(e) except: if e.contentType == 'episode': logger.error( "No se ha podido guardar las urls de emergencia de %s en la videoteca" % e.contentTitle) logger.error(traceback.format_exc()) continue # No hay lista de episodios, no hay nada que guardar if not len(new_episodelist): logger.info("No hay lista de episodios, salimos sin crear strm") return 0, 0, 0 # fix float porque la division se hace mal en python 2.x t = float(100) / len(new_episodelist) for i, e in enumerate(scraper.sort_episode_list(new_episodelist)): if not silent: p_dialog.update(int(math.ceil((i + 1) * t)), config.get_localized_string(60064), e.title) season_episode = "%sx%s" % (e.contentSeason, str( e.contentEpisodeNumber).zfill(2)) strm_path = filetools.join(path, "%s.strm" % season_episode) nfo_path = filetools.join(path, "%s.nfo" % season_episode) json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) if season_episode in nostrm_episodelist: continue strm_exists = strm_path in ficheros nfo_exists = nfo_path in ficheros json_exists = json_path in ficheros if not strm_exists: # Si no existe season_episode.strm añadirlo item_strm = Item(action='play_from_library', channel='videolibrary', strm_path=strm_path.replace(TVSHOWS_PATH, ""), infoLabels={}) item_strm.contentSeason = e.contentSeason item_strm.contentEpisodeNumber = e.contentEpisodeNumber item_strm.contentType = e.contentType item_strm.contentTitle = season_episode # FILTERTOOLS if item_strm.list_language: # si tvshow.nfo tiene filtro se le pasa al item_strm que se va a generar if "library_filter_show" in serie: item_strm.library_filter_show = serie.library_filter_show if item_strm.library_filter_show == "": logger.error( "Se ha producido un error al obtener el nombre de la serie a filtrar" ) # logger.debug("item_strm" + item_strm.tostring('\n')) # logger.debug("serie " + serie.tostring('\n')) strm_exists = filetools.write( strm_path, '%s?%s' % (addon_name, item_strm.tourl())) item_nfo = None if not nfo_exists and e.infoLabels["code"]: # Si no existe season_episode.nfo añadirlo scraper.find_and_set_infoLabels(e) head_nfo = scraper.get_nfo(e) item_nfo = e.clone(channel="videolibrary", url="", action='findvideos', strm_path=strm_path.replace(TVSHOWS_PATH, "")) nfo_exists = filetools.write(nfo_path, head_nfo + item_nfo.tojson()) # Solo si existen season_episode.nfo y season_episode.strm continuamos if nfo_exists and strm_exists: if not json_exists or overwrite: # Obtenemos infoLabel del episodio if not item_nfo: head_nfo, item_nfo = read_nfo(nfo_path) e.infoLabels = item_nfo.infoLabels if filetools.write(json_path, e.tojson()): if not json_exists: logger.info("Insertado: %s" % json_path) insertados += 1 # Marcamos episodio como no visto news_in_playcounts[season_episode] = 0 # Marcamos la temporada como no vista news_in_playcounts["season %s" % e.contentSeason] = 0 # Marcamos la serie como no vista # logger.debug("serie " + serie.tostring('\n')) news_in_playcounts[serie.contentSerieName] = 0 else: logger.info("Sobreescrito: %s" % json_path) sobreescritos += 1 else: logger.info("Fallido: %s" % json_path) fallidos += 1 else: logger.info("Fallido: %s" % json_path) fallidos += 1 if not silent and p_dialog.iscanceled(): break if not silent: p_dialog.close() if news_in_playcounts: # Si hay nuevos episodios los marcamos como no vistos en tvshow.nfo ... tvshow_path = filetools.join(path, "tvshow.nfo") try: import datetime head_nfo, tvshow_item = read_nfo(tvshow_path) tvshow_item.library_playcounts.update(news_in_playcounts) #Si la operación de insertar/borrar urls de emergencia en los .jsons de los episodios ha tenido éxito, se marca el .nfo if emergency_urls_succ: if tvshow_item.emergency_urls and not isinstance( tvshow_item.emergency_urls, dict): del tvshow_item.emergency_urls if emergency_urls_stat in [ 1, 3 ]: #Operación de guardar/actualizar enlaces if not tvshow_item.emergency_urls: tvshow_item.emergency_urls = dict() tvshow_item.emergency_urls.update({serie.channel: True}) elif emergency_urls_stat == 2: #Operación de Borrar enlaces if tvshow_item.emergency_urls and tvshow_item.emergency_urls.get( serie.channel, False): tvshow_item.emergency_urls.pop( serie.channel, None) #borramos la entrada del .nfo if tvshow_item.active == 30: tvshow_item.active = 1 update_last = datetime.date.today() tvshow_item.update_last = update_last.strftime('%Y-%m-%d') update_next = datetime.date.today() + datetime.timedelta( days=int(tvshow_item.active)) tvshow_item.update_next = update_next.strftime('%Y-%m-%d') filetools.write(tvshow_path, head_nfo + tvshow_item.tojson()) except: logger.error("Error al actualizar tvshow.nfo") logger.error( "No se ha podido guardar las urls de emergencia de %s en la videoteca" % tvshow_item.contentSerieName) logger.error(traceback.format_exc()) fallidos = -1 else: # ... si ha sido correcto actualizamos la videoteca de Kodi if config.is_xbmc() and not silent: from platformcode import xbmc_videolibrary xbmc_videolibrary.update(FOLDER_TVSHOWS, filetools.basename(path)) if fallidos == len(episodelist): fallidos = -1 logger.debug("%s [%s]: insertados= %s, sobreescritos= %s, fallidos= %s" % (serie.contentSerieName, serie.channel, insertados, sobreescritos, fallidos)) return insertados, sobreescritos, fallidos
def downloadfileGzipped(url, pathfichero): logger.info("url=" + url) nombrefichero = pathfichero logger.info("nombrefichero=" + nombrefichero) nombrefichero = filetools.makeLegalFilename(nombrefichero) logger.info("nombrefichero=" + nombrefichero) patron = "(http://[^/]+)/.+" matches = re.compile(patron, re.DOTALL).findall(url) if len(matches): logger.info("URL principal :" + matches[0]) url1 = matches[0] else: url1 = url txheaders = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; ' 'Media Center PC 5.0; .NET CLR 3.0.04506)', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'es-es,es;q=0.8,en-us;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip,deflate', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Keep-Alive': '115', 'Connection': 'keep-alive', 'Referer': url1, } txdata = "" # Crea el diálogo de progreso from platformcode import platformtools progreso = platformtools.dialog_progress("addon", config.get_localized_string(60200), url.split("|")[0], nombrefichero) # Timeout del socket a 60 segundos socket.setdefaulttimeout(10) h = urllib.request.HTTPHandler(debuglevel=0) request = urllib.request.Request(url, txdata, txheaders) # if existSize > 0: # request.add_header('Range', 'bytes=%d-' % (existSize, )) opener = urllib.request.build_opener(h) urllib.request.install_opener(opener) try: connexion = opener.open(request) except urllib.error.HTTPError as e: logger.error("error %d (%s) al abrir la url %s" % (e.code, e.msg, url)) progreso.close() # El error 416 es que el rango pedido es mayor que el fichero => es que ya está completo if e.code == 416: return 0 else: return -2 nombre_fichero_base = filetools.basename(nombrefichero) if len(nombre_fichero_base) == 0: logger.info("Buscando nombre en el Headers de respuesta") nombre_base = connexion.headers["Content-Disposition"] logger.info(nombre_base) patron = 'filename="([^"]+)"' matches = re.compile(patron, re.DOTALL).findall(nombre_base) if len(matches) > 0: titulo = matches[0] titulo = GetTitleFromFile(titulo) nombrefichero = filetools.join(pathfichero, titulo) else: logger.info("Nombre del fichero no encontrado, Colocando nombre temporal :sin_nombre.txt") titulo = "sin_nombre.txt" nombrefichero = filetools.join(pathfichero, titulo) totalfichero = int(connexion.headers["Content-Length"]) # despues f = filetools.file_open(nombrefichero, 'w', vfs=VFS) logger.info("fichero nuevo abierto") grabado = 0 logger.info("Content-Length=%s" % totalfichero) blocksize = 100 * 1024 bloqueleido = connexion.read(blocksize) try: import io compressedstream = io.StringIO(bloqueleido) import gzip gzipper = gzip.GzipFile(fileobj=compressedstream) bloquedata = gzipper.read() gzipper.close() logger.info("Iniciando descarga del fichero, bloqueleido=%s" % len(bloqueleido)) except: logger.error("ERROR : El archivo a descargar no esta comprimido con Gzip") f.close() progreso.close() return -2 maxreintentos = 10 while len(bloqueleido) > 0: try: # Escribe el bloque leido f.write(bloquedata) grabado += len(bloqueleido) percent = int(float(grabado) * 100 / float(totalfichero)) totalmb = float(float(totalfichero) / (1024 * 1024)) descargadosmb = float(float(grabado) / (1024 * 1024)) # Lee el siguiente bloque, reintentando para no parar todo al primer timeout reintentos = 0 while reintentos <= maxreintentos: try: before = time.time() bloqueleido = connexion.read(blocksize) import gzip import io compressedstream = io.StringIO(bloqueleido) gzipper = gzip.GzipFile(fileobj=compressedstream) bloquedata = gzipper.read() gzipper.close() after = time.time() if (after - before) > 0: velocidad = old_div(len(bloqueleido), (after - before)) falta = totalfichero - grabado if velocidad > 0: tiempofalta = old_div(falta, velocidad) else: tiempofalta = 0 logger.info(sec_to_hms(tiempofalta)) progreso.update(percent, "%.2fMB/%.2fMB (%d%%) %.2f Kb/s %s falta " % (descargadosmb, totalmb, percent, old_div(velocidad, 1024), sec_to_hms(tiempofalta))) break except: reintentos += 1 logger.info("ERROR en la descarga del bloque, reintento %d" % reintentos) for line in sys.exc_info(): logger.error("%s" % line) # El usuario cancelo la descarga if progreso.iscanceled(): logger.info("Descarga del fichero cancelada") f.close() progreso.close() return -1 # Ha habido un error en la descarga if reintentos > maxreintentos: logger.info("ERROR en la descarga del fichero") f.close() progreso.close() return -2 except: logger.info("ERROR en la descarga del fichero") for line in sys.exc_info(): logger.error("%s" % line) f.close() progreso.close() return -2 f.close() # print data progreso.close() logger.info("Fin descarga del fichero") return nombrefichero
def verify_directories_created(): from platformcode import logger from core import filetools from platformcode import xbmc_videolibrary config_paths = [["videolibrarypath", "videolibrary"], ["downloadpath", "downloads"], ["downloadlistpath", "downloads/list"], ["settings_path", "settings_channels"]] for path, default in config_paths: saved_path = get_setting(path) # videoteca if path == "videolibrarypath": if not saved_path: saved_path = xbmc_videolibrary.search_library_path() if saved_path: set_setting(path, saved_path) if not saved_path: saved_path = "special://profile/addon_data/plugin.video." + PLUGIN_NAME + "/" + default set_setting(path, saved_path) saved_path = xbmc.translatePath(saved_path) if not filetools.exists(saved_path): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) config_paths = [["folder_movies", "CINE"], ["folder_tvshows", "SERIES"]] for path, default in config_paths: saved_path = get_setting(path) if not saved_path: saved_path = default set_setting(path, saved_path) content_path = filetools.join(get_videolibrary_path(), saved_path) if not filetools.exists(content_path): logger.debug("Creating %s: %s" % (path, content_path)) # si se crea el directorio filetools.mkdir(content_path) try: from core import scrapertools # Buscamos el archivo addon.xml del skin activo skindir = filetools.join(xbmc.translatePath("special://home"), 'addons', xbmc.getSkinDir(), 'addon.xml') if not os.path.isdir(skindir): return # No hace falta mostrar error en el log si no existe la carpeta # Extraemos el nombre de la carpeta de resolución por defecto folder = "" data = filetools.read(skindir) res = scrapertools.find_multiple_matches(data, '(<res .*?>)') for r in res: if 'default="true"' in r: folder = scrapertools.find_single_match(r, 'folder="([^"]+)"') break # Comprobamos si existe en el addon y sino es así, la creamos default = filetools.join(get_runtime_path(), 'resources', 'skins', 'Default') if folder and not filetools.exists(filetools.join(default, folder)): filetools.mkdir(filetools.join(default, folder)) # Copiamos el archivo a dicha carpeta desde la de 720p si éste no existe o si el tamaño es diferente if folder and folder != '720p': for root, folders, files in filetools.walk( filetools.join(default, '720p')): for f in files: if not filetools.exists(filetools.join(default, folder, f)) or \ (filetools.getsize(filetools.join(default, folder, f)) != filetools.getsize(filetools.join(default, '720p', f))): filetools.copy(filetools.join(default, '720p', f), filetools.join(default, folder, f), True) except: import traceback logger.error("Al comprobar o crear la carpeta de resolución") logger.error(traceback.format_exc())
def save_movie(item): """ guarda en la libreria de peliculas el elemento item, con los valores que contiene. @type item: item @param item: elemento que se va a guardar. @rtype insertados: int @return: el número de elementos insertados @rtype sobreescritos: int @return: el número de elementos sobreescritos @rtype fallidos: int @return: el número de elementos fallidos o -1 si ha fallado todo """ logger.info() # logger.debug(item.tostring('\n')) insertados = 0 sobreescritos = 0 fallidos = 0 path = "" # Itentamos obtener el titulo correcto: # 1. contentTitle: Este deberia ser el sitio correcto, ya que title suele contener "Añadir a la videoteca..." # 2. fulltitle # 3. title if not item.contentTitle: # Colocamos el titulo correcto en su sitio para que scraper lo localize if item.fulltitle: item.contentTitle = item.fulltitle else: item.contentTitle = item.title # Si llegados a este punto no tenemos titulo, salimos if not item.contentTitle or not item.channel: logger.debug("NO ENCONTRADO contentTitle") return 0, 0, -1 # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) # Llegados a este punto podemos tener: # scraper_return = True: Un item con infoLabels con la información actualizada de la peli # scraper_return = False: Un item sin información de la peli (se ha dado a cancelar en la ventana) # item.infoLabels['code'] == "" : No se ha encontrado el identificador de IMDB necesario para continuar, salimos if not scraper_return or not item.infoLabels['code']: # TODO de momento si no hay resultado no añadimos nada, # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano logger.debug("NO ENCONTRADO EN SCRAPER O NO TIENE code") return 0, 0, -1 _id = item.infoLabels['code'][0] # progress dialog p_dialog = platformtools.dialog_progress( config.get_localized_string(20000), config.get_localized_string(60062)) if config.get_setting( "original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']: base_name = item.infoLabels['originaltitle'] else: base_name = item.contentTitle base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8") if config.get_setting("lowerize_title", "videolibrary") == 0: base_name = base_name.lower() for raiz, subcarpetas, ficheros in filetools.walk(MOVIES_PATH): for c in subcarpetas: code = scrapertools.find_single_match(c, '\[(.*?)\]') if code and code in item.infoLabels['code']: path = filetools.join(raiz, c) _id = code break if not path: # Crear carpeta path = filetools.join(MOVIES_PATH, ("%s [%s]" % (base_name, _id)).strip()) logger.info("Creando directorio pelicula:" + path) if not filetools.mkdir(path): logger.debug("No se ha podido crear el directorio") return 0, 0, -1 nfo_path = filetools.join(path, "%s [%s].nfo" % (base_name, _id)) strm_path = filetools.join(path, "%s.strm" % base_name) json_path = filetools.join(path, ("%s [%s].json" % (base_name, item.channel.lower()))) nfo_exists = filetools.exists(nfo_path) strm_exists = filetools.exists(strm_path) json_exists = filetools.exists(json_path) if not nfo_exists: # Creamos .nfo si no existe logger.info("Creando .nfo: " + nfo_path) head_nfo = scraper.get_nfo(item) item_nfo = Item(title=item.contentTitle, channel="videolibrary", action='findvideos', library_playcounts={"%s [%s]" % (base_name, _id): 0}, infoLabels=item.infoLabels, library_urls={}) else: # Si existe .nfo, pero estamos añadiendo un nuevo canal lo abrimos head_nfo, item_nfo = read_nfo(nfo_path) if not strm_exists: # Crear base_name.strm si no existe item_strm = Item(channel='videolibrary', action='play_from_library', strm_path=strm_path.replace(MOVIES_PATH, ""), contentType='movie', contentTitle=item.contentTitle) strm_exists = filetools.write( strm_path, '%s?%s' % (addon_name, item_strm.tourl())) item_nfo.strm_path = strm_path.replace(MOVIES_PATH, "") # Solo si existen item_nfo y .strm continuamos if item_nfo and strm_exists: if json_exists: logger.info("El fichero existe. Se sobreescribe") sobreescritos += 1 else: insertados += 1 # Si se ha marcado la opción de url de emergencia, se añade ésta a la película después de haber ejecutado Findvideos del canal try: channel = generictools.verify_channel(item.channel) if config.get_setting("emergency_urls", channel) in [1, 3]: item = emergency_urls(item, None, json_path) if item_nfo.emergency_urls and not isinstance( item_nfo.emergency_urls, dict): del item_nfo.emergency_urls if not item_nfo.emergency_urls: item_nfo.emergency_urls = dict() item_nfo.emergency_urls.update({item.channel: True}) except: logger.error( "No se ha podido guardar las urls de emergencia de %s en la videoteca" % item.contentTitle) logger.error(traceback.format_exc()) if filetools.write(json_path, item.tojson()): p_dialog.update(100, 'Añadiendo película...', item.contentTitle) item_nfo.library_urls[item.channel] = item.url if filetools.write(nfo_path, head_nfo + item_nfo.tojson()): # actualizamos la videoteca de Kodi con la pelicula if config.is_xbmc(): from platformcode import xbmc_videolibrary xbmc_videolibrary.update(FOLDER_MOVIES, filetools.basename(path) + "/") p_dialog.close() return insertados, sobreescritos, fallidos # Si llegamos a este punto es por q algo ha fallado logger.error("No se ha podido guardar %s en la videoteca" % item.contentTitle) p_dialog.update(100, config.get_localized_string(60063), item.contentTitle) p_dialog.close() return 0, 0, -1
def execute_sql_kodi(sql): """ Ejecuta la consulta sql contra la base de datos de kodi @param sql: Consulta sql valida @type sql: str @return: Numero de registros modificados o devueltos por la consulta @rtype nun_records: int @return: lista con el resultado de la consulta @rtype records: list of tuples """ logger.info() file_db = "" nun_records = 0 records = None # Buscamos el archivo de la BBDD de videos segun la version de kodi video_db = config.get_platform(True)['video_db'] if video_db: file_db = filetools.join( xbmc.translatePath("special://userdata/Database"), video_db) # metodo alternativo para localizar la BBDD if not file_db or not filetools.exists(file_db): file_db = "" for f in filetools.listdir( xbmc.translatePath("special://userdata/Database")): path_f = filetools.join( xbmc.translatePath("special://userdata/Database"), f) if filetools.isfile(path_f) and f.lower().startswith( 'myvideos') and f.lower().endswith('.db'): file_db = path_f break if file_db: logger.info("Archivo de BD: %s" % file_db) conn = None try: import sqlite3 conn = sqlite3.connect(file_db) cursor = conn.cursor() logger.info("Ejecutando sql: %s" % sql) cursor.execute(sql) conn.commit() records = cursor.fetchall() if sql.lower().startswith("select"): nun_records = len(records) if nun_records == 1 and records[0][0] is None: nun_records = 0 records = [] else: nun_records = conn.total_changes conn.close() logger.info("Consulta ejecutada. Registros: %s" % nun_records) except: logger.error("Error al ejecutar la consulta sql") if conn: conn.close() else: logger.debug("Base de datos no encontrada") return nun_records, records
def save_tvshow(item, episodelist): """ guarda en la libreria de series la serie con todos los capitulos incluidos en la lista episodelist @type item: item @param item: item que representa la serie a guardar @type episodelist: list @param episodelist: listado de items que representan los episodios que se van a guardar. @rtype insertados: int @return: el número de episodios insertados @rtype sobreescritos: int @return: el número de episodios sobreescritos @rtype fallidos: int @return: el número de episodios fallidos o -1 si ha fallado toda la serie @rtype path: str @return: directorio serie """ logger.info() # logger.debug(item.tostring('\n')) path = "" # Si llegados a este punto no tenemos titulo o code, salimos if not (item.contentSerieName or item.infoLabels['code']) or not item.channel: logger.debug("NO ENCONTRADO contentSerieName NI code") return 0, 0, -1, path # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) # Llegados a este punto podemos tener: # scraper_return = True: Un item con infoLabels con la información actualizada de la serie # scraper_return = False: Un item sin información de la peli (se ha dado a cancelar en la ventana) # item.infoLabels['code'] == "" : No se ha encontrado el identificador de IMDB necesario para continuar, salimos if not scraper_return or not item.infoLabels['code']: # TODO de momento si no hay resultado no añadimos nada, # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano logger.debug("NO ENCONTRADO EN SCRAPER O NO TIENE code") return 0, 0, -1, path _id = item.infoLabels['code'][0] if config.get_setting( "original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']: base_name = item.infoLabels['originaltitle'] elif item.infoLabels['tvshowtitle']: base_name = item.infoLabels['tvshowtitle'] elif item.infoLabels['title']: base_name = item.infoLabels['title'] else: base_name = item.contentSerieName base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8") if config.get_setting("lowerize_title", "videolibrary") == 0: base_name = base_name.lower() for raiz, subcarpetas, ficheros in filetools.walk(TVSHOWS_PATH): for c in subcarpetas: code = scrapertools.find_single_match(c, '\[(.*?)\]') if code and code in item.infoLabels['code']: path = filetools.join(raiz, c) _id = code break if not path: path = filetools.join(TVSHOWS_PATH, ("%s [%s]" % (base_name, _id)).strip()) logger.info("Creando directorio serie: " + path) try: filetools.mkdir(path) except OSError, exception: if exception.errno != errno.EEXIST: raise
def sync_trakt_addon(path_folder): """ Actualiza los valores de episodios vistos si """ logger.info() # si existe el addon hacemos la busqueda if xbmc.getCondVisibility('System.HasAddon("script.trakt")'): # importamos dependencias paths = [ "special://home/addons/script.module.dateutil/lib/", "special://home/addons/script.module.six/lib/", "special://home/addons/script.module.arrow/lib/", "special://home/addons/script.module.trakt/lib/", "special://home/addons/script.trakt/" ] for path in paths: import sys sys.path.append(xbmc.translatePath(path)) # se obtiene las series vistas try: from resources.lib.traktapi import traktAPI traktapi = traktAPI() except: return shows = traktapi.getShowsWatched({}) shows = shows.items() # obtenemos el id de la serie para comparar import re _id = re.findall("\[(.*?)\]", path_folder, flags=re.DOTALL)[0] logger.debug("el id es %s" % _id) if "tt" in _id: type_id = "imdb" elif "tvdb_" in _id: _id = _id.strip("tvdb_") type_id = "tvdb" elif "tmdb_" in _id: type_id = "tmdb" _id = _id.strip("tmdb_") else: logger.error("No hay _id de la serie") return # obtenemos los valores de la serie from core import videolibrarytools tvshow_file = filetools.join(path_folder, "tvshow.nfo") head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) # buscamos en las series de trakt for show in shows: show_aux = show[1].to_dict() try: _id_trakt = show_aux['ids'].get(type_id, None) # logger.debug("ID ES %s" % _id_trakt) if _id_trakt: if _id == _id_trakt: logger.debug("ENCONTRADO!! %s" % show_aux) # creamos el diccionario de trakt para la serie encontrada con el valor que tiene "visto" dict_trakt_show = {} for idx_season, season in enumerate( show_aux['seasons']): for idx_episode, episode in enumerate( show_aux['seasons'][idx_season] ['episodes']): sea_epi = "%sx%s" % ( show_aux['seasons'][idx_season]['number'], str(show_aux['seasons'][idx_season] ['episodes'][idx_episode] ['number']).zfill(2)) dict_trakt_show[sea_epi] = show_aux['seasons'][ idx_season]['episodes'][idx_episode][ 'watched'] logger.debug("dict_trakt_show %s " % dict_trakt_show) # obtenemos las keys que son episodios regex_epi = re.compile('\d+x\d+') keys_episodes = [ key for key in serie.library_playcounts if regex_epi.match(key) ] # obtenemos las keys que son temporadas keys_seasons = [ key for key in serie.library_playcounts if 'season ' in key ] # obtenemos los numeros de las keys temporadas seasons = [ key.strip('season ') for key in keys_seasons ] # marcamos los episodios vistos for k in keys_episodes: serie.library_playcounts[k] = dict_trakt_show.get( k, 0) for season in seasons: episodios_temporada = 0 episodios_vistos_temporada = 0 # obtenemos las keys de los episodios de una determinada temporada keys_season_episodes = [ key for key in keys_episodes if key.startswith("%sx" % season) ] for k in keys_season_episodes: episodios_temporada += 1 if serie.library_playcounts[k] > 0: episodios_vistos_temporada += 1 # se comprueba que si todos los episodios están vistos, se marque la temporada como vista if episodios_temporada == episodios_vistos_temporada: serie.library_playcounts.update( {"season %s" % season: 1}) temporada = 0 temporada_vista = 0 for k in keys_seasons: temporada += 1 if serie.library_playcounts[k] > 0: temporada_vista += 1 # se comprueba que si todas las temporadas están vistas, se marque la serie como vista if temporada == temporada_vista: serie.library_playcounts.update({serie.title: 1}) logger.debug("los valores nuevos %s " % serie.library_playcounts) filetools.write(tvshow_file, head_nfo + serie.tojson()) break else: continue else: logger.error( "no se ha podido obtener el id, trakt tiene: %s" % show_aux['ids']) except: import traceback logger.error(traceback.format_exc())
def updateFromZip(message='Installazione in corso...'): dp = platformtools.dialog_progress_bg('Kodi on Demand', message) dp.update(0) remotefilename = 'https://github.com/' + user + "/" + repo + "/archive/" + branch + ".zip" localfilename = filetools.join(xbmc.translatePath("special://home/addons/"), "plugin.video.kod.update.zip") destpathname = xbmc.translatePath("special://home/addons/") extractedDir = filetools.join(destpathname, "addon-" + branch) logger.info("remotefilename=%s" % remotefilename) logger.info("localfilename=%s" % localfilename) logger.info('extract dir: ' + extractedDir) # pulizia preliminare remove(localfilename) removeTree(extractedDir) try: urllib.urlretrieve(remotefilename, localfilename, lambda nb, bs, fs, url=remotefilename: _pbhook(nb, bs, fs, url, dp)) except Exception as e: platformtools.dialog_ok('Kodi on Demand', 'Non riesco a scaricare il file d\'installazione da github, questo è probabilmente dovuto ad una mancanza di connessione (o qualcosa impedisce di raggiungere github).\n' 'Controlla bene e quando hai risolto riapri KoD.') logger.info('Non sono riuscito a scaricare il file zip') logger.info(e) dp.close() return False # Lo descomprime logger.info("decompressione...") logger.info("destpathname=%s" % destpathname) if os.path.isfile(localfilename): logger.info('il file esiste') import zipfile try: hash = fixZipGetHash(localfilename) logger.info(hash) with zipfile.ZipFile(fOpen(localfilename, 'rb')) as zip: size = sum([zinfo.file_size for zinfo in zip.filelist]) cur_size = 0 for member in zip.infolist(): zip.extract(member, destpathname) cur_size += member.file_size dp.update(int(80 + cur_size * 19 / size)) except Exception as e: logger.info('Non sono riuscito ad estrarre il file zip') logger.error(e) import traceback logger.error(traceback.print_exc()) dp.close() remove(localfilename) return False dp.update(99) # puliamo tutto global addonDir if extractedDir != addonDir: removeTree(addonDir) xbmc.sleep(1000) rename(extractedDir, 'plugin.video.kod') addonDir = filetools.join(destpathname, 'plugin.video.kod') logger.info("Cancellando il file zip...") remove(localfilename) dp.update(100) dp.close() if message != 'Installazione in corso...': xbmc.executebuiltin("UpdateLocalAddons") refreshLang() return hash
def mark_content_as_watched_on_kodi(item, value=1): """ marca el contenido como visto o no visto 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')) payload_f = '' if item.contentType == "movie": movieid = 0 payload = { "jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties": ["title", "playcount", "originaltitle", "file"] }, "id": 1 } data = get_data(payload) if 'result' in data and "movies" in data['result']: filename = filetools.basename(item.strm_path) head, tail = filetools.split(filetools.split(item.strm_path)[0]) path = filetools.join(tail, filename) for d in data['result']['movies']: if d['file'].replace("/", "\\").endswith(path.replace("/", "\\")): # logger.debug("marco la pelicula como vista") movieid = d['movieid'] break if movieid != 0: payload_f = { "jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": movieid, "playcount": value }, "id": 1 } else: # item.contentType != 'movie' episodeid = 0 payload = { "jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "properties": ["title", "playcount", "showtitle", "file", "tvshowid"] }, "id": 1 } data = get_data(payload) if 'result' in data and "episodes" in data['result']: filename = filetools.basename(item.strm_path) head, tail = filetools.split(filetools.split(item.strm_path)[0]) path = filetools.join(tail, filename) for d in data['result']['episodes']: if d['file'].replace("/", "\\").endswith(path.replace("/", "\\")): # logger.debug("marco el episodio como visto") episodeid = d['episodeid'] break if episodeid != 0: payload_f = { "jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": episodeid, "playcount": value }, "id": 1 } if payload_f: # Marcar como visto data = get_data(payload_f) # logger.debug(str(data)) if data['result'] != 'OK': logger.error("ERROR al poner el contenido como visto")
def findvideos(item): logger.info() # logger.debug("item:\n" + item.tostring('\n')) itemlist = [] list_canales = {} item_local = None if not item.contentTitle or not item.strm_path: logger.debug("No se pueden buscar videos por falta de parametros") return [] content_title = filter(lambda c: c not in ":*?<>|\/", item.contentTitle).strip().lower() if item.contentType == 'movie': item.strm_path = filetools.join(library.MOVIES_PATH, item.strm_path) path_dir = os.path.dirname(item.strm_path) item.nfo = filetools.join(path_dir, os.path.basename(path_dir) + ".nfo") else: item.strm_path = filetools.join(library.TVSHOWS_PATH, item.strm_path) path_dir = os.path.dirname(item.strm_path) item.nfo = filetools.join(path_dir, 'tvshow.nfo') for fd in filetools.listdir(path_dir): if fd.endswith('.json'): contenido, nom_canal = fd[:-6].split('[') if (content_title in contenido.strip() or item.contentType == 'movie') and nom_canal not in \ list_canales.keys(): list_canales[nom_canal] = filetools.join(path_dir, fd) num_canales = len(list_canales) logger.debug(str(list_canales)) if 'descargas' in list_canales: json_path = list_canales['descargas'] item_json = Item().fromjson(filetools.read(json_path)) #Soporte para rutas relativas en descargas if filetools.is_relative(item_json.url): item_json.url = filetools.join(library.LIBRARY_PATH,item_json.url) del list_canales['descargas'] # Comprobar q el video no haya sido borrado if filetools.exists(item_json.url): item_local = item_json.clone(action='play') itemlist.append(item_local) else: num_canales -= 1 filtro_canal = '' if num_canales > 1 and config.get_setting("ask_channel", "biblioteca") == True: opciones = ["Mostra solo link %s" % k.capitalize() for k in list_canales.keys()] opciones.insert(0, "Mosta tutti i collegamenti") if item_local: opciones.append(item_local.title) from platformcode import platformtools index = platformtools.dialog_select(config.get_localized_string(30163), opciones) if index < 0: return [] elif item_local and index == len(opciones) - 1: filtro_canal = 'descargas' platformtools.play_video(item_local) elif index > 0: filtro_canal = opciones[index].replace("Mostra solo link ", "") itemlist = [] for nom_canal, json_path in list_canales.items(): if filtro_canal and filtro_canal != nom_canal.capitalize(): continue # Importamos el canal de la parte seleccionada try: channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal]) except ImportError: exec "import channels." + nom_canal + " as channel" item_json = Item().fromjson(filetools.read(json_path)) list_servers = [] try: # FILTERTOOLS # si el canal tiene filtro se le pasa el nombre que tiene guardado para que filtre correctamente. if "list_idiomas" in item_json: # si se viene desde la biblioteca de pelisalacarta if "library_filter_show" in item: item_json.show = item.library_filter_show.get(nom_canal, "") # Ejecutamos find_videos, del canal o común if hasattr(channel, 'findvideos'): list_servers = getattr(channel, 'findvideos')(item_json) else: from core import servertools list_servers = servertools.find_video_items(item_json) except Exception as ex: logger.error("Ha fallado la funcion findvideos para el canal %s" % nom_canal) template = "An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logger.error(message) # Cambiarle el titulo a los servers añadiendoles el nombre del canal delante y # las infoLabels y las imagenes del item si el server no tiene for server in list_servers: if not server.action: # Ignorar las etiquetas continue server.contentChannel = server.channel server.channel = "biblioteca" server.nfo = item.nfo server.strm_path = item.strm_path # Se añade el nombre del canal si se desea if config.get_setting("quit_channel_name", "biblioteca") == 0: server.title = "%s: %s" % (nom_canal.capitalize(), server.title) server.infoLabels = item_json.infoLabels if not server.thumbnail: server.thumbnail = item.thumbnail # logger.debug("server:\n%s" % server.tostring('\n')) itemlist.append(server) # return sorted(itemlist, key=lambda it: it.title.lower()) return itemlist
def update(path, p_dialog, i, t, serie, overwrite): 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 insertados_total = 0 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 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) if serie.library_filter_show: serie.show = serie.library_filter_show.get( serie.channel, serie.contentSerieName) 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) == 3: # Sobrescribir todos los archivos (tvshow.nfo, 1x01.nfo, 1x01 [canal].json, 1x01.strm, etc...) insertados, sobreescritos, fallidos, notusedpath = videolibrarytools.save_tvshow( serie, itemlist) #serie= videolibrary.check_season_playcount(serie, serie.contentSeason) #if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()): # 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 filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()): # 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()) 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()) 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(): #Si es Kodi, lo hacemos from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) return insertados_total > 0
def check_for_update(overwrite=True): logger.info("Actualizando series...") logger.info("Overwrite? -> " + str(overwrite)) p_dialog = None serie_actualizada = False update_when_finished = False library_updated = False hoy = datetime.date.today() overwrite_everything = False try: if overwrite == "everything": overwrite = True overwrite_everything = True if config.get_setting("updatelibrary", "biblioteca") != 0 or overwrite: config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "biblioteca") if config.get_setting("updatelibrary", "biblioteca") == 1 and not overwrite: # "Actualizar al inicio" y No venimos del canal configuracion updatelibrary_wait = [0, 10000, 20000, 30000, 60000] wait = updatelibrary_wait[int( config.get_setting("updatelibrary_wait", "biblioteca"))] if wait > 0: import xbmc xbmc.sleep(wait) heading = 'Actualizando biblioteca....' p_dialog = platformtools.dialog_progress_bg( 'pelisalacarta', heading) p_dialog.update(0, '') show_list = [] for path, folders, files in filetools.walk(library.TVSHOWS_PATH): show_list.extend([ filetools.join(path, f) for f in files if f == "tvshow.nfo" ]) if show_list: t = float(100) / len(show_list) for i, tvshow_file in enumerate(show_list): head_nfo, serie = library.read_nfo(tvshow_file) path = filetools.dirname(tvshow_file) logger.info("serie=" + serie.contentSerieName) p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName) interval = int(serie.active) # Podria ser del tipo bool if not serie.active: # si la serie no esta activa descartar continue # obtenemos las fecha de auctualizacion y de la proxima programada para esta serie update_next = serie.update_next if update_next: y, m, d = update_next.split('-') update_next = datetime.date(int(y), int(m), int(d)) else: update_next = hoy update_last = serie.update_last if update_last: y, m, d = update_last.split('-') update_last = datetime.date(int(y), int(m), int(d)) else: update_last = hoy # si la serie esta activa ... if overwrite or config.get_setting("updatetvshows_interval", "biblioteca") == 0: # ... forzar actualizacion independientemente del intervalo if overwrite_everything: overwrite = "everything" serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) elif interval == 1 and update_next <= hoy: # ...actualizacion diaria serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada and update_last <= hoy - datetime.timedelta( days=7): # si hace una semana q no se actualiza, pasar el intervalo a semanal interval = 7 update_next = hoy + datetime.timedelta(days=interval) elif interval == 7 and update_next <= hoy: # ...actualizacion semanal serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: if update_last <= hoy - datetime.timedelta(days=14): # si hace 2 semanas q no se actualiza, pasar el intervalo a mensual interval = 30 update_next += datetime.timedelta(days=interval) elif interval == 30 and update_next <= hoy: # ...actualizacion mensual serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next += datetime.timedelta(days=interval) if interval != int(serie.active) or update_next.strftime( '%Y-%m-%d') != serie.update_next: serie.active = interval serie.update_next = update_next.strftime('%Y-%m-%d') serie.channel = "biblioteca" serie.action = "get_temporadas" filetools.write(tvshow_file, head_nfo + serie.tojson()) if serie_actualizada: if config.get_setting("search_new_content", "biblioteca") == 0: # Actualizamos la biblioteca de Kodi xbmc_library.update(folder=filetools.basename(path)) library_updated = True else: update_when_finished = True if config.get_setting("search_new_content", "biblioteca") == 1: if update_when_finished: # Actualizamos la biblioteca de Kodi import xbmc xbmc.executebuiltin('UpdateLibrary(video)') library_updated = True if config.get_setting("clean_after_update", "biblioteca") is True: if library_updated: import xbmc xbmc.executebuiltin('CleanLibrary(video)') p_dialog.close() else: logger.info( "No actualiza la biblioteca, está desactivado en la configuración de pelisalacarta" ) except Exception as ex: logger.error("Se ha producido un error al actualizar las series") template = "An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logger.error(message) if p_dialog: p_dialog.close()
def check_for_update(overwrite=True): logger.info("Actualizando series...") from core import filetools from core import channeltools, videolibrarytools from platformcode import platformtools from channels import videolibrary from lib import generictools p_dialog = None serie_actualizada = False update_when_finished = False hoy = datetime.date.today() estado_verify_playcount_series = False try: if config.get_setting("update", "videolibrary") != 0 or overwrite: config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "videolibrary") heading = config.get_localized_string(60389) p_dialog = platformtools.dialog_progress_bg( config.get_localized_string(20000), heading) p_dialog.update(0, '') show_list = [] for path, folders, files in filetools.walk( videolibrarytools.TVSHOWS_PATH): show_list.extend([ filetools.join(path, f) for f in files if f == "tvshow.nfo" ]) if show_list: t = float(100) / len(show_list) for i, tvshow_file in enumerate(show_list): try: head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) if not serie: logger.error('.nfo erroneo en ' + str(tvshow_file)) continue path = filetools.dirname(tvshow_file) ###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial overwrite_forced = False try: serie, serie, overwrite_forced = generictools.redirect_clone_newpct1( serie, head_nfo, serie, path, overwrite, lookup=True) except: logger.error(traceback.format_exc()) if overwrite_forced == True: overwrite = True serie.update_next = '' info_status = '' if serie.infoLabels['status']: info_status = serie.infoLabels['status'] logger.info("Serie=%s, Activa=%s, Fecha=%s, Status=%s" % (serie.contentSerieName, \ str(serie.active), str(serie.update_last), str(info_status))) p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName) #Verificamos el estado del serie.library_playcounts de la Serie por si está incompleto try: estado = False #Si no hemos hecho la verificación o no tiene playcount, entramos estado = config.get_setting("verify_playcount", "videolibrary") if not estado or estado == False or not serie.library_playcounts: #Si no se ha pasado antes, lo hacemos ahora serie, estado = videolibrary.verify_playcount_series( serie, path ) #También se pasa si falta un PlayCount por completo except: logger.error(traceback.format_exc()) else: if estado: #Si ha tenido éxito la actualización... estado_verify_playcount_series = True #... se marca para cambiar la opción de la Videoteca interval = int(serie.active) # Podria ser del tipo bool if not serie.active: # si la serie no esta activa descartar if overwrite_forced == False: #Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa, aunque la serie esté desactivada try: if config.is_xbmc(): #Si es Kodi, lo hacemos from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_content_as_watched_on_alfa( path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) continue # obtenemos las fecha de actualizacion y de la proxima programada para esta serie update_next = serie.update_next if update_next: y, m, d = update_next.split('-') update_next = datetime.date(int(y), int(m), int(d)) else: update_next = hoy update_last = serie.update_last if update_last: y, m, d = update_last.split('-') update_last = datetime.date(int(y), int(m), int(d)) else: update_last = hoy # si la serie esta activa ... if overwrite or config.get_setting( "updatetvshows_interval", "videolibrary") == 0: # ... forzar actualizacion independientemente del intervalo serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next = hoy + datetime.timedelta( days=interval) elif interval == 1 and update_next <= hoy: # ...actualizacion diaria serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada and update_last <= hoy - datetime.timedelta( days=7): # si hace una semana q no se actualiza, pasar el intervalo a semanal interval = 7 update_next = hoy + datetime.timedelta( days=interval) elif interval == 7 and update_next <= hoy: # ...actualizacion semanal serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: if update_last <= hoy - datetime.timedelta( days=14): # si hace 2 semanas q no se actualiza, pasar el intervalo a mensual interval = 30 update_next += datetime.timedelta(days=interval) elif interval == 30 and update_next <= hoy: # ...actualizacion mensual serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next += datetime.timedelta(days=interval) if serie_actualizada: update_last = hoy update_next = hoy + datetime.timedelta(days=interval) head_nfo, serie = videolibrarytools.read_nfo( tvshow_file ) #Vuelve a leer el.nfo, que ha sido modificado if interval != int(serie.active) or update_next.strftime( '%Y-%m-%d' ) != serie.update_next or update_last.strftime( '%Y-%m-%d') != serie.update_last: serie.update_last = update_last.strftime('%Y-%m-%d') if update_next > hoy: serie.update_next = update_next.strftime( '%Y-%m-%d') if serie.infoLabels[ "status"] != "Ended" and serie.infoLabels[ "status"] != "Canceled": serie.active = interval serie.channel = "videolibrary" serie.action = "get_seasons" filetools.write(tvshow_file, head_nfo + serie.tojson()) if serie_actualizada: if config.get_setting("search_new_content", "videolibrary") == 0: # Actualizamos la videoteca de Kodi: Buscar contenido en la carpeta de la serie if config.is_xbmc(): from platformcode import xbmc_videolibrary xbmc_videolibrary.update( folder=filetools.basename(path)) else: update_when_finished = True except Exception as ex: logger.error( "Se ha producido un error al actualizar la serie %s" % tvshow_file) template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) if estado_verify_playcount_series: #Si se ha cambiado algún playcount, ... estado = config.set_setting( "verify_playcount", True, "videolibrary" ) #... actualizamos la opción de Videolibrary if config.get_setting( "search_new_content", "videolibrary") == 1 and update_when_finished: # Actualizamos la videoteca de Kodi: Buscar contenido en todas las series if config.is_xbmc(): from platformcode import xbmc_videolibrary xbmc_videolibrary.update() p_dialog.close() else: logger.info( "No actualiza la videoteca, está desactivado en la configuración de alfa" ) except Exception as ex: logger.error("Se ha producido un error al actualizar las series") template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) if p_dialog: p_dialog.close() from core.item import Item item_dummy = Item() videolibrary.list_movies(item_dummy, silent=True)
def update(path, p_dialog, i, t, serie, overwrite): logger.debug("Updating " + path) insertados_total = 0 nfo_file = xbmc.translatePath(filetools.join(path, 'tvshow.nfo')) head_nfo, it = videolibrarytools.read_nfo(nfo_file) videolibrarytools.update_renumber_options(it, head_nfo, path) if not serie.library_url: serie = it category = serie.category # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in serie.library_urls.items(): serie.channel = channel module = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) url = module.host + urlsplit(url).path serie.url = url ###### Redirection to the NewPct1.py channel if it is a clone, or to another channel and url if there has been judicial intervention try: head_nfo, it = videolibrarytools.read_nfo( nfo_file) # Refresh the .nfo to collect updates if it.emergency_urls: serie.emergency_urls = it.emergency_urls serie.category = category except: logger.error(traceback.format_exc()) channel_enabled = channeltools.is_enabled(serie.channel) if channel_enabled: heading = config.get_localized_string(20000) p_dialog.update( int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (serie.contentSerieName, serie.channel.capitalize())) try: pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py') logger.debug("loading channel: " + pathchannels + " " + serie.channel) if serie.library_filter_show: serie.show = serie.library_filter_show.get( serie.channel, serie.contentSerieName) obj = __import__('channels.%s' % serie.channel, fromlist=[pathchannels]) itemlist = obj.episodios(serie) try: if int(overwrite) == 3: # Overwrite all files (tvshow.nfo, 1x01.nfo, 1x01 [channel] .json, 1x01.strm, etc ...) insertados, sobreescritos, fallidos, notusedpath = videolibrarytools.save_tvshow( serie, itemlist) #serie= videolibrary.check_season_playcount(serie, serie.contentSeason) #if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()): # 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 filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()): # serie.infoLabels['playcount'] = serie.playcount insertados_total += insertados except Exception as ex: logger.error( "Error when saving the chapters of the series") template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) except Exception as ex: logger.error("Error in obtaining the episodes of: %s" % serie.show) template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) else: logger.debug("Channel %s not active is not updated" % serie.channel) # Synchronize the episodes seen from the Kodi video library with that of KoD try: if config.is_xbmc(): # If it's Kodi, we do it from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_content_as_watched_on_kod( filetools.join(path, 'tvshow.nfo')) except: logger.error(traceback.format_exc()) return insertados_total > 0
def imagepath(image): if len(image.split('.')) == 1: image += '.png' path = filetools.join(config.get_runtime_path(), 'resources', 'skins', 'Default', 'media', 'Infoplus', image) return path
def series(item): logger.info() itemlist = [] # Obtenemos todos los tvshow.nfo de la biblioteca de SERIES recursivamente for raiz, subcarpetas, ficheros in filetools.walk(library.TVSHOWS_PATH): for f in ficheros: if f == "tvshow.nfo": tvshow_path = filetools.join(raiz, f) # logger.debug(tvshow_path) head_nfo, item_tvshow = library.read_nfo(tvshow_path) item_tvshow.title = item_tvshow.contentTitle item_tvshow.path = raiz item_tvshow.nfo = tvshow_path # Menu contextual: Marcar como visto/no visto visto = item_tvshow.library_playcounts.get( item_tvshow.contentTitle, 0) item_tvshow.infoLabels["playcount"] = visto if visto > 0: texto_visto = "Marcar serie como no vista" contador = 0 else: texto_visto = "Marcar serie como vista" contador = 1 # Menu contextual: Buscar automáticamente nuevos episodios o no if item_tvshow.active and int(item_tvshow.active) > 0: texto_update = "Buscar automáticamente nuevos episodios: Desactivar" value = 0 item_tvshow.text_color = "green" else: texto_update = "Buscar automáticamente nuevos episodios: Activar" value = 1 item_tvshow.text_color = "0xFFDF7401" # Menu contextual: Eliminar serie/canal num_canales = len(item_tvshow.library_urls) if "descargas" in item_tvshow.library_urls: num_canales -= 1 if num_canales > 1: texto_eliminar = "Eliminar serie/canal" multicanal = True else: texto_eliminar = "Eliminar esta serie" multicanal = False item_tvshow.context = [{ "title": texto_visto, "action": "mark_content_as_watched", "channel": "biblioteca", "playcount": contador }, { "title": texto_update, "action": "mark_tvshow_as_updatable", "channel": "biblioteca", "active": value }, { "title": texto_eliminar, "action": "eliminar", "channel": "biblioteca", "multicanal": multicanal }, { "title": "Buscar nuevos episodios ahora", "action": "update_serie", "channel": "biblioteca" }] # ,{"title": "Cambiar contenido (PENDIENTE)", # "action": "", # "channel": "biblioteca"}] # logger.debug("item_tvshow:\n" + item_tvshow.tostring('\n')) itemlist.append(item_tvshow) if itemlist: itemlist = sorted(itemlist, key=lambda it: it.title.lower()) itemlist.append( Item(channel=item.channel, action="update_biblio", thumbnail=item.thumbnail, title="Buscar nuevos episodios y actualizar biblioteca", folder=False)) return itemlist
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]