def episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title item.extra2 = 'xyz' del item.extra2 #Limpiamos num. Temporada y Episodio que ha podido quedar por Novedades season_display = 0 if item.contentSeason: if item.season_colapse: #Si viene del menú de Temporadas... season_display = item.contentSeason #... salvamos el num de sesión a pintar item.from_num_season_colapse = season_display del item.season_colapse item.contentType = "tvshow" if item.from_title_season_colapse: item.title = item.from_title_season_colapse del item.from_title_season_colapse if item.infoLabels['title']: del item.infoLabels['title'] del item.infoLabels['season'] if item.contentEpisodeNumber: del item.infoLabels['episode'] if season_display == 0 and item.from_num_season_colapse: season_display = item.from_num_season_colapse # Obtener la información actualizada de la Serie. TMDB es imprescindible para Videoteca if not item.infoLabels['tmdb_id']: tmdb.set_infoLabels(item, True) # Descarga la página data = '' #Inserto en num de página en la url try: data = httptools.downloadpage(item.url, timeout=timeout).data data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: #Algún error de proceso, salimos pass if not data: logger.error( "ERROR 01: EPISODIOS: La Web no responde o la URL es erronea" + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log' )) return itemlist #Buscamos los episodios matches = jsontools.load(data) if not matches: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_episodios( item, itemlist) #Llamamos al método para el pintado del error return itemlist #Salimos logger.error( "ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug(matches) # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for temporada in matches.get("temporadas", []): if season_display > 0 and temporada.get( "numerotemporada", 0) != season_display: #si no es nuestra temp., pasamos continue #Si hay más de una temporada, solo las enumeramos if len(matches.get("temporadas", [])) > 1 and item.season_colapse: item_local = item.clone() #creo una copia de Item item_local.action = "findvideos" #y lo preparo para la reproducción item_local.contentType = "episode" item_local.extra = "episodios" item_local.contentSeason = temporada.get( "numerotemporada", 1) #Guardo el num. de temporada item_local.contentEpisodeNumber = 1 #relleno el num. de episodio por compatibilidad itemlist.append(item_local.clone()) #lo pinto continue #Paso a la siguiente temporada #Aquí tratamos todos los episodios de una temporada season = temporada.get("numerotemporada", 1) for episodio in temporada.get("capituls", []): item_local = item.clone() #creo una copia de Item item_local.action = "findvideos" #y lo preparo para la reproducción item_local.contentType = "episode" item_local.extra = "episodios" if item_local.library_playcounts: del item_local.library_playcounts if item_local.library_urls: del item_local.library_urls if item_local.path: del item_local.path if item_local.update_last: del item_local.update_last if item_local.update_next: del item_local.update_next if item_local.channel_host: del item_local.channel_host if item_local.active: del item_local.active if item_local.contentTitle: del item_local.infoLabels['title'] if item_local.season_colapse: del item_local.season_colapse if item_local.tmdb_stat: del item_local.tmdb_stat item_local.title = '' item_local.context = "['buscar_trailer']" title = episodio.get("nomcapitul", "") #título del episodio info_epi = episodio.get("infocapitul", "") #información adicional del episodio item_local.language = [] item_local.url = [] if episodio.get("links", {}).get("magnet"): #buscamos los magnets activos url = episodio.get("links", {}).get("magnet") #salvamos el magnet quality = episodio.get("links", {}).get( "calitat", "") #salvamos la calidad del magnet item_local.url += [(url, quality) ] #guardamos todo como url para findvideos item_local.quality = quality.strip( ) #agregamos a la calidad del título if not item_local.language: item_local.language += ['CAST'] #Castellano por defecto #Buscamos la Temporada y el Episodio try: item_local.contentSeason = int( season) #Copiamos el num. de Temporada except: item_local.contentSeason = 1 #Si hay error, lo dejamos en 1 try: item_local.contentEpisodeNumber = int( episodio.get("numerocapitul", 1)) #Copiamos el num. de Episodio except: item_local.contentEpisodeNumber = 1 #Si hay error, lo dejamos en 1 if 'miniserie' in title.lower( ): #Si es una Miniserie, lo ajustamos if not item_local.contentSeason: item_local.contentSeason = 1 title = title.replace('miniserie', '').replace('MiniSerie', '') #Si son episodios múltiples, lo extraemos patron1 = '\d+[x|X]\d{1,2}.?(?:y|Y|al|Al)?.?(?:(?:\d+[x|X])?(\d{1,2}))?' epi_rango = scrapertools.find_single_match(info_epi, patron1) if epi_rango: item_local.infoLabels['episodio_titulo'] = 'al %s ' % epi_rango item_local.title = '%sx%s al %s -' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2), str(epi_rango).zfill(2)) else: item_local.title = '%sx%s -' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) item.infoLabels['episodio_titulo'] = '%s' % title itemlist.append(item_local.clone()) #logger.debug(item_local) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber) )) #clasificamos if item.season_colapse and not item.add_videolibrary: #Si viene de listado, mostramos solo Temporadas item, itemlist = generictools.post_tmdb_seasons(item, itemlist) if not item.season_colapse: #Si no es pantalla de Temporadas, pintamos todo # Pasada por TMDB y clasificación de lista por temporada y episodio tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_episodios(item, itemlist) #logger.debug(item) return itemlist
def episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title #Limpiamos num. Temporada y Episodio que ha podido quedar por Novedades season_display = 0 if item.contentSeason: if item.season_colapse: #Si viene del menú de Temporadas... season_display = item.contentSeason #... salvamos el num de sesión a pintar item.from_num_season_colapse = season_display del item.season_colapse item.contentType = "tvshow" if item.from_title_season_colapse: item.title = item.from_title_season_colapse del item.from_title_season_colapse if item.infoLabels['title']: del item.infoLabels['title'] del item.infoLabels['season'] if item.contentEpisodeNumber: del item.infoLabels['episode'] if season_display == 0 and item.from_num_season_colapse: season_display = item.from_num_season_colapse # Obtener la información actualizada de la Serie. TMDB es imprescindible para Videoteca try: tmdb.set_infoLabels(item, True, idioma_busqueda='es,en') except: pass modo_ultima_temp_alt = modo_ultima_temp if item.ow_force == "1": #Si hay un traspaso de canal o url, se actualiza todo modo_ultima_temp_alt = False max_temp = 1 if item.infoLabels['number_of_seasons']: max_temp = item.infoLabels['number_of_seasons'] y = [] if modo_ultima_temp_alt and item.library_playcounts: #Averiguar cuantas temporadas hay en Videoteca patron = 'season (\d+)' matches = re.compile(patron, re.DOTALL).findall(str(item.library_playcounts)) for x in matches: y += [int(x)] max_temp = max(y) # Descarga la página data = '' #Inserto en num de página en la url try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "utf-8", errors="replace").encode("utf-8") except: #Algún error de proceso, salimos pass if not data: logger.error( "ERROR 01: EPISODIOS: La Web no responde o la URL es erronea" + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log' )) return itemlist status, itemlist = check_blocked_IP( data, itemlist) #Comprobamos si la IP ha sido bloqueada if status: return itemlist #IP bloqueada #Capturamos las temporadas de episodios dentro de la serie patron_temp = '<h1\s*class="[^"]+">Season\s*(\d+)<\/h1><div class="tvcontent"><div id="[^"]+"><\/div>(.*?<\/div><\/div>)(?:<script>.*?<\/script>)?<\/div>' temp_serie = re.compile(patron_temp, re.DOTALL).findall(data) for season_num, temporada in temp_serie: patron = '<div id="episode_(\d+)"><div class="[^"]+">\s*<a onclick="[^"]+"\s*class="[^"]+"><div class="[^"]+">.*?\s*(\d+)<\/div>\s*(.*?)\s*<' matches = re.compile(patron, re.DOTALL).findall(temporada) if not matches: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_episodios( item, itemlist) #Llamamos al método para el pintado del error return itemlist #Salimos logger.error( "ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) season = max_temp #Comprobamos si realmente sabemos el num. máximo de temporadas if item.library_playcounts or (item.infoLabels['number_of_seasons'] and item.tmdb_stat): num_temporadas_flag = True else: num_temporadas_flag = False if modo_ultima_temp_alt and item.library_playcounts: #Si solo se actualiza la última temporada de Videoteca if int(season_num) < max_temp: break #Sale del bucle actual del FOR # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for epi_id, episode_num, scrapedtitle in matches: item_local = item.clone() item_local.action = "findvideos" item_local.contentType = "episode" item_local.extra = "episodios" if item_local.library_playcounts: del item_local.library_playcounts if item_local.library_urls: del item_local.library_urls if item_local.path: del item_local.path if item_local.update_last: del item_local.update_last if item_local.update_next: del item_local.update_next if item_local.channel_host: del item_local.channel_host if item_local.active: del item_local.active if item_local.contentTitle: del item_local.infoLabels['title'] if item_local.season_colapse: del item_local.season_colapse item_local.title = '' item_local.context = "['buscar_trailer']" item_local.url = urlparse.urljoin( host, 'tv.php?ajax=1&tvepisode=%s' % epi_id) title = scrapedtitle item_local.language = ['VO'] if not item_local.infoLabels['poster_path']: item_local.thumbnail = item_local.infoLabels['thumbnail'] epi_rango = False try: item_local.contentSeason = int(season_num) if 'season pack' in title.lower(): item_local.contentEpisodeNumber = 1 epi_rango = True else: item_local.contentEpisodeNumber = int(episode_num) except: logger.error('ERROR al extraer Temporada/Episodio: ' + title) item_local.contentSeason = 1 item_local.contentEpisodeNumber = 0 #Si son episodios múltiples, lo extraemos if epi_rango: item_local.infoLabels['episodio_titulo'] = 'al 99' item_local.title = '%sx%s al 99 - Season Pack' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) else: item_local.title = '%sx%s - ' % ( str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) if season_display > 0: if item_local.contentSeason > season_display: continue elif item_local.contentSeason < season_display: break itemlist.append(item_local.clone()) #logger.debug(item_local) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber) )) #clasificamos if item.season_colapse and not item.add_videolibrary: #Si viene de listado, mostramos solo Temporadas item, itemlist = generictools.post_tmdb_seasons(item, itemlist) if not item.season_colapse: #Si no es pantalla de Temporadas, pintamos todo # Pasada por TMDB y clasificación de lista por temporada y episodio tmdb.set_infoLabels(itemlist, True, idioma_busqueda='es,en') #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_episodios(item, itemlist) #logger.debug(item) return itemlist
def listado(item): logger.info() itemlist = [] 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 episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title if item.subtitle: del item.subtitle #Limpiamos num. Temporada y Episodio que ha podido quedar por Novedades season_display = 0 if item.contentSeason: if item.season_colapse: #Si viene del menú de Temporadas... season_display = item.contentSeason #... salvamos el num de sesión a pintar item.from_num_season_colapse = season_display del item.season_colapse item.contentType = "tvshow" if item.from_title_season_colapse: item.title = item.from_title_season_colapse del item.from_title_season_colapse if item.infoLabels['title']: del item.infoLabels['title'] del item.infoLabels['season'] if item.contentEpisodeNumber: del item.infoLabels['episode'] if season_display == 0 and item.from_num_season_colapse: season_display = item.from_num_season_colapse # Obtener la información actualizada de la Serie. TMDB es imprescindible para Videoteca if not item.infoLabels['tmdb_id']: tmdb.set_infoLabels(item, True) modo_ultima_temp_alt = modo_ultima_temp if item.ow_force == "1": #Si hay un traspaso de canal o url, se actualiza todo modo_ultima_temp_alt = False max_temp = 1 if item.infoLabels['number_of_seasons']: max_temp = item.infoLabels['number_of_seasons'] y = [] if modo_ultima_temp_alt and item.library_playcounts: #Averiguar cuantas temporadas hay en Videoteca patron = 'season (\d+)' matches = re.compile(patron, re.DOTALL).findall(str(item.library_playcounts)) for x in matches: y += [int(x)] max_temp = max(y) # Descarga la página data = '' #Inserto en num de página en la url try: data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)| ", "", httptools.downloadpage(item.url, timeout=timeout).data) #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") except: #Algún error de proceso, salimos pass if not data: logger.error( "ERROR 01: EPISODIOS: La Web no responde o la URL es erronea" + item.url) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log' )) return itemlist patron = '<td class="capitulonombre"><img src="([^"]+)[^>]+>(?:<a href="[^>]+>)(.*?)<\/a><\/td><td class="capitulodescarga"><a href="([^"]+)[^>]+>.*?(?:<td class="capitulofecha">.*?(\d{4})?.*?<\/td>)?(?:<td class="capitulosubtitulo"><a href="([^"]+)[^>]+>.*?<\/td>)?<td class="capitulodescarga"><\/tr>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_episodios( item, itemlist) #Llamamos al método para el pintado del error return itemlist #Salimos logger.error( "ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) season = max_temp #Comprobamos si realmente sabemos el num. máximo de temporadas if item.library_playcounts or (item.infoLabels['number_of_seasons'] and item.tmdb_stat): num_temporadas_flag = True else: num_temporadas_flag = False # Recorremos todos los episodios generando un Item local por cada uno en Itemlist for scrapedlanguage, scrapedtitle, scrapedurl, year, scrapedsubtitle in matches: item_local = item.clone() item_local.action = "findvideos" item_local.contentType = "episode" item_local.extra = "episodios" if item_local.library_playcounts: del item_local.library_playcounts if item_local.library_urls: del item_local.library_urls if item_local.path: del item_local.path if item_local.update_last: del item_local.update_last if item_local.update_next: del item_local.update_next if item_local.channel_host: del item_local.channel_host if item_local.active: del item_local.active if item_local.contentTitle: del item_local.infoLabels['title'] if item_local.season_colapse: del item_local.season_colapse item_local.title = '' item_local.context = "['buscar_trailer']" item_local.url = scrapedurl.replace('&', '&').replace( '.io/', sufix).replace('.com/', sufix) if scrapedsubtitle: item_local.subtitle = scrapedsubtitle.replace( '&', '&').replace('.io/', sufix).replace('.com/', sufix) title = scrapedtitle item_local.language = [] if "1.png" in scrapedlanguage: item_local.language += ['CAST'] if "512.png" in scrapedlanguage or 'latino' in title.lower(): item_local.language += ['LAT'] if ("1.png" not in scrapedlanguage and "512.png" not in scrapedlanguage ) or "eng" in title.lower() or "sub" in title.lower(): item_local.language += ['VOSE'] try: item_local.contentEpisodeNumber = 0 if 'miniserie' in title.lower(): item_local.contentSeason = 1 title = title.replace('miniserie', '').replace('MiniSerie', '') elif 'completa' in title.lower(): patron = '[t|T].*?(\d+) [c|C]ompleta' if scrapertools.find_single_match(title, patron): item_local.contentSeason = int( scrapertools.find_single_match(title, patron)) if not item_local.contentSeason: #Extraemos los episodios patron = '(\d{1,2})[x|X](\d{1,2})' item_local.contentSeason, item_local.contentEpisodeNumber = scrapertools.find_single_match( title, patron) item_local.contentSeason = int(item_local.contentSeason) item_local.contentEpisodeNumber = int( item_local.contentEpisodeNumber) except: logger.error('ERROR al extraer Temporada/Episodio: ' + title) item_local.contentSeason = 1 item_local.contentEpisodeNumber = 0 #Si son eisodios múltiples, lo extraemos patron1 = '\d+[x|X]\d{1,2}.?(?:y|Y|al|Al)?(?:\d+[x|X]\d{1,2})?.?(?:y|Y|al|Al)?.?\d+[x|X](\d{1,2})' epi_rango = scrapertools.find_single_match(title, patron1) if epi_rango: item_local.infoLabels['episodio_titulo'] = 'al %s' % epi_rango item_local.title = '%sx%s al %s -' % (str( item_local.contentSeason), str( item_local.contentEpisodeNumber).zfill(2), str(epi_rango).zfill(2)) else: item_local.title = '%sx%s -' % (str( item_local.contentSeason), str( item_local.contentEpisodeNumber).zfill(2)) if modo_ultima_temp_alt and item.library_playcounts: #Si solo se actualiza la última temporada de Videoteca if item_local.contentSeason < max_temp: break #Sale del bucle actual del FOR if season_display > 0: if item_local.contentSeason > season_display: continue elif item_local.contentSeason < season_display: break itemlist.append(item_local.clone()) #logger.debug(item_local) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber) )) #clasificamos if item.season_colapse and not item.add_videolibrary: #Si viene de listado, mostramos solo Temporadas item, itemlist = generictools.post_tmdb_seasons(item, itemlist) if not item.season_colapse: #Si no es pantalla de Temporadas, pintamos todo # Pasada por TMDB y clasificación de lista por temporada y episodio tmdb.set_infoLabels(itemlist, True) #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_episodios(item, itemlist) #logger.debug(item) return itemlist
def 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): 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 episodios(item): logger.info() itemlist = [] item.category = categoria #logger.debug(item) if item.from_title: item.title = item.from_title #Limpiamos num. Temporada y Episodio que ha podido quedar por Novedades season_display = 0 if item.contentSeason: if item.season_colapse: #Si viene del menú de Temporadas... season_display = item.contentSeason #... salvamos el num de sesión a pintar item.from_num_season_colapse = season_display del item.season_colapse item.contentType = "tvshow" if item.from_title_season_colapse: item.title = item.from_title_season_colapse del item.from_title_season_colapse if item.infoLabels['title']: del item.infoLabels['title'] del item.infoLabels['season'] if item.contentEpisodeNumber: del item.infoLabels['episode'] if season_display == 0 and item.from_num_season_colapse: season_display = item.from_num_season_colapse # Obtener la información actualizada de la Serie. TMDB es imprescindible para Videoteca try: tmdb.set_infoLabels(item, True, idioma_busqueda='es,en') except: pass modo_ultima_temp_alt = modo_ultima_temp if item.ow_force == "1": #Si hay una migración de canal o url, se actualiza todo modo_ultima_temp_alt = False # Vemos la última temporada de TMDB y del .nfo max_temp = 1 if item.infoLabels['number_of_seasons']: max_temp = item.infoLabels['number_of_seasons'] y = [] if modo_ultima_temp_alt and item.library_playcounts: #Averiguar cuantas temporadas hay en Videoteca patron = 'season (\d+)' matches = re.compile(patron, re.DOTALL).findall(str(item.library_playcounts)) for x in matches: y += [int(x)] max_temp = max(y) # Si la series tiene solo una temporada, o se lista solo una temporada, guardamos la url y seguimos normalmente list_temp = [] list_temp.append(item.url) # Descarga las páginas for url in list_temp: # Recorre todas las temporadas encontradas data, success, code, item, itemlist = generictools.downloadpage(url, timeout=timeout, s2=False, item=item, itemlist=itemlist) # Descargamos la página #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not success: # Si ERROR o lista de errores ... return itemlist # ... Salimos patron = '<tr>(?:\s*<td>[^<]+<\/td>)?\s*<td>([^<]+)<\/td>\s*<td>([^<]+)<\/td>\s*' patron += '<td\s*class=[^<]+<\/td>(?:<td>([^<]+)<\/td>)?\s*<td\s*class=[^<]+<\/td>\s*' patron += '<td>\s*<a\s*class="[^"]+"\s*(?:data-row="[^"]+"\s*data-post="[^"]+"\s*)?' patron += 'href="([^"]+)"\s*(?:data-season="([^"]+)"\s*data-serie="([^"]+)")?' matches = re.compile(patron, re.DOTALL).findall(data) #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) # Recorremos todos los episodios generando un Item local por cada uno en Itemlist x = 0 for scrapedquality, scrapedlanguage, scrapedsize, scrapedurl, season_num, episode_num in matches: item_local = item.clone() item_local.action = "findvideos" item_local.contentType = "episode" if item_local.library_playcounts: del item_local.library_playcounts if item_local.library_urls: del item_local.library_urls if item_local.path: del item_local.path if item_local.update_last: del item_local.update_last if item_local.update_next: del item_local.update_next if item_local.channel_host: del item_local.channel_host if item_local.active: del item_local.active if item_local.contentTitle: del item_local.infoLabels['title'] if item_local.season_colapse: del item_local.season_colapse item_local.url = url # Usamos las url de la temporada, no hay de episodio item_local.matches = [] item_local.matches.append(matches[x]) # Salvado Matches de cada episodio x += 1 item_local.context = "['buscar_trailer']" if not item_local.infoLabels['poster_path']: item_local.thumbnail = item_local.infoLabels['thumbnail'] # Extraemos números de temporada y episodio try: item_local.contentSeason = int(season_num) except: item_local.contentSeason = 1 try: item_local.contentEpisodeNumber = int(episode_num) except: item_local.contentEpisodeNumber = 0 item_local.title = '%sx%s - ' % (str(item_local.contentSeason), str(item_local.contentEpisodeNumber).zfill(2)) # 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 = '720p' # Comprobamos si hay más de un enlace por episodio, entonces los agrupamos if len(itemlist) > 0 and item_local.contentSeason == itemlist[-1].contentSeason \ and item_local.contentEpisodeNumber == itemlist[-1].contentEpisodeNumber \ and itemlist[-1].contentEpisodeNumber != 0: # solo guardamos un episodio ... if itemlist[-1].quality: if item_local.quality not in itemlist[-1].quality: itemlist[-1].quality += ", " + item_local.quality # ... pero acumulamos las calidades else: itemlist[-1].quality = item_local.quality itemlist[-1].matches.append(item_local.matches[0]) # Salvado Matches en el episodio anterior continue # ignoramos el episodio duplicado if season_display > 0: # Son de la temporada estos episodios? if item_local.contentSeason > season_display: break elif item_local.contentSeason < season_display: continue if modo_ultima_temp_alt and item.library_playcounts: # Si solo se actualiza la última temporada de Videoteca if item_local.contentSeason < max_temp: continue # Sale del bucle actual del FOR itemlist.append(item_local.clone()) #logger.debug(item_local) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber))) #clasificamos if item.season_colapse and not item.add_videolibrary: #Si viene de listado, mostramos solo Temporadas item, itemlist = generictools.post_tmdb_seasons(item, itemlist) if not item.season_colapse: #Si no es pantalla de Temporadas, pintamos todo # Pasada por TMDB y clasificación de lista por temporada y episodio tmdb.set_infoLabels(itemlist, True, idioma_busqueda='es,en') #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_episodios(item, itemlist) #logger.debug(item) return itemlist
def listado(item): logger.info() itemlist = [] # 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