Browse Source

Add support for multiple tracker tiers

pjc 5 years ago
parent
commit
7a67eae8ac

+ 13
- 0
_packages/tracker-tiers/classes/config.template View File

@@ -0,0 +1,13 @@
1
+<?php
2
+
3
+// Tracker urls to be added to torrent files à la http://bittorrent.org/beps/bep_0012.html
4
+define('ANNOUNCE_URLS', [
5
+  [ # Tier 1
6
+    'https://track.biotorrents.de:443',
7
+  ],
8
+  [ # Tier 2
9
+    'udp://tracker.coppersurfer.tk:6969/announce',
10
+    'udp://tracker.cyberia.is:6969/announce',
11
+    'udp://tracker.leechers-paradise.org:6969/announce'
12
+  ]
13
+]);

+ 19
- 0
_packages/tracker-tiers/classes/torrent_form.class View File

@@ -0,0 +1,19 @@
1
+<p style="text-align: center;">
2
+  <?php
3
+    $Announces = ANNOUNCE_URLS[0];
4
+    #$Announces = call_user_func_array('array_merge', ANNOUNCE_URLS);
5
+    foreach ($Announces as $Announce) {
6
+      # Loop through tracker URLs
7
+  ?>
8
+  <strong>Announce</strong>
9
+  <input type="text"
10
+    value="<?= $Announce . '/' . G::$LoggedUser['torrent_pass'] . '/announce' ?>"
11
+    size="74" onclick="this.select();" readonly="readonly" /> <br />
12
+  <?php
13
+    }
14
+  ?>
15
+
16
+  <strong>Source</strong>
17
+  <input type="text" value="<?= Users::get_upload_sources()[0] ?>"
18
+    size="20" onclick="this.select();" readonly="readonly" />
19
+</p>

+ 34
- 0
_packages/tracker-tiers/classes/torrentsdl.class.php View File

@@ -0,0 +1,34 @@
1
+<?php
2
+
3
+class TorrentsDL
4
+{
5
+    # ...
6
+
7
+    /**
8
+     * Create a Zip object and store the query results
9
+     *
10
+     * @param mysqli_result $QueryResult results from a query on the collector pages
11
+     * @param string $Title name of the collection that will be created
12
+     * @param string $AnnounceURL URL to add to the created torrents
13
+     */
14
+    public function __construct(&$QueryResult, $Title)
15
+    {
16
+        G::$Cache->InternalCache = false; // The internal cache is almost completely useless for this
17
+        Zip::unlimit(); // Need more memory and longer timeout
18
+        $this->QueryResult = $QueryResult;
19
+        $this->Title = $Title;
20
+        $this->User = G::$LoggedUser;
21
+        $this->AnnounceURL = ANNOUNCE_URLS[0][0].'/'.G::$LoggedUser['torrent_pass'].'/announce';
22
+
23
+        function add_passkey($Ann)
24
+        {
25
+            return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann.'/'.G::$LoggedUser['torrent_pass'].'/announce';
26
+        }
27
+
28
+        $this->AnnounceList = array(array_map('add_passkey', ANNOUNCE_URLS[0]), ANNOUNCE_URLS[1]);
29
+        #$this->AnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map('add_passkey', ANNOUNCE_URLS);
30
+        $this->Zip = new Zip(Misc::file_string($Title));
31
+    }
32
+
33
+    # ...
34
+}

+ 10
- 0
_packages/tracker-tiers/readme.md View File

@@ -0,0 +1,10 @@
1
+# Multiple tracker tiers
2
+
3
+BioTorrents.de supports two tiers of trackers:
4
+
5
+  - Tier 1: Authenticated private tracker URLs using the familiar Gazelle/Ocelot features
6
+  - Tier 2: A list of standalone public trackers as backups, in case the main tracker goes down
7
+
8
+Please note that all torrent contents are hashed with the private flag, so the normal protections against DHT, PEX, etc., work as expected.
9
+
10
+Support for multiple trackers does not extend to magnet links!

+ 20
- 0
_packages/tracker-tiers/sections/torrents/download.php View File

@@ -0,0 +1,20 @@
1
+<?php
2
+
3
+# ...
4
+
5
+header('Content-Type: application/x-bittorrent; charset=utf-8');
6
+header('Content-disposition: attachment; filename="'.$FileName.'"');
7
+
8
+function add_passkey($Ann)
9
+{
10
+    global $TorrentPass;
11
+    return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann.'/'.$TorrentPass.'/announce';
12
+}
13
+
14
+$UserAnnounceURL = ANNOUNCE_URLS[0][0].'/'.$TorrentPass.'/announce';
15
+$UserAnnounceList = array(array_map('add_passkey', ANNOUNCE_URLS[0]), ANNOUNCE_URLS[1]);
16
+#$UserAnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map('add_passkey', ANNOUNCE_URLS);
17
+
18
+echo TorrentsDL::get_file($Contents, $UserAnnounceURL, $UserAnnounceList);
19
+
20
+define('SKIP_NO_CACHE_HEADERS', 1);

+ 238
- 229
classes/torrent.class.php View File

@@ -1,4 +1,4 @@
1
-<?
1
+<?php
2 2
 /*******************************************************************************
3 3
 |~~~~ Gazelle bencode parser                         ~~~~|
4 4
 --------------------------------------------------------------------------------
@@ -63,266 +63,275 @@ the BENCODE_DICT class.
63 63
 
64 64
 
65 65
 *******************************************************************************/
66
-class BENCODE2 {
67
-  var $Val; // Decoded array
68
-  var $Pos = 1; // Pointer that indicates our position in the string
69
-  var $Str = ''; // Torrent string
70
-
71
-  function __construct($Val, $IsParsed = false) {
72
-    if (!$IsParsed) {
73
-      $this->Str = $Val;
74
-      $this->dec();
75
-    } else {
76
-      $this->Val = $Val;
77
-    }
78
-  }
79
-
80
-  // Decode an element based on the type. The type is really just an indicator.
81
-  function decode($Type, $Key) {
82
-    if (is_number($Type)) { // Element is a string
83
-      // Get length of string
84
-      $StrLen = $Type;
85
-      while ($this->Str[$this->Pos + 1] != ':') {
86
-        $this->Pos++;
87
-        $StrLen.=$this->Str[$this->Pos];
88
-      }
89
-      $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
90
-
91
-      $this->Pos += $StrLen;
92
-      $this->Pos += 2;
93
-
94
-    } elseif ($Type == 'i') { // Element is an int
95
-      $this->Pos++;
96
-
97
-      // Find end of integer (first occurance of 'e' after position)
98
-      $End = strpos($this->Str, 'e', $this->Pos);
99
-
100
-      // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
101
-      $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
102
-      $this->Pos = $End + 1;
103
-
104
-    } elseif ($Type == 'l') { // Element is a list
105
-      $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
106
-      $this->Pos += $this->Val[$Key]->Pos;
107
-
108
-    } elseif ($Type == 'd') { // Element is a dictionary
109
-      $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
110
-      $this->Pos += $this->Val[$Key]->Pos;
111
-      // Sort by key to respect spec
112
-      if (!empty($this->Val[$Key]->Val)) {
113
-        ksort($this->Val[$Key]->Val);
66
+class BENCODE2
67
+{
68
+    public $Val; // Decoded array
69
+  public $Pos = 1; // Pointer that indicates our position in the string
70
+  public $Str = ''; // Torrent string
71
+
72
+  public function __construct($Val, $IsParsed = false)
73
+  {
74
+      if (!$IsParsed) {
75
+          $this->Str = $Val;
76
+          $this->dec();
77
+      } else {
78
+          $this->Val = $Val;
114 79
       }
80
+  }
115 81
 
116
-    } else {
117
-      die('Invalid torrent file');
82
+    // Decode an element based on the type. The type is really just an indicator.
83
+    public function decode($Type, $Key)
84
+    {
85
+        if (is_number($Type)) { // Element is a string
86
+            // Get length of string
87
+            $StrLen = $Type;
88
+            while ($this->Str[$this->Pos + 1] !== ':') {
89
+                $this->Pos++;
90
+                $StrLen.=$this->Str[$this->Pos];
91
+            }
92
+            $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
93
+
94
+            $this->Pos += $StrLen;
95
+            $this->Pos += 2;
96
+        } elseif ($Type === 'i') { // Element is an int
97
+            $this->Pos++;
98
+
99
+            // Find end of integer (first occurance of 'e' after position)
100
+            $End = strpos($this->Str, 'e', $this->Pos);
101
+
102
+            // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
103
+            $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
104
+            $this->Pos = $End + 1;
105
+        } elseif ($Type === 'l') { // Element is a list
106
+            $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
107
+            $this->Pos += $this->Val[$Key]->Pos;
108
+        } elseif ($Type === 'd') { // Element is a dictionary
109
+            $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
110
+            $this->Pos += $this->Val[$Key]->Pos;
111
+            // Sort by key to respect spec
112
+            if (!empty($this->Val[$Key]->Val)) {
113
+                ksort($this->Val[$Key]->Val);
114
+            }
115
+        } else {
116
+            die('Invalid torrent file');
117
+        }
118 118
     }
119
-  }
120 119
 
121
-  function encode($Val) {
122
-    if (is_int($Val)) { // Integer
123
-      return 'i'.$Val.'e';
124
-    } elseif (is_string($Val)) {
125
-      return strlen($Val).':'.$Val;
126
-    } elseif (is_object($Val)) {
127
-      return $Val->enc();
128
-    } else {
129
-      return 'fail';
120
+    public function encode($Val)
121
+    {
122
+        if (is_int($Val)) { // Integer
123
+            return 'i'.$Val.'e';
124
+        } elseif (is_string($Val)) {
125
+            return strlen($Val).':'.$Val;
126
+        } elseif (is_object($Val)) {
127
+            return $Val->enc();
128
+        } else {
129
+            return 'fail';
130
+        }
130 131
     }
131
-  }
132 132
 }
133 133
 
134
-class BENCODE_LIST extends BENCODE2 {
135
-  function enc() {
136
-    if (empty($this->Val)) {
137
-      return 'le';
138
-    }
139
-    $Str = 'l';
140
-    reset($this->Val);
141
-    foreach ($this->Val as $Value) {
142
-      $Str.=$this->encode($Value);
134
+class BENCODE_LIST extends BENCODE2
135
+{
136
+    public function enc()
137
+    {
138
+        if (empty($this->Val)) {
139
+            return 'le';
140
+        }
141
+        $Str = 'l';
142
+        reset($this->Val);
143
+        foreach ($this->Val as $Value) {
144
+            $Str.=$this->encode($Value);
145
+        }
146
+        return $Str.'e';
143 147
     }
144
-    return $Str.'e';
145
-  }
146
-
147
-  // Decode a list
148
-  function dec() {
149
-    $Key = 0; // Array index
150
-    $Length = strlen($this->Str);
151
-    while ($this->Pos < $Length) {
152
-      $Type = $this->Str[$this->Pos];
153
-      // $Type now indicates what type of element we're dealing with
154
-      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
155
-
156
-      if ($Type == 'e') { // End of list
157
-        $this->Pos += 1;
158
-        unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
159
-        return;
160
-      }
161 148
 
162
-      // Decode the bencoded element.
163
-      // This function changes $this->Pos and $this->Val, so you don't have to.
164
-      $this->decode($Type, $Key);
165
-      ++$Key;
149
+    // Decode a list
150
+    public function dec()
151
+    {
152
+        $Key = 0; // Array index
153
+        $Length = strlen($this->Str);
154
+        while ($this->Pos < $Length) {
155
+            $Type = $this->Str[$this->Pos];
156
+            // $Type now indicates what type of element we're dealing with
157
+            // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
158
+
159
+            if ($Type === 'e') { // End of list
160
+                $this->Pos += 1;
161
+                unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
162
+                return;
163
+            }
164
+
165
+            // Decode the bencoded element.
166
+            // This function changes $this->Pos and $this->Val, so you don't have to.
167
+            $this->decode($Type, $Key);
168
+            ++$Key;
169
+        }
170
+        return true;
166 171
     }
167
-    return true;
168
-  }
169 172
 }
170 173
 
171
-class BENCODE_DICT extends BENCODE2 {
172
-  function enc() {
173
-    if (empty($this->Val)) {
174
-      return 'de';
175
-    }
176
-    $Str = 'd';
177
-    reset($this->Val);
178
-    foreach ($this->Val as $Key => $Value) {
179
-      $Str.=strlen($Key).':'.$Key.$this->encode($Value);
174
+class BENCODE_DICT extends BENCODE2
175
+{
176
+    public function enc()
177
+    {
178
+        if (empty($this->Val)) {
179
+            return 'de';
180
+        }
181
+        $Str = 'd';
182
+        reset($this->Val);
183
+        foreach ($this->Val as $Key => $Value) {
184
+            $Str.=strlen($Key).':'.$Key.$this->encode($Value);
185
+        }
186
+        return $Str.'e';
180 187
     }
181
-    return $Str.'e';
182
-  }
183
-
184
-  // Decode a dictionary
185
-  function dec() {
186
-    $Length = strlen($this->Str);
187
-    while ($this->Pos<$Length) {
188
-
189
-      if ($this->Str[$this->Pos] == 'e') { // End of dictionary
190
-        $this->Pos += 1;
191
-        unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
192
-        return;
193
-      }
194
-
195
-      // Get the dictionary key
196
-      // Length of the key, in bytes
197
-      $KeyLen = $this->Str[$this->Pos];
198
-
199
-      // Allow for multi-digit lengths
200
-      while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
201
-        $this->Pos++;
202
-        $KeyLen.=$this->Str[$this->Pos];
203
-      }
204
-      // $this->Pos is now on the last letter of the key length
205
-      // Adding 2 brings it past that character and the ':' to the beginning of the string
206
-      $this->Pos += 2;
207
-
208
-      // Get the name of the key
209
-      $Key = substr($this->Str, $this->Pos, $KeyLen);
210
-
211
-      // Move the position past the key to the beginning of the element
212
-      $this->Pos += $KeyLen;
213
-      $Type = $this->Str[$this->Pos];
214
-      // $Type now indicates what type of element we're dealing with
215
-      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
216
-
217
-      // Decode the bencoded element.
218
-      // This function changes $this->Pos and $this->Val, so you don't have to.
219
-      $this->decode($Type, $Key);
220
-
221 188
 
189
+    // Decode a dictionary
190
+    public function dec()
191
+    {
192
+        $Length = strlen($this->Str);
193
+        while ($this->Pos<$Length) {
194
+            if ($this->Str[$this->Pos] === 'e') { // End of dictionary
195
+                $this->Pos += 1;
196
+                unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
197
+                return;
198
+            }
199
+
200
+            // Get the dictionary key
201
+            // Length of the key, in bytes
202
+            $KeyLen = $this->Str[$this->Pos];
203
+
204
+            // Allow for multi-digit lengths
205
+            while ($this->Str[$this->Pos + 1] !== ':' && $this->Pos + 1 < $Length) {
206
+                $this->Pos++;
207
+                $KeyLen.=$this->Str[$this->Pos];
208
+            }
209
+            // $this->Pos is now on the last letter of the key length
210
+            // Adding 2 brings it past that character and the ':' to the beginning of the string
211
+            $this->Pos += 2;
212
+
213
+            // Get the name of the key
214
+            $Key = substr($this->Str, $this->Pos, $KeyLen);
215
+
216
+            // Move the position past the key to the beginning of the element
217
+            $this->Pos += $KeyLen;
218
+            $Type = $this->Str[$this->Pos];
219
+            // $Type now indicates what type of element we're dealing with
220
+            // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
221
+
222
+            // Decode the bencoded element.
223
+            // This function changes $this->Pos and $this->Val, so you don't have to.
224
+            $this->decode($Type, $Key);
225
+        }
226
+        return true;
222 227
     }
223
-    return true;
224
-  }
225 228
 }
226 229
 
227 230
 
228
-class TORRENT extends BENCODE_DICT {
229
-  function dump() {
230
-    // Convenience function used for testing and figuring out how we store the data
231
-    print_r($this->Val);
232
-  }
233
-
234
-  function dump_data() {
235
-    // Function which serializes $this->Val for storage
236
-    return base64_encode(serialize($this->Val));
237
-  }
231
+class TORRENT extends BENCODE_DICT
232
+{
233
+    public function dump()
234
+    {
235
+        // Convenience function used for testing and figuring out how we store the data
236
+        print_r($this->Val);
237
+    }
238 238
 
239
-  function set_announce_list($UrlsList) {
240
-    $AnnounceList = new BENCODE_LIST([], true);
241
-    foreach ($UrlsList as $Urls) {
242
-      $SubList = new BENCODE_LIST($Urls, true);
243
-      unset($SubList->Str);
244
-      $AnnounceList->Val[] = $SubList;
239
+    public function dump_data()
240
+    {
241
+        // Function which serializes $this->Val for storage
242
+        return base64_encode(serialize($this->Val));
245 243
     }
246
-    $this->Val['announce-list'] = $AnnounceList;
247
-  }
248 244
 
249
-  function set_announce_url($Announce) {
250
-    $this->Val['announce'] = $Announce;
251
-    ksort($this->Val);
252
-  }
245
+    public function set_announce_list($UrlsList)
246
+    {
247
+        $AnnounceList = new BENCODE_LIST([], true);
248
+        foreach ($UrlsList as $Urls) {
249
+            $SubList = new BENCODE_LIST($Urls, true);
250
+            unset($SubList->Str);
251
+            $AnnounceList->Val[] = $SubList;
252
+        }
253
+        $this->Val['announce-list'] = $AnnounceList;
254
+    }
253 255
 
254
-  // Returns an array of:
255
-  //  * the files in the torrent
256
-  //  * the total size of files described therein
257
-  function file_list() {
258
-    $FileList = [];
259
-    if (!isset($this->Val['info']->Val['files'])) { // Single file mode
260
-      $TotalSize = $this->Val['info']->Val['length'];
261
-      $FileList[] = array($TotalSize, $this->get_name());
262
-    } else { // Multiple file mode
263
-      $FileNames = [];
264
-      $FileSizes = [];
265
-      $TotalSize = 0;
266
-      $Files = $this->Val['info']->Val['files']->Val;
267
-      if (isset($Files[0]->Val['path.utf-8'])) {
268
-        $PathKey = 'path.utf-8';
269
-      } else {
270
-        $PathKey = 'path';
271
-      }
272
-      foreach ($Files as $File) {
273
-        $FileSize = $File->Val['length'];
274
-        $TotalSize += $FileSize;
256
+    public function set_announce_url($Announce)
257
+    {
258
+        $this->Val['announce'] = $Announce;
259
+        ksort($this->Val);
260
+    }
275 261
 
276
-        $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
277
-        $FileSizes[] = $FileSize;
278
-        $FileNames[] = $FileName;
279
-      }
280
-      natcasesort($FileNames);
281
-      foreach ($FileNames as $Index => $FileName) {
282
-        $FileList[] = array($FileSizes[$Index], $FileName);
283
-      }
262
+    // Returns an array of:
263
+    //  * the files in the torrent
264
+    //  * the total size of files described therein
265
+    public function file_list()
266
+    {
267
+        $FileList = [];
268
+        if (!isset($this->Val['info']->Val['files'])) { // Single file mode
269
+            $TotalSize = $this->Val['info']->Val['length'];
270
+            $FileList[] = array($TotalSize, $this->get_name());
271
+        } else { // Multiple file mode
272
+            $FileNames = [];
273
+            $FileSizes = [];
274
+            $TotalSize = 0;
275
+            $Files = $this->Val['info']->Val['files']->Val;
276
+            if (isset($Files[0]->Val['path.utf-8'])) {
277
+                $PathKey = 'path.utf-8';
278
+            } else {
279
+                $PathKey = 'path';
280
+            }
281
+            foreach ($Files as $File) {
282
+                $FileSize = $File->Val['length'];
283
+                $TotalSize += $FileSize;
284
+
285
+                $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
286
+                $FileSizes[] = $FileSize;
287
+                $FileNames[] = $FileName;
288
+            }
289
+            natcasesort($FileNames);
290
+            foreach ($FileNames as $Index => $FileName) {
291
+                $FileList[] = array($FileSizes[$Index], $FileName);
292
+            }
293
+        }
294
+        return array($TotalSize, $FileList);
284 295
     }
285
-    return array($TotalSize, $FileList);
286
-  }
287 296
 
288
-  function get_name() {
289
-    if (isset($this->Val['info']->Val['name.utf-8'])) {
290
-      return $this->Val['info']->Val['name.utf-8'];
291
-    } else {
292
-      return $this->Val['info']->Val['name'];
297
+    public function get_name()
298
+    {
299
+        if (isset($this->Val['info']->Val['name.utf-8'])) {
300
+            return $this->Val['info']->Val['name.utf-8'];
301
+        } else {
302
+            return $this->Val['info']->Val['name'];
303
+        }
293 304
     }
294
-  }
295 305
 
296
-  function make_private() {
297
-    //----- The following properties do not affect the infohash:
306
+    public function make_private()
307
+    {
308
+        //----- The following properties do not affect the infohash:
298 309
 
299
-    // anounce-list is an unofficial extension to the protocol
300
-    // that allows for multiple trackers per torrent
301
-    unset($this->Val['announce-list']);
310
+        // anounce-list is an unofficial extension to the protocol
311
+        // that allows for multiple trackers per torrent
312
+        unset($this->Val['announce-list']);
302 313
 
303
-    // Bitcomet & Azureus cache peers in here
304
-    unset($this->Val['nodes']);
314
+        // Bitcomet & Azureus cache peers in here
315
+        unset($this->Val['nodes']);
305 316
 
306
-    // Azureus stores the dht_backup_enable flag here
307
-    unset($this->Val['azureus_properties']);
317
+        // Azureus stores the dht_backup_enable flag here
318
+        unset($this->Val['azureus_properties']);
308 319
 
309
-    // Remove web-seeds
310
-    unset($this->Val['url-list']);
320
+        // Remove web-seeds
321
+        #unset($this->Val['url-list']);
311 322
 
312
-    // Remove libtorrent resume info
313
-    unset($this->Val['libtorrent_resume']);
323
+        // Remove libtorrent resume info
324
+        unset($this->Val['libtorrent_resume']);
314 325
 
315
-    //----- End properties that do not affect the infohash
316
-    if ($this->Val['info']->Val['private']) {
317
-      return true; // Torrent is private
318
-    } else {
319
-      // Torrent is not private!
320
-      // add private tracker flag and sort info dictionary
321
-      $this->Val['info']->Val['private'] = 1;
322
-      ksort($this->Val['info']->Val);
323
-      return false;
326
+        //----- End properties that do not affect the infohash
327
+        if ($this->Val['info']->Val['private']) {
328
+            return true; // Torrent is private
329
+        } else {
330
+            // Torrent is not private!
331
+            // add private tracker flag and sort info dictionary
332
+            $this->Val['info']->Val['private'] = 1;
333
+            ksort($this->Val['info']->Val);
334
+            return false;
335
+        }
324 336
     }
325
-  }
326 337
 }
327
-
328
-?>

+ 21
- 29
classes/torrent_form.class.php View File

@@ -16,7 +16,7 @@ class TorrentForm
16 16
     public $ContainersProt = [];
17 17
     public $Codecs = [];
18 18
     public $Resolutions = [];
19
-    var $AudioFormats = [];
19
+    public $AudioFormats = [];
20 20
     #var $Subbing = [];
21 21
     #var $Languages = [];
22 22
     #var $Platform = [];
@@ -82,26 +82,18 @@ class TorrentForm
82 82
 
83 83
   <p style="text-align: center;">
84 84
     <?php
85
-      $Announces = call_user_func_array('array_merge', ANNOUNCE_URLS);
86
-        foreach ($Announces as $Announce) {
87
-            # Loop through tracker URLs?>
85
+      $Announces = ANNOUNCE_URLS[0];
86
+      #$Announces = call_user_func_array('array_merge', ANNOUNCE_URLS);
87
+      foreach ($Announces as $Announce) {
88
+          # Loop through tracker URLs
89
+            ?>
88 90
     <strong>Announce</strong>
89
-
90
-    <?php
91
-    # Buying into the shit coding style
92
-    # Just trying to mirror content on a Tier 2 public tracker
93
-    if (!strstr($Announce, 'openbittorrent')) {
94
-        ?>
95 91
     <input type="text"
96 92
       value="<?= $Announce . '/' . G::$LoggedUser['torrent_pass'] . '/announce' ?>"
97 93
       size="74" onclick="this.select();" readonly="readonly" /> <br />
98 94
     <?php
99
-    } else { ?>
100
-    <input type="text" value="<?= $Announce ?>" size="74"
101
-      onclick="this.select();" readonly="readonly" /> <br />
102
-    <?php
103
-    }
104
-        } ?>
95
+      }
96
+    ?>
105 97
 
106 98
     <strong>Source</strong>
107 99
     <input type="text" value="<?= Users::get_upload_sources()[0] ?>"
@@ -156,8 +148,8 @@ class TorrentForm
156 148
 
157 149
       <tr>
158 150
         <td class="label">
159
-        Torrent File
160
-        <strong class="important_text">*</strong>
151
+          Torrent File
152
+          <strong class="important_text">*</strong>
161 153
         </td>
162 154
         <td><input id="file" type="file" name="file_input" size="50" /><br />
163 155
           Use the above announce URL and set the private flag in your BitTorrent client, e.g.,
@@ -167,8 +159,8 @@ class TorrentForm
167 159
 
168 160
       <tr>
169 161
         <td class="label">
170
-        Category
171
-        <strong class="important_text">*</strong>
162
+          Category
163
+          <strong class="important_text">*</strong>
172 164
         </td>
173 165
         <td>
174 166
           <select id="categories" name="type" onchange="Categories()" <?= ($this->DisabledFlag) ? ' disabled="disabled"' : '' ?>>
@@ -318,13 +310,13 @@ class TorrentForm
318 310
   </tr>
319 311
 
320 312
   <!-- Semantic Versioning -->
321
-    <tr id="audio_tr">
313
+  <tr id="audio_tr">
322 314
     <td class="label">Version</td>
323 315
     <td>
324
-      <input type="text" id="audioformat" name="audioformat" size="10"
325
-        pattern="\d+\.\d+\.\d+" value="<?= display_str($Torrent['AudioFormat']) ?>"
316
+      <input type="text" id="audioformat" name="audioformat" size="10" pattern="\d+\.\d+\.\d+"
317
+        value="<?= display_str($Torrent['AudioFormat']) ?>"
326 318
         <?= $this->Disabled ?>/><br />
327
-      Please see <a href="https://semver.org target="_blank">Semantic Versioning</a>; start with 0.1.0
319
+      Please see <a href="https://semver.org target=" _blank">Semantic Versioning</a>; start with 0.1.0
328 320
     </td>
329 321
   </tr>
330 322
 
@@ -465,7 +457,7 @@ class TorrentForm
465 457
     </td>
466 458
     <td>
467 459
       <select name="media">
468
-      <option value="">---</option>
460
+        <option value="">---</option>
469 461
         <?php
470 462
           foreach ($this->Media as $Media) {
471 463
               echo "\t\t\t\t\t\t<option value=\"$Media\"";
@@ -545,7 +537,7 @@ class TorrentForm
545 537
     </td>
546 538
     <td>
547 539
       <select name="container">
548
-      <option value="">---</option>
540
+        <option value="">---</option>
549 541
         <?php
550 542
           foreach ($this->Containers as $Name => $Container) {
551 543
               echo "<option value='$Name'>$Name</option>\n";
@@ -563,7 +555,7 @@ class TorrentForm
563 555
     </td>
564 556
     <td>
565 557
       <select id="container" name="container">
566
-      <option value="">---</option>
558
+        <option value="">---</option>
567 559
         <?php
568 560
           foreach ($this->ContainersGames as $Name => $Container) {
569 561
               echo "<option value='$Name'>$Name</option>\n";
@@ -581,7 +573,7 @@ class TorrentForm
581 573
     </td>
582 574
     <td>
583 575
       <select id="container" name="container">
584
-      <option value="">---</option>
576
+        <option value="">---</option>
585 577
         <?php
586 578
           foreach ($this->ContainersProt as $Name => $Container) {
587 579
               echo "<option value='$Name'>$Name</option>\n";
@@ -599,7 +591,7 @@ class TorrentForm
599 591
     </td>
600 592
     <td>
601 593
       <select name='archive'>
602
-      <option value="">---</option>
594
+        <option value="">---</option>
603 595
         <?php
604 596
           foreach ($this->Archives as $Name => $Archive) {
605 597
               echo "\t\t\t\t\t\t<option value=\"$Name\"";

+ 215
- 200
classes/torrentsdl.class.php View File

@@ -1,142 +1,154 @@
1
-<?
1
+<?php
2 2
 /**
3 3
  * Class for functions related to the features involving torrent downloads
4 4
  */
5
-class TorrentsDL {
6
-  const ChunkSize = 100;
7
-  const MaxPathLength = 200;
8
-  private $QueryResult;
9
-  private $QueryRowNum = 0;
10
-  private $Zip;
11
-  private $IDBoundaries;
12
-  private $FailedFiles = [];
13
-  private $NumAdded = 0;
14
-  private $NumFound = 0;
15
-  private $Size = 0;
16
-  private $Title;
17
-  private $User;
18
-  private $AnnounceURL;
19
-  private $AnnounceList;
5
+class TorrentsDL
6
+{
7
+    const ChunkSize = 100;
8
+    const MaxPathLength = 200;
9
+    private $QueryResult;
10
+    private $QueryRowNum = 0;
11
+    private $Zip;
12
+    private $IDBoundaries;
13
+    private $FailedFiles = [];
14
+    private $NumAdded = 0;
15
+    private $NumFound = 0;
16
+    private $Size = 0;
17
+    private $Title;
18
+    private $User;
19
+    private $AnnounceURL;
20
+    private $AnnounceList;
20 21
 
21
-  /**
22
-   * Create a Zip object and store the query results
23
-   *
24
-   * @param mysqli_result $QueryResult results from a query on the collector pages
25
-   * @param string $Title name of the collection that will be created
26
-   * @param string $AnnounceURL URL to add to the created torrents
27
-   */
28
-  public function __construct(&$QueryResult, $Title) {
29
-    G::$Cache->InternalCache = false; // The internal cache is almost completely useless for this
30
-    Zip::unlimit(); // Need more memory and longer timeout
31
-    $this->QueryResult = $QueryResult;
32
-    $this->Title = $Title;
33
-    $this->User = G::$LoggedUser;
34
-    $this->AnnounceURL = ANNOUNCE_URLS[0][0]."/".G::$LoggedUser['torrent_pass']."/announce";
35
-    function add_passkey($Ann) {
36
-      return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann."/".G::$LoggedUser['torrent_pass']."/announce";
37
-    }
38
-    $this->AnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map('add_passkey', ANNOUNCE_URLS);
39
-    $this->Zip = new Zip(Misc::file_string($Title));
40
-  }
22
+    /**
23
+     * Create a Zip object and store the query results
24
+     *
25
+     * @param mysqli_result $QueryResult results from a query on the collector pages
26
+     * @param string $Title name of the collection that will be created
27
+     * @param string $AnnounceURL URL to add to the created torrents
28
+     */
29
+    public function __construct(&$QueryResult, $Title)
30
+    {
31
+        G::$Cache->InternalCache = false; // The internal cache is almost completely useless for this
32
+        Zip::unlimit(); // Need more memory and longer timeout
33
+        $this->QueryResult = $QueryResult;
34
+        $this->Title = $Title;
35
+        $this->User = G::$LoggedUser;
36
+        $this->AnnounceURL = ANNOUNCE_URLS[0][0].'/'.G::$LoggedUser['torrent_pass'].'/announce';
41 37
 
42
-  /**
43
-   * Store the results from a DB query in smaller chunks to save memory
44
-   *
45
-   * @param string $Key the key to use in the result hash map
46
-   * @return array with results and torrent group IDs or false if there are no results left
47
-   */
48
-  public function get_downloads($Key) {
49
-    $GroupIDs = $Downloads = [];
50
-    $OldQuery = G::$DB->get_query_id();
51
-    G::$DB->set_query_id($this->QueryResult);
52
-    if (!isset($this->IDBoundaries)) {
53
-      if ($Key == 'TorrentID') {
54
-        $this->IDBoundaries = false;
55
-      } else {
56
-        $this->IDBoundaries = G::$DB->to_pair($Key, 'TorrentID', false);
57
-      }
58
-    }
59
-    $Found = 0;
60
-    while ($Download = G::$DB->next_record(MYSQLI_ASSOC, false)) {
61
-      if (!$this->IDBoundaries || $Download['TorrentID'] == $this->IDBoundaries[$Download[$Key]]) {
62
-        $Found++;
63
-        $Downloads[$Download[$Key]] = $Download;
64
-        $GroupIDs[$Download['TorrentID']] = $Download['GroupID'];
65
-        if ($Found >= self::ChunkSize) {
66
-          break;
38
+        function add_passkey($Ann)
39
+        {
40
+            return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann.'/'.G::$LoggedUser['torrent_pass'].'/announce';
67 41
         }
68
-      }
42
+
43
+        $this->AnnounceList = array(array_map('add_passkey', ANNOUNCE_URLS[0]), ANNOUNCE_URLS[1]);
44
+        #$this->AnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map('add_passkey', ANNOUNCE_URLS);
45
+        $this->Zip = new Zip(Misc::file_string($Title));
69 46
     }
70
-    $this->NumFound += $Found;
71
-    G::$DB->set_query_id($OldQuery);
72
-    if (empty($Downloads)) {
73
-      return false;
47
+
48
+    /**
49
+     * Store the results from a DB query in smaller chunks to save memory
50
+     *
51
+     * @param string $Key the key to use in the result hash map
52
+     * @return array with results and torrent group IDs or false if there are no results left
53
+     */
54
+    public function get_downloads($Key)
55
+    {
56
+        $GroupIDs = $Downloads = [];
57
+        $OldQuery = G::$DB->get_query_id();
58
+        G::$DB->set_query_id($this->QueryResult);
59
+        if (!isset($this->IDBoundaries)) {
60
+            if ($Key == 'TorrentID') {
61
+                $this->IDBoundaries = false;
62
+            } else {
63
+                $this->IDBoundaries = G::$DB->to_pair($Key, 'TorrentID', false);
64
+            }
65
+        }
66
+        $Found = 0;
67
+        while ($Download = G::$DB->next_record(MYSQLI_ASSOC, false)) {
68
+            if (!$this->IDBoundaries || $Download['TorrentID'] == $this->IDBoundaries[$Download[$Key]]) {
69
+                $Found++;
70
+                $Downloads[$Download[$Key]] = $Download;
71
+                $GroupIDs[$Download['TorrentID']] = $Download['GroupID'];
72
+                if ($Found >= self::ChunkSize) {
73
+                    break;
74
+                }
75
+            }
76
+        }
77
+        $this->NumFound += $Found;
78
+        G::$DB->set_query_id($OldQuery);
79
+        if (empty($Downloads)) {
80
+            return false;
81
+        }
82
+        return array($Downloads, $GroupIDs);
74 83
     }
75
-    return array($Downloads, $GroupIDs);
76
-  }
77 84
 
78
-  /**
79
-   * Add a file to the zip archive
80
-   *
81
-   * @param string $TorrentData bencoded torrent without announce url (new format) or TORRENT object (old format)
82
-   * @param array $Info file info stored as an array with at least the keys
83
-   *  Artist, Name, Year, Media, Format, Encoding and TorrentID
84
-   * @param string $FolderName folder name
85
-   */
86
-  public function add_file(&$TorrentData, $Info, $FolderName = '') {
87
-    $FolderName = Misc::file_string($FolderName);
88
-    $MaxPathLength = $FolderName ? (self::MaxPathLength - strlen($FolderName) - 1) : self::MaxPathLength;
89
-    $FileName = self::construct_file_name($Info['Artist'], $Info['Name'], $Info['Year'], $Info['Media'], $Info['Format'], $Info['Encoding'], $Info['TorrentID'], $MaxPathLength);
90
-    $this->Size += $Info['Size'];
91
-    $this->NumAdded++;
92
-    $this->Zip->add_file(self::get_file($TorrentData, $this->AnnounceURL, $this->AnnounceList), ($FolderName ? "$FolderName/" : "") . $FileName);
93
-    usleep(25000); // We don't want to send much faster than the client can receive
94
-  }
85
+    /**
86
+     * Add a file to the zip archive
87
+     *
88
+     * @param string $TorrentData bencoded torrent without announce url (new format) or TORRENT object (old format)
89
+     * @param array $Info file info stored as an array with at least the keys
90
+     *  Artist, Name, Year, Media, Format, Encoding and TorrentID
91
+     * @param string $FolderName folder name
92
+     */
93
+    public function add_file(&$TorrentData, $Info, $FolderName = '')
94
+    {
95
+        $FolderName = Misc::file_string($FolderName);
96
+        $MaxPathLength = $FolderName ? (self::MaxPathLength - strlen($FolderName) - 1) : self::MaxPathLength;
97
+        $FileName = self::construct_file_name($Info['Artist'], $Info['Name'], $Info['Year'], $Info['Media'], $Info['Format'], $Info['Encoding'], $Info['TorrentID'], $MaxPathLength);
98
+        $this->Size += $Info['Size'];
99
+        $this->NumAdded++;
100
+        $this->Zip->add_file(self::get_file($TorrentData, $this->AnnounceURL, $this->AnnounceList), ($FolderName ? "$FolderName/" : "") . $FileName);
101
+        usleep(25000); // We don't want to send much faster than the client can receive
102
+    }
95 103
 
96
-  /**
97
-   * Add a file to the list of files that could not be downloaded
98
-   *
99
-   * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
100
-   */
101
-  public function fail_file($Info) {
102
-    $this->FailedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
103
-  }
104
+    /**
105
+     * Add a file to the list of files that could not be downloaded
106
+     *
107
+     * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
108
+     */
109
+    public function fail_file($Info)
110
+    {
111
+        $this->FailedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
112
+    }
104 113
 
105
-  /**
106
-   * Add a file to the list of files that did not match the user's format or quality requirements
107
-   *
108
-   * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
109
-   */
110
-  public function skip_file($Info) {
111
-    $this->SkippedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
112
-  }
114
+    /**
115
+     * Add a file to the list of files that did not match the user's format or quality requirements
116
+     *
117
+     * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
118
+     */
119
+    public function skip_file($Info)
120
+    {
121
+        $this->SkippedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
122
+    }
113 123
 
114
-  /**
115
-   * Add a summary to the archive and include a list of files that could not be added. Close the zip archive
116
-   *
117
-   * @param bool $FilterStats whether to include filter stats in the report
118
-   */
119
-  public function finalize($FilterStats = true) {
120
-    $this->Zip->add_file($this->summary($FilterStats), "Summary.txt");
121
-    if (!empty($this->FailedFiles)) {
122
-      $this->Zip->add_file($this->errors(), "Errors.txt");
124
+    /**
125
+     * Add a summary to the archive and include a list of files that could not be added. Close the zip archive
126
+     *
127
+     * @param bool $FilterStats whether to include filter stats in the report
128
+     */
129
+    public function finalize($FilterStats = true)
130
+    {
131
+        $this->Zip->add_file($this->summary($FilterStats), "Summary.txt");
132
+        if (!empty($this->FailedFiles)) {
133
+            $this->Zip->add_file($this->errors(), "Errors.txt");
134
+        }
135
+        $this->Zip->close_stream();
123 136
     }
124
-    $this->Zip->close_stream();
125
-  }
126 137
 
127
-  /**
128
-   * Produce a summary text over the collector results
129
-   *
130
-   * @param bool $FilterStats whether to include filter stats in the report
131
-   * @return summary text
132
-   */
133
-  public function summary($FilterStats) {
134
-    global $ScriptStartTime;
135
-    $Time = number_format(1000 * (microtime(true) - $ScriptStartTime), 2)." ms";
136
-    $Used = Format::get_size(memory_get_usage(true));
137
-    $Date = date("M d Y, H:i");
138
-    $NumSkipped = count($this->SkippedFiles);
139
-    return "Collector Download Summary for $this->Title - " . SITE_NAME . "\r\n"
138
+    /**
139
+     * Produce a summary text over the collector results
140
+     *
141
+     * @param bool $FilterStats whether to include filter stats in the report
142
+     * @return summary text
143
+     */
144
+    public function summary($FilterStats)
145
+    {
146
+        global $ScriptStartTime;
147
+        $Time = number_format(1000 * (microtime(true) - $ScriptStartTime), 2)." ms";
148
+        $Used = Format::get_size(memory_get_usage(true));
149
+        $Date = date("M d Y, H:i");
150
+        $NumSkipped = count($this->SkippedFiles);
151
+        return "Collector Download Summary for $this->Title - " . SITE_NAME . "\r\n"
140 152
       . "\r\n"
141 153
       . "User:    {$this->User[Username]}\r\n"
142 154
       . "Passkey: {$this->User[torrent_pass]}\r\n"
@@ -157,89 +169,92 @@ class TorrentsDL {
157 169
           . "Albums unavailable within your criteria (consider making a request for your desired format):\r\n"
158 170
           . implode("\r\n", $this->SkippedFiles) . "\r\n"
159 171
         : "");
160
-  }
172
+    }
161 173
 
162
-  /**
163
-   * Compile a list of files that could not be added to the archive
164
-   *
165
-   * @return list of files
166
-   */
167
-  public function errors() {
168
-    return "A server error occurred. Please try again at a later time.\r\n"
174
+    /**
175
+     * Compile a list of files that could not be added to the archive
176
+     *
177
+     * @return list of files
178
+     */
179
+    public function errors()
180
+    {
181
+        return "A server error occurred. Please try again at a later time.\r\n"
169 182
       . "\r\n"
170 183
       . "The following torrents could not be downloaded:\r\n"
171 184
       . implode("\r\n", $this->FailedFiles) . "\r\n";
172
-  }
173
-
174
-  /**
175
-   * Combine a bunch of torrent info into a standardized file name
176
-   *
177
-   * @params most input variables are self-explanatory
178
-   * @param int $TorrentID if given, append "-TorrentID" to torrent name
179
-   * @param int $MaxLength maximum file name length
180
-   * @return file name with at most $MaxLength characters
181
-   */
182
-  public static function construct_file_name($Artist, $Album, $Year, $Media, $Format, $Encoding, $TorrentID = false, $MaxLength = self::MaxPathLength) {
183
-    $MaxLength -= 8; // ".torrent"
184
-    if ($TorrentID !== false) {
185
-      $MaxLength -= (strlen($TorrentID) + 1);
186
-    }
187
-    $TorrentArtist = Misc::file_string($Artist);
188
-    $TorrentName = Misc::file_string($Album);
189
-    if ($Year > 0) {
190
-      $TorrentName .= " - $Year";
191
-    }
192
-    $TorrentInfo = [];
193
-    if ($Media != '') {
194
-      $TorrentInfo[] = $Media;
195
-    }
196
-    if ($Format != '') {
197
-      $TorrentInfo[] = $Format;
198
-    }
199
-    if ($Encoding != '') {
200
-      $TorrentInfo[] = $Encoding;
201
-    }
202
-    if (!empty($TorrentInfo)) {
203
-      $TorrentInfo = ' (' . Misc::file_string(implode(' - ', $TorrentInfo)) . ')';
204
-    } else {
205
-      $TorrentInfo = '';
206 185
     }
207 186
 
208
-    if (!$TorrentName) {
209
-      $TorrentName = 'No Name';
210
-    } elseif (mb_strlen($TorrentArtist . $TorrentName . $TorrentInfo, 'UTF-8') <= $MaxLength) {
211
-      $TorrentName = $TorrentArtist . $TorrentName;
212
-    }
187
+    /**
188
+     * Combine a bunch of torrent info into a standardized file name
189
+     *
190
+     * @params most input variables are self-explanatory
191
+     * @param int $TorrentID if given, append "-TorrentID" to torrent name
192
+     * @param int $MaxLength maximum file name length
193
+     * @return file name with at most $MaxLength characters
194
+     */
195
+    public static function construct_file_name($Artist, $Album, $Year, $Media, $Format, $Encoding, $TorrentID = false, $MaxLength = self::MaxPathLength)
196
+    {
197
+        $MaxLength -= 8; // ".torrent"
198
+        if ($TorrentID !== false) {
199
+            $MaxLength -= (strlen($TorrentID) + 1);
200
+        }
201
+        $TorrentArtist = Misc::file_string($Artist);
202
+        $TorrentName = Misc::file_string($Album);
203
+        if ($Year > 0) {
204
+            $TorrentName .= " - $Year";
205
+        }
206
+        $TorrentInfo = [];
207
+        if ($Media != '') {
208
+            $TorrentInfo[] = $Media;
209
+        }
210
+        if ($Format != '') {
211
+            $TorrentInfo[] = $Format;
212
+        }
213
+        if ($Encoding != '') {
214
+            $TorrentInfo[] = $Encoding;
215
+        }
216
+        if (!empty($TorrentInfo)) {
217
+            $TorrentInfo = ' (' . Misc::file_string(implode(' - ', $TorrentInfo)) . ')';
218
+        } else {
219
+            $TorrentInfo = '';
220
+        }
213 221
 
214
-    $TorrentName = Format::cut_string($TorrentName . $TorrentInfo, $MaxLength, true, false);
215
-    if ($TorrentID !== false) {
216
-      $TorrentName .= "-$TorrentID";
217
-    }
218
-    return "$TorrentName.torrent";
219
-  }
222
+        if (!$TorrentName) {
223
+            $TorrentName = 'No Name';
224
+        } elseif (mb_strlen($TorrentArtist . $TorrentName . $TorrentInfo, 'UTF-8') <= $MaxLength) {
225
+            $TorrentName = $TorrentArtist . $TorrentName;
226
+        }
220 227
 
221
-  /**
222
-   * Convert a stored torrent into a binary file that can be loaded in a torrent client
223
-   *
224
-   * @param mixed $TorrentData bencoded torrent without announce URL (new format) or TORRENT object (old format)
225
-   * @return bencoded string
226
-   */
227
-  public static function get_file(&$TorrentData, $AnnounceURL, $AnnounceList = []) {
228
-    if (Misc::is_new_torrent($TorrentData)) {
229
-      $Bencode = BencodeTorrent::add_announce_url($TorrentData, $AnnounceURL);
230
-      if (!empty($AnnounceList)) {
231
-        $Bencode = BencodeTorrent::add_announce_list($Bencode, $AnnounceList);
232
-      }
233
-      return $Bencode;
228
+        $TorrentName = Format::cut_string($TorrentName . $TorrentInfo, $MaxLength, true, false);
229
+        if ($TorrentID !== false) {
230
+            $TorrentName .= "-$TorrentID";
231
+        }
232
+        return "$TorrentName.torrent";
234 233
     }
235
-    $Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
236
-    $Tor->set_announce_url($AnnounceURL);
237
-    unset($Tor->Val['announce-list']);
238
-    if (!empty($AnnounceList)) {
239
-      $Tor->set_announce_list($AnnounceList);
234
+
235
+    /**
236
+     * Convert a stored torrent into a binary file that can be loaded in a torrent client
237
+     *
238
+     * @param mixed $TorrentData bencoded torrent without announce URL (new format) or TORRENT object (old format)
239
+     * @return bencoded string
240
+     */
241
+    public static function get_file(&$TorrentData, $AnnounceURL, $AnnounceList = [])
242
+    {
243
+        if (Misc::is_new_torrent($TorrentData)) {
244
+            $Bencode = BencodeTorrent::add_announce_url($TorrentData, $AnnounceURL);
245
+            if (!empty($AnnounceList)) {
246
+                $Bencode = BencodeTorrent::add_announce_list($Bencode, $AnnounceList);
247
+            }
248
+            return $Bencode;
249
+        }
250
+        $Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
251
+        $Tor->set_announce_url($AnnounceURL);
252
+        unset($Tor->Val['announce-list']);
253
+        if (!empty($AnnounceList)) {
254
+            $Tor->set_announce_list($AnnounceList);
255
+        }
256
+        unset($Tor->Val['url-list']);
257
+        unset($Tor->Val['libtorrent_resume']);
258
+        return $Tor->enc();
240 259
     }
241
-    unset($Tor->Val['url-list']);
242
-    unset($Tor->Val['libtorrent_resume']);
243
-    return $Tor->enc();
244
-  }
245 260
 }

+ 97
- 95
sections/torrents/download.php View File

@@ -1,38 +1,38 @@
1
-<?
1
+<?php
2 2
 if (!isset($_REQUEST['authkey']) || !isset($_REQUEST['torrent_pass'])) {
3
-  enforce_login();
4
-  $TorrentPass = $LoggedUser['torrent_pass'];
5
-  $UserID    = $LoggedUser['ID'];
6
-  $AuthKey   = $LoggedUser['AuthKey'];
3
+    enforce_login();
4
+    $TorrentPass = $LoggedUser['torrent_pass'];
5
+    $UserID    = $LoggedUser['ID'];
6
+    $AuthKey   = $LoggedUser['AuthKey'];
7 7
 } else {
8
-  if (strpos($_REQUEST['torrent_pass'], '_') !== false) {
9
-    error(404);
10
-  }
8
+    if (strpos($_REQUEST['torrent_pass'], '_') !== false) {
9
+        error(404);
10
+    }
11 11
 
12
-  $UserInfo = $Cache->get_value('user_'.$_REQUEST['torrent_pass']);
13
-  if (!is_array($UserInfo)) {
14
-    $DB->query("
12
+    $UserInfo = $Cache->get_value('user_'.$_REQUEST['torrent_pass']);
13
+    if (!is_array($UserInfo)) {
14
+        $DB->query("
15 15
       SELECT ID, la.UserID
16 16
       FROM users_main AS m
17 17
         INNER JOIN users_info AS i ON i.UserID = m.ID
18 18
         LEFT JOIN locked_accounts AS la ON la.UserID = m.ID
19 19
       WHERE m.torrent_pass = '".db_string($_REQUEST['torrent_pass'])."'
20 20
         AND m.Enabled = '1'");
21
-    $UserInfo = $DB->next_record();
22
-    $Cache->cache_value('user_'.$_REQUEST['torrent_pass'], $UserInfo, 3600);
23
-  }
24
-  $UserInfo = array($UserInfo);
25
-  list($UserID, $Locked) = array_shift($UserInfo);
26
-  if (!$UserID) {
27
-    error(0);
28
-  }
29
-  $TorrentPass = $_REQUEST['torrent_pass'];
30
-  $AuthKey = $_REQUEST['authkey'];
31
-
32
-  if ($Locked == $UserID) {
33
-    header('HTTP/1.1 403 Forbidden');
34
-    die();
35
-  }
21
+        $UserInfo = $DB->next_record();
22
+        $Cache->cache_value('user_'.$_REQUEST['torrent_pass'], $UserInfo, 3600);
23
+    }
24
+    $UserInfo = array($UserInfo);
25
+    list($UserID, $Locked) = array_shift($UserInfo);
26
+    if (!$UserID) {
27
+        error(0);
28
+    }
29
+    $TorrentPass = $_REQUEST['torrent_pass'];
30
+    $AuthKey = $_REQUEST['authkey'];
31
+
32
+    if ($Locked == $UserID) {
33
+        header('HTTP/1.1 403 Forbidden');
34
+        die();
35
+    }
36 36
 }
37 37
 
38 38
 $TorrentID = $_REQUEST['id'];
@@ -40,7 +40,7 @@ $TorrentID = $_REQUEST['id'];
40 40
 
41 41
 
42 42
 if (!is_number($TorrentID)) {
43
-  error(0);
43
+    error(0);
44 44
 }
45 45
 
46 46
 /* uTorrent Remote and various scripts redownload .torrent files periodically.
@@ -48,21 +48,21 @@ if (!is_number($TorrentID)) {
48 48
   if the .torrent file has been downloaded four times before */
49 49
 $ScriptUAs = array('BTWebClient*', 'Python-urllib*', 'python-requests*');
50 50
 if (Misc::in_array_partial($_SERVER['HTTP_USER_AGENT'], $ScriptUAs)) {
51
-  $DB->query("
51
+    $DB->query("
52 52
     SELECT 1
53 53
     FROM users_downloads
54 54
     WHERE UserID = $UserID
55 55
       AND TorrentID = $TorrentID
56 56
     LIMIT 4");
57
-  if ($DB->record_count() === 4) {
58
-    error('You have already downloaded this torrent file four times. If you need to download it again, please do so from your browser.', true);
59
-    die();
60
-  }
57
+    if ($DB->record_count() === 4) {
58
+        error('You have already downloaded this torrent file four times. If you need to download it again, please do so from your browser.', true);
59
+        die();
60
+    }
61 61
 }
62 62
 
63 63
 $Info = $Cache->get_value('torrent_download_'.$TorrentID);
64 64
 if (!is_array($Info) || !array_key_exists('PlainArtists', $Info) || empty($Info[10])) {
65
-  $DB->query("
65
+    $DB->query("
66 66
     SELECT
67 67
       t.Media,
68 68
       t.AudioFormat,
@@ -78,17 +78,17 @@ if (!is_array($Info) || !array_key_exists('PlainArtists', $Info) || empty($Info[
78 78
     FROM torrents AS t
79 79
       INNER JOIN torrents_group AS tg ON tg.ID = t.GroupID
80 80
     WHERE t.ID = '".db_string($TorrentID)."'");
81
-  if (!$DB->has_results()) {
82
-    error(404);
83
-  }
84
-  $Info = array($DB->next_record(MYSQLI_NUM, array(4, 5, 6, 10)));
85
-  $Artists = Artists::get_artist($Info[0][4], false);
86
-  $Info['Artists'] = Artists::display_artists($Artists, false, true);
87
-  $Info['PlainArtists'] = Artists::display_artists($Artists, false, true, false);
88
-  $Cache->cache_value("torrent_download_$TorrentID", $Info, 0);
81
+    if (!$DB->has_results()) {
82
+        error(404);
83
+    }
84
+    $Info = array($DB->next_record(MYSQLI_NUM, array(4, 5, 6, 10)));
85
+    $Artists = Artists::get_artist($Info[0][4], false);
86
+    $Info['Artists'] = Artists::display_artists($Artists, false, true);
87
+    $Info['PlainArtists'] = Artists::display_artists($Artists, false, true, false);
88
+    $Cache->cache_value("torrent_download_$TorrentID", $Info, 0);
89 89
 }
90 90
 if (!is_array($Info[0])) {
91
-  error(404);
91
+    error(404);
92 92
 }
93 93
 list($Media, $Format, $Encoding, $Year, $GroupID, $Name, $Image, $CategoryID, $Size, $FreeTorrent, $InfoHash) = array_shift($Info); // used for generating the filename
94 94
 $Artists = $Info['Artists'];
@@ -96,80 +96,79 @@ $Artists = $Info['Artists'];
96 96
 // If he's trying use a token on this, we need to make sure he has one,
97 97
 // deduct it, add this to the FLs table, and update his cache key.
98 98
 if ($_REQUEST['usetoken'] && $FreeTorrent == '0') {
99
-  if (isset($LoggedUser)) {
100
-    $FLTokens = $LoggedUser['FLTokens'];
101
-    if ($LoggedUser['CanLeech'] != '1') {
102
-      error('You cannot use tokens while leech disabled.');
103
-    }
104
-  }
105
-  else {
106
-    $UInfo = Users::user_heavy_info($UserID);
107
-    if ($UInfo['CanLeech'] != '1') {
108
-      error('You may not use tokens while leech disabled.');
99
+    if (isset($LoggedUser)) {
100
+        $FLTokens = $LoggedUser['FLTokens'];
101
+        if ($LoggedUser['CanLeech'] != '1') {
102
+            error('You cannot use tokens while leech disabled.');
103
+        }
104
+    } else {
105
+        $UInfo = Users::user_heavy_info($UserID);
106
+        if ($UInfo['CanLeech'] != '1') {
107
+            error('You may not use tokens while leech disabled.');
108
+        }
109
+        $FLTokens = $UInfo['FLTokens'];
109 110
     }
110
-    $FLTokens = $UInfo['FLTokens'];
111
-  }
112 111
 
113
-  // First make sure this isn't already FL, and if it is, do nothing
114
-
115
-  if (!Torrents::has_token($TorrentID)) {
116
-    if ($FLTokens <= 0) {
117
-      error('You do not have any freeleech tokens left. Please use the regular DL link.');
118
-    }
119
-    if ($Size >= 10737418240) {
120
-      error('This torrent is too large. Please use the regular DL link.');
121
-    }
122
-
123
-    // Let the tracker know about this
124
-    if (!Tracker::update_tracker('add_token', ['info_hash' => substr('%'.chunk_split($InfoHash,2,'%'),0,-1), 'userid' => $UserID])) {
125
-      error('Sorry! An error occurred while trying to register your token. Most often, this is due to the tracker being down or under heavy load. Please try again later.');
126
-    }
112
+    // First make sure this isn't already FL, and if it is, do nothing
127 113
 
128 114
     if (!Torrents::has_token($TorrentID)) {
129
-      $DB->query("
115
+        if ($FLTokens <= 0) {
116
+            error('You do not have any freeleech tokens left. Please use the regular DL link.');
117
+        }
118
+        if ($Size >= 10737418240) {
119
+            error('This torrent is too large. Please use the regular DL link.');
120
+        }
121
+
122
+        // Let the tracker know about this
123
+        if (!Tracker::update_tracker('add_token', ['info_hash' => substr('%'.chunk_split($InfoHash, 2, '%'), 0, -1), 'userid' => $UserID])) {
124
+            error('Sorry! An error occurred while trying to register your token. Most often, this is due to the tracker being down or under heavy load. Please try again later.');
125
+        }
126
+
127
+        if (!Torrents::has_token($TorrentID)) {
128
+            $DB->query("
130 129
         INSERT INTO users_freeleeches (UserID, TorrentID, Time)
131 130
         VALUES ($UserID, $TorrentID, NOW())
132 131
         ON DUPLICATE KEY UPDATE
133 132
           Time = VALUES(Time),
134 133
           Expired = FALSE,
135 134
           Uses = Uses + 1");
136
-      $DB->query("
135
+            $DB->query("
137 136
         UPDATE users_main
138 137
         SET FLTokens = FLTokens - 1
139 138
         WHERE ID = $UserID");
140 139
 
141
-      // Fix for downloadthemall messing with the cached token count
142
-      $UInfo = Users::user_heavy_info($UserID);
143
-      $FLTokens = $UInfo['FLTokens'];
140
+            // Fix for downloadthemall messing with the cached token count
141
+            $UInfo = Users::user_heavy_info($UserID);
142
+            $FLTokens = $UInfo['FLTokens'];
144 143
 
145
-      $Cache->begin_transaction("user_info_heavy_$UserID");
146
-      $Cache->update_row(false, array('FLTokens' => ($FLTokens - 1)));
147
-      $Cache->commit_transaction(0);
144
+            $Cache->begin_transaction("user_info_heavy_$UserID");
145
+            $Cache->update_row(false, array('FLTokens' => ($FLTokens - 1)));
146
+            $Cache->commit_transaction(0);
148 147
 
149
-      $Cache->delete_value("users_tokens_$UserID");
148
+            $Cache->delete_value("users_tokens_$UserID");
149
+        }
150 150
     }
151
-  }
152 151
 }
153 152
 
154 153
 //Stupid Recent Snatches On User Page
155 154
 if ($Image != '') {
156
-  $RecentSnatches = $Cache->get_value("recent_snatches_$UserID");
157
-  if (!empty($RecentSnatches)) {
158
-    $Snatch = array(
155
+    $RecentSnatches = $Cache->get_value("recent_snatches_$UserID");
156
+    if (!empty($RecentSnatches)) {
157
+        $Snatch = array(
159 158
         'ID' => $GroupID,
160 159
         'Name' => $Name,
161 160
         'Artist' => $Artists,
162 161
         'WikiImage' => $Image);
163
-    if (!in_array($Snatch, $RecentSnatches)) {
164
-      if (count($RecentSnatches) === 5) {
165
-        array_pop($RecentSnatches);
166
-      }
167
-      array_unshift($RecentSnatches, $Snatch);
168
-    } elseif (!is_array($RecentSnatches)) {
169
-      $RecentSnatches = array($Snatch);
162
+        if (!in_array($Snatch, $RecentSnatches)) {
163
+            if (count($RecentSnatches) === 5) {
164
+                array_pop($RecentSnatches);
165
+            }
166
+            array_unshift($RecentSnatches, $Snatch);
167
+        } elseif (!is_array($RecentSnatches)) {
168
+            $RecentSnatches = array($Snatch);
169
+        }
170
+        $Cache->cache_value("recent_snatches_$UserID", $RecentSnatches, 0);
170 171
     }
171
-    $Cache->cache_value("recent_snatches_$UserID", $RecentSnatches, 0);
172
-  }
173 172
 }
174 173
 
175 174
 $DB->query("
@@ -183,12 +182,15 @@ $FileName = TorrentsDL::construct_file_name($Info['PlainArtists'], $Name, $Year,
183 182
 header('Content-Type: application/x-bittorrent; charset=utf-8');
184 183
 header('Content-disposition: attachment; filename="'.$FileName.'"');
185 184
 
186
-function add_passkey($ann) {
187
-  global $TorrentPass;
188
-  return (is_array($ann)) ? array_map("add_passkey", $ann) : $ann."/".$TorrentPass."/announce";
185
+function add_passkey($Ann)
186
+{
187
+    global $TorrentPass;
188
+    return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann.'/'.$TorrentPass.'/announce';
189 189
 }
190
-$UserAnnounceURL = ANNOUNCE_URLS[0][0]."/".$TorrentPass."/announce";
191
-$UserAnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map("add_passkey", ANNOUNCE_URLS);
190
+
191
+$UserAnnounceURL = ANNOUNCE_URLS[0][0].'/'.$TorrentPass.'/announce';
192
+$UserAnnounceList = array(array_map('add_passkey', ANNOUNCE_URLS[0]), ANNOUNCE_URLS[1]);
193
+#$UserAnnounceList = (sizeof(ANNOUNCE_URLS) === 1 && sizeof(ANNOUNCE_URLS[0]) === 1) ? [] : array_map('add_passkey', ANNOUNCE_URLS);
192 194
 
193 195
 echo TorrentsDL::get_file($Contents, $UserAnnounceURL, $UserAnnounceList);
194 196
 

Loading…
Cancel
Save