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

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

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

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

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

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
-<?
1
+<?php
2
 /*******************************************************************************
2
 /*******************************************************************************
3
 |~~~~ Gazelle bencode parser                         ~~~~|
3
 |~~~~ Gazelle bencode parser                         ~~~~|
4
 --------------------------------------------------------------------------------
4
 --------------------------------------------------------------------------------
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
     public $ContainersProt = [];
16
     public $ContainersProt = [];
17
     public $Codecs = [];
17
     public $Codecs = [];
18
     public $Resolutions = [];
18
     public $Resolutions = [];
19
-    var $AudioFormats = [];
19
+    public $AudioFormats = [];
20
     #var $Subbing = [];
20
     #var $Subbing = [];
21
     #var $Languages = [];
21
     #var $Languages = [];
22
     #var $Platform = [];
22
     #var $Platform = [];
82
 
82
 
83
   <p style="text-align: center;">
83
   <p style="text-align: center;">
84
     <?php
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
     <strong>Announce</strong>
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
     <input type="text"
91
     <input type="text"
96
       value="<?= $Announce . '/' . G::$LoggedUser['torrent_pass'] . '/announce' ?>"
92
       value="<?= $Announce . '/' . G::$LoggedUser['torrent_pass'] . '/announce' ?>"
97
       size="74" onclick="this.select();" readonly="readonly" /> <br />
93
       size="74" onclick="this.select();" readonly="readonly" /> <br />
98
     <?php
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
     <strong>Source</strong>
98
     <strong>Source</strong>
107
     <input type="text" value="<?= Users::get_upload_sources()[0] ?>"
99
     <input type="text" value="<?= Users::get_upload_sources()[0] ?>"
156
 
148
 
157
       <tr>
149
       <tr>
158
         <td class="label">
150
         <td class="label">
159
-        Torrent File
160
-        <strong class="important_text">*</strong>
151
+          Torrent File
152
+          <strong class="important_text">*</strong>
161
         </td>
153
         </td>
162
         <td><input id="file" type="file" name="file_input" size="50" /><br />
154
         <td><input id="file" type="file" name="file_input" size="50" /><br />
163
           Use the above announce URL and set the private flag in your BitTorrent client, e.g.,
155
           Use the above announce URL and set the private flag in your BitTorrent client, e.g.,
167
 
159
 
168
       <tr>
160
       <tr>
169
         <td class="label">
161
         <td class="label">
170
-        Category
171
-        <strong class="important_text">*</strong>
162
+          Category
163
+          <strong class="important_text">*</strong>
172
         </td>
164
         </td>
173
         <td>
165
         <td>
174
           <select id="categories" name="type" onchange="Categories()" <?= ($this->DisabledFlag) ? ' disabled="disabled"' : '' ?>>
166
           <select id="categories" name="type" onchange="Categories()" <?= ($this->DisabledFlag) ? ' disabled="disabled"' : '' ?>>
318
   </tr>
310
   </tr>
319
 
311
 
320
   <!-- Semantic Versioning -->
312
   <!-- Semantic Versioning -->
321
-    <tr id="audio_tr">
313
+  <tr id="audio_tr">
322
     <td class="label">Version</td>
314
     <td class="label">Version</td>
323
     <td>
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
         <?= $this->Disabled ?>/><br />
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
     </td>
320
     </td>
329
   </tr>
321
   </tr>
330
 
322
 
465
     </td>
457
     </td>
466
     <td>
458
     <td>
467
       <select name="media">
459
       <select name="media">
468
-      <option value="">---</option>
460
+        <option value="">---</option>
469
         <?php
461
         <?php
470
           foreach ($this->Media as $Media) {
462
           foreach ($this->Media as $Media) {
471
               echo "\t\t\t\t\t\t<option value=\"$Media\"";
463
               echo "\t\t\t\t\t\t<option value=\"$Media\"";
545
     </td>
537
     </td>
546
     <td>
538
     <td>
547
       <select name="container">
539
       <select name="container">
548
-      <option value="">---</option>
540
+        <option value="">---</option>
549
         <?php
541
         <?php
550
           foreach ($this->Containers as $Name => $Container) {
542
           foreach ($this->Containers as $Name => $Container) {
551
               echo "<option value='$Name'>$Name</option>\n";
543
               echo "<option value='$Name'>$Name</option>\n";
563
     </td>
555
     </td>
564
     <td>
556
     <td>
565
       <select id="container" name="container">
557
       <select id="container" name="container">
566
-      <option value="">---</option>
558
+        <option value="">---</option>
567
         <?php
559
         <?php
568
           foreach ($this->ContainersGames as $Name => $Container) {
560
           foreach ($this->ContainersGames as $Name => $Container) {
569
               echo "<option value='$Name'>$Name</option>\n";
561
               echo "<option value='$Name'>$Name</option>\n";
581
     </td>
573
     </td>
582
     <td>
574
     <td>
583
       <select id="container" name="container">
575
       <select id="container" name="container">
584
-      <option value="">---</option>
576
+        <option value="">---</option>
585
         <?php
577
         <?php
586
           foreach ($this->ContainersProt as $Name => $Container) {
578
           foreach ($this->ContainersProt as $Name => $Container) {
587
               echo "<option value='$Name'>$Name</option>\n";
579
               echo "<option value='$Name'>$Name</option>\n";
599
     </td>
591
     </td>
600
     <td>
592
     <td>
601
       <select name='archive'>
593
       <select name='archive'>
602
-      <option value="">---</option>
594
+        <option value="">---</option>
603
         <?php
595
         <?php
604
           foreach ($this->Archives as $Name => $Archive) {
596
           foreach ($this->Archives as $Name => $Archive) {
605
               echo "\t\t\t\t\t\t<option value=\"$Name\"";
597
               echo "\t\t\t\t\t\t<option value=\"$Name\"";

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

1
-<?
1
+<?php
2
 /**
2
 /**
3
  * Class for functions related to the features involving torrent downloads
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
       . "\r\n"
152
       . "\r\n"
141
       . "User:    {$this->User[Username]}\r\n"
153
       . "User:    {$this->User[Username]}\r\n"
142
       . "Passkey: {$this->User[torrent_pass]}\r\n"
154
       . "Passkey: {$this->User[torrent_pass]}\r\n"
157
           . "Albums unavailable within your criteria (consider making a request for your desired format):\r\n"
169
           . "Albums unavailable within your criteria (consider making a request for your desired format):\r\n"
158
           . implode("\r\n", $this->SkippedFiles) . "\r\n"
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
       . "\r\n"
182
       . "\r\n"
170
       . "The following torrents could not be downloaded:\r\n"
183
       . "The following torrents could not be downloaded:\r\n"
171
       . implode("\r\n", $this->FailedFiles) . "\r\n";
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
-<?
1
+<?php
2
 if (!isset($_REQUEST['authkey']) || !isset($_REQUEST['torrent_pass'])) {
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
 } else {
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
       SELECT ID, la.UserID
15
       SELECT ID, la.UserID
16
       FROM users_main AS m
16
       FROM users_main AS m
17
         INNER JOIN users_info AS i ON i.UserID = m.ID
17
         INNER JOIN users_info AS i ON i.UserID = m.ID
18
         LEFT JOIN locked_accounts AS la ON la.UserID = m.ID
18
         LEFT JOIN locked_accounts AS la ON la.UserID = m.ID
19
       WHERE m.torrent_pass = '".db_string($_REQUEST['torrent_pass'])."'
19
       WHERE m.torrent_pass = '".db_string($_REQUEST['torrent_pass'])."'
20
         AND m.Enabled = '1'");
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
 $TorrentID = $_REQUEST['id'];
38
 $TorrentID = $_REQUEST['id'];
40
 
40
 
41
 
41
 
42
 if (!is_number($TorrentID)) {
42
 if (!is_number($TorrentID)) {
43
-  error(0);
43
+    error(0);
44
 }
44
 }
45
 
45
 
46
 /* uTorrent Remote and various scripts redownload .torrent files periodically.
46
 /* uTorrent Remote and various scripts redownload .torrent files periodically.
48
   if the .torrent file has been downloaded four times before */
48
   if the .torrent file has been downloaded four times before */
49
 $ScriptUAs = array('BTWebClient*', 'Python-urllib*', 'python-requests*');
49
 $ScriptUAs = array('BTWebClient*', 'Python-urllib*', 'python-requests*');
50
 if (Misc::in_array_partial($_SERVER['HTTP_USER_AGENT'], $ScriptUAs)) {
50
 if (Misc::in_array_partial($_SERVER['HTTP_USER_AGENT'], $ScriptUAs)) {
51
-  $DB->query("
51
+    $DB->query("
52
     SELECT 1
52
     SELECT 1
53
     FROM users_downloads
53
     FROM users_downloads
54
     WHERE UserID = $UserID
54
     WHERE UserID = $UserID
55
       AND TorrentID = $TorrentID
55
       AND TorrentID = $TorrentID
56
     LIMIT 4");
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
 $Info = $Cache->get_value('torrent_download_'.$TorrentID);
63
 $Info = $Cache->get_value('torrent_download_'.$TorrentID);
64
 if (!is_array($Info) || !array_key_exists('PlainArtists', $Info) || empty($Info[10])) {
64
 if (!is_array($Info) || !array_key_exists('PlainArtists', $Info) || empty($Info[10])) {
65
-  $DB->query("
65
+    $DB->query("
66
     SELECT
66
     SELECT
67
       t.Media,
67
       t.Media,
68
       t.AudioFormat,
68
       t.AudioFormat,
78
     FROM torrents AS t
78
     FROM torrents AS t
79
       INNER JOIN torrents_group AS tg ON tg.ID = t.GroupID
79
       INNER JOIN torrents_group AS tg ON tg.ID = t.GroupID
80
     WHERE t.ID = '".db_string($TorrentID)."'");
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
 if (!is_array($Info[0])) {
90
 if (!is_array($Info[0])) {
91
-  error(404);
91
+    error(404);
92
 }
92
 }
93
 list($Media, $Format, $Encoding, $Year, $GroupID, $Name, $Image, $CategoryID, $Size, $FreeTorrent, $InfoHash) = array_shift($Info); // used for generating the filename
93
 list($Media, $Format, $Encoding, $Year, $GroupID, $Name, $Image, $CategoryID, $Size, $FreeTorrent, $InfoHash) = array_shift($Info); // used for generating the filename
94
 $Artists = $Info['Artists'];
94
 $Artists = $Info['Artists'];
96
 // If he's trying use a token on this, we need to make sure he has one,
96
 // If he's trying use a token on this, we need to make sure he has one,
97
 // deduct it, add this to the FLs table, and update his cache key.
97
 // deduct it, add this to the FLs table, and update his cache key.
98
 if ($_REQUEST['usetoken'] && $FreeTorrent == '0') {
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
     if (!Torrents::has_token($TorrentID)) {
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
         INSERT INTO users_freeleeches (UserID, TorrentID, Time)
129
         INSERT INTO users_freeleeches (UserID, TorrentID, Time)
131
         VALUES ($UserID, $TorrentID, NOW())
130
         VALUES ($UserID, $TorrentID, NOW())
132
         ON DUPLICATE KEY UPDATE
131
         ON DUPLICATE KEY UPDATE
133
           Time = VALUES(Time),
132
           Time = VALUES(Time),
134
           Expired = FALSE,
133
           Expired = FALSE,
135
           Uses = Uses + 1");
134
           Uses = Uses + 1");
136
-      $DB->query("
135
+            $DB->query("
137
         UPDATE users_main
136
         UPDATE users_main
138
         SET FLTokens = FLTokens - 1
137
         SET FLTokens = FLTokens - 1
139
         WHERE ID = $UserID");
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
 //Stupid Recent Snatches On User Page
153
 //Stupid Recent Snatches On User Page
155
 if ($Image != '') {
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
         'ID' => $GroupID,
158
         'ID' => $GroupID,
160
         'Name' => $Name,
159
         'Name' => $Name,
161
         'Artist' => $Artists,
160
         'Artist' => $Artists,
162
         'WikiImage' => $Image);
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
 $DB->query("
174
 $DB->query("
183
 header('Content-Type: application/x-bittorrent; charset=utf-8');
182
 header('Content-Type: application/x-bittorrent; charset=utf-8');
184
 header('Content-disposition: attachment; filename="'.$FileName.'"');
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
 echo TorrentsDL::get_file($Contents, $UserAnnounceURL, $UserAnnounceList);
195
 echo TorrentsDL::get_file($Contents, $UserAnnounceURL, $UserAnnounceList);
194
 
196
 

Loading…
Cancel
Save