El presente documento es, simplemente, un pequeño manual de programación de descargas con rtorrent. Un manual más amplio de uso y configuración general puede hallarse en [1]. De hecho, si es la primera vez que se acerca a rtorrent, es recomendable (obligado, más bien) que lea [1] o un documento similar: estas líneas no le van a enseñar a escribir un rtorrent.rc entero, sino sólo aquella parte relacionada con la programación y automatización de descargas. Picoteo para ello en ideas de algunos tutoriales, respuestas en listas de dsitribución o foros, etc., y amplio y aporto con los conocimientos que he adquirido configurando mi propio rtorrent.rc.
Al grano, ¿qué voy a conseguir programando las descargas en rtorrent? (hablando en plata, ¿qué voy a conseguir leyéndome tu ladrillo?). Básicamente hacer más automático su uso y en particular:
(Sí, estoy plagiando miserablemente el comienzo de [3])
Para los puntos (1), (2) y (3), el propio rtorrent facilita la solución; en cambio, los puntos (3) y (4) necesitan que recurramos a un script externo.
~/rtorrent/ session historial watch queue temp downloads rtorrent.rc
Explíquemos para qué sirve cada directorio.session contiene los torrents que se están descargando y un fichero de bloqueo (torrent.lock), que sirve para saber si rtorrent está corriendo. No debemos preocuparnos de él: lo gestiona el propio programa. historial es un directorio que almacena los torrent que nos bajamos en el pasado. watch es el directorio que se inspecciona en búsqueda de nuevos .rtorrent; si aparece alguno nuevo, se empezará a descargar. queue representa la cola de descargas, dentro de él estarán todos aquellos .torrent que esperan ser descargados (es decir, ser movidos a watch para que rtorrent los descubra. temp es el directorio temporal de descargas, donde se almacenan los ficheros cuya descarga aún no se ha completado. Por último, downloads contiene los ficheros ya descargados.
Esta estructura de ficheros, no se crea automáticamente, así que debe hacerse a mano. He incluido en el directorio el fichero rtorrent.rc, que será el fichero de configuración. Como forzosamente este fichero debe ser ~/.rtorrent.rc, puede solucionarse la cosa con un simple enlace simbólico:
$ ln -s ~/rtorrent/rtorrent.rc ~/.rtorrent.rc
¡Ojo! El fichero que hay a continuación y todos los de este manual no son .rtorrent.rc completos, contienen solamente las líneas que permiten programar las descargas. El resto de parámetros (upload_rate, etc.) consúltelos en otro documento.
#execute_log = ~/rtorrent/execute.log directory = ~/rtorrent/temp session = ~/rtorrent/session schedule = watch_directory,5,10,"load_start=~/rtorrent/watch/*.torrent,d.set_custom1=~/rtorrent/downloads" schedule = untied_directory,5,5,close_untied= #schedule = tied_directory,5,10,start_tied= schedule = ratio,10,60,"close_on_ratio=800,200M,1000,d.erase=" schedule = low_diskspace,5,60,close_low_diskspace=100M on_erase = move_complete,"execute={mv,-u,$d.get_base_path=,$d.get_custom1=}" on_erase = move_tie,"execute={mv,$d.get_tied_to_file=,~/rtorrent/historial}"
La primera línea está comentada, pero puede descomentarse para depurar errores, si vemos que rtorrent no hace lo que queremos. Simplemente, habilita un fichero donde se escribirá la salida de los comandos execute.
La segunda y tercera líneas admiten breve explicación: definen cuál es el directorio de descargas y cuál el de sesión.
Las cinco siguientes (las schedule) son tareas que se ejecutan periódicamente y tienen la siguiente sintaxis:
schedule = id,start,interval,commands
id es simplemente un identificador, un nombre arbitrario que se le da a la regla. Obviamente si repetimos el nombre machacaremos la primera regla con la segunda. start es el tiempo que tarda en ejecutarse la regla tras el arranque de rtorrent. interval define cada cuánto tiempo se ejecutará la regla y commands es la lista de comandos que se ejecutarán.
Ahora analicemos las que hay definidas en nuestro rtorrent.rc:
schedule = watch_directory,5,10,"load_start=/rtorrent/watch/*.torrent,d.set_custom1= /rtorrent/downloads"
Tenemos una primera regla llamada watch_directory que se ejecuta cinco segundos después de haber arrancado rtorrent y que se repite cada diez segundos. Lo que hace es load_start (es decir, cargar y arrancar, se puede sólo cargar con load) todos los torrent que encuentre en ~/rtorrent/watch/. Además para ese(os) torrent(s) concretos define una variable de usuario llamada custom1 con valor ~/rtorrent/downloads. Obviamente es aquí donde van a ir a parar los ficheros ya descargados y ya se verá cómo se logra un poco más adelante. Es necesario notar que la variable de usuario no puede tener un nombre arbitrario: sólo son admisibles custom{1,2,3,4,5}. Y cinco son más que suficientes.
Una precisión sobre la sintaxis de las instrucciones. Si empiezan por d. se refieren a un torrent en particular. Además todas deben acabar con un signo =.
schedule = untied_directory,5,5,close_untied=
La segunda regla (untied_directory) simplemente cierra los torrents de los que haya desaparecido su amarre (su .rtorrent correspondiente). Tied en inglés significa amarrado y untied, lo contrario, desamarrado. En la jerga del programa una descarga está tied to file (amarrada a un fichero) cuando tiene asociado un amarre (un .torrent) en el directorio watch. Así que, close_untied, simplemente, significa cerrar los torrent desamarrados, es decir, cerrar los torrents que están amarrados a un .rtorrent que ha desaparecido (de watch, obviamente).
schedule = tied_directory,5,10,start_tied=
Es una regla contraria a la anterior. Significa: empieza a descargar un torrent del que hayas encontrado su amarre en watch. Es decir, si volvemos a dejar el .rtorrent en "watch" que previamente borramos de allí, la descarga correspondiente, que estará cerrada por nuestra regla untied_directory volverá a activarse. En el ejemplo, está comentada porque esta regla impide que paremos una descarga manualmente desde el cliente con Ctrl+D, ya que a los diez segundos, cuando vuelva a ejecutarse, encontrará el amarre en watch y... start_tied.
Relacionadas con estas reglas hay otros comandos interesantes. Para la regla untied_directory podría haber usado stop_untied, que para el torrent en vez de cerrarlo (cerrar, además de parar la descarga, cierra los ficheros y descarta los chunk que se han quedado a medias), o bien, remove_untied que directamente elimina el torrent del cliente. ¡Ojo! Los ficheros de descarga seguirán existiendo en el disco duro.
schedule = ratio,10,60,"close_on_ratio=800,200M,1000,d.erase="
La cuarta de las reglas se define para controlar qué se hace cuando un torrent llega a un determinado ratio de upload/download. Se ha definido que se cierre si se alcanza ratio 8.0 (800%), pero si es menor de 200 MB, entonces el ratio deberá ser de 10.0 (1000%). Detrás del último parámetro pueden serguir añadiéndose (con comas) más comandos. En este caso d.erase que lo que hace es borrar el torrent del cliente (lo cual lanzará los disparadores que se describen más adelante).
schedule = low_diskspace,5,60,close_low_diskspace=100M
Esta última cierra las descargas cuando no queden más de 100Mb en el disco duro.
El fichero se cierra con dos triggers (dos disparadores) que se lanzan al borrarse el torrent. Hay otras posibilidades: al finalizar la descarga (on_finished), al empezarla (on_start), al cerrar el torrent (on_close), etc... En la página del manual de rtorrent vienen todas las posibilidades.
on_erase = move_complete,"execute={mv,-u,$d.get_base_path=,$d.get_custom1=}" on_erase = move_.torrent,"execute={mv,$d.get_tied_to_file=,/rtorrent/historial}"
Ambos disparadores se definen para cuando el torrent es eliminado del cliente (on_erase). El primero mueve los ficheros descargados desde el directorio temporal (el marcado por la instrucción directory de la segunda línea) al directorio de descargas definitivas definido en d.get_custom1. El parámetro -u de mv es propio del mv de GNU, para la versiones BSD hay que usar -n.
He preferido que el mover los ficheros descargados se haga al eliminar el torrent del cliente. También habría sido posible hacerlo al completar la descarga, pero en ese caso hay que añadir una instrucción más al comando:
on_finished = move_complete,"execute={mv,-u,$d.get_base_path=,$d.get_custom1=};d.set_directory=$d.get_custom1"
es decir, cuando muevas el fichero, cambia también la variable directory para que yo sepa dónde está el fichero y pueda seguir compartiéndolo.
La versión anterior tiene un pequeño problema a la hora de aplicarla en otro ordenador: que todo el fichero está plagado de ~/rtorrent/ que quizás habría que sustituir, si quisiésemos adoptarlo. Lo suyo sería tener una variable global que tuviese este valor y que el resto de variables la usasen. El problema es que no hay ningún custom1 global. Pero podemos hacer lo siguiente: usar directory y definir para cada descarga un d.get_directory como la concatenación de directory y temp.
¡Hecho!, es exactamente la misma configuración que para el caso anterior, pero ahora basta con cambiar una única línea para personalizar dónde queremos tener nuestra estructura de ficheros para rtorrent.
Se ha añadido un disparador más que hace la concatenación que necesitábamos para toda descarga que se añada al cliente. El resto de los cambios se basa en hacer las concatenaciones pertinentes. El por qué tiene esa sintaxis tan enrevesada habrá que preguntárselo al parser de rtorrent: me llevó toda una tarde con pruebas de ensayo-error el dar con la tecla.
Quizás en este punto se pregunte el lector por qué se a añadido el disparador en vez de, simplemente, añadir las dos órdenes después de load_start. la razón está las descargas que puedan añadirse a mano a través del cliente. Incluyendo el disparador, estas descargas también definen d.get_directory y d.get_custom1.
Además, misteriosamente, he añadido una línea:
try_import = "$cat=$get_directory=\,branch.rc"
La línea de marras no tiene nada que ver con lo anterior. De hecho, tiene que ver con lo que viene. try_import es, simplemente, un comando que intenta importar un fichero de configuración. En la práctica sería como incluir el contenido del fichero que es invocado en la posición que ocupa este comando en el fichero invocador. Se preguntará ¿y por qué hace tal? La respuesta es sencilla: hasta aquí la programación es bastante simple y, con ligeras variantes (exceptuando esta última argucia de usar cat), puede hallarse en muchos artículos de la red. Lo que viene a continuación es más avanzado y, casi todo, de cosecha propia. Además requiere las últimas versiones de rtorrent (al momento de escribir estas líneas la 0.8.2), porque las más antiguas (la 0.7.9, que es la últiam estable, por ejemplo) no soportan algunos de los comandos. Por todo esto, lo he preferido separar en un fichero autónomo (~/rtorrent/branch.rc).
El nombre escogido tiene su explicación: branch es uno de esos famosos comandos que no existen en las versiones más antiguas. Pero al grano. Vamos a afinar más el programador para lograr mejores automatizaciones:
He colocado en el fichero las tareas en el orden en que las declaré antes.
Para mandar el correo he usado mutt y he procurado escribir el comando de envío directamente para ahorrarme una llamada a bash. El por qué uso mutt y no mail se debe a que mail obliga a pasar el cuerpo del mensaje a través de la entrada estándar y no tengo ni idea de cómo puedo hacer redirecciones o tuberías con execute. Obviamente, también puede invocarse un script:
on_finished = notification, execute={"$cat=$get_directory\,notify.sh"}
y dentro de él mandar el mensaje de la forma que se prefiera. La línea está comentada porque... no he podido probarla: no dispongo de servidor de correo en el portátil desde el que pruebo lo que escribo. Posiblemente haya que afinarla de algún modo.
La segunda y la tercera líneas se encargan de nuestro segundo propósito. La primera de ellas es trivial: ahora al desaparecer el amarre de watch, eliminamos la descarga del cliente. Esto, en principio, lanzaría la regla move_complete definida en rtorrent.rc que movía los ficheros descargados del directorio temporal al de descargas definitivas. Pero eso no es el comportamiento que queremos para este caso particular, así que esa es la razón de que exista la línea tercera. En ella se rescribe la regla de modo que primero se pregunte ¿existe el fichero de amarre? Si existe, muevo los ficheros a downloads, si no existe (precisamente este caso), los borro. Y en la pregunta es donde entra el comando branch. branch permite crear estructuras condicionales, como también permite el comando if. Pero if, por mi experiencia no acaba de funcionar bien. La sintaxis es:
branch=condicion,accion1,accion2
Si la condición se cumple se ejecuta accion1 y, si no, accion2. accion2 es opcional y, de hecho, no existe en la línea que analizamos. Para que se entienda mejor el uso, pondré un par de ejemplos más sencillitos:
branch=d.get_custom1=,print=1,print=0
Pruebe a ejecutar esto en la línea de comandos que se abre al pulsar Ctrl+X. Si eligió un torrent que tiene definida la variable custom1, verá que se escribe 1; si eligió uno que no la tiene definida, verá que se escribe 0.
branch=d.is_open=,print=1,print=0
Ahora que escriba 1 ó 0 dependerá de que el torrent esté abierto o cerrado.
Volvamos después de esto a nuestra más enrevesada línea:
on_erase = move_complete,"branch=\"execute_nothrow={test,-f,$d.get_tied_to_file=}\",\"execute={rm,-rf,--,$d.get_base_path=}\",\"execute={mv,-n,$d.get_base_path=,$d.get_custom1=}\""
La condición de branch en este caso, no es la consulta de una simple variable, si no un script que devolverá 0 o 1. El script es simplemente el comando test que comprueba si existe el fichero de amarre. Si no existe, devuelve 1 y borramos los ficheros (condición 1); si existe, devuelve 0 y los movemos (condición 2).
La siguiente regla rescribe la que se definió en rtorrent.rc para el caso en que nos quedáramos sin espacio en el disco duro:
schedule = low_diskspace,5,300,"branch=\"execute_nothrow={\\\"$cat=$get_directory=\\,checkspace.py\\\",100}\",\"d.multicall=active,\\\"f.multicall=,f.set_priority=0\\\",d.update_priorities=\""
La regla invoca un script en python (podría haberse escrito también en bash, por ejemplo) que admite como parámetro los megabytes libres mínimos por debajo de los cuales rtorrent deja de descargar los ficheros de los torrent activos, pero sigue compartiéndolos. Esto se logra poniendo la prioridad de descarga a 0 para todos esos ficheros (a mano equivale a marcarlos como off en "downloads">"file list").
El script propuesto es el siguiente:
La última línea nos permitirá tener una cola de .torrent en espera. En rtorrent no hay (por ahora, según prometen) implementadas las colas de descarga, así que tenemos que recurrir a un script externo: