Cómo descargar tus series favoritas en forma automática

En otro post, hablamos sobre Torrent Episode Downloader (TED), un excelente programa escrito en Java que nos permite agregar nuestras series favoritas y descargarlas en forma automática a medida que los nuevos capítulos van saliendo.

El método que se describe en este post es una alternativa a TED, que probablemente muchos de Uds. encuentren de interés.

Nota: antes de comenzar, me parece prudente decir que existen otros métodos para conseguir los mismos resultados. Una forma de hacerlo es usando TED, pero también hay algunos clientes de torrent que vienen con soporte para RSS (lo cual hace todo mucho más fácil). Además, existen otros scripts (similares al que se muestra a continuación) que hacen lo mismo (e incluso mejor)… estoy pensando, por ejemplo, en FlexRSS.

El método consiste en crear una tarea programada que ejecute cada cierto tiempo un script python. Este script descarga los torrents a través de RSS. Muchos sitios de descarga de torrents permiten esta opción, siendo el más popular ezRSS. La ventaja de usar RSS para descargar torrents es que te permite “suscribirte” e ir descargando los torrents de tus series favoritas a medida que van apareciendo los nuevos capítulos. Igual que cuando te suscribís a un blog o a un feed de noticias.

Los pasos a seguir

1.- Instalá el paquete python-beautifulsoup.

sudo apt-get install python-beautifulsoup

2.- Abrí tu editor de textos favorito. Copiá el siguiente código dentro de él y guardá el archivo con el siguiente nombre: ~/bin/tormon.py

#!/usr/bin/env python

import urllib2,urlparse
from urllib2 import HTTPError,URLError
from BeautifulSoup import BeautifulSoup
import os
import optparse

__usage__='''
tormon.py -O ~/test/tormon -u "http://rss.feed"
'''

class Main(object):
    '''
    tormon checks an rss feed for new torrents. When it finds a new .torrent, to
    downloads it to a specified output directory, where (presumably) a monitoring
    torrent program will download the corresponding file.    
    '''
    def parse_options(self):
        usage = 'usage: %prog [options]'+__usage__
        parser = optparse.OptionParser(usage=usage)
        parser.add_option(
            '-O', '--output_dir', dest='output_dir',
            help='directory into which new torrents are saved',
            metavar='DIR')
        parser.add_option(
            '-f', '--filetype', dest='filetype',
            action='append',
            default=[],
            help='admissible file types',
            metavar='TYPE')
        parser.add_option(
            '-d', '--downloaded_torrents', dest='downloaded_torrents',
            default=os.path.expanduser('~/.downloaded_torrents'),
            help='log of already downloaded torrents',
            metavar='FILE')
        parser.add_option(
            '-e', '--error_log', dest='error_log',
            help='log of torrents tormon failed to download',
            metavar='FILE')
        parser.add_option(
            '-b', '--batch', dest='batch',
            help='file containing list of rss feed urls',
            metavar='FILE')
        parser.add_option(
            '-u', '--url', dest='url',
            action='append',
            default=[],
            help='url of the rss feed',
            metavar='URL')
        parser.add_option(
            '-m','--mark_all_downloaded', dest='mark_all_downloaded',
            action='store_true',
            default=False,
            help="mark all torrents as already downloaded")
        parser.add_option(
            '-M','--match_by_filename', dest='match_by_filename',
            action='store_true',
            default=False,
            help="recognize downloaded files by filename, not URL. Matching by URL is the default.")        
        (self.opt, args) = parser.parse_args()
        if self.opt.batch:
            for line in open(self.opt.batch,'r'):
                line=line.strip()
                if line and not line.startswith('#'):
                    self.opt.url.append(line)
        if not self.opt.output_dir:
            self.opt.output_dir=os.path.expanduser('~/Desktop')
        if not self.opt.filetype:
            self.opt.filetype=['.torrent']        if not self.opt.error_log:
            self.opt.error_log=self.opt.downloaded_torrents+'.errors'
        try:
            os.makedirs(self.opt.output_dir)
        except OSError:
            if not os.path.exists(self.opt.output_dir):
                print('tormon failed to create directory %s'%self.opt.output_dir)
                exit(1)
    def load_list_of_already_downloaded_torrents(self):
        try:
            self.downloaded=open(self.opt.downloaded_torrents,'r').read().split()
        except IOError:
            self.downloaded=[]        try:
            self.errors=open(self.opt.error_log,'r').read().split()
        except IOError:
            self.errors=[]    def update_downloaded(self,url):
        self.downloaded.append(url)
        try:
            self.errors.remove(url)
        except ValueError:
            pass        
    def download_torrent(self,url):
        try:
            sock=urllib2.urlopen(url)
        except (HTTPError, URLError):
            # print('tormon failed to download %s'%url)
            if url not in self.errors:
                self.errors.append(url)
        else:
            filename=self.url2filename(url)
            target_file=os.path.join(self.opt.output_dir,filename)
            print('Downloading %s'%target_file)
            content=sock.read()
            sock.close()
            fh=open(target_file,'w')
            fh.write(content)
            fh.close()
            self.update_downloaded(url)
    def url2filename(self,url):
        return os.path.basename(urlparse.urlparse(url)[2])
    def has_been_downloaded(self,url):
        if self.opt.match_by_filename:
            filename=self.url2filename(url)
            return (filename in [self.url2filename(link) for link in self.downloaded])
        else:
            return (url in self.downloaded)
    def parse_rss_feed(self):
        for url in self.opt.url:
            print('RSS feed: %s'%url)
            try:
                sock=urllib2.urlopen(url)
            except (HTTPError, URLError):
                print('tormon failed to download %s'%url)
            else:
                content=sock.read()
                sock.close()
                soup=BeautifulSoup(content)
                links=([link.nextSibling for link in soup.findAll('link')]+
                       [link['href'] for link in soup.findAll('a')]+
                       [link['url'] for link in soup.findAll('media:content')])
                for link in links:
                    if (any([link.lower().endswith(ending)
                             for ending in self.opt.filetype])
                        and not self.has_been_downloaded(link)):
                        if self.opt.mark_all_downloaded:
                            print('Marking %s as downloaded'%link)
                            self.update_downloaded(link)
                        else:
                            self.download_torrent(link)
    def save_list_of_already_downloaded_torrents(self):
        fh=open(self.opt.downloaded_torrents, 'w')
        fh.write('n'.join(self.downloaded))
        fh.close()
        fh=open(self.opt.error_log, 'w')
        fh.write('n'.join(self.errors))
        fh.close()
    def __init__(self):
        self.parse_options()        
        self.load_list_of_already_downloaded_torrents()
        try:
            self.parse_rss_feed()
        except KeyboardInterrupt:
            pass
        finally:
            self.save_list_of_already_downloaded_torrents()
if __name__=='__main__':
    Main()

3.- Otorgale permisos de ejecución.

chmod +x ~/bin/tormon.py

4.- Verificá que todo funciona bien.

tormon.py -O ~/torrents/ -u "http://rss.feed"

Donde dice ~/torrents/, tenés que reemplazarlo por la ruta donde querés guardar los torrents descargados. Tené en cuenta que van a ser muchos archivos .torrent.

Donde dice “http://rss.feed”, tenés que reemplazarlo por el URL del feed RSS de tu serie favorita. ¿Cómo conseguirlo? Bueno, en caso de que quieras usar ezRSS, accedé a la página principal y escribí el nombre de la serie. Aparecerá un listado enorme con los resultados. En caso de que quieras refinar la búsqueda (filtrando fecha, calidad o persona que ripeó el video), podés hacerlo guiándote con los ejemplos que se publican claramente en esa página. Una vez que tenés los resultados que buscás, hacé clic derecho sobre el link que dice Search-based RSS feed que aparece al lado del botón naranja característico de los feeds RSS. Copiá el link y pegalo reemplazando al http://rss.feed del ejemplo.

Algunos datos extra para tener en cuenta:

  • En caso de omitor el parámetro -O, los archivos .torrent se descargarán en el Escritorio.
  • Si ejecutás el mismo comando inmediatamente después, no debería descargar ningún torrent nuevo, a menos que se haya agregado un nuevo torrent al feed RSS.
  • Este comando crea la carpeta donde se guardarán los torrents en caso de que no exista.
  • Un listado de los URLs de los torrents descargados con éxito se guardará en  ~/.downloaded_torrents.
  • Para monitorear más de 1 feed RSS, podés usar el parámetro -u. Ejemplo: tormon.py -u “http://rss.feed1” -u “http://rss.feed2”

5.- Si todo funciona bien, podés agregar el script como una tarea programada de crontab.

crontab -e

Este comando abrirá un editor de textos.

Pegá el siguiente código de modo que quede al comienzo del archivo:

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/home/USER/bin
MAILTO=USER

Cambiá USER por tu nombre de usuario.

Pegá el siguiente código en alguna parte debajo de PATH=…

*/15 * * * * tormon.py -u "http://rss.feed"

Esto ejecutará el script cada 15 minutos. Claro, podés cambiarlo para que se adapte a tus necesidades. Al tratarse de series de televisión, lo prudente podría ser que se ejecute una vez por semana. No olvides leer nuestro post anterior en el que explicamos paso a paso cómo agregar tareas a crontab.

Para ejecutarlo todos los domingos a las 10 AM:

00 10 * * 0 tormon.py -u "http://rss.feed"

Nota: no olvides reemplazar los parámetros pasados a tormon.py con aquellos que se ajusten a tus necesidades. Como mínimo, en el comando anterior, habría que reemplazar la URL del feed RSS.

Ya para terminar, asegurate que haya una línea en blanco al final del archivo crontab. No sé por qué pero es un requisito de crontab para que todo funcione bien.

Guardá el archivo y salí del editor de textos.

Nota: en caso de que tengas instalado un agente de transferencia de e-mails (mail transfer agent), como exim4, la línea MAILTO=USER le indicará a crontab que te envíe los resultados de la ejecución de tormon.py en un e-mail.

Comparte para difundir

Si te ha gustado nuestro contenido ahora puedes ayudar a difundirlo en las redes sociales de manera sencilla usando los siguientes botones:

Envía
Pinea
Print

7 comentarios

  1.   Jakeukalane dijo

    Bueno, afortunadamente sé algo de inglés. Lo hice con YaRSS. A ver si funciona.

  2.   Jakeukalane dijo

    Sí, genial. pero nadie explica como usar FlexRSS. En su página es todo muy bonito pero no he encontrado manera de agregarlo a deluge… además dicen que en Deluge viene uno por defecto y no es verdad.

    Saludos

  3. Qbittorrent y otros llevan incorporados sistemas de programación. Estaría bien explicar como funciona cada uno de ellos, Yo suelo explicar el de microtorrent para MS WOS y el de Qbittorrent para Linux. En espoiler había un tutorial , pero a buen seguro que recogerás muchas visitas si haces videos con cada programa popular de torrents, añadiendo por ejemplo el EZ

  4.   Usemos Linux dijo

    Gracias Miquel! Voy a tenerlo en cuenta, como todos tus comentarios y sugerencias!
    Te envío un fuerte abrazo! Pablo.

  5.   Seaofgrass dijo

    Aqui un repositorio que contiene este programa:
    https://launchpad.net/~lopeztobal/+archive/maths
    via: http://linuxmusica.com/

  6.   Sharik dijo

    Deja ya de predicar el uso de un kernel y propaga el uso de un sistema operativo!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

*

  1. Responsable de los datos: Miguel Ángel Gatón
  2. Finalidad de los datos: Controlar el SPAM, gestión de comentarios.
  3. Legitimación: Tu consentimiento
  4. Comunicación de los datos: No se comunicarán los datos a terceros salvo por obligación legal.
  5. Almacenamiento de los datos: Base de datos alojada en Occentus Networks (UE)
  6. Derechos: En cualquier momento puedes limitar, recuperar y borrar tu información.