def episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title item.extra2 = 'xyz' del item.extra2 #Limpiamos num. Temporada y Episodio que ha podido quedar por Novedades season_display = 0 if item.contentSeason: if item.season_colapse: #Si viene del menú de Temporadas... season_display = item.contentSeason #... salvamos el num de sesión a pintar item.from_num_season_colapse = season_display del item.season_colapse item.contentType = "tvshow" if item.from_title_season_colapse: item.title = item.from_title_season_colapse del item.from_title_season_colapse if item.infoLabels['title']: del item.infoLabels['title'] del item.infoLabels['season'] if item.contentEpisodeNumber: del item.infoLabels['episode'] if season_display == 0 and item.from_num_season_colapse: season_display = item.from_num_season_colapse # Obtener la información actualizada de la Serie. TMDB es imprescindible para Videoteca #if not item.infoLabels['tmdb_id']: try: tmdb.set_infoLabels(item, True) #TMDB de cada Temp except: pass # Descarga la página data = '' #Inserto en num de página en la url try: data = httptools.downloadpage(item.url, timeout=timeout).data if not PY3: data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: #Algún error de proceso, salimos pass if not data: logger.error( "ERROR 01: EPISODIOS: La Web no responde o la URL es erronea" + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log' )) return itemlist #Buscamos los episodios matches = jsontools.load(data) if not matches: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_episodios( item, itemlist) #Llamamos al método para el pintado del error return itemlist #Salimos logger.error( "ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug(matches) # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for temporada in matches.get("temporadas", []): if season_display > 0 and temporada.get( "numerotemporada", 0) != season_display: #si no es nuestra temp., pasamos continue #Si hay más de una temporada, solo las enumeramos if len(matches.get("temporadas", [])) > 1 and item.season_colapse: item_local = item.clone() #creo una copia de Item item_local.action = "findvideos" #y lo preparo para la reproducción item_local.contentType = "episode" item_local.extra = "episodios" item_local.contentSeason = temporada.get( "numerotemporada", 1) #Guardo el num. de temporada item_local.contentEpisodeNumber = 1 #relleno el num. de episodio por compatibilidad itemlist.append(item_local.clone()) #lo pinto continue #Paso a la siguiente temporada #Aquí tratamos todos los episodios de una temporada season = temporada.get("numerotemporada", 1) for episodio in temporada.get("capituls", []): item_local = item.clone() #creo una copia de Item item_local.action = "findvideos" #y lo preparo para la reproducción item_local.contentType = "episode" item_local.extra = "episodios" if item_local.library_playcounts: del item_local.library_playcounts if item_local.library_urls: del item_local.library_urls if item_local.path: del item_local.path if item_local.update_last: del item_local.update_last if item_local.update_next: del item_local.update_next if item_local.channel_host: del item_local.channel_host if item_local.active: del item_local.active if item_local.contentTitle: del item_local.infoLabels['title'] if item_local.season_colapse: del item_local.season_colapse if item_local.tmdb_stat: del item_local.tmdb_stat item_local.title = '' item_local.context = "['buscar_trailer']" title = episodio.get("nomcapitul", "") #título del episodio info_epi = episodio.get("infocapitul", "") #información adicional del episodio item_local.language = [] item_local.url = [] if episodio.get("links", {}).get("magnet"): #buscamos los magnets activos url = episodio.get("links", {}).get("magnet") #salvamos el magnet quality = episodio.get("links", {}).get( "calitat", "") #salvamos la calidad del magnet item_local.url += [(url, quality) ] #guardamos todo como url para findvideos item_local.quality = quality.strip( ) #agregamos a la calidad del título if not item_local.language: item_local.language += ['CAST'] #Castellano por defecto #Buscamos la Temporada y el Episodio try: item_local.contentSeason = int( season) #Copiamos el num. de Temporada except: item_local.contentSeason = 1 #Si hay error, lo dejamos en 1 try: item_local.contentEpisodeNumber = int( episodio.get("numerocapitul", 1)) #Copiamos el num. de Episodio except: item_local.contentEpisodeNumber = 1 #Si hay error, lo dejamos en 1 if 'miniserie' in title.lower( ): #Si es una Miniserie, lo ajustamos if not item_local.contentSeason: item_local.contentSeason = 1 title = title.replace('miniserie', '').replace('MiniSerie', '') #Si son episodios múltiples, lo extraemos patron1 = '\d+[x|X]\d{1,2}.?(?:y|Y|al|Al)?.?(?:(?:\d+[x|X])?(\d{1,2}))?' epi_rango = scrapertools.find_single_match(info_epi, patron1) if epi_rango: item_local.infoLabels['episodio_titulo'] = 'al %s ' % epi_rango item_local.title = '%sx%s al %s -' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2), str(epi_rango).zfill(2)) else: item_local.title = '%sx%s -' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) item.infoLabels['episodio_titulo'] = '%s' % title itemlist.append(item_local.clone()) #logger.debug(item_local) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber) )) #clasificamos if item.season_colapse and not item.add_videolibrary: #Si viene de listado, mostramos solo Temporadas item, itemlist = generictools.post_tmdb_seasons(item, itemlist) if not item.season_colapse: #Si no es pantalla de Temporadas, pintamos todo # Pasada por TMDB y clasificación de lista por temporada y episodio tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_episodios(item, itemlist) #logger.debug(item) return itemlist
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 if config.is_xbmc(): from platformcode import xbmc_videolibrary 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 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 and not config.get_setting( 'cleanlibrary', 'videolibrary', default=False): 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(): xbmc_videolibrary.update( folder=filetools.basename(path)) update_when_finished = True 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) logger.error(traceback.format_exc(1)) 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: if config.is_xbmc() and config.get_setting( 'cleanlibrary', 'videolibrary', default=False): while xbmc.getCondVisibility( 'Library.IsScanningVideo()'): # Se espera a que acabe time.sleep(1) xbmc.executebuiltin('CleanLibrary(video)') while xbmc.getCondVisibility( 'Library.IsScanningVideo()'): # Se espera a que acabe time.sleep(1) update_when_finished = True config.set_setting('cleanlibrary', False, 'videolibrary') if update_when_finished: # Actualizamos la videoteca de Kodi: Buscar contenido en todas las series if config.is_xbmc(): 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() # Sincroniza los "vistos" de la Videoteca de Películas from core.item import Item item_dummy = Item() videolibrary.list_movies(item_dummy, silent=True) # Descarga los últimos episodios disponibles, si el canal lo permite from channels import downloads downloads.download_auto(item_dummy)
def find_and_set_infoLabels(item): """ función que se llama para buscar y setear los infolabels :param item: :return: boleano que indica si se ha podido encontrar el 'code' """ global scraper scraper = None # logger.debug("item:\n" + item.tostring('\n')) list_opciones_cuadro = [config.get_localized_string(60223), config.get_localized_string(60224)] # Si se añaden más scrapers hay q declararlos aqui-> "modulo_scraper": "Texto_en_cuadro" scrapers_disponibles = {'tmdb': config.get_localized_string(60225), 'tvdb': config.get_localized_string(60226)} # Obtener el Scraper por defecto de la configuracion segun el tipo de contenido if item.contentType == "movie": scraper_actual = ['tmdb'][config.get_setting("scraper_movies", "videolibrary")] tipo_contenido = config.get_localized_string(70283) title = item.contentTitle # Completar lista de opciones para este tipo de contenido list_opciones_cuadro.append(scrapers_disponibles['tmdb']) else: scraper_actual = ['tmdb', 'tvdb'][config.get_setting("scraper_tvshows", "videolibrary")] tipo_contenido = "serie" title = item.contentSerieName # Completar lista de opciones para este tipo de contenido list_opciones_cuadro.append(scrapers_disponibles['tmdb']) list_opciones_cuadro.append(scrapers_disponibles['tvdb']) # Importamos el scraper try: scraper = __import__('core.%s' % scraper_actual, fromlist=["core.%s" % scraper_actual]) except ImportError: exec("import core." + scraper_actual + " as scraper") except: import traceback logger.error(traceback.format_exc()) while scraper: # Llamamos a la funcion find_and_set_infoLabels del scraper seleccionado scraper_result = scraper.find_and_set_infoLabels(item) # Verificar si existe 'code' if scraper_result and item.infoLabels['code']: # code correcto logger.info("Identificador encontrado: %s" % item.infoLabels['code']) scraper.completar_codigos(item) return True elif scraper_result: # Contenido encontrado pero no hay 'code' msg = config.get_localized_string(60227) % title else: # Contenido no encontrado msg = config.get_localized_string(60228) % title logger.info(msg) # Mostrar cuadro con otras opciones: if scrapers_disponibles[scraper_actual] in list_opciones_cuadro: list_opciones_cuadro.remove(scrapers_disponibles[scraper_actual]) index = platformtools.dialog_select(msg, list_opciones_cuadro) if index < 0: logger.debug("Se ha pulsado 'cancelar' en la ventana '%s'" % msg) return False elif index == 0: # Pregunta el titulo title = platformtools.dialog_input(title, config.get_localized_string(60229) % tipo_contenido) if title: if item.contentType == "movie": item.contentTitle = title else: item.contentSerieName = title else: logger.debug("he pulsado 'cancelar' en la ventana 'Introduzca el nombre correcto'") return False elif index == 1: # Hay q crear un cuadro de dialogo para introducir los datos logger.info("Completar información") if cuadro_completar(item): # code correcto logger.info("Identificador encontrado: %s" % str(item.infoLabels['code'])) return True # raise elif list_opciones_cuadro[index] in list(scrapers_disponibles.values()): # Obtener el nombre del modulo del scraper for k, v in list(scrapers_disponibles.items()): if list_opciones_cuadro[index] == v: if scrapers_disponibles[scraper_actual] not in list_opciones_cuadro: list_opciones_cuadro.append(scrapers_disponibles[scraper_actual]) # Importamos el scraper k scraper_actual = k try: scraper = None scraper = __import__('core.%s' % scraper_actual, fromlist=["core.%s" % scraper_actual]) except ImportError: exec("import core." + scraper_actual + " as scraper_module") break logger.error("Error al importar el modulo scraper %s" % scraper_actual)
def update_external_addon(addon_name): logger.info(addon_name) try: #Verificamos que el addon está instalado if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name): #Path de actualizaciones de Alfa alfa_addon_updates_mig = filetools.join(config.get_runtime_path(), "lib") alfa_addon_updates = filetools.join(alfa_addon_updates_mig, addon_name) #Path de destino en addon externo __settings__ = xbmcaddon.Addon(id="plugin.video." + addon_name) if addon_name.lower() in ['quasar', 'elementum']: addon_path_mig = filetools.join(xbmc.translatePath(__settings__.getAddonInfo('Path')), \ filetools.join("resources", "site-packages")) addon_path = filetools.join(addon_path_mig, addon_name) else: addon_path_mig = '' addon_path = '' #Hay modificaciones en Alfa? Las copiamos al addon, incuidas las carpetas de migración a PY3 if filetools.exists(alfa_addon_updates) and filetools.exists( addon_path): for root, folders, files in filetools.walk( alfa_addon_updates_mig): if ('future' in root or 'past' in root) and not 'concurrent' in root: for file in files: alfa_addon_updates_mig_folder = root.replace( alfa_addon_updates_mig, addon_path_mig) if not filetools.exists( alfa_addon_updates_mig_folder): filetools.mkdir(alfa_addon_updates_mig_folder) if file.endswith('.pyo') or file.endswith('.pyd'): continue input_file = filetools.join(root, file) output_file = input_file.replace( alfa_addon_updates_mig, addon_path_mig) if not filetools.copy( input_file, output_file, silent=True): logger.error( 'Error en la copia de MIGRACIÓN: Input: %s o Output: %s' % (input_file, output_file)) return False for root, folders, files in filetools.walk(alfa_addon_updates): for file in files: input_file = filetools.join(root, file) output_file = input_file.replace( alfa_addon_updates, addon_path) if not filetools.copy( input_file, output_file, silent=True): logger.error( 'Error en la copia: Input: %s o Output: %s' % (input_file, output_file)) return False return True else: logger.error('Alguna carpeta no existe: Alfa: %s o %s: %s' % (alfa_addon_updates, addon_name, addon_path)) # Se ha desinstalado Quasar, reseteamos la opción else: config.set_setting('addon_quasar_update', False) if filetools.exists( filetools.join(config.get_data_path(), "%s.json" % addon_name)): filetools.remove( filetools.join(config.get_data_path(), "%s.json" % addon_name)) return True except: logger.error(traceback.format_exc()) return False
def init(): logger.info() """ Todo el código añadido al add-on se borra con cada actualización. Esta función permite restaurarlo automáticamente con cada actualización. Esto permite al usuario tener su propio código, bajo su responsabilidad, y restaurarlo al add-on cada vez que se actualiza. El mecanismo funciona copiando el contenido de la carpeta-arbol "./userdata/addon_data/plugin.video.alfa/custom_code/..." sobre las carpetas de código del add-on. No verifica el contenido, solo vuelca(reemplaza) el contenido de "custom_code". El usuario almacenará en las subcarpetas de "custom_code" su código actualizado y listo para ser copiado en cualquier momento. Si no se desea que copie algo, simplemente se borra de "custom_code" y ya no se copiará en la próxima actualización. Los pasos que sigue esta función, son los siguientes: 1.- La función se llama desde videolibrary_service.py, desde la función inicial: # Copia Custom code a las carpetas de Alfa desde la zona de Userdata from platformcode import custom_code custom_code.init() 2.- En el inicio de Kodi, comprueba si existe la carpeta "custom_code" en "./userdata/addon_data/plugin.video.alfa/". Si no existe, la crea y sale sin más, dando al ususario la posibilidad de copiar sobre esa estructura su código, y que la función la vuelque sobre el add-on en el próximo inicio de Kodi. 3.- En el siguiente inicio de Kodi, comprueba si existe el custom_code.json en la carpeta root del add-on. Si no existe, lo crea con el número de versión del add-on vacío, para permitir que se copien los archivos en esta pasada. 4.- Verifica que el número de versión del add-on es diferente de el de custom_code.json. Si es la misma versión, se sale porque ya se realizo la copia anteriormente. Si la versión es distinta, se realiza el volcado de todos los archivos de la carpeta-árbol "custom_code" sobre el add-on. Si la carpeta de destino no existe, dará un error y se cancelará la copia. Se considera que no tienen sentido nuevas carpetas. 5.- Si la copia ha terminado con éxito, se actualiza el custom_code.json con el número de versión del add-on, para que en inicios sucesivos de Kodi no se realicen las copias, hasta que el add-on cambie de versión. En el número de versión del add-on no se considera el número de fix. Tiempos: Copiando 7 archivos de prueba, el proceso ha tardado una décima de segundo. """ try: #Borra el .zip de instalación de Alfa de la carpeta Packages, por si está corrupto, y que así se pueda descargar de nuevo version = 'plugin.video.alfa-%s.zip' % config.get_addon_version( with_fix=False) filetools.remove( filetools.join(xbmc.translatePath('special://home'), 'addons', 'packages', version), True) #Verifica si Kodi tiene algún achivo de Base de Datos de Vídeo de versiones anteriores, entonces los borra verify_Kodi_video_DB() #LIBTORRENT: se descarga el binario de Libtorrent cada vez que se actualiza Alfa try: threading.Thread(target=update_libtorrent).start( ) # Creamos un Thread independiente, hasta el fin de Kodi time.sleep(2) # Dejamos terminar la inicialización... except: # Si hay problemas de threading, nos vamos logger.error(traceback.format_exc()) #QUASAR: Preguntamos si se hacen modificaciones a Quasar if not filetools.exists(filetools.join(config.get_data_path(), "quasar.json")) \ and not config.get_setting('addon_quasar_update', default=False): question_update_external_addon("quasar") #QUASAR: Hacemos las modificaciones a Quasar, si está permitido, y si está instalado if config.get_setting('addon_quasar_update', default=False) or \ (filetools.exists(filetools.join(config.get_data_path(), \ "quasar.json")) and not xbmc.getCondVisibility('System.HasAddon("plugin.video.quasar")')): if not update_external_addon("quasar"): platformtools.dialog_notification( "Actualización Quasar", "Ha fallado. Consulte el log") #Existe carpeta "custom_code" ? Si no existe se crea y se sale custom_code_dir = filetools.join(config.get_data_path(), 'custom_code') if not filetools.exists(custom_code_dir): create_folder_structure(custom_code_dir) return else: #Existe "custom_code.json" ? Si no existe se crea custom_code_json_path = config.get_runtime_path() custom_code_json = filetools.join(custom_code_json_path, 'custom_code.json') if not filetools.exists(custom_code_json): create_json(custom_code_json_path) #Se verifica si la versión del .json y del add-on son iguales. Si es así se sale. Si no se copia "custom_code" al add-on verify_copy_folders(custom_code_dir, custom_code_json_path) except: logger.error(traceback.format_exc())
def update(path, p_dialog, i, t, serie, overwrite): logger.info("Actualizando " + path) insertados_total = 0 head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in 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: serie, it, overwrite = generictools.redirect_clone_newpct1(serie, head_nfo, it, path, overwrite) except: pass channel_enabled = channeltools.is_enabled(serie.channel) if channel_enabled: heading = config.get_localized_string(60389) p_dialog.update(int(math.ceil((i + 1) * t)), heading, "%s: %s" % (serie.contentSerieName, serie.channel.capitalize())) try: pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py') logger.info("Cargando canal: " + pathchannels + " " + serie.channel) if serie.library_filter_show: serie.show = serie.library_filter_show.get(serie.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, 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, 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, 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) else: logger.debug("Canal %s no activo no se actualiza" % serie.channel)
def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialogo=False): """ Función para obtener la url real del vídeo @param server: Servidor donde está alojado el vídeo @type server: str @param url: url del vídeo @type url: str @param video_password: Password para el vídeo @type video_password: str @param muestra_dialogo: Muestra el diálogo de progreso @type muestra_dialogo: bool @return: devuelve la url del video @rtype: list """ logger.info("Server: %s, Url: %s" % (server, url)) server = server.lower() video_urls = [] video_exists = True error_messages = [] opciones = [] # Si el vídeo es "directo" o "local", no hay que buscar más if server=="directo" or server=="local": logger.info("Server: %s, la url es la buena" % server) video_urls.append([ "%s [%s]" % (urlparse.urlparse(url)[2][-4:], server) , url ]) # Averigua la URL del vídeo else: if server: server_parameters = get_server_parameters(server) else: server_parameters = {} if server_parameters: # Muestra un diágo de progreso if muestra_dialogo: progreso = platformtools.dialog_progress("streamondemand", "Connessione con %s" % server_parameters["name"]) #Cuenta las opciones disponibles, para calcular el porcentaje orden = [["free"] + [server] + [premium for premium in server_parameters["premium"] if not premium == server], [server] + [premium for premium in server_parameters["premium"] if not premium == server] + ["free"], [premium for premium in server_parameters["premium"] if not premium == server] + [server] + ["free"] ] if server_parameters["free"] == "true": opciones.append("free") opciones.extend([premium for premium in server_parameters["premium"] if config.get_setting("premium",server=premium)]) priority = int(config.get_setting("resolve_priority")) opciones = sorted(opciones, key=lambda x: orden[priority].index(x)) logger.info("Opciones disponibles: %s | %s" % (len(opciones), opciones)) else: logger.error("No existe conector para el servidor %s" % server) error_messages.append("Non esiste alcuna connessione per il server %s" % server) muestra_dialogo = False #Importa el server try: server_module = __import__('servers.%s' % server, None, None, ["servers.%s" % server]) logger.info("Servidor importado: %s" % server_module) except: server_module = None logger.error("No se ha podido importar el servidor: %s" % server) import traceback logger.error(traceback.format_exc()) # Si tiene una función para ver si el vídeo existe, lo comprueba ahora if hasattr(server_module, 'test_video_exists'): logger.info("Invocando a %s.test_video_exists" % server) try: video_exists, message = server_module.test_video_exists(page_url=url) if not video_exists: error_messages.append(message) logger.info("test_video_exists dice que el video no existe") else: logger.info("test_video_exists dice que el video SI existe") except: logger.error("No se ha podido comprobar si el video existe") import traceback logger.error(traceback.format_exc()) #Si el video existe y el modo free está disponible, obtenemos la url if video_exists: for opcion in opciones: #Opcion free y premium propio usa el mismo server if opcion == "free" or opcion == server: serverid = server_module server_name = server_parameters["name"] #Resto de opciones premium usa un debrider else: serverid = __import__('servers.debriders.%s' % opcion, None, None, ["servers.debriders.%s" % opcion]) server_name = get_server_parameters(opcion)["name"] #Muestra el progreso if muestra_dialogo: progreso.update((100 / len(opciones)) * opciones.index(opcion) , "Connessione con %s" % server_name) #Modo free if opcion == "free": try: logger.info("Invocando a %s.get_video_url" % server) response = serverid.get_video_url(page_url=url, video_password=video_password) if response: save_server_stats({server: "sucess"}, "resolve") video_urls.extend(response) except: save_server_stats({server: "error"}, "resolve") logger.error("Error al obrener la url en modo free") error_messages.append("Si è verificato un errore in %s" % server_name) import traceback logger.error(traceback.format_exc()) #Modo premium else: try: logger.info("Invocando a %s.get_video_url" % opcion) response = serverid.get_video_url(page_url=url, premium=True, user=config.get_setting("user", server=opcion), password=config.get_setting("password", server=opcion), video_password=video_password) if response and response[0][1]: if opcion == server: save_server_stats({server: "sucess"}, "resolve") video_urls.extend(response) elif response and response[0][0]: error_messages.append(response[0][0]) else: error_messages.append("Si è verificato un errore in %s" % server_name) except: if opcion == server: save_server_stats({server: "error"}, "resolve") logger.error("Error en el servidor: %s" % opcion) error_messages.append("Si è verificato un errore in %s" % server_name) import traceback logger.error(traceback.format_exc()) #Si ya tenemos URLS, dejamos de buscar if video_urls and config.get_setting("resolve_stop") == True: break #Cerramos el progreso if muestra_dialogo: progreso.update( 100 , "Proceso finalizado") progreso.close() #Si no hay opciones disponibles mostramos el aviso de las cuentas premium if video_exists and not opciones and server_parameters.get("premium"): listapremium = [get_server_parameters(premium)["name"] for premium in server_parameters["premium"]] error_messages.append("Para ver un vídeo en %s necesitas<br/>una cuenta en: %s" % (server, " o ".join(listapremium))) #Si no tenemos urls ni mensaje de error, ponemos uno generico elif not video_urls and not error_messages: error_messages.append("Si è verificato un errore in %s" % get_server_parameters(server)["name"]) return video_urls, len(video_urls) > 0, "<br/>".join(error_messages)
def submenu(item): logger.info() itemlist = [] item.filter_lang = True data = '' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) except: pass if not data: logger.error( "ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log' )) return itemlist #Algo no funciona, pintamos lo que tenemos patron = '<div class="cab_menu"\s*>.*?<\/div>' #Menú principal data1 = scrapertools.find_single_match(data, patron) patron = '<div id="menu_langen"\s*>.*?<\/div>' #Menú de idiomas data1 += scrapertools.find_single_match(data, patron) patron = '<a href="(.*?)".*?title="(.*?)"' #Encontrar todos los apartados matches = re.compile(patron, re.DOTALL).findall(data1) if not matches: item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente for clone_inter, autoridad in item.intervencion: thumb_intervenido = get_thumb(autoridad) itemlist.append( item.clone(action='', title="[COLOR yellow]" + clone_inter.capitalize() + ': [/COLOR]' + intervenido_judicial + '. Reportar el problema en el foro', thumbnail=thumb_intervenido)) return itemlist #Salimos logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data1) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: if PY3: scrapedtitle = re.sub('\r\n', '', scrapedtitle).strip() else: scrapedtitle = re.sub('\r\n', '', scrapedtitle).decode('utf8').strip() scrapedtitle = scrapedtitle.replace(" torrent", "").replace( " Torrent", "").replace("Series y ", "").title() if "castellano" in scrapedtitle.lower( ): #Evita la entrada de peliculas castellano del menú de idiomas continue if item.extra == "series": #Tratamos Series if not "/serie" in scrapedurl: continue else: #Tratamos Películas if "/serie" in scrapedurl: continue if 'subtitulado' in scrapedtitle.lower( ) or 'latino' in scrapedtitle.lower( ) or 'original' in scrapedtitle.lower(): item.filter_lang = False itemlist.append( item.clone(action="listado", title=scrapedtitle, url=scrapedurl)) if item.extra == "series": #Añadimos Series VOSE que está fuera del menú principal itemlist.append( item.clone(action="listado", title="Series VOSE", url=host + "/series-vose/", filter_lang=False)) return itemlist
def listado(item): logger.info() itemlist = [] inicio = time.time( ) # Controlaremos que el proceso no exceda de un tiempo razonable fin = inicio + 5 # Después de este tiempo pintamos (segundos) timeout_search = timeout # Timeout para descargas if item.extra == 'search': timeout_search = timeout * 2 # Timeout un poco más largo para las búsquedas if timeout_search < 5: timeout_search = 5 # Timeout un poco más largo para las búsquedas # Descarga la página data = '' try: data = re.sub( r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout_search).data) except: pass if not data: #Si la web está caída salimos sin dar error logger.error( "ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos patron = '<div id="principal">.*?<\/nav><\/div><\/div>' data = scrapertools.find_single_match(data, patron) patron = '<li>\s*<div\s*class="[^"]+">\s*<a href="([^"]+)"\s*' #url patron += 'title="([^"]+)"\s*(?:alt="[^"]+")?\s*>\s*' #título patron += '<img (?:class="[^"]+")?\s*src="([^"]+)".*?border="[^"]+"\s*' #thumb patron += 'title="([^"]+)".*?' #categoría patron += '<span class="[^"]+"\s*id="[^"]+">\s*<i>\s*' patron += "<img src='[^']+'\s*data-src='[^']+\/(\w+).png'.*?" #idioma patron += '<span class="[^"]+" style="[^"]+"\s*><i>(.*?)?<\/i>' #calidad patron += '(?:<\/span.*?="dig1">(.*?)?)?' #tamaño patron += '(?:<.*?="dig2">(.*?)?)?<\/span><\/div>' #tipo tamaño matches = re.compile(patron, re.DOTALL).findall(data) if not matches and not '<title>503 Backend fetch failed</title>' in data and not 'No se han encontrado resultados' in data: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_listado( item, itemlist) #Llamamos al método para el pintado del error return itemlist #Salimos logger.error( "ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedcategory, scrapedlang, \ scrapedcalidad, scrapedsize, scrapedsizet in matches: item_local = item.clone() #Creamos copia de Item para trabajar if PY3: title = re.sub('\r\n', '', scrapedtitle).strip() else: title = re.sub('\r\n', '', scrapedtitle).decode('utf8').strip() title = title.replace(" torrent", "").replace(" Torrent", "").replace("Series y ", "") item_local.url = urlparse.urljoin(host, scrapedurl) item_local.thumbnail = urlparse.urljoin(host, scrapedthumbnail) if "---" in scrapedcalidad: #limpiamos calidades scrapedcalidad = '' if "microhd" in title.lower(): item_local.quality = "microHD" if not "/series-vose/" in item.url and not item_local.quality: item_local.quality = scrapedcalidad if scrapertools.find_single_match(item_local.quality, r'\d+\.\d+'): item_local.quality = '' if not item_local.quality and ( "DVDRip" in title or "HDRip" in title or "BR-LINE" in title or "HDTS-SCREENER" in title or "BDRip" in title or "BR-Screener" in title or "DVDScreener" in title or "TS-Screener" in title): item_local.quality = scrapertools.find_single_match( title, r'\((.*?)\)') item_local.quality = item_local.quality.replace("Latino", "") if not scrapedsizet or "---" in scrapedsizet: scrapedsize = '' else: item_local.quality += ' [%s %s]' % (scrapedsize.replace( ".", ","), scrapedsizet) item_local.language = [ ] #Verificamos el idioma por si encontramos algo if "latino" in scrapedlang.lower( ) or "latino" in item.url or "latino" in title.lower(): item_local.language += ["LAT"] if scrapedlang.lower() in ['vos', 'vose'] or "vose" in item.url or "vos" in item.url \ or "vose" in scrapedurl or "vos" in scrapedurl or "subt" in title.lower(): item_local.language += ["VOSE"] elif scrapedlang.lower() in ['ingles', 'inglés', 'english', 'original', 'vo'] or "ingles" in item.url \ or "vo" in item.url or "ingles" in scrapedurl or "vo" in scrapedurl: item_local.language += ["VO"] if item_local.language == []: item_local.language = ['CAST'] #Por defecto if "dual" in scrapedlang.lower() or "dual" in title.lower(): item_local.language[0:0] = ["DUAL"] #Limpiamos el título de la basura innecesaria title = title.replace("Dual", "").replace("dual", "").replace( "Subtitulada", "").replace("subtitulada", "").replace("Subt", "").replace( "subt", "").replace("Sub", "").replace("sub", "").replace( "(Proper)", "").replace("(proper)", "").replace("Proper", "").replace( "proper", "").replace("#", "").replace("(Latino)", "").replace("Latino", "") title = title.replace("- HDRip", "").replace("(HDRip)", "").replace( "- Hdrip", "").replace("(microHD)", "").replace("(DVDRip)", "").replace( "(HDRip)", "").replace("(BR-LINE)", "").replace( "(HDTS-SCREENER)", "").replace("(BDRip)", "").replace( "(BR-Screener)", "").replace("(DVDScreener)", "").replace( "TS-Screener", "").replace(" TS", "").replace( " Ts", "").replace("temporada", "").replace( "Temporada", "").replace("capitulo", "").replace("Capitulo", "") title = re.sub(r'(?:\d+)?x.?\s?\d+', '', title) title = re.sub(r'\??\s?\d*?\&.*', '', title).title().strip() item_local.from_title = title #Guardamos esta etiqueta para posible desambiguación de título if item_local.extra == "peliculas": #preparamos Item para películas if "/serie" in scrapedurl or "/serie" in item.url: continue if not "/serie" in scrapedurl and not "/serie" in item.url: item_local.contentType = "movie" item_local.contentTitle = title item_local.extra = "peliculas" if item_local.extra == "series": #preparamos Item para series if not "/serie" in scrapedurl and not "/serie" in item.url: continue if "/serie" in scrapedurl or "/serie" in item.url: item_local.contentType = "episode" item_local.extra = "series" epi_mult = scrapertools.find_single_match(item_local.url, r'cap.*?-\d+-al-(\d+)') item_local.contentSeason = scrapertools.find_single_match( item_local.url, r'temporada-(\d+)') item_local.contentEpisodeNumber = scrapertools.find_single_match( item_local.url, r'cap.*?-(\d+)') if not item_local.contentSeason: item_local.contentSeason = scrapertools.find_single_match( item_local.url, r'-(\d+)[x|X]\d+') if not item_local.contentEpisodeNumber: item_local.contentEpisodeNumber = scrapertools.find_single_match( item_local.url, r'-\d+[x|X](\d+)') if not item_local.contentSeason or item_local.contentSeason < 1: item_local.contentSeason = 0 if item_local.contentEpisodeNumber < 1: item_local.contentEpisodeNumber = 1 item_local.contentSerieName = title if epi_mult: title = "%sx%s al %s -" % ( item_local.contentSeason, str(item_local.contentEpisodeNumber).zfill(2), str(epi_mult).zfill(2) ) #Creamos un título con el rango de episodios else: title = '%sx%s ' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) item_local.action = "findvideos" item_local.title = title.strip() item_local.infoLabels['year'] = "-" #Pasamos a TMDB cada Item, para evitar el efecto memoria de tmdb #if item.category: #Si este campo no existe es que viene de la primera pasada de una búsqueda global, pasamos # tmdb.set_infoLabels(item_local, True) #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting( 'filter_languages', channel ) > 0 and item.filter_lang: #Si hay idioma seleccionado, se filtra itemlist = filtertools.get_link(itemlist, item_local, list_language) else: itemlist.append(item_local.clone()) #Si no, pintar pantalla #if not item.category: #Si este campo no existe es que viene de la primera pasada de una búsqueda global # return itemlist #Retornamos sin pasar por la fase de maquillaje para ahorra tiempo #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Extrae el paginador patron = '<div class="paginacion">.*?<span class="pagina pag_actual".*?' patron += "<a href='([^']+)'.*?" #url siguiente página patron += 'class="pagina">(\d+)<' #próxima página matches = scrapertools.find_single_match(data, patron) patron = 'class="pagina pag_sig">Siguiente.*?' patron += "<a href='.*?\/page\/(\d+)\/" #total de páginas last_page = scrapertools.find_single_match(data, patron) if not last_page: patron = '<div class="paginacion">.*?' patron += 'class="pagina">(\d+)<\/a><\/div><\/nav><\/div><\/div>' #total de páginas last_page = scrapertools.find_single_match(data, patron) if matches: scrapedurl = urlparse.urljoin(item.url, matches[0]) if last_page: title = '[COLOR gold]Página siguiente >>[/COLOR] %s de %s' % ( int(matches[1]) - 1, last_page) else: title = '[COLOR gold]Página siguiente >>[/COLOR] %s' % ( int(matches[1]) - 1) itemlist.append( Item(channel=item.channel, action="listado", title=title, url=scrapedurl, extra=item.extra, filter_lang=item.filter_lang)) return itemlist
def findvideos(item): logger.info() itemlist = [] #Bajamos los datos de la página try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) except: logger.error( "ERROR 01: FINDVIDEOS: La Web no responde o la URL es erronea: " + item.url + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #data = unicode(data, "utf-8", errors="replace") #Añadimos el tamaño para todos size = scrapertools.find_single_match(item.quality, '\s\[(\d+,?\d*?\s\w[b|B]s)\]') if size: item.title = re.sub('\s\[\d+,?\d*?\s\w[b|B]s\]', '', item.title) #Quitamos size de título, si lo traía item.title = '%s [%s]' % (item.title, size ) #Agregamos size al final del título item.quality = re.sub( '\s\[\d+,?\d*?\s\w[b|B]s\]', '', item.quality) #Quitamos size de calidad, si lo traía item.quality = '%s [%s]' % (item.quality, size ) #Agregamos size al final de calidad item.quality = item.quality.replace("G", "G ").replace( "M", "M ") #Se evita la palabra reservada en Unify patron_t = '<div class="enlace_descarga".*?<a href="(.*?\.torrent)"' link_torrent = scrapertools.find_single_match(data, patron_t) link_torrent = urlparse.urljoin(item.url, link_torrent) link_torrent = link_torrent.replace( " ", "%20") #sustituimos espacios por %20, por si acaso #logger.info("link Torrent: " + link_torrent) patron_m = '<div class="enlace_descarga".*?<a href="(magnet:?.*?)"' link_magnet = scrapertools.find_single_match(data, patron_m) link_magnet = urlparse.urljoin(item.url, link_magnet) #logger.info("link Magnet: " + link_magnet) if not link_torrent and not link_magnet: #error logger.error( "ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron_t + " / " + patron_m + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() #Ahora pintamos el link del Torrent, si lo hay if link_torrent: # Hay Torrent ? if item_local.quality: item_local.quality += " " item_local.quality += "[Torrent]" item_local.url = link_torrent item_local.title = '[COLOR yellow][?][/COLOR] [COLOR yellow][Torrent][/COLOR] [COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR]' % ( item_local.quality, str( item_local.language)) #Preparamos título de Torrent item_local.title = re.sub(r'\s\[COLOR \w+\]\[\[?\]?\]\[\/COLOR\]', '', item_local.title) #Quitamos etiquetas vacías item_local.title = re.sub(r'\s\[COLOR \w+\]\[\/COLOR\]', '', item_local.title) #Quitamos colores vacíos item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist.append(item_local.clone()) #Pintar pantalla #Ahora pintamos el link del Magnet, si lo hay if link_magnet: # Hay Magnet ? if item_local.quality: item_local.quality += " " item_local.quality = item_local.quality.replace("[Torrent]", "") + "[Magnet]" item_local.url = link_magnet item_local.title = '[COLOR yellow][?][/COLOR] [COLOR yellow][Torrent][/COLOR] [COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR]' % ( item_local.quality, str( item_local.language)) #Preparamos título de Magnet item_local.title = re.sub(r'\s\[COLOR \w+\]\[\[?\]?\]\[\/COLOR\]', '', item_local.title) #Quitamos etiquetas vacías item_local.title = re.sub(r'\s\[COLOR \w+\]\[\/COLOR\]', '', item_local.title) #Quitamos colores vacíos item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist.append(item_local.clone()) #Pintar pantalla #logger.debug("TORRENT: " + link_torrent + "MAGNET: " + link_magnet + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / tamaño: " + size + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) return itemlist
def submenu(item): logger.info() itemlist = [] try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) except: logger.error( "ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log' )) return itemlist #Algo no funciona, pintamos lo que tenemos patron = '<div class="cab_menu">.*?<\/div>' #Menú principal data1 = scrapertools.get_match(data, patron) patron = '<div id="menu_langen">.*?<\/div>' #Menú de idiomas data1 += scrapertools.get_match(data, patron) patron = '<a href="(.*?)".*?title="(.*?)"' #Encontrar todos los apartados matches = re.compile(patron, re.DOTALL).findall(data1) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data1) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: scrapedtitle = re.sub('\r\n', '', scrapedtitle).decode('utf8').strip() scrapedtitle = scrapedtitle.replace(" torrent", "").replace( " Torrent", "").replace("Series y ", "").title() if "castellano" in scrapedtitle.lower( ): #Evita la entrada de peliculas castellano del menú de idiomas continue if item.extra == "series": #Tratamos Series if not "/serie" in scrapedurl: continue else: #Tratamos Películas if "/serie" in scrapedurl: continue itemlist.append( item.clone(action="listado", title=scrapedtitle, url=scrapedurl)) if item.extra == "series": #Añadimos Series VOSE que está fuera del menú principal itemlist.append( item.clone(action="listado", title="Series VOSE", url=host + "/series-vose/")) return itemlist
def listado(item): logger.info() itemlist = [] # Descarga la página try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) except: logger.error( "ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if not data: #Si la web está caída salimos sin dar error logger.error( "ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos patron = '<div id="principal">.*?<\/nav><\/div><\/div>' data = scrapertools.find_single_match(data, patron) patron = '<li>.*?<a href="(.*?)".*?' #url patron += 'title="(.*?)".*?' #título patron += 'src="(.*?)".*?' #thumb patron += "title='(.*?)'.*?" #categoría, idioma patron += '"><i>(.*?)<\/i><\/span.*?' #calidad patron += '="dig1">(.*?)<.*?' #tamaño patron += '="dig2">(.*?)<\/span><\/div>' #tipo tamaño matches = re.compile(patron, re.DOTALL).findall(data) if not matches and not '<title>503 Backend fetch failed</title>' in data: #error logger.error( "ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedcategory, scrapedcalidad, scrapedsize, scrapedsizet in matches: item_local = item.clone() #Creamos copia de Item para trabajar title = re.sub('\r\n', '', scrapedtitle).decode('utf8').strip() title = title.replace(" torrent", "").replace(" Torrent", "").replace("Series y ", "") item_local.url = urlparse.urljoin(host, scrapedurl) item_local.thumbnail = urlparse.urljoin(host, scrapedthumbnail) if "---" in scrapedcalidad: #limpiamos calidades scrapedcalidad = '' if "microhd" in title.lower(): item_local.quality = "microHD" if not "/series-vose/" in item.url and not item_local.quality: item_local.quality = scrapedcalidad if scrapertools.find_single_match(item_local.quality, r'\d+\.\d+'): item_local.quality = '' if not item_local.quality and ( "DVDRip" in title or "HDRip" in title or "BR-LINE" in title or "HDTS-SCREENER" in title or "BDRip" in title or "BR-Screener" in title or "DVDScreener" in title or "TS-Screener" in title): item_local.quality = scrapertools.find_single_match( title, r'\((.*?)\)') item_local.quality = item_local.quality.replace("Latino", "") if not scrapedsizet: scrapedsize = '' else: item_local.quality += ' [%s %s]' % (scrapedsize.replace( ".", ","), scrapedsizet) item_local.language = [ ] #Verificamos el idioma por si encontramos algo if "latino" in scrapedcategory.lower( ) or "latino" in item.url or "latino" in title.lower(): item_local.language += ["LAT"] if "ingles" in scrapedcategory.lower( ) or "ingles" in item.url or "vose" in scrapedurl or "vose" in item.url: if "VOSE" in scrapedcategory.lower() or "sub" in title.lower( ) or "vose" in scrapedurl or "vose" in item.url: item_local.language += ["VOS"] else: item_local.language += ["VO"] if "dual" in scrapedcategory.lower() or "dual" in title.lower(): item_local.language[0:0] = ["DUAL"] #Limpiamos el título de la basuna innecesaria title = title.replace("Dual", "").replace("dual", "").replace( "Subtitulada", "").replace("subtitulada", "").replace("Subt", "").replace( "subt", "").replace("Sub", "").replace("sub", "").replace( "(Proper)", "").replace("(proper)", "").replace("Proper", "").replace( "proper", "").replace("#", "").replace("(Latino)", "").replace("Latino", "") title = title.replace("- HDRip", "").replace("(HDRip)", "").replace( "- Hdrip", "").replace("(microHD)", "").replace("(DVDRip)", "").replace( "(HDRip)", "").replace("(BR-LINE)", "").replace( "(HDTS-SCREENER)", "").replace("(BDRip)", "").replace( "(BR-Screener)", "").replace("(DVDScreener)", "").replace( "TS-Screener", "").replace(" TS", "").replace(" Ts", "") title = re.sub(r'\??\s?\d*?\&.*', '', title).title().strip() if item_local.extra == "peliculas": #preparamos Item para películas if "/serie" in scrapedurl or "/serie" in item.url: continue if not "/serie" in scrapedurl and not "/serie" in item.url: item_local.contentType = "movie" item_local.contentTitle = title item_local.extra = "peliculas" if item_local.extra == "series": #preparamos Item para series if not "/serie" in scrapedurl and not "/serie" in item.url: continue if "/serie" in scrapedurl or "/serie" in item.url: item_local.contentType = "episode" item_local.extra = "series" epi_mult = scrapertools.find_single_match(item_local.url, r'cap.*?-\d+-al-(\d+)') item_local.contentSeason = scrapertools.find_single_match( item_local.url, r'temp.*?-(\d+)') item_local.contentEpisodeNumber = scrapertools.find_single_match( item_local.url, r'cap.*?-(\d+)') if not item_local.contentSeason: item_local.contentSeason = scrapertools.find_single_match( item_local.url, r'-(\d+)[x|X]\d+') if not item_local.contentEpisodeNumber: item_local.contentEpisodeNumber = scrapertools.find_single_match( item_local.url, r'-\d+[x|X](\d+)') if item_local.contentSeason < 1: item_local.contentSeason = 1 if item_local.contentEpisodeNumber < 1: item_local.contentEpisodeNumber = 1 item_local.contentSerieName = title if epi_mult: title = "%sx%s al %s -" % ( item_local.contentSeason, str(item_local.contentEpisodeNumber).zfill(2), str(epi_mult).zfill(2) ) #Creamos un título con el rango de episodios else: title = '%sx%s ' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) item_local.action = "findvideos" item_local.title = title.strip() item_local.infoLabels['year'] = "-" #Pasamos a TMDB cada Item, para evitar el efecto memoria de tmdb if item.category: #Si este campo no existe es que viene de la primera pasada de una búsqueda global, pasamos tmdb.set_infoLabels(item_local, True) itemlist.append(item_local.clone()) #Pintar pantalla #if not item.category: #Si este campo no existe es que viene de la primera pasada de una búsqueda global # return itemlist #Retornamos sin pasar por la fase de maquillaje para ahorra tiempo #Pasamos a TMDB la lista completa Itemlist #tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Extrae el paginador patron = '<div class="paginacion">.*?<span class="pagina pag_actual".*?' patron += "<a href='([^']+)'.*?" #url siguiente página patron += 'class="pagina">(\d+)<' #próxima página matches = scrapertools.find_single_match(data, patron) patron = 'class="pagina pag_sig">Siguiente.*?' patron += "<a href='.*?\/page\/(\d+)\/" #total de páginas last_page = scrapertools.find_single_match(data, patron) if not last_page: patron = '<div class="paginacion">.*?' patron += 'class="pagina">(\d+)<\/a><\/div><\/nav><\/div><\/div>' #total de páginas last_page = scrapertools.find_single_match(data, patron) if matches: scrapedurl = urlparse.urljoin(item.url, matches[0]) if last_page: title = '[COLOR gold]Página siguiente >>[/COLOR] %s de %s' % ( int(matches[1]) - 1, last_page) else: title = '[COLOR gold]Página siguiente >>[/COLOR] %s' % ( int(matches[1]) - 1) itemlist.append( Item(channel=item.channel, action="listado", title=title, url=scrapedurl, extra=item.extra)) 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 os.path.isfile(os.path.join(config.get_runtime_path(), "servers", server + ".json")): path = os.path.join(config.get_runtime_path(), "servers", server + ".json") # Debriders elif os.path.isfile(os.path.join(config.get_runtime_path(), "servers", "debriders", server + ".json")): path = os.path.join(config.get_runtime_path(), "servers", "debriders", server + ".json") import filetools data = filetools.read(path) dict_server = jsontools.load(data) # 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"] = os.path.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 type(dict_server[k]) == str: dict_server[k] = [dict_server[k]] # if not dict_server.has_key(k) or dict_server[k] == "": # dict_server[k] = [] # elif type(dict_server[k]) == dict: # dict_server[k] = dict_server[k]["value"] # if type(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 = "Error al cargar el servidor: %s\n" % server import traceback logger.error(mensaje + traceback.format_exc()) return {} return dict_servers_parameters[server]
def do_search(item, categories=None): logger.info("blaa categorias %s" % categories) if categories is None: categories = [] multithread = config.get_setting("multithread", "search") result_mode = config.get_setting("result_mode", "search") tecleado = item.extra itemlist = [] channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json') logger.info("channels_path=%s" % channels_path) channel_language = config.get_setting("channel_language") logger.info("channel_language=%s" % channel_language) if channel_language == "": channel_language = "all" logger.info("channel_language=%s" % channel_language) # Para Kodi es necesario esperar antes de cargar el progreso, de lo contrario # el cuadro de progreso queda "detras" del cuadro "cargando..." y no se le puede dar a cancelar time.sleep(0.5) progreso = platformtools.dialog_progress("Buscando '%s'..." % tecleado, "") channel_files = sorted(glob.glob(channels_path), key=lambda x: os.path.basename(x)) import math # fix float porque la division se hace mal en python 2.x number_of_channels = float(100) / len(channel_files) threads = [] search_results = {} start_time = time.time() for index, infile in enumerate(channel_files): try: percentage = int(math.ceil((index + 1) * number_of_channels)) basename = os.path.basename(infile) basename_without_extension = basename[:-5] logger.info("%s..." % basename_without_extension) channel_parameters = channeltools.get_channel_parameters( basename_without_extension) # No busca si es un canal inactivo if not channel_parameters["active"]: logger.info("%s -no activo-" % basename_without_extension) continue # En caso de búsqueda por categorias if categories: # Si no se ha seleccionado torrent no se muestra if "torrent" not in categories: if "torrent" in channel_parameters["categories"]: logger.info("%s -torrent-" % basename_without_extension) continue for cat in categories: if cat not in channel_parameters["categories"]: logger.info("%s -no en %s-" % (basename_without_extension, cat)) continue # No busca si es un canal para adultos, y el modo adulto está desactivado if channel_parameters["adult"] and config.get_setting( "adult_mode") == 0: logger.info("%s -adulto-" % basename_without_extension) continue # No busca si el canal es en un idioma filtrado if channel_language != "all" and channel_parameters[ "language"] != channel_language: logger.info("%s -idioma no válido-" % basename_without_extension) continue # No busca si es un canal excluido de la búsqueda global include_in_global_search = channel_parameters[ "include_in_global_search"] if include_in_global_search: # Buscar en la configuracion del canal include_in_global_search = config.get_setting( "include_in_global_search", basename_without_extension) if not include_in_global_search: logger.info("%s -no incluido en lista a buscar-" % basename_without_extension) continue if progreso.iscanceled(): progreso.close() logger.info("Búsqueda cancelada") return itemlist # Modo Multi Thread if multithread: t = Thread(target=channel_search, args=[search_results, channel_parameters, tecleado], name=channel_parameters["title"]) t.setDaemon(True) t.start() threads.append(t) # Modo single Thread else: logger.info("Intentado búsqueda en %s de %s " % (basename_without_extension, tecleado)) channel_search(search_results, channel_parameters, tecleado) logger.info("%s incluido en la búsqueda" % basename_without_extension) progreso.update(percentage, "Buscando en %s..." % channel_parameters["title"]) except: logger.error("No se puede buscar en: %s" % channel_parameters["title"]) import traceback logger.error(traceback.format_exc()) continue # Modo Multi Thread # Usando isAlive() no es necesario try-except, # ya que esta funcion (a diferencia de is_alive()) # es compatible tanto con versiones antiguas de python como nuevas if multithread: pendent = [a for a in threads if a.isAlive()] t = float(100) / len(pendent) while pendent: index = (len(threads) - len(pendent)) + 1 percentage = int(math.ceil(index * t)) list_pendent_names = [a.getName() for a in pendent] mensaje = "Buscando en %s" % (", ".join(list_pendent_names)) progreso.update( percentage, "Finalizado en %d/%d canales..." % (len(threads) - len(pendent), len(threads)), mensaje) logger.debug(mensaje) if progreso.iscanceled(): logger.info("Búsqueda cancelada") break time.sleep(0.5) pendent = [a for a in threads if a.isAlive()] total = 0 for channel in sorted(search_results.keys()): for element in search_results[channel]: total += len(element["itemlist"]) title = channel # resultados agrupados por canales if result_mode == 0: if len(search_results[channel]) > 1: title += " [%s]" % element["item"].title.strip() title += " (%s)" % len(element["itemlist"]) title = re.sub("\[COLOR [^\]]+\]", "", title) title = re.sub("\[/COLOR]", "", title) itemlist.append( Item(title=title, channel="search", action="show_result", url=element["item"].url, extra=element["item"].extra, folder=True, adult=element["adult"], from_action="search", from_channel=element["item"].channel, tecleado=tecleado)) # todos los resultados juntos, en la misma lista else: title = " [ Resultados del canal %s ] " % channel itemlist.append( Item(title=title, channel="search", action="", folder=False, text_bold=True)) for i in element["itemlist"]: if i.action: title = " " + i.title itemlist.append( i.clone(title=title, from_action=i.action, from_channel=i.channel, channel="search", action="show_result", adult=element["adult"])) title = "Buscando: '%s' | Encontrado: %d vídeos | Tiempo: %2.f segundos" % ( tecleado, total, time.time() - start_time) itemlist.insert(0, Item(title=title, text_color='yellow')) progreso.close() return itemlist
def add_tvshow(item, channel=None): """ Guarda contenido en la libreria de series. Este contenido puede ser uno de estos dos: - La serie con todos los capitulos incluidos en la lista episodelist. - Un solo capitulo descargado previamente en local. Para añadir episodios descargados en local, el item debe tener exclusivamente: - contentSerieName (o show): Titulo de la serie - contentTitle: titulo del episodio para extraer season_and_episode ("1x01 Piloto") - title: titulo a mostrar junto al listado de enlaces -findvideos- ("Reproducir video local") - infoLabels["tmdb_id"] o infoLabels["imdb_id"] - contentType != "movie" - channel = "downloads" - url : ruta local al video @type item: item @param item: item que representa la serie a guardar @type channel: modulo @param channel: canal desde el que se guardara la serie. Por defecto se importara item.from_channel o item.channel """ logger.info("show=#" + item.show + "#") if item.channel == "downloads": itemlist = [item.clone()] else: # Esta marca es porque el item tiene algo más aparte en el atributo "extra" item.action = item.extra if isinstance(item.extra, str) and "###" in item.extra: item.action = item.extra.split("###")[0] item.extra = item.extra.split("###")[1] if item.from_action: item.__dict__["action"] = item.__dict__.pop("from_action") if item.from_channel: item.__dict__["channel"] = item.__dict__.pop("from_channel") if not channel: try: channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel]) except ImportError: exec "import channels." + item.channel + " as channel" #Para desambiguar títulos, se provoca que TMDB pregunte por el título realmente deseado #El usuario puede seleccionar el título entre los ofrecidos en la primera pantalla #o puede cancelar e introducir un nuevo título en la segunda pantalla #Si lo hace en "Introducir otro nombre", TMDB buscará automáticamente el nuevo título #Si lo hace en "Completar Información", cambia parcialmente al nuevo título, pero no busca en TMDB. Hay que hacerlo #Si se cancela la segunda pantalla, la variable "scraper_return" estará en False. El usuario no quiere seguir item = generictools.update_title( item ) #Llamamos al método que actualiza el título con tmdb.find_and_set_infoLabels #if item.tmdb_stat: # del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca # Obtiene el listado de episodios itemlist = getattr(channel, item.action)(item) global magnet_caching magnet_caching = False insertados, sobreescritos, fallidos, path = save_tvshow(item, itemlist) if not insertados and not sobreescritos and not fallidos: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067)) logger.error( "La serie %s no se ha podido añadir a la videoteca. No se ha podido obtener ningun episodio" % item.show) elif fallidos == -1: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068)) logger.error("La serie %s no se ha podido añadir a la videoteca" % item.show) elif fallidos > 0: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60069)) logger.error( "No se han podido añadir %s episodios de la serie %s a la videoteca" % (fallidos, item.show)) else: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070)) logger.info( "Se han añadido %s episodios de la serie %s a la videoteca" % (insertados, item.show)) if config.is_xbmc(): if config.get_setting("sync_trakt_new_tvshow", "videolibrary"): import xbmc from platformcode import xbmc_videolibrary if config.get_setting("sync_trakt_new_tvshow_wait", "videolibrary"): # Comprobar que no se esta buscando contenido en la videoteca de Kodi while xbmc.getCondVisibility('Library.IsScanningVideo()'): xbmc.sleep(1000) # Se lanza la sincronizacion para la videoteca de Kodi xbmc_videolibrary.sync_trakt_kodi() # Se lanza la sincronización para la videoteca del addon xbmc_videolibrary.sync_trakt_addon(path)
def findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if not item.language: item.language = ['CAST'] #Castellano por defecto #Bajamos los datos de la página data = '' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass if not data: logger.error( "ERROR 01: FINDVIDEOS: La Web no responde o la URL es erronea: " + item.url + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log', folder=False)) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? link_torrent = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent link_magnet = item.emergency_urls[1][ 0] #Guardamos la url del .Magnet item.armagedon = True #Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: #Si es llamado desde creación de Videoteca... return item #Devolvemos el Item de la llamada else: return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #data = unicode(data, "utf-8", errors="replace") patron_t = '<div class="enlace_descarga".*?<a href="(.*?\.torrent)"' patron_m = '<div class="enlace_descarga".*?<a href="(magnet:?.*?)"' if not item.armagedon: #Si es un proceso normal, seguimos link_torrent = scrapertools.find_single_match(data, patron_t) link_torrent = urlparse.urljoin(item.url, link_torrent) link_torrent = link_torrent.replace( " ", "%20") #sustituimos espacios por %20, por si acaso #logger.info("link Torrent: " + link_torrent) link_magnet = scrapertools.find_single_match(data, patron_m) link_magnet = urlparse.urljoin(item.url, link_magnet) #logger.info("link Magnet: " + link_magnet) #Si es un lookup para cargar las urls de emergencia en la Videoteca... if (link_torrent or link_magnet) and item.videolibray_emergency_urls: item.emergency_urls = [] item.emergency_urls.append([link_torrent ]) #Salvamos el enlace de .torrent item.emergency_urls.append([link_magnet ]) #Salvamos el enlace de .magnet return item #... y nos vamos #Añadimos el tamaño para todos size = scrapertools.find_single_match(item.quality, '\s\[(\d+,?\d*?\s\w\s*[b|B]s*)\]') if size: item.title = re.sub('\s\[\d+,?\d*?\s\w\s*[b|B]s*\]', '', item.title) #Quitamos size de título, si lo traía item.quality = re.sub( '\s\[\d+,?\d*?\s\w\s*[b|B]s*\]', '', item.quality) #Quitamos size de calidad, si lo traía if not link_torrent and not link_magnet: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_findvideos( item, itemlist) #Llamamos al método para el pintado del error else: logger.error( "ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron_t + " / " + patron_m + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log', folder=False)) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? link_torrent = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent link_magnet = item.emergency_urls[1][ 0] #Guardamos la url del .Magnet item.armagedon = True #Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: #Si es llamado desde creación de Videoteca... return item #Devolvemos el Item de la llamada else: return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) if not size and not item.armagedon: size = generictools.get_torrent_size( link_torrent) #Buscamos el tamaño en el .torrent if size: size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') #Ahora pintamos el link del Torrent, si lo hay if link_torrent: # Hay Torrent ? #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.torrent_info = "[Torrent] " item_local.torrent_info += '%s' % size #Agregamos size if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') if item.armagedon: #Si es catastrófico, lo marcamos item_local.quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % item_local.quality item_local.url = link_torrent if item_local.url and item.emergency_urls and not item.armagedon: item_local.torrent_alt = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent ALTERNATIVA item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Torrent #Preparamos título y calidad, quitamos etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.quality = re.sub( r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality) item_local.quality = item_local.quality.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado #Ahora pintamos el link del Magnet, si lo hay itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if link_magnet: # Hay Magnet ? #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.torrent_info = "[Magnet] " item_local.torrent_info += '%s' % size #Agregamos size if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') if item.armagedon: #Si es catastrófico, lo marcamos item_local.quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % item_local.quality item_local.url = link_magnet item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Magnet item_local.title = re.sub(r'\s\[COLOR \w+\]\[\[?\]?\]\[\/COLOR\]', '', item_local.title) #Quitamos etiquetas vacías item_local.title = re.sub(r'\s\[COLOR \w+\]\[\/COLOR\]', '', item_local.title) #Quitamos colores vacíos item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado #logger.debug("TORRENT: " + link_torrent + "MAGNET: " + link_magnet + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / tamaño: " + size + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def emergency_urls(item, channel=None, path=None, headers={}): logger.info() import re from servers import torrent try: magnet_caching_e = magnet_caching except: magnet_caching_e = True """ 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 category_save = item.category #... guarda la categoría original por si hay fail-over o redirección en Newpct1 if item.channel_redir: #... si hay un redir, se restaura temporamente el canal alternativo item.channel = scrapertools.find_single_match( item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').lower() item.category = scrapertools.find_single_match( item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() 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 = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 item.category = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 del item_res.videolibray_emergency_urls #... y se borra la marca de lookup if item.videolibray_emergency_urls: del item.videolibray_emergency_urls #... y se borra la marca de lookup original except: logger.error('ERROR al procesar el título en Findvideos del Canal: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) item.channel = channel_save #... restaura el canal original por si hay fail-over o redirección en Newpct1 item.category = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 item_res = item.clone( ) #Si ha habido un error, se devuelve el Item original if item_res.videolibray_emergency_urls: del item_res.videolibray_emergency_urls #... y se borra la marca de lookup if item.videolibray_emergency_urls: del item.videolibray_emergency_urls #... y se borra la marca de lookup 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: referer = None post = None 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 if item_res.referer: referer = item_res.referer if item_res.post: post = item_res.post 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 = '' if magnet_caching_e or not url.startswith('magnet'): path_real = torrent.caching_torrents( url, referer, post, torrents_path=torrents_path, headers=headers ) #... 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 #Restauramos variables originales if item.referer: item_res.referer = item.referer elif item_res.referer: del item_res.referer if item.referer: item_res.referer = item.referer elif item_res.referer: del item_res.referer item_res.url = item.url 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 get_video_url(page_url, premium=False, user="", password="", video_password=""): logger.info("url=" + page_url) video_urls = [] if "crunchyroll.com" in page_url: media_id = page_url.rsplit("-", 1)[1] else: media_id = scrapertools.find_single_match(page_url, 'media_id=(\d+)') url = "https://www.crunchyroll.com/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=%s" \ "&video_format=0&video_quality=0&auto_play=0&aff=af-12299-plwa" % media_id post = "current_page=%s" % page_url data = httptools.downloadpage(url, post, headers=GLOBAL_HEADER).data if "<msg>Media not available</msg>" in data or "flash_block.png" in data: data = httptools.downloadpage(proxy + url, post, headers=GLOBAL_HEADER, cookies=False).data media_url = scrapertools.find_single_match(data, '<file>(.*?)</file>').replace( "&", "&") if not media_url: return video_urls elif not media_url.startswith("http"): rtmp = scrapertools.find_single_match(data, '<host>(.*?)</host>').replace( "&", "&") media_url = rtmp + " playpath=%s" % media_url filename = "RTMP" else: filename = scrapertools.get_filename_from_url(media_url)[-4:] quality = scrapertools.find_single_match(data, '<height>(.*?)</height>') try: idiomas = [ 'Español \(España\)', 'Español\]', 'English', 'Italiano', 'Français', 'Português', 'Deutsch' ] index_sub = int(config.get_setting("sub", server="crunchyroll")) idioma_sub = idiomas[index_sub] link_sub = scrapertools.find_single_match( data, "link='([^']+)' title='\[%s" % idioma_sub) if not link_sub and index_sub == 0: link_sub = scrapertools.find_single_match( data, "link='([^']+)' title='\[Español\]") elif not link_sub and index_sub == 1: link_sub = scrapertools.find_single_match( data, "link='([^']+)' title='\[Español \(España\)") if not link_sub: link_sub = scrapertools.find_single_match( data, "link='([^']+)' title='\[English") data_sub = httptools.downloadpage(link_sub.replace("&", "&"), headers=GLOBAL_HEADER).data id_sub = scrapertools.find_single_match(data_sub, "subtitle id='([^']+)'") iv = scrapertools.find_single_match(data_sub, '<iv>(.*?)</iv>') data_sub = scrapertools.find_single_match(data_sub, '<data>(.*?)</data>') file_sub = decrypt_subs(iv, data_sub, id_sub) except: import traceback logger.error(traceback.format_exc()) file_sub = "" video_urls.append([ "%s %sp [crunchyroll]" % (filename, quality), media_url, 0, file_sub ]) for video_url in video_urls: logger.info("%s - %s" % (video_url[0], video_url[1])) return video_urls
def check_for_update(overwrite=True): logger.info("Actualizando series...") 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): head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) 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: pass if overwrite_forced == True: overwrite = True serie.update_next = '' logger.info("serie=" + serie.contentSerieName) 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: pass 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: pass 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) 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) 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: 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: # 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 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, 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()
def findvideos(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data _sa = scrapertools.find_single_match(data, 'var _sa = (true|false);') _sl = scrapertools.find_single_match(data, 'var _sl = ([^;]+);') sl = eval(_sl) buttons = scrapertools.find_multiple_matches( data, '<button.*?class="selop" sl="([^"]+)">') if not buttons: buttons = [0, 1, 2] for id in buttons: title = '%s' new_url = golink(int(id), _sa, sl) data_new = httptools.downloadpage(new_url).data matches = scrapertools.find_multiple_matches( data_new, 'javascript">(.*?)</script>') js = "" for part in matches: js += part #logger.info("test before:" + js) try: matches = scrapertools.find_multiple_matches( data_new, '" id="(.*?)" val="(.*?)"') for zanga, val in matches: js = js.replace( 'var %s = document.getElementById("%s");' % (zanga, zanga), "") js = js.replace('%s.getAttribute("val")' % zanga, '"%s"' % val) #logger.info("test1 after:" +js) except: pass #v1 js = re.sub('(document\[.*?)=', 'prem=', js) #Parcheando a lo bruto v2 video = scrapertools.find_single_match(js, "sources: \[\{src:(.*?), type") js = re.sub(' videojs\((.*?)\);', video + ";", js) from lib import js2py js2py.disable_pyimport() context = js2py.EvalJs({'atob': atob}) try: result = context.eval(js) except: logger.error("Js2Py no puede desofuscar el codigo, ¿cambió?") continue url = scrapertools.find_single_match(result, 'src="(.*?)"') #v2 if not url: url = result.strip() itemlist.append( Item(channel=item.channel, title=title, url=url, action='play', language='latino', infoLabels=item.infoLabels)) itemlist = servertools.get_servers_itemlist( itemlist, lambda i: i.title % i.server.capitalize()) # Requerido para FilterTools itemlist = filtertools.get_links(itemlist, item, list_language) # Requerido para AutoPlay autoplay.start(itemlist, item) 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 """ global dict_servers_parameters server = server.split('.')[0] if not server: return {} if not server in dict_servers_parameters: try: #Servers if os.path.isfile(os.path.join(config.get_runtime_path(),"servers", server + ".xml")): JSONFile = xml2dict(os.path.join(config.get_runtime_path(),"servers", server + ".xml"))["server"] #Debriders elif os.path.isfile(os.path.join(config.get_runtime_path(),"servers", "debriders", server + ".xml")): JSONFile = xml2dict(os.path.join(config.get_runtime_path(),"servers", "debriders", server + ".xml"))["server"] for k in ['premium', 'id']: if not JSONFile.has_key(k) or JSONFile[k] == "": JSONFile[k] = [] elif type(JSONFile[k]) == dict: JSONFile[k] = JSONFile[k]["value"] if type(JSONFile[k]) == str: JSONFile[k] = [JSONFile[k]] if JSONFile.has_key('find_videos'): if type(JSONFile['find_videos']['patterns']) == dict: JSONFile['find_videos']['patterns'] = [JSONFile['find_videos']['patterns']] if not JSONFile['find_videos'].get("ignore_urls", ""): JSONFile['find_videos']["ignore_urls"] = [] elif type(JSONFile['find_videos']["ignore_urls"] == dict): JSONFile['find_videos']["ignore_urls"] = JSONFile['find_videos']["ignore_urls"]["value"] if type(JSONFile['find_videos']["ignore_urls"]) == str: JSONFile['find_videos']["ignore_urls"] = [JSONFile['find_videos']["ignore_urls"]] if JSONFile.has_key('settings'): if type(JSONFile['settings']) == dict: JSONFile['settings'] = [JSONFile['settings']] if len(JSONFile['settings']): JSONFile['has_settings'] = True else: JSONFile['has_settings'] = False else: JSONFile['has_settings'] = False dict_servers_parameters[server] = JSONFile except: mensaje = "Error al cargar el servidor: %s\n" % server import traceback logger.error(mensaje + traceback.format_exc()) return {} return dict_servers_parameters[server]
def token_trakt(item): from platformcode import platformtools headers = { 'Content-Type': 'application/json', 'trakt-api-key': client_id, 'trakt-api-version': '2' } try: if item.extra == "renew": refresh = config.get_setting("refresh_token_trakt", "trakt") url = "http://api-v2launch.trakt.tv/oauth/device/token" post = { 'refresh_token': refresh, 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'refresh_token' } post = jsontools.dump(post) data = httptools.downloadpage(url, post=post, headers=headers).data data = jsontools.load(data) elif item.action == "token_trakt": url = "http://api-v2launch.trakt.tv/oauth/device/token" post = "code=%s&client_id=%s&client_secret=%s" % ( item.device_code, client_id, client_secret) data = httptools.downloadpage(url, post=post, headers=headers).data data = jsontools.load(data) else: import time dialog_auth = platformtools.dialog_progress( config.get_localized_string(60251), config.get_localized_string(60252) % item.verify_url, config.get_localized_string(60253) % item.user_code, config.get_localized_string(60254)) # Generalmente cada 5 segundos se intenta comprobar si el usuario ha introducido el código while True: time.sleep(item.intervalo) try: if dialog_auth.iscanceled(): config.set_setting("trakt_sync", False) return url = "http://api-v2launch.trakt.tv/oauth/device/token" post = { 'code': item.device_code, 'client_id': client_id, 'client_secret': client_secret } post = jsontools.dump(post) data = httptools.downloadpage(url, post=post, headers=headers).data data = jsontools.load(data) if "access_token" in data: # Código introducido, salimos del bucle break except: pass try: dialog_auth.close() except: pass token = data["access_token"] refresh = data["refresh_token"] config.set_setting("token_trakt", token, "trakt") config.set_setting("refresh_token_trakt", refresh, "trakt") if not item.folder: platformtools.dialog_notification( config.get_localized_string(60255), config.get_localized_string(60256)) if config.is_xbmc(): import xbmc xbmc.executebuiltin("Container.Refresh") return except: import traceback logger.error(traceback.format_exc()) if not item.folder: return platformtools.dialog_notification( config.get_localized_string(60527), config.get_localized_string(60258)) token = "" itemlist = [] if token: itemlist.append( item.clone(config.get_localized_string(60256), action="")) else: itemlist.append( item.clone(config.get_localized_string(60260), action="")) return itemlist
def update_libtorrent(): logger.info() if not config.get_setting("mct_buffer", server="torrent", default=""): default = config.get_setting("torrent_client", server="torrent", default=0) config.set_setting("torrent_client", default, server="torrent") config.set_setting("mct_buffer", "50", server="torrent") if config.get_setting("mct_download_path", server="torrent", default=config.get_setting("downloadpath")): config.set_setting("mct_download_path", config.get_setting("downloadpath"), server="torrent") config.set_setting("mct_background_download", True, server="torrent") config.set_setting("mct_rar_unpack", True, server="torrent") config.set_setting("bt_buffer", "50", server="torrent") if config.get_setting("bt_download_path", server="torrent", default=config.get_setting("downloadpath")): config.set_setting("bt_download_path", config.get_setting("downloadpath"), server="torrent") config.set_setting("mct_download_limit", "", server="torrent") config.set_setting("magnet2torrent", False, server="torrent") if not filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) or not \ config.get_setting("unrar_path", server="torrent", default=""): path = filetools.join(config.get_runtime_path(), 'lib', 'rarfiles') creationflags = '' sufix = '' unrar = '' for device in filetools.listdir(path): if xbmc.getCondVisibility( "system.platform.android") and 'android' not in device: continue if xbmc.getCondVisibility( "system.platform.windows") and 'windows' not in device: continue if not xbmc.getCondVisibility("system.platform.windows") and not xbmc.getCondVisibility("system.platform.android") \ and ('android' in device or 'windows' in device): continue if 'windows' in device: creationflags = 0x08000000 sufix = '.exe' else: creationflags = '' sufix = '' unrar = filetools.join(path, device, 'unrar%s') % sufix if not filetools.exists(unrar): unrar = '' if unrar: if not xbmc.getCondVisibility("system.platform.windows"): try: if xbmc.getCondVisibility("system.platform.android"): # Para Android copiamos el binario a la partición del sistema unrar_org = unrar unrar = filetools.join( xbmc.translatePath('special://xbmc/'), 'files').replace('/cache/apk/assets', '') if not filetools.exists(unrar): filetools.mkdir(unrar) unrar = filetools.join(unrar, 'unrar') filetools.copy(unrar_org, unrar, silent=True) command = ['chmod', '777', '%s' % unrar] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() command = ['ls', '-l', unrar] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() xbmc.log('######## UnRAR file: %s' % str(output_cmd), xbmc.LOGNOTICE) except: xbmc.log( '######## UnRAR ERROR in path: %s' % str(unrar), xbmc.LOGNOTICE) logger.error(traceback.format_exc(1)) try: if xbmc.getCondVisibility("system.platform.windows"): p = subprocess.Popen(unrar, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=creationflags) else: p = subprocess.Popen(unrar, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() if p.returncode != 0 or error_cmd: xbmc.log('######## UnRAR returncode in module %s: %s, %s in %s' % \ (device, str(p.returncode), str(error_cmd), unrar), xbmc.LOGNOTICE) unrar = '' else: xbmc.log( '######## UnRAR OK in %s: %s' % (device, unrar), xbmc.LOGNOTICE) break except: xbmc.log( '######## UnRAR ERROR in module %s: %s' % (device, unrar), xbmc.LOGNOTICE) logger.error(traceback.format_exc(1)) unrar = '' if unrar: config.set_setting("unrar_path", unrar, server="torrent") if filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) and \ config.get_setting("libtorrent_path", server="torrent", default="") : return try: from lib.python_libtorrent.python_libtorrent import get_libtorrent except Exception as e: logger.error(traceback.format_exc(1)) if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") config.set_setting("libtorrent_path", "", server="torrent") if not config.get_setting( "libtorrent_error", server="torrent", default=''): config.set_setting("libtorrent_error", str(e), server="torrent") return
def 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.error("NO ENCONTRADO contentSerieName NI code: " + item.url) 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.error("NO ENCONTRADO EN SCRAPER O NO TIENE code: " + item.url) return 0, 0, -1, path _id = item.infoLabels['code'][0] if not item.infoLabels['code'][0] or item.infoLabels['code'][0] == 'None': if item.infoLabels['code'][1] and item.infoLabels['code'][1] != 'None': _id = item.infoLabels['code'][1] elif item.infoLabels['code'][ 2] and item.infoLabels['code'][2] != 'None': _id = item.infoLabels['code'][2] else: logger.error("NO ENCONTRADO EN SCRAPER O NO TIENE code: " + item.url + ' / ' + item.infoLabels['code']) return 0, 0, -1, path 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 != 'None' 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 verify_Kodi_video_DB(): logger.info() import random platform = {} path = '' db_files = [] try: path = filetools.join(xbmc.translatePath("special://masterprofile/"), "Database") if filetools.exists(path): platform = config.get_platform(full_version=True) if platform and platform['num_version'] <= 19: db_files = filetools.walk(path) if filetools.exists(filetools.join(path, platform['video_db'])): for root, folders, files in db_files: for file in files: if platform['video_db'] not in file: if file.startswith('MyVideos'): randnum = str(random.randrange(1, 999999)) filetools.rename( filetools.join(path, file), 'OLD_' + randnum + '_' + file) logger.error('BD obsoleta: ' + file) else: logger.error('Video_DB: ' + str(platform['video_db']) + ' para versión Kodi ' + str(platform['num_version']) + ' NO EXISTE. Analizar carpeta: ' + str(db_files)) else: logger.error( 'Estructura de get_platform(full_version=True) incorrecta') else: logger.error('Path a Userdata/Database (' + path + ') no encontrado') except: logger.error('Platform: ' + str(platform) + ' / Path: ' + str(path) + ' / Files: ' + str(db_files)) logger.error(traceback.format_exc()) return
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: headers = {} if e.headers: headers = e.headers 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, headers=headers) #... las generamos else: e = emergency_urls( e, channel, json_path, headers=headers ) #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, headers=headers) #generamos las urls if e.emergency_urls: #Si ya tenemos urls... emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo if not e.infoLabels["tmdb_id"] or ( serie.infoLabels["tmdb_id"] and e.infoLabels["tmdb_id"] != serie.infoLabels["tmdb_id"] ): #en series multicanal, prevalece el infolabels... e.infoLabels = serie.infoLabels #... del canal actual y no el del original e.contentSeason, e.contentEpisodeNumber = season_episode.split("x") if e.videolibray_emergency_urls: del e.videolibray_emergency_urls if e.channel_redir: del e.channel_redir #... y se borran las marcas de redirecciones 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 try: t = float(100) / len(new_episodelist) except: t = 0 last_season_episode = '' 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) high_sea = e.contentSeason high_epi = e.contentEpisodeNumber if scrapertools.find_single_match(e.title, '[a|A][l|L]\s*(\d+)'): high_epi = int( scrapertools.find_single_match(e.title, 'al\s*(\d+)')) max_sea = e.infoLabels["number_of_seasons"] max_epi = 0 if e.infoLabels["number_of_seasons"] and ( e.infoLabels["temporada_num_episodios"] or e.infoLabels["number_of_seasons"] == 1): if e.infoLabels["number_of_seasons"] == 1 and e.infoLabels[ "number_of_episodes"]: max_epi = e.infoLabels["number_of_episodes"] else: max_epi = e.infoLabels["temporada_num_episodios"] 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: logger.error('Error en la estructura de la Videoteca: Serie ' + serie.contentSerieName + ' ' + season_episode) 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, "")) if item_nfo.emergency_urls: del item_nfo.emergency_urls #Solo se mantiene en el .json del episodio 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) # En series multicanal, prevalece el infolabels del canal actual y no el del original if not e.infoLabels["tmdb_id"] or (item_nfo.infoLabels["tmdb_id"] \ and e.infoLabels["tmdb_id"] != item_nfo.infoLabels["tmdb_id"]): 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 #logger.debug('high_sea x high_epi: %sx%s' % (str(high_sea), str(high_epi))) #logger.debug('max_sea x max_epi: %sx%s' % (str(max_sea), str(max_epi))) if not silent: p_dialog.close() if news_in_playcounts or emergency_urls_succ or serie.infoLabels[ "status"] == "Ended" or serie.infoLabels["status"] == "Canceled": # 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() if tvshow_item.library_urls.get(serie.channel, False): 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 if tvshow_item.infoLabels["tmdb_id"] == serie.infoLabels[ "tmdb_id"]: tvshow_item.infoLabels = serie.infoLabels tvshow_item.infoLabels["title"] = tvshow_item.infoLabels[ "tvshowtitle"] if max_sea == high_sea and max_epi == high_epi and ( tvshow_item.infoLabels["status"] == "Ended" or tvshow_item.infoLabels["status"] == "Canceled") and insertados == 0 and fallidos == 0: tvshow_item.active = 0 # ... no la actualizaremos más logger.debug("%s [%s]: serie 'Terminada' o 'Cancelada'. Se desactiva la actualización periódica" % \ (serie.contentSerieName, serie.channel)) 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 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 if config.is_xbmc(): from platformcode import xbmc_videolibrary 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()) #Si el canal lo permite, se comienza el proceso de descarga de los nuevos episodios descargados serie.channel = generictools.verify_channel(serie.channel) if insertados > 0 and config.get_setting( 'auto_download_new', serie.channel, default=False): config.set_setting( "search_new_content", 1, "videolibrary") # Escaneamos a final todas la series serie.sub_action = 'auto' serie.category = itemlist[0].category from channels import downloads downloads.save_download(serie, silent=True) if serie.sub_action: del serie.sub_action else: logger.debug("Canal %s no activo no se actualiza" % serie.channel) #Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc() and not config.get_setting( 'cleanlibrary', 'videolibrary', default=False): #Si es Kodi, lo hacemos xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) return insertados_total > 0
def 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: headers = {} if item.headers: headers = item.headers channel = generictools.verify_channel(item.channel) if config.get_setting("emergency_urls", channel) in [1, 3]: item = emergency_urls(item, None, json_path, headers=headers) 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
except: if url.startswith("rtmp"): error = downloadfileRTMP(url, nombrefichero, silent) if error and not silent: from platformcode import platformtools platformtools.dialog_ok("Download non consentito", "Il formato RTMP non", "è supportato") else: import traceback from pprint import pprint exc_type, exc_value, exc_tb = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_tb) for line in lines: line_splits = line.split("\n") for line_split in line_splits: logger.error(line_split) try: f.close() except: pass if not silent: try: progreso.close() except: pass logger.info("Fin descarga del fichero")
def findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if not item.language: item.language = ['CAST'] #Castellano por defecto matches = [] item.category = categoria item.extra2 = 'xyz' del item.extra2 #logger.debug(item) matches = item.url if not matches: #error logger.error( "ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web: " + str(item)) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web. Verificar en la Web esto último y reportar el error con el log', folder=False)) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? item.url = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent matches = item.emergency_urls[1] #Restauramos matches item.armagedon = True #Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: #Si es llamado desde creación de Videoteca... return item #Devolvemos el Item de la llamada else: return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug(matches) #Si es un lookup para cargar las urls de emergencia en la Videoteca... if item.videolibray_emergency_urls: item.emergency_urls = [] #Iniciamos emergency_urls item.emergency_urls.append( []) #Reservamos el espacio para los .torrents locales item.emergency_urls.append(matches) #Salvamnos matches... #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB if not item.videolibray_emergency_urls: item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) #Ahora tratamos los enlaces .torrent for scrapedurl, quality in matches: #leemos los magnets con la diferentes calidades #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.url = scrapedurl if item.videolibray_emergency_urls: item.emergency_urls[0].append( scrapedurl) #guardamos la url y pasamos a la siguiente continue if item.emergency_urls and not item.videolibray_emergency_urls: item_local.torrent_alt = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent ALTERNATIVA if item.armagedon: item_local.url = item.emergency_urls[0][ 0] #... ponemos la emergencia como primaria del item.emergency_urls[0][0] #Una vez tratado lo limpiamos size = '' if not item.armagedon: size = generictools.get_torrent_size( item_local.url) #Buscamos el tamaño en el .torrent if size: size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') item_local.torrent_info = '%s' % size #Agregamos size if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') if item.armagedon: #Si es catastrófico, lo marcamos quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % quality #Añadimos la calidad y copiamos la duración item_local.quality = quality if scrapertools.find_single_match(item.quality, '(\[\d+:\d+\ h])'): item_local.quality += ' [/COLOR][COLOR white]%s' % scrapertools.find_single_match( item.quality, '(\[\d+:\d+\ h])') #Ahora pintamos el link del Torrent item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Torrent #Preparamos título y calidad, quitamos etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.quality = re.sub( r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality).strip() item_local.quality = item_local.quality.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Servidor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío #logger.debug("TORRENT: " + scrapedurl + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) if item.videolibray_emergency_urls: #Si ya hemos guardado todas las urls... return item #... nos vamos if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist