def episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title #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 try: tmdb.set_infoLabels(item, True, idioma_busqueda='es,en') except: pass modo_ultima_temp_alt = modo_ultima_temp if item.ow_force == "1": #Si hay un traspaso de canal o url, se actualiza todo modo_ultima_temp_alt = False max_temp = 1 if item.infoLabels['number_of_seasons']: max_temp = item.infoLabels['number_of_seasons'] y = [] if modo_ultima_temp_alt and item.library_playcounts: #Averiguar cuantas temporadas hay en Videoteca patron = 'season (\d+)' matches = re.compile(patron, re.DOTALL).findall(str(item.library_playcounts)) for x in matches: y += [int(x)] max_temp = max(y) # Descarga la página data = '' #Inserto en num de página en la url try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", 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 status, itemlist = check_blocked_IP(data, itemlist) #Comprobamos si la IP ha sido bloqueada if status: return itemlist #IP bloqueada #Capturamos las temporadas de episodios dentro de la serie patron_temp = '<h1\s*class="[^"]+">Season\s*(\d+)<\/h1><div class="tvcontent"><div id="[^"]+"><\/div>(.*?<\/div><\/div>)(?:<script>.*?<\/script>)?<\/div>' temp_serie = re.compile(patron_temp, re.DOTALL).findall(data) for season_num, temporada in temp_serie: patron = '<div id="episode_(\d+)"><div class="[^"]+">\s*<a onclick="[^"]+"\s*class="[^"]+"><div class="[^"]+">.*?\s*(\d+)<\/div>\s*(.*?)\s*<' matches = re.compile(patron, re.DOTALL).findall(temporada) 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 " + " / PATRON: " + patron + " / DATA: " + 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("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) season = max_temp #Comprobamos si realmente sabemos el num. máximo de temporadas if item.library_playcounts or (item.infoLabels['number_of_seasons'] and item.tmdb_stat): num_temporadas_flag = True else: num_temporadas_flag = False if modo_ultima_temp_alt and item.library_playcounts: #Si solo se actualiza la última temporada de Videoteca if int(season_num) < max_temp: break #Sale del bucle actual del FOR # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for epi_id, episode_num, scrapedtitle in matches: item_local = item.clone() item_local.action = "findvideos" 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 item_local.title = '' item_local.context = "['buscar_trailer']" item_local.url = urlparse.urljoin(host, 'tv.php?ajax=1&tvepisode=%s' % epi_id) title = scrapedtitle item_local.language = ['VO'] if not item_local.infoLabels['poster_path']: item_local.thumbnail = item_local.infoLabels['thumbnail'] epi_rango = False try: item_local.contentSeason = int(season_num) if 'season pack' in title.lower(): item_local.contentEpisodeNumber = 1 epi_rango = True else: item_local.contentEpisodeNumber = int(episode_num) except: logger.error('ERROR al extraer Temporada/Episodio: ' + title) item_local.contentSeason = 1 item_local.contentEpisodeNumber = 0 #Si son episodios múltiples, lo extraemos if epi_rango: item_local.infoLabels['episodio_titulo'] = 'al 99' item_local.title = '%sx%s al 99 - Season Pack' % (str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) else: item_local.title = '%sx%s - ' % (str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) if season_display > 0: if item_local.contentSeason > season_display: continue elif item_local.contentSeason < season_display: break 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, idioma_busqueda='es,en') #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 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, idioma patron += '<span class="[^"]+" style="[^"]+"\s*><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 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, 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 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 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"] if item_local.language == []: item_local.language = ['CAST'] #Por defecto #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 listado(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial if item.curr_page: curr_page = int(item.curr_page) # Si viene de una pasada anterior, lo usamos del item.curr_page # ... y lo borramos if item.last_page: last_page = int(item.last_page) # Si viene de una pasada anterior, lo usamos del item.last_page # ... y lo borramos cnt_tot = 40 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist inicio = time.time() # Controlaremos que el proceso no exceda de un tiempo razonable fin = inicio + 3 # 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 #Sistema de paginado para evitar páginas vacías o semi-vacías en casos de búsquedas con series con muchos episodios title_lista = [] # Guarda la lista de series que ya están en Itemlist, para no duplicar lineas if item.title_lista: # Si viene de una pasada anterior, la lista ya estará guardada title_lista.extend(item.title_lista) # Se usa la lista de páginas anteriores en Item del item.title_lista # ... limpiamos if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' next_page_url = item.url #Máximo num. de líneas permitidas por TMDB. Máx de 3 segundos por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot * 0.50 and curr_page <= last_page and fin > time.time(): # Descarga la página data = '' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(next_page_url, timeout=timeout_search).data) if not PY3: data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass curr_page += 1 #Apunto ya a la página siguiente if not data and not item.extra2: #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')) break #si no hay más datos, algo no funciona, pintamos lo que tenemos status, itemlist = check_blocked_IP(data, itemlist) #Comprobamos si la IP ha sido bloqueada if status: return itemlist #IP bloqueada #Patrón para todo, incluido búsquedas en cualquier caso patron = '<tr class="lista2"><td align="(?:[^"]+)?"\s*class="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*style="(?:[^"]+)?"><a href="[^"]+"><img src="([^"]+)?"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*\/><\/a><\/td><td\s*align="(?:[^"]+)?"\s*class="(?:[^"]+)?"><a onmouseover="(?:[^"]+)?"\s*onmouseout="(?:[^"]+)?"\s*href="[^"]+" title="[^"]+">([^<]+)<\/a>\s*<a href="([^"]+)"><img src="[^"]+"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>\s*(?:<a href="([^"]+)"><img src="[^"]+"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>)?\s*<br><span.*?<\/span>\s*<\/td><td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">.*?<\/td><td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">([^<]+)?<\/td><td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">\s*<font color="(?:[^"]+)?">(\d+)?<\/font>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches and item.extra != 'search': #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: 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')) break #si no hay más datos, algo no funciona, pintamos lo que tenemos if not matches and item.extra == 'search': #búsqueda vacía return itemlist #Salimos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) #Buscamos la próxima y la última página patron_next = '<a href="([^"]+page=(\d+))" title="next page">' if item.extra == 'search': patron_last = '<a href="[^"]+"\s*title="page\s*\d+">\d+<\/a>\s*<b>(\d+)<\/b><\/div><\/div><\/td>' else: patron_last = 'title="previous page"[^<]+<\/a>\s*<a href="[^>]+>(\d+)<\/a>' try: next_page_url, next_page = scrapertools.find_single_match(data, patron_next) next_page = int(next_page) next_page_url = item.url + '&page=' + str(next_page) except: #Si no lo encuentra, lo ponemos a 1 #logger.error('ERROR 03: LISTADO: Al obtener la paginación: ' + patron_next + ' / ' + patron_last + ' / ' + scrapertools.find_single_match(data, "<ul class=\"pagination\">.*?<\/span><\/a><\/li><\/ul><\/nav><\/div><\/div><\/div>")) next_page = 1 #logger.debug('curr_page: ' + str(curr_page) + ' / next_page: ' + str(next_page) + ' / last_page: ' + str(last_page)) if last_page == 99999: #Si es el valor inicial, buscamos if item.extra == 'search': last_page = 99 try: data_last = '' data_last = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(item.url + '&page=%s' % last_page, timeout=timeout_search).data) if not PY3: data_last = unicode(data_last, "utf-8", errors="replace").encode("utf-8") last_page = int(scrapertools.find_single_match(data_last, patron_last)) #lo cargamos como entero except: #Si no lo encuentra, lo ponemos a 1 #logger.error('ERROR 03: LISTADO: Al obtener la paginación: ' + patron_next + ' / ' + patron_last + ' / ' + scrapertools.find_single_match(data, "<ul class=\"pagination\">.*?<\/span><\/a><\/li><\/ul><\/nav><\/div><\/div><\/div>")) last_page = next_page #logger.debug('curr_page: ' + str(curr_page) + ' / next_page: ' + str(next_page) + ' / last_page: ' + str(last_page)) #Empezamos el procesado de matches for scrapedthumbnail, scrapedtitle, scrapedurl, scrapedepisodes, scrapedsize, scrapedseeds in matches: title = scrapedtitle if scrapedepisodes: url = scrapedepisodes else: url = scrapedurl size = scrapedsize # Slugify, pero más light title = title.replace("á", "a").replace("é", "e").replace("í", "i")\ .replace("ó", "o").replace("ú", "u").replace("ü", "u")\ .replace("�", "ñ").replace("ñ", "ñ") title = scrapertools.decode_utf8_error(title) if scrapedurl in title_lista: #Si ya hemos procesado el título, lo ignoramos continue else: title_lista += [scrapedurl] #la añadimos a la lista de títulos #cnt_title += 1 item_local = item.clone() #Creamos copia de Item para trabajar if item_local.tipo: #... y limpiamos del item_local.tipo if item_local.totalItems: del item_local.totalItems if item_local.intervencion: del item_local.intervencion if item_local.viewmode: del item_local.viewmode item_local.extra2 = True del item_local.extra2 item_local.text_bold = True del item_local.text_bold item_local.text_color = True del item_local.text_color title_subs = [] #creamos una lista para guardar info importante item_local.language = ['VO'] #creamos lista para los idiomas item_local.quality = '' #iniciamos calidad item_local.thumbnail = scrapedthumbnail #iniciamos thumbnail if item.extra == 'search': if scrapedepisodes: item_local.extra = 'series' else: item_local.extra = 'peliculas' item_local.url = urlparse.urljoin(host, url) #guardamos la url final if item_local.extra != 'series': item_local.url += '&order=size&by=ASC' #guardamos la url final item_local.context = "['buscar_trailer']" item_local.contentType = "movie" #por defecto, son películas item_local.action = "findvideos" #Analizamos los formatos de la películas if item_local.extra == 'peliculas': patron_title = '(.*?)\.([1|2][9|0]\d{2})?\.(.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): logger.error('ERROR tratando título PELI: ' + title) continue try: title, year, item_local.quality = scrapertools.find_single_match(title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') #Analizamos los formatos de series, temporadas y episodios elif item_local.extra == 'series': patron_title = '(.*?)(\.[1|2][9|0]\d{2})?\.S\d{2}.*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): patron_title = '(.*?)\.*([1|2][9|0]\d{2})?(?:\.\d{2}\.\d{2}).*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): logger.error('ERROR tratando título SERIE: ' + title) continue try: title, year, item_local.quality = scrapertools.find_single_match(title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') year = '-' item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = True #Muestra las series agrupadas por temporadas #Limpiamos el título de la basura innecesaria title = re.sub(r'(?i)TV|Online', '', title).strip() item_local.quality = re.sub(r'(?i)proper|unrated|directors|cut|german|repack|internal|real|korean|extended|masted|docu|oar|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Analizamos el año. Si no está claro ponemos '-' try: year_int = int(year) if year_int >= 1940 and year_int <= 2050: item_local.infoLabels["year"] = year_int else: item_local.infoLabels["year"] = '-' except: item_local.infoLabels["year"] = '-' #Terminamos de limpiar el título title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').strip().lower().title() item_local.from_title = title.strip().lower().title() #Guardamos esta etiqueta para posible desambiguación de título #Salvamos el título según el tipo de contenido if item_local.contentType == "movie": item_local.contentTitle = title else: item_local.contentSerieName = title.strip().lower().title() item_local.title = title.strip().lower().title() #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB item_local.title_subs = title_subs #Salvamos y borramos el número de temporadas porque TMDB a veces hace tonterias. Lo pasamos como serie completa if item_local.contentSeason and (item_local.contentType == "season" or item_local.contentType == "tvshow"): item_local.contentSeason_save = item_local.contentSeason del item_local.infoLabels['season'] #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting('filter_languages', channel) > 0: #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 cnt_title = len(itemlist) #Contador de líneas añadidas #logger.debug(item_local) #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda='es,en') #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Si es necesario añadir paginacion if curr_page <= last_page: if last_page: title = '%s de %s' % (curr_page-1, last_page) else: title = '%s' % curr_page-1 itemlist.append(Item(channel=item.channel, action="listado", title=">> Página siguiente " + title, title_lista=title_lista, url=next_page_url, extra=item.extra, extra2=item.extra2, last_page=str(last_page), curr_page=str(curr_page))) return itemlist
def findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if not item.language: item.language = ['VO'] #VO por defecto matches = [] item.category = categoria #logger.debug(item) #Bajamos los datos de la página data = '' patron = '<tr class="lista2">\s*<td align="(?:[^"]+)?"\s*class="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*style="(?:[^"]+)?">\s*<a href="[^"]+">\s*<img src="([^"]+)?"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*\/><\/a><\/td>\s*<td\s*align="(?:[^"]+)?"(?:\s*width="[^"]+")?\s*class="(?:[^"]+)?">\s*<a onmouseover="(?:[^"]+)?"\s*onmouseout="(?:[^"]+)?"\s*href="([^"]+)" title="[^"]+">(.*?)<\/a>\s*<a href="[^"]+">\s*<img src="[^"]+"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>(?:\s*<a.*?<\/a>)?\s*<br><span.*?<\/span>\s*<\/td>\s*<td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">.*?<\/td>\s*<td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">(.*?)?<\/td>\s*<td align="(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">\s*<font color="(?:[^"]+)?">(\d+)?<\/font>' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) if not PY3: data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass if not data: logger.error("ERROR 01: FINDVIDEOS: La Web no responde o la URL es erronea: " + item.url) 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)) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos status, itemlist = check_blocked_IP(data, itemlist) #Comprobamos si la IP ha sido bloqueada if status: return itemlist #IP bloqueada matches = re.compile(patron, re.DOTALL).findall(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_findvideos(item, itemlist) #Llamamos al método para el pintado del error else: logger.error("ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web " + " / PATRON: " + patron + data) 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)) 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) #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) #Ahora tratamos los enlaces .torrent con las diferentes calidades for scrapedthumbnail, scrapedurl, scrapedtitle, scrapedsize, scrapedseeds in matches: #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() title = scrapedtitle #Analizamos los formatos de la películas y series if item_local.contentType == 'movie': patron_title = '(.*?)\.([1|2][9|0]\d{2})?\.(.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): continue else: patron_title = '(.*?)(\.[1|2][9|0]\d{2})?\.S\d{2}.*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): patron_title = '(.*?)\.*([1|2][9|0]\d{2})?(?:\.\d{2}\.\d{2}).*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): continue try: title, year, item_local.quality = scrapertools.find_single_match(title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') item_local.quality = re.sub(r'(?i)proper|unrated|directors|cut|german|repack|internal|real|korean|extended|masted|docu|oar|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Buscamos si ya tiene tamaño, si no, los buscamos en el archivo .torrent size = scrapedsize if size: item_local.title = '%s [%s]' % (item_local.title, size) #Agregamos size al final del título 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 #Añadimos los seeds en calidad, como información adicional if scrapedseeds: item_local.torrent_info += 'Seeds: %s' % scrapedseeds #Agregamos seeds if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip().strip(',') #Ahora pintamos el link del Torrent item_local.url = urlparse.urljoin(host, scrapedurl) 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 #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 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
def listado(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial if item.curr_page: curr_page = int( item.curr_page) # Si viene de una pasada anterior, lo usamos del item.curr_page # ... y lo borramos if item.last_page: last_page = int( item.last_page) # Si viene de una pasada anterior, lo usamos del item.last_page # ... y lo borramos cnt_tot = 40 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en 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 #Sistema de paginado para evitar páginas vacías o semi-vacías en casos de búsquedas con series con muchos episodios title_lista = [ ] # Guarda la lista de series que ya están en Itemlist, para no duplicar lineas if item.title_lista: # Si viene de una pasada anterior, la lista ya estará guardada title_lista.extend( item.title_lista) # Se usa la lista de páginas anteriores en Item del item.title_lista # ... limpiamos if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' next_page_url = item.url #Máximo num. de líneas permitidas por TMDB. Máx de 10 segundos por Itemlist para no degradar el rendimiento while cnt_title < cnt_tot * 0.5 and curr_page <= last_page and fin > time.time( ): # Descarga la página data = '' try: data = re.sub( r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(next_page_url, timeout=timeout_search).data) #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") except: pass curr_page += 1 #Apunto ya a la página siguiente 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' )) break #si no hay más datos, algo no funciona, pintamos lo que tenemos #Patrón para todo, menos para Series completas, incluido búsquedas en cualquier caso patron = '<td class="vertThseccion"><img src="([^"]+)"[^>]+><a href="([^"]+)"\s*title="([^"]+)"\s*>[^<]+<\/a><\/td><td>.*?(\d+)?<\/td><td>([^<]+)?<\/td><td>([^<]+)?<\/td><\/tr>' #Si son series completas, ponemos un patrón especializado if item.extra == 'series': patron = '<(td)><a href="([^"]+)"\s*title="([^"]+)"\s*><[^>]+src="[^"]+\/(\d{4})[^"]+"[^>]+>(?:(\d+))?\s*(?:(\d+))?<\/a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches and not '<p>Lo sentimos, pero que esta buscando algo que no esta aqui. </p>' in data and not item.extra2 and not '<h2>Sin resultados</h2> 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_episodios( 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' )) break #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) #Buscamos la próxima y la última página patron_last = "<div class='pagination'>.*?<a href='([^']+\/page\/(\d+)[^']+)'\s*>(?:»)?(?:\d+)?<\/a><\/div>" if last_page == 99999: #Si es el valor inicial, buscamos last page try: next_page_url, last_page = scrapertools.find_single_match( data, patron_last) #cargamos la url y la última página last_page = int(last_page) except: #Si no lo encuentra, lo ponemos a 1 last_page = 1 #logger.error('ERROR 03: LISTADO: Al obtener la paginación: ' + patron_last + ' / ' + next_page_url + ' / ' + str(last_page)) #logger.debug('curr_page: ' + str(curr_page) + '/ last_page: ' + str(last_page)) if last_page > 1: next_page_url = re.sub(r'\/page\/\d+\/', '/page/%s/' % curr_page, next_page_url) next_page_url = next_page_url.replace('&', '&') else: next_page_url = item.url #logger.debug('curr_page: ' + str(curr_page) + '/ last_page: ' + str(last_page) + '/ next_page_url: ' + next_page_url) #Empezamos el procesado de matches for scrapedlanguage, scrapedurl, scrapedtitle, year, scrapedcategory, scrapedquality in matches: title = scrapedtitle url = scrapedurl.replace('&', '&') title = title.replace("á", "a").replace("é", "e").replace( "í", "i").replace("ó", "o").replace("ú", "u").replace( "ü", "u").replace("�", "ñ").replace("ñ", "ñ").replace( "ã", "a").replace("&etilde;", "e").replace( "ĩ", "i").replace("õ", "o").replace( "ũ", "u").replace("ñ", "ñ").replace( "’", "'").replace('&', '&') #cnt_title += 1 item_local = item.clone() #Creamos copia de Item para trabajar if item_local.tipo: #... y limpiamos del item_local.tipo if item_local.totalItems: del item_local.totalItems if item_local.category: del item_local.category if item_local.intervencion: del item_local.intervencion if item_local.viewmode: del item_local.viewmode item_local.extra2 = True del item_local.extra2 item_local.text_bold = True del item_local.text_bold item_local.text_color = True del item_local.text_color title_subs = [] #creamos una lista para guardar info importante item_local.language = [] #creamos lista para los idiomas item_local.quality = scrapedquality #iniciamos calidad item_local.thumbnail = '' item_local.url = url.replace('&', '&').replace( '.io/', sufix).replace('.com/', sufix) #guardamos la url final item_local.context = "['buscar_trailer']" item_local.contentType = "movie" #por defecto, son películas item_local.action = "findvideos" #Analizamos el formato de series if '/series' in scrapedurl or item_local.extra == 'series' or 'series' in scrapedcategory: item_local.extra = 'series' item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = True #Muestra las series agrupadas por temporadas #Detectamos idiomas if "1.png" in scrapedlanguage: item_local.language += ['CAST'] if "512.png" in scrapedlanguage or 'latino' in title.lower(): item_local.language += ['LAT'] if ("1.png" not in scrapedlanguage and "512.png" not in scrapedlanguage ) or "eng" in title.lower() or "sub" in title.lower(): item_local.language += ['VOSE'] if '-3d' in scrapedurl: title = title.replace('3D', '').replace('3d', '') item_local.quality += ' 3D' #Detectamos el año item_local.infoLabels['year'] = '-' if year: try: year = int(year) if year >= 1970 and year <= 2040: item_local.infoLabels["year"] = year except: pass #Detectamos info importante a guardar para después de TMDB if "extendida" in title.lower() or "extended" in title.lower( ) or "v.e." in title.lower() or "v e " in title.lower(): title_subs += ["[V. Extendida]"] title = title.replace("Version Extendida", "").replace( "(Version Extendida)", "").replace("V. Extendida", "").replace("VExtendida", "").replace( "V Extendida", "").replace("V.Extendida", "").replace( "V Extendida", "").replace("V.E.", "").replace("V E ", "") if scrapertools.find_single_match(title, '[m|M].*?serie'): title = re.sub(r'[m|M]iniserie', '', title) title_subs += ["Miniserie"] if scrapertools.find_single_match(title, '[s|S]aga'): title = re.sub(r'[s|S]aga', '', title) title_subs += ["Saga"] if scrapertools.find_single_match(title, '[c|C]olecc'): title = re.sub(r'[c|C]olecc...', '', title) title_subs += ["Colección"] #Empezamos a limpiar el título en varias pasadas patron = '\s?-?\s?(line)?\s?-\s?$' regex = re.compile(patron, re.I) title = regex.sub("", title) title = re.sub(r'\(\d{4}\s*?\)', '', title) title = re.sub(r'\[\d{4}\s*?\]', '', title) title = re.sub(r'[s|S]erie', '', title) title = re.sub(r'- $', '', title) title = re.sub(r'\d+[M|m|G|g][B|b]', '', title) #Limpiamos el título de la basura innecesaria title = re.sub( r'(?i)TV|Online|Spanish|Torrent|en Espa\xc3\xb1ol|Español|Latino|Subtitulado|Blurayrip|Bluray rip|\[.*?\]|R2 Pal|\xe3\x80\x90 Descargar Torrent \xe3\x80\x91|Completa|Temporada|Descargar|Torren|\(iso\)|\(dvd.*?\)|(?:\d+\s*)?\d{3,4}p.*?$|extended|(?:\d+\s*)?bdrip.*?$|\(.*?\).*?$|iso$|unrated|\[.*?$|\d{4}$', '', title) #Obtenemos temporada y episodio si se trata de Episodios if item_local.contentType == "episode": patron = '(\d+)[x|X](\d+)' try: item_local.contentSeason, item_local.contentEpisodeNumber = scrapertools.find_single_match( title, patron) except: item_local.contentSeason = 1 item_local.contentEpisodeNumber = 0 #Si son eisodios múltiples, lo extraemos patron1 = '\d+[x|X]\d+.?(?:y|Y|al|Al)?.?\d+[x|X](\d+)' epi_rango = scrapertools.find_single_match(title, patron1) if epi_rango: item_local.infoLabels[ 'episodio_titulo'] = 'al %s' % epi_rango title = re.sub(patron1, '', title) else: title = re.sub(patron, '', title) #Terminamos de limpiar el título title = re.sub(r'\??\s?\d*?\&.*', '', title) title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').strip().lower().title() item_local.from_title = title.strip().lower().title( ) #Guardamos esta etiqueta para posible desambiguación de título #Salvamos el título según el tipo de contenido if item_local.contentType == "movie": item_local.contentTitle = title else: item_local.contentSerieName = title.strip().lower().title() item_local.title = title.strip().lower().title() item_local.quality = item_local.quality.strip() #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB item_local.title_subs = title_subs #Salvamos y borramos el número de temporadas porque TMDB a veces hace tonterias. Lo pasamos como serie completa if item_local.contentSeason and (item_local.contentType == "season" or item_local.contentType == "tvshow"): item_local.contentSeason_save = item_local.contentSeason del item_local.infoLabels['season'] #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting( 'filter_languages', channel) > 0: #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 cnt_title = len(itemlist) #Contador de líneas añadidas #logger.debug(item_local) #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Si es necesario añadir paginacion if curr_page <= last_page and last_page > 1: if last_page: title = '%s de %s' % (curr_page - 1, last_page) else: title = '%s' % curr_page - 1 itemlist.append( Item(channel=item.channel, action="listado", title=">> Página siguiente " + title, title_lista=title_lista, url=next_page_url, extra=item.extra, extra2=item.extra2, last_page=str(last_page), curr_page=str(curr_page))) return itemlist
def episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title if item.subtitle: del item.subtitle #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 modo_ultima_temp_alt = modo_ultima_temp if item.ow_force == "1": #Si hay un traspaso de canal o url, se actualiza todo modo_ultima_temp_alt = False max_temp = 1 if item.infoLabels['number_of_seasons']: max_temp = item.infoLabels['number_of_seasons'] y = [] if modo_ultima_temp_alt and item.library_playcounts: #Averiguar cuantas temporadas hay en Videoteca patron = 'season (\d+)' matches = re.compile(patron, re.DOTALL).findall(str(item.library_playcounts)) for x in matches: y += [int(x)] max_temp = max(y) # Descarga la página data = '' #Inserto en num de página en la url try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(item.url, timeout=timeout).data) #data = unicode(data, "iso-8859-1", 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 patron = '<td class="capitulonombre"><img src="([^"]+)[^>]+>(?:<a href="[^>]+>)(.*?)<\/a><\/td><td class="capitulodescarga"><a href="([^"]+)[^>]+>.*?(?:<td class="capitulofecha">.*?(\d{4})?.*?<\/td>)?(?:<td class="capitulosubtitulo"><a href="([^"]+)[^>]+>.*?<\/td>)?<td class="capitulodescarga"><\/tr>' matches = re.compile(patron, re.DOTALL).findall(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 " + " / PATRON: " + patron + " / DATA: " + 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("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) season = max_temp #Comprobamos si realmente sabemos el num. máximo de temporadas if item.library_playcounts or (item.infoLabels['number_of_seasons'] and item.tmdb_stat): num_temporadas_flag = True else: num_temporadas_flag = False # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for scrapedlanguage, scrapedtitle, scrapedurl, year, scrapedsubtitle in matches: item_local = item.clone() item_local.action = "findvideos" 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 item_local.title = '' item_local.context = "['buscar_trailer']" item_local.url = scrapedurl.replace('&', '&').replace( '.io/', sufix).replace('.com/', sufix) if scrapedsubtitle: item_local.subtitle = scrapedsubtitle.replace( '&', '&').replace('.io/', sufix).replace('.com/', sufix) title = scrapedtitle item_local.language = [] if "1.png" in scrapedlanguage: item_local.language += ['CAST'] if "512.png" in scrapedlanguage or 'latino' in title.lower(): item_local.language += ['LAT'] if ("1.png" not in scrapedlanguage and "512.png" not in scrapedlanguage ) or "eng" in title.lower() or "sub" in title.lower(): item_local.language += ['VOSE'] try: item_local.contentEpisodeNumber = 0 if 'miniserie' in title.lower(): item_local.contentSeason = 1 title = title.replace('miniserie', '').replace('MiniSerie', '') elif 'completa' in title.lower(): patron = '[t|T].*?(\d+) [c|C]ompleta' if scrapertools.find_single_match(title, patron): item_local.contentSeason = int( scrapertools.find_single_match(title, patron)) if not item_local.contentSeason: #Extraemos los episodios patron = '(\d{1,2})[x|X](\d{1,2})' item_local.contentSeason, item_local.contentEpisodeNumber = scrapertools.find_single_match( title, patron) item_local.contentSeason = int(item_local.contentSeason) item_local.contentEpisodeNumber = int( item_local.contentEpisodeNumber) except: logger.error('ERROR al extraer Temporada/Episodio: ' + title) item_local.contentSeason = 1 item_local.contentEpisodeNumber = 0 #Si son eisodios múltiples, lo extraemos patron1 = '\d+[x|X]\d{1,2}.?(?:y|Y|al|Al)?(?:\d+[x|X]\d{1,2})?.?(?:y|Y|al|Al)?.?\d+[x|X](\d{1,2})' epi_rango = scrapertools.find_single_match(title, 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)) if modo_ultima_temp_alt and item.library_playcounts: #Si solo se actualiza la última temporada de Videoteca if item_local.contentSeason < max_temp: break #Sale del bucle actual del FOR if season_display > 0: if item_local.contentSeason > season_display: continue elif item_local.contentSeason < season_display: break 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 submenu(item): logger.info() itemlist = [] item.filter_lang = True 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: 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 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\s*class="enlace_descarga"[^>]+>\s*<a\s*href=)?"([^"]+\.torrent)"' patron_m = '(?:<div\s*class="enlace_descarga"[^>]+>\s*<a\s*href=)?"(magnet:?[^"]+)"' if not item.armagedon: #Si es un proceso normal, seguimos data_links = data for x in range(2): link_torrent = scrapertools.find_single_match(data_links, patron_t) if link_torrent: link_torrent = urlparse.urljoin(host, 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_links, patron_m) #logger.info("link Magnet: " + link_magnet) if not (link_torrent and link_magnet) and x == 0: data_links = generictools.identifying_links(data_links) #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() if not size or 'Magnet' in size: item_local.alive = "??" # Calidad del link sin verificar elif 'ERROR' in size and 'Pincha' in size: item_local.alive = "ok" # link en error, CF challenge, Chrome disponible elif 'ERROR' in size and 'Introduce' in size: item_local.alive = "??" # link en error, CF challenge, ruta de descarga no disponible item_local.channel = 'setting' item_local.action = 'setting_torrent' item_local.unify = False item_local.folder = False item_local.item_org = item.tourl() elif 'ERROR' in size: item_local.alive = "no" # Calidad del link en error, CF challenge? else: item_local.alive = "ok" # Calidad del link verificada if item_local.channel != 'setting': 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 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 try: tmdb.set_infoLabels(item, True) #TMDB actualizado except: pass item.category = categoria item.extra2 = 'xyz' del item.extra2 item.url = item.url.replace('http:', 'https:') #Por si viene de la videoteca #logger.debug(item) #Bajamos los datos de la página data = '' patron = '<p><a href="([^"]+)" rel' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass if not data: logger.error( "ERROR 01: FINDVIDEOS: La Web no responde o la URL es erronea: " + item.url) 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' )) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? 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 if not item.armagedon: matches = re.compile(patron, re.DOTALL).findall(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_findvideos( item, itemlist) #Llamamos al método para el pintado del error else: logger.error( "ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web " + " / PATRON: " + patron + data) 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' )) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? 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("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) #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 de los vídeos... #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 in matches: #leemos los torrents con la diferentes calidades if 'javascript' in scrapedurl: #evitamos la basura continue url = '' if not item.armagedon: url = urlparse.urljoin(host, scrapedurl) #Leemos la siguiente página, que es de verdad donde está el magnet/torrent try: data = re.sub( r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(url, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass patron = "window.open\('([^']+)'" url = scrapertools.find_single_match(data, patron) if not url: #error logger.error( "ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web " + " / PATRON: " + patron + data) 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' )) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? item.armagedon = True #Marcamos la situación como catastrófica else: continue #si no hay más datos, algo no funciona, pasamos al siguiente #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.url = urlparse.urljoin(host, url) if item.videolibray_emergency_urls: item.emergency_urls[0].append( item_local.url) #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] #Restauramos la url if len(item.emergency_urls[0]) > 1: del item.emergency_urls[0][0] #Buscamos si ya tiene tamaño, si no, los buscamos en el archivo .torrent size = scrapertools.find_single_match( item_local.quality, '\s?\[(\d+,?\d*?\s\w\s?[b|B])\]') if not size and not item.armagedon: size = generictools.get_torrent_size( item_local.url) #Buscamos el tamaño en el .torrent if size: item_local.title = re.sub( r'\s?\[\d+,?\d*?\s\w\s?[b|B]\]', '', item_local.title) #Quitamos size de título, si lo traía item_local.title = '%s [%s]' % ( item_local.title, size) #Agregamos size al final del título size = size.replace('GB', 'G B').replace('Gb', 'G b').replace( 'MB', 'M B').replace('Mb', 'M b') item_local.quality = re.sub( r'\s?\[\d+,?\d*?\s\w\s?[b|B]\]', '', item_local.quality) #Quitamos size de calidad, si lo traía item_local.quality = '%s [%s]' % ( item_local.quality, size ) #Agregamos size al final de la calidad if item.armagedon: #Si es catastrófico, lo marcamos item_local.quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % item_local.quality #Ahora pintamos el link del 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 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)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def categorias(item): logger.info() itemlist = [] data = '' try: data = re.sub(r"\n|\r|\t| |<br>|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass patron = '<li><a href="([^"]+)" rel="tag" class="[^>]+>(.*?)<\/a><\/li>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): 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 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append( item.clone( action='', title=item.category + ': ERROR 01: SUBMENU: 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 matches = re.compile(patron, re.DOTALL).findall(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': 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 #logger.debug(matches) for scrapedurl, scrapedtitle in matches: itemlist.append( item.clone(action="listado", title=scrapedtitle.capitalize().strip(), url=scrapedurl)) return itemlist
def listado(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) curr_page = 1 # Página inicial cnt_title = 0 # Contador de líneas insertadas en Itemlist if item.curr_page: curr_page = int( item.curr_page) # Si viene de una pasada anterior, lo usamos del item.curr_page # ... y lo borramos if item.last_page: last_page = int( item.last_page) # Si viene de una pasada anterior, lo usamos del item.last_page # ... y lo borramos cnt_tot = 40 # Poner el num. máximo de items por página cnt_pct = 0.725 #% de la página a llenar 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 if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' next_page_url = item.url #Máximo num. de líneas permitidas por TMDB. Máx de 10 segundos por Itemlist para no degradar el rendimiento while cnt_title < cnt_tot * cnt_pct and fin > time.time(): # Descarga la página data = '' try: data = re.sub( r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(next_page_url, timeout=timeout_search).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") 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' )) break #si no hay más datos, algo no funciona, pintamos lo que tenemos #Patrón para todo, menos para Alfabeto if item.extra == 'search': patron = '<div class="moditemfdb"><a title="([^"]+)"\s+href="([^"]+)"><img.*?class="thumbnailresult" src="([^"]+)"\/><\/a>' elif item.extra2 == 'categorias': patron = '<div class="blogitem "><a href="([^"]+)".*?src="([^"]+)" alt.*?title="([^"]+)">' else: patron = '<div class="blogitem "><a title="([^"]+)"\s+href="([^"]+)">.*?src="([^"]+)" onload' matches = re.compile(patron, re.DOTALL).findall(data) if not matches and not 'Total: 0 resultados encontrados' in data and not 'Total: 0 results found' in data: 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: 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' )) break #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) #Buscamos la url de paginado y la última página patron = '<a href="([^"]+=(\d+))" title="Next">Next<\/a>' if not scrapertools.find_single_match(data, patron): patron = '<a href="([^"]+=(\d+))" title="Siguiente">Siguiente<\/a>' try: next_page_url, curr_page = scrapertools.find_single_match( data, patron) curr_page = int(curr_page) / len(matches) except: #Si no lo encuentra, lo ponemos a 1 #logger.error('ERROR 03: LISTADO: Al obtener la paginación: ' + patron + ' / ' + data) fin = 0 #Forzamos a salir del WHILE al final del FOR cnt_title = 0 #Evitamos pié de página curr_page = 1 next_page_url = item.url next_page_url = urlparse.urljoin(host, next_page_url) #logger.debug('curr_page: ' + str(curr_page) + ' / url: ' + next_page_url) #Empezamos el procesado de matches for scrapedtitle, scrapedurl, scrapedthumb in matches: if item.extra2 == 'categorias': #Cambia el orden de tres parámetros (Categorías) title = scrapedthumb url = urlparse.urljoin(host, scrapedtitle) thumb = scrapedurl else: #lo estándar title = scrapedtitle url = urlparse.urljoin(host, scrapedurl) thumb = scrapedthumb quality = scrapertools.find_single_match( title, '\[(.*?)\]') #capturamos quality title = re.sub(r'\[.*?\]', '', title) #y lo borramos de title title = title.replace("á", "a").replace("é", "e").replace( "í", "i").replace("ó", "o").replace("ú", "u").replace( "ü", "u").replace("�", "ñ").replace("ñ", "ñ").replace( "ã", "a").replace("&etilde;", "e").replace( "ĩ", "i").replace("õ", "o").replace( "ũ", "u").replace("ñ", "ñ").replace("’", "'") item_local = item.clone() #Creamos copia de Item para trabajar if item_local.tipo: #... y limpiamos del item_local.tipo if item_local.totalItems: del item_local.totalItems if item_local.post_num: del item_local.post_num if item_local.intervencion: del item_local.intervencion if item_local.viewmode: del item_local.viewmode item_local.text_bold = True del item_local.text_bold item_local.text_color = True del item_local.text_color title_subs = [] #creamos una lista para guardar info importante item_local.language = [] #iniciamos Lenguaje item_local.quality = quality #guardamos la calidad, si la hay item_local.url = url #guardamos el thumb item_local.thumbnail = thumb #guardamos el thumb item_local.context = "['buscar_trailer']" item_local.contentType = "movie" #por defecto, son películas item_local.action = "findvideos" #Ajustamos los idiomas if ("-latino-" in url.lower() or "(latino)" in title.lower()) and "LAT" not in item_local.language: item_local.language += ['LAT'] elif ('-vos-' in url.lower() or '-vose-' in url.lower() or '(vos)' in title.lower() or '(vose)' in title.lower()) and "VOSE" not in item_local.language: item_local.language += ['VOSE'] elif ('-vo-' in url.lower() or '(vo)' in title.lower()) and "VO" not in item_local.language: item_local.language += ['VO'] if item_local.language == []: item_local.language = ['CAST'] #Por defecto title = re.sub(r'\(.*?\)', '', title) #Limpiamos del idioma de title #Detectamos info interesante a guardar para después de TMDB if scrapertools.find_single_match(title, '[m|M].*?serie'): title = re.sub(r'[m|M]iniserie', '', title) title_subs += ["Miniserie"] if scrapertools.find_single_match(title, '[s|S]aga'): title = re.sub(r'[s|S]aga', '', title) title_subs += ["Saga"] if scrapertools.find_single_match(title, '[c|C]olecc'): title = re.sub(r'[c|C]olecc...', '', title) title_subs += ["Colección"] if "duolog" in title.lower(): title_subs += ["[Saga]"] title = title.replace(" Duologia", "").replace( " duologia", "").replace(" Duolog", "").replace(" duolog", "") if "trilog" in title.lower(): title_subs += ["[Saga]"] title = title.replace(" Trilogia", "").replace( " trilogia", "").replace(" Trilog", "").replace(" trilog", "") if "extendida" in title.lower() or "v.e." in title.lower( ) or "v e " in title.lower(): title_subs += ["[V. Extendida]"] title = title.replace("Version Extendida", "").replace( "(Version Extendida)", "").replace("V. Extendida", "").replace("VExtendida", "").replace( "V Extendida", "").replace("V.Extendida", "").replace( "V Extendida", "").replace("V.E.", "").replace( "V E ", "").replace("V:Extendida", "") item_local.infoLabels["year"] = '-' #Reseteamos el año para TMDB #Limpiamos el título de la basura innecesaria title = re.sub(r'- $', '', title) title = re.sub( r'(?i)TV|Online|Spanish|Torrent|en Espa\xc3\xb1ol|Español|Latino|Subtitulado|Blurayrip|Bluray rip|\[.*?\]|R2 Pal|\xe3\x80\x90 Descargar Torrent \xe3\x80\x91|Completa|Temporada|Descargar|Torren', '', title) #Terminamos de limpiar el título title = re.sub(r'\??\s?\d*?\&.*', '', title) title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').strip().lower().title() item_local.from_title = title.strip().lower().title( ) #Guardamos esta etiqueta para posible desambiguación de título #Salvamos el título según el tipo de contenido if item_local.contentType == "movie": item_local.contentTitle = title.strip().lower().title() else: item_local.contentSerieName = title.strip().lower().title() item_local.title = title.strip().lower().title( ) #Guardamos el título #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB item_local.title_subs = title_subs #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting( 'filter_languages', channel) > 0: #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 cnt_title = len(itemlist) #Contador de líneas añadidas #logger.debug(item_local) #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Si es necesario añadir paginacion if cnt_title >= cnt_tot * cnt_pct: title = '%s' % curr_page itemlist.append( Item(channel=item.channel, action="listado", title=">> Página siguiente " + title, url=next_page_url, extra=item.extra, extra2=item.extra2)) return itemlist
def calidades(item): logger.info() itemlist = [] data = '' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass patron = '<div align="[^"]+"><div style="[^"]+" id="divadvsearch">(.*?)<\/a><\/div><\/div><\/form><\/div>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): status, itemlist = check_blocked_IP( data, itemlist) #Comprobamos si la IP ha sido bloqueada if status: return itemlist #IP bloqueada 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 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append( item.clone( action='', title=item.category + ': ERROR 01: SUBMENU: 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 data = scrapertools.find_single_match(data, patron) #Seleccionamos el bloque patron = '<div class="divadvscat"><input class="inputadvscat" type="checkbox" name="category\[.*?\]" value="[^"]+"\s*(?:.*?)?\/> <a href="([^"]+)">(.*?)<\/a>\s*<\/div>\s*' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': 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 #logger.debug(patron) #logger.debug(matches) #logger.debug(data) itemlist.append( item.clone(action="listado", title="ALL", extra2="calidades")) for scrapedurl, scrapedtitle in matches: if not "Mov" in scrapedtitle and item.extra == 'peliculas': continue if not "TV" in scrapedtitle and item.extra == 'series': continue title = scrapedtitle.strip().replace('Movs/', '').replace('Movies/', '') url = urlparse.urljoin(host, scrapedurl + "&search=&order=data&by=DESC") itemlist.append( item.clone(action="listado", title=title, url=url, extra2="calidades")) return itemlist
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 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 listado(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial last_title = 99999 # Última línea inicial cnt_matches = 0 # Contador de líneas insertadas en Itemlist if item.curr_page: curr_page = int( item.curr_page) # Si viene de una pasada anterior, lo usamos del item.curr_page # ... y lo borramos if item.last_page: last_page = int( item.last_page) # Si viene de una pasada anterior, lo usamos del item.last_page # ... y lo borramos if item.cnt_matches: cnt_matches = int( item.cnt_matches) # Si viene de una pasada anterior, lo usamos item.cnt_matches = 0 del item.cnt_matches # ... y lo borramos cnt_tot = 40 # Poner el num. máximo de items por página cnt_pct = 0.625 #% de la página a llenar cnt_title = 0 # Contador de líneas insertadas en Itemlist inicio = time.time( ) # Controlaremos que el proceso no exceda de un tiempo razonable fin = inicio + 10 # 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 item.tmdb_stat = True # Este canal no es ambiguo en los títulos #Sistema de paginado para evitar páginas vacías o semi-vacías en casos de búsquedas con series con muchos episodios title_lista = [ ] # Guarda la lista de series que ya están en Itemlist, para no duplicar lineas if item.title_lista: # Si viene de una pasada anterior, la lista ya estará guardada title_lista.extend( item.title_lista) # Se usa la lista de páginas anteriores en Item del item.title_lista # ... limpiamos if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' next_page_url = item.url #Máximo num. de líneas permitidas por TMDB. Máx de 10 segundos por Itemlist para no degradar el rendimiento while cnt_title < cnt_tot * cnt_pct and cnt_matches + 1 < last_title and fin > time.time( ): # Descarga la página data = '' try: data = httptools.downloadpage(next_page_url, timeout=timeout_search).data data = unicode(data, "utf-8", errors="replace").encode("utf-8") pos = data.find('[') if pos > 0: data = data[pos:] 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' )) break #si no hay más datos, algo no funciona, pintamos lo que tenemos matches = jsontools.load(data) #cargamos lo datos como dict. if not matches and data[1] != ']': #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: LISTADO: Ha cambiado la estructura de la Web " + 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 last_title = len(matches) #Tamaño de total matches matches = matches[cnt_matches:] #avanzamos hasta la página actual #logger.debug(matches) #logger.debug(data) if last_page == 99999: #Si es el valor inicial, cargamos el num. de items last_page = int((last_title / (cnt_tot * cnt_pct))) curr_page = 1 #Empezamos el procesado de matches for titulo in matches: cnt_title += 1 #Sumamos 1 a los títulos tratados if cnt_title > cnt_tot * cnt_pct: cnt_title += last_title break cnt_matches += 1 #Sumamos 1 a total títulos tratados title = titulo.get("nom", "") #nombre del título title = title.replace("á", "a").replace("é", "e").replace( "í", "i").replace("ó", "o").replace("ú", "u").replace( "ü", "u").replace("�", "ñ").replace("ñ", "ñ").replace( "ã", "a").replace("&etilde;", "e").replace( "ĩ", "i").replace("õ", "o").replace( "ũ", "u").replace("ñ", "ñ").replace("’", "'") item_local = item.clone() #Creamos copia de Item para trabajar if item_local.tipo: #... y limpiamos del item_local.tipo if item_local.totalItems: del item_local.totalItems if item_local.post_num: del item_local.post_num if item_local.intervencion: del item_local.intervencion if item_local.viewmode: del item_local.viewmode item_local.text_bold = True del item_local.text_bold item_local.text_color = True del item_local.text_color if titulo.get("posterurl", ""): item_local.thumbnail = "http://image.tmdb.org/t/p/w342%s" % titulo.get( "posterurl", "") #thumb if titulo.get("backurl", ""): item_local.fanart = "http://image.tmdb.org/t/p/w1280%s" % titulo.get( "backurl", "") #Fanart url = titulo.get("magnets", {}) #magnet de diversas calidades year = titulo.get("year", "") #año if titulo.get("id", ""): item_local.infoLabels["tmdb_id"] = titulo.get("id", "") #TMDB id title_subs = [] #creamos una lista para guardar info importante item_local.language = [] #iniciamos Lenguaje item_local.quality = '' #inicialmos la calidad item_local.context = "['buscar_trailer']" item_local.contentType = "movie" #por defecto, son películas item_local.action = "findvideos" #Analizamos los formatos de series if item_local.extra == 'series': item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = True #Muestra las series agrupadas por temporadas item_local.url = "%s?id=%s" % (api_temp, titulo.get( "id", "")) #Salvamos la url special para series #Revisamos para peliculas todos los magnets, extrayendo dirección y calidad if item_local.contentType == "movie": item_local.url = [] #iniciamos dict. de magnets for etiqueta, magnet in titulo.get("magnets", {}).iteritems(): if magnet.get("magnet"): #buscamos los magnets activos url = magnet.get("magnet") #salvamos el magnet quality = magnet.get( "quality", "") #salvamos la calidad del magnet item_local.url += [ (url, quality) ] #guardamos todo como url para findvideos item_local.quality += "%s, " % quality.strip( ) #agregamos a la calidad del título item_local.quality = re.sub(r', $', '', item_local.quality) if not item_local.url: #si no hay magnets, no seguimos continue if item_local.language == []: item_local.language = ['CAST'] #Detectamos info interesante a guardar para después de TMDB if scrapertools.find_single_match(title, '[m|M].*?serie'): title = re.sub(r'[m|M]iniserie', '', title) title_subs += ["Miniserie"] if scrapertools.find_single_match(title, '[s|S]aga'): title = re.sub(r'[s|S]aga', '', title) title_subs += ["Saga"] if scrapertools.find_single_match(title, '[c|C]olecc'): title = re.sub(r'[c|C]olecc...', '', title) title_subs += ["Colección"] if "duolog" in title.lower(): title_subs += ["[Saga]"] title = title.replace(" Duologia", "").replace( " duologia", "").replace(" Duolog", "").replace(" duolog", "") if "trilog" in title.lower(): title_subs += ["[Saga]"] title = title.replace(" Trilogia", "").replace( " trilogia", "").replace(" Trilog", "").replace(" trilog", "") if "extendida" in title.lower() or "v.e." in title.lower( ) or "v e " in title.lower(): title_subs += ["[V. Extendida]"] title = title.replace("Version Extendida", "").replace( "(Version Extendida)", "").replace("V. Extendida", "").replace("VExtendida", "").replace( "V Extendida", "").replace("V.Extendida", "").replace( "V Extendida", "").replace("V.E.", "").replace( "V E ", "").replace("V:Extendida", "") #Analizamos el año. Si no está claro ponemos '-' try: yeat_int = int(year) if yeat_int >= 1950 and yeat_int <= 2040: item_local.infoLabels["year"] = yeat_int else: item_local.infoLabels["year"] = '-' except: item_local.infoLabels["year"] = '-' #Empezamos a limpiar el título en varias pasadas title = re.sub(r'[s|S]erie', '', title) title = re.sub(r'- $', '', title) #Limpiamos el título de la basura innecesaria title = re.sub( r'(?i)TV|Online|Spanish|Torrent|en Espa\xc3\xb1ol|Español|Latino|Subtitulado|Blurayrip|Bluray rip|\[.*?\]|R2 Pal|\xe3\x80\x90 Descargar Torrent \xe3\x80\x91|Completa|Temporada|Descargar|Torren', '', title) #Terminamos de limpiar el título title = re.sub(r'\??\s?\d*?\&.*', '', title) title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').strip().lower().title() item_local.from_title = title.strip().lower().title( ) #Guardamos esta etiqueta para posible desambiguación de título #Salvamos el título según el tipo de contenido if item_local.contentType == "movie": item_local.contentTitle = title.strip().lower().title() else: item_local.contentSerieName = title.strip().lower().title() item_local.title = title.strip().lower().title() #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB item_local.title_subs = title_subs #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting( 'filter_languages', channel) > 0: #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 #logger.debug(item_local) #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Si es necesario añadir paginacion if cnt_title >= cnt_tot * cnt_pct: title = '%s' % curr_page if cnt_matches + 1 >= last_title: #Si hemos pintado ya todo lo de esta página... cnt_matches = 0 #... la próxima pasada leeremos otra página next_page_url = re.sub( r'page=(\d+)', r'page=' + str(int(re.search('\d+', next_page_url).group()) + 1), next_page_url) itemlist.append( Item(channel=item.channel, action="listado", title=">> Página siguiente " + title, url=next_page_url, extra=item.extra, extra2=item.extra2, last_page=str(last_page), curr_page=str(curr_page + 1), cnt_matches=str(cnt_matches))) return itemlist
def findvideos(item): logger.info() itemlist = [] #Bajamos los datos de la página 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: 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 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 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 return itemlist #Salimos 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) if size: 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 #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