def listado(item): logger.info() itemlist = [] title_subs = [] item.category = categoria thumb_pelis = get_thumb("channels_movie.png") thumb_series = get_thumb("channels_tvshow.png") #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial last_page_print = 1 # Última página inicial, para píe de página page_factor = 1.0 # Factor de conversión de pag. web a pag. Alfa 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.page_factor: page_factor = float( item.page_factor) # Si viene de una pasada anterior, lo usamos del item.page_factor # ... y lo borramos if item.last_page_print: last_page_print = item.last_page_print # Si viene de una pasada anterior, lo usamos del item.last_page_print # ... y lo borramos cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist if item.cnt_tot_match: cnt_tot_match = float( item.cnt_tot_match ) # restauramos el contador TOTAL de líneas procesadas de matches del item.cnt_tot_match else: cnt_tot_match = 0.0 # Contador TOTAL de líneas procesadas de matches 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 * 2 # Timeout para descargas #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 matches = [] post = None forced_proxy_opt = None referer = item.url if item.post: # Rescatamos el Post, si lo hay post = item.post forced_proxy_opt = None if item.referer: referer = item.referer patron_canonical = 'rel="?canonical"?\s*href="?([^"|>]+)["|>|\s*]' next_page_url = item.url #Máximo num. de líneas permitidas por TMDB. Máx de 5 segundos por Itemlist para no degradar el rendimiento while (cnt_title < cnt_tot and curr_page <= last_page and fin > time.time()) or item.matches: # Descarga la página data = '' cnt_match = 0 # Contador de líneas procesadas de matches if not item.matches: # si no viene de una pasada anterior, descargamos data, response, item, itemlist = generictools.downloadpage( next_page_url, timeout=timeout_search, post=post, s2=False, canonical=canonical, forced_proxy_opt=forced_proxy_opt, referer=referer, item=item, itemlist=itemlist) # Descargamos la página) # Verificamos si ha cambiado el Host if response.host: next_page_url = response.url_new if scrapertools.find_single_match(data, patron_canonical): next_page_url = scrapertools.find_single_match( data, patron_canonical) if not 'page/' in next_page_url: if curr_page == 1: next_page_url += 'page/1/' else: next_page_url += 'page/%s/' % curr_page referer = next_page_url curr_page += 1 #Apunto ya a la página siguiente if not data: #Si la web está caída salimos sin dar error if len(itemlist) > 1: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist # Si no hay nada más, salimos directamente patron = '<div id="principal">.*?<\/nav><\/div><\/div>' data = scrapertools.find_single_match(data, patron) patron = '<li>\s*<div\s*class="[^"]+"\s*>\s*<a\s*href="([^"]+)"\s*' patron += 'title="([^"]+)"\s*(?:alt="[^"]+")?\s*>\s*<img\s*(?:class="[^"]+")?' patron += '\s*src="([^"]+)".*?border="[^"]+"\s*title="([^"]+)".*?<span\s*class="[^"]+"' patron += '\s*id="[^"]+"\s*>\s*<i>\s*<img\s*src="[^"]+"\s*data-src="[^"]+\/(\w+).png"' patron += '.*?<span\s*class="[^"]+"\s*style="[^"]+"\s*>\s*<i>(.*?)?<\/i>' patron += '(?:<\/span.*?="dig1"\s*>(.*?)?)?(?:<.*?="dig2">(.*?)?)?<\/span>\s*<\/div>' if not item.matches: # De pasada anterior o desde Novedades? matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches del item.matches if not matches and len( itemlist) > 0: # Página vacía pero hay algo que pintar last_page = 0 break if not matches and not '<title>503 Backend fetch failed</title>' in data and not 'No se han encontrado resultados' in data: 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 página next_page_url = re.sub(r'page\/(\d+)', 'page/%s' % str(curr_page), next_page_url) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page) + ' / page_factor: ' + str(page_factor)) #Buscamos la última página if last_page == 99999: # Si es el valor inicial, buscamos patron_last = '(?i)siguiente[^<]*<\/a>\s*<a\s*href="[^"]+\/(\d+)\/[^"]*"' if not scrapertools.find_single_match(data, patron_last): patron_last = 'class="pagina">(\d+)<\/a>\s*<\/div>' try: last_page = int( scrapertools.find_single_match(data, patron_last)) page_factor = float(len(matches)) / float(cnt_tot) except: # Si no lo encuentra, lo ponemos a 999 last_page = 999 #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page) + ' / page_factor: ' + str(page_factor)) for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedcategory, scrapedlang, \ scrapedcalidad, scrapedsize, scrapedsizet in matches: cnt_match += 1 item_local = item.clone() # Creamos copia de Item para trabajar title = scrapedtitle.replace(" torrent", "").replace( " Torrent", "").replace("Series y ", "") item_local.url = urlparse.urljoin(host, scrapedurl) item_local.thumbnail = urlparse.urljoin(host, scrapedthumbnail) if "---" in scrapedcalidad: # limpiamos calidades scrapedcalidad = '' if "microhd" in title.lower(): item_local.quality = "microHD" if not "/series-vose/" in item.url and not item_local.quality: item_local.quality = scrapedcalidad if scrapertools.find_single_match(item_local.quality, r'\d+\.\d+'): item_local.quality = '' if not item_local.quality and ("DVDRip" in title or "HDRip" in title \ or "BR-LINE" in title or "HDTS-SCREENER" in title \ or "BDRip" in title or "BR-Screener" in title \ or "DVDScreener" in title or "TS-Screener" in title): item_local.quality = scrapertools.find_single_match( title, r'\((.*?)\)') item_local.quality = item_local.quality.replace("Latino", "") if not scrapedsizet or "---" in scrapedsizet: scrapedsize = '' else: item_local.quality += ' [%s %s]' % (scrapedsize.replace( ".", ","), scrapedsizet) item_local.language = [ ] # Verificamos el idioma por si encontramos algo if "latino" in scrapedlang.lower( ) or "latino" in item.url or "latino" in title.lower(): item_local.language += ["LAT"] if scrapedlang.lower() in ['vos', 'vose'] or "vose" in item.url or "vos" in item.url \ or "vose" in scrapedurl or "vos" in scrapedurl or "subt" in title.lower(): item_local.language += ["VOSE"] elif scrapedlang.lower() in ['ingles', 'inglés', 'english', 'original', 'vo'] or "ingles" in item.url \ or "vo" in item.url or "ingles" in scrapedurl or "vo" in scrapedurl: item_local.language += ["VO"] if item_local.language == []: item_local.language = ['CAST'] # Por defecto if "dual" in scrapedlang.lower() or "dual" in title.lower(): item_local.language[0:0] = ["DUAL"] #Limpiamos el título de la basura innecesaria title = title.replace("Dual", "").replace("dual", "").replace( "Subtitulada", "").replace("subtitulada", "").replace("Subt", "").replace( "subt", "").replace("Sub", "").replace("sub", "").replace( "(Proper)", "").replace("(proper)", "").replace( "Proper", "").replace("proper", "").replace( "#", "").replace("(Latino)", "").replace("Latino", "") title = title.replace("- HDRip", "").replace( "(HDRip)", "").replace("- Hdrip", "").replace("(microHD)", "").replace( "(DVDRip)", "").replace("(HDRip)", "").replace( "(BR-LINE)", "").replace("(HDTS-SCREENER)", "").replace( "(BDRip)", "").replace("(BR-Screener)", "").replace( "(DVDScreener)", "").replace("TS-Screener", "").replace( " TS", "").replace(" Ts", "").replace( "temporada", "").replace("Temporada", "").replace( "capitulo", "").replace("Capitulo", "") title = re.sub(r'(?i)\s*S\d+E\d+', '', title) 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 title_subs = [] # Creamos una lista para guardar info importante 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+)') if scrapertools.find_single_match(scrapedtitle, r'(?i)\s*S(\d+)E(\d+)'): item_local.contentSeason, item_local.contentEpisodeNumber = scrapertools.find_single_match( scrapedtitle, r'(?i)\s*S(\d+)E(\d+)') else: 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+)') try: if not item_local.contentSeason: item_local.contentSeason = 0 if not item_local.contentEpisodeNumber: item_local.contentEpisodeNumber = 1 item_local.contentSeason = int(item_local.contentSeason) item_local.contentEpisodeNumber = int( item_local.contentEpisodeNumber) except: pass if not item_local.contentSeason or item_local.contentSeason < 1: item_local.contentSeason = 0 if item_local.contentEpisodeNumber < 1: item_local.contentEpisodeNumber = 1 #title_subs += ['Episodio %sx%s' % (item_local.contentSeason, str(item_local.contentEpisodeNumber).zfill(2))] title_subs += [' (MAX_EPISODIOS)'] 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'] = "-" #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 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 cnt_title = len( itemlist) # Recalculamos los items después del filtrado if cnt_title >= cnt_tot and ( len(matches) - cnt_match ) + cnt_title > cnt_tot * 1.3: #Contador de líneas añadidas break #logger.debug(item_local) matches = matches[cnt_match:] # Salvamos la entradas no procesadas cnt_tot_match += cnt_match # Calcular el num. total de items mostrados #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda=idioma_busqueda) #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 or len(matches) > 0: curr_page_print = int(cnt_tot_match / float(cnt_tot)) if curr_page_print < 1: curr_page_print = 1 if last_page: if last_page > 1: last_page_print = int((last_page * page_factor) + 0.999999) title = '%s de %s' % (curr_page_print, last_page_print) else: title = '%s' % curr_page_print 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), page_factor=str(page_factor), cnt_tot_match=str(cnt_tot_match), matches=matches, last_page_print=last_page_print, post=post, referer=referer)) 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'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, flags=re.IGNORECASE) #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 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="([^"]+)"\s*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: 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) 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) 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 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("’", "'") 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 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 listado(item): # Listado principal y de búsquedas logger.info() itemlist = [] item.category = categoria thumb_pelis = get_thumb("channels_movie.png") thumb_series = get_thumb("channels_tvshow.png") #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial last_page_print = 1 # Última página inicial, para píe de página page_factor = 1.0 # Factor de conversión de pag. web a pag. Alfa 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.page_factor: page_factor = float( item.page_factor) # Si viene de una pasada anterior, lo usamos del item.page_factor # ... y lo borramos if item.last_page_print: last_page_print = item.last_page_print # Si viene de una pasada anterior, lo usamos del item.last_page_print # ... y lo borramos cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist if item.cnt_tot_match: cnt_tot_match = float( item.cnt_tot_match ) # restauramos el contador TOTAL de líneas procesadas de matches del item.cnt_tot_match else: cnt_tot_match = 0.0 # Contador TOTAL de líneas procesadas de matches 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 * 2 # Timeout para descargas if item.extra == 'search' and item.extra2 == 'episodios': # Si viene de episodio que quitan los límites cnt_tot = 999 fin = inicio + 30 #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 matches = [] if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' post = None headers = None forced_proxy_opt = None if item.post: forced_proxy_opt = None if item.post or item.post is None: # Rescatamos el Post, si lo hay post = item.post del item.post if item.headers or item.headers is None: # Rescatamos el Headers, si lo hay headers = item.headers del item.headers next_page_url = item.url # Máximo num. de líneas permitidas por TMDB. Máx de 5 segundos por Itemlist para no degradar el rendimiento while (cnt_title < cnt_tot and curr_page <= last_page and fin > time.time()) or item.matches: # Descarga la página data = '' cnt_match = 0 # Contador de líneas procesadas de matches if not item.matches: # si no viene de una pasada anterior, descargamos data, response, item, itemlist = generictools.downloadpage( next_page_url, canonical=canonical, headers=headers, timeout=timeout_search, post=post, s2=False, item=item, itemlist=itemlist) # Descargamos la página) # Verificamos si ha cambiado el Host if response.host: next_page_url = response.url_new # Verificamos si se ha cargado una página correcta curr_page += 1 # Apunto ya a la página siguiente if not data or not response.sucess: # Si la web está caída salimos sin dar error if len(itemlist) > 1: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist # Si no hay nada más, salimos directamente headers = {'referer': next_page_url} #Patrón para búsquedas, pelis y series patron = '<div\s*class="item hitem">\s*<a\s*href="([^"]+)">.*?' patron += '(?:<div\s*class="nota">\s*(.*?)\s*<\/div>)?\s*<img[^>]*src="([^"]+)"' patron += '.*?<div\s*class="titulo">\s*<span>\s*([^<]*)<\/span>' if not item.matches: # De pasada anterior? matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches del item.matches #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) if not matches and item.extra != 'search' and not item.extra2: #error logger.error( "ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) 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 if len(itemlist) > 0: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist #Salimos # Buscamos la próxima página next_page_url = re.sub(r'page\/(\d+)', 'page/%s' % str(curr_page), item.url) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) # Buscamos la última página if last_page == 99999: #Si es el valor inicial, buscamos patron_last = 'Last\s*Page"\s*href="[^"]+\/(\d*)\/"' if not scrapertools.find_single_match(data, patron_last): patron_last = 'href="[^"]+">(\d+)<\/a>(?:<span[^<]*<\/span>)?\s*<a[^>]*aria-label="Next\s*Page"' try: last_page = int( scrapertools.find_single_match(data, patron_last)) page_factor = float(len(matches)) / float(cnt_tot) except: #Si no lo encuentra, lo ponemos a 999 last_page = 1 last_page_print = int((float(len(matches)) / float(cnt_tot)) + 0.999999) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) #Empezamos el procesado de matches for scrapedurl, scrapedlang, scrapedthumb, scrapedtitle in matches: cnt_match += 1 title = scrapedtitle title = scrapertools.remove_htmltags(title).rstrip( '.') # Removemos Tags del título url = scrapedurl title_subs = [] #creamos una lista para guardar info importante # 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) cnt_title += 1 # Incrementamos el contador de entradas válidas 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 item_local.headers = headers # Tratamos los idiomas if scrapedlang: item_local.language = [] langs = scrapedlang.split('>') logger.error(langs) for lang in langs: if not lang: continue if 'espanol' in lang: item_local.language += ['CAST'] elif 'latin' in lang: item_local.language += ['LAT'] elif 'english' in lang or 'ingles' in lang: item_local.language += ['VO'] else: item_local.language += ['OTHER'] if not item_local.language: item_local.language = ['CAST'] # [CAST] por defecto if not item_local.quality: item_local.quality = 'DVDR' # DVDR por defecto item_local.thumbnail = urlparse.urljoin( host, scrapedthumb) # iniciamos thumbnail item_local.url = urlparse.urljoin(host, url) # guardamos la url final item_local.context = "['buscar_trailer']" # ... y el contexto # Guardamos los formatos para películas item_local.contentType = "movie" item_local.action = "findvideos" title = re.sub( r'(?i)TV|Online|(4k-hdr)|(fullbluray)|4k| - 4k|(3d)|miniserie|ciclo\s*[^-|–]+[-|–]\s*', '', title).strip() item_local.quality = re.sub( r'(?i)proper|unrated|directors|cut|repack|internal|real|extended|masted|docu|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() # Analizamos el año. Si no está claro ponemos '-' item_local.infoLabels["year"] = '-' # Terminamos de limpiar el título title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').replace( '[4K]', '').replace('(4K)', '').strip().lower().title() title = title.strip().lower().title() item_local.from_title = title #Guardamos esta etiqueta para posible desambiguación de título item_local.contentTitle = title item_local.title = 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 filter_languages > 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) # Recalculamos los items después del filtrado if cnt_title >= cnt_tot and ( len(matches) - cnt_match ) + cnt_title > cnt_tot * 1.3: #Contador de líneas añadidas break #logger.debug(item_local) matches = matches[cnt_match:] # Salvamos la entradas no procesadas cnt_tot_match += cnt_match # Calcular el num. total de items mostrados #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda=idioma_busqueda) #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 or len(matches) > 0: curr_page_print = int(cnt_tot_match / float(cnt_tot)) if curr_page_print < 1: curr_page_print = 1 if last_page: if last_page > 1: last_page_print = int((last_page * page_factor) + 0.999999) title = '%s de %s' % (curr_page_print, last_page_print) else: title = '%s' % curr_page_print 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), page_factor=str(page_factor), cnt_tot_match=str(cnt_tot_match), matches=matches, last_page_print=last_page_print, post=post, headers=headers)) 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 + 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 #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.45 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, "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 #Patrón para todo, menos para Series completas, incluido búsquedas en cualquier caso patron = '<tr><td(?: class="[^"]+")?><a href="([^"]+)".?title="([^"]+)".*?<\/a><\/td><td(?: class="[^"]+")?>(?:<a href="[^"]+">)?(.*?)(?:<\/a>)?<\/td><td(?: class="[^"]+")?>.*?<\/td><td(?: class="[^"]+")?>(.*?)<\/td><\/tr>' #Si son series completas, ponemos un patrón especializado if item.extra == 'series': patron = '<div class="[^"]+"><p class="[^"]+"><a href="([^"]+)".?title="([^"]+)"><img src="([^"]+)".*?<a href=\'[^\']+\'.?title="([^"]+)".*?<\/p><\/div>' 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_next = "<ul class=\"pagination\">.*?\(current\).*?href='([^']+)'>(\d+)<\/a><\/li>" #patron_last = "<ul class=\"pagination\">.*?\(current\).*?href='[^']+'>\d+<\/a><\/li>.*?href='[^']+\/(\d+)\/(?:\?s=[^']+)?'><span aria-hidden='[^']+'>&\w+;<\/span><\/a><\/li><\/ul><\/nav><\/div><\/div><\/div>" patron_last = "<ul class=\"pagination\">.*?\(current\).*?href='[^']+'>\d+<\/a><\/li>.*?href='[^']+\/(\d+)\/(?:\?[^']+)?'>(?:\d+)?(?:<span aria-hidden='[^']+'>&\w+;<\/span>)?<\/a><\/li><\/ul><\/nav><\/div><\/div><\/div>" try: next_page_url, next_page = scrapertools.find_single_match( data, patron_next) next_page = int(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 try: last_page = int( scrapertools.find_single_match( data, 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 scrapedurl, scrapedtitle, cat_ppal, size in matches: if "/programas" in scrapedurl or "/otros" in scrapedurl: continue title = scrapedtitle url = scrapedurl 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("’", "'") extra = item.extra #Si es una búsqueda, convierte los episodios en Series completas, aptas para la Videoteca if extra == 'search' and '/series' in scrapedurl and not "Temp" in title and not "emporada" in title: if scrapedurl in title_lista: #Si ya hemos procesado la serie, pasamos de los episodios adicionales continue # Descarga la página del episodio, buscando el enlace a la serie completa data_serie = '' try: data_serie = re.sub( r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(scrapedurl, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: pass if not data_serie: #Si la web está caída salimos sin dar error. Pintamos el episodio logger.error( "ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + scrapedurl + " / SERIE: " + scrapedurl) else: patron_serie = '<div id="where_i_am">.*?<a href="[^"]+">.*?<\/a>.*?<a href="([^"]+)">' url = scrapertools.find_single_match( data_serie, patron_serie) #buscamos la url de la serie completa if url: url = host + url extra = 'series' #es una serie completa title_lista += [ scrapedurl ] #la añadimos a la lista de series completas procesadas title = scrapedurl #salvamos el título de la serie completa else: url = scrapedurl #No se encuentra la Serie, se trata como Episodio suelto 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.post_num: del item_local.post_num 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 if item_local.url_plus: del item_local.url_plus title_subs = [] #creamos una lista para guardar info importante item_local.language = [] #creamos lista para los idiomas item_local.quality = '' #iniciamos calidad quality_alt = '' if 'series' in cat_ppal or extra == 'series': item_local.thumbnail = cat_ppal #si son series, contiene el thumb else: quality_alt = scrapedurl.lower().strip( ) #si no son series, contiene la calidad item_local.thumbnail = '' #guardamos el thumb item_local.extra = extra #guardamos el extra procesado item_local.url = url #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 '/peliculas/' in scrapedurl or item_local.extra == 'Películas': item_local.quality = 'HDRip ' elif '/peliculas-hd' in scrapedurl or item_local.extra == 'Películas HD': item_local.quality = 'HD ' elif '/peliculas-dvdr' in scrapedurl or item_local.extra == 'Películas DVDR': item_local.quality = 'DVDR ' elif 'subtituladas' in cat_ppal or item_local.extra == 'VOSE' or 'vose' in title.lower( ): item_local.language += ['VOSE'] elif 'Version Original' in cat_ppal or item_local.extra == 'VO' or 'vo' in title.lower( ): item_local.language += ['VO'] #Analizamos los formatos de series, temporadas y episodios elif '/series' in scrapedurl or item_local.extra == 'series': item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = True #Muestra las series agrupadas por temporadas elif item_local.extra == 'episodios': item_local.contentType = "episode" item_local.extra = "episodios" if "Temp" in title or "emporada" in title: try: item_local.contentSeason = int( scrapertools.find_single_match( title, '[t|T]emp.*?(\d+)')) except: item_local.contentSeason = 1 title = re.sub(r'[t|T]emp.*?\d+', '', title) title_subs += ["Temporada"] item_local.contentType = "season" item_local.extra = "season" if item_local.contentType == "movie": #para las peliculas ponemos el mismo extra item_local.extra = "peliculas" #Detectamos idiomas if "latino" in scrapedurl.lower() or "latino" in title.lower(): item_local.language += ['LAT'] elif "vose" in scrapedurl.lower() or "vos" in scrapedurl.lower( ) or "vose" in title.lower() or "vos" in title.lower(): item_local.language += ['VOSE'] if item_local.language == []: item_local.language = ['CAST'] #Detectamos el año patron = '(\d{4})\s*?(?:\)|\])?$' item_local.infoLabels["year"] = '-' year = '' year = scrapertools.find_single_match(title, patron) if year: title_alt = re.sub(patron, "", title) title_alt = title_alt.strip() if title_alt: title = title_alt 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 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 = 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", "").replace( "LATINO", "").replace("Spanish", "").replace( "Trailer", "").replace("Audio", "") title = title.replace("HDTV-Screener", "").replace( "DVDSCR", "").replace("TS ALTA", "").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(" 480p", "").replace( " 480P", "").replace( " 720p", "").replace( " 720P", "").replace(" 1080p", "").replace( " 1080P", "" ).replace( "DVDRip", "" ).replace( " Dvd", "").replace( " DVD", "").replace( " V.O", "" ).replace(" Unrated", "").replace( " UNRATED", "" ).replace(" unrated", "").replace( "screener", "" ).replace( "TS-SCREENER", "" ).replace( "TSScreener", "" ).replace( "HQ", "" ).replace( "AC3 5.1", "" ).replace("Telesync", "").replace( "Line Dubbed", "" ).replace( "line Dubbed", "" ).replace("LineDuB", "").replace( "Line", "" ).replace( "XviD", "" ).replace( "xvid", "" ).replace( "XVID", "" ).replace( "Mic Dubbed", "").replace( "HD", "" ).replace( "V2", "" ).replace("CAM", "").replace( "VHS.SCR", "" ).replace( "Dvd5", "" ).replace( "DVD5", "" ).replace("Iso", "").replace( "ISO", "").replace( "Reparado", "").replace( "reparado", "").replace( "DVD9", "").replace( "Dvd9", "") #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() if item_local.contentType == "episode": item_local.title = '%sx%s ' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) item_local.extra3 = 'completa' else: item_local.title = title.strip().lower().title() if scrapertools.find_single_match(size, '\d+.\d+\s?[g|G|m|M][b|B]'): size = size.replace('b', ' B').replace('B', ' B').replace( 'b', 'B').replace('g', 'G').replace('m', 'M').replace('.', ',') item_local.quality += '[%s]' % size #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'] itemlist.append(item_local.clone()) #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 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 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'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, flags=re.IGNORECASE) #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 listado(item): # Listado principal y de búsquedas logger.info() itemlist = [] item.category = categoria thumb_pelis = get_thumb("channels_movie.png") thumb_series = get_thumb("channels_tvshow.png") #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial last_page_print = 1 # Última página inicial, para píe de página page_factor = 1.0 # Factor de conversión de pag. web a pag. Alfa 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.page_factor: page_factor = float( item.page_factor) # Si viene de una pasada anterior, lo usamos del item.page_factor # ... y lo borramos if item.last_page_print: last_page_print = item.last_page_print # Si viene de una pasada anterior, lo usamos del item.last_page_print # ... y lo borramos cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist if item.cnt_tot_match: cnt_tot_match = float( item.cnt_tot_match ) # restauramos el contador TOTAL de líneas procesadas de matches del item.cnt_tot_match else: cnt_tot_match = 0.0 # Contador TOTAL de líneas procesadas de matches 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 * 2 # Timeout para descargas if item.extra == 'search' and item.extra2 == 'episodios': # Si viene de episodio que quitan los límites cnt_tot = 999 fin = inicio + 30 #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 matches = [] if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' post = None if item.post: # Rescatamos el Post, si lo hay post = item.post next_page_url = item.url # Máximo num. de líneas permitidas por TMDB. Máx de 5 segundos por Itemlist para no degradar el rendimiento while (cnt_title < cnt_tot and curr_page <= last_page and fin > time.time()) or item.matches: # Descarga la página data = '' cnt_match = 0 # Contador de líneas procesadas de matches if not item.matches: # si no viene de una pasada anterior, descargamos data, response, item, itemlist = generictools.downloadpage( next_page_url, timeout=timeout_search, post=post, s2=False, item=item, itemlist=itemlist) # Descargamos la página) # Verificamos si ha cambiado el Host global host, canonical if response.canonical and response.canonical != host: host, canonical = generictools.check_host( channel, [response.canonical] + host_alt, host_black_list, host='', CF=True, alfa_s=True, canonical=True) # Verificamos si se ha cargado una página correcta curr_page += 1 # Apunto ya a la página siguiente if not data or not response.sucess: # Si la web está caída salimos sin dar error if len(itemlist) > 1: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist # Si no hay nada más, salimos directamente if item.extra2 == 'PELICULA': #Patrón para seleccionar el bloque patron = '(?i)<header\s*class="archive_post">\s*<h2>\s*A.adido\s*recientemente\s*<\/h2>' patron += '\s*<span>\s*[^<]*\s*<\/span>\s*<\/header>\s*<div\s*id="archive-content"' patron += '\s*class="animation[^"]*">(.*?<\/article>\s*<\/div>' patron += '(?:\s*<div\s*class="pagination">.*?<\/div>))' data = scrapertools.find_single_match(data, patron) #logger.debug(data) #Patrón para búsquedas, pelis y series if item.extra == 'search': patron = '<article><div\s*class="image">.*?<img\s*src="([^"]+)".*?<span\s*' patron += 'class="movies">()[^<]*<\/span>.*?<a\s*href="([^"]+)">\s*([^<]*)' patron += '<\/a>\s*<\/div>\s*<div[^<]*<span[^<]*<\/span>\s*<span\s*' patron += 'class="year">\s*(?:(\d{4}))?\s*<\/span>' else: patron = '<article\s*id="post[^>]+>.*?<img\s*src="([^"]+)".*?<span\s*' patron += 'class="quality">\s*([^<]*)<\/span>.*?<h3>\s*<a\s*href="([^"]+)">' patron += '\s*([^<]*)<\/a>\s*<\/h3>\s*<span>(?:.*?(\d{4}))?\s*<\/span>' if not item.matches: # De pasada anterior? matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches del item.matches #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) if not matches and item.extra != 'search' and not item.extra2: #error logger.error( "ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) 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 if len(itemlist) > 0: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist #Salimos # Actualizado la url por si ha habido redirecciones if last_page == 99999: #Si es la primera pasada... patron_canonical = '<link\s*rel="canonical"\s*href="([^"]+)"\s*\/*>' if scrapertools.find_single_match(data, patron_canonical): canonical = scrapertools.find_single_match( data, patron_canonical) if not canonical.endswith('/'): canonical += '/' item.url = canonical + 'page/1/' # Buscamos la próxima página next_page_url = re.sub(r'page\/(\d+)', 'page/%s' % str(curr_page), item.url) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) # Buscamos la última página if last_page == 99999: #Si es el valor inicial, buscamos patron_last = '<div\s*class="pagination">\s*<span>P.gina\s*\d+\s*de\s*(\d+)\s*<\/span>' try: last_page = int( scrapertools.find_single_match(data, patron_last)) page_factor = float(len(matches)) / float(cnt_tot) except: #Si no lo encuentra, lo ponemos a 999 last_page = 1 last_page_print = int((float(len(matches)) / float(cnt_tot)) + 0.999999) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) #Empezamos el procesado de matches for scrapedthumb, scrapedquality, scrapedurl, scrapedtitle, scrapedyear in matches: scrapedlanguage = '' cnt_match += 1 title = scrapedtitle title = scrapertools.remove_htmltags(title).rstrip( '.') # Removemos Tags del título url = scrapedurl title_subs = [] #creamos una lista para guardar info importante # 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) cnt_title += 1 # Incrementamos el contador de entradas válidas 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 # Procesamos idiomas item_local.language = [] #creamos lista para los idiomas if '[Subs. integrados]' in scrapedquality or '(Sub Forzados)' in scrapedquality \ or 'Sub' in scrapedquality or 'ing' in scrapedlanguage.lower(): item_local.language = ['VOS'] # añadimos VOS if 'lat' in scrapedlanguage.lower(): item_local.language += ['LAT'] # añadimos LAT if 'castellano' in scrapedquality.lower() or ('español' in scrapedquality.lower() \ and not 'latino' in scrapedquality.lower()) or 'cas' in scrapedlanguage.lower(): item_local.language += ['CAST'] # añadimos CAST if '[Dual' in title or 'dual' in scrapedquality.lower( ) or 'dual' in scrapedlanguage.lower(): title = re.sub(r'(?i)\[dual.*?\]', '', title) item_local.language += ['DUAL'] # añadimos DUAL if not item_local.language: item_local.language = ['LAT'] # [LAT] por defecto # Procesamos Calidad if scrapedquality: item_local.quality = scrapertools.remove_htmltags( scrapedquality) # iniciamos calidad if '[720p]' in scrapedquality.lower( ) or '720p' in scrapedquality.lower(): item_local.quality = '720p' if '[1080p]' in scrapedquality.lower( ) or '1080p' in scrapedquality.lower(): item_local.quality = '1080p' if '4k' in scrapedquality.lower(): item_local.quality = '4K' if '3d' in scrapedquality.lower( ) and not '3d' in item_local.quality.lower(): item_local.quality += ', 3D' if not item_local.quality: item_local.quality = '1080p' item_local.thumbnail = urlparse.urljoin( host, scrapedthumb) #iniciamos thumbnail item_local.url = urlparse.urljoin(host, url) #guardamos la url final item_local.context = "['buscar_trailer']" #... y el contexto # Guardamos los formatos para películas item_local.contentType = "movie" item_local.action = "findvideos" title = re.sub( r'(?i)TV|Online|(4k-hdr)|(fullbluray)|4k| - 4k|(3d)|miniserie', '', title).strip() item_local.quality = re.sub( r'(?i)proper|unrated|directors|cut|repack|internal|real|extended|masted|docu|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Analizamos el año. Si no está claro ponemos '-' item_local.infoLabels["year"] = '-' try: if scrapedyear: item_local.infoLabels["year"] = int(scrapedyear) except: pass #Terminamos de limpiar el título title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').replace( '[4K]', '').replace('(4K)', '').strip().lower().title() title = title.strip().lower().title() item_local.from_title = title #Guardamos esta etiqueta para posible desambiguación de título item_local.contentTitle = title item_local.title = 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 filter_languages > 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) # Recalculamos los items después del filtrado if cnt_title >= cnt_tot and ( len(matches) - cnt_match ) + cnt_title > cnt_tot * 1.3: #Contador de líneas añadidas break #logger.debug(item_local) matches = matches[cnt_match:] # Salvamos la entradas no procesadas cnt_tot_match += cnt_match # Calcular el num. total de items mostrados #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda=idioma_busqueda) #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 or len(matches) > 0: curr_page_print = int(cnt_tot_match / float(cnt_tot)) if curr_page_print < 1: curr_page_print = 1 if last_page: if last_page > 1: last_page_print = int((last_page * page_factor) + 0.999999) title = '%s de %s' % (curr_page_print, last_page_print) else: title = '%s' % curr_page_print 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), page_factor=str(page_factor), cnt_tot_match=str(cnt_tot_match), matches=matches, last_page_print=last_page_print, post=post)) return itemlist
def listado(item): # Listado principal y de búsquedas logger.info() itemlist = [] item.category = categoria thumb_pelis = get_thumb("channels_movie.png") thumb_series = get_thumb("channels_tvshow.png") #logger.debug(item) curr_page = 1 # Página inicial last_page = 99999 # Última página inicial last_page_print = 1 # Última página inicial, para píe de página page_factor = 1.0 # Factor de conversión de pag. web a pag. Alfa 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.page_factor: page_factor = float(item.page_factor) # Si viene de una pasada anterior, lo usamos del item.page_factor # ... y lo borramos if item.last_page_print: last_page_print = item.last_page_print # Si viene de una pasada anterior, lo usamos del item.last_page_print # ... y lo borramos cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist if item.cnt_tot_match: cnt_tot_match = float(item.cnt_tot_match) # restauramos el contador TOTAL de líneas procesadas de matches del item.cnt_tot_match else: cnt_tot_match = 0.0 # Contador TOTAL de líneas procesadas de matches 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 * 2 # Timeout para descargas if item.extra == 'search' and item.extra2 == 'episodios': # Si viene de episodio que quitan los límites cnt_tot = 999 fin = inicio + 30 #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 matches = [] if not item.extra2: # Si viene de Catálogo o de Alfabeto item.extra2 = '' post = None if item.post: # Rescatamos el Post, si lo hay post = item.post next_page_url = item.url # Máximo num. de líneas permitidas por TMDB. Máx de 5 segundos por Itemlist para no degradar el rendimiento while (cnt_title < cnt_tot and curr_page <= last_page and fin > time.time()) or item.matches: # Descarga la página data = '' cnt_match = 0 # Contador de líneas procesadas de matches if not item.matches: # si no viene de una pasada anterior, descargamos data, success, code, item, itemlist = generictools.downloadpage(next_page_url, timeout=timeout_search, post=post, s2=False, item=item, itemlist=itemlist) # Descargamos la página) # Verificamos si se ha cargado una página correcta curr_page += 1 # Apunto ya a la página siguiente if not data or not success: # Si la web está caída salimos sin dar error if len(itemlist) > 1: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist # Si no hay nada más, salimos directamente #Patrón para búsquedas, pelis y series patron = '<div\s*class="[^"]+">\s*<div\s*class="card">\s*<a\s*href="([^"]+)"\s*' patron += 'class="card__cover">\s*<img\s*src="([^"]+)"\s*alt="[^"]*">\s*' patron += '<div\s*class="card__play">.*?<\/div>\s*<ul\s*class="card__list">\s*' patron += '<li>([^<]+)<\/li>\s*<\/ul>\s*<\/a>\s*<div\s*class="card__content">\s*' patron += '<h3\s*class="card__title"><a\s*href="[^"]+">([^<]+)<\/a><\/h3>' patron += '.*?<\/div>\s*<\/div>\s*<\/div>' if not item.matches: # De pasada anterior? matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches del item.matches #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) if not matches and item.extra != 'search' and not item.extra2: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) 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 if len(itemlist) > 0: # Si hay algo que pintar lo pintamos last_page = 0 break return itemlist #Salimos #Buscamos la próxima página next_page_url = re.sub(r'page\/(\d+)', 'page/%s' % str(curr_page), item.url) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) #Buscamos la última página if last_page == 99999: #Si es el valor inicial, buscamos patron_last = '<ul\s*class="pagination[^"]+">.*?<li>\s*<a\s*class="page-numbers"\s*href="[^"]+">' patron_last += '(\d+)<\/a><\/li>\s*<li>\s*<a\s*class="next page-numbers"\s*href="[^"]+">»<\/a><\/li>\s*<\/ul>' try: last_page = int(scrapertools.find_single_match(data, patron_last)) page_factor = float(len(matches)) / float(cnt_tot) except: #Si no lo encuentra, lo ponemos a 999 last_page = 1 last_page_print = int((float(len(matches)) / float(cnt_tot)) + 0.999999) #logger.debug('curr_page: ' + str(curr_page) + ' / last_page: ' + str(last_page)) #Empezamos el procesado de matches for scrapedurl, scrapedthumb, scrapedquality, scrapedtitle in matches: cnt_match += 1 title = scrapedtitle title = scrapertools.remove_htmltags(title).rstrip('.') # Removemos Tags del título url = scrapedurl title_subs = [] #creamos una lista para guardar info importante title = title.replace("á", "a").replace("é", "e").replace("í", "i")\ .replace("ó", "o").replace("ú", "u").replace("ü", "u")\ .replace("�", "ñ").replace("ñ", "ñ").replace("’", "'")\ .replace("&", "&") # Se filtran las entradas para evitar duplicados de Temporadas url_list = url if url_list in title_lista: #Si ya hemos procesado el título, lo ignoramos continue else: title_lista += [url_list] #la añadimos a la lista de títulos # Si es una búsqueda por años, filtramos por tipo de contenido if 'anno' in item.extra2 and item.extra == 'series' and '/serie' not in url: continue elif 'anno' in item.extra2 and item.extra == 'peliculas' and '/serie' in url: continue cnt_title += 1 # Incrementamos el contador de entradas válidas 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 # Después de un Search se restablecen las categorías if item_local.extra == 'search': if '/serie' in url: item_local.extra = 'series' # Serie búsqueda else: item_local.extra = 'peliculas' # Película búsqueda # Procesamos idiomas item_local.language = [] #creamos lista para los idiomas if '[Subs. integrados]' in scrapedquality or '(Sub Forzados)' in scrapedquality \ or 'Sub' in scrapedquality: item_local.language = ['VOS'] # añadimos VOS if 'castellano' in scrapedquality.lower() or ('español' in scrapedquality.lower() and not 'latino' in scrapedquality.lower()): item_local.language += ['CAST'] # añadimos CAST if '[Dual' in title or 'dual' in scrapedquality.lower(): title = re.sub(r'(?i)\[dual.*?\]', '', title) item_local.language += ['DUAL'] # añadimos DUAL if not item_local.language: item_local.language = ['LAT'] # [LAT] por defecto # Procesamos Calidad if scrapedquality: item_local.quality = scrapertools.remove_htmltags(scrapedquality) # iniciamos calidad if '[720p]' in scrapedquality.lower() or '720p' in scrapedquality.lower(): item_local.quality = '720p' if '[1080p]' in scrapedquality.lower() or '1080p' in scrapedquality.lower(): item_local.quality = '1080p' if '4k' in scrapedquality.lower(): item_local.quality = '4K' if '3d' in scrapedquality.lower() and not '3d' in item_local.quality.lower(): item_local.quality += ', 3D' if not item_local.quality or item_local.extra == 'series': item_local.quality = '720p' item_local.thumbnail = '' #iniciamos thumbnail item_local.url = urlparse.urljoin(host, url) #guardamos la url final item_local.context = "['buscar_trailer']" #... y el contexto # Guardamos los formatos para series if item_local.extra == 'series' or '/serie' in item_local.url: item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = season_colapse #Muestra las series agrupadas por temporadas? else: # Guardamos los formatos para películas item_local.contentType = "movie" item_local.action = "findvideos" #Limpiamos el título de la basura innecesaria if item_local.contentType == "tvshow": title = scrapertools.find_single_match(title, '(^.*?)\s*(?:$|\(|\[|-)') title = re.sub(r'(?i)TV|Online|(4k-hdr)|(fullbluray)|4k| - 4k|(3d)|miniserie', '', title).strip() item_local.quality = re.sub(r'(?i)proper|unrated|directors|cut|repack|internal|real|extended|masted|docu|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Analizamos el año. Si no está claro ponemos '-' item_local.infoLabels["year"] = '-' try: if 'anno' in item.extra2: item_local.infoLabels["year"] = int(item.extra2.replace('anno', '')) except: pass #Terminamos de limpiar el título title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').replace('[4K]', '').replace('(4K)', '').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 filter_languages > 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) # Recalculamos los items después del filtrado if cnt_title >= cnt_tot and (len(matches) - cnt_match) + cnt_title > cnt_tot * 1.3: #Contador de líneas añadidas break #logger.debug(item_local) matches = matches[cnt_match:] # Salvamos la entradas no procesadas cnt_tot_match += cnt_match # Calcular el num. total de items mostrados #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda='es') #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 or len(matches) > 0: curr_page_print = int(cnt_tot_match / float(cnt_tot)) if curr_page_print < 1: curr_page_print = 1 if last_page: if last_page > 1: last_page_print = int((last_page * page_factor) + 0.999999) title = '%s de %s' % (curr_page_print, last_page_print) else: title = '%s' % curr_page_print 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), page_factor=str(page_factor), cnt_tot_match=str(cnt_tot_match), matches=matches, last_page_print=last_page_print, post=post)) return itemlist
def listado(item): logger.info() itemlist = [] # Descarga la página data = '' try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) except: pass if not data and item.extra != "año": #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 elif not data and item.extra == "año": #cuando no hay datos para un año, da error. Tratamos de evitar el error return itemlist patron = '<div class="browse-movie-wrap col-xs-10 col-sm-4 col-md-5 col-lg-4"><a href="([^"]+)".*?src="([^"]+)".*?alt="([^"]+)".*?rel="tag">([^"]+)<\/a>\s?<\/div><div class="[^"]+">(.*?)<\/div><\/div><\/div>' #data = scrapertools.find_single_match(data, patron) matches = re.compile(patron, re.DOTALL).findall(data) if not matches and not '<ul class="tsc_pagination tsc_pagination' 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' )) 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, scrapedthumbnail, scrapedtitle, scrapedyear, scrapedqualities in matches: item_local = item.clone() #Creamos copia de Item para trabajar title_subs = [] title = re.sub('\r\n', '', scrapedtitle).decode('utf8').strip() item_local.url = scrapedurl item_local.thumbnail = scrapedthumbnail scrapedtorrent = '' if scrapedqualities: patron_quality = '<a href="([^"]+)"\s?rel="[^"]+"\s?title="[^"]+">(.*?)<\/a>' matches_quality = re.compile(patron_quality, re.DOTALL).findall(scrapedqualities) quality = '' for scrapedtorrent, scrapedquality in matches_quality: quality_inter = scrapedquality quality_inter = re.sub('HDr$', 'HDrip', quality_inter) quality_inter = re.sub('720$', '720p', quality_inter) quality_inter = re.sub('1080$', '1080p', quality_inter) if quality: quality += ', %s' % quality_inter else: quality = quality_inter if quality: item_local.quality = quality item_local.language = [ ] #Verificamos el idioma por si encontramos algo if "latino" in scrapedtorrent.lower( ) or "latino" in item.url or "latino" in title.lower(): item_local.language += ["LAT"] if "ingles" in scrapedtorrent.lower( ) or "ingles" in item.url or "vose" in scrapedurl or "vose" in item.url: if "VOSE" in scrapedtorrent.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 scrapedtorrent.lower() or "dual" in title.lower(): item_local.language[0:0] = ["DUAL"] #Limpiamos el título de la basura innecesaria title = title.replace("Dual", "").replace("dual", "").replace( "Subtitulada", "").replace("subtitulada", "").replace("Subt", "").replace( "subt", "").replace("Sub", "").replace("sub", "").replace( "(Proper)", "").replace("(proper)", "").replace("Proper", "").replace( "proper", "").replace("#", "").replace("(Latino)", "").replace("Latino", "") title = title.replace("- HDRip", "").replace("(HDRip)", "").replace( "- Hdrip", "").replace("(microHD)", "").replace("(DVDRip)", "").replace( "(HDRip)", "").replace("(BR-LINE)", "").replace( "(HDTS-SCREENER)", "").replace("(BDRip)", "").replace( "(BR-Screener)", "").replace("(DVDScreener)", "").replace( "TS-Screener", "").replace(" TS", "").replace(" Ts", "") title = re.sub(r'\??\s?\d*?\&.*', '', title).title().strip() item_local.from_title = title #Guardamos esta etiqueta para posible desambiguación de título item_local.contentType = "movie" item_local.contentTitle = title item_local.extra = "peliculas" item_local.action = "findvideos" item_local.title = title.strip() item_local.infoLabels['year'] = "-" if scrapedyear >= "1900" and scrapedyear <= "2040": title_subs += [scrapedyear] itemlist.append(item_local.clone()) #Pintar pantalla #if not item.category: #Si este campo no existe es que viene de la primera pasada de una búsqueda global # return itemlist #Retornamos sin pasar por la fase de maquillaje para ahorra tiempo #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Extrae el paginador patron = '<li><a href="[^"]+">(\d+)<\/a><\/li>' #total de páginas patron += '<li><a href="([^"]+\/page\/(\d+)\/)"\s?rel="[^"]+">Página siguiente[^<]+<\/a><\/li><\/ul><\/div><\/ul>' #url siguiente url_next = '' if scrapertools.find_single_match(data, patron): last_page, url_next, next_num = scrapertools.find_single_match( data, patron) if url_next: if last_page: title = '[COLOR gold]Página siguiente >>[/COLOR] %s de %s' % ( int(next_num) - 1, last_page) else: title = '[COLOR gold]Página siguiente >>[/COLOR] %s' % ( int(next_num) - 1) itemlist.append( Item(channel=item.channel, action="listado", title=title, url=url_next, extra=item.extra)) return itemlist