# -*- coding: utf-8 -*- # ------------------------------------------------------------ # GenericTools # ------------------------------------------------------------ # Código reusable de diferentes partes de los canales que pueden # ser llamadados desde otros canales, y así carificar el formato # y resultado de cada canal y reducir el costo su mantenimiento # ------------------------------------------------------------ import re import sys import urllib import urlparse import datetime from channelselector import get_thumb from core import httptools from core import scrapertools from core import servertools from core import channeltools from core import filetools from core.item import Item from platformcode import config, logger from core import tmdb channel_py = "newpct1" intervenido_judicial = 'Dominio intervenido por la Autoridad Judicial' intervenido_policia = ')", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout).data) else: data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) except: data = '' if not data: #no ha habido suerte, probamos con el siguiente canal válido logger.error("ERROR 01: " + item.action + ": La Web no responde o la URL es erronea: " + item.url) continue #Hemos logrado leer la web, validamos si encontramos un línk válido en esta estructura #Evitar páginas engañosas que puede meter al canal en un loop infinito if (not ".com/images/no_imagen.jpg" in data and not ".com/images/imagen-no-disponible.jpg" in data) or item.action != "episodios": if patron: data_alt = scrapertools.find_single_match(data, patron) if patron2 != None: data_alt = scrapertools.find_single_match(data_alt, patron2) if not data_alt: #no ha habido suerte, probamos con el siguiente canal logger.error("ERROR 02: " + item.action + ": Ha cambiado la estructura de la Web: " + item.url + " / Patron: " + patron) web_intervenida(item, data) data = '' continue else: break #por fin !!! Este canal parece que funciona else: logger.error("ERROR 02: " + item.action + ": Ha cambiado la estructura de la Web: " + item.url + " / Patron: " + patron) web_intervenida(item, data) data = '' continue del item.extra2 #Borramos acción temporal excluyente if not data: #Si no ha logrado encontrar nada, salimos limpiando variables if item.channel == channel_py: if item.channel_alt: item.category = item.channel_alt.capitalize() del item.channel_alt else: if item.channel_alt: item.channel = item.channel_alt del item.channel_alt if item.url_alt: item.url = item.url_alt del item.url_alt item.channel_host = channel_host_failed #logger.debug(item) return (item, data) def web_intervenida(item, data, desactivar=True): logger.info() """ Llamada para verificar si la caída de un clone de Newpct1 es debido a una intervención judicial La llamada al método desde es: from lib import generictools item = generictools.web_intervenida(item, data[, desactivar=True]) - Entrada: data: resultado de la descarga. Nos permite analizar si se trata de una intervención - Entrada: desactivar=True: indica que desactiva el canal o clone en caso de intervención judicial - Salida: item.intervencion: devuele un array con el nombre del clone intervenido y el thumb de la autoridad que interviene. El canal puede anunciarlo. - Salida: Si es un clone de Newpct1, se desactiva el clone en el .json del Canal. Si es otro canal, se desactiva el canal en su .json. """ intervencion = () if intervenido_policia in data or intervenido_guardia in data: #Verificamos que sea una intervención judicial judicial = 'intervenido_gc.png' #Por defecto thumb de la Benemérita if intervenido_policia in data: judicial = 'intervenido_pn.jpeg' #thumb de la Policia Nacional category = item.category if not item.category: category = item.channel intervencion = (category, judicial) #Guardamos el nombre canal/categoría y el thumb judicial if not item.intervencion: item.intervencion = [] #Si no existe el array, lo creamos item.intervencion += [intervencion] #Añadimos esta intervención al array logger.error("ERROR 99: " + category + ": " + intervenido_judicial + ": " + item.url + ": DESACTIVADO=" + str(desactivar) + " / DATA: " + data) if desactivar == False: #Si no queremos desactivar el canal, nos vamos return item #Cargamos en .json del canal para ver las listas de valores en settings. Carga las claves desordenadas !!! from core import filetools import json json_data = channeltools.get_channel_json(item.channel) if item.channel == channel_py: #Si es un clone de Newpct1, lo desactivamos for settings in json_data['settings']: #Se recorren todos los settings if settings['id'] == "clonenewpct1_channels_list": #Encontramos en setting action_excluded = scrapertools.find_single_match(settings['default'], "\('\d', '%s', '[^']+', '[^']*', '([^']*)'\)" % item.category.lower()) #extraemos el valor de action_excluded if action_excluded: if "intervenido" not in action_excluded: action_excluded += ', %s' % judicial #Agregamos el thumb de la autoridad judicial else: action_excluded = '%s' % judicial #Reemplazamos el estado a desactivado y agregamos el thumb de la autoridad judicial settings['default'] = re.sub(r"\('\d', '%s', ('[^']+', '[^']*'), '[^']*'\)" % item.category.lower(), r"('0', '%s', \1, '%s')" % (item.category.lower(), action_excluded), settings['default']) break else: json_data['active'] = False #Se desactiva el canal json_data['thumbnail'] = ', thumb_%s' % judicial #Guardamos el thumb de la autoridad judicial #Guardamos los cambios hechos en el .json try: channel_path = filetools.join(config.get_runtime_path(), "channels", item.channel + ".json") with open(channel_path, 'w') as outfile: #Grabamos el .json actualizado json.dump(json_data, outfile, sort_keys = True, indent = 2, ensure_ascii = False) except: logger.error("ERROR 98 al salvar el archivo: %s" % channel_path) #logger.debug(item) return item def redirect_clone_newpct1(item, head_nfo=None, it=None, overwrite=False, path=False): logger.info() """ Llamada para redirigir cualquier llamada a un clone de NewPct1 a NewPct1.py, o de una url de un canal caido a una alternativa Incluye las llamadas estándar del canal y la llamadas externas: - Play fron Library - Videolibrary Update La lógica es reemplazar item.channel por "newpct1" y dejar el nombre del clone en item.category. De esta forma utiliza siempre el código de NewPct1.py, aunque con las urls y apariencia del clone seleccionado por el usuario. En el caso de un canal/clone caído o intervenido judicialmente, puede reemplazar el canal en item.channel, o el clone en item.category, y la parte de item.url que se introduzca en una tabla. Esta conversión sólo se realiza si el canal original está inactivo, pero lo realiza siempre para los clones, o si el canal de origen y destino son los mismos. Este método interroga el .json de NewPct1 para extraer la lista de canales clones. Si item.channel es un clone de NewPct1 y está en esa lista, actualiza item.channel='newpct1' También en este .json está la tabla para la conversión de canales y urls: - activo: está o no activa esta entrada - canal_org: canal o clone de origen - canal_des: canal o clone de destino (puede ser el mismo) - url_org: parte de la url a sustituir de canal o clone de origen - url_des: parte de la url a sustituir de canal o clone de destino - patron1: expresión Regex aplicable a la url (opcional) - patron2: expresión Regex aplicable a la url (opcional) - patron3: expresión Regex aplicable a la url (opcional) - patron4: expresión Regex aplicable a la url (opcional) - patron5: expresión Regex aplicable a la url (opcional) - content_inc: contenido al que aplica esta entrada, o * (item.contentType o item.extra) - content_exc: contenido que se excluye de esta entrada (item.contentType) (opcional) - ow_force: indicador para la acción de "videolibrary_service.py". Puede crear la variable item.ow_force: - force: indica al canal que analize toda la serie y que videolibrary_service la reescriba - auto: indica a videolibrary_service que la reescriba - no: no acción para videolibrary_service, solo redirige en visionado de videolibrary ejemplo: ('1', 'mejortorrent', 'mejortorrent1', 'http://www.mejortorrent.com/', 'https://mejortorrent1.com/', 'auto') La llamada recibe el parámetro Item, el .nfo y los devuleve actualizados, así como opcionalmente el parámetro "overwrite· que puede forzar la reescritura de todos los archivos de la serie, y el parámetro "path" si viene de videolibrary_service """ if not it: it = Item() #logger.debug(item) ow_force_param = True channel_enabled = False update_stat = 0 #Array con los datos de los canales alternativos #Cargamos en .json de Newpct1 para ver las listas de valores en settings fail_over_list = channeltools.get_channel_json(channel_py) for settings in fail_over_list['settings']: #Se recorren todos los settings if settings['id'] == "clonenewpct1_channels_list": #Encontramos en setting fail_over_list = settings['default'] #Carga lista de clones if settings['id'] == "intervenidos_channels_list": #Encontramos en setting intervencion = settings['default'] #Carga lista de clones y canales intervenidos #primero tratamos los clones de Newpct1 channel_alt = item.channel #Salvamos en nombre del canal o clone channel = "'%s'" % item.channel if channel in fail_over_list: #Si es un clone de Newpct1, se actualiza el canal item.channel = channel_py #Ahora tratamos las webs intervenidas, tranformamos la url, el nfo y borramos los archivos obsoletos de la serie if channel not in intervencion: #Hacemos una lookup para ver si... return (item, it, overwrite) #... el canal/clone está listado import ast intervencion_list = ast.literal_eval(intervencion) #Convertir a Array el string #logger.debug(intervencion_list) if item.channel != channel_py: channel_enabled = channeltools.is_enabled(item.channel) #Verificamos que el canal esté inactivo for activo, canal_org, canal_des, url_org, url_des, patron1, patron2, patron3, patron4, patron5, content_inc, content_exc, ow_force in intervencion_list: if activo == '1' and canal_org == channel_alt: #Es esta nuestra entrada? if item.contentType == "list": #Si viene de Videolibrary, le cambiamos ya el canal if item.channel != channel_py: item.channel = canal_des #Cambiamos el canal. Si es clone, lo hace el canal continue #Salimos sin hacer nada más. item está casi vacío if item.contentType not in content_inc and "*" not in content_inc: #Está el contenido el la lista de incluidos continue if item.contentType in content_exc: #Está el contenido excluido? continue if channel_enabled and canal_org != canal_des: #Si el canal está activo, puede ser solo... continue #... una intervención que afecte solo a una región if ow_force == 'no' and path != False: #Queremos que el canal solo visualice sin migración? continue #Salimos sin tocas archivos item.url = item.url.replace(url_org, url_des) #reemplzamos una parte de url if patron1: #Hay expresión regex? url = scrapertools.find_single_match(item.url, patron1) #La aplicamos a url if patron2: #Hay más expresión regex? url += scrapertools.find_single_match(item.url, patron2) #La aplicamos a url if patron3: #Hay más expresión regex? url += scrapertools.find_single_match(item.url, patron3) #La aplicamos a url if patron4: #Hay más expresión regex? url += scrapertools.find_single_match(item.url, patron4) #La aplicamos a url if patron5: #Hay más expresión regex? url += scrapertools.find_single_match(item.url, patron5) #La aplicamos a url item.url = url #Guardamos la suma de los resultados intermedios update_stat += 1 #Ya hemos actualizado algo if update_stat > 0: #Ha habido alguna actualización? Entonces salvamos if item.channel == channel_py: #Si es Newpct1... if item.contentType == "tvshow": item.url = re.sub(r'\/\d+\/?$', '', item.url) #parece que con el título ecuentra la serie, normalmente... if it.url: it.url = item.url #reemplazamos una parte de url en .nfo, aunque no suele haberla if item.library_urls: item.library_urls.pop(canal_org, None) item.library_urls = {canal_des: item.url} it.library_urls = item.library_urls if item.channel != channel_py: item.channel = canal_des #Cambiamos el canal. Si es clone, lo hace el canal if channel_alt == item.category.lower(): #Actualizamos la Categoría y si la tenía item.category = item.channel.capitalize() if ow_force == 'force': #Queremos que el canal revise la serie entera? item.ow_force = "1" #Se lo decimos if ow_force in ['force', 'auto']: #Sobreescribir la series? overwrite = ow_force_param #Sí, lo marcamos if item.contentType in ['tvshow', 'season'] and it.library_urls: if path == False: TVSHOWS_PATH = item.path else: TVSHOWS_PATH = path # Listamos todos los ficheros de la serie, asi evitamos tener que comprobar si existe uno por uno raiz, carpetas_series, ficheros = filetools.walk(TVSHOWS_PATH).next() ficheros = [filetools.join(TVSHOWS_PATH, f) for f in ficheros] #Almacenamos la lista de archivos de la carpeta canal_erase = '[%s]' % canal_org for archivo in ficheros: if canal_erase in archivo: #Borramos los .json que sean del canal intervenido filetools.remove(archivo) if "tvshow.nfo" in archivo: filetools.write(archivo, head_nfo + it.tojson()) #escribo el .nfo por si aborta update #logger.debug(item) return (item, it, overwrite)