A PHP script to start a torrent and download it where the .torrent was located using Transmission JSON-RPC

I wrote this script because I never found a Transmission remote GUI that permits to start downloading a torrent in a specific directory.

So, here’s the script, I hope you’ll like it!

#!/usr/local/bin/php -q
<?php
/*
VERSION: 0.9
AUTHOR: gimpe
EMAIL: gimpe [at] hype-o-thetic.com
WEBSITE: https://blog.gimpe.com

USAGE: You simply need to update the "configuration constants" with your own
       information and run the script manually or schedule it to be run as a
       cronjob (a.g. every 30 minutes).

DESCRIPTION: This script will recursively search into directory to find .torrent
             files. It will automatically start the download inside the
             directory where the .torrrent was located. And finally, it will
             delete the .torrent file (if there was no error returned by
             Transmission). This script has been tested under FreeNAS 0.7RC2
             Khasadar (revision 4899) but it should work on anything :) FreeNAS
             or not as it is using the Transmission JSON-RPC interface with
             sockets (curl is NOT needed as FreeNAS embedded doesn't include it
             with PHP).

CHANGELOG
 0.9: 2009-11-07 Beta version
 0.2: 2009-09-13 Code clean up
 0.1: 2009-09-11 Make it work

REFERENCES:
 Transmission JSON-RPC doc: http://trac.transmissionbt.com/browser/trunk/doc/rpc-spec.txt
*/

// configuration constants
define('SEEDRATIOLIMIT', 1.5);      // seed the torrent until this ratio is reached
define('USERNAME', 'username');     // FreeNAS BitTorrent Administrative WebGUI username
define('PASSWORD', 'password');     // FreeNAS BitTorrent Administrative WebGUI password
define('DIR', '/mnt/media/video');  // directory to scan recursively for .torrent (no trailling slash)

// send an empty request to retrieve the current X-Transmission-Session-Id
$response = transmissionJsonrpcClient(array());

// check if we have the X-Transmission-Session-Id
if (!strlen($response['xTransmissionSessionId']))
{
    print 'Unable to get X-Transmission-Session-Id' . PHP_EOL;
    exit;
}

// start dir scan to start torrents downloads
searchTorrentInDir(DIR, $response['xTransmissionSessionId']);

////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////FUNCTIONS/////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// send a request JSON-RPC request to transmission
function transmissionJsonrpcClient($request, $xTransmissionSessionId = '')
{
    // encode the request in json
    $content = json_encode($request);

    $fsockErrNo      = 0;
    $fsockErrStr     = '';
    $fsockTimeout    = 10;
    $response   = '';

    if ($fp = @fsockopen('localhost', 9091, $fsockErrNo, $fsockErrStr, $fsockTimeout))
    {
        $rawRequest = 'POST /transmission/rpc HTTP/1.0' . PHP_EOL
                      . 'Content-type: text/json;charset=utf-8' . PHP_EOL
                      . 'X-Transmission-Session-Id: ' . $xTransmissionSessionId . PHP_EOL
                      . 'Authorization: Basic ' . base64_encode(USERNAME . ':' . PASSWORD) . PHP_EOL
                      . 'Content-Length: ' . strlen($content) . PHP_EOL . PHP_EOL
                      . $content;
        fwrite($fp, $rawRequest);
        $response = stream_get_contents($fp);
        fclose($fp);

        // if "409 conflict" + empty request, this is a dummy request to retrieve the X-Transmission-Session-Id
        if (strstr($response, '409: Conflict') && !count($request))
        {
            // find the X-Transmission-Session-Id in the response
            if (preg_match('/X-Transmission-Session-Id: (w+)/', $response, $matches))
            {
                $xTransmissionSessionId = $matches[1];
            }
            else
            {
                print 'ERROR no X-Transmission-Session-Id' . PHP_EOL;
                exit;
            }
        }
    }
    else
    {
        print 'ERROR cant't connect to transmission JSON-RPC Server: ' . $fsockErrStr . PHP_EOL;
        exit;
    }

    $return = '';
    if (count($request))
    {
        if (preg_match("/({.*)/msi", $response, $matches))
        {
            $return = json_decode($matches[0], true);
        }
        else
        {
            print 'ERROR unable to retrieve the transmission JSON response in the raw socket response: ' . print_r($response, true) . PHP_EOL;
        }
    }

    return array('response' => $return, 'xTransmissionSessionId' => $xTransmissionSessionId);
}

// recursively scan a directory to find .torrent files and start the torrent download
function searchTorrentInDir($dir, $xTransmissionSessionId)
{
    $dirContent = scandir($dir);

    foreach($dirContent as $key => $file)
    {
        $path = $dir . '/' . $file;

        if (basename($path) == '.' || basename($path) == '..')
        {
            continue;
        }

        // if content is a readable file
        if (is_file($path) && is_readable($path))
        {
            $pathinfo = pathinfo($path);

            // if it is *.torrent
            if (in_array($pathinfo['extension'], array('torrent')))
            {
                $filename  = $pathinfo['filename'];
                $extension = $pathinfo['extension'];
                $dirname   = $pathinfo['dirname'];

                // get .torrent meta info
                $torrrentMetainfo = file_get_contents($path);

                $request = array(
                                    'arguments' => array(
                                                                'download-dir' => $dirname
                                                              , 'metainfo' => base64_encode($torrrentMetainfo)
                                                          )
                                  , 'method'    => 'torrent-add'
                                  , 'tag'       => ''
                );
                $response = transmissionJsonrpcClient($request, $xTransmissionSessionId);

                // if success
                if ($response['response']['result'] === 'success')
                {
                    print "added "$filename" to download in "$dirname"" . PHP_EOL;

                    // set ratio
                    $request = array(
                                          'arguments' => array(
                                                                    'id'               => $response['response']['arguments']['torrent-added']['id']
                                                                  , 'seedRatioLimit'   => SEEDRATIOLIMIT
                                                                  , 'seedRatioLimited' => TRUE
                                                              )
                                        , 'method'    => 'session-set'
                    );
                    $response = transmissionJsonrpcClient($request, $xTransmissionSessionId);

                    // delete .torrent file
                    unlink($path);
                }
                else
                {
                    print "ERROR adding file "$filename": ". print_r($response, true) . PHP_EOL;
                }
            }
        }
        else if (is_dir($path) && is_readable($path))
        {
            // Recursive call
            searchTorrentInDir($path, $xTransmissionSessionId);
        }
    }

    return;
}
?>

One Reply to “A PHP script to start a torrent and download it where the .torrent was located using Transmission JSON-RPC”

  1. Hi, thks for the plug…but in my NAS LG N1T1 doesn’t work ;(

    It has a transmission client with a web server but not response when i run it

    Thks

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.