Recently I’ve been throwing together some Perl code to help manage and run query’s on my rtorrent installation.

I’ll try to document the steps here in a series of blog posts. This post is for my own use, and may be lacking in clarity in some places.

NOTE: These scripts and code snippets are not a “complete project”. They are probably not what your looking for. If you do happen to find pieces here and there useful. That’s awesome! Have fun!

To get my Perl scripts talking to rTorrent/ruTorrent XML-RPC communication is needed. To accomplished this the Perl module XML::RPC is used. It provides simple “Pure Perl” methods for XML::RPC communication.

Assuming Perl and cpan are setup.

sudo cpan install XML::RPC Data::Dumper

This will install the XML::RPC and Data::Dumper perl modules into your environment. The Data::Dumper module is used for testing.


A bit of information is needed to connect to your rtorrent installation.

  • The User you login to ruTorrent with. : user
  • The Password you login to ruTorrent with: password
  • The Host url your installation is running on: rtorrent.example.com
  • The Port, if your site is running https and it probably is. This port will be 443 as https communicates over that port.
  • The Endpoint: RPC2 in my case. This may change depending on how rtorrent and ruTorrent are setup. – To setup your endpoint you can look at RPC-Setup-XMLRPC from the makers of rtorrent.

The script is provided with these bits of information at runtime, to avoid storing anything hardcoded into the scripts. The command to run the script looks like this.

perl rtgen-db.pl user password rtorrent.example.com 443 RPC2

Assuming the script is called rtgen-db.pl

Inside the script these command line switches are “caught” with the variable $ARGV[]. Keep in mind it’s zero indexed. ex. $ARGV[0] will be user.

The script will look like this.

my $user = $ARGV[0]; # User.
my $pass = $ARGV[1]; # Password.
my $host = $ARGV[2]; # Host
my $port = $ARGV[3]; # Port
my $endp = $ARGV[4]; # Endpoint.

From here each variable can be used in a script. (Technically each $ARGV[] variable can be used as well. I’ve written it out here for clarity.) I have included an alternative to clean up and minimize code clutter.

The string that is used to generate a useable “URL” is:

"https://$user\:$pass\@$host\:$port\/$endp"
  • Alternative url, after tweaking and calling $ARGV[] directly is:.
"https://$ARGV[0]\:$ARGV[1]\@$ARGV[2]\:$ARGV[3]\/$ARGV[4]"

To call the XML::RPC library make sure it’s listed at the top of the script. use XML::RPC; and call it with.

my $xmlrpc = XML::RPC->new("https://$user\:$pass\@$host\:$port\/$endp");
  • Alternative complete call is:
my $xmlrpc = XML::RPC->new("https://$ARGV[0]\:$ARGV[1]\@$ARGV[2]\:$ARGV[3]\/$ARGV[4]");

Now that we can communicate with rtorrent. We need to know what say, and what to ask it. Here we build on the wonderful work done by the github user mdevaev on the project emonoda. - Which they picked up from gi-torrent

They have done a wonderful job documenting and compiling it into a nice format for me to easily read.

Reference:

I find it here: rtorrent-xmlrpc-reference


The call that I am interested in at the moment is. download_list

Passed to the XML::RPC library the call looks like this.

my $dl_list = $xmlrpc->call( 'download_list' );

From here the script will connect to the server and get the hashes of all the torrents.

Now I have chosen to setup a for each loop to loop over all the results returned from the call and get the name of the torrent associated with it.

foreach my $i () {
//get the name of the torrent from the server.//
}

That code looks like this.

foreach my $i (@{ $dl_list}) {
        my $name = $xmlrpc->call( 'd.get_name',$i );
        print "$name\n";
}

The call used is d.get_name from: rtorrent-xmlrpc-reference

This loops over each torrent hash and returns the name of it.


From here. It takes quite awhile to run this program, there is a lot of communication going on. The next step is to find a way to store that information locally. So it can be used in further scripting - filtering. And other such routines, etc.

The data structure that I will be using is an Associative Array.

The final snip of code is:

my %hash_name = ();
foreach my $i (@{ $dl_list}) {
        my $name = $xmlrpc->call( 'd.get_name',$i );
        print "$name\n";
        $hash_name{$i} = "$name";
}

The next big step is finding a way to store that data locally, this is done through the use of a local database.

There is a very nice little article over at the Linux Journal which talks about Creating and Using a Database with Perl.

The snip of code used to open and create a database is as simple as (mud?) here it is:

tie (%hash_name_db, DB_File, "hash_name.db", O_CREAT|O_RDWR, 0644) ||
        die ("Cannot create or open hash_name.db");

Make sure to close the database and write everything at the end.

untie(%hash_name_db);

The interesting point to note here is the %hash_name variable in the foreach loop is writing these results to a memory location. Instead one can write them directly to file, using %hash_name_db instead of %hash_name

The full snip of code is:

tie (%hash_name_db, DB_File, "hash_name.db", O_CREAT|O_RDWR, 0644) ||
        die ("Cannot create or open hash_name.db");

print "Building Database...\n";
foreach my $i (@{ $dl_list}) {
	my $name = $xmlrpc->call( 'd.get_name',$i );
        print "$name\n";
        $hash_name_db{"$i"} = $name;
}
  • There’s a few print statements thrown in just for clarity on what’s going on.

All that’s left is to call the database, sort it and print it out.

That can be done with this snip of code:

foreach (sort keys %hash_name_db) {
    print "$_ : $hash_name_db{ $_ }\n";
  }

Don’t forget to close the file afterwards with:

untie(%hash_name_db);

The full functional script with no frills.:

#!/usr/bin/perl
# https://github.com/rakshasa/rtorrent/wiki/RPC-Setup-XMLRPC
# https://mdevaev.github.io/emonoda/rTorrent-XMLRPC-Reference/
# https://www.linuxjournal.com/article/1381
use XML::RPC;
use Data::Dumper;
use DB_File;
use Fcntl;

# Run Example: perl rtgen-db.pl user pass host port endpoint
my $xmlrpc = XML::RPC->new("https://$ARGV[0]\:$ARGV[1]\@$ARGV[2]\:$ARGV[3]\/$ARGV[4]");
my $dl_list = $xmlrpc->call( 'download_list' );
tie (%hash_name_db, DB_File, "hash_name.db", O_CREAT|O_RDWR, 0644) ||
        die ("Cannot create or open hash_name.db");
foreach my $i (@{ $dl_list}) {
	my $name = $xmlrpc->call( 'd.get_name',$i );
        print "$name\n";
        $hash_name_db{"$i"} = $name;
}
foreach (sort keys %hash_name_db) {
    print "$_ : $hash_name_db{ $_ }\n";
}
untie(%hash_name_db);

Now comes the hardest part. Deciding on a name for this Perl module to include it in cpan.

The name that I settled on is: Rtmgr::Gen::Db as to if that’s a “good name” I’m not sure. The reasons why I chose it were.

  • Its namespace that’s not already used.
  • rt stands for rT(orrent), and mgr stands for Manager. As this is a type of manager for rTorrent.
  • The Gen part of the namespace looks generating Database files.

All these pieces might change up as I work on the functionality of the module. This is a starting point.


With my namespace in hand I need to generate a skeleton for my Perl module.

module-starter --module=Rtmgr::Gen::Db \
    --author="Clem Morton" --email=[email protected].org

Should build up a skeleton module nicely!

Also its a good idea to put the source code under version control I will start tracking the module in git with these commands:

git init
git add .
git commit -a
git remote add origin [email protected].com:clem16/pm-rtmgr.git
git push -u origin master

In the lib/Rtmgr/Gen/ folder of the project. There will be a Db.pm file created. This is where I will be placing my code.

  • The latest source code of this module can be viewed on GitHub

It should be fairly self documenting.


This amazing article has information on building and publishing a module on cpan. You can find it here.

When its time to publish to cpan.

  • The source docs for git commands and tags is here
  • The source docs for uploading to cpan is found here
  • You will need CPAN::Uploader so run sudo cpan install CPAN::Uploader
git add .
git commit -a
git tag -a v0.01 -m "First Release 0.01"
git push
git push origin --tags

perl Makefile.PL
make manifest
make
make install
make dist
cpan-upload -u clem Rtmgr-Gen-Db-0.01.tar.gz
make clean

As of March 20, 2020 : There is a version of this up on CPAN. cpan install Rtmgr

  • The repository is tracked and maintained here: Rtmgr it has all the latest changes.
  • Release tags on GitHub correspond to releases pushed up to CPAN.
  • As I use and develop the module, I will continue to update the GitHub and CPAN Versions.
  • The module might undergo a complete rewrite again. I continue to find and fix things - and add new feature.