Torrent Pouncer is an automatic torrent downloader for periodic releases of tv shows, series and similar. Contrary to popular RSS-based torrent downloaders, it searches various torrent search engines like Mininova and Pirate Bay. For user convenience, it keeps databases of downloaded torrents and associates them with shows and season and episode numbers. Torrent Pouncer is easily extensible with new search engine support and features a very powerful configuration language.
The following requirements must be met in order to successfully install and use Torrent Pouncer:
scrAPI is distributed under MIT license, while Torrent Pouncer is covered by GPL license. There are several ways to install these packages, some of them are:
# scrapi, torrent pouncer deb http://kjdf.sdf-eu.org/debian ./and then just install torrent-pouncer package using aptitude. scrapi-ruby1.8 will be downloaded automatically to satisfy dependencies.
Torrent Pouncer is always invoked with a configuration file as an argument. If it's not found in current directory, Pouncer will try hard to find it in ~/.pouncer directory. So, for example, when invoked like this:
pounce galacticaIt will look for configuration file under following paths: ./galactica, ~/.pouncer/galactica, ~/.pouncer/galactica.conf, ~/.pouncer/galactica.cfg, ~/.pouncer/galactica.rb.
Torrent Pouncer also maintains a separate database for each configuration file. It contains information on torrents found on remote search engine web pages, as well as tracks which episodes we have already seen. The command line utility allows to download new torrents (which is the default action), mark the given episode as not seen ("unwatch", useful when we got a corrupted torrent), and the combination of the two - "rewatch". See the built-in documentation for details how to use it (pounce --help).
An example, imaginary configuration file may look like this:
------------------------- galactica.conf -----------------------------
# search Pirate Bay for 'galactica'
search PirateBay, 'galactica'
# add score 1 (default) to our favourite release group "orenji"
prefer {|t| t.name =~ /orenji/i}
# don't you hate those pesky rar releases? worry no more
prefer(-2) do |t|
wget(t.torrent) {|file| system "grep -q '\.rar' #{file}"}
end
# assign a score of 0-1 based on number of seeds, 1 to the best seeded one
prefer_dynamic do |t, torrents|
max = torrents.map {|x| x.seeds}.max.to_f
t.seeds / max
end
# big fat releases
filter {|t, torrents| t.size > 320 and t.size < 380}
# get season 3 episode 9 and upwards and everything from season 4
# (we have seen the rest before switching to torrent pouncer)
filter {|t| t.season == 3 and t.episode >= 9 or t.season >= 4}
# copy torrent to current directory
action_copy '.'
----------------------- galactica.conf end ---------------------------
A Torrent Pouncer configuration file consists of at least one search and action statement, and usually a few filter and prefer statements. The basic mode of operation for Pouncer is more or less this:
Below is the description of valid configuration file statements:
Select search engine and search phrase to be used for finding new torrents. Can be used more than once in config file, in this case search results will be combined.
search Mininova, "galactica"
Perform an action on the downloaded torrent file once all filters and preferences have been applied. The property t.tempfname will point to a temporary file which contains the downloaded torrent. More than one actions can be used, they are executed sequentially.
Example:
action do |t|
system "cp #{t.tempfname} ~/torrents/#{t.filename}"
puts "downloaded file '#{t.filename}'"
end
A common action that copies a file to a given location. If given a block, its return value will be used, otherwise it will use the path argument. If the string points to a directory, the torrent will be copied there with its t.filename as name. Otherwise the string is interpreted as full path to file.
Examples (following are more or less equivalent):
action_copy "~/torrents"
action_copy {"~/torrents"}
action_copy {|t| "~/torrents/" + t.filename}
Reject all torrents for which the block doesn't evaluate to true. If the block can accept 2 arguments, it will also be given a list of all "competing" torrents. All filters are applied sequentially with non-matching torrents being rejected each time.
Examples:
filter {|t| t.size > 300} # accept only big files
filter {|t| t.name =~ /LOL/} # we are faithful to this one group
filter do |t, torrents| # we want only the biggest file
max_size = torrents.map {|x| x.size}.max
t.size == max_size
end
Preferences are means of stating which torrents we like more. For each torrent, if the block evaluates to true, the torrent will be awarded some points (1 if not explicitely stated). Torrents with higher score will be preferred when choosing the torrent to be downloaded and passed to actions. Similarly to filter, the block can accept 2 arguments, in which case the second argument will be list of all torrents being considered.
Examples:
prefer {|t| t.seeds > 100} # we like lots of seeds
prefer(-1) {|t| t.seeds < 3} # punish poorly seeded torrents
prefer(0.5) do |t, torrents| # slightly prefer the biggest file
max_size = torrents.map {|x| x.size}.max
t.size == max_size
end
Similar to regular prefer, but this time the block is expected to return the number of points to be rewarded (or false).
Examples:
prefer_dynamic {|t| t.seeds} # add as many points as torrent has seeds
prefer_dynamic do |t, torrents| # add 0-1 points, depending on relative number of seeds
max_seeds = torrents.map {|x| x.seeds}.max.to_f
t.seeds / max_seeds
end
Path to a database file. If not provided, the default location (~/.pouncer) will be used with the filename derived from configuration file name. Might be useful if you don't want to store your config files in ~/.pouncer as well.
Example:
database "~/.galactica.pouncer.database"
Define a custom rule for extracting the season and episode numbers from torrent file names, useful when the default extractor doesn't work. It should return a list of 2 numbers.
Example:
extract_season_episode do |t| # this is actually the default extractor
case t.name
when /(\d+)x(\d+)/i then [$1.to_i, $2.to_i]
when /s(\d+)e(\d+)/i then [$1.to_i, $2.to_i]
end
end
Pouncer also provides some useful functions that can be used in configuration scripts:
Download url to a temporary file and pass its path to the block. Returns result of the block.
Example:
prefer(-2) do |t| # punish torrents containing a .rar file
wget(t.torrent) {|file| system "grep -q '\.rar' #{file}"}
end
Torrent Pouncer is rather easily extended to support new search engines. The code itself can either be forced into the main program file or stored in ~/.pouncer (it is automatically added to Ruby's search path) and required from within each config file. Same goes for custom actions (like built-in action_copy).
In order to write to new search backend we will need to understand how Pouncer interacts with Searchers. Pouncer expects a Searcher class (derived from SearcherBase to respond to 2 methods:
When developing new backends it is helpful to learn how built-in ones work first. Also, the scrAPI cheat sheet might prove to be useful. If you write a new search backend you will be very welcome to send it to the maintainer of Torrent Pouncer.
The following people have contributed to Torrent Pouncer:
You can contact the author using this email address: Michal Janeczek <janeczek@gmail.com>.