def temporadas_anteriores(item): patron = '<h2\s*style="[^>]+>\s*<a\s*href="([^"]+)".*?>\s*<span\s*style="[^>]+>\s*' patron += '<strong>\s*(.*?)\s*<\/strong>\s*<\/span>\s*<\/a>\s*<\/h2>' data, success, code, item, itemlist = generictools.downloadpage(item.url, timeout=timeout, s2=False, patron=patron, item=item, itemlist=[]) # Descargamos la página matches = re.compile(patron, re.DOTALL).findall(data) for scrapedurl, scrapedtitle in matches: item_local = item.clone() item_local.action = "findvideos" item_local.contentType = session item_local.contentPlot += '[B]%s[/B]\n\n' % scrapedtitle item_local.url_enlaces = [(scrapedurl, 'Torrent')] year = scrapertools.find_single_match(scrapedtitle, '\d{4}') if year: item_local.infoLabels['year'] = int(year) item_local.infoLabels['aired'] = str(year) item_local.title = scrapedtitle item_local.contentTitle = item_local.title item_local.from_title = item_local.title itemlist.append(item_local.clone()) return itemlist
def genero(item): logger.info() itemlist = [] patron = '<li\s*id="menu-item-[^"]+"\s*class="menu-item[^"]+genres[^"]+">\s*' patron += '<a\s*href="([^"]+)">\s*([^<]+)<\/a>\s*<\/li>' data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, s2=False, patron=patron, item=item, 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, y si además tiene la estructura correcta if not response.sucess or itemlist: # Si ERROR o lista de errores ... return itemlist # ... Salimos matches = re.compile(patron, re.DOTALL).findall(data) #logger.debug(patron) #logger.debug(matches) #logger.debug(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, gen in matches: itemlist.append( item.clone(action="listado", title=gen.capitalize(), url=scrapedurl + 'page/1/')) if len(itemlist) > 1: itemlist = sorted(itemlist, key=lambda it: it.title) #clasificamos return itemlist
def mainlist(item): logger.info() itemlist = [] thumb_novedades = get_thumb("on_the_air.png") thumb_separador = get_thumb("next.png") thumb_settings = get_thumb("setting_0.png") autoplay.init(item.channel, list_servers, list_quality) # obtenemos el bloque con las cabeceras de deportes patron = 'Men[^<]+<\/span>\s*<\/div>\s*<nav\s*class="elementor-nav-menu--dropdown\s*' patron += 'elementor-nav-menu__container"\s*(?:[^>]+>)?\s*(?:[^>]+>)?\s*(.*?)\s*<\/ul\s*><\/nav>' data, success, code, item, itemlist = generictools.downloadpage( host, timeout=timeout, s2=False, patron=patron, item=item, itemlist=[]) # Descargamos la página data = scrapertools.find_single_match(data, patron) if success and data: # Obtenemos el enlace para cada Deporte patron = '<li\s*class="menu-item menu[^>]+>\s*<a\s*href="([^"]+)"[^>]+>\s*(.*?)\s*<\/a\s*><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) #logger.debug(patron) #logger.debug(matches) #logger.debug(data) for url, sport in matches: if sport in enlace_void: continue itemlist.append( Item(channel=item.channel, title=sport, action="listado", url=url, thumbnail=thumb_sports, extra="deportes")) # Configuración del Canal y de Autoplay itemlist.append( Item(channel=item.channel, url=host, title="[COLOR yellow]Configuración:[/COLOR]", folder=False, thumbnail=thumb_separador)) itemlist.append( Item(channel=item.channel, action="configuracion", title="Configurar canal", thumbnail=thumb_settings)) autoplay.show_option(item.channel, itemlist) #Activamos Autoplay return itemlist
def submenu(item): patron = '<li\s*id="menu-item-[^"]+"\s*class="menu-item[^"]+">\s*<a\s*href="([^"]+)">' patron += '\s*<icona\s*class="fa[^"]+">\s*<\/icona>\s*(\w+)\s*(?:<\/a>\s*)?<\/a>.*?<\/li>' data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, s2=False, patron=patron, item=item, 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, y si además tiene la estructura correcta if not response.sucess or itemlist: # Si ERROR o lista de errores .. return itemlist # ... Salimos matches = re.compile(patron, re.DOTALL).findall(data) #logger.debug(patron) #logger.debug(matches) #logger.debug(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: if scrapedtitle in item.extra2: item.url = scrapedurl if not item.url.endswith('/'): item.url += '/' item.url += 'page/1/' return listado(item) return itemlist
def calidad(item): logger.info() itemlist = [] patron = '<a class="dropdown-toggle header__nav-link"\s*href="#"\s*role="button"' patron += '\s*data-toggle="dropdown">CALIDAD\s*<\/a>\s*<ul class="dropdown-menu header__dropdown-menu">' patron += '\s*(.*?)\s*<\/ul>\s*<\/li>' data, success, code, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, s2=False, patron=patron, item=item, itemlist=[]) # Descargamos la página #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not success or itemlist: # Si ERROR o lista de errores ... return itemlist # ... Salimos data = scrapertools.find_single_match(data, patron) patron = '<li><a\s*href="([^"]+)"\s*target="[^"]*">([^<]+)\s*<\/a>\s*<\/li>' matches = re.compile(patron, re.DOTALL).findall(data) #logger.debug(patron) #logger.debug(matches) #logger.debug(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, cal in matches: itemlist.append( item.clone(action="listado", title=cal.capitalize(), url=scrapedurl + 'page/1/', extra2='calidad')) return itemlist
def findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados matches = [] data = '' response = {'data': data, 'sucess': False, 'code': 0} response = type('HTTPResponse', (), response) torrent_params = { 'url': item.url, 'torrents_path': None, 'local_torr': item.torrents_path, 'lookup': False, 'force': True, 'data_torrent': True, 'subtitles': True, 'file_list': True } #logger.debug(item) #Bajamos los datos de la página patron = '<a\s*class="torrent_download[^"]*"\s*href="([^"]+)"' if not item.matches: data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, canonical=canonical, headers=item.headers, s2=False, patron=patron, 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 data and not item.matches) or response.code == 999: if item.emergency_urls and not item.videolibray_emergency_urls: # Hay urls de emergencia? if len(item.emergency_urls) > 1: matches = item.emergency_urls[ 1] # Restauramos matches de vídeos elif len(item.emergency_urls) == 1 and item.emergency_urls[0]: matches = item.emergency_urls[ 0] # Restauramos matches de vídeos - OLD FORMAT item.armagedon = True # Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: # Si es llamado desde creación de Videoteca... return item # Devolvemos el Item de la llamada else: return itemlist # si no hay más datos, algo no funciona, pintamos lo que tenemos if not item.armagedon: if not item.matches: matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) if not matches: # error return itemlist # Si es un lookup para cargar las urls de emergencia en la Videoteca... if item.videolibray_emergency_urls: item.emergency_urls = [] # Iniciamos emergency_urls item.emergency_urls.append( []) # Reservamos el espacio para los .torrents locales matches_list = [] # Convertimos matches-tuple a matches-list for tupla in matches: if isinstance(tupla, tuple): matches_list.append(list(tupla)) if matches_list: item.emergency_urls.append( matches_list) # Salvamnos matches de los vídeos... else: item.emergency_urls.append(matches) # Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB if not item.videolibray_emergency_urls: item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) # Ahora tratamos los enlaces .torrent con las diferentes calidades for x, (scrapedurl) in enumerate(matches): scrapedpassword = '' #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.url = generictools.convert_url_base64( scrapedurl, host_torrent) if item.videolibray_emergency_urls and item_local.url != scrapedurl: item.emergency_urls[1][x][0] = item_local.url # Buscamos el enlace definitivo, si es necesario if not item_local.url.startswith( 'magnet') and not item_local.url.endswith('.torrent'): patron = '<a\s*id="link"[^>]*href="([^"]+)"' data, response, item, itemlist = generictools.downloadpage( item_local.url, timeout=timeout, canonical=canonical, s2=False, patron=patron, item=item, itemlist=itemlist) item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: continue # Restauramos urls de emergencia si es necesario local_torr = '' if item.emergency_urls and not item.videolibray_emergency_urls: try: # Guardamos la url ALTERNATIVA if item.emergency_urls[0][0].startswith( 'http') or item.emergency_urls[0][0].startswith('//'): item_local.torrent_alt = generictools.convert_url_base64( item.emergency_urls[0][0], host_torrent) else: item_local.torrent_alt = generictools.convert_url_base64( item.emergency_urls[0][0]) except: item_local.torrent_alt = '' item.emergency_urls[0] = [] from core import filetools if item.contentType == 'movie': FOLDER = config.get_setting("folder_movies") else: FOLDER = config.get_setting("folder_tvshows") if item.armagedon and item_local.torrent_alt: item_local.url = item_local.torrent_alt # Restauramos la url if not item.torrent_alt.startswith('http'): local_torr = filetools.join(config.get_videolibrary_path(), FOLDER, item_local.url) if len(item.emergency_urls[0]) > 1: del item.emergency_urls[0][0] #Buscamos tamaño en el archivo .torrent size = '' if item_local.torrent_info: size = item_local.torrent_info if not size and not item.videolibray_emergency_urls and not item_local.url.startswith( 'magnet:'): if not item.armagedon: torrent_params['url'] = item_local.url torrent_params[ 'local_torr'] = local_torr or item_local.torrents_path torrent_params = generictools.get_torrent_size( item_local.url, torrent_params=torrent_params, item=item_local) size = torrent_params['size'] if torrent_params['torrents_path']: item_local.torrents_path = torrent_params['torrents_path'] if 'ERROR' in size and item.emergency_urls and not item.videolibray_emergency_urls: item_local.armagedon = True try: # Restauramos la url if item.emergency_urls[0][0].startswith( 'http' ) or item.emergency_urls[0][0].startswith('//'): item_local.url = generictools.convert_url_base64( item.emergency_urls[0][0], host_torrent) else: item_local.url = generictools.convert_url_base64( item.emergency_urls[0][0]) if not item.url.startswith('http'): local_torr = filetools.join( config.get_videolibrary_path(), FOLDER, item_local.url) except: item_local.torrent_alt = '' item.emergency_urls[0] = [] torrent_params['url'] = item_local.url torrent_params['local_torr'] = local_torr torrent_params = generictools.get_torrent_size( item_local.url, torrent_params=torrent_params, item=item_local) size = torrent_params['size'] if torrent_params['torrents_path']: item_local.torrents_path = torrent_params[ 'torrents_path'] if size: size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') item_local.torrent_info = '%s, ' % size #Agregamos size if item_local.url.startswith( 'magnet:') and not 'Magnet' in item_local.torrent_info: item_local.torrent_info += ' Magnet' if item_local.torrent_info: item_local.torrent_info = item_local.torrent_info.strip().strip( ',') if item.videolibray_emergency_urls: item.torrent_info = item_local.torrent_info if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info # Guadamos la password del RAR password = scrapedpassword # Si tiene contraseña, la guardamos y la pintamos if password or item.password: if not item.password: item.password = password item_local.password = item.password itemlist.append( item.clone( action="", title="[COLOR magenta][B] Contraseña: [/B][/COLOR]'" + item_local.password + "'", folder=False)) # Guardamos urls de emergencia si se viene desde un Lookup de creación de Videoteca if item.videolibray_emergency_urls: item.emergency_urls[0].append( item_local.url) #guardamos la url y nos vamos continue if item_local.armagedon: item_local.quality = '[COLOR hotpink][E][/COLOR] [COLOR limegreen]%s[/COLOR]' % item_local.quality #Ahora pintamos el link del Torrent item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título y calidad, quitando etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace("[]", "")\ .replace("()", "").replace("(/)", "").replace("[/]", "")\ .replace("|", "").strip() item_local.quality = re.sub( r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality) item_local.quality = item_local.quality.replace("--", "").replace("[]", "")\ .replace("()", "").replace("(/)", "").replace("[/]", "")\ .replace("|", "").strip() if not item_local.torrent_info or 'Magnet' in item_local.torrent_info: item_local.alive = "??" #Calidad del link sin verificar elif 'ERROR' in item_local.torrent_info and 'Pincha' in item_local.torrent_info: item_local.alive = "ok" #link en error, CF challenge, Chrome disponible elif 'ERROR' in item_local.torrent_info and 'Introduce' in item_local.torrent_info: item_local.alive = "??" #link en error, CF challenge, ruta de descarga no disponible item_local.channel = 'setting' item_local.action = 'setting_torrent' item_local.unify = False item_local.folder = False item_local.item_org = item.tourl() elif 'ERROR' in item_local.torrent_info: item_local.alive = "no" #Calidad del link en error, CF challenge? else: item_local.alive = "ok" #Calidad del link verificada if item_local.channel != 'setting': item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío #logger.debug("TORRENT: " + scrapedurl + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) #Si es un lookup para cargar las urls de emergencia en la Videoteca... if item.videolibray_emergency_urls: return item #... nos vamos if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) if len(itemlist_t) == 0: if len(itemlist) == 0 or (len(itemlist) > 0 and itemlist[-1].server != 'torrent'): return [] itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def listado(item): # 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 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 + 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 = '' data, response, item, itemlist = generictools.downloadpage( next_page_url, timeout=timeout_search, canonical=canonical, item=item, itemlist=itemlist, quote_rep=False, check_blocked_IP=True) # Descargamos la página data = re.sub(r" ", "", data) # Verificamos si ha cambiado el Host if response.host: next_page_url = response.url_new 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 if len(itemlist) > 1: # Si hay algo que pintar lo pintamos last_page = 0 break logger.error( "ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + next_page_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 nada más, salimos directamente #Patrón para todo, incluido búsquedas en cualquier caso patron = '<tr class="lista2"><td align="(?:[^"]+)?"\s*class="(?:[^"]+)?"' patron += '\s*width="(?:[^"]+)?"\s*style="(?:[^"]+)?"><a href="[^"]+">' patron += '<img src="([^"]+)?"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*\/>' patron += '<\/a><\/td><td\s*align="(?:[^"]+)?"\s*class="(?:[^"]+)?"><a onmouseover="' patron += '(?:[^"]+)?"\s*onmouseout="(?:[^"]+)?"\s*href="[^"]+" title="[^"]+"' patron += '>([^<]+)<\/a>\s*<a href="([^"]+)"><img src="[^"]+"\s*border="' patron += '(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>\s*(?:<a href="([^"]+)">' patron += '<img src="[^"]+"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>)?' patron += '\s*<br><span.*?<\/span>\s*<\/td><td align="(?:[^"]+)?"\s*width="' patron += '(?:[^"]+)?"\s*class="(?:[^"]+)?">.*?<\/td><td align="(?:[^"]+)?"\s*' patron += 'width="(?:[^"]+)?"\s*class="(?:[^"]+)?">([^<]+)?<\/td><td align="' patron += '(?:[^"]+)?"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">\s*' patron += '<font color="(?:[^"]+)?">(\d+)?<\/font>' 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 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, response, item, itemlist = generictools.downloadpage( item.url + '&page=%s' % last_page, timeout=timeout_search, quote_rep=False, item=item, itemlist=itemlist) data_last = re.sub(r" ", "", data_last) last_page = int( scrapertools.find_single_match( data_last, patron_last)) #lo cargamos como entero except: #Si no lo encuentra, lo ponemos a 1 #logger.error('ERROR 03: LISTADO: Al obtener la paginación: ' + patron_next + ' / ' + patron_last + ' / ' + scrapertools.find_single_match(data, "<ul class=\"pagination\">.*?<\/span><\/a><\/li><\/ul><\/nav><\/div><\/div><\/div>")) last_page = next_page #logger.debug('curr_page: ' + str(curr_page) + ' / next_page: ' + str(next_page) + ' / last_page: ' + str(last_page)) #Empezamos el procesado de matches for scrapedthumbnail, scrapedtitle, scrapedurl, scrapedepisodes, scrapedsize, scrapedseeds in matches: title = scrapedtitle if scrapedepisodes: url = scrapedepisodes else: url = scrapedurl size = scrapedsize # Slugify, pero más light title = title.replace("á", "a").replace("é", "e").replace("í", "i")\ .replace("ó", "o").replace("ú", "u").replace("ü", "u")\ .replace("�", "ñ").replace("ñ", "ñ") title = scrapertools.decode_utf8_error(title) if scrapedurl in title_lista: #Si ya hemos procesado el título, lo ignoramos continue else: title_lista += [scrapedurl] #la añadimos a la lista de títulos #cnt_title += 1 item_local = item.clone() #Creamos copia de Item para trabajar if item_local.tipo: #... y limpiamos del item_local.tipo if item_local.totalItems: del item_local.totalItems if item_local.intervencion: del item_local.intervencion if item_local.viewmode: del item_local.viewmode item_local.extra2 = True del item_local.extra2 item_local.text_bold = True del item_local.text_bold item_local.text_color = True del item_local.text_color title_subs = [] #creamos una lista para guardar info importante item_local.language = ['VO'] #creamos lista para los idiomas item_local.quality = '' #iniciamos calidad item_local.thumbnail = scrapedthumbnail #iniciamos thumbnail if item.extra == 'search': if scrapedepisodes: item_local.extra = 'series' else: item_local.extra = 'peliculas' item_local.url = urlparse.urljoin(host, url) #guardamos la url final if item_local.extra != 'series': item_local.url += '&order=size&by=ASC' #guardamos la url final item_local.context = "['buscar_trailer']" item_local.contentType = "movie" #por defecto, son películas item_local.action = "findvideos" #Analizamos los formatos de la películas if item_local.extra == 'peliculas': patron_title = '(.*?)\.([1|2][9|0]\d{2})?\.(.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): logger.error('ERROR tratando título PELI: ' + title) continue try: title, year, item_local.quality = scrapertools.find_single_match( title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') #Analizamos los formatos de series, temporadas y episodios elif item_local.extra == 'series': patron_title = '(.*?)(\.[1|2][9|0]\d{2})?\.S\d{2}.*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): patron_title = '(.*?)\.*([1|2][9|0]\d{2})?(?:\.\d{2}\.\d{2}).*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): logger.error('ERROR tratando título SERIE: ' + title) continue try: title, year, item_local.quality = scrapertools.find_single_match( title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') year = '-' item_local.contentType = "tvshow" item_local.action = "episodios" item_local.season_colapse = True #Muestra las series agrupadas por temporadas #Limpiamos el título de la basura innecesaria title = re.sub(r'(?i)TV|Online', '', title).strip() item_local.quality = re.sub( r'(?i)proper|unrated|directors|cut|german|repack|internal|real|korean|extended|masted|docu|oar|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Analizamos el año. Si no está claro ponemos '-' try: year_int = int(year) if year_int >= 1940 and year_int <= 2050: item_local.infoLabels["year"] = year_int else: item_local.infoLabels["year"] = '-' except: item_local.infoLabels["year"] = '-' #Terminamos de limpiar el título title = re.sub(r'[\(|\[]\s+[\)|\]]', '', title) title = title.replace('()', '').replace('[]', '').strip().lower().title() item_local.from_title = title.strip().lower().title( ) #Guardamos esta etiqueta para posible desambiguación de título #Salvamos el título según el tipo de contenido if item_local.contentType == "movie": item_local.contentTitle = title else: item_local.contentSerieName = title.strip().lower().title() item_local.title = title.strip().lower().title() #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB item_local.title_subs = title_subs #Salvamos y borramos el número de temporadas porque TMDB a veces hace tonterias. Lo pasamos como serie completa if item_local.contentSeason and (item_local.contentType == "season" or item_local.contentType == "tvshow"): item_local.contentSeason_save = item_local.contentSeason del item_local.infoLabels['season'] #Ahora se filtra por idioma, si procede, y se pinta lo que vale if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist = filtertools.get_link(itemlist, item_local, list_language) else: itemlist.append(item_local.clone()) #Si no, pintar pantalla cnt_title = len(itemlist) #Contador de líneas añadidas #logger.debug(item_local) #Pasamos a TMDB la lista completa Itemlist tmdb.set_infoLabels(itemlist, __modo_grafico__, idioma_busqueda='es,en') #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB item, itemlist = generictools.post_tmdb_listado(item, itemlist) # Si es necesario añadir paginacion if curr_page <= last_page: if last_page: title = '%s de %s' % (curr_page - 1, last_page) else: title = '%s' % curr_page - 1 itemlist.append( Item(channel=item.channel, action="listado", title=">> Página siguiente " + title, title_lista=title_lista, url=next_page_url, extra=item.extra, extra2=item.extra2, last_page=str(last_page), curr_page=str(curr_page))) return itemlist
def calidades(item): logger.info() itemlist = [] data = '' patron = '<div align="[^"]+"><div style="[^"]+" id="divadvsearch">(.*?)<\/a><\/div><\/div><\/form><\/div>' data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, canonical=canonical, patron=patron, item=item, itemlist=[], quote_rep=False, check_blocked_IP=True) # Descargamos la página if not response.sucess or itemlist: # Si ERROR o lista de errores lo reintentamos con otro Host return itemlist # ... Salimos data = scrapertools.find_single_match(data, patron) #Seleccionamos el bloque patron = '<div class="divadvscat"><input class="inputadvscat" type="checkbox" ' patron += 'name="category\[.*?\]" value="[^"]+"\s*(?:.*?)?\/> <a href="([^"]+)">(.*?)<\/a>\s*<\/div>\s*' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log' )) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug(patron) #logger.debug(matches) #logger.debug(data) itemlist.append( item.clone(action="listado", title="ALL", extra2="calidades")) for scrapedurl, scrapedtitle in matches: if not "Mov" in scrapedtitle and item.extra == 'peliculas': continue if not "TV" in scrapedtitle and item.extra == 'series': continue title = scrapedtitle.strip().replace('Movs/', '').replace('Movies/', '') url = urlparse.urljoin(host, scrapedurl + "&search=&order=data&by=DESC") itemlist.append( item.clone(action="listado", title=title, url=url, extra2="calidades")) return itemlist
def 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 episodios(item): logger.info() itemlist = [] season = 1 episode = 1 download_connector = config.get_setting('download_connector', channel, default=0) download_connectors = ["Torrent", "Okru", "Mega", "UpStream"] try: download_preference = download_connectors[download_connector] except: download_preference = download_connectors[0] logger.error(traceback.format_exc(1)) #logger.debug(item) # Descargamos evento data, success, code, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, s2=False, item=item, itemlist=[]) # Descargamos la página if not success: return itemlist item.contentPlot = '%s[B]%s %s[/B]\n\n' % (item.contentPlot, item.title, item.infoLabels['aired']) # Obtenemos el thumb del evento patron = 'data-widget_type="image.default">.*?data-src="([^"]+)"' if scrapertools.find_single_match(data, patron): item.thumbnail = scrapertools.find_single_match(data, patron) item.contentThumbnail = item.thumbnail # Localizamos los datos del Evento patron = '<meta\s*property="og:description"\s*content="([^"]+)\s*DESCARGAS\s*SESIONES\s*VOD' if scrapertools.find_single_match(data, patron): # Circuito item.contentPlot += '[COLOR yellow][B]%s:[/B][/COLOR]\n' % scrapertools.find_single_match( data, patron).capitalize() # Procesamos los eventos patron_eventos = '<li\s*class[^>]*>\s*<span\s*class="eael-tab-title"\s*>\s*([^<]*)<\/span>\s*<\/li>' eventos = re.compile(patron_eventos, re.DOTALL).findall(data) patron_descargas = '<iframe\s*src="([^"]+)"[^>]*>\s*<\/iframe>(?:\s*<\/p>)?(?:<p>)?(?:\s*<a\s*class="boton"\s*href="([^"]*)")?' descargas = re.compile(patron_descargas, re.DOTALL).findall(data) #logger.debug("PATRON Eventos: " + patron_eventos) #logger.debug(eventos) #logger.debug("PATRON Descargas: " + patron_descargas) #logger.debug(descargas) #logger.debug(data) for x, actividad in enumerate(eventos): item_local = item.clone() item_local.action = "findvideos" item_local.contentType = session item_local.matches = [] item_local.title = actividad item_local.contentTitle = item_local.title try: enlaces = descargas[x] except: enlaces = [] for enlace in enlaces: server = 'Torrent' if 'ok.ru' in enlace: server = 'Okru' elif 'mega' in enlace: server = 'Mega' elif 'upstream' in enlace: server = 'UpStream' elif 'torrent' in enlace: enlace = urlparse.urljoin(host, enlace) if not enlace.startswith('http'): enlace = 'https:' + enlace if server == download_preference: item_local.matches.insert(0, (enlace, server)) else: item_local.matches.append((enlace, server)) item_local.contentSeason = season item_local.contentEpisodeNumber = episode episode += 1 itemlist.append(item_local.clone()) return itemlist
def episodios(item): logger.info() itemlist = [] item.url_enlaces = [] season = 1 episode = 1 download_connector = config.get_setting('download_connector', channel, default=0) download_connectors = [ "Torrent", "Ok", "Mega", "UpStream" ] try: download_preference = download_connectors[download_connector] except: download_preference = download_connectors[0] logger.error(traceback.format_exc(1)) #logger.debug(item) # Descargamos evento data, success, code, item, itemlist = generictools.downloadpage(item.url, timeout=timeout, s2=False, item=item, itemlist=[]) # Descargamos la página if not success: return itemlist item.contentPlot = '%s[B]%s %s[/B]\n\n' % (item.contentPlot, item.title, item.infoLabels['aired']) # Obtenemos el thumb del evento patron = '<div class="elementor-image">\s*<img\s*width="[^"]*"\s*height="[^"]*"\s*src="([^"]+)"' if scrapertools.find_single_match(data, patron): item.thumbnail = scrapertools.find_single_match(data, patron) item.contentThumbnail = item.thumbnail # Localizamos los datos del Evento patron = '(?i)<h2\s*class="elementor-heading-title[^>]+>\s*CIRCUITO\s*DE\s*(.*?)\s*<\/h2>' if scrapertools.find_single_match(data, patron): # Circuito item.contentPlot += '[COLOR yellow][B]%s:[/B][/COLOR]\n' % scrapertools.find_single_match(data, patron).capitalize() patron = '<tr><th\s*scope="row">(.*?)<\/th><td colspan[^<]+>(.*?)<\/td><\/tr>' # Detalles del Circuito datos_evento = re.compile(patron, re.DOTALL).findall(data) for clave, valor in datos_evento: if 'Vuelta' not in clave: item.contentPlot += '- %s: %s\n' % (clave, valor) else: patron = '(.*?)(?:<br\s*\/>\s*)?<span.*?<\/span>(.*?)(?:<br\s*\/>\s*)?<span.*?<\/span>(.*?)(?:<br\s*\/>\s*)?$' if scrapertools.find_single_match(valor, patron): tiempo, deportista, equipo = scrapertools.find_single_match(valor, patron) tiempo = scrapertools.remove_htmltags(tiempo) # Removemos Tags del título item.contentPlot += '- %s: %s, %s, %s\n' % (clave, tiempo, deportista, equipo) # Procesamos los eventos patron = '<div[^>]+>(?:\s*<p>)?\s*<iframe\s*[^>]+>\s*<\/iframe>(?:\s*<\/p>)?\s*' patron += '<p\s*style[^>]+>\s*<a\s*href="([^"]+)"\s*(?:target[^>]+)?>\s*' patron +='(?:Descargar \w+)?\s*(.*?)\s*<\/a><\/p><\/div>' # Una sola sesión if scrapertools.find_single_match(data, patron): item_local = item.clone() item_local.url_enlaces = [(scrapertools.find_single_match(data, patron))] item_local.action = "findvideos" item_local.contentType = session return findvideos(item_local) patron = '<div\s*id="elementor-tab-title[^>]+>.*?<\/span>\s*<a\s*href="[^"]*"\s*(.*?)\s*<\/div>\s*<\/div>' # Varias sesiones eventos = re.compile(patron, re.DOTALL).findall(data) #logger.debug("PATRON: " + patron) #logger.debug(eventos) #logger.debug(data) for actividad in eventos: item_local = item.clone() item_local.action = "findvideos" item_local.contentType = session item_local.url_enlaces = [] patron = 'class="elementor-toggle-title">(.*?)<\/a>' item_local.title = scrapertools.find_single_match(actividad, patron) item_local.contentTitle = item_local.title if not item_local.title: return itemlist # Enlace por defecto de Okru patron = '(?:<p>)?<iframe.*?src="([^"]+)"[^<]+><\/iframe>' enlace = scrapertools.find_single_match(actividad, patron) if enlace and 'ok.ru' in enlace: if not enlace.startswith('http'): enlace = 'https:' + enlace item_local.url_enlaces.append((enlace, 'Okru')) # Otros enlaces patron = '(?:<p>)?<a\s*href="([^"]+)"[^>]*>(?:\s*Descargar\s*\w+)?\s*(.*?)\s*<\/a>' enlaces_descargas = re.compile(patron, re.DOTALL).findall(actividad) for enlace, server in enlaces_descargas: if enlace and server: if not enlace.startswith('http'): enlace = 'https:' + enlace if server == download_preference: item_local.url_enlaces.insert(0, (enlace, server)) else: item_local.url_enlaces.append((enlace, server)) item_local.contentSeason = season item_local.contentEpisodeNumber = episode episode += 1 itemlist.append(item_local.clone()) return itemlist
def listado(item): # Listado principal logger.info() itemlist = [] matches = [] logos = {'Fórmula 1': '/f1-logo', 'Fórmula 2': '/f2-', 'Fórmula E': '/fe-', 'MotoGP': '/moto-gp', 'Moto2': '/moto2', 'Moto3': '/moto3'} item.category = categoria #logger.debug(item) cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_offset = 0 # offset para cnt_title en searchs curr_page = 1 last_page = 999 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 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 (next_page_url and 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 item.extra2 == 'novedades': patron = '<div\s*class="elementor-widget-container">\s*<div\s*class=' patron += '"elementor-image">\s*<a\s*href="([^"]+)">\s*<img\s*(?:width="[^"]+"\s*' patron += 'height="[^"]+"\s*)?src="([^"]+)"\s*class="attachment-medium_large\s*' patron += 'size-medium_large"\s*alt="[^"]*"\s*(?:loading="[^"]*"\s*)?srcset=.*?<h4\s*class=' patron += '"elementor-heading[^>]+>\s*<a\s*href="[^"]+">\s*(.*?)\s*<\/a>\s*<\/h4>' else: patron = '<article\s*class="[^>]+>\s*<div\s*class="elementor-post__card">\s*' patron += '<a\s*class="[^"]+"\s*href="([^"]+)"\s*>\s*<div\s*class=' patron += '"elementor-post__thumbnail"\s*>\s*<\s*img.*?src="([^"]+)".*?' patron += '<h3\s*class="elementor-post__title"\s*>\s*<a href="[^"]+"\s*>' patron += '\s*(.*?)\s*<\/a>\s*<\/h3>\s*<\/div>\s*<\/div>\s*<\/article>' 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, s2=False, patron=patron, 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 # Comprobar si hay más páginas patron_page = '<a\s*class="page-numbers[^"]+"\s*href="([^"]+)">Siguiente' if scrapertools.find_single_match(data, patron_page): next_page_url = scrapertools.find_single_match(data, patron_page) else: next_page_url = '' 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) # Iniciamos el Plot y marcamos TMDB como no usable item.contentPlot = '[COLOR gold][B]%s[/B][/COLOR]%s\n\n' % (item.title, item.channel_sufix) #iniciamos el Plot con el Deporte item.from_title = '%s - ' % item.title item.infoLabels['tmdb_id'] = null #Empezamos el procesado de matches for scrapedurl, scrapedthumb, scrapedtitle in matches: #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() cnt_match += 1 title = scrapedtitle title = scrapertools.remove_htmltags(title).rstrip('.') # Removemos Tags del título title = title.replace("á", "a").replace("é", "e").replace("í", "i")\ .replace("ó", "o").replace("ú", "u").replace("ü", "u")\ .replace("�", "ñ").replace("ñ", "ñ").replace("’", "'")\ .replace("&", "&") cnt_title += 1 # Incrementamos el contador de entradas válidas # Procesamos idiomas item_local.language = [] #creamos lista para los idiomas if not item_local.language: item_local.language = ['CAST'] # [CAST] por defecto # Procesamos Calidad if not item_local.quality: item_local.quality = 'HDTV' item_local.thumbnail = scrapedthumb #iniciamos thumbnail item_local.contentThumbnail = scrapedthumb #iniciamos thumbnail item_local.infoLabels['fanart'] = scrapedthumb #iniciamos Fanart # Para Novedades buscamos el Deporte en los thumbs if item_local.extra2 == 'novedades': for sport, logo in list(logos.items()): if logo in item_local.thumbnail.lower(): item_local.contentPlot = '[COLOR gold][B]%s[/B][/COLOR]%s\n\n' % (sport, item.channel_sufix) item_local.from_title = '%s - ' % sport break item_local.url = scrapedurl #iniciamos la url item_local.url_tvshow = item_local.url # Guardamos los formatos para películas item_local.contentType = event item_local.action = "episodios" year = scrapertools.find_single_match(title, '\d{4}') if year: item_local.infoLabels['year'] = int(year) item_local.infoLabels['aired'] = str(year) title = re.sub(r'(?i)TV|Online|(4k-hdr)|(fullbluray)|4k| - 4k|(3d)|miniserie|\d{4}', '', title).strip() item_local.title = title.strip().lower().title() item_local.contentTitle = item_local.title item_local.from_title += item_local.title #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) - cnt_offset # 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 # Enlace a Temporadas anteriores if item.extra2 != 'novedades': patron = '<h2\s*class=".*?<a\s*href="([^"]+)"\s*class="' url_temp_anteriores = scrapertools.find_single_match(data, patron) itemlist.insert(0,item.clone(title="Temporadas anteriores", url=url_temp_anteriores, action="temporadas_anteriores", thumbnail=thumb_sports, url_tvshow = url_temp_anteriores, language=['CAST'], quality = 'HDTV')) 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 patron_temp = '<h1\s*class="[^"]+">Season\s*(\d+)<\/h1><div class="tvcontent">' patron_temp += '<div id="[^"]+"><\/div>(.*?<\/div><\/div>)(?:<script>.*?<\/script>)?<\/div>' data = '' #Inserto en num de página en la url data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, canonical=canonical, patron=patron_temp, item=item, itemlist=[], quote_rep=False, check_blocked_IP=True) data = re.sub(r" ", "", data) if not data or response.code in [ 999, 99 ]: # Si ERROR o lista de errores lo reintentamos con otro Host return itemlist # ... Salimos #Capturamos las temporadas de episodios dentro de la serie 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="[^"]+"' patron += '\s*class="[^"]+"><div class="[^"]+">.*?\s*(\d+)<\/div>\s*(.*?)\s*<' matches = re.compile(patron, re.DOTALL).findall(temporada) if not matches: #error 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 play( item ): #Permite preparar la descarga de los .torrents y subtítulos externos logger.info() itemlist = [] headers = [] from core import downloadtools from core import ziptools from core import filetools #buscamos la url del .torrent patron = '<tr><td align="(?:[^"]+)?"\s*class="(?:[^"]+)?"\s*width="(?:[^"]+)?">' patron += '\s*Torrent:<\/td><td class="(?:[^"]+)?">\s*<img src="(?:[^"]+)?"\s*' patron += 'alt="(?:[^"]+)?"\s*border="(?:[^"]+)?"\s*\/>\s*<a onmouseover="' patron += '(?:[^"]+)?"\s*onmouseout="(?:[^"]+)?" href="([^"]+)".*?<\/a>' data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, patron=patron, item=item, itemlist=[], quote_rep=False, check_blocked_IP=True) if not data or response.code in [ 999, 99 ]: # Si ERROR o lista de errores lo reintentamos con otro Host return itemlist # ... Salimos item.url = urlparse.urljoin(host, scrapertools.find_single_match(data, patron)) #buscamos subtítulos en español patron = '<tr><td align="(?:[^"]+)?"\s*class="(?:[^"]+)?"\s*>\s*Subs.*?<\/td><td class="(?:[^"]+)?"\s*>(.*?)(?:<br\/>)?<\/td><\/tr>' data_subt = scrapertools.find_single_match(data, patron) if data_subt: patron = '<a href="([^"]+)"\s*onmouseover="return overlib\(' patron += "'Download Spanish subtitles'" patron += '\)"\s*onmouseout="(?:[^"]+)?"\s*><img src="(?:[^"]+)?"\s*><\/a>' subt = scrapertools.find_single_match(data_subt, patron) if subt: item.subtitle = urlparse.urljoin(host, subt) if item.subtitle: #Si hay urls de sub-títulos, se descargan from core import httptools headers.append(["User-Agent", httptools.get_user_agent() ]) #Se busca el User-Agent por defecto videolibrary_path = config.get_videolibrary_path( ) #Calculamos el path absoluto a partir de la Videoteca if videolibrary_path.lower().startswith( "smb://"): #Si es una conexión SMB, usamos userdata local videolibrary_path = config.get_data_path( ) #Calculamos el path absoluto a partir de Userdata videolibrary_path = filetools.join(videolibrary_path, "subtitles") #Primero se borra la carpeta de subtitulos para limpiar y luego se crea if filetools.exists(videolibrary_path): filetools.rmtree(videolibrary_path) time.sleep(1) if not filetools.exists(videolibrary_path): filetools.mkdir(videolibrary_path) subtitle_name = 'Rarbg-ES_SUBT.zip' #Nombre del archivo de sub-títulos subtitle_folder_path = filetools.join(videolibrary_path, subtitle_name) #Path de descarga ret = downloadtools.downloadfile(item.subtitle, subtitle_folder_path, headers=headers, continuar=True, silent=True) if filetools.exists(subtitle_folder_path): # Descomprimir zip dentro del addon # --------------------------------- try: unzipper = ziptools.ziptools() unzipper.extract(subtitle_folder_path, videolibrary_path) except: import xbmc xbmc.executebuiltin('Extract("%s", "%s")' % (subtitle_folder_path, videolibrary_path)) time.sleep(1) # Borrar el zip descargado # ------------------------ filetools.remove(subtitle_folder_path) #Tomo el primer archivo de subtítulos como valor por defecto for raiz, subcarpetas, ficheros in filetools.walk( videolibrary_path): for f in ficheros: if f.endswith(".srt"): #f_es = 'rarbg_subtitle.spa.srt' f_es = scrapertools.find_single_match( item.url, '&f=(.*?).torrent$').replace('.', ' ').replace( '-', ' ').lower() + '.spa.srt' if not f_es: f_es = item.infoLabels['originaltitle'] + '.spa.srt' f_es = f_es.replace(':', '').lower() filetools.rename( filetools.join(videolibrary_path, f), filetools.join(videolibrary_path, f_es)) item.subtitle = filetools.join( videolibrary_path, f_es) #Archivo de subtitulos break break itemlist.append(item.clone()) #Reproducción normal return itemlist
def findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if not item.language: item.language = ['VO'] #VO por defecto matches = [] item.category = categoria #logger.debug(item) #Bajamos los datos de la página data = '' patron = '<tr class="lista2">\s*<td align="(?:[^"]+)?"\s*class="(?:[^"]+)?' patron += '"\s*width="(?:[^"]+)?"\s*style="(?:[^"]+)?">\s*<a href="[^"]+">\s*' patron += '<img src="([^"]+)?"\s*border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*\/><\/a><\/td>\s*' patron += '<td\s*align="(?:[^"]+)?"(?:\s*width="[^"]+")?\s*class="(?:[^"]+)?">\s*' patron += '<a onmouseover="(?:[^"]+)?"\s*onmouseout="(?:[^"]+)?"\s*href="([^"]+)"' patron += ' title="[^"]+">(.*?)<\/a>\s*<a href="[^"]+">\s*<img src="[^"]+"\s*' patron += 'border="(?:[^"]+)?"\s*alt="(?:[^"]+)?"\s*><\/a>(?:\s*<a.*?<\/a>)?' patron += '\s*<br><span.*?<\/span>\s*<\/td>\s*<td align="(?:[^"]+)?"\s*width="' patron += '(?:[^"]+)?"\s*class="(?:[^"]+)?">.*?<\/td>\s*<td align="(?:[^"]+)?' patron += '"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">(.*?)?<\/td>\s*<td align="(?:[^"]+)?' patron += '"\s*width="(?:[^"]+)?"\s*class="(?:[^"]+)?">\s*<font color="(?:[^"]+)?">(\d+)?<\/font>' data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, canonical=canonical, patron=patron, item=item, itemlist=itemlist, quote_rep=False, check_blocked_IP=True) if not data or response.code in [ 999, 99 ]: # Si ERROR o lista de errores lo reintentamos con otro Host return itemlist # ... Salimos matches = re.compile(patron, re.DOTALL).findall(data) if not matches: #error logger.error( "ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web " + " / PATRON: " + patron + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: No hay enlaces o ha cambiado la estructura de la Web. Verificar en la Web esto último y reportar el error con el log', folder=False)) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) #Ahora tratamos los enlaces .torrent con las diferentes calidades for scrapedthumbnail, scrapedurl, scrapedtitle, scrapedsize, scrapedseeds in matches: #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() title = scrapedtitle #Analizamos los formatos de la películas y series if item_local.contentType == 'movie': patron_title = '(.*?)\.([1|2][9|0]\d{2})?\.(.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): continue else: patron_title = '(.*?)(\.[1|2][9|0]\d{2})?\.S\d{2}.*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): patron_title = '(.*?)\.*([1|2][9|0]\d{2})?(?:\.\d{2}\.\d{2}).*?\.([\d|A-Z]{2}.*?)(?:-.*?)?$' if not scrapertools.find_single_match(title, patron_title): continue try: title, year, item_local.quality = scrapertools.find_single_match( title, patron_title) except: title = scrapedtitle year = '' item_local.quality = '' title = title.replace('.', ' ') item_local.quality = item_local.quality.replace('.', ' ') item_local.quality = re.sub( r'(?i)proper|unrated|directors|cut|german|repack|internal|real|korean|extended|masted|docu|oar|super|duper|amzn|uncensored|hulu', '', item_local.quality).strip() #Buscamos si ya tiene tamaño, si no, los buscamos en el archivo .torrent size = scrapedsize if size: item_local.title = '%s [%s]' % ( item_local.title, size) #Agregamos size al final del título size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') item_local.torrent_info = '%s, ' % size #Agregamos size #Añadimos los seeds en calidad, como información adicional if scrapedseeds: item_local.torrent_info += 'Seeds: %s' % scrapedseeds #Agregamos seeds if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') #Ahora pintamos el link del Torrent item_local.url = urlparse.urljoin(host, scrapedurl) item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Torrent #Preparamos título y calidad, quitamos etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.quality = re.sub( r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality) item_local.quality = item_local.quality.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío #logger.debug("TORRENT: " + scrapedurl + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def listado(item): # 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 findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados matches = [] data = '' code = 0 #logger.debug(item) #Bajamos los datos de la página y seleccionamos el bloque patron = '\s*<th\s*class="hide-on-mobile">Total\s*Descargas<\/th>\s*<th>' patron += 'Descargar<\/th>\s*<\/thead>\s*<tbody>\s*(.*?<\/tr>)\s*<\/tbody>' patron += '\s*<\/table>\s*<\/div>\s*<\/div>\s*<\/div>' if not item.matches: data, success, code, item, itemlist = generictools.downloadpage(item.url, timeout=timeout, s2=False, patron=patron, item=item, itemlist=[]) # Descargamos la página) #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if (not data and not item.matches) or code == 999: if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? if len(item.emergency_urls) > 1: matches = item.emergency_urls[1] #Restauramos matches de vídeos item.armagedon = True #Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: #Si es llamado desde creación de Videoteca... return item #Devolvemos el Item de la llamada else: return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif data: # Seleccionamos el bloque y buscamos los apartados data = scrapertools.find_single_match(data, patron) 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="([^"]+)")?' if not item.armagedon: if not item.matches: matches = re.compile(patron, re.DOTALL).findall(data) else: matches = item.matches #logger.debug("PATRON: " + patron) #logger.debug(matches) #logger.debug(data) if not matches: #error return itemlist #Si es un lookup para cargar las urls de emergencia en la Videoteca... if item.videolibray_emergency_urls: item.emergency_urls = [] #Iniciamos emergency_urls item.emergency_urls.append([]) #Reservamos el espacio para los .torrents locales item.emergency_urls.append(matches) #Salvamnos matches de los vídeos... #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB if not item.videolibray_emergency_urls: item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) #Ahora tratamos los enlaces .torrent con las diferentes calidades for scrapedquality, scrapedlanguage, scrapedsize, scrapedurl, season_num, episode_num in matches: scrapedpassword = '' #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.url = scrapedurl # Restauramos urls de emergencia si es necesario local_torr = '' if item.emergency_urls and not item.videolibray_emergency_urls: item_local.torrent_alt = item.emergency_urls[0][0] #Guardamos la url del .Torrent ALTERNATIVA if item.armagedon: item_local.url = item.emergency_urls[0][0] #Restauramos la url if item_local.url.startswith("\\") or item_local.url.startswith("/"): from core import filetools if item.contentType == 'movie': FOLDER = config.get_setting("folder_movies") else: FOLDER = config.get_setting("folder_tvshows") local_torr = filetools.join(config.get_videolibrary_path(), FOLDER, item_local.url) if len(item.emergency_urls[0]) > 1: del item.emergency_urls[0][0] # Procesamos idiomas item_local.language = [] #creamos lista para los idiomas item_local.quality = scrapedquality # Copiamos la calidad if '[Subs. integrados]' in scrapedlanguage or '(Sub Forzados)' in scrapedlanguage \ or 'Subs integrados' in scrapedlanguage: item_local.language = ['VOS'] # añadimos VOS if 'castellano' in scrapedlanguage.lower() or ('español' in scrapedlanguage.lower() and not 'latino' in scrapedlanguage.lower()): item_local.language += ['CAST'] # añadimos CAST if 'dual' in item_local.quality.lower(): item_local.quality = re.sub(r'(?i)dual.*?', '', item_local.quality).strip() item_local.language += ['DUAL'] # añadimos DUAL if not item_local.language: item_local.language = ['LAT'] # [LAT] por defecto #Buscamos tamaño en el archivo .torrent size = '' if item_local.torrent_info: size = item_local.torrent_info elif scrapedsize: size = scrapedsize if not size and not item.videolibray_emergency_urls and not item_local.url.startswith('magnet:'): if not item.armagedon: size = generictools.get_torrent_size(item_local.url, local_torr=local_torr) #Buscamos el tamaño en el .torrent desde la web if 'ERROR' in size and item.emergency_urls and not item.videolibray_emergency_urls: item_local.armagedon = True item_local.url = item.emergency_urls[0][0] #Restauramos la url local_torr = filetools.join(config.get_videolibrary_path(), FOLDER, item_local.url) size = generictools.get_torrent_size(item_local.url, local_torr=local_torr) #Buscamos el tamaño en el .torrent emergencia if size: size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') item_local.torrent_info = '%s, ' % size #Agregamos size if item_local.url.startswith('magnet:') and not 'Magnet' in item_local.torrent_info: item_local.torrent_info += ' Magnet' if item_local.torrent_info: item_local.torrent_info = item_local.torrent_info.strip().strip(',') item.torrent_info = item_local.torrent_info if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info # Guadamos la password del RAR password = scrapedpassword # Si tiene contraseña, la guardamos y la pintamos if password or item.password: if not item.password: item.password = password item_local.password = item.password itemlist.append(item.clone(action="", title="[COLOR magenta][B] Contraseña: [/B][/COLOR]'" + item_local.password + "'", folder=False)) # Guardamos urls de emergencia si se viene desde un Lookup de creación de Videoteca if item.videolibray_emergency_urls: item.emergency_urls[0].append(item_local.url) #guardamos la url y nos vamos continue if item_local.armagedon: item_local.quality = '[COLOR hotpink][E][/COLOR] [COLOR limegreen]%s[/COLOR]' % item_local.quality #Ahora pintamos el link del Torrent item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título y calidad, quitando etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace("[]", "")\ .replace("()", "").replace("(/)", "").replace("[/]", "")\ .replace("|", "").strip() item_local.quality = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality) item_local.quality = item_local.quality.replace("--", "").replace("[]", "")\ .replace("()", "").replace("(/)", "").replace("[/]", "")\ .replace("|", "").strip() if not size or 'Magnet' in size: item_local.alive = "??" #Calidad del link sin verificar elif 'ERROR' in size and 'Pincha' in size: item_local.alive = "ok" #link en error, CF challenge, Chrome disponible elif 'ERROR' in size and 'Introduce' in size: item_local.alive = "??" #link en error, CF challenge, ruta de descarga no disponible item_local.channel = 'setting' item_local.action = 'setting_torrent' item_local.unify = False item_local.folder = False item_local.item_org = item.tourl() elif 'ERROR' in size: item_local.alive = "no" #Calidad del link en error, CF challenge? else: item_local.alive = "ok" #Calidad del link verificada if item_local.channel != 'setting': item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append(item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting('filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link(itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío #logger.debug("TORRENT: " + scrapedurl + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) #Si es un lookup para cargar las urls de emergencia en la Videoteca... if item.videolibray_emergency_urls: return item #... nos vamos if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len(itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb("next.png") #... pintamos todo con aviso itemlist.append(Item(channel=item.channel, url=host, title="[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend(itemlist_t) #Pintar pantalla con todo si no hay filtrado # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def submenu(item): logger.info() from datetime import date todays_date = date.today() itemlist = [] item.filter_lang = True patron = '<div class="cab_menu"\s*>.*?<\/div>' #Menú principal data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, s2=False, canonical=canonical, patron=patron, item=item, itemlist=[]) # Descargamos la página # Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not response.sucess or itemlist: # Si ERROR o lista de errores ... return itemlist # ... Salimos data1 = scrapertools.find_single_match(data, patron) patron = '<div id="menu_langen"\s*>.*?<\/div>' #Menú de idiomas data1 += scrapertools.find_single_match(data, patron) patron = '<a href="(.*?)".*?title="(.*?)"' #Encontrar todos los apartados matches = re.compile(patron, re.DOTALL).findall(data1) #logger.debug(patron) #logger.debug(matches) #logger.debug(data) if not matches: logger.error( "ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. ' + 'Reportar el error con el log')) return itemlist # Si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.replace(" torrent", "").replace(" Torrent", "").replace("Series y ", "").title() if item.extra in ['novedades'] and 'estreno' in scrapedurl: if str(todays_date.year) in scrapedurl: title = 'Estrenos %s' % todays_date.year elif str(todays_date.year - 1) in scrapedurl: title = 'Estrenos %s' % str(todays_date.year - 1) else: continue item.url = scrapedurl item.title = title return listado(item) elif item.extra not in ['novedades']: if 'estreno' in scrapedurl: continue if "castellano" in scrapedtitle.lower( ): # Evita la entrada de peliculas castellano del menú de idiomas continue if item.extra == "series": # Tratamos Series if not "/serie" in scrapedurl: continue else: # Tratamos Películas if "/serie" in scrapedurl: continue if 'subtitulado' in scrapedtitle.lower( ) or 'latino' in scrapedtitle.lower( ) or 'original' in scrapedtitle.lower(): item.filter_lang = False itemlist.append( item.clone(action="listado", title=title, url=scrapedurl)) if item.extra == "series": # Añadimos Series VOSE que está fuera del menú principal itemlist.append( item.clone(action="listado", title="Series VOSE", url=host + "series-vose/", filter_lang=False)) # Generos if item.extra == 'peliculas': patron = '<li\s*id="mas_categorias">\s*<i[^>]*>\s*<\/i>\s*categorias<\/li>(.*?)\/ul>' data1 = scrapertools.find_single_match(data, patron) patron = '<li>\s*<a\s*rel="nofollow"\s*href="([^"]+)"\s*title="[^"]+">\s*([^<]+)<\/a>\s*<\/li>' matches = re.compile(patron, re.DOTALL).findall(data1) #logger.debug(patron) #logger.debug(matches) #logger.debug(data1) if not matches: return itemlist itemlist.append(item.clone(action='', title='Géneros', url='')) for scrapedurl, scrapedtitle in sorted(matches): title = scrapertools.decode_utf8_error(scrapedtitle) itemlist.append( item.clone(action="listado", title=' - ' + title, url=scrapedurl)) 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 findvideos(item): logger.info() itemlist = [] itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if not item.language: item.language = ['CAST'] #Castellano por defecto post = None forced_proxy_opt = None referer = None if item.post: # Rescatamos el Post, si lo hay post = item.post if item.referer: referer = item.referer torrent_params = { 'url': item.url, 'torrents_path': None, 'local_torr': item.torrents_path, 'lookup': False, 'force': True, 'data_torrent': True, 'subtitles': True, 'file_list': True } #Bajamos los datos de la página if not item.matches: data, response, item, itemlist = generictools.downloadpage( item.url, timeout=timeout, canonical=canonical, post=post, referer=referer, forced_proxy_opt=forced_proxy_opt, s2=False, item=item, itemlist=[]) # Descargamos la página) if not data and not item.matches: logger.error( "ERROR 01: FINDVIDEOS: La Web no responde o la URL es erronea: " + item.url + " / DATA: " + data) itemlist.append(item.clone(action='', title=item.channel.capitalize() + \ ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log', folder=False)) if item.emergency_urls and not item.videolibray_emergency_urls: # Hay urls de emergencia? link_torrent = item.emergency_urls[0][ 0] # Guardamos la url del .Torrent link_magnet = item.emergency_urls[1][ 0] # Guardamos la url del .Magnet item.armagedon = True # Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: # Si es llamado desde creación de Videoteca... return item # Devolvemos el Item de la llamada else: return itemlist # si no hay más datos, algo no funciona, pintamos lo que tenemos patron_t = '(?:<div\s*class="enlace_descarga"[^>]+>\s*<a\s*href=)?"([^"]+\.torrent)"' patron_m = '(?:<div\s*class="enlace_descarga"[^>]+>\s*<a\s*href=)?"(magnet:?[^"]+)"' if not item.armagedon: # Si es un proceso normal, seguimos data_links = data for x in range(2): link_torrent = scrapertools.find_single_match(data_links, patron_t) if link_torrent: link_torrent = urlparse.urljoin(host, link_torrent) link_torrent = link_torrent.replace( " ", "%20") # sustituimos espacios por %20, por si acaso #logger.info("link Torrent: " + link_torrent) link_magnet = scrapertools.find_single_match(data_links, patron_m) #logger.info("link Magnet: " + link_magnet) if not (link_torrent and link_magnet) and x == 0: data_links = generictools.identifying_links(data_links) #Si es un lookup para cargar las urls de emergencia en la Videoteca... if (link_torrent or link_magnet) and item.videolibray_emergency_urls: item.emergency_urls = [] item.emergency_urls.append([link_torrent ]) #Salvamos el enlace de .torrent item.emergency_urls.append([link_magnet ]) #Salvamos el enlace de .magnet return item #... y nos vamos #Añadimos el tamaño para todos size = scrapertools.find_single_match(item.quality, '\s\[(\d+,?\d*?\s\w\s*[b|B]s*)\]') if size: item.title = re.sub('\s\[\d+,?\d*?\s\w\s*[b|B]s*\]', '', item.title) #Quitamos size de título, si lo traía item.quality = re.sub( '\s\[\d+,?\d*?\s\w\s*[b|B]s*\]', '', item.quality) #Quitamos size de calidad, si lo traía if not link_torrent and not link_magnet: #error item = generictools.web_intervenida( item, data) #Verificamos que no haya sido clausurada if item.intervencion: #Sí ha sido clausurada judicialmente item, itemlist = generictools.post_tmdb_findvideos( item, itemlist) #Llamamos al método para el pintado del error else: logger.error( "ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron_t + " / " + patron_m + " / DATA: " + data) itemlist.append( item.clone( action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log', folder=False)) if item.emergency_urls and not item.videolibray_emergency_urls: #Hay urls de emergencia? link_torrent = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent link_magnet = item.emergency_urls[1][ 0] #Guardamos la url del .Magnet item.armagedon = True #Marcamos la situación como catastrófica else: if item.videolibray_emergency_urls: #Si es llamado desde creación de Videoteca... return item #Devolvemos el Item de la llamada else: return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Llamamos al método para crear el título general del vídeo, con toda la información obtenida de TMDB item, itemlist = generictools.post_tmdb_findvideos(item, itemlist) if not size and not item.armagedon: torrent_params['url'] = link_torrent torrent_params = generictools.get_torrent_size( link_torrent, torrent_params=torrent_params, referer=host, item=item) # Tamaño en el .torrent size = torrent_params['size'] if torrent_params['torrents_path']: item.torrents_path = torrent_params['torrents_path'] if size: size = size.replace('GB', 'G·B').replace('Gb', 'G·b').replace('MB', 'M·B')\ .replace('Mb', 'M·b').replace('.', ',') #Ahora pintamos el link del Torrent, si lo hay if link_torrent: # Hay Torrent ? #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.torrent_info = "[Torrent] " item_local.torrent_info += '%s' % size #Agregamos size if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') if item.armagedon: #Si es catastrófico, lo marcamos item_local.quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % item_local.quality item_local.url = link_torrent if item_local.url and item.emergency_urls and not item.armagedon: item_local.torrent_alt = item.emergency_urls[0][ 0] #Guardamos la url del .Torrent ALTERNATIVA item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Torrent #Preparamos título y calidad, quitamos etiquetas vacías item_local.title = re.sub(r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.title) item_local.title = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.title) item_local.title = item_local.title.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() item_local.quality = re.sub( r'\s?\[COLOR \w+\]\[\[?\s?\]?\]\[\/COLOR\]', '', item_local.quality) item_local.quality = re.sub(r'\s?\[COLOR \w+\]\s?\[\/COLOR\]', '', item_local.quality) item_local.quality = item_local.quality.replace("--", "").replace( "[]", "").replace("()", "").replace("(/)", "").replace("[/]", "").strip() if not size or 'Magnet' in size: item_local.alive = "??" # Calidad del link sin verificar elif 'ERROR' in size and 'Pincha' in size: item_local.alive = "ok" # link en error, CF challenge, Chrome disponible elif 'ERROR' in size and 'Introduce' in size: item_local.alive = "??" # link en error, CF challenge, ruta de descarga no disponible item_local.channel = 'setting' item_local.action = 'setting_torrent' item_local.unify = False item_local.folder = False item_local.item_org = item.tourl() elif 'ERROR' in size: item_local.alive = "no" # Calidad del link en error, CF challenge? else: item_local.alive = "ok" # Calidad del link verificada if item_local.channel != 'setting': item_local.action = "play" # Visualizar vídeo item_local.server = "torrent" # Seridor Torrent itemlist_t.append( item_local.clone()) # Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: # Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado #Ahora pintamos el link del Magnet, si lo hay itemlist_t = [] #Itemlist total de enlaces itemlist_f = [] #Itemlist de enlaces filtrados if link_magnet: # Hay Magnet ? #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() item_local.torrent_info = "[Magnet] " item_local.torrent_info += '%s' % size #Agregamos size if not item.unify: item_local.torrent_info = '[%s]' % item_local.torrent_info.strip( ).strip(',') if item.armagedon: #Si es catastrófico, lo marcamos item_local.quality = '[/COLOR][COLOR hotpink][E] [COLOR limegreen]%s' % item_local.quality item_local.url = link_magnet item_local.title = '[[COLOR yellow]?[/COLOR]] [COLOR yellow][Torrent][/COLOR] ' \ + '[COLOR limegreen][%s][/COLOR] [COLOR red]%s[/COLOR] %s' % \ (item_local.quality, str(item_local.language), \ item_local.torrent_info) #Preparamos título de Magnet item_local.title = re.sub(r'\s\[COLOR \w+\]\[\[?\]?\]\[\/COLOR\]', '', item_local.title) #Quitamos etiquetas vacías item_local.title = re.sub(r'\s\[COLOR \w+\]\[\/COLOR\]', '', item_local.title) #Quitamos colores vacíos item_local.alive = "??" #Calidad del link sin verificar item_local.action = "play" #Visualizar vídeo item_local.server = "torrent" #Seridor Torrent itemlist_t.append( item_local.clone()) #Pintar pantalla, si no se filtran idiomas # Requerido para FilterTools if config.get_setting( 'filter_languages', channel) > 0: #Si hay idioma seleccionado, se filtra itemlist_f = filtertools.get_link( itemlist_f, item_local, list_language) #Pintar pantalla, si no está vacío if len(itemlist_f) > 0: #Si hay entradas filtradas... itemlist.extend(itemlist_f) #Pintamos pantalla filtrada else: if config.get_setting('filter_languages', channel) > 0 and len( itemlist_t) > 0: #Si no hay entradas filtradas ... thumb_separador = get_thumb( "next.png") #... pintamos todo con aviso itemlist.append( Item( channel=item.channel, url=host, title= "[COLOR red][B]NO hay elementos con el idioma seleccionado[/B][/COLOR]", thumbnail=thumb_separador, folder=False)) itemlist.extend( itemlist_t) #Pintar pantalla con todo si no hay filtrado #logger.debug("TORRENT: " + link_torrent + "MAGNET: " + link_magnet + " / title gen/torr: " + item.title + " / " + item_local.title + " / calidad: " + item_local.quality + " / tamaño: " + size + " / content: " + item_local.contentTitle + " / " + item_local.contentSerieName) #logger.debug(item_local) # Requerido para AutoPlay autoplay.start(itemlist, item) #Lanzamos Autoplay return itemlist
def listado(item): # Listado principal logger.info() itemlist = [] matches = [] item.category = categoria #logger.debug(item) cnt_tot = 30 # Poner el num. máximo de items por página cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_offset = 0 # offset para cnt_title en searchs curr_page = 1 last_page = 999 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 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 (next_page_url and 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 patron = 'data-column-clickable="([^"]+")[^>]*data-id="([^"]+)".*?<h4\s*' patron += 'class="elementor-heading-title[^>]+>\s*<span1[^>]*>\s*([^<]*)' patron += '<\/span1>([^<]*)<\/h4>.*?<h5\s*class="elementor-image-box-title">\s*' patron += '([^<]+)<\/h5>\s*(?:<p\s*class="elementor-image-box-description">\s*([^<]+)<\/p>)?' 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, 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 # Comprobar si hay más páginas patron_page = '<a\s*class="page-numbers[^"]+"\s*href="([^"]+)">Siguiente' if scrapertools.find_single_match(data, patron_page): next_page_url = scrapertools.find_single_match(data, patron_page) else: next_page_url = '' 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) # Iniciamos el Plot y marcamos TMDB como no usable item.contentPlot = '[COLOR gold][B]%s[/B][/COLOR]%s\n\n' % ( item.title, item.channel_sufix) #iniciamos el Plot con el Deporte item.from_title = '%s - ' % item.title item.infoLabels['tmdb_id'] = null #Empezamos el procesado de matches for scrapedurl, scrapedthumb, scrapedtitle1, scrapedtitle2, date1, date2 in matches: #Generamos una copia de Item para trabajar sobre ella item_local = item.clone() cnt_match += 1 title = '%s%s: %s %s' % (scrapedtitle1, scrapedtitle2, date1, date2) title = scrapertools.remove_htmltags(title).rstrip( '.') # Removemos Tags del título title = title.replace("á", "a").replace("é", "e").replace("í", "i")\ .replace("ó", "o").replace("ú", "u").replace("ü", "u")\ .replace("�", "ñ").replace("ñ", "ñ").replace("’", "'")\ .replace("&", "&") cnt_title += 1 # Incrementamos el contador de entradas válidas # Procesamos idiomas item_local.language = [] #creamos lista para los idiomas if not item_local.language: item_local.language = ['CAST'] # [CAST] por defecto # Procesamos Calidad if not item_local.quality: item_local.quality = 'HDTV' patron_thumb = '\.elementor-element\.elementor-element-%s\s*>.*?url\(([^\)]+)\)' % scrapedthumb item_local.thumbnail = scrapertools.find_single_match( data, patron_thumb) #iniciamos thumbnail item_local.contentThumbnail = item_local.thumbnail #iniciamos thumbnail item_local.infoLabels[ 'fanart'] = item_local.thumbnail #iniciamos Fanart item_local.url = urlparse.urljoin(host, scrapedurl) #iniciamos la url item_local.url_tvshow = item_local.url # Guardamos los formatos para películas item_local.contentType = event item_local.action = "episodios" year = scrapertools.find_single_match(title, '\d{4}') if not year: import datetime year = datetime.datetime.now().year if year: item_local.infoLabels['year'] = int(year) item_local.infoLabels['aired'] = str(year) title = re.sub( r'(?i)TV|Online|(4k-hdr)|(fullbluray)|4k| - 4k|(3d)|miniserie|\d{4}', '', title).strip() item_local.title = title.strip().lower().title() item_local.contentTitle = item_local.title item_local.from_title += item_local.title #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 ) - cnt_offset # 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 return itemlist