I made the Perl script to get data from .torrent files, pool the trackers and get some statistics (file hash, IP connected to the tracker, file size, etc.). No big science, just some Perl-fu. To run it, you need: Perl module Bencode, curl and transmission-show installed. Debug garbage is sent to stderr and the proper output to stdout.
#!/usr/bin/perl
use Bencode qw( bencode bdecode );
use Data::Dumper;
use warnings;
use strict;
my $G_PEER_ID = "hfgdbvnchdgfhvnfbghf";
my $G_MAX_TIME = 20;
sub peer_decode
{
my $d = shift;
my @a = split '', $d;
# printf ">>%d %d<<\n", length($d), scalar(@a);
my @ret;
while(@a) {
my $ip = sprintf "%d.%d.%d.%d" ,
unpack('C',shift(@a)),
unpack('C',shift(@a)),
unpack('C',shift(@a)),
unpack('C',shift(@a));
my $port = sprintf "%d", 256 * unpack('C',shift(@a))
+ unpack('C',shift(@a));
# printf "%d $ip $port\n",scalar(@a);
push @ret, $ip;
}
return \@ret;
}
sub get_tracker_data_from_file
{
my $fname = shift;
my $ret = {};
my $c = `transmission-show $fname`;
print STDERR "$c\n";
if ( $c =~ /^\s+Hash:\s*(\S+)/mg ) {
$ret->{'hash'} = $1;
}
if ( $c =~ /^\s+Total Size:\s*(.+)$/mg ) {
$ret->{'size'} = $1;
}
my @g;
@g = ($c =~ /Tier \#\d+[\n\r\s]+(\S+)/gm);
if ( @g ) {
$ret->{'tiers'} = \@g;
}
return $ret;
}
sub get_peer_ips
{
my $hash = shift;
my $tracker = shift;
my $ret = undef;
$hash =~ s/(..)/\%$1/g;
$tracker =~ s/\/$//;
my $c = "curl -m $G_MAX_TIME -s '$tracker?info_hash=$hash&peer_id=$G_PEER_ID&uploaded=0&downloaded=0&left=1'";
print STDERR "$c\n";
my $w = `$c`;
return undef if not $w;
printf STDERR "%s\n" , Dumper($w);
return undef if $w =~ /<\s*html\s*>/gi;
$w = bdecode($w, 1);
if ( defined $w->{'peers'} ) {
$ret = peer_decode($w->{'peers'});
}
return $ret;
}
# -- main
my @files = @ARGV;
if ( not @files ) {
print <<END
usage: $0 <file1.torrent> <file2.torrent> ...
(c) http://stackoverflow.com/users/497208
END
}
for my $fname ( @files ) {
printf STDERR "File: %s\n", $fname;
my $tr = get_tracker_data_from_file($fname);
printf STDERR "%s\n", Dumper $tr;
my $hash = undef;
$hash = $tr->{'hash'} if defined $tr->{'hash'};
exit if not defined $hash;
my $size = undef;
if ( defined $tr->{'size'} ) {
$size = $tr->{'size'};
}
else {
$size = "?";
}
if ( defined $tr->{'tiers'} ) {
# shift @{$tr->{'tiers'}} for (1..5);
for my $tracker ( @{$tr->{'tiers'}} ) {
my $ips = get_peer_ips( $hash, $tracker);
printf STDERR "%s\n", Dumper $ips;
if ( defined $ips ) {
for my $ip ( @$ips ) {
my $c = sprintf "%s; %16s; %s; %s", $hash, $ip, $size, $tracker;
printf STDERR "$c\n";
printf "$c\n";
}
}
}
}
}