{"id":73,"date":"2009-07-28T12:15:31","date_gmt":"2009-07-28T17:15:31","guid":{"rendered":"http:\/\/fw.hardijzer.nl\/?p=73"},"modified":"2009-07-28T12:23:19","modified_gmt":"2009-07-28T17:23:19","slug":"my-rtorrent-setup","status":"publish","type":"post","link":"https:\/\/fw.hardijzer.nl\/?p=73","title":{"rendered":"My rtorrent setup"},"content":{"rendered":"<p>I hate leaving my main desktop turned on at night. I&#8217;m pretty sure it has something to do with the fact that it&#8217;s: a) noisy, b) in the same room I sleep in, and I: c) can&#8217;t sleep with a lot of noise or light in my room. This is why I have a seperate computer (without monitor that is) in another room that does all the stuff I&#8217;d want to be doing at night. It used to record from the TV channel, but dutch television sucks when it comes to good series, so a while ago I put a torrent client on there. Here&#8217;s a description of my old setup, and how I set it up today.<br \/>\n<!--more--><br \/>\nOriginally it worked like this: I had several directories where FlexGet or I myself would dump torrent files. All these directories were listed in rtorrent as watch directories, with each a seperate directory they got moved to when finished. This worked pretty well, but it had some shortcomings:<\/p>\n<ul>\n<li>It never cleaned up the torrent files, so at this point I had well over 200 .torrent files that I really no longer needed, but still existed on the drive.<\/li>\n<li>I only had some directory for &#8220;general&#8221; torrents that I could manually deposit torrents in. This way games, linux distro&#8217;s, movies, everything I manually downloaded ended up in the same directory.<\/li>\n<li>rtorrent never actually erased any of the torrents. It stopped seeding at a point, but it would still exist in the overview. Because of this the rtorrent overview was a mess, and the only way to really make any sense out of it was to look at the &#8220;Incomplete&#8221; tab only.<\/li>\n<li>If I wanted to add a new RSS feed with a seperate directory, I had to adjust bot the flexget config and the rtorrent config, and restart rtorrent.<\/li>\n<\/ul>\n<p>Now, as tvrss shut down, and I needed to reconfigure a few things, so I figured I&#8217;d better completely re-do the setup. What I came up with were a few PHP scripts that would fire on several rtorrent events and do all the hard work. Here&#8217;s my current setup:<\/p>\n<ul>\n<li>\/media\/tb\/.rtorrent\/data\/: this directory holds all the data that rtorrent downloads or has downloaded. Incomplete files are actually in here, complete files will be symlinks to their final destination(s)<\/li>\n<li>\/media\/tb\/.rtorrent\/incoming\/: This is the directory that holds all completed files<\/li>\n<li>\/media\/tb\/.rtorrent\/session\/: rtorrent session info<\/li>\n<li>\/media\/tb\/.rtorrent\/torrentdump\/: This is where I can dump torrents for manual downloading. Files will end up in \/media\/tb\/.rtorrent\/incoming\/Dump. It also works with recursive dirs: all torrents in \/media\/tb\/.rtorrent\/torrentdump\/A\/B\/C will be downloaded to \/media\/tb\/.rtorrent\/incoming\/Dump\/A\/B\/C.<\/li>\n<li>\/media\/tb\/.rtorrent\/torrents\/: This holds the torrents actually being downloaded, as well as a .info file for each torrent holding information on what should happen with it after it&#8217;s completed.<\/li>\n<li>\/media\/tb\/.rtorrent\/scandump.sh: A PHP script that will scan the torrentdump directory, move the torrents to the torrents directory, and create .info files for each<\/li>\n<li>\/media\/tb\/.rtorrent\/oncompleted.sh: A PHP script that will be fired by rtorrent once a download finishes. This will move the downloaded data to it&#8217;s destination directory, leave a symlink in the data directory, fix up permissions, and remove the torrent and info file.<\/li>\n<li>\/media\/tb\/.rtorrent\/rtorrent.rc: rtorrent config file.<\/li>\n<li>\/media\/tb\/Incoming: symlink to \/media\/tb\/.rtorrent\/incoming<\/li>\n<li>\/media\/tb\/TorrentDump: symlink to \/media\/tb\/.rtorrent\/torrentdump<\/li>\n<\/ul>\n<p>Let&#8217;s start with scandump.sh:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/php\r\n&lt;?\r\n$suffix=&quot;.torrent&quot;;\r\n\r\nfunction scan($directory,$outputpath,&amp;$todo) {\r\n\t$d=opendir($directory);\r\n\tif ($d!==FALSE) {\r\n\t\twhile (FALSE !== ($file=readdir($d))) {\r\n\t\t\tif ($file&#x5B;0]==&quot;.&quot;) {\r\n\t\t\t\t\/\/Ignore\r\n\t\t\t} else {\r\n\t\t\t\t$path=$directory.&quot;\/&quot;.$file;\r\n\t\t\t\tif (is_dir($path)) {\r\n\t\t\t\t\tscan($path,$outputpath.&quot;\/&quot;.$file,$todo);\r\n\t\t\t\t} else if (substr($path,strlen($path)-strlen($suffix))==$suffix) {\r\n\t\t\t\t\t$todo&#x5B;$path]=Array(\r\n\t\t\t\t\t\t&quot;path&quot;=&gt;$outputpath\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tclosedir($d);\r\n\t}\r\n}\r\n$todo=Array();\r\nscan(&quot;\/media\/tb\/.rtorrent\/torrentdump&quot;,&quot;Dump&quot;,$todo);\r\n$torrentdir=&quot;\/media\/tb\/.rtorrent\/torrents\/&quot;;\r\nforeach ($todo as $torrent=&gt;$info) {\r\n\t$target=$torrentdir.basename($torrent);\r\n\t$infopath=$target.&quot;.info&quot;;\r\n\tfile_put_contents($infopath,serialize($info));\r\n\texec(&quot;mv -f &quot;.escapeshellarg($torrent).&quot; &quot;.escapeshellarg($target));\r\n}\r\n?&gt;\r\n<\/pre>\n<p>the &#8220;scan&#8221; function recursively scans a directory for torrent files. Every torrent file it finds will be put in the $todo array, together with the destination directory (and maybe other info). The main script will call this on \/media\/tb\/.rtorrent\/torrentdump, together with a &#8220;Dump&#8221; directory as output dir. After that, it will create a .info file for each torrent first (which contains the serialized data from the scan function), and then move the torrent to the torrents dir for rtorrent to download.<\/p>\n<p>Next up: oncompleted.sh:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/php\r\n&lt;?\r\n$torrent=$argv&#x5B;1];\r\n$infofile=$torrent.&quot;.info&quot;;\r\nif (!file_exists($infofile))\r\n\tdie(&quot;Nothing to do&quot;);\r\n$datapath=$argv&#x5B;2];\r\n$info=unserialize(file_get_contents($infofile));\r\n$downloaddir=&quot;\/media\/tb\/.rtorrent\/incoming\/&quot;;\r\n$newdir=$downloaddir;\r\n$newpath=$newdir.&quot;\/&quot;.$data;\r\n$pathsplit=explode(&quot;\/&quot;,$info&#x5B;&quot;path&quot;]);\r\n$newpath=$newdir;\r\nforeach ($pathsplit as $pathbit) {\r\n\t\/\/Make new directory (with chmod and all)\r\n\t$newdir.=&quot;\/&quot;.$pathbit;\r\n\texec(&quot;mkdir -m 777 &quot;.escapeshellarg($newdir));\r\n}\r\n\/\/Move data\r\nexec(&quot;mv -f &quot;.escapeshellarg($datapath).&quot; &quot;.escapeshellarg($newpath));\r\n\/\/Chmod data\r\nexec(&quot;chmod -R 666 &quot;.escapeshellarg($newpath));\r\n\/\/Link old data to new data\r\nexec(&quot;ln -s &quot;.escapeshellarg($newpath).&quot; &quot;.escapeshellarg($datapath));\r\n\/\/Remove torrent file (will have rtorrent remove symlink)\r\nexec(&quot;rm -rf &quot;.escapeshellarg($torrent));\r\n\/\/Remove info file\r\nexec(&quot;rm -rf &quot;.escapeshellarg($infofile));\r\n?&gt;\r\n<\/pre>\n<p>This gets both the torrent file ($argv[1]), and the download path ($argv[2]). It tries to open the .info file, and then creates the needed directories (as read\/write for everyone), moves the file, chmods it read\/write, set up a symlink on the old location (for rtorrent to keep seeding), and removes the torrent and info files.<\/p>\n<p>rtorrent config follows:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n# This is an example resource file for rTorrent. Copy to\r\n# ~\/.rtorrent.rc and enable\/modify the options as needed. Remember to\r\n# uncomment the options you wish to enable.\r\n\r\n# Maximum and minimum number of peers to connect to per torrent.\r\n#min_peers = 40\r\n#max_peers = 100\r\n\r\n# Same as above but for seeding completed torrents (-1 = same as downloading)\r\n#min_peers_seed = 10\r\n#max_peers_seed = 50\r\n\r\n# Maximum number of simultanious uploads per torrent.\r\n#max_uploads = 15\r\n\r\n# Global upload and download rate in KiB. &quot;0&quot; for unlimited.\r\n#download_rate = 0\r\n#upload_rate = 0\r\n\r\n# Default directory to save the downloaded torrents.\r\ndirectory = \/media\/tb\/.rtorrent\/data\/\r\n\r\n# Default session directory. Make sure you don't run multiple instance\r\n# of rtorrent using the same session directory. Perhaps using a\r\n# relative path?\r\nsession = \/media\/tb\/.rtorrent\/session\/\r\n\r\n# Watch a directory for new torrents, and stop those that have been\r\n# deleted.\r\n#schedule = watch_directory,5,5,load_start=.\/watch\/*.torrent\r\n#schedule = untied_directory,5,5,stop_untied=\r\n\r\n# Close torrents when diskspace is low.\r\n#schedule = low_diskspace,5,60,close_low_diskspace=100M\r\n\r\n# Stop torrents when reaching upload ratio in percent,\r\n# when also reaching total upload in bytes, or when\r\n# reaching final upload ratio in percent.\r\n# example: stop at ratio 2.0 with at least 200 MB uploaded, or else ratio 20.0\r\n#schedule = ratio,60,60,&quot;stop_on_ratio=200,200M,2000&quot;\r\n\r\n# The ip address reported to the tracker.\r\n#ip = 127.0.0.1\r\n#ip = rakshasa.no\r\n\r\n# The ip address the listening socket and outgoing connections is\r\n# bound to.\r\n#bind = 127.0.0.1\r\n#bind = rakshasa.no\r\n\r\n# Port range to use for listening.\r\nport_range = 12300-12400\r\n\r\n# Start opening ports at a random position within the port range.\r\nport_random = yes\r\n\r\n# Check hash for finished torrents. Might be usefull until the bug is\r\n# fixed that causes lack of diskspace not to be properly reported.\r\ncheck_hash = no\r\n\r\n# Set whetever the client should try to connect to UDP trackers.\r\nuse_udp_trackers = yes\r\n\r\n# Alternative calls to bind and ip that should handle dynamic ip's.\r\n#schedule = ip_tick,0,1800,ip=rakshasa\r\n#schedule = bind_tick,0,1800,bind=rakshasa\r\n\r\n# Encryption options, set to none (default) or any combination of the following:\r\n# allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext\r\n#\r\n# The example value allows incoming encrypted connections, starts unencrypted\r\n# outgoing connections but retries with encryption if they fail, preferring\r\n# plaintext to RC4 encryption after the encrypted handshake\r\n#\r\nencryption = allow_incoming,try_outgoing,enable_retry\r\n\r\n# Enable DHT support for trackerless torrents or when all trackers are down.\r\n# May be set to &quot;disable&quot; (completely disable DHT), &quot;off&quot; (do not start DHT),\r\n# &quot;auto&quot; (start and stop DHT as needed), or &quot;on&quot; (start DHT immediately).\r\n# The default is &quot;off&quot;. For DHT to work, a session directory must be defined.\r\n# \r\ndht = on\r\n\r\n# UDP port to use for DHT. \r\n# \r\ndht_port = 12300\r\n\r\n# Enable peer exchange (for torrents not marked private)\r\n#\r\npeer_exchange = yes\r\n\r\n#\r\n# Do not modify the following parameters unless you know what you're doing.\r\n#\r\n\r\n# Hash read-ahead controls how many MB to request the kernel to read\r\n# ahead. If the value is too low the disk may not be fully utilized,\r\n# while if too high the kernel might not be able to keep the read\r\n# pages in memory thus end up trashing.\r\n#hash_read_ahead = 10\r\n\r\n# Interval between attempts to check the hash, in milliseconds.\r\n#hash_interval = 100\r\n\r\n# Number of attempts to check the hash while using the mincore status,\r\n# before forcing. Overworked systems might need lower values to get a\r\n# decent hash checking rate.\r\n#hash_max_tries = 10\r\n\r\n# Set the umask for this process, which is applied to all files created by the program.\r\n# umask = 0666\r\n\r\n\r\n# Watches\r\n# Scan torrent dump, and watch for torrents\r\nschedule = watch_directory,10,10,&quot;execute=\/media\/tb\/.rtorrent\/scandump.sh;load_start=\/media\/tb\/.rtorrent\/torrents\/*.torrent&quot;\r\n# Watch for torrent files being deleted\r\nschedule = watch_untied,10,10,&quot;remove_untied=&quot;\r\n# If a torrent is erased, erase the contents\r\non_erase = rm_files,&quot;execute=rm,-rf,--,$d.get_base_path=&quot;\r\n# Run oncompleted on a completed torrent\r\non_finished = linkup,&quot;execute=\/media\/tb\/.rtorrent\/oncompleted.sh,$d.get_tied_to_file=,$d.get_base_path=&quot;\r\n\r\n# Throthling\r\nschedule = throttle_high,01:00:00,24:00:00,&quot;download_rate=0;upload_rate=50&quot;\r\nschedule = throttle_low,09:00:00,24:00:00,&quot;download_rate=500;upload_rate=20&quot;\r\ndownload_rate=500\r\nupload_rate=20\r\nschedule = ratio,10,10,&quot;stop_on_ratio=1,1K,2&quot;\r\n\r\n# XMLRPC for wTorrent\r\nscgi_port = localhost:5000\r\n<\/pre>\n<p>Some of the notable changes from a default rtorrent setup:<\/p>\n<ul>\n<li>Before watching the watch directory, it calls scandump.sh<\/li>\n<li>After the torrent file is deleted, it&#8217;s removed (= completed files stop seeding)<\/li>\n<li>If a torrent is erased, the data is erased. Note that if a torrent is completed, the data is merely a symlink, so no completed torrents will be deleted<\/li>\n<li>On finished, oncompleted.sh will be run<\/li>\n<\/ul>\n<p>So, this is a much better setup than I had already. Some of the things I still need to fix:<\/p>\n<ul>\n<li>Set up FlexGet to download series, and create appropriate .info files for each torrent<\/li>\n<li>Find a way to have untied torrents seed for a while, and remove after a certain seeding threshold<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I hate leaving my main desktop turned on at night. I&#8217;m pretty sure it has something to do with the fact that it&#8217;s: a) noisy, b) in the same room I sleep in, and I: c) can&#8217;t sleep with a lot of noise or light in my room. This is why I have a seperate &hellip; <a href=\"https:\/\/fw.hardijzer.nl\/?p=73\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">My rtorrent setup<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-73","post","type-post","status-publish","format-standard","hentry","category-personal"],"_links":{"self":[{"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=73"}],"version-history":[{"count":7,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/posts\/73\/revisions"}],"predecessor-version":[{"id":221,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=\/wp\/v2\/posts\/73\/revisions\/221"}],"wp:attachment":[{"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fw.hardijzer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}