BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

create.php 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <?php
  2. function safe_b64encode($string) {
  3. $data = base64_encode($string);
  4. $data = str_replace(array('+','/','='),array('-','_',''),$data);
  5. return $data;
  6. }
  7. class Torrent {
  8. public $metadata;
  9. public $name;
  10. public $id;
  11. function __construct ($url_or_file) {
  12. $this->name = urldecode(end(explode('/', $url_or_file)));
  13. $this->id = safe_b64encode($url_or_file);
  14. $filesize = (int) array_change_key_case(
  15. get_headers($url_or_file, TRUE))['content-length'];
  16. $piece_size = $this->get_piece_size($filesize);
  17. $log = getcwd() . "/log/" . $this->id;
  18. # now create the actual torrent
  19. $this->metadata = array(
  20. 'announce' => 'http://academictorrents.com/announce.php',
  21. 'encoding' => 'UTF-8',
  22. 'info' => array(
  23. 'length' => $filesize,
  24. 'name' => $this->name,
  25. 'pieces' => $this->make_pieces($url_or_file, $piece_size,
  26. $filesize, $log),
  27. 'piece length' => $piece_size,
  28. ),
  29. 'url-list' => array($url_or_file),
  30. );
  31. $this->save();
  32. }
  33. static function bencode($var) {
  34. if (is_int($var)) {
  35. return 'i' . $var . 'e';
  36. } else if (is_string($var)) {
  37. return strlen($var) . ':' . $var;
  38. } else if (is_array($var)) {
  39. # must distinguish between dict and list
  40. for ($i = 0; $i < count($var); $i++) {
  41. # if dict, cannot index using ints?
  42. if (!isset($var[$i])) {
  43. $dictionary = $var;
  44. ksort($dictionary);
  45. $ret = 'd';
  46. foreach ($dictionary as $key => $value) {
  47. $ret .= Torrent::bencode($key) . Torrent::bencode($value);
  48. }
  49. return $ret . 'e';
  50. }
  51. }
  52. $ret = 'l';
  53. foreach ($var as $value) {
  54. $ret .= Torrent::bencode($value);
  55. }
  56. return $ret . 'e';
  57. }
  58. }
  59. private function get_piece_size($filesize) {
  60. $piece_length = 524288;
  61. while (ceil($filesize / $piece_length) == 1) {
  62. $piece_length /= 2;
  63. }
  64. while (ceil($filesize / $piece_length) > 1500) {
  65. $piece_length *= 2;
  66. }
  67. return $piece_length;
  68. }
  69. private function make_pieces($url, $piece_length, $filesize, $logfile) {
  70. if (($fp = fopen($url, 'r')) == FALSE) {
  71. return FALSE;
  72. }
  73. $pieces = '';
  74. $part = '';
  75. $position = 0;
  76. $i = 0;
  77. while ($position < $filesize) {
  78. $bytes_read = 0;
  79. # fread doesn't actually read in the correct number of bytes
  80. # piece together multiple freads
  81. while ($bytes_read < $piece_length && $position < $filesize) {
  82. $this_part = fread($fp, min($piece_length, $filesize - $position));
  83. $bytes_read += strlen($this_part);
  84. $position += strlen($this_part);
  85. $part .= $this_part;
  86. }
  87. $next_part = substr($part, $piece_length);
  88. $part = substr($part, 0, $piece_length);
  89. $piece = sha1($part, $raw_output=TRUE);
  90. $pieces .= $piece;
  91. $part = $next_part;
  92. if ($position > $filesize) {
  93. $position = $filesize;
  94. }
  95. # log progress every 5 pieces
  96. if ($i++ % 5 == 0 || $position == $filesize) {
  97. $log = fopen($logfile, "w");
  98. fwrite($log, $position . '/' . $filesize);
  99. fflush($f);
  100. fclose($log);
  101. }
  102. }
  103. fflush($f);
  104. fclose($fp);
  105. return $pieces;
  106. }
  107. private function save() {
  108. $dir = getcwd() . "/torrents/" . $this->id;
  109. mkdir($dir);
  110. $f = fopen($dir . "/" . $this->name . ".torrent", "w");
  111. fwrite($f, Torrent::bencode($this->metadata));
  112. fflush($f);
  113. fclose($f);
  114. }
  115. }
  116. /*
  117. create:
  118. 1. Input: GET variables url-encoded string "url".
  119. 2. Creates log for "id" in ./log/ for the download.
  120. 3. Streamingly creates torrent, updating log.
  121. 4. Dumps finished torrent file in ./torrents/
  122. */
  123. # Main
  124. if (isset($_GET["url"]) && filter_var($_GET["url"], FILTER_VALIDATE_URL)) {
  125. $logname = getcwd() . "/log/" . safe_b64encode($_GET["url"]);
  126. # if log exists, don't start new torrent
  127. if (file_exists($logname)) {
  128. # check status; return "done", or "processing"
  129. $contents = explode("/", stream_get_contents(fopen($logname, "r")));
  130. $progress = intval($contents[0]);
  131. $total = intval($contents[1]);
  132. if ($progress==$total) {
  133. echo(json_encode(array(
  134. 'status' => 'OK',
  135. 'msg' => "Torrent complete!")));
  136. } else {
  137. echo(json_encode(array(
  138. 'status' => 'OK',
  139. 'msg' => "Torrent already processing!")));
  140. }
  141. } else {
  142. $torrent = new Torrent($_GET["url"]);
  143. }
  144. } else {
  145. echo(json_encode(array(
  146. 'status' => 'ERROR',
  147. 'msg' => "Requires GET variable 'url'")));
  148. };
  149. ?>