4 Commits

Author SHA1 Message Date
  biotorrents 72cb2e0792 Add OPS's prepared_query() SQL method 4 years ago
  biotorrents 63fe3124b5 Further integrate Skeleton and fix a large swath of minor bugs 4 years ago
  biotorrents 1530171f7b Add Skeleton CSS support, mostly 4 years ago
  biotorrents f397d945f4 Add $ENV->convert, update readme and config template, add more Twig templates, etc. 4 years ago
84 changed files with 1825 additions and 3003 deletions
  1. 1
    0
      .gitignore
  2. 5
    16
      classes/autoload.php
  3. 0
    63
      classes/charts.class.php
  4. 32
    24
      classes/config.template.php
  5. 46
    39
      classes/env.class.php
  6. 0
    44
      classes/input.class.php
  7. 34
    8
      classes/mysql.class.php
  8. 26
    6
      classes/security.class.php
  9. 0
    360
      classes/seqhash.class.php
  10. 67
    63
      classes/torrent_form.class.php
  11. 6
    3
      classes/twig.class.php
  12. 11
    3
      classes/util.php
  13. 17
    15
      composer.json
  14. 178
    38
      composer.lock
  15. 1
    1
      design/privatefooter.php
  16. 1
    0
      design/privateheader.php
  17. 1
    0
      design/publicfooter.php
  18. 4
    1
      design/publicheader.php
  19. 1
    1
      design/views/generic/reply/quickreply.php
  20. 1
    1
      design/views/generic/reply/staffpm.php
  21. 39
    20
      readme.md
  22. 22
    4
      sections/api/autofill/doi.php
  23. 1
    0
      sections/api/index.php
  24. 4
    4
      sections/better/better.php
  25. 3
    3
      sections/better/index.php
  26. 24
    25
      sections/better/literature.php
  27. 9
    9
      sections/better/single.php
  28. 15
    13
      sections/bookmarks/torrents.php
  29. 2
    2
      sections/collages/browse.php
  30. 2
    2
      sections/collages/edit.php
  31. 1
    1
      sections/collages/new.php
  32. 6
    11
      sections/collages/torrent_collage.php
  33. 113
    64
      sections/comments/comments.php
  34. 11
    2
      sections/comments/index.php
  35. 15
    1
      sections/donate/donate.php
  36. 2
    2
      sections/forums/newthread.php
  37. 47
    36
      sections/friends/friends.php
  38. 7
    2
      sections/inbox/inbox.php
  39. 25
    7
      sections/login/login.php
  40. 14
    11
      sections/login/recover_step2.php
  41. 2
    1
      sections/register/step1.php
  42. 12
    11
      sections/reportsv2/report.php
  43. 3
    4
      sections/reportsv2/takereport.php
  44. 2
    2
      sections/requests/new_edit.php
  45. 7
    7
      sections/requests/request.php
  46. 19
    19
      sections/requests/requests.php
  47. 1
    1
      sections/rules/clients.php
  48. 9
    9
      sections/tools/tools.php
  49. 1
    1
      sections/top10/donors.php
  50. 1
    1
      sections/top10/tags.php
  51. 1
    1
      sections/top10/torrents.php
  52. 1
    1
      sections/top10/users.php
  53. 13
    5
      sections/torrents/browse.php
  54. 10
    10
      sections/torrents/details.php
  55. 78
    78
      sections/torrents/user.php
  56. 2
    2
      sections/upload/index.php
  57. 21
    17
      sections/user/notify_edit.php
  58. 2
    2
      sections/user/user.php
  59. 59
    55
      sections/userhistory/subscriptions.php
  60. 1
    1
      sections/wiki/article.php
  61. 1
    1
      sections/wiki/wiki_browse.php
  62. BIN
      static/common/logos/torrents.bio.png
  63. 254
    217
      static/functions/upload.js
  64. 0
    23
      static/functions/vendor/biojs/cytoscape.js
  65. 0
    1335
      static/functions/vendor/biojs/ntseq.js
  66. 30
    72
      static/styles/bookish/scss/colors.scss
  67. 11
    2
      static/styles/bookish/scss/fonts.scss
  68. 20
    72
      static/styles/bookish/scss/layout.scss
  69. 11
    10
      static/styles/bookish/scss/menus.scss
  70. 65
    76
      static/styles/bookish/scss/tables.scss
  71. 1
    0
      static/styles/global/global.scss
  72. 1
    1
      static/styles/global/scss/debug.scss
  73. 0
    1
      static/styles/global/scss/fonts.scss
  74. 28
    0
      static/styles/global/scss/layout.scss
  75. 20
    0
      static/styles/global/scss/legacy.scss
  76. 162
    0
      static/styles/global/scss/skeleton-fixes.scss
  77. 19
    9
      static/styles/public/scss/public.scss
  78. 24
    0
      templates/input/passphrase.html
  79. 14
    0
      templates/torrent_form/mirrors.html
  80. 16
    0
      templates/torrent_form/picture.html
  81. 54
    0
      templates/torrent_form/seqhash.html
  82. 2
    2
      templates/torrent_form/version.html
  83. 53
    0
      templates/wiki/browse.html
  84. 0
    49
      templates/wiki/browse.twig

+ 1
- 0
.gitignore View File

@@ -33,3 +33,4 @@ __MACOSX/
33 33
 /static/common/badges/**
34 34
 /static/styles/**/*.css
35 35
 /static/styles/assets/fonts/**
36
+fonts.tgz

+ 5
- 16
classes/autoload.php View File

@@ -11,8 +11,10 @@ declare(strict_types=1);
11 11
  * @see https://www.php.net/manual/en/language.oop5.autoload.php
12 12
  */
13 13
 spl_autoload_register(function ($ClassName) {
14
-    $FilePath = SERVER_ROOT . '/classes/' . strtolower($ClassName) . '.class.php';
15
-    #$FilePath = $_SERVER['DOCUMENT_ROOT'] . '/classes/' . strtolower($ClassName) . '.class.php';
14
+  $ENV = ENV::go();
15
+
16
+  $classname = strtolower($ClassName);
17
+    $FilePath = "$ENV->SERVER_ROOT/classes/$classname.class.php";
16 18
 
17 19
     if (!file_exists($FilePath)) {
18 20
         // todo: Rename the following classes to conform with the code guidelines
@@ -43,24 +45,11 @@ spl_autoload_register(function ($ClassName) {
43 45
           $FileName = 'env.class';
44 46
           break;
45 47
 
46
-        case 'Parsedown':
47
-          $FileName = 'vendor/Parsedown';
48
-          break;
49
-
50
-        case 'ParsedownExtra':
51
-          $FileName = 'vendor/ParsedownExtra';
52
-          break;
53
-
54
-        case 'TwitterAPIExchange':
55
-          $FileName = 'vendor/TwitterAPIExchange';
56
-          break;
57
-
58 48
         default:
59 49
           error("Couldn't import class $ClassName");
60 50
     }
61 51
 
62
-        $FilePath = SERVER_ROOT . "/classes/$FileName.php";
63
-        #$FilePath = $_SERVER['DOCUMENT_ROOT'] . "/classes/$FileName.php";
52
+        $FilePath = "$ENV->SERVER_ROOT/classes/$FileName.php";
64 53
     }
65 54
 
66 55
     require_once $FilePath;

+ 0
- 63
classes/charts.class.php View File

@@ -168,66 +168,3 @@ class PIE_CHART extends GOOGLE_CHARTS
168 168
         $this->URL .= "&chl=".implode('|', $Labels).'&chd=e:'.implode('', $Data);
169 169
     }
170 170
 }
171
-
172
-/*
173
-class LOG_BAR_GRAPH extends GOOGLE_CHARTS
174
-{
175
-    // todo: Finish
176
-    public function __construct($Base, $Width, $Height, $Options = [])
177
-    {
178
-        parent::__construct('lc', $Width, $Height, $Options);
179
-    }
180
-
181
-    public function color($Color)
182
-    {
183
-        $this->URL .= '&chco='.$Color.'&chm=B,'.$Color.'50,0,0,0';
184
-    }
185
-
186
-    public function generate()
187
-    {
188
-        $Max = max($this->Data);
189
-        $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
190
-        $Data = [];
191
-
192
-        foreach ($this->Data as $Value) {
193
-            $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
194
-        }
195
-        $this->URL .= "&chxt=y,x&chxs=0,h&chxl=1:|".implode('|', $this->Labels).'&chxr=0,'.$Min.','.($Max-$Min).'&chd=e:'.implode('', $Data);
196
-    }
197
-}
198
-*/
199
-
200
-/*
201
-class POLL_GRAPH extends GOOGLE_CHARTS
202
-{
203
-    public function __construct()
204
-    {
205
-        $this->URL .= '?cht=bhg';
206
-    }
207
-
208
-    public function add($Label, $Data)
209
-    {
210
-        if ($Label !== false) {
211
-            $this->Labels[] = Format::cut_string($Label, 35);
212
-        }
213
-        $this->Data[] = $Data;
214
-    }
215
-
216
-    public function generate()
217
-    {
218
-        $Count = count($this->Data);
219
-        $Height = (30 * $Count) + 20;
220
-        $Max = max($this->Data);
221
-        $Sum = array_sum($this->Data);
222
-        $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
223
-        $Data = [];
224
-        $Labels = [];
225
-
226
-        foreach ($this->Data as $Key => $Value) {
227
-            $Data[] = $this->encode(($Value / $Max) * 4095);
228
-            $Labels[] = '@t'.str_replace(array(' ', ','), array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';
229
-        }
230
-        $this->URL .= "&chbh=25,0,5&chs=214x$Height&chl=0%|".round($Increment, 1)."%|".round($Increment * 2, 1)."%|".round($Increment * 3, 1)."%|".round($Increment * 4, 1)."%&chm=".implode('|', $Labels).'&chd=e:'.implode('', $Data);
231
-    }
232
-}
233
-*/

+ 32
- 24
classes/config.template.php View File

@@ -1,3 +1,4 @@
1
+
1 2
 <?php
2 3
 declare(strict_types=1);
3 4
 
@@ -19,7 +20,7 @@ declare(strict_types=1);
19 20
  *   $LongArray = [];
20 21
  *   ENV::setPub(
21 22
  *     'CONFIG',
22
- *     new RecursiveArrayObject($LongArray)
23
+ *     $ENV->convert($LongArray)
23 24
  *   );
24 25
  *
25 26
  *   $ENV = ENV::go();
@@ -32,9 +33,8 @@ declare(strict_types=1);
32 33
  *
33 34
  *   var_dump(
34 35
  *     $ENV->dedupe(
35
- *       $ENV->CATS->SEQ->Platforms,
36
- *       $ENV->CATS->IMG->Platforms->toArray(),
37
- *       [$MapVectorFormats, $MapRasterFormats, $PlainFormats]
36
+ *       $ENV->META->Formats->Sequences,
37
+ *       $ENV->META->Formats->Proteins->toArray()
38 38
  *     )
39 39
  *   );
40 40
  */
@@ -42,6 +42,8 @@ declare(strict_types=1);
42 42
 # Initialize
43 43
 require_once 'env.class.php';
44 44
 $ENV = ENV::go();
45
+
46
+# Basic info
45 47
 ENV::setPub('PHP_MIN', '7.4.0');
46 48
 ENV::setPub('DEV', true);
47 49
 
@@ -132,7 +134,7 @@ $TechSupport = [
132 134
 ];
133 135
 ENV::setPub(
134 136
     'HELP',
135
-    new RecursiveArrayObject($TechSupport)
137
+    $ENV->convert($TechSupport)
136 138
 );
137 139
 
138 140
 
@@ -180,9 +182,9 @@ ENV::setPriv('SQLPORT', 3306);
180 182
 #ENV::setPriv('SQLSOCK', '/var/run/mysqld/mysqld.sock');
181 183
 
182 184
 # TLS client certs
183
-ENV::setPriv('SQL_CERT', "/var/www/sql-keys/client-cert.pem");
184
-ENV::setPriv('SQL_KEY', "/var/www/sql-keys/client-key.pem");
185
-ENV::setPriv('SQL_CA', "/var/www/sql-keys/ca.pem");
185
+ENV::setPriv('SQL_CERT', "$ENV->WEB_ROOT/sql-keys/client-cert.pem");
186
+ENV::setPriv('SQL_KEY', "$ENV->WEB_ROOT/sql-keys/client-key.pem");
187
+ENV::setPriv('SQL_CA', "$ENV->WEB_ROOT/sql-keys/ca.pem");
186 188
 
187 189
  # Production
188 190
  if (!$ENV->DEV) {
@@ -251,7 +253,7 @@ if (!$ENV->DEV) {
251 253
     ];
252 254
     ENV::setPub(
253 255
         'ANNOUNCE_URLS',
254
-        new RecursiveArrayObject($AnnounceURLs)
256
+        $ENV->convert($AnnounceURLs)
255 257
     );
256 258
 }
257 259
 
@@ -270,7 +272,7 @@ else {
270 272
     ];
271 273
     ENV::setPub(
272 274
         'ANNOUNCE_URLS',
273
-        new RecursiveArrayObject($AnnounceURLs)
275
+        $ENV->convert($AnnounceURLs)
274 276
     );
275 277
 }
276 278
 
@@ -378,6 +380,10 @@ ENV::setPub('FEATURE_SEND_EMAIL', true);
378 380
 # (should only be used for initial setup)
379 381
 ENV::setPub('FEATURE_SET_ENC_KEY_PUBLIC', false);
380 382
 
383
+# Attempt to support the Seqhash algorithm
384
+# https://blog.libredna.org/post/seqhash/
385
+ENV::setPub('FEATURE_BIOPHP', true);
386
+
381 387
 
382 388
 /**
383 389
  * Settings
@@ -592,7 +598,7 @@ $AutomatedBadgeIDs = [
592 598
 ];
593 599
 ENV::setPub(
594 600
     'AUTOMATED_BADGE_IDS',
595
-    new RecursiveArrayObject($AutomatedBadgeIDs)
601
+    $ENV->convert($AutomatedBadgeIDs)
596 602
 );
597 603
 
598 604
 
@@ -822,11 +828,13 @@ $DB = [
822 828
     'picture' => ['name' => 'Picture', 'desc' => 'A meaningful picture, e.g., the specimen or a thumbnail'],
823 829
 
824 830
     # From the non-renamed `torrents` table
825
-    'version' => ['name' => 'Version', 'desc' => 'Start with 0.1.0', 'note' => 'Please see <a href="https://semver.org target=" _blank">Semantic Versioning</a>'],
831
+    'version' => ['name' => 'Version', 'desc' => 'Start with 0.1.0', 'note' => 'Please see <a href="https://semver.org" target="_blank">Semantic Versioning</a>'],
832
+    'license' => ['name' => 'License', 'desc' => '', 'note' => 'Please see <a href="http://www.dcc.ac.uk/resources/how-guides/license-research-data" target="_blank">How to License Research Data</a>'],
833
+    'mirrors' => ['name' => 'Mirrors', 'desc' => 'Up to two FTP/HTTP addresses that either point directly to a file, or for multi-file torrents, to the enclosing folder'],
826 834
 ];
827 835
 ENV::setPub(
828 836
     'DB',
829
-    new RecursiveArrayObject($DB)
837
+    $ENV->convert($DB)
830 838
 );
831 839
 
832 840
 
@@ -947,7 +955,7 @@ $META = [
947 955
             'Binary',
948 956
             'Text',
949 957
         ],
950
-    ], # End $this->META->Platforms
958
+    ], # End $ENV->META->Platforms
951 959
 
952 960
     /**
953 961
      * 1.
@@ -1172,7 +1180,7 @@ $META = [
1172 1180
             'Jupyter'      => ['ipynb'],
1173 1181
             'Ontology'     => ['cgif', 'cl', 'clif', 'csv', 'htm', 'html', 'kif', 'obo', 'owl', 'rdf', 'rdfa', 'rdfs', 'rif', 'tsv', 'xcl', 'xht', 'xhtml', 'xml'],
1174 1182
         ],
1175
-    ], # End $this->META->Formats
1183
+    ], # End $ENV->META->Formats
1176 1184
 
1177 1185
 
1178 1186
     /**
@@ -1268,7 +1276,7 @@ $META = [
1268 1276
             'Velocity',
1269 1277
             'Weight',
1270 1278
         ],
1271
-    ], # End $this->META->Scopes
1279
+    ], # End $ENV->META->Scopes
1272 1280
 
1273 1281
     /**
1274 1282
      * 1.
@@ -1294,11 +1302,11 @@ $META = [
1294 1302
         'OpenMTA',
1295 1303
         'Public Domain',
1296 1304
         'Unspecified',
1297
-    ], # End $this->META->Licenses
1305
+    ], # End $ENV->META->Licenses
1298 1306
 ];
1299 1307
 ENV::setPub(
1300 1308
     'META',
1301
-    new RecursiveArrayObject($META)
1309
+    $ENV->convert($META)
1302 1310
 );
1303 1311
 
1304 1312
 
@@ -1322,16 +1330,16 @@ $CATS = [
1322 1330
         'Icon' => "$CatIcons/sequences.png",
1323 1331
         'Description' => "For data that's ACGT, ACGU, amino acid letters on disk.",
1324 1332
         'Platforms' => $ENV->META->Platforms->Sequences,
1325
-        'Formats' => [
1326
-            $ENV->META->Formats->Sequences,
1327
-            $ENV->META->Formats->Proteins,
1328
-            $ENV->META->Formats->Plain,
1333
+        'Formats' => array_merge([
1329 1334
             /*
1330 1335
             'Sequences' => $ENV->META->Formats->Sequences,
1331 1336
             'Proteins' => $ENV->META->Formats->Proteins,
1332 1337
             'Plain' => $ENV->META->Formats->Plain,
1333 1338
             */
1334
-        ],
1339
+            $ENV->META->Formats->Sequences,
1340
+            $ENV->META->Formats->Proteins,
1341
+            $ENV->META->Formats->Plain,
1342
+        ]),
1335 1343
     ],
1336 1344
 
1337 1345
     2 => [
@@ -1481,7 +1489,7 @@ $CATS = [
1481 1489
 ];
1482 1490
 ENV::setPub(
1483 1491
     'CATS',
1484
-    new RecursiveArrayObject($CATS)
1492
+    $ENV->convert($CATS)
1485 1493
 );
1486 1494
 
1487 1495
 

+ 46
- 39
classes/env.class.php View File

@@ -43,19 +43,13 @@ class ENV
43 43
     # Prevents multiple instances
44 44
     public function __clone()
45 45
     {
46
-        return trigger_error(
47
-            'clone() not allowed',
48
-            E_USER_ERROR
49
-        );
46
+        return error('clone() not allowed.');
50 47
     }
51 48
 
52 49
     # Prevents unserializing
53 50
     public function __wakeup()
54 51
     {
55
-        return trigger_error(
56
-            'wakeup() not allowed',
57
-            E_USER_ERROR
58
-        );
52
+        return error('wakeup() not allowed.');
59 53
     }
60 54
 
61 55
     # $this->key returns public->key
@@ -112,8 +106,39 @@ class ENV
112 106
     }
113 107
 
114 108
 
109
+    /**
110
+     * convert
111
+     *
112
+     * Take a mixed input and returns a RecursiveArrayObject.
113
+     * This function is the sausage grinder, so to speak.
114
+     */
115
+    public function convert($obj)
116
+    {
117
+        switch (gettype($obj)) {
118
+            case 'string':
119
+                $out = json_decode($obj, true);
120
+                return (json_last_error() === JSON_ERROR_NONE)
121
+                    ? new RecursiveArrayObject($out)
122
+                    : error('json_last_error_msg(): ' . json_last_error_msg());
123
+                break;
124
+            
125
+            case 'array':
126
+            case 'object':
127
+                return new RecursiveArrayObject($obj);
128
+            
129
+            default:
130
+                return error('$ENV->convert() expects a JSON string, array, or object.');
131
+                break;
132
+        }
133
+    }
134
+
135
+
115 136
     /**
116 137
      * toArray
138
+     *
139
+     * Takes an object and returns an array.
140
+     * @param object|string $obj Thing to turn into an array
141
+     * @return $new New recursive array with $obj contents
117 142
      * @see https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array
118 143
      */
119 144
     public function toArray($obj)
@@ -135,30 +160,6 @@ class ENV
135 160
     }
136 161
 
137 162
 
138
-    /**
139
-     * fromJson
140
-     *
141
-     * @param string $JSON Valid JavaScript object string
142
-     * @return RecursiveArrayObject Not stdClass as in json_decode()
143
-     */
144
-
145
-    public function fromJson($str)
146
-    {
147
-        if (!is_string($str) || is_empty($str)) {
148
-            error('$ENV->fromJson() expects a string.');
149
-        }
150
-
151
-        $json = json_decode($str, true);
152
-        
153
-        if (json_last_error() === JSON_ERROR_NONE) {
154
-            # Decode to array and construct RAO
155
-            return new RecursiveArrayObject($json);
156
-        } else {
157
-            error('Unable to parse JSON in $ENV->fromJson().');
158
-        }
159
-    }
160
-
161
-
162 163
     /**
163 164
      * dedupe
164 165
      *
@@ -181,18 +182,24 @@ class ENV
181 182
     /**
182 183
      * flatten
183 184
      *
184
-     * Takes an $ENV node (Recursive ArrayObject)
185
+     * Takes an $ENV node or array of them
185 186
      * and flattens out the multi-dimensionality.
186
-     * Returns a single, non-deduplicated array.
187
+     * It returns a flat array with keys intact.
187 188
      */
188
-    public function flatten($arr)
189
+    public function flatten($arr, int $lvl = null)
189 190
     {
191
+        if (!is_array($arr) && !is_object($arr)) {
192
+            return error('$ENV->flatten() expects an array or object, got ' . gettype($arr));
193
+        }
194
+
190 195
         $new = array();
191 196
 
192 197
         foreach ($arr as $k => $v) {
193
-            if (is_object($v)) {
198
+            /*
199
+             if (is_object($v)) {
194 200
                 $v = $this->toArray($v);
195 201
             }
202
+            */
196 203
     
197 204
             if (is_array($v)) {
198 205
                 $new = array_merge($new, $this->flatten($v));
@@ -212,7 +219,7 @@ class ENV
212 219
      * Maps a callback (or default) to an object.
213 220
      *
214 221
      * Example output:
215
-     * $Hashes = $ENV->map('md5', $ENV->CATS->SEQ);
222
+     * $Hashes = $ENV->map('md5', $ENV->CATS->{6});
216 223
      *
217 224
      * var_dump($Hashes);
218 225
      * object(RecursiveArrayObject)#324 (1) {
@@ -237,10 +244,10 @@ class ENV
237 244
      * string(32) "52963afccc006d2bce3c890ad9e8f73a"
238 245
      *
239 246
      * @param string $fn Callback function
240
-     * @param object $obj Object to operate on
247
+     * @param object|string $obj Object or property to operate on
241 248
      * @return object $RAO Mapped RecursiveArrayObject
242 249
      */
243
-    public function map($fn = '', $obj = null)
250
+    public function map(string $fn = '', $obj = null)
244 251
     {
245 252
         # Set a default function if desired
246 253
         if (empty($fn) && !is_object($fn)) {

+ 0
- 44
classes/input.class.php View File

@@ -1,44 +0,0 @@
1
-<?php
2
-declare(strict_types=1);
3
-
4
-/**
5
- * Input class
6
- * 
7
- * An attempt to normalize and secure form inputs.
8
- */
9
-
10
-class Input {
11
-
12
-    /**
13
-     * passphrase
14
-     */
15
-    function passphrase(
16
-        string $Name = 'password',
17
-        string $ID = 'password',
18
-        string $Placeholder = 'Passphrase',
19
-        bool $Advice = false) {
20
-        $ENV = ENV::go();
21
-
22
-        # Input validation
23
-        if (!is_string($Name) || empty($Name)) {
24
-            error("Expected non-empty string, got \$Name = $Name in Input::passphrase.");
25
-        }
26
-
27
-        if (!empty($Advice) && $Advice !== true || $Advice !== false) {
28
-            error("Expected true|false, got \$Advice = $Advice in Input::passphrase.");
29
-        }
30
-
31
-        $Field = <<<HTML
32
-        <input type="password" name="$Name" id="$ID" placeholder="$Placeholder"
33
-          minlength="$ENV->PW_MIN" maxlength="$ENV->PW_MAX"
34
-          class="inputtext" autocomplete="off" required="required" />
35
-HTML;
36
-
37
-if ($Advice) {
38
-    return $Field . $ENV->PW_ADVICE;
39
-} else {
40
-    return $Field;
41
-}
42
-
43
-    }
44
-}

+ 34
- 8
classes/mysql.class.php View File

@@ -111,10 +111,6 @@ set_query_id($ResultSet)
111 111
 -------------------------------------------------------------------------------------
112 112
 *///---------------------------------------------------------------------------------
113 113
 
114
-if (!extension_loaded('mysqli')) {
115
-    error('Mysqli Extension not loaded.');
116
-}
117
-
118 114
 
119 115
 /**
120 116
  * db_string
@@ -285,9 +281,27 @@ class DB_MYSQL
285 281
 
286 282
 
287 283
     /**
288
-     * prepare_query
284
+     * Prepare and execute a prepared query returning the result set.
285
+     *
286
+     * Utility function that wraps DB_MYSQL::prepare and DB_MYSQL::execute
287
+     * as most times, the query is going to be one-off and this will save
288
+     * on keystrokes. If you do plan to be executing a prepared query
289
+     * multiple times with different bound parameters, you'll want to call
290
+     * the two functions separately instead of this function.
291
+     *
292
+     * @param $Query
293
+     * @param mixed ...$Parameters
294
+     * @return bool|mysqli_result
295
+     */
296
+    public function prepared_query($Query, ...$Parameters) {
297
+        $this->prepare($Query);
298
+        return $this->execute(...$Parameters);
299
+    }
300
+
301
+    /**
302
+     * prepare
289 303
      */
290
-    public function prepare_query($Query, &...$BindVars)
304
+    public function prepare($Query, &...$BindVars)
291 305
     {
292 306
         $this->connect();
293 307
         $this->StatementID = mysqli_prepare($this->LinkID, $Query);
@@ -306,11 +320,17 @@ class DB_MYSQL
306 320
         return $this->StatementID;
307 321
     }
308 322
 
323
+    # Compatibility function for the old name
324
+    public function prepare_query($Query, &...$BindVars)
325
+    {
326
+        return $this->prepare($Query, $BindVars);
327
+    }
328
+
309 329
 
310 330
     /**
311
-     * exec_prepared_query
331
+     * execute
312 332
      */
313
-    public function exec_prepared_query()
333
+    public function execute()
314 334
     {
315 335
         $QueryStartTime = microtime(true);
316 336
         mysqli_stmt_execute($this->StatementID);
@@ -320,6 +340,12 @@ class DB_MYSQL
320 340
         $this->Time += $QueryRunTime;
321 341
     }
322 342
 
343
+    # Compatibility function for the old name
344
+    public function exec_prepared_query()
345
+    {
346
+        return $this->execute();
347
+    }
348
+
323 349
 
324 350
     /**
325 351
      * Runs a raw query assuming pre-sanitized input. However, attempting to self sanitize (such

+ 26
- 6
classes/security.class.php View File

@@ -39,23 +39,43 @@ class Security
39 39
     {
40 40
         $ENV = ENV::go();
41 41
 
42
+        # Bad PHP version
43
+        if (version_compare(PHP_VERSION, $ENV->PHP_MIN, '<')) {
44
+            error("Gazelle requires PHP > $ENV->PHP_MIN.");
45
+        }
46
+
42 47
         # short_open_tag
43 48
         if (!ini_get('short_open_tag')) {
44
-            error('short_open_tag != On in php.ini');
49
+            error('short_open_tag != On in php.ini.');
45 50
         }
46 51
 
47 52
         # apcu
48 53
         if (!extension_loaded('apcu')) {
49
-            error('APCu extension not loaded');
54
+            error('APCu extension php-apcu not loaded.');
50 55
         }
51 56
 
52
-        # Bad PHP version
53
-        if (version_compare($ENV->PHP_MIN, '7.4.0', '<')) {
54
-            error("Gazelle requires PHP > $ENV->PHP_MIN.");
57
+        # mbstring
58
+        if (!extension_loaded('mbstring')) {
59
+            error('Multibyte string extension php-mbstring not loaded.');
60
+        }
61
+
62
+        # memcache
63
+        if (!extension_loaded('memcache')) {
64
+            error('memcached extension php-memcache not loaded.');
65
+        }
66
+
67
+        # mysqli
68
+        if (!extension_loaded('mysqli')) {
69
+            error('mysqli extension php-mysql not loaded.');
70
+        }
71
+        
72
+        # blake3
73
+        if ($ENV->FEATURE_BIOPHP && !extension_loaded('blake3')) {
74
+            error('Please install and enable the php-blake3 extension.');
55 75
         }
56 76
 
57 77
         # Deal with dumbasses
58
-        if (isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) {
78
+        if (isset($_REQUEST['info_hash']) || isset($_REQUEST['peer_id'])) {
59 79
             error(
60 80
                 'd14:failure reason40:Invalid .torrent, try downloading again.e',
61 81
                 $NoHTML = true,

+ 0
- 360
classes/seqhash.class.php View File

@@ -1,360 +0,0 @@
1
-<?php
2
-#declare(strict_types = 1);
3
-# PHP Notice:  Trying to access array offset on value of type bool in /var/www/html/dev.biotorrents.de/classes/seqhash.class.php on line 233
4
-
5
-/**
6
- * Seqhash
7
- *
8
- * Implements Keoni's Seqhash algorithm for DNA/RNA/protein sequences,
9
- * e.g., v1_DCD_4b0616d1b3fc632e42d78521deb38b44fba95cca9fde159e01cd567fa996ceb9
10
- *
11
- * > The first element is the version tag (v1 for version 1).
12
- * > If there is ever a Seqhash version 2, this tag will differentiate seqhashes.
13
- *
14
- * > The second element is the metadata tag, which has 3 letters.
15
- * > The first letter codes for the sequenceType (D for DNA, R for RNA, and P for Protein).
16
- * > The second letter codes for whether or not the sequence is circular (C for Circular, L for Linear).
17
- * > The final letter codes for whether or not the sequence is double stranded (D for Double stranded, S for Single stranded).
18
- *
19
- * > The final element is the blake3 hash of the sequence (once rotated and complemented).
20
- *
21
- * Requires the php-blake3 extension from:
22
- * https://github.com/cypherbits/php-blake3
23
- *
24
- * @see https://blog.libredna.org/post/seqhash/
25
- * @see https://github.com/TimothyStiles/poly/blob/prime/hash.go
26
- * @see https://github.com/TimothyStiles/poly/blob/prime/hash_test.go
27
- */
28
-
29
-class Seqhash
30
-{
31
-    /**
32
-     * boothLeastRotation
33
-     *
34
-     * Gets the least rotation of a circular string.
35
-     * @see https://en.wikipedia.org/wiki/Lexicographically_minimal_string_rotation
36
-     */
37
-    public function boothLeastRotation(string $Sequence)
38
-    {
39
-        # First concatenate the sequence to itself to avoid modular arithmatic
40
-        # todo: Use buffers just for speed? May get annoying with larger sequences
41
-        $Sequence = $Sequence . $Sequence;
42
-        $LeastRotationIndex = 0;
43
-
44
-        # Initializing failure slice
45
-        $FailureSlice = array_fill(0, strlen($Sequence), -1);
46
-
47
-        /*
48
-        for ($i = 0; $i <= strlen($Sequence); $i++) {
49
-            $FailureSlice[$i] = -1;
50
-        }
51
-        */
52
-
53
-        # Iterate through each character in the doubled-over sequence
54
-        for ($CharacterIndex = 1; $CharacterIndex < strlen($Sequence); $CharacterIndex++) {
55
-
56
-            # Get character
57
-            $Character = $Sequence[$CharacterIndex];
58
-
59
-            # Get failure
60
-            $Failure = $FailureSlice[$CharacterIndex - $LeastRotationIndex - 1];
61
-
62
-            # While failure !== -1 and character !== the character found at the least rotation + failure + 1
63
-            while ($Failure !== -1 && $Character !== $Sequence[$LeastRotationIndex + $Failure + 1]) {
64
-
65
-                # If character is lexically less than whatever is at $LeastRotationIndex, update $LeastRotationIndex
66
-                if ($Character < $Sequence[$LeastRotationIndex + $Failure + 1]) {
67
-                    $LeastRotationIndex = $CharacterIndex - $Failure - 1;
68
-                }
69
-
70
-                # Update failure using previous failure as index?
71
-                $Failure = $FailureSlice[$Failure];
72
-            } # while
73
-
74
-            # If character does not equal whatever character is at leastRotationIndex plus failure
75
-            if ($Character !== $Sequence[$LeastRotationIndex + $Failure + 1]) {
76
-
77
-                # If character is lexically less then what is rotated, $LeastRotatationIndex gets value of $CharacterIndex
78
-                if ($Character < $Sequence[$LeastRotationIndex]) {
79
-                    $LeastRotationIndex = $CharacterIndex;
80
-                }
81
-
82
-                # Assign -1 to whatever is at the index of difference between character and rotation indices
83
-                $FailureSlice[$CharacterIndex - $LeastRotationIndex] = -1;
84
-    
85
-            # If character does equal whatever character is at $LeastRotationIndex + $Failure
86
-            } else {
87
-                # Assign $Failure + 1 at the index of difference between character and rotation indices
88
-                $FailureSlice[$CharacterIndex - $LeastRotationIndex] = $Failure + 1;
89
-            }
90
-        } # for
91
-
92
-        return $LeastRotationIndex;
93
-    }
94
-
95
-
96
-    /**
97
-     * rotateSequence
98
-     *
99
-     * Rotates circular sequences to a deterministic point.
100
-     */
101
-    public function rotateSequence(string $Sequence)
102
-    {
103
-        $RotationIndex = $this->boothLeastRotation($Sequence);
104
-
105
-        # Writing the same sequence twice
106
-        # PHP has no strings.Builder.WriteString
107
-        $ConcatenatedSequence = $Sequence . $Sequence;
108
-
109
-        # https://stackoverflow.com/a/2423867
110
-        $Length = $RotationIndex % strlen($Sequence);
111
-        return substr($Sequence, $Length) . substr($Sequence, 0, $Length);
112
-    }
113
-
114
-
115
-    /**
116
-     * reverseComplement
117
-     *
118
-     * Takes the reverse complement of a sequence.
119
-     * Doesn't validate the sequence alphabet first.
120
-     */
121
-    public function reverseComplement(string $Sequence)
122
-    {
123
-        # Normalize the sequence
124
-        $Sequence = strtoupper($Sequence);
125
-
126
-        /**
127
-         * Provides 1:1 mapping between bases and their complements.
128
-         * Kind of ghetto, but lowercase replaces help stop extra flips.
129
-         * @see https://github.com/TimothyStiles/poly/blob/prime/sequence.go
130
-         */
131
-        $RuneMap = [
132
-            'A' => 't',
133
-            'B' => 'v',
134
-            'C' => 'g',
135
-            'D' => 'h',
136
-            'G' => 'c',
137
-            'H' => 'd',
138
-            'K' => 'm',
139
-            'M' => 'k',
140
-            'N' => 'n',
141
-            'R' => 'y',
142
-            'S' => 's',
143
-            'T' => 'a',
144
-            'U' => 'a',
145
-            'V' => 'b',
146
-            'W' => 'w',
147
-            'Y' => 'r',
148
-        ];
149
-
150
-        return $ComplementString = strtoupper(
151
-            str_replace(
152
-                array_keys($RuneMap),
153
-                array_values($RuneMap),
154
-                $Sequence
155
-            )
156
-        );
157
-    }
158
-
159
-
160
-    /**
161
-     * hash
162
-     *
163
-     * Create a Seqhash from a string.
164
-     */
165
-    public function hash(
166
-        string $Sequence,
167
-        string $SequenceType,
168
-        bool   $Circular = false,
169
-        bool   $DoubleStranded = true
170
-    ) {
171
-        # Check for Blake3 support
172
-        if (!extension_loaded('blake3')) {
173
-            throw new Exception('Please install and enable the php-blake3 extension.');
174
-        }
175
-
176
-        # By definition, Seqhashes are of uppercase sequences
177
-        $Sequence = strtoupper($Sequence);
178
-
179
-        # If RNA, convert to a DNA sequence
180
-        # The hash itself between a DNA and RNA sequence will not be different,
181
-        # but their Seqhash will have a different metadata string (R vs. D)
182
-        if ($SequenceType === 'RNA') {
183
-            $Sequence = str_replace('T', 'U', $Sequence);
184
-        }
185
-
186
-        # Run checks on the input
187
-        if (!in_array($SequenceType, ['DNA', 'RNA', 'PROTEIN'])) {
188
-            throw new Exception("SequenceType must be one of [DNA, RNA, PROTEIN]. Got $SequenceType.");
189
-        }
190
-
191
-        # Check the alphabet used
192
-        $SequenceRegex = '/[ATUGCYRSWKMBDHVNZ]/';
193
-        $ProteinRegex = '/[ACDEFGHIKLMNPQRSTVWYUO*BXZ]/';
194
-
195
-        # todo: Refactor this to detect $SequenceType from alphabet
196
-        if ($SequenceType === 'DNA' || $SequenceType === 'RNA') {
197
-            foreach (str_split($Sequence) as $Letter) {
198
-                if (!preg_match($SequenceRegex, $Letter)) {
199
-                    throw new Exception("Only letters ATUGCYRSWKMBDHVNZ are allowed for DNA/RNA. Got $Letter.");
200
-                }
201
-            }
202
-        }
203
-
204
-        /**
205
-         * Selenocysteine (Sec; U) and pyrrolysine (Pyl; O) are added
206
-         * in accordance with https://www.uniprot.org/help/sequences
207
-         *
208
-         * The release notes https://web.expasy.org/docs/relnotes/relstat.html
209
-         * also state there are Asx (B), Glx (Z), and Xaa (X) amino acids,
210
-         * so these are added in as well.
211
-         */
212
-        else {
213
-            foreach (str_split($Sequence) as $Letter) {
214
-                if (!preg_match($ProteinRegex, $Letter)) {
215
-                    throw new Exception("Only letters ACDEFGHIKLMNPQRSTVWYUO*BXZ are allowed for proteins. Got $Letter.");
216
-                }
217
-            }
218
-        }
219
-    
220
-        # There is no check for circular proteins since proteins can be circular
221
-        if ($SequenceType === 'PROTEIN' && $DoubleStranded) {
222
-            throw new Exception("Proteins can't be double stranded.");
223
-        }
224
-
225
-        # Gets deterministic sequence based off of metadata + sequence
226
-        #switch ($Circular && $DoubleStranded) {
227
-        switch ([$Circular, $DoubleStranded]) {
228
-            #case (true && true):
229
-            case [true, true]:
230
-                $PotentialSequences = [
231
-                    $this->rotateSequence($Sequence),
232
-                    $this->rotateSequence($this->reverseComplement($Sequence)),
233
-                ];
234
-                $DeterministicSequence = sort($PotentialSequences)[0];
235
-                break;
236
-
237
-            #case (true && false):
238
-            case [true, false]:
239
-                $DeterministicSequence = $this->rotateSequence($Sequence);
240
-                break;
241
-
242
-            #case (false && true):
243
-            case [false, true]:
244
-                $PotentialSequences = [
245
-                    $Sequence,
246
-                    $this->reverseComplement($Sequence),
247
-                ];
248
-                $DeterministicSequence = sort($PotentialSequences)[0];
249
-                break;
250
-
251
-            #case (false && false):
252
-            case [false, false]:
253
-                $DeterministicSequence = $Sequence;
254
-                break;
255
-
256
-            default:
257
-                break;
258
-        }
259
-
260
-        /**
261
-         * Build 3 letter metadata
262
-         */
263
-
264
-        # Get first letter: D for DNA, R for RNA, and P for Protein
265
-        switch ($SequenceType) {
266
-            case 'DNA':
267
-                $SequenceTypeLetter = 'D';
268
-                break;
269
-            
270
-            case 'RNA':
271
-                $SequenceTypeLetter = 'R';
272
-                break;
273
-            
274
-            case 'PROTEIN':
275
-                $SequenceTypeLetter = 'P';
276
-                break;
277
-                
278
-            default:
279
-                break;
280
-            }
281
-
282
-        # Get 2nd letter: C for circular, L for Linear
283
-        if ($Circular) {
284
-            $CircularLetter = 'C';
285
-        } else {
286
-            $CircularLetter = 'L';
287
-        }
288
-
289
-        # Get 3rd letter: D for Double stranded, S for Single stranded
290
-        if ($DoubleStranded) {
291
-            $DoubleStrandedLetter = 'D';
292
-        } else {
293
-            $DoubleStrandedLetter = 'S';
294
-        }
295
-
296
-        # php-blake3 returns hex by default,
297
-        # binary if $rawOutput = true
298
-        return
299
-            'v1'
300
-          . '_'
301
-          . $SequenceTypeLetter
302
-          . $CircularLetter
303
-          . $DoubleStrandedLetter
304
-          . '_'
305
-          . blake3($DeterministicSequence);
306
-    }
307
-
308
-
309
-    /**
310
-     * validate
311
-     *
312
-     * Validates a Seqhash's metadata.
313
-     * Doesn't check the Blake3 hash itself,
314
-     * because php-blake3 has no such feature.
315
-     */
316
-    public function validate(string $Seqhash)
317
-    {
318
-        $Parts = explode('_', $Seqhash);
319
-
320
-        # Check version info
321
-        if ($Parts[0] !== 'v1') {
322
-            throw new Exception("Invalid version info. Got $Parts[0].");
323
-        }
324
-
325
-        # Check 3 letter metadata
326
-        $Meta = str_split($Parts[1]);
327
-        if (!in_array($Meta[0], ['D', 'R', 'P'])
328
-         || !in_array($Meta[1], ['C', 'L'])
329
-         || !in_array($Meta[2], ['D', 'S'])) {
330
-            throw new Exception("Invalid metadata. Got $Parts[1].");
331
-        }
332
-
333
-        # Check Blake3 hex and hash length
334
-        if (!ctype_xdigit($Parts[2]) || strlen($Parts[2] !== 64)) {
335
-            throw new Exception("Invalid Blake3 hash. Expected a 64-character hex string.");
336
-        }
337
-
338
-        return true;
339
-    }
340
-
341
-
342
-    /**
343
-     * gcContent
344
-     *
345
-     * Bonus feature!
346
-     * Calculate GC content of a DNA sequence.
347
-     * Shamelessly ripped from kennypavan/BioPHP.
348
-     *
349
-     * @see https://github.com/kennypavan/BioPHP/blob/master/BioPHP.php
350
-     */
351
-    public function gcContent(string $Sequence, int $Precision = 2)
352
-    {
353
-        $Sequence = strtoupper($Sequence);
354
-        
355
-        $G = substr_count($Sequence, 'G');
356
-        $C = substr_count($Sequence, 'C');
357
-
358
-        return number_format((($G + $C) / strlen($Sequence)) * 100, $Precision);
359
-    }
360
-}

+ 67
- 63
classes/torrent_form.class.php View File

@@ -76,7 +76,7 @@ class TorrentForm
76 76
 
77 77
     /**
78 78
      * ====================
79
-     * = Twig based class =
79
+     * = Twig-based class =
80 80
      * ====================
81 81
     */
82 82
 
@@ -388,8 +388,8 @@ HTML;
388 388
 
389 389
         echo <<<HTML
390 390
               <tr>
391
-                <td>
392
-                  <input id="post" type="submit" value="$Value" />
391
+                <td class="center">
392
+                  <input id="post" type="submit" value="$Value" class="button-primary" />
393 393
                 </td>
394 394
               </tr>
395 395
             </table> <!-- torrent_form -->
@@ -403,7 +403,7 @@ HTML;
403 403
      * upload_form
404 404
      *
405 405
      * Finally the "real" upload form.
406
-     * Contains all the field you'd expect.
406
+     * Contains all the fields you'd expect.
407 407
      *
408 408
      * This is currently one enormous function.
409 409
      * It has sub-functions, variables, and everything.
@@ -438,13 +438,13 @@ HTML;
438 438
 
439 439
 
440 440
         /**
441
-         * Semantic Version
441
+         * Version
442 442
          */
443 443
         
444 444
         $Version = display_str($Torrent['Version']);
445 445
 
446 446
         echo $Twig->render(
447
-            'torrent_form/identifier.html',
447
+            'torrent_form/version.html',
448 448
             [
449 449
               'db' => $ENV->DB->version,
450 450
               'version' => $Version,
@@ -583,7 +583,7 @@ HTML;
583 583
             'torrent_form/year.html',
584 584
             [
585 585
             'db' => $ENV->DB->year,
586
-            'location' => $TorrentYear,
586
+            'year' => $TorrentYear,
587 587
           ]
588 588
         );
589 589
 
@@ -699,7 +699,7 @@ HTML;
699 699
                 $trID = 'media_tr',
700 700
                 $Label = 'Platform',
701 701
                 $Torrent = $Torrent,
702
-                $Media = $ENV->META->Platforms->Sequences
702
+                $Media = $ENV->CATS->{1}->Platforms
703 703
             );
704 704
             
705 705
 
@@ -710,10 +710,7 @@ HTML;
710 710
                 $trID = 'media_graphs_tr',
711 711
                 $Label = 'Platform',
712 712
                 $Torrent = $Torrent,
713
-                $Media = $ENV->flatten([
714
-                    $ENV->META->Platforms->Graphs,
715
-                    $ENV->META->Platforms->Sequences
716
-                ])
713
+                $Media = $ENV->CATS->{2}->Platforms
717 714
             );
718 715
             
719 716
 
@@ -724,10 +721,7 @@ HTML;
724 721
                 $trID = 'media_scalars_vectors_tr',
725 722
                 $Label = 'Platform',
726 723
                 $Torrent = $Torrent,
727
-                $Media = $ENV->flatten([
728
-                    $ENV->META->Platforms->Graphs,
729
-                    $ENV->META->Platforms->Images
730
-                ])
724
+                $Media = $ENV->CATS->{5}->Platforms
731 725
             );
732 726
 
733 727
 
@@ -738,7 +732,7 @@ HTML;
738 732
                 $trID = 'media_images_tr',
739 733
                 $Label = 'Platform',
740 734
                 $Torrent = $Torrent,
741
-                $Media = $ENV->META->Platforms->Images
735
+                $Media = $ENV->CATS->{8}->Platforms
742 736
             );
743 737
 
744 738
 
@@ -749,7 +743,7 @@ HTML;
749 743
                 $trID = 'media_documents_tr',
750 744
                 $Label = 'Platform',
751 745
                 $Torrent = $Torrent,
752
-                $Media = $ENV->META->Platforms->Documents
746
+                $Media = $ENV->CATS->{11}->Platforms
753 747
             );
754 748
 
755 749
 
@@ -760,7 +754,7 @@ HTML;
760 754
                 $trID = 'media_machine_data_tr',
761 755
                 $Label = 'Platform',
762 756
                 $Torrent = $Torrent,
763
-                $Media = $ENV->META->Platforms->Raw
757
+                $Media = $ENV->CATS->{12}->Platforms
764 758
             );
765 759
         } # fi NewTorrent
766 760
         else {
@@ -780,6 +774,7 @@ HTML;
780 774
          */
781 775
         function formatSelect($trID = '', $Label = '', $Torrent = [], $FileTypes = [])
782 776
         {
777
+            #var_dump($FileTypes);
783 778
             echo <<<HTML
784 779
             <tr id="$trID">
785 780
               <td>
@@ -787,21 +782,24 @@ HTML;
787 782
                   $Label
788 783
                 <label>
789 784
               </td>
790
-              
785
+
791 786
               <td>
792 787
                 <select id="container" name="container">
793 788
                   <option value="Autofill">Autofill</option>
794 789
 HTML;
795 790
 
796
-            foreach ($FileTypes as $Type => $Extensions) {
797
-                echo "<option value='$Type'";
791
+            foreach ($FileTypes as $FileType) {
792
+                foreach ($FileType as $Type => $Extensions) {
793
+                    echo "<option value='$Type'";
798 794
 
799
-                if ($Type === ($Torrent['Container'] ?? false)) {
800
-                    echo ' selected';
801
-                }
795
+                    if ($Type === ($Torrent['Container'] ?? false)) {
796
+                        echo ' selected';
797
+                    }
802 798
 
803
-                echo ">$Type</option>\n";
799
+                    echo ">$Type</option>\n";
800
+                }
804 801
             }
802
+        
805 803
 
806 804
             echo <<<HTML
807 805
                 </select>
@@ -826,7 +824,7 @@ HTML;
826 824
             $trID = 'container_tr',
827 825
             $Label = 'Format',
828 826
             $Torrent = $Torrent,
829
-            $FileTypes = array_merge(($ENV->CATS->{1}->Formats))
827
+            $FileTypes = $ENV->CATS->{1}->Formats
830 828
         );
831 829
         
832 830
 
@@ -837,7 +835,8 @@ HTML;
837 835
             $trID = 'container_graphs_tr',
838 836
             $Label = 'Format',
839 837
             $Torrent = $Torrent,
840
-            $FileTypes = array_merge($this->GraphXmlFormats, $this->GraphTxtFormats, $this->SeqFormats, $this->ProtFormats, $this->PlainFormats)
838
+            #$FileTypes = array_column($ENV->META, $Formats)
839
+            $FileTypes = $ENV->CATS->{2}->Formats
841 840
         );
842 841
 
843 842
 
@@ -848,7 +847,8 @@ HTML;
848 847
             $trID = 'container_scalars_vectors_tr',
849 848
             $Label = 'Format',
850 849
             $Torrent = $Torrent,
851
-            $FileTypes = $ENV->flatten($ENV->CATS->{5}->Formats)
850
+            #$FileTypes = $ENV->flatten($ENV->CATS->{5}->Formats)
851
+            $FileTypes = $ENV->CATS->{5}->Formats
852 852
         );
853 853
 
854 854
 
@@ -859,7 +859,8 @@ HTML;
859 859
             $trID = 'container_images_tr',
860 860
             $Label = 'Format',
861 861
             $Torrent = $Torrent,
862
-            $FileTypes = array_merge($this->ImgFormats, $this->PlainFormats)
862
+            #$FileTypes = array_merge($this->ImgFormats)
863
+            $FileTypes = $ENV->CATS->{8}->Formats
863 864
         );
864 865
 
865 866
 
@@ -870,7 +871,8 @@ HTML;
870 871
             $trID = 'container_spatial_tr',
871 872
             $Label = 'Format',
872 873
             $Torrent = $Torrent,
873
-            $FileTypes = array_merge($this->MapVectorFormats, $this->MapRasterFormats, $this->ImgFormats, $this->PlainFormats)
874
+            #$FileTypes = array_merge($this->MapVectorFormats, $this->MapRasterFormats, $this->ImgFormats, $this->PlainFormats)
875
+            $FileTypes = $ENV->CATS->{9}->Formats
874 876
         );
875 877
 
876 878
 
@@ -881,7 +883,8 @@ HTML;
881 883
             $trID = 'container_documents_tr',
882 884
             $Label = 'Format',
883 885
             $Torrent = $Torrent,
884
-            $FileTypes = array_merge($this->BinDocFormats, $this->CpuGenFormats, $this->PlainFormats)
886
+            #$FileTypes = array_merge($this->BinDocFormats, $this->CpuGenFormats, $this->PlainFormats)
887
+            $FileTypes = $ENV->CATS->{11}->Formats
885 888
         );
886 889
 
887 890
 
@@ -892,7 +895,8 @@ HTML;
892 895
             $trID = 'archive_tr',
893 896
             $Label = 'Archive',
894 897
             $Torrent = $Torrent,
895
-            $FileTypes = $this->Archives
898
+            # $ENV->Archives nests -1 deep
899
+            $FileTypes = [$ENV->META->Formats->Archives]
896 900
         );
897 901
 
898 902
 
@@ -1030,21 +1034,13 @@ HTML;
1030 1034
             $TorrentImage = display_str($Torrent['Image']);
1031 1035
             $Disabled = $this->Disabled;
1032 1036
 
1033
-            echo <<<HTML
1034
-            <tr id="cover_tr">
1035
-            <td>
1036
-              <label for="image">
1037
-                Picture
1038
-              </label>
1039
-            </td>
1040
-            
1041
-            <td>
1042
-              <input type="text" id="image" name="image" size="60"
1043
-                placeholder="A meaningful picture, e.g., the specimen or a thumbnail"
1044
-                value="$TorrentImage" $Disabled? />
1045
-            </td>
1046
-          </tr>
1047
-HTML;
1037
+            echo $Twig->render(
1038
+                'torrent_form/picture.html',
1039
+                [
1040
+                    'db' => $ENV->DB->picture,
1041
+                    'picture' => $TorrentImage,
1042
+                ]
1043
+            );
1048 1044
         }
1049 1045
 
1050 1046
 
@@ -1056,21 +1052,13 @@ HTML;
1056 1052
          */
1057 1053
         if (!$this->DisabledFlag && $this->NewTorrent) {
1058 1054
             $TorrentMirrors = display_str($Torrent['Mirrors']);
1059
-            echo <<<HTML
1060
-            <tr id="mirrors_tr">
1061
-              <td>
1062
-                <label for="mirrors">
1063
-                  Mirrors
1064
-                </label>
1065
-              </td>
1066
-              
1067
-              <td>
1068
-                <!-- Needs to be all on one line -->
1069
-                <textarea rows="2" name="mirrors" id="mirrors"
1070
-                  placeholder="Up to two FTP/HTTP addresses that either point directly to a file, or for multi-file torrents, to the enclosing folder">$TorrentMirrors</textarea>
1071
-              </td>
1072
-            </tr>
1073
-HTML;
1055
+            echo $Twig->render(
1056
+                'torrent_form/mirrors.html',
1057
+                [
1058
+                  'db' => $ENV->DB->mirrors,
1059
+                  'mirrors' => $TorrentMirrors,
1060
+              ]
1061
+            );
1074 1062
         }
1075 1063
 
1076 1064
 
@@ -1103,6 +1091,22 @@ HTML;
1103 1091
         }
1104 1092
 
1105 1093
 
1094
+        /**
1095
+         * Seqhash
1096
+         */
1097
+
1098
+        if ($ENV->FEATURE_BIOPHP && !$this->DisabledFlag && $this->NewTorrent) {
1099
+            $TorrentSeqhash = display_str($Torrent['Seqhash']);
1100
+            echo $Twig->render(
1101
+                'torrent_form/seqhash.html',
1102
+                [
1103
+                    'db' => $ENV->DB->seqhash,
1104
+                    'seqhash' => $TorrentSeqhash,
1105
+                ]
1106
+            );
1107
+        }
1108
+
1109
+
1106 1110
         /**
1107 1111
          * Torrent group description
1108 1112
          *

+ 6
- 3
classes/twig.class.php View File

@@ -60,13 +60,16 @@ class Twig
60 60
     private static function factory(): \Twig\Environment
61 61
     {
62 62
         $ENV = ENV::go();
63
+
64
+        # https://twig.symfony.com/doc/3.x/api.html
63 65
         $Twig = new \Twig\Environment(
64 66
             new \Twig\Loader\FilesystemLoader("$ENV->SERVER_ROOT/templates"),
65 67
             [
66 68
                 'auto_reload' => true,
67
-                'autoescape' => 'html',
68
-                'cache' => "$ENV->WEB_ROOT/cache/twig"
69
-                #'debug' => DEBUG_MODE,
69
+                'autoescape' => 'name',
70
+                'cache' => "$ENV->WEB_ROOT/cache/twig",
71
+                'debug' => $ENV->DEV,
72
+                'strict_variables' => true,
70 73
         ]
71 74
         );
72 75
 

+ 11
- 3
classes/util.php View File

@@ -383,14 +383,14 @@ function error($Error = 1, $NoHTML = false, $Log = false, $Debug = true) # , $JS
383 383
      * Append $Log
384 384
      * Formerly in sections/error/index.php
385 385
      */
386
-    if ($Log ?? false) {
386
+    if ($Log) {
387 387
         $Message .= " <a href='log.php?search=$Title'>Search Log</a>";
388 388
     }
389 389
 
390 390
     /**
391 391
      * Append $Debug
392 392
      */
393
-    if ($Debug ?? false) {
393
+    if ($Debug) {
394 394
         $DateTime = strftime('%c', $_SERVER['REQUEST_TIME']);
395 395
         $BackTrace = debug_string_backtrace();
396 396
 
@@ -516,7 +516,15 @@ function json_print($Status, $Message)
516 516
  */
517 517
 function json_error($Code)
518 518
 {
519
-    echo json_encode(add_json_info(['status' => 'failure', 'error' => $Code, 'response' => []]));
519
+    echo json_encode(
520
+        add_json_info(
521
+            [
522
+                'status' => 'failure',
523
+                'error' => $Code,
524
+                'response' => []
525
+            ]
526
+        )
527
+    );
520 528
     die();
521 529
 }
522 530
 

+ 17
- 15
composer.json View File

@@ -1,36 +1,39 @@
1 1
 {
2 2
   "name": "biotorrents/gazelle",
3 3
   "description": "Web framework for private BitTorrent trackers using Ocelot",
4
-
5 4
   "type": "project",
6 5
   "license": "Unlicense",
7
-
8 6
   "authors": [
9
-    { "name": "What.cd" },
10
-    { "name": "Oppaitime" },
11
-    { "name": "BioTorrents.de" }
7
+    {
8
+      "name": "What.cd"
9
+    },
10
+    {
11
+      "name": "Oppaitime"
12
+    },
13
+    {
14
+      "name": "BioTorrents.de"
15
+    }
12 16
   ],
13
-
14 17
   "autoload": {
15
-    "classmap": ["classes/"],
16
-    "files": ["classes/autoload.php"]
18
+    "classmap": [
19
+      "classes/"
20
+    ],
21
+    "files": [
22
+      "classes/autoload.php"
23
+    ]
17 24
   },
18
-
19 25
   "config": {
20 26
     "sort-packages": true
21 27
   },
22
-
23 28
   "require": {
24 29
     "php": ">=7.4",
25
-
26 30
     "ext-apcu": "*",
27
-    "ext-blake3": "*",
28 31
     "ext-curl": "*",
29 32
     "ext-json": "*",
30 33
     "ext-mbstring": "*",
31 34
     "ext-memcache": "*",
32 35
     "ext-mysqli": "*",
33
-
36
+    "biotorrents/biophp": "dev-master",
34 37
     "erusev/parsedown": "^1.8.0-beta-7",
35 38
     "erusev/parsedown-extra": "^0.8.1",
36 39
     "j7mbo/twitter-api-php": "^1.0.6",
@@ -38,13 +41,12 @@
38 41
     "robmorgan/phinx": "^0.12.7",
39 42
     "twig/twig": "^3.3.2"
40 43
   },
41
-
42 44
   "require-dev": {
45
+    "d11wtq/boris": "^1.0.10",
43 46
     "phpstan/phpstan": "^0.12.92",
44 47
     "phpunit/phpunit": "^9.5.6",
45 48
     "squizlabs/php_codesniffer": "^3.6.0"
46 49
   },
47
-
48 50
   "scripts": {
49 51
     "phpstan": "phpstan analyse",
50 52
     "test": "phpunit"

+ 178
- 38
composer.lock View File

@@ -4,20 +4,66 @@
4 4
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 5
         "This file is @generated automatically"
6 6
     ],
7
-    "content-hash": "b306af0027bec610a1abaf7776f3253c",
7
+    "content-hash": "344f2e6f0358a24896af389a4bca5a1a",
8 8
     "packages": [
9
+        {
10
+            "name": "biotorrents/biophp",
11
+            "version": "dev-master",
12
+            "source": {
13
+                "type": "git",
14
+                "url": "https://github.com/biotorrents/biophp.git",
15
+                "reference": "8b099fb0c78ec2a5dcab16c351e5d369853109ee"
16
+            },
17
+            "dist": {
18
+                "type": "zip",
19
+                "url": "https://api.github.com/repos/biotorrents/biophp/zipball/8b099fb0c78ec2a5dcab16c351e5d369853109ee",
20
+                "reference": "8b099fb0c78ec2a5dcab16c351e5d369853109ee",
21
+                "shasum": ""
22
+            },
23
+            "require": {
24
+                "ext-blake3": "*",
25
+                "ext-curl": "*",
26
+                "pear/math_biginteger": "^1.0.3",
27
+                "php": ">=7.4"
28
+            },
29
+            "require-dev": {
30
+                "d11wtq/boris": "^1.0.10"
31
+            },
32
+            "default-branch": true,
33
+            "type": "library",
34
+            "autoload": {
35
+                "psr-4": {
36
+                    "BioPHP\\": "src/"
37
+                }
38
+            },
39
+            "notification-url": "https://packagist.org/downloads/",
40
+            "license": [
41
+                "MIT"
42
+            ],
43
+            "authors": [
44
+                {
45
+                    "name": "ohm",
46
+                    "email": "help@biotorrents.de"
47
+                }
48
+            ],
49
+            "description": "BioPHP implements some light tools for manipulating genomic data",
50
+            "support": {
51
+                "source": "https://github.com/biotorrents/biophp/tree/master"
52
+            },
53
+            "time": "2021-07-23T19:02:18+00:00"
54
+        },
9 55
         {
10 56
             "name": "cakephp/core",
11
-            "version": "4.2.7",
57
+            "version": "4.2.8",
12 58
             "source": {
13 59
                 "type": "git",
14 60
                 "url": "https://github.com/cakephp/core.git",
15
-                "reference": "aa8b40e2adcfbe52c71ec273866628ffc6d87838"
61
+                "reference": "bed4b6f09550909beea5440627d5a6ff85fb1934"
16 62
             },
17 63
             "dist": {
18 64
                 "type": "zip",
19
-                "url": "https://api.github.com/repos/cakephp/core/zipball/aa8b40e2adcfbe52c71ec273866628ffc6d87838",
20
-                "reference": "aa8b40e2adcfbe52c71ec273866628ffc6d87838",
65
+                "url": "https://api.github.com/repos/cakephp/core/zipball/bed4b6f09550909beea5440627d5a6ff85fb1934",
66
+                "reference": "bed4b6f09550909beea5440627d5a6ff85fb1934",
21 67
                 "shasum": ""
22 68
             },
23 69
             "require": {
@@ -61,11 +107,11 @@
61 107
                 "issues": "https://github.com/cakephp/cakephp/issues",
62 108
                 "source": "https://github.com/cakephp/core"
63 109
             },
64
-            "time": "2021-05-24T17:26:44+00:00"
110
+            "time": "2021-06-26T14:06:56+00:00"
65 111
         },
66 112
         {
67 113
             "name": "cakephp/database",
68
-            "version": "4.2.7",
114
+            "version": "4.2.8",
69 115
             "source": {
70 116
                 "type": "git",
71 117
                 "url": "https://github.com/cakephp/database.git",
@@ -120,16 +166,16 @@
120 166
         },
121 167
         {
122 168
             "name": "cakephp/datasource",
123
-            "version": "4.2.7",
169
+            "version": "4.2.8",
124 170
             "source": {
125 171
                 "type": "git",
126 172
                 "url": "https://github.com/cakephp/datasource.git",
127
-                "reference": "cfc914efc099d48300c1a99316fc8d0d55babc67"
173
+                "reference": "cc101051e8d601cf6c2895d635ccefecca97ff4e"
128 174
             },
129 175
             "dist": {
130 176
                 "type": "zip",
131
-                "url": "https://api.github.com/repos/cakephp/datasource/zipball/cfc914efc099d48300c1a99316fc8d0d55babc67",
132
-                "reference": "cfc914efc099d48300c1a99316fc8d0d55babc67",
177
+                "url": "https://api.github.com/repos/cakephp/datasource/zipball/cc101051e8d601cf6c2895d635ccefecca97ff4e",
178
+                "reference": "cc101051e8d601cf6c2895d635ccefecca97ff4e",
133 179
                 "shasum": ""
134 180
             },
135 181
             "require": {
@@ -174,11 +220,11 @@
174 220
                 "issues": "https://github.com/cakephp/cakephp/issues",
175 221
                 "source": "https://github.com/cakephp/datasource"
176 222
             },
177
-            "time": "2021-05-24T17:26:44+00:00"
223
+            "time": "2021-07-03T10:28:16+00:00"
178 224
         },
179 225
         {
180 226
             "name": "cakephp/utility",
181
-            "version": "4.2.7",
227
+            "version": "4.2.8",
182 228
             "source": {
183 229
                 "type": "git",
184 230
                 "url": "https://github.com/cakephp/utility.git",
@@ -435,6 +481,59 @@
435 481
             },
436 482
             "time": "2020-10-12T00:27:44+00:00"
437 483
         },
484
+        {
485
+            "name": "pear/math_biginteger",
486
+            "version": "v1.0.3",
487
+            "source": {
488
+                "type": "git",
489
+                "url": "https://github.com/pear/Math_BigInteger.git",
490
+                "reference": "33d4357543037a458fad3e8c837a01b93104e592"
491
+            },
492
+            "dist": {
493
+                "type": "zip",
494
+                "url": "https://api.github.com/repos/pear/Math_BigInteger/zipball/33d4357543037a458fad3e8c837a01b93104e592",
495
+                "reference": "33d4357543037a458fad3e8c837a01b93104e592",
496
+                "shasum": ""
497
+            },
498
+            "require": {
499
+                "ext-pcre": "*",
500
+                "php": ">=4.2.0"
501
+            },
502
+            "suggest": {
503
+                "ext-bcmath": "Allows using the BCMath extension internally for computation. Faster than native implementation.",
504
+                "ext-gmp": "Allows using the GNU Multiple Precision extension internally for computation. If you are doing a lot of computation this is the recommended extension."
505
+            },
506
+            "type": "library",
507
+            "autoload": {
508
+                "psr-0": {
509
+                    "Math_": "./"
510
+                }
511
+            },
512
+            "notification-url": "https://packagist.org/downloads/",
513
+            "license": [
514
+                "MIT"
515
+            ],
516
+            "authors": [
517
+                {
518
+                    "name": "Jim Wigginton",
519
+                    "email": "terrafrost@php.net"
520
+                }
521
+            ],
522
+            "description": "Pure-PHP arbitrary precission integer arithmetic library. If GMP or BCMath are available they are used.",
523
+            "homepage": "https://github.com/pear/Math_BigInteger",
524
+            "keywords": [
525
+                "arbitrary",
526
+                "bcmath",
527
+                "gmp",
528
+                "integer",
529
+                "precision"
530
+            ],
531
+            "support": {
532
+                "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Math_BigInteger",
533
+                "source": "https://github.com/pear/Math_BigInteger"
534
+            },
535
+            "time": "2016-04-12T05:46:52+00:00"
536
+        },
438 537
         {
439 538
             "name": "psr/container",
440 539
             "version": "2.0.1",
@@ -1768,6 +1867,46 @@
1768 1867
         }
1769 1868
     ],
1770 1869
     "packages-dev": [
1870
+        {
1871
+            "name": "d11wtq/boris",
1872
+            "version": "v1.0.10",
1873
+            "source": {
1874
+                "type": "git",
1875
+                "url": "https://github.com/borisrepl/boris.git",
1876
+                "reference": "31055b15e2d3fe47f31f6aa8e277f8f3fc7eb483"
1877
+            },
1878
+            "dist": {
1879
+                "type": "zip",
1880
+                "url": "https://api.github.com/repos/borisrepl/boris/zipball/31055b15e2d3fe47f31f6aa8e277f8f3fc7eb483",
1881
+                "reference": "31055b15e2d3fe47f31f6aa8e277f8f3fc7eb483",
1882
+                "shasum": ""
1883
+            },
1884
+            "require": {
1885
+                "ext-pcntl": "*",
1886
+                "ext-posix": "*",
1887
+                "ext-readline": "*",
1888
+                "php": ">=5.3.0"
1889
+            },
1890
+            "bin": [
1891
+                "bin/boris"
1892
+            ],
1893
+            "type": "library",
1894
+            "autoload": {
1895
+                "psr-0": {
1896
+                    "Boris": "lib"
1897
+                }
1898
+            },
1899
+            "notification-url": "https://packagist.org/downloads/",
1900
+            "license": [
1901
+                "MIT"
1902
+            ],
1903
+            "description": "A tiny, but robust REPL (Read-Evaluate-Print-Loop) for PHP.",
1904
+            "support": {
1905
+                "issues": "https://github.com/borisrepl/boris/issues",
1906
+                "source": "https://github.com/borisrepl/boris/tree/v1.0.10"
1907
+            },
1908
+            "time": "2015-03-01T08:05:19+00:00"
1909
+        },
1771 1910
         {
1772 1911
             "name": "doctrine/instantiator",
1773 1912
             "version": "1.4.0",
@@ -1897,16 +2036,16 @@
1897 2036
         },
1898 2037
         {
1899 2038
             "name": "nikic/php-parser",
1900
-            "version": "v4.11.0",
2039
+            "version": "v4.12.0",
1901 2040
             "source": {
1902 2041
                 "type": "git",
1903 2042
                 "url": "https://github.com/nikic/PHP-Parser.git",
1904
-                "reference": "fe14cf3672a149364fb66dfe11bf6549af899f94"
2043
+                "reference": "6608f01670c3cc5079e18c1dab1104e002579143"
1905 2044
             },
1906 2045
             "dist": {
1907 2046
                 "type": "zip",
1908
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/fe14cf3672a149364fb66dfe11bf6549af899f94",
1909
-                "reference": "fe14cf3672a149364fb66dfe11bf6549af899f94",
2047
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143",
2048
+                "reference": "6608f01670c3cc5079e18c1dab1104e002579143",
1910 2049
                 "shasum": ""
1911 2050
             },
1912 2051
             "require": {
@@ -1947,22 +2086,22 @@
1947 2086
             ],
1948 2087
             "support": {
1949 2088
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
1950
-                "source": "https://github.com/nikic/PHP-Parser/tree/v4.11.0"
2089
+                "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0"
1951 2090
             },
1952
-            "time": "2021-07-03T13:36:55+00:00"
2091
+            "time": "2021-07-21T10:44:31+00:00"
1953 2092
         },
1954 2093
         {
1955 2094
             "name": "phar-io/manifest",
1956
-            "version": "2.0.1",
2095
+            "version": "2.0.3",
1957 2096
             "source": {
1958 2097
                 "type": "git",
1959 2098
                 "url": "https://github.com/phar-io/manifest.git",
1960
-                "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133"
2099
+                "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
1961 2100
             },
1962 2101
             "dist": {
1963 2102
                 "type": "zip",
1964
-                "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
1965
-                "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
2103
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
2104
+                "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
1966 2105
                 "shasum": ""
1967 2106
             },
1968 2107
             "require": {
@@ -2007,9 +2146,9 @@
2007 2146
             "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
2008 2147
             "support": {
2009 2148
                 "issues": "https://github.com/phar-io/manifest/issues",
2010
-                "source": "https://github.com/phar-io/manifest/tree/master"
2149
+                "source": "https://github.com/phar-io/manifest/tree/2.0.3"
2011 2150
             },
2012
-            "time": "2020-06-27T14:33:11+00:00"
2151
+            "time": "2021-07-20T11:28:43+00:00"
2013 2152
         },
2014 2153
         {
2015 2154
             "name": "phar-io/version",
@@ -2289,16 +2428,16 @@
2289 2428
         },
2290 2429
         {
2291 2430
             "name": "phpstan/phpstan",
2292
-            "version": "0.12.92",
2431
+            "version": "0.12.93",
2293 2432
             "source": {
2294 2433
                 "type": "git",
2295 2434
                 "url": "https://github.com/phpstan/phpstan.git",
2296
-                "reference": "64d4c5dc8ea96972bc18432d137a330239a5d2b2"
2435
+                "reference": "7b7602f05d340ffa418c59299f8c053ac6c3e7ea"
2297 2436
             },
2298 2437
             "dist": {
2299 2438
                 "type": "zip",
2300
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/64d4c5dc8ea96972bc18432d137a330239a5d2b2",
2301
-                "reference": "64d4c5dc8ea96972bc18432d137a330239a5d2b2",
2439
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/7b7602f05d340ffa418c59299f8c053ac6c3e7ea",
2440
+                "reference": "7b7602f05d340ffa418c59299f8c053ac6c3e7ea",
2302 2441
                 "shasum": ""
2303 2442
             },
2304 2443
             "require": {
@@ -2329,7 +2468,7 @@
2329 2468
             "description": "PHPStan - PHP Static Analysis Tool",
2330 2469
             "support": {
2331 2470
                 "issues": "https://github.com/phpstan/phpstan/issues",
2332
-                "source": "https://github.com/phpstan/phpstan/tree/0.12.92"
2471
+                "source": "https://github.com/phpstan/phpstan/tree/0.12.93"
2333 2472
             },
2334 2473
             "funding": [
2335 2474
                 {
@@ -2349,7 +2488,7 @@
2349 2488
                     "type": "tidelift"
2350 2489
                 }
2351 2490
             ],
2352
-            "time": "2021-07-10T13:53:49+00:00"
2491
+            "time": "2021-07-20T10:49:53+00:00"
2353 2492
         },
2354 2493
         {
2355 2494
             "name": "phpunit/php-code-coverage",
@@ -2671,16 +2810,16 @@
2671 2810
         },
2672 2811
         {
2673 2812
             "name": "phpunit/phpunit",
2674
-            "version": "9.5.6",
2813
+            "version": "9.5.7",
2675 2814
             "source": {
2676 2815
                 "type": "git",
2677 2816
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
2678
-                "reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb"
2817
+                "reference": "d0dc8b6999c937616df4fb046792004b33fd31c5"
2679 2818
             },
2680 2819
             "dist": {
2681 2820
                 "type": "zip",
2682
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
2683
-                "reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
2821
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0dc8b6999c937616df4fb046792004b33fd31c5",
2822
+                "reference": "d0dc8b6999c937616df4fb046792004b33fd31c5",
2684 2823
                 "shasum": ""
2685 2824
             },
2686 2825
             "require": {
@@ -2758,7 +2897,7 @@
2758 2897
             ],
2759 2898
             "support": {
2760 2899
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
2761
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.6"
2900
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.7"
2762 2901
             },
2763 2902
             "funding": [
2764 2903
                 {
@@ -2770,7 +2909,7 @@
2770 2909
                     "type": "github"
2771 2910
                 }
2772 2911
             ],
2773
-            "time": "2021-06-23T05:14:38+00:00"
2912
+            "time": "2021-07-19T06:14:47+00:00"
2774 2913
         },
2775 2914
         {
2776 2915
             "name": "sebastian/cli-parser",
@@ -3625,6 +3764,7 @@
3625 3764
                     "type": "github"
3626 3765
                 }
3627 3766
             ],
3767
+            "abandoned": true,
3628 3768
             "time": "2020-09-28T06:45:17+00:00"
3629 3769
         },
3630 3770
         {
@@ -3904,6 +4044,7 @@
3904 4044
     "aliases": [],
3905 4045
     "minimum-stability": "stable",
3906 4046
     "stability-flags": {
4047
+        "biotorrents/biophp": 20,
3907 4048
         "erusev/parsedown": 10
3908 4049
     },
3909 4050
     "prefer-stable": false,
@@ -3911,7 +4052,6 @@
3911 4052
     "platform": {
3912 4053
         "php": ">=7.4",
3913 4054
         "ext-apcu": "*",
3914
-        "ext-blake3": "*",
3915 4055
         "ext-curl": "*",
3916 4056
         "ext-json": "*",
3917 4057
         "ext-mbstring": "*",

+ 1
- 1
design/privatefooter.php View File

@@ -6,7 +6,7 @@ $Sep = '&emsp;';
6 6
 
7 7
 # End <div#content>, begin <footer>
8 8
 # This needs to be <main>, in each page
9
-echo $HTML = '</div></main><footer class="halfwide">';
9
+echo $HTML = '</div></main><footer>';
10 10
 
11 11
 # Disclaimer
12 12
 #if (!empty($Options['disclaimer'])) {

+ 1
- 0
design/privateheader.php View File

@@ -50,6 +50,7 @@ $Styles = array_filter(
50 50
         [
51 51
           'vendor/jquery-ui.min',
52 52
           'vendor/normalize',
53
+          'vendor/skeleton',
53 54
           #'assets/fonts/fa/css/all.min',
54 55
           'global'
55 56
         ],

+ 1
- 0
design/publicfooter.php View File

@@ -8,6 +8,7 @@ echo <<<HTML
8 8
 
9 9
 <footer>
10 10
   <a href="https://github.com/biotorrents/gazelle" target="_blank">GitHub</a>
11
+  <a href="https://docs.biotorrents.de" target="_blank">API</a>
11 12
   <a href="/legal.php?p=privacy">Privacy</a>
12 13
   <a href="/legal.php?p=dmca">DMCA</a>
13 14
 </footer>

+ 4
- 1
design/publicheader.php View File

@@ -41,7 +41,7 @@ foreach ($Scripts as $Script) {
41 41
 }
42 42
 
43 43
 # Load CSS
44
-$Styles = ['vendor/normalize', 'global', 'public'];
44
+$Styles = ['vendor/normalize', 'vendor/skeleton', 'global', 'public'];
45 45
 foreach ($Styles as $Style) {
46 46
     echo View::pushAsset(
47 47
         "$ENV->STATIC_SERVER/styles/$Style.css",
@@ -68,12 +68,15 @@ if ($ENV->OPEN_REGISTRATION) {
68 68
     echo '<a href="register.php">Register</a>';
69 69
 }
70 70
 
71
+/*
71 72
 $Email = $ENV->HELP->Email;
72 73
 $Subject = $ENV->HELP->Subject;
73 74
 $Body = $ENV->HELP->Body;
74 75
 echo "<a href='mailto:$Email?subject=$Subject&body=$Body'>Support</a>";
76
+*/
75 77
 
76 78
 echo <<<HTML
79
+    <a href="https://github.com/biotorrents/gazelle/issues" target="_blank">Support</a>
77 80
   </header>
78 81
 
79 82
 <main>

+ 1
- 1
design/views/generic/reply/quickreply.php View File

@@ -200,7 +200,7 @@ if (!isset($InputTitle)) {
200 200
           class="hidden button_preview_<?=$ReplyText->getID()?>"
201 201
           tabindex="1" />
202 202
 
203
-        <input type="submit" value="Post" id="submit_button" tabindex="1" />
203
+        <input type="submit" class="button-primary" value="Post" id="submit_button" tabindex="1" />
204 204
       </div>
205 205
     </form>
206 206
   </div>

+ 1
- 1
design/views/generic/reply/staffpm.php View File

@@ -32,7 +32,7 @@ $TextPrev = new TEXTAREA_PREVIEW(
32 32
 
33 33
     <input type="button" value="Preview"
34 34
       class="hidden button_preview_<?=$TextPrev->getID()?>" />
35
-    <input type="submit" value="Send message" />
35
+    <input type="submit" class="button-primary" value="Send message" />
36 36
     <input type="button" value="Hide" data-toggle-target="#compose" />
37 37
   </form>
38 38
 </div>

+ 39
- 20
readme.md View File

@@ -1,9 +1,11 @@
1 1
 # BioTorrents.de Gazelle
2 2
 
3 3
 This software is twice removed from the original
4
-[What.cd Gazelle](https://github.com/WhatCD/Gazelle):
5
-it's based on the security hardened PHP7 fork
4
+[What.cd Gazelle](https://github.com/WhatCD/Gazelle).
5
+It's based on the security hardened PHP7 fork
6 6
 [Oppaitime Gazelle](https://git.oppaiti.me/Oppaitime/Gazelle).
7
+It shares several features with
8
+[Orpheus Gazelle](https://github.com/OPSnet/Gazelle).
7 9
 The goal is to organize a functional database with pleasant interfaces,
8 10
 and render insightful views using data from robust external sources.
9 11
 
@@ -23,6 +25,7 @@ BioTorrents.de supports an array of
23 25
 with the appropriate bold/italic glyphs and monospace.
24 26
 These options are available to every theme.
25 27
 Font Awesome 5 is also universally available.
28
+[Download the fonts](https://docs.biotorrents.de/dl/fonts.tgz).
26 29
 
27 30
 ## Markdown support
28 31
 
@@ -36,30 +39,46 @@ Support for the default Gazelle recursive regex BBcode parser.
36 39
 ## $ENV recursive singleton
37 40
 
38 41
 [The site configuration](classes/config.template.php)
39
-is being migrated to a format govered by
40
-[the ENV special class](classes/env.class.php)
41
-for modified ArrayObjects.
42
-This is useful for several reasons:
43
-
44
-- prevents multiple configs loaded in memory;
45
-- ensures the config's immutability;
46
-- doesn't pollute the constants table;
47
-- allows public (echoed) and private (accessed) values;
48
-- supports large, nested static metadata structures;
49
-- able to scope access to the function level;
50
-- easy to extend ENV with new class methods;
51
-- good interoperability potential with JSON; and
52
-- native PHP ArrayObject support with Array compatibility.
42
+is being migrated to a format govered by the
43
+[ENV special class](classes/env.class.php)
44
+for modified recursive ArrayObjects.
53 45
 
54 46
 ## Twig template system
55 47
 
56
-Similar to ENV,
57
-[the Twig interface](classes/twig.class.php)
48
+Similar to ENV, the
49
+[Twig interface](classes/twig.class.php)
58 50
 operates as a singleton because it's an external module with its own cache.
59 51
 Twig provides a security benefit by escaping rendered output,
60 52
 and a secondary benefit of clarifying the PHP running the site sections.
61
-Several custom filters are available from
62
-[Orpheus Gazelle](https://github.com/OPSnet/Gazelle).
53
+Several custom filters are available from OPS.
54
+
55
+## Active data minimization
56
+
57
+BioTorrents.de has
58
+[real lawyer-vetted policies](templates/legal).
59
+In the process of matching the tech to the legal word,
60
+we dropped support for a number of compromising features:
61
+
62
+- Bitcoin, PayPal, and currency exchange API and system calls;
63
+- Bitcoin addresses, user donation history, and similar metadata; and
64
+- IP address and geolocation, email address, passphrase, and passkey history.
65
+
66
+Besides that, BioTorrents has several passive developments in progress:
67
+
68
+- prepare all queries with parameterized statements;
69
+- declare strict mode at the top of every PHP and JS file;
70
+- check strict equality and strong typing, including function arguments;
71
+- run all files through generic formatters such as PHP-CS-Fixer; and
72
+- move all external libraries to uncomplicated package management.
73
+
74
+## Minor changes
75
+
76
+- Database crypto bumped up to AES-256
77
+- Good subresource integrity support
78
+- Configurable HTTP status code errors
79
+- Integrated diceware passphrase generator
80
+- TLS database connections
81
+- Semantic HTML5 themes (WIP)
63 82
 
64 83
 # Changelog: WCD → OT
65 84
 

+ 22
- 4
sections/api/autofill/doi.php View File

@@ -1,14 +1,32 @@
1 1
 <?php
2
-#declare(strict_types=1);
2
+declare(strict_types=1);
3
+
4
+$ENV = ENV::go();
3 5
 
4 6
 if (!$_GET['doi']) {
5
-    json_die();
7
+    json_error('expected doi param');
8
+} elseif (!preg_match("/$ENV->DOI_REGEX/", strtoupper($_GET['doi']))) {
9
+    json_error('expected valid doi');
10
+} else {
11
+    $DOI = $_GET['doi'];
6 12
 }
7 13
 
14
+# https://weichie.com/blog/curl-api-calls-with-php/
15
+$curl = curl_init();
16
+curl_setopt($curl, CURLOPT_URL, "$ENV->SS/$DOI");
17
+curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
18
+curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
19
+$output = curl_exec($curl);
20
+curl_close($curl);
21
+
22
+# I don't like this nested json_*code() business
23
+# It's slow and unnecesary since SS already outputs JSON
24
+# todo: At least cache the response, then refactor
8 25
 print
9 26
     json_encode(
10 27
         [
11 28
             'status' => 'success',
12
-            'response' => ['loadAverage' => sys_getloadavg()]
13
-        ]
29
+            'response' => json_decode($output, true),
30
+        ],
31
+        JSON_UNESCAPED_SLASHES
14 32
     );

+ 1
- 0
sections/api/index.php View File

@@ -266,6 +266,7 @@ switch ($_GET['action']) {
266 266
   */
267 267
 
268 268
   case 'autofill':
269
+    require_once "$ENV->SERVER_ROOT/sections/api/autofill/doi.php";
269 270
     /*
270 271
     if ($_GET['cat'] === 'anime') {
271 272
         require_once "$ENV->SERVER_ROOT/sections/api/autofill/anime.php";

+ 4
- 4
sections/better/better.php View File

@@ -24,7 +24,7 @@ View::show_header('Better');
24 24
 </h3>
25 25
 
26 26
 <div class="box pad">
27
-  <table>
27
+  <table class="better_list">
28 28
     <tr class="colhead">
29 29
       <td style="width: 150px;">Method</td>
30 30
       <td style="width: 400px;">Additional Information</td>
@@ -42,11 +42,11 @@ View::show_header('Better');
42 42
 
43 43
     <tr class="row">
44 44
       <td class="nobr">
45
-        <a href="better.php?method=screenshots&filter=all">Publications</a>
45
+        <a href="better.php?method=literature&filter=all">DOI numbers</a>
46 46
       </td>
47 47
 
48 48
       <td class="nobr">
49
-        When a torrent group doesn't have a publication
49
+        Torrent groups without citations, for enhanced metadata support
50 50
       </td>
51 51
     </tr>
52 52
 
@@ -55,7 +55,7 @@ View::show_header('Better');
55 55
         <a href="better.php?method=covers&filter=all">Pictures</a>
56 56
       </td>
57 57
       <td class="nobr">
58
-        When a torrent group doesn't have a picture
58
+        Torrent groups without pictures, for at-a-glance context
59 59
       </td>
60 60
     </tr>
61 61
 

+ 3
- 3
sections/better/index.php View File

@@ -1,7 +1,7 @@
1 1
 <?php
2 2
 declare(strict_types=1);
3 3
 
4
-enforce_login();
4
+#enforce_login();
5 5
 
6 6
 if (isset($_GET['method'])) {
7 7
     switch ($_GET['method']) {
@@ -9,8 +9,8 @@ if (isset($_GET['method'])) {
9 9
       require_once SERVER_ROOT.'/sections/better/single.php';
10 10
       break;
11 11
   
12
-    case 'screenshots':
13
-      require_once SERVER_ROOT.'/sections/better/screenshots.php';
12
+    case 'literature':
13
+      require_once SERVER_ROOT.'/sections/better/literature.php';
14 14
       break;
15 15
 
16 16
     case 'covers':

sections/better/screenshots.php → sections/better/literature.php View File

@@ -3,57 +3,56 @@ declare(strict_types=1);
3 3
 
4 4
 $All = (!empty($_GET['filter']) && $_GET['filter'] === 'all');
5 5
 $Join = $All
6
-? ''
7
-: (
8
-    'JOIN torrents AS t ON t.GroupID=tg.ID
9
-    JOIN xbt_snatched AS x ON x.fid = t.ID AND x.uid = '
10
-    . $LoggedUser['ID']
11
-);
6
+    ? ''
7
+    : ("
8
+        JOIN `torrents` AS t ON t.`GroupID` = tg.`id`
9
+        JOIN `xbt_snatched` AS x ON x.`fid` = t.`ID`
10
+        AND x.`uid` = '$LoggedUser[ID]'
11
+    ");
12 12
 
13 13
 View::show_header('Torrent groups with no publications');
14 14
 
15
-$DB->query("
15
+$DB->prepared_query("
16 16
 SELECT SQL_CALC_FOUND_ROWS
17
-  tg.`ID`
17
+  tg.`id`
18 18
 FROM
19 19
   `torrents_group` AS tg
20 20
 $Join
21 21
 WHERE
22
-  tg.`ID` NOT IN(
22
+  tg.`id` NOT IN(
23 23
   SELECT DISTINCT
24
-    `TorrentID`
24
+    `group_id`
25 25
   FROM
26
-    `torrents_doi`
26
+    `literature`
27 27
   )
28 28
 ORDER BY
29 29
   RAND()
30 30
 LIMIT 20
31 31
 ");
32 32
 
33
-$Groups = $DB->to_array('ID', MYSQLI_ASSOC);
33
+$Groups = $DB->to_array('id', MYSQLI_ASSOC);
34 34
 $DB->query('SELECT FOUND_ROWS()');
35 35
 list($NumResults) = $DB->next_record();
36
-$Results = Torrents::get_groups(array_keys($Groups));
37
-?>
36
+$Results = Torrents::get_groups(array_keys($Groups)); ?>
38 37
 
39 38
 <div class="header">
40 39
   <?php if ($All) { ?>
41 40
   <h2>
42
-    All groups with no publications
41
+    All groups with no DOI numbers
43 42
   </h2>
44 43
 
45 44
   <?php } else { ?>
46 45
   <h2>
47
-    Torrent groups with no publications that you have snatched
46
+    Torrent groups with no DOI numbers that you have snatched
48 47
   </h2>
49 48
   <?php } ?>
50 49
 
51 50
   <div class="linkbox">
52 51
     <a href="better.php" class="brackets">Back to better.php list</a>
53 52
     <?php if ($All) { ?>
54
-    <a href="better.php?method=screenshots" class="brackets">Show only those you have snatched</a>
53
+    <a href="better.php?method=literature" class="brackets">Show only those you have snatched</a>
55 54
     <?php } else { ?>
56
-    <a href="better.php?method=screenshots&amp;filter=all" class="brackets">Show all</a>
55
+    <a href="better.php?method=literature&amp;filter=all" class="brackets">Show all</a>
57 56
     <?php } ?>
58 57
   </div>
59 58
 </div>
@@ -67,22 +66,22 @@ $Results = Torrents::get_groups(array_keys($Groups));
67 66
     <?php
68 67
 foreach ($Results as $Result) {
69 68
     extract($Result);
70
-    $LangName = $Name ? $Name : ($Title2 ? $Title2 : $NameJP);
71
-    $TorrentTags = new Tags($TagList);
69
+    $LangName = $title ? $title : ($subject ? $subject : $object);
70
+    $TorrentTags = new Tags($tag_list);
72 71
 
73
-    $DisplayName = "<a href='torrents.php?id=$ID' ";
72
+    $DisplayName = "<a href='torrents.php?id=$id' ";
74 73
     if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
75
-        $DisplayName .= 'data-cover="'.ImageTools::process($WikiImage, 'thumb').'" ';
74
+        $DisplayName .= 'data-cover="'.ImageTools::process($picture, 'thumb').'" ';
76 75
     }
77 76
     $DisplayName .= ">$LangName</a>";
78 77
 
79
-    if ($Year > 0) {
80
-        $DisplayName .= " [$Year]";
78
+    if ($year > 0) {
79
+        $DisplayName .= " [$year]";
81 80
     } ?>
82 81
 
83 82
     <tr class="torrent">
84 83
       <td>
85
-        <div class="<?=Format::css_category($CategoryID)?>"></div>
84
+        <div class="<?=Format::css_category($category_id)?>"></div>
86 85
       </td>
87 86
 
88 87
       <td>

+ 9
- 9
sections/better/single.php View File

@@ -1,13 +1,15 @@
1 1
 <?php
2
+declare(strict_types = 1);
3
+
2 4
 if (($Results = $Cache->get_value('better_single_groupids')) === false) {
3 5
     $DB->query("
4 6
     SELECT
5
-      t.ID AS TorrentID,
6
-      t.GroupID AS GroupID
7
-    FROM xbt_files_users AS x
8
-      JOIN torrents AS t ON t.ID=x.fid
9
-    GROUP BY x.fid
10
-    HAVING COUNT(x.uid) = 1
7
+      t.`ID` AS `TorrentID`,
8
+      t.`GroupID` AS `GroupID`
9
+    FROM `xbt_files_users` AS x
10
+      JOIN `torrents` AS t ON t.`ID`=x.`fid`
11
+    GROUP BY x.`fid`
12
+    HAVING COUNT(x.`uid`) = 1
11 13
     LIMIT 30");
12 14
 
13 15
     $Results = $DB->to_pair('GroupID', 'TorrentID', false);
@@ -15,9 +17,7 @@ if (($Results = $Cache->get_value('better_single_groupids')) === false) {
15 17
 }
16 18
 
17 19
 $Groups = Torrents::get_groups(array_keys($Results));
18
-
19
-View::show_header('Single seeder torrents');
20
-?>
20
+View::show_header('Single seeder torrents'); ?>
21 21
 
22 22
 <div class="header">
23 23
   <h2>

+ 15
- 13
sections/bookmarks/torrents.php View File

@@ -66,18 +66,19 @@ foreach ($GroupIDs as $GroupID) {
66 66
         }
67 67
     }
68 68
 
69
-    $TorrentTags = new Tags($TagList);
70
-    $DisplayName = Artists::display_artists($Artists);
71
-    $GroupName = empty($GroupName) ? (empty($GroupTitle2) ? $GroupNameJP : $GroupTitle2) : $GroupName;
69
+    $TorrentTags = new Tags($tag_list);
70
+    $DisplayName = '';
71
+    #$DisplayName = Artists::display_artists($Artists);
72
+    $GroupName = empty($title) ? (empty($subject) ? $object : $subject) : $title;
72 73
     
73 74
     $DisplayName .= '<a href="torrents.php?id='.$GroupID.'" ';
74 75
     if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
75
-        $DisplayName .= 'data-cover="'.ImageTools::process($WikiImage, 'thumb').'" ';
76
+        $DisplayName .= 'data-cover="'.ImageTools::process($picture, 'thumb').'" ';
76 77
     }
77 78
 
78 79
     $DisplayName .= ' class="tooltip" title="View torrent group" dir="ltr">'.$GroupName.'</a>';
79
-    if ($GroupYear > 0) {
80
-        $DisplayName = "$DisplayName [$GroupYear]";
80
+    if ($year > 0) {
81
+        $DisplayName = "$DisplayName [$year]";
81 82
     }
82 83
     $SnatchedGroupClass = $GroupFlags['IsSnatched'] ? ' snatched_group' : '';
83 84
 
@@ -159,11 +160,12 @@ foreach ($GroupIDs as $GroupID) {
159 160
         $TorrentID = key($Torrents);
160 161
         $Torrent = current($Torrents);
161 162
 
162
-        $DisplayName = Artists::display_artists(Artists::get_artist($GroupID));
163
+        $DisplayName = '';
164
+        #$DisplayName = Artists::display_artists(Artists::get_artist($GroupID));
163 165
         $DisplayName .= '<a href="torrents.php?id='.$GroupID.'" ';
164 166
 
165 167
         if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
166
-            $DisplayName .= 'data-cover="'.ImageTools::process($WikiImage, 'thumb').'" ';
168
+            $DisplayName .= 'data-cover="'.ImageTools::process($picture, 'thumb').'" ';
167 169
         }
168 170
 
169 171
         $DisplayName .=' class="tooltip" title="View torrent group" dir="ltr">'.$GroupName.'</a>';
@@ -241,8 +243,8 @@ foreach ($GroupIDs as $GroupID) {
241 243
     #$DisplayName .= Artists::display_artists($Artists, false);
242 244
     $DisplayName .= $GroupName;
243 245
 
244
-    if ($GroupYear > 0) {
245
-        $DisplayName = "$DisplayName [$GroupYear]";
246
+    if ($year > 0) {
247
+        $DisplayName = "$DisplayName [$year]";
246 248
     }
247 249
 
248 250
     $Tags = display_str($TorrentTags->format());
@@ -252,12 +254,12 @@ foreach ($GroupIDs as $GroupID) {
252 254
   <a href="torrents.php?id=<?=$GroupID?>"
253 255
     class="bookmark_<?=$GroupID?>">
254 256
 
255
-    <?php if (!$WikiImage) {
256
-        $WikiImage = STATIC_SERVER.'common/noartwork/music.png';
257
+    <?php if (!$picture) {
258
+        $picture = STATIC_SERVER.'common/noartwork/music.png';
257 259
     } ?>
258 260
 
259 261
     <img class="tooltip"
260
-      src="<?=ImageTools::process($WikiImage, 'thumb')?>"
262
+      src="<?=ImageTools::process($picture, 'thumb')?>"
261 263
       alt="<?=$DisplayName?>"
262 264
       title="<?=$DisplayName?>"
263 265
       data-title-plain="<?=$DisplayName?>" width="100%" />

+ 2
- 2
sections/collages/browse.php View File

@@ -180,7 +180,7 @@ View::show_header(($BookmarkView) ? 'Your bookmarked collections' : 'Collections
180 180
         <input type="hidden" name="action" value="search" />
181 181
       </div>
182 182
 
183
-      <table cellpadding="6" cellspacing="1" border="0" class="layout" width="100%">
183
+      <table cellpadding="6" cellspacing="1" border="0" class="layout torrent_search" width="100%">
184 184
         <tr id="search_terms">
185 185
           <td class="label"></td>
186 186
           <td>
@@ -262,7 +262,7 @@ View::show_header(($BookmarkView) ? 'Your bookmarked collections' : 'Collections
262 262
         </tr>
263 263
         <tr>
264 264
           <td colspan="2" class="center">
265
-            <input type="submit" value="Search" />
265
+            <input type="submit" class="button-primary" value="Search" />
266 266
           </td>
267 267
         </tr>
268 268
       </table>

+ 2
- 2
sections/collages/edit.php View File

@@ -44,7 +44,7 @@ if (!empty($Err)) {
44 44
         value="<?=$LoggedUser['AuthKey']?>" />
45 45
       <input type="hidden" name="collageid"
46 46
         value="<?=$CollageID?>" />
47
-      <table id="edit_collage" class="layout">
47
+      <table id="edit_collage" class="layout collage_edit">
48 48
         <?php if (check_perms('site_collages_delete') || ($CategoryID == 0 && $UserID == $LoggedUser['ID'] && check_perms('site_collages_renamepersonal'))) { ?>
49 49
         <tr>
50 50
           <td class="label">Name</td>
@@ -117,7 +117,7 @@ if (check_perms('site_collages_delete')) { ?>
117 117
 
118 118
         <?php } ?>
119 119
         <tr>
120
-          <td colspan="2" class="center"><input type="submit" value="Edit" /></td>
120
+          <td colspan="2" class="center"><input type="submit" class="button-primary" value="Edit" /></td>
121 121
         </tr>
122 122
       </table>
123 123
     </form>

+ 1
- 1
sections/collages/new.php View File

@@ -136,7 +136,7 @@ new TEXTAREA_PREVIEW(
136 136
 
137 137
         <tr>
138 138
           <td colspan="2" class="center">
139
-            <input type="submit" value="Create" />
139
+            <input type="submit" class="button-primary" value="Create" />
140 140
           </td>
141 141
         </tr>
142 142
       </table>

+ 6
- 11
sections/collages/torrent_collage.php View File

@@ -231,11 +231,7 @@ foreach ($GroupIDs as $GroupID) {
231 231
   id="group_<?=$GroupID?>">
232 232
   <td></td>
233 233
 
234
-  <td class="center">
235
-    <div title="<?=$TorrentTags->title()?>"
236
-      class="tooltip <?=Format::css_category($GroupCategoryID)?> <?=$TorrentTags->css_name()?>">
237
-    </div>
238
-  </td>
234
+  <td></td>
239 235
 
240 236
   <td>
241 237
     <span class="brackets">
@@ -584,13 +580,12 @@ foreach ($UserAdditions as $UserID => $Additions) {
584 580
             value="<?=$LoggedUser['AuthKey']?>" />
585 581
           <input type="hidden" name="collageid"
586 582
             value="<?=$CollageID?>" />
587
-          <div>
588
-            <input type="text" size="20" name="url" />
589
-          </div>
583
+
590 584
           <div class="submit_div">
591
-            <input type="submit" value="Add" />
585
+            <input type="text" size="20" name="url" />
586
+            <input type="submit" class="button-primary" value="Add" />
592 587
           </div>
593
-          <span style="font-style: italic;">Enter the URL of a torrent group on the site.</span>
588
+          <p>Enter the URL of a torrent group on the site.</p>
594 589
         </form>
595 590
       </div>
596 591
 
@@ -672,7 +667,7 @@ if (!$LoggedUser['DisablePosting']) {
672 667
             <textarea name="body" cols="24" rows="5"></textarea>
673 668
           </div>
674 669
           <div class="submit_div">
675
-            <input type="submit" id="submit_button" value="Post" />
670
+            <input type="submit" id="submit_button" class="button-primary" value="Post" />
676 671
           </div>
677 672
         </div>
678 673
       </form>

+ 113
- 64
sections/comments/comments.php View File

@@ -1,5 +1,7 @@
1 1
 <?
2
-/*
2
+declare(strict_types=1);
3
+
4
+/**
3 5
  * $_REQUEST['action'] is artist, collages, requests or torrents (default torrents)
4 6
  * $_REQUEST['type'] depends on the page:
5 7
  *     collages:
@@ -16,17 +18,18 @@
16 18
 // User ID
17 19
 if (isset($_GET['id']) && is_number($_GET['id'])) {
18 20
   $UserID = (int)$_GET['id'];
19
-
20 21
   $UserInfo = Users::user_info($UserID);
21
-
22 22
   $Username = $UserInfo['Username'];
23
-  if ($LoggedUser['ID'] == $UserID) {
23
+
24
+  if ($LoggedUser['ID'] === $UserID) {
24 25
     $Self = true;
25 26
   } else {
26 27
     $Self = false;
27 28
   }
29
+
28 30
   $Perms = Permissions::get_permissions($UserInfo['PermissionID']);
29 31
   $UserClass = $Perms['Class'];
32
+
30 33
   if (!check_paranoia('torrentcomments', $UserInfo['Paranoia'], $UserClass, $UserID)) {
31 34
     error(403);
32 35
   }
@@ -49,91 +52,111 @@ if (!isset($_REQUEST['action'])) {
49 52
 } else {
50 53
   $Action = $_REQUEST['action'];
51 54
 }
55
+
52 56
 if (!isset($_REQUEST['type'])) {
53 57
   $Type = 'default';
54 58
 } else {
55 59
   $Type = $_REQUEST['type'];
56 60
 }
57 61
 
62
+
58 63
 // Construct the SQL query
64
+
59 65
 $Conditions = $Join = [];
60 66
 switch ($Action) {
67
+  # artist comments
61 68
   case 'artist':
62
-    $Field1 = 'artists_group.ArtistID';
63
-    $Field2 = 'artists_group.Name';
64
-    $Table = 'artists_group';
69
+    $Field1 = '`artists_group`.`ArtistID`';
70
+    $Field2 = '`artists_group`.`Name`';
71
+    $Table = '`artists_group`';
65 72
     $Title = 'Artist comments left by ' . ($Self ? 'you' : $Username);
66 73
     $Header = 'Artist comments left by ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false));
67
-    $Conditions[] = "comments.AuthorID = $UserID";
74
+    $Conditions[] = "`comments`.`AuthorID` = $UserID";
68 75
     break;
76
+
77
+  
78
+  # collage comments
69 79
   case 'collages':
70
-    $Field1 = 'collages.ID';
71
-    $Field2 = 'collages.Name';
72
-    $Table = 'collages';
73
-    $Conditions[] = "collages.Deleted = '0'";
80
+    $Field1 = '`collages`.`ID`';
81
+    $Field2 = '`collages`.`Name`';
82
+    $Table = '`collages`';
83
+    $Conditions[] = "`collages`.`Deleted` = '0'";
84
+
74 85
     if ($Type == 'created') {
75
-      $Conditions[] = "collages.UserID = $UserID";
76
-      $Conditions[] = "comments.AuthorID != $UserID";
86
+      $Conditions[] = "`collages`.`UserID` = $UserID";
87
+      $Conditions[] = "`comments`.`AuthorID` != $UserID";
77 88
       $Title = 'Comments left on collages ' . ($Self ? 'you' : $Username) . ' created';
78 89
       $Header = 'Comments left on collages ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false)) . ' created';
79 90
     } elseif ($Type == 'contributed') {
80
-      $Conditions[] = 'IF(collages.CategoryID = ' . array_search('Artists', $CollageCats) . ', collages_artists.ArtistID, collages_torrents.GroupID) IS NOT NULL';
81
-      $Conditions[] = "comments.AuthorID != $UserID";
82
-      $Join[] = "LEFT JOIN collages_torrents ON collages_torrents.CollageID = collages.ID AND collages_torrents.UserID = $UserID";
83
-      $Join[] = "LEFT JOIN collages_artists ON collages_artists.CollageID = collages.ID AND collages_artists.UserID = $UserID";
91
+      $Conditions[] = 'IF(`collages`.`CategoryID` = ' . array_search('Artists', $CollageCats) . ', `collages_artists`.`ArtistID`, `collages_torrents`.`GroupID`) IS NOT NULL';
92
+      $Conditions[] = "`comments`.`AuthorID` != $UserID";
93
+      $Join[] = "LEFT JOIN `collages_torrents` ON `collages_torrents`.`CollageID` = `collages`.`ID` AND `collages_torrents`.`UserID` = $UserID";
94
+      $Join[] = "LEFT JOIN `collages_artists` ON `collages_artists`.`CollageID` = `collages`.`ID` AND `collages_artists`.`UserID` = $UserID";
84 95
       $Title = 'Comments left on collages ' . ($Self ? 'you\'ve' : $Username . ' has') . ' contributed to';
85 96
       $Header = 'Comments left on collages ' . ($Self ? 'you\'ve' : Users::format_username($UserID, false, false, false).' has') . ' contributed to';
86 97
     } else {
87 98
       $Type = 'default';
88
-      $Conditions[] = "comments.AuthorID = $UserID";
99
+      $Conditions[] = "`comments`.`AuthorID` = $UserID";
89 100
       $Title = 'Collage comments left by ' . ($Self ? 'you' : $Username);
90 101
       $Header = 'Collage comments left by ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false));
91 102
     }
92 103
     break;
104
+
105
+
106
+  # request comments
93 107
   case 'requests':
94
-    $Field1 = 'requests.ID';
95
-    $Field2 = 'requests.Title';
108
+    $Field1 = '`requests`.`ID`';
109
+    $Field2 = '`requests`.`Title`';
96 110
     $Table = 'requests';
111
+
97 112
     if ($Type == 'created') {
98
-      $Conditions[] = "requests.UserID = $UserID";
99
-      $Conditions[] = "comments.AuthorID != $UserID";
113
+      $Conditions[] = "`requests`.`UserID` = $UserID";
114
+      $Conditions[] = "`comments`.`AuthorID` != $UserID";
100 115
       $Title = 'Comments left on requests ' . ($Self ? 'you' : $Username) . ' created';
101 116
       $Header = 'Comments left on requests ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false)) . ' created';
102 117
     } elseif ($Type == 'voted') {
103
-      $Conditions[] = "requests_votes.UserID = $UserID";
104
-      $Conditions[] = "comments.AuthorID != $UserID";
105
-      $Join[] = 'JOIN requests_votes ON requests_votes.RequestID = requests.ID';
118
+      $Conditions[] = "`requests_votes`.`UserID` = $UserID";
119
+      $Conditions[] = "`comments`.`AuthorID` != $UserID";
120
+      $Join[] = 'JOIN `requests_votes` ON `requests_votes`.`RequestID` = `requests`.`ID`';
106 121
       $Title = 'Comments left on requests ' . ($Self ? 'you\'ve' : $Username . ' has') . ' voted on';
107 122
       $Header = 'Comments left on requests ' . ($Self ? 'you\'ve' : Users::format_username($UserID, false, false, false) . ' has') . ' voted on';
108 123
     } else {
109 124
       $Type = 'default';
110
-      $Conditions[] = "comments.AuthorID = $UserID";
125
+      $Conditions[] = "`comments`.`AuthorID` = $UserID";
111 126
       $Title = 'Request comments left by ' . ($Self ? 'you' : $Username);
112 127
       $Header = 'Request comments left by ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false));
113 128
     }
114 129
     break;
130
+
131
+
132
+  # torrent comments
115 133
   case 'torrents':
116 134
   default:
117 135
     $Action = 'torrents';
118
-    $Field1 = 'torrents.GroupID';
119
-    $Field2 = "COALESCE(NULLIF(tg.Name,''),NULLIF(tg.Title2,''),tg.NameJP) AS Name";
120
-    $Table = 'torrents';
121
-    $Join[] = 'JOIN torrents_group AS tg ON torrents.GroupID = tg.ID';
136
+    $Field1 = '`torrents`.`GroupID`';
137
+    $Field2 = "COALESCE(NULLIF(tg.`title`,''),NULLIF(tg.`subject`,''),tg.`object`) AS Name";
138
+    $Table = '`torrents`';
139
+    $Join[] = 'JOIN `torrents_group` AS tg ON `torrents`.`GroupID` = tg.`id`';
140
+
122 141
     if ($Type == 'uploaded') {
123
-      $Conditions[] = "torrents.UserID = $UserID";
124
-      $Conditions[] = 'comments.AddedTime > torrents.Time';
125
-      $Conditions[] = "comments.AuthorID != $UserID";
142
+      $Conditions[] = "`torrents`.`UserID` = $UserID";
143
+      $Conditions[] = '`comments`.`AddedTime` > `torrents`.`Time`';
144
+      $Conditions[] = "`comments`.`AuthorID` != $UserID";
126 145
       $Title = 'Comments left on torrents ' . ($Self ? 'you\'ve' : $Username . ' has') . ' uploaded';
127 146
       $Header = 'Comments left on torrents ' . ($Self ? 'you\'ve' : Users::format_username($UserID, false, false, false) . ' has') . ' uploaded';
128 147
     } else {
129 148
       $Type = 'default';
130
-      $Conditions[] = "comments.AuthorID = $UserID";
149
+      $Conditions[] = "`comments`.`AuthorID` = $UserID";
131 150
       $Title = 'Torrent comments left by ' . ($Self ? 'you' : $Username);
132 151
       $Header = 'Torrent comments left by ' . ($Self ? 'you' : Users::format_username($UserID, false, false, false));
133 152
     }
134 153
     break;
135 154
 }
136
-$Join[] = "JOIN comments ON comments.Page = '$Action' AND comments.PageID = $Field1";
155
+
156
+# end SQL query constructor
157
+
158
+
159
+$Join[] = "JOIN `comments` ON `comments`.`Page` = '$Action' AND `comments`.`PageID` = $Field1";
137 160
 $Join = implode("\n\t\t", $Join);
138 161
 $Conditions = implode(" AND ", $Conditions);
139 162
 $Conditions = ($Conditions ? 'WHERE ' . $Conditions : '');
@@ -141,20 +164,20 @@ $Conditions = ($Conditions ? 'WHERE ' . $Conditions : '');
141 164
 $SQL = "
142 165
   SELECT
143 166
     SQL_CALC_FOUND_ROWS
144
-    comments.AuthorID,
145
-    comments.Page,
146
-    comments.PageID,
167
+    `comments`.`AuthorID`,
168
+    `comments`.`Page`,
169
+    `comments`.`PageID`,
147 170
     $Field2,
148
-    comments.ID,
149
-    comments.Body,
150
-    comments.AddedTime,
151
-    comments.EditedTime,
152
-    comments.EditedUserID
171
+    `comments`.`ID`,
172
+    `comments`.`Body`,
173
+    `comments`.`AddedTime`,
174
+    `comments`.`EditedTime`,
175
+    `comments`.`EditedUserID`
153 176
   FROM $Table
154 177
     $Join
155 178
   $Conditions
156
-  GROUP BY comments.ID
157
-  ORDER BY comments.ID DESC
179
+  GROUP BY `comments`.`ID`
180
+  ORDER BY `comments`.`ID` DESC
158 181
   LIMIT $Limit";
159 182
 
160 183
 $Comments = $DB->query($SQL);
@@ -163,65 +186,89 @@ $Count = $DB->record_count();
163 186
 $DB->query("SELECT FOUND_ROWS()");
164 187
 list($Results) = $DB->next_record();
165 188
 $Pages = Format::get_pages($Page, $Results, $PerPage, 11);
166
-
167 189
 $DB->set_query_id($Comments);
168
-if ($Action == 'requests') {
190
+
191
+# Remove the weird comment headings on torrent and request comments
192
+/*
193
+if ($Action === 'requests') {
169 194
   $RequestIDs = array_flip(array_flip($DB->collect('PageID')));
170 195
   $Artists = [];
196
+
171 197
   foreach ($RequestIDs as $RequestID) {
172 198
     $Artists[$RequestID] = Requests::get_artists($RequestID);
173 199
   }
174 200
   $DB->set_query_id($Comments);
175
-} elseif ($Action == 'torrents') {
201
+} elseif ($Action === 'torrents') {
176 202
   $GroupIDs = array_flip(array_flip($DB->collect('PageID')));
177 203
   $Artists = Artists::get_artists($GroupIDs);
178 204
   $DB->set_query_id($Comments);
179 205
 }
206
+*/
207
+
208
+# Replace the "shifting" main links with regular static ones
209
+# There are already shifting supplemental links for each type
210
+$ActionLinks[] = '<a href="comments.php?action=torrents' . $LinkID . '" class="brackets">Torrent comments</a>';
211
+$ActionLinks[] = '<a href="comments.php?action=collages' . $LinkID . '" class="brackets">Collections comments</a>';
212
+$ActionLinks[] = '<a href="comments.php?action=requests' . $LinkID . '" class="brackets">Request comments</a>';
213
+$ActionLinks[] = '<a href="comments.php?action=artist' . $LinkID . '" class="brackets">Artist comments</a>';
180 214
 
215
+/*
181 216
 $LinkID = (!$Self ? '&amp;id=' . $UserID : '');
182 217
 $ActionLinks = $TypeLinks = [];
183
-if ($Action != 'artist') {
218
+if ($Action !== 'artist') {
184 219
   $ActionLinks[] = '<a href="comments.php?action=artist' . $LinkID . '" class="brackets">Artist comments</a>';
185 220
 }
186
-if ($Action != 'collages') {
221
+
222
+if ($Action !== 'collages') {
187 223
   $ActionLinks[] = '<a href="comments.php?action=collages' . $LinkID . '" class="brackets">Collections comments</a>';
188 224
 }
189
-if ($Action != 'requests') {
225
+
226
+if ($Action !== 'requests') {
190 227
   $ActionLinks[] = '<a href="comments.php?action=requests' . $LinkID . '" class="brackets">Request comments</a>';
191 228
 }
192
-if ($Action != 'torrents') {
229
+
230
+if ($Action !== 'torrents') {
193 231
   $ActionLinks[] = '<a href="comments.php?action=torrents' . $LinkID . '" class="brackets">Torrent comments</a>';
194 232
 }
233
+*/
234
+
195 235
 switch ($Action) {
196 236
   case 'collages':
197 237
     $BaseLink = 'comments.php?action=collages' . $LinkID;
198
-    if ($Type != 'default') {
238
+    if ($Type !== 'default') {
199 239
       $TypeLinks[] = '<a href="' . $BaseLink . '" class="brackets">Display collage comments ' . ($Self ? 'you\'ve' : $Username . ' has') . ' made</a>';
200 240
     }
201
-    if ($Type != 'created') {
241
+
242
+    if ($Type !== 'created') {
202 243
       $TypeLinks[] = '<a href="' . $BaseLink . '&amp;type=created" class="brackets">Display comments left on ' . ($Self ? 'your collections' : 'collections created by ' .$Username) . '</a>';
203 244
     }
204
-    if ($Type != 'contributed') {
245
+
246
+    if ($Type !== 'contributed') {
205 247
       $TypeLinks[] = '<a href="' . $BaseLink . '&amp;type=contributed" class="brackets">Display comments left on collections ' . ($Self ? 'you\'ve' : $Username . ' has') . ' contributed to</a>';
206 248
     }
207 249
     break;
250
+
208 251
   case 'requests':
209 252
     $BaseLink = 'comments.php?action=requests' . $LinkID;
210
-    if ($Type != 'default') {
253
+    if ($Type !== 'default') {
211 254
       $TypeLinks[] = '<a href="' . $BaseLink . '" class="brackets">Display request comments you\'ve made</a>';
212 255
     }
213
-    if ($Type != 'created') {
256
+
257
+    if ($Type !== 'created') {
214 258
       $TypeLinks[] = '<a href="' . $BaseLink . '&amp;type=created" class="brackets">Display comments left on your requests</a>';
215 259
     }
216
-    if ($Type != 'voted') {
260
+
261
+    if ($Type !== 'voted') {
217 262
       $TypeLinks[] = '<a href="' . $BaseLink . '&amp;type=voted" class="brackets">Display comments left on requests you\'ve voted on</a>';
218 263
     }
219 264
     break;
265
+
220 266
   case 'torrents':
221
-    if ($Type != 'default') {
267
+    if ($Type !== 'default') {
222 268
       $TypeLinks[] = '<a href="comments.php?action=torrents' . $LinkID . '" class="brackets">Display comments you have made</a>';
223 269
     }
224
-    if ($Type != 'uploaded') {
270
+
271
+    if ($Type !== 'uploaded') {
225 272
       $TypeLinks[] = '<a href="comments.php?action=torrents' . $LinkID . '&amp;type=uploaded" class="brackets">Display comments left on your uploads</a>';
226 273
     }
227 274
     break;
@@ -250,12 +297,15 @@ if ($Count > 0) {
250 297
       case 'artist':
251 298
         $Header = " on <a href=\"artist.php?id=$PageID\">$Name</a>";
252 299
         break;
300
+
253 301
       case 'collages':
254 302
         $Header = " on <a href=\"collages.php?id=$PageID\">$Name</a>";
255 303
         break;
304
+
256 305
       case 'requests':
257 306
         $Header = ' on ' . Artists::display_artists($Artists[$PageID]) . " <a href=\"requests.php?action=view&id=$PageID\">$Name</a>";
258 307
         break;
308
+
259 309
       case 'torrents':
260 310
         $Header = ' on ' . Artists::display_artists($Artists[$PageID]) . " <a href=\"torrents.php?id=$PageID\">$Name</a>";
261 311
         break;
@@ -263,11 +313,10 @@ if ($Count > 0) {
263 313
     CommentsView::render_comment($AuthorID, $PostID, $Body, $AddedTime, $EditedUserID, $EditedTime, $Link, false, $Header, false);
264 314
   }
265 315
 } else { ?>
266
-  <div class="center">No results.</div>
316
+  <h2 class="center">No results.</h2>
267 317
 <? } ?>
268 318
   <div class="linkbox">
269 319
     <?=$Pages?>
270 320
   </div>
271 321
 </div>
272
-<?
273
-View::show_footer();
322
+<? View::show_footer();

+ 11
- 2
sections/comments/index.php View File

@@ -1,10 +1,12 @@
1 1
 <?
2
+declare(strict_types=1);
3
+
2 4
 enforce_login();
3 5
 
4 6
 // fix old links
5
-if ($_REQUEST['action'] == 'artists') {
7
+if ($_REQUEST['action'] === 'artists') {
6 8
   $_REQUEST['action'] = 'artist';
7
-} elseif ($_REQUEST['action'] == 'my_torrents') {
9
+} elseif ($_REQUEST['action'] === 'my_torrents') {
8 10
   $_REQUEST['action'] = 'torrents';
9 11
   $_REQUEST['type'] = 'uploaded';
10 12
 }
@@ -18,24 +20,31 @@ switch ($Action) {
18 20
   case 'take_post':
19 21
     require SERVER_ROOT . '/sections/comments/take_post.php';
20 22
     break;
23
+
21 24
   case 'take_edit':
22 25
     require SERVER_ROOT . '/sections/comments/take_edit.php';
23 26
     break;
27
+
24 28
   case 'take_delete':
25 29
     require SERVER_ROOT . '/sections/comments/take_delete.php';
26 30
     break;
31
+
27 32
   case 'warn':
28 33
     require SERVER_ROOT . '/sections/comments/warn.php';
29 34
     break;
35
+
30 36
   case 'take_warn':
31 37
     require SERVER_ROOT . '/sections/comments/take_warn.php';
32 38
     break;
39
+
33 40
   case 'get':
34 41
     require SERVER_ROOT . '/sections/comments/get.php';
35 42
     break;
43
+
36 44
   case 'jump':
37 45
     require SERVER_ROOT . '/sections/comments/jump.php';
38 46
     break;
47
+    
39 48
   case 'artist':
40 49
   case 'collages':
41 50
   case 'requests':

+ 15
- 1
sections/donate/donate.php View File

@@ -55,7 +55,8 @@ View::show_header('Donate');
55 55
 
56 56
       <li>
57 57
         <strong>Domain.</strong>
58
-        The domain name is $15 per year.
58
+        The primary domain name (biotorrents.de) is $15 per year.
59
+        The secondary one (torrents.bio) is $80 per year.
59 60
         The TLS certificates are gratis.
60 61
       </li>
61 62
 
@@ -64,6 +65,19 @@ View::show_header('Donate');
64 65
         Omics Tools LLC is <?= $ENV->SITE_NAME ?>'s parent company.
65 66
         It's $50 per year for annual reports and $125 for resident agent services.
66 67
       </li>
68
+
69
+      <li>
70
+        <strong>Legal.</strong>
71
+        Registering a U.S. copyright agent is $6 per year.
72
+        The legal counsel is gratis.
73
+      </li>
74
+
75
+
76
+      <li>
77
+        <strong>Total.</strong>
78
+        Depending on the exchange rate, it costs about $350 per year to run <?= $ENV->SITE_NAME ?>.
79
+      </li>
80
+
67 81
     </ul>
68 82
   </div>
69 83
 

+ 2
- 2
sections/forums/newthread.php View File

@@ -103,7 +103,7 @@ View::show_header(
103 103
       <input type="hidden" name="auth"
104 104
         value="<?=$LoggedUser['AuthKey']?>" />
105 105
       <input type="hidden" name="forum" value="<?=$ForumID?>" />
106
-      <table id="newthreadtext" class="layout">
106
+      <table id="newthreadtext" class="layout new_thread">
107 107
         <tr>
108 108
           <td class="label">Title</td>
109 109
           <td><input id="title" class="required" type="text" name="title" style="width: 98%;" /></td>
@@ -196,7 +196,7 @@ if (check_perms('forums_polls_create')) {
196 196
       <div id="buttons" class="center">
197 197
         <input type="button" value="Preview" onclick="Newthread_Preview(1);" id="newthreadpreviewbutton" />
198 198
         <input type="button" value="Editor" onclick="Newthread_Preview(0);" id="newthreadeditbutton" class="hidden" />
199
-        <input type="submit" class="submit" id="submit_button" value="Create" />
199
+        <input type="submit" class="submit button-primary" id="submit_button" value="Create" />
200 200
       </div>
201 201
     </form>
202 202
   </div>

+ 47
- 36
sections/friends/friends.php View File

@@ -1,46 +1,43 @@
1 1
 <?php
2 2
 #declare(strict_types=1);
3 3
 
4
-/************************************************************************
5
-//------------// Main friends page //----------------------------------//
6
-This page lists a user's friends.
4
+/**
5
+ * Main friends page
6
+ * 
7
+ * This page lists a user's friends.
8
+ * There's no real point in caching this page.
9
+ * I doubt users load it that much.
10
+ */
7 11
 
8
-There's no real point in caching this page. I doubt users load it that
9
-much.
10
-************************************************************************/
12
+$ENV = ENV::go();
11 13
 
12 14
 // Number of users per page
13 15
 define('FRIENDS_PER_PAGE', '20');
14
-include_once(SERVER_ROOT.'/classes/paranoia.class.php');
15
-
16
-
16
+include_once "$ENV->SERVER_ROOT/classes/paranoia.class.php";
17 17
 
18 18
 View::show_header('Friends');
19 19
 
20
-
21 20
 $UserID = $LoggedUser['ID'];
22
-
23
-
24 21
 list($Page, $Limit) = Format::page_limit(FRIENDS_PER_PAGE);
25 22
 
26 23
 // Main query
27 24
 $DB->query("
28 25
   SELECT
29 26
     SQL_CALC_FOUND_ROWS
30
-    f.FriendID,
31
-    f.Comment,
32
-    m.Username,
33
-    m.Uploaded,
34
-    m.Downloaded,
35
-    m.PermissionID,
36
-    m.Paranoia,
37
-    m.LastAccess,
38
-    i.Avatar
39
-  FROM friends AS f
40
-    JOIN users_main AS m ON f.FriendID = m.ID
41
-    JOIN users_info AS i ON f.FriendID = i.UserID
42
-  WHERE f.UserID = '$UserID'
43
-  ORDER BY Username
27
+    f.`FriendID`,
28
+    f.`Comment`,
29
+    m.`Username`,
30
+    m.`Uploaded`,
31
+    m.`Downloaded`,
32
+    m.`PermissionID`,
33
+    m.`Paranoia`,
34
+    m.`LastAccess`,
35
+    i.`Avatar`
36
+  FROM `friends` AS f
37
+    JOIN `users_main` AS m ON f.`FriendID` = m.`ID`
38
+    JOIN `users_info` AS i ON f.`FriendID` = i.`UserID`
39
+  WHERE f.`UserID` = '$UserID'
40
+  ORDER BY `Username`
44 41
   LIMIT $Limit");
45 42
 $Friends = $DB->to_array(false, MYSQLI_BOTH, array(6, 'Paranoia'));
46 43
 
@@ -48,24 +45,26 @@ $Friends = $DB->to_array(false, MYSQLI_BOTH, array(6, 'Paranoia'));
48 45
 $DB->query('SELECT FOUND_ROWS()');
49 46
 list($Results) = $DB->next_record();
50 47
 
51
-// Start printing stuff
52
-?>
48
+// Start printing stuff ?>
49
+
53 50
 <div>
54 51
   <div class="header">
55 52
     <h2>Friends List</h2>
56 53
   </div>
54
+
57 55
   <div class="linkbox">
58 56
     <?php
59 57
 // Pagination
60 58
 $Pages = Format::get_pages($Page, $Results, FRIENDS_PER_PAGE, 9);
61
-echo $Pages;
62
-?>
59
+echo $Pages; ?>
63 60
   </div>
61
+
64 62
   <div class="box pad">
65 63
     <?php
66
-if ($Results == 0) {
64
+if ($Results === 0) {
67 65
     echo '<p>You have no friends! :(</p>';
68 66
 }
67
+
69 68
 // Start printing out friends
70 69
 foreach ($Friends as $Friend) {
71 70
     list($FriendID, $Comment, $Username, $Uploaded, $Downloaded, $Class, $Paranoia, $LastAccess, $Avatar) = $Friend; ?>
@@ -80,11 +79,13 @@ foreach ($Friends as $Friend) {
80 79
               &nbsp;Ratio: <strong><?=Format::get_ratio_html($Uploaded, $Downloaded)?></strong>
81 80
               <?php
82 81
   }
82
+
83 83
     if (check_paranoia('uploaded', $Paranoia, $Class, $FriendID)) {
84 84
         ?>
85 85
               &nbsp;Up: <strong><?=Format::get_size($Uploaded)?></strong>
86 86
               <?php
87 87
     }
88
+
88 89
     if (check_paranoia('downloaded', $Paranoia, $Class, $FriendID)) {
89 90
         ?>
90 91
               &nbsp;Down: <strong><?=Format::get_size($Downloaded)?></strong>
@@ -106,13 +107,23 @@ foreach ($Friends as $Friend) {
106 107
             <input type="hidden" name="friendid"
107 108
               value="<?=$FriendID?>" />
108 109
 
109
-            <textarea name="comment" rows="4"
110
-              cols="65"><?=$Comment?></textarea>
110
+            <textarea
111
+              name = "comment"
112
+              rows = "5"
113
+              cols = "50"
114
+              placeholder ="Your saved notes about this friend"
115
+              ><?=$Comment?></textarea>
111 116
           </td>
112 117
           <td class="left" valign="top">
113
-            <input type="submit" name="action" value="Update" /><br />
114
-            <input type="submit" name="action" value="Remove friend" /><br />
115
-            <input type="submit" name="action" value="Contact" /><br />
118
+          <p>
119
+            <input type="submit" name="action" value="Update" />
120
+            <input type="submit" name="action" value="Remove friend" />
121
+          </p>
122
+
123
+          <p>
124
+            <input type="submit" name="action" class="button-primary" value="Contact" />
125
+          </p>
126
+
116 127
           </td>
117 128
         </tr>
118 129
       </table>

+ 7
- 2
sections/inbox/inbox.php View File

@@ -122,7 +122,7 @@ echo $Pages;
122 122
     <input type="hidden" name="action" value="masschange" />
123 123
     <input type="hidden" name="auth"
124 124
       value="<?=$LoggedUser['AuthKey']?>" />
125
-    <input type="submit" name="read" value="Mark as read" />
125
+    <input type="submit" name="read" class="button-primary" value="Mark as read" />
126 126
     <input type="submit" name="unread" value="Mark as unread" />
127 127
     <input type="submit" name="delete" value="Delete message(s)" />
128 128
 
@@ -181,12 +181,17 @@ echo $Pages;
181 181
       }
182 182
   } ?>
183 183
     </table>
184
-    <input type="submit" name="read" value="Mark as read" />
184
+    <?php
185
+    $MsgLimit = ($LoggedUser['PostsPerPage']) ? $LoggedUser['PostsPerPage'] : MESSAGES_PER_PAGE;
186
+    if ($Count > $MsgLimit) { ?>
187
+    <input type="submit" name="read" class="button-primary" value="Mark as read" />
185 188
     <input type="submit" name="unread" value="Mark as unread" />
186 189
     <input type="submit" name="delete" value="Delete message(s)" />
190
+    <?php } ?>
187 191
   </form>
188 192
   <?php } ?>
189 193
 </div>
194
+
190 195
 <div class="linkbox">
191 196
   <?= $Pages ?>
192 197
 </div>

+ 25
- 7
sections/login/login.php View File

@@ -1,6 +1,9 @@
1 1
 <?php
2 2
 declare(strict_types=1);
3 3
 
4
+$ENV = ENV::go();
5
+$Twig = Twig::go();
6
+
4 7
 View::show_header('Login'); ?>
5 8
 
6 9
 <p class="center mouseless">
@@ -36,18 +39,27 @@ if (!$Banned) { ?>
36 39
   </aside>
37 40
   <?php } ?>
38 41
 
39
-  <table>
42
+  <br />
43
+  <table class="login_form">
40 44
     <tr>
41 45
       <td colspan="2">
42 46
         <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" name="username"
43 47
           id="username" class="inputtext" required="required" maxlength="20" pattern="[A-Za-z0-9_?]{1,20}"
44
-          autofocus="autofocus" placeholder="Username" size="40" autocomplete="username" />
48
+          autofocus="autofocus" placeholder="Username" size="35" autocomplete="username" />
45 49
       </td>
46 50
     </tr>
47 51
 
48 52
     <tr>
49 53
       <td>
50
-        <?= Input::passphrase() ?>
54
+        <?=
55
+        $Twig->render('input/passphrase.html', [
56
+          'name' => 'password',
57
+          'id' => 'password',
58
+          'placeholder' => 'Passphrase',
59
+          'pw_min' => $ENV->PW_MIN,
60
+          'pw_max' => $ENV->PW_MAX,
61
+          'advice' => false,
62
+        ]) ?>
51 63
       </td>
52 64
 
53 65
       <td>
@@ -58,9 +70,15 @@ if (!$Banned) { ?>
58 70
     </tr>
59 71
 
60 72
     <tr>
61
-      <td colspan="2">
62
-        <input type="submit" name="login" value="Log In" class="submit" />
73
+      <td colspan="4">
74
+        <input type="submit" name="login" value="Log In" class="submit button-primary" />
75
+
76
+        <?php if ($ENV->OPEN_REGISTRATION) { ?>
77
+          &ensp;
78
+          <a href="/register.php" class="button">Register</a>
79
+          <?php } ?>
63 80
       </td>
81
+
64 82
     </tr>
65 83
   </table>
66 84
 </form>
@@ -76,8 +94,8 @@ else { ?>
76 94
 
77 95
 if ($Attempts > 0) { ?>
78 96
 <p class="center">
79
-  Forgot your password?
80
-  <a href="login.php?act=recover" class="tooltip" title="Recover your password">Reset it here!</a>
97
+  Forgot your passphrase?
98
+  <a href="login.php?act=recover" class="tooltip" title="Recover your passphrase">Reset it here!</a>
81 99
 </p>
82 100
 
83 101
 <?php

+ 14
- 11
sections/login/recover_step2.php View File

@@ -2,8 +2,9 @@
2 2
 declare(strict_types=1);
3 3
 
4 4
 $ENV = ENV::go();
5
-View::show_header('Recover Password', 'validate,password_validate');
5
+$Twig = Twig::go();
6 6
 
7
+View::show_header('Recover Password', 'validate,password_validate');
7 8
 echo '<h2>Reset your password</h2>';
8 9
 
9 10
 if (empty($PassWasReset)) {
@@ -22,11 +23,12 @@ if (empty($PassWasReset)) {
22 23
       </td>
23 24
 
24 25
       <td>
25
-        <?= Input::passphrase($Name = 'password', $ID='new_pass_1', $Placeholder = 'New passphrase') ?>
26
-        <!--
27
-        <input type="password" minlength="15" name="password" id="new_pass_1" class="inputtext" size="40"
28
-          placeholder="New Password" pattern=".{15,307200}" required style="width: 250px !important;">
29
-        -->
26
+        <?=
27
+        $Twig->render('input/passphrase.html', [
28
+          'name' => 'password',
29
+          'id' => 'new_pass_1',
30
+          'placeholder' => 'New passphrase'
31
+        ]) ?>
30 32
       </td>
31 33
     </tr>
32 34
 
@@ -35,11 +37,12 @@ if (empty($PassWasReset)) {
35 37
         <strong id="pass_match"></strong>
36 38
       </td>
37 39
       <td>
38
-        <?= Input::passphrase($Name = 'verifypassword', $ID='new_pass_2', $Placeholder = 'Confirm passphrase') ?>
39
-        <!--
40
-        <input type="password" minlength="15" name="verifypassword" id="new_pass_2" class="inputtext" size="40"
41
-          placeholder="Confirm Password" pattern=".{15,307200}" required style="width: 250px !important;">
42
-        -->
40
+      <?=
41
+        $Twig->render('input/passphrase.html', [
42
+          'name' => 'verifypassword',
43
+          'id' => 'new_pass_2',
44
+          'placeholder' => 'Confirm passphrase'
45
+        ]) ?>
43 46
       </td>
44 47
     </tr>
45 48
 

+ 2
- 1
sections/register/step1.php View File

@@ -39,6 +39,7 @@ if (empty($Sent)) { ?>
39 39
           <strong>Don't choose one associated with your real name.</strong>
40 40
           If you do, we won't be changing it for you.
41 41
         </p>
42
+        <br />
42 43
 
43 44
         <input type="text" name="username" id="username" class="inputtext" placeholder="Username"
44 45
           value="<?=(!empty($_REQUEST['username']) ? display_str($_REQUEST['username']) : '')?>" />
@@ -96,7 +97,7 @@ if (empty($Sent)) { ?>
96 97
     </tr>
97 98
 
98 99
     <tr>
99
-      <td colspan="2" align="right"><input type="submit" name="submit" value="Submit" class="submit" /></td>
100
+      <td colspan="2" align="right"><input type="submit" name="submit" value="Submit" class="submit button-primary" /></td>
100 101
     </tr>
101 102
   </table>
102 103
 </form>

+ 12
- 11
sections/reportsv2/report.php View File

@@ -1,12 +1,14 @@
1 1
 <?php
2 2
 #declare(strict_types=1);
3 3
 
4
-/*
4
+/**
5 5
  * This is the frontend of reporting a torrent, it's what users see when
6 6
  * they visit reportsv2.php?id=xxx
7 7
  */
8 8
 
9
-include(SERVER_ROOT.'/sections/torrents/functions.php');
9
+$ENV = ENV::go();
10
+
11
+require_once "$ENV->SERVER_ROOT/sections/torrents/functions.php";
10 12
 
11 13
 // If we're not coming from torrents.php, check we're being returned because of an error.
12 14
 if (!isset($_GET['id']) || !is_number($_GET['id'])) {
@@ -16,11 +18,11 @@ if (!isset($_GET['id']) || !is_number($_GET['id'])) {
16 18
 } else {
17 19
     $TorrentID = $_GET['id'];
18 20
     $DB->query("
19
-    SELECT tg.CategoryID, t.GroupID, u.Username
20
-    FROM torrents_group AS tg
21
-      LEFT JOIN torrents AS t ON t.GroupID = tg.ID
22
-      LEFT JOIN users_main AS u ON t.UserID = u.ID
23
-    WHERE t.ID = " . $_GET['id']);
21
+    SELECT tg.`category_id`, t.`GroupID`, u.`Username`
22
+    FROM `torrents_group` AS tg
23
+      LEFT JOIN `torrents` AS t ON t.`GroupID` = tg.`id`
24
+      LEFT JOIN `users_main` AS u ON t.`UserID` = u.`ID`
25
+    WHERE t.`ID` = " . $_GET['id']);
24 26
     list($CategoryID, $GroupID, $Username) = $DB->next_record();
25 27
     $Artists = Artists::get_artist($GroupID);
26 28
     $TorrentCache = get_group_info($GroupID, true);
@@ -137,7 +139,7 @@ View::show_header('Report', 'reportsv2,browse,torrent,bbcode,recommend');
137 139
 
138 140
       <div id="dynamic_form">
139 141
 <?php
140
-        /*
142
+        /**
141 143
          * THIS IS WHERE SEXY AJAX COMES IN
142 144
          * The following malarky is needed so that if you get sent back here, the fields are filled in.
143 145
          */
@@ -149,8 +151,7 @@ View::show_header('Report', 'reportsv2,browse,torrent,bbcode,recommend');
149 151
         <input id="extra" type="hidden" name="extra" value="<?=(!empty($_POST['extra']) ? display_str($_POST['extra']) : '')?>" />
150 152
       </div>
151 153
     </div>
152
-  <input type="submit" value="Report" />
154
+  <input type="submit" class="button-primary" value="Report" />
153 155
   </form>
154 156
 </div>
155
-<?php
156
-View::show_footer();
157
+<?php View::show_footer();

+ 3
- 4
sections/reportsv2/takereport.php View File

@@ -1,5 +1,6 @@
1 1
 <?
2
-/*
2
+
3
+/**
3 4
  * This page handles the backend from when a user submits a report.
4 5
  * It checks for (in order):
5 6
  * 1. The usual POST injections, then checks that things.
@@ -56,8 +57,6 @@ if (!empty($_POST['sitelink'])) {
56 57
   } else {
57 58
     $Err = 'The permalink was incorrect. It should look like '.site_url().'torrents.php?torrentid=12345';
58 59
   }
59
-} else {
60
-  $ExtraIDs = '';
61 60
 }
62 61
 
63 62
 if (!empty($_POST['link'])) {
@@ -108,7 +107,7 @@ if (!$DB->has_results()) {
108 107
 list($GroupID) = $DB->next_record();
109 108
 
110 109
 if (!empty($Err)) {
111
-  error($Err);
110
+  error($Error = $Err, $Debug = false);
112 111
   include(SERVER_ROOT.'/sections/reportsv2/report.php');
113 112
   error();
114 113
 }

+ 2
- 2
sections/requests/new_edit.php View File

@@ -444,13 +444,13 @@ View::show_header(
444 444
         <!-- Submit -->
445 445
         <tr>
446 446
           <td colspan="2" class="center">
447
-            <input type="submit" id="button" value="Create" disabled="disabled" />
447
+            <input type="submit" id="button" class="button-primary" value="Create" disabled="disabled" />
448 448
           </td>
449 449
         </tr>
450 450
         <?php } else { ?>
451 451
         <tr>
452 452
           <td colspan="2" class="center">
453
-            <input type="submit" id="button" value="Edit" />
453
+            <input type="submit" id="button" class="button-primary" value="Edit" />
454 454
           </td>
455 455
         </tr>
456 456
         <?php } ?>

+ 7
- 7
sections/requests/request.php View File

@@ -244,7 +244,7 @@ $encoded_artist = urlencode($encoded_artist);
244 244
     <div class="box">
245 245
       <div class="head"><strong>Info</strong></div>
246 246
       <div class="pad">
247
-        <table class="layout">
247
+        <table class="layout request_form">
248 248
           <tr>
249 249
             <td class="label">Created</td>
250 250
             <td>
@@ -318,16 +318,16 @@ $encoded_artist = urlencode($encoded_artist);
318 318
           <tr id="voting">
319 319
             <td class="label">Custom Vote</td>
320 320
             <td>
321
-              These units are in base 2, not base 10, e.g., there are 1,024 MiB in 1 GiB
321
+              These units are in base 2, not base 10, e.g., there are 1,024 MiB in 1 GiB.
322
+              <strong>The system deducts <?= ($RequestTax * 100) ?>% as tax.</strong>
323
+              <br />
324
+
322 325
               <input type="text" id="amount_box" size="8" onchange="Calculate();" />
323 326
               <select id="unit" name="unit" onchange="Calculate();">
324 327
                 <option value="mb">MiB</option>
325 328
                 <option value="gb">GiB</option>
326 329
               </select>
327 330
               <input type="button" value="Preview" onclick="Calculate();" />
328
-              <strong>The system deducts <?= ($RequestTax * 100) ?>%
329
-                as tax</strong>
330
-
331 331
             </td>
332 332
           </tr>
333 333
           <tr>
@@ -361,7 +361,7 @@ $encoded_artist = urlencode($encoded_artist);
361 361
                   <li><strong>Ratio:</strong> <span id="new_ratio"><?= Format::get_ratio_html($LoggedUser['BytesUploaded'], $LoggedUser['BytesDownloaded']) ?></span>
362 362
                   </li>
363 363
                 </ul>
364
-                <input type="button" id="button" value="Vote!" disabled="disabled" onclick="Vote();" />
364
+                <input type="button" id="button" value="Vote!" class="button-primary" disabled="disabled" onclick="Vote();" />
365 365
               </form>
366 366
             </td>
367 367
           </tr>
@@ -413,7 +413,7 @@ $encoded_artist = urlencode($encoded_artist);
413 413
                 </div>
414 414
                 <?php } ?>
415 415
                 <div class="submit_div">
416
-                  <input type="submit" value="Fill" />
416
+                  <input type="submit" class="button-primary" value="Fill" />
417 417
                 </div>
418 418
               </form>
419 419
             </td>

+ 19
- 19
sections/requests/requests.php View File

@@ -359,7 +359,7 @@ View::show_header($Title, 'requests');
359 359
             value="<?=$_GET['userid']?>" />
360 360
         <?php } ?>
361 361
         <div class="box pad">
362
-            <table cellpadding="6" cellspacing="1" border="0" class="layout" width="100%">
362
+            <table cellpadding="6" cellspacing="1" border="0" class="layout torrent_requests" width="100%">
363 363
 
364 364
                 <tr id="search_terms">
365 365
                     <td class="label">
@@ -443,7 +443,7 @@ View::show_header($Title, 'requests');
443 443
             <table class="layout">
444 444
                 <tr>
445 445
                     <td colspan="2" class="center">
446
-                        <input type="submit" value="Search" />
446
+                        <input type="submit" class="button-primary" value="Search" />
447 447
                     </td>
448 448
                 </tr>
449 449
             </table>
@@ -456,37 +456,37 @@ View::show_header($Title, 'requests');
456 456
     <?php } ?>
457 457
     <table id="request_table" class="request_table border" cellpadding="6" cellspacing="1" border="0" width="100%">
458 458
         <tr class="colhead_dark">
459
-            <td class="small cats_col"></td>
460
-            <td style="width: 38%;" class="nobr">
459
+            <th class="small cats_col"></th>
460
+            <th style="width: 38%;" class="nobr">
461 461
                 <strong>Request Name</strong>
462
-            </td>
463
-            <td class="nobr">
462
+            </th>
463
+            <th class="nobr">
464 464
                 <a
465 465
                     href="?order=votes&amp;sort=<?=($OrderBy === 'votes' ? $NewSort : 'desc')?>&amp;<?=$CurrentURL?>"><strong>Votes</strong></a>
466
-            </td>
467
-            <td class="nobr">
466
+            </th>
467
+            <th class="nobr">
468 468
                 <a
469 469
                     href="?order=bounty&amp;sort=<?=($OrderBy === 'bounty' ? $NewSort : 'desc')?>&amp;<?=$CurrentURL?>"><strong>Bounty</strong></a>
470
-            </td>
471
-            <td class="nobr">
470
+            </th>
471
+            <th class="nobr">
472 472
                 <a
473 473
                     href="?order=filled&amp;sort=<?=($OrderBy === 'filled' ? $NewSort : 'desc')?>&amp;<?=$CurrentURL?>"><strong>Filled</strong></a>
474
-            </td>
475
-            <td class="nobr">
474
+            </th>
475
+            <th class="nobr">
476 476
                 <strong>Filled by</strong>
477
-            </td>
478
-            <td class="nobr">
477
+            </th>
478
+            <th class="nobr">
479 479
                 <strong>Requested by</strong>
480
-            </td>
481
-            <td class="nobr">
480
+            </th>
481
+            <th class="nobr">
482 482
                 <a
483 483
                     href="?order=created&amp;sort=<?=($OrderBy === 'created' ? $NewSort : 'desc')?>&amp;<?=$CurrentURL?>"><strong>Created</strong></a>
484
-            </td>
485
-            <td class="nobr">
484
+            </th>
485
+            <th class="nobr">
486 486
                 <a
487 487
                     href="?order=lastvote&amp;sort=<?=($OrderBy === 'lastvote' ? $NewSort : 'desc')?>&amp;<?=$CurrentURL?>"><strong>Last
488 488
                         vote</strong></a>
489
-            </td>
489
+            </th>
490 490
         </tr>
491 491
         <?php
492 492
     if ($NumResults === 0) {

+ 1
- 1
sections/rules/clients.php View File

@@ -34,7 +34,7 @@ if (!$WhitelistedClients = $Cache->get_value('whitelisted_clients')) {
34 34
   </p>
35 35
   <br />
36 36
 
37
-  <table>
37
+  <table class="clients_table">
38 38
     <tr class="colhead">
39 39
       <td>
40 40
         <strong>Allowed Clients</strong>

+ 9
- 9
sections/tools/tools.php View File

@@ -53,7 +53,7 @@ View::show_header('Staff Tools');
53 53
   if ($ToolsHTML) {
54 54
       ?>
55 55
     <div class="permission_subcontainer">
56
-      <table class="layout">
56
+      <table class="layout admin_tools">
57 57
         <tr class="colhead">
58 58
           <td>Administration</td>
59 59
         </tr>
@@ -72,7 +72,7 @@ View::show_header('Staff Tools');
72 72
   if ($ToolsHTML) {
73 73
       ?>
74 74
     <div class="permission_subcontainer">
75
-      <table class="layout">
75
+      <table class="layout admin_tools">
76 76
         <tr class="colhead">
77 77
           <td>Announcements</td>
78 78
         </tr>
@@ -89,7 +89,7 @@ View::show_header('Staff Tools');
89 89
   if ($ToolsHTML) {
90 90
       ?>
91 91
     <div class="permission_subcontainer">
92
-      <table class="layout">
92
+      <table class="layout admin_tools">
93 93
         <tr class="colhead">
94 94
           <td>Community</td>
95 95
         </tr>
@@ -107,7 +107,7 @@ View::show_header('Staff Tools');
107 107
   if ($ToolsHTML) {
108 108
       ?>
109 109
     <div class="permission_subcontainer">
110
-      <table class="layout">
110
+      <table class="layout admin_tools">
111 111
         <tr class="colhead">
112 112
           <td>Finances</td>
113 113
         </tr>
@@ -130,7 +130,7 @@ View::show_header('Staff Tools');
130 130
   if ($ToolsHTML) {
131 131
       ?>
132 132
     <div class="permission_subcontainer">
133
-      <table class="layout">
133
+      <table class="layout admin_tools">
134 134
         <tr class="colhead">
135 135
           <td>Queue</td>
136 136
         </tr>
@@ -149,7 +149,7 @@ View::show_header('Staff Tools');
149 149
   if ($ToolsHTML) {
150 150
       ?>
151 151
     <div class="permission_subcontainer">
152
-      <table class="layout">
152
+      <table class="layout admin_tools">
153 153
         <tr class="colhead">
154 154
           <td>Managers</td>
155 155
         </tr>
@@ -171,7 +171,7 @@ View::show_header('Staff Tools');
171 171
   if ($ToolsHTML) {
172 172
       ?>
173 173
     <div class="permission_subcontainer">
174
-      <table class="layout">
174
+      <table class="layout admin_tools">
175 175
         <tr class="colhead">
176 176
           <td>Development</td>
177 177
         </tr>
@@ -200,7 +200,7 @@ View::show_header('Staff Tools');
200 200
   if ($ToolsHTML) {
201 201
       ?>
202 202
     <div class="permission_subcontainer">
203
-      <table class="layout">
203
+      <table class="layout admin_tools">
204 204
         <tr class="colhead">
205 205
           <td>Site Information</td>
206 206
         </tr>
@@ -224,7 +224,7 @@ View::show_header('Staff Tools');
224 224
   if ($ToolsHTML) {
225 225
       ?>
226 226
     <div class="permission_subcontainer">
227
-      <table class="layout">
227
+      <table class="layout admin_tools">
228 228
         <tr class="colhead">
229 229
           <td>Torrents</td>
230 230
         </tr>

+ 1
- 1
sections/top10/donors.php View File

@@ -65,7 +65,7 @@ function generate_user_table($Caption, $Results, $Limit)
65 65
     </small>
66 66
   </h3>
67 67
 
68
-  <table class="border">
68
+  <table class="border top10_table">
69 69
     <tr class="colhead">
70 70
       <td class="center">Position</td>
71 71
       <td>User</td>

+ 1
- 1
sections/top10/tags.php View File

@@ -108,7 +108,7 @@ function generate_tag_table($Caption, $Tag, $Details, $Limit, $RequestsTable = f
108 108
     </small>
109 109
   </h3>
110 110
 
111
-  <table class="border">
111
+  <table class="border top10_table">
112 112
     <tr class="colhead">
113 113
       <td class="center">Rank</td>
114 114
       <td>Tag</td>

+ 1
- 1
sections/top10/torrents.php View File

@@ -92,7 +92,7 @@ if (check_perms('site_advanced_top10')) {
92 92
                 </tr>
93 93
                 <tr>
94 94
                     <td colspan="2" class="center">
95
-                        <input type="submit" value="Search" />
95
+                        <input type="submit" class="button-primary" value="Search" />
96 96
                     </td>
97 97
                 </tr>
98 98
             </table>

+ 1
- 1
sections/top10/users.php View File

@@ -130,7 +130,7 @@ function generate_user_table($Caption, $Tag, $Details, $Limit)
130 130
       <?php } ?>
131 131
     </small>
132 132
   </h3>
133
-  <table class="border">
133
+  <table class="border top10_table">
134 134
     <tr class="colhead">
135 135
       <td class="center">Rank</td>
136 136
       <td>User</td>

+ 13
- 5
sections/torrents/browse.php View File

@@ -195,7 +195,7 @@ View::show_header('Browse Torrents', 'browse');
195 195
         <?php
196 196
         } ?>
197 197
 
198
-        <table class="layout">
198
+        <table class="layout torrent_search">
199 199
           <tr id="numbers" class="ftr_advanced<?=$HideAdvanced?>">
200 200
             <td class="label">
201 201
               <!--
@@ -607,17 +607,25 @@ View::show_header('Browse Torrents', 'browse');
607 607
           </tr>
608 608
         </table>
609 609
 
610
-        <!-- Result count and submit button -->
610
+        <!-- Result count, submit, and reset -->
611 611
         <div class="submit ft_submit">
612
-          <span class="float_left"><?=number_format($NumResults)?>
613
-            Results</span>
614
-          <input type="submit" value="Search" />
612
+          <span class="float_left">
613
+            <?=number_format($NumResults)?>
614
+            Results
615
+          </span>
616
+
617
+          <input type="submit" value="Search" class="button-primary"/>
618
+
615 619
           <input type="hidden" name="action" id="ft_type"
616 620
             value="<?=($AdvancedSearch ? 'advanced' : 'basic')?>" />
621
+
617 622
           <input type="hidden" name="searchsubmit" value="1" />
623
+
618 624
           <input type="button" value="Reset" <input type="button" value="Reset"
619 625
             onclick="window.location.href = 'torrents.php<?php if (isset($_GET['action']) && $_GET['action'] === 'advanced') { ?>?action=advanced<?php } ?>'" />
626
+
620 627
           &emsp;
628
+
621 629
           <?php if ($Search->has_filters()) { ?>
622 630
           <input type="submit" name="setdefault" value="Make Default" />
623 631
           <?php }

+ 10
- 10
sections/torrents/details.php View File

@@ -322,7 +322,7 @@ $Index++;
322 322
             value="<?=$GroupID?>" />
323 323
           <input type="text" id="artist" name="artistname[]" <?php Users::has_autocomplete_enabled('other'); ?>
324 324
           />
325
-          <input type="submit" value="Add" />
325
+          <input type="submit" class="button-primary" value="Add" />
326 326
         </form>
327 327
       </div>
328 328
     </div>
@@ -396,7 +396,7 @@ $Index++;
396 396
             value="<?=$GroupID?>" />
397 397
           <input type="text" name="tagname" id="tagname" <?php Users::has_autocomplete_enabled('other'); ?>
398 398
           />
399
-          <input type="submit" value="Add" />
399
+          <input type="submit" class="button-primary" value="Add" />
400 400
         </form>
401 401
         <br />
402 402
         <strong><a href="rules.php?p=tag" class="brackets">View tagging rules</a></strong>
@@ -413,16 +413,16 @@ $Index++;
413 413
         class="torrent_table details<?=$GroupFlags['IsSnatched'] ? ' snatched' : ''?>"
414 414
         id="torrent_details">
415 415
         <tr class="colhead_dark">
416
-          <td width="80%"><strong>Torrents</strong></td>
417
-          <td><strong>Size</strong></td>
418
-          <td class="sign snatches">
416
+          <th width="80%"><strong>Torrents</strong></th>
417
+          <th><strong>Size</strong></th>
418
+          <th class="sign snatches">
419 419
420
-          <td class="sign seeders">
420
+          <th class="sign seeders">
421 421
             &uarr;
422
-          </td>
423
-          <td class="sign leechers">
422
+          </th>
423
+          <th class="sign leechers">
424 424
             &darr;
425
-          </td>
425
+          </th>
426 426
         </tr>
427 427
         <?php
428 428
 function filelist($Str)
@@ -851,7 +851,7 @@ if (count($Collages) > 0) {
851 851
     <div class="box">
852 852
       <table class="collage_table" id="collages">
853 853
         <tr class="colhead">
854
-          <td width="75%"><a href="#">&uarr;</a>&nbsp;This content is in <?=number_format(count($Collages))?> collection<?=((count($Collages) > 1) ? 's' : '')?><?=$SeeAll?>
854
+          <td width="85%"><a href="#">&uarr;</a>&nbsp;This content is in <?=number_format(count($Collages))?> collection<?=((count($Collages) > 1) ? 's' : '')?><?=$SeeAll?>
855 855
           </td>
856 856
           <td># torrents</td>
857 857
         </tr>

+ 78
- 78
sections/torrents/user.php View File

@@ -50,43 +50,43 @@ if (!empty($_GET['way']) && array_key_exists($_GET['way'], $Ways)) {
50 50
 $SearchWhere = [];
51 51
 if (!empty($_GET['format'])) {
52 52
     if (in_array($_GET['format'], $Formats)) {
53
-        $SearchWhere[] = "t.Format = '".db_string($_GET['format'])."'";
53
+        $SearchWhere[] = "t.`Format` = '".db_string($_GET['format'])."'";
54 54
     }
55 55
 }
56 56
 
57 57
 # Get release specifics
58 58
 if (isset($_GET['container'])
59 59
  && in_array($_GET['container'], $ENV-flatten($ENV->META->Formats))) {
60
-    $SearchWhere[] = "t.Container = '".db_string($_GET['container'])."'";
60
+    $SearchWhere[] = "t.`Container` = '".db_string($_GET['container'])."'";
61 61
 }
62 62
 
63 63
 if (isset($_GET['bitrate'])
64 64
  && in_array($_GET['bitrate'], $Bitrates)) {
65
-    $SearchWhere[] = "t.Encoding = '".db_string($_GET['bitrate'])."'";
65
+    $SearchWhere[] = "t.`Encoding` = '".db_string($_GET['bitrate'])."'";
66 66
 }
67 67
 
68 68
 if (isset($_GET['media'])
69 69
  && in_array($_GET['media'], $ENV-flatten($ENV->META->Platforms))) {
70
-    $SearchWhere[] = "t.Media = '".db_string($_GET['media'])."'";
70
+    $SearchWhere[] = "t.`Media` = '".db_string($_GET['media'])."'";
71 71
 }
72 72
 
73 73
 if (isset($_GET['codec'])
74 74
  && in_array($_GET['codec'], $ENV->META->Licenses)) {
75
-    $SearchWhere[] = "t.Codec = '".db_string($_GET['codec'])."'";
75
+    $SearchWhere[] = "t.`Codec` = '".db_string($_GET['codec'])."'";
76 76
 }
77 77
 
78 78
 if (isset($_GET['version'])) {
79
-    $SearchWhere[] = "t.Version = '".db_string($_GET['version'])."'";
79
+    $SearchWhere[] = "t.`Version` = '".db_string($_GET['version'])."'";
80 80
 }
81 81
 
82 82
 if (isset($_GET['resolution'])
83 83
  && in_array($_GET['resolution'], $ENV->flatten($ENV->META->Scopes))) {
84
-    $SearchWhere[] = "t.Resolution = '".db_string($_GET['resolution'])."'";
84
+    $SearchWhere[] = "t.`Resolution` = '".db_string($_GET['resolution'])."'";
85 85
 }
86 86
 
87 87
 if (isset($_GET['censored'])
88 88
  && in_array($_GET['censored'], array(1, 0))) {
89
-    $SearchWhere[] = "t.Censored = '".db_string($_GET['censored'])."'";
89
+    $SearchWhere[] = "t.`Censored` = '".db_string($_GET['censored'])."'";
90 90
 }
91 91
 
92 92
 if (!empty($_GET['categories'])) {
@@ -95,7 +95,7 @@ if (!empty($_GET['categories'])) {
95 95
         if (!is_number($Cat)) {
96 96
             error(0);
97 97
         }
98
-        $Cats[] = "tg.CategoryID = '".db_string($Cat)."'";
98
+        $Cats[] = "tg.`category_id` = '".db_string($Cat)."'";
99 99
     }
100 100
     $SearchWhere[] = '('.implode(' OR ', $Cats).')';
101 101
 }
@@ -120,9 +120,9 @@ if (!empty($_GET['tags'])) {
120 120
             if (empty($Tag)) {
121 121
                 continue;
122 122
             }
123
-            $TagList[] = "tg.TagList NOT RLIKE '[[:<:]]".db_string($Tag)."(:[^ ]+)?[[:>:]]'";
123
+            $TagList[] = "tg.`tag_list` NOT RLIKE '[[:<:]]".db_string($Tag)."(:[^ ]+)?[[:>:]]'";
124 124
         } else {
125
-            $TagList[] = "tg.TagList RLIKE '[[:<:]]".db_string($Tag)."(:[^ ]+)?[[:>:]]'";
125
+            $TagList[] = "tg.`tag_list` RLIKE '[[:<:]]".db_string($Tag)."(:[^ ]+)?[[:>:]]'";
126 126
         }
127 127
     }
128 128
 
@@ -151,74 +151,74 @@ switch ($_GET['type']) {
151 151
     if (!check_paranoia('snatched', $User['Paranoia'], $UserClass, $UserID)) {
152 152
         error(403);
153 153
     }
154
-    $Time = 'xs.tstamp';
155
-    $UserField = 'xs.uid';
154
+    $Time = 'xs.`tstamp`';
155
+    $UserField = 'xs.`uid`';
156 156
     $ExtraWhere = '';
157 157
     $From = "
158
-      xbt_snatched AS xs
159
-        JOIN torrents AS t ON t.ID = xs.fid";
158
+      `xbt_snatched` AS xs
159
+        JOIN `torrents` AS t ON t.`ID` = xs.`fid`";
160 160
     break;
161 161
 
162 162
   case 'seeding':
163 163
     if (!check_paranoia('seeding', $User['Paranoia'], $UserClass, $UserID)) {
164 164
         error(403);
165 165
     }
166
-    $Time = '(xfu.mtime - xfu.timespent)';
167
-    $UserField = 'xfu.uid';
166
+    $Time = '(xfu.`mtime` - xfu.`timespent`)';
167
+    $UserField = 'xfu.`uid`';
168 168
     $ExtraWhere = '
169
-      AND xfu.active = 1
170
-      AND xfu.Remaining = 0';
169
+      AND xfu.`active` = 1
170
+      AND xfu.`Remaining` = 0';
171 171
     $From = "
172
-      xbt_files_users AS xfu
173
-        JOIN torrents AS t ON t.ID = xfu.fid";
172
+      `xbt_files_users` AS xfu
173
+        JOIN `torrents` AS t ON t.`ID` = xfu.`fid`";
174 174
     break;
175 175
 
176 176
   case 'contest':
177
-    $Time = 'unix_timestamp(t.Time)';
178
-    $UserField = 't.UserID';
177
+    $Time = 'unix_timestamp(t.`Time`)';
178
+    $UserField = 't.`UserID`';
179 179
     $ExtraWhere = "
180
-      AND t.ID IN (
181
-        SELECT TorrentID
182
-        FROM library_contest
183
-        WHERE UserID = $UserID
180
+      AND t.`ID` IN (
181
+        SELECT `TorrentID`
182
+        FROM `library_contest`
183
+        WHERE `UserID` = $UserID
184 184
       )";
185
-    $From = 'torrents AS t';
185
+    $From = '`torrents` AS t';
186 186
     break;
187 187
 
188 188
   case 'leeching':
189 189
     if (!check_paranoia('leeching', $User['Paranoia'], $UserClass, $UserID)) {
190 190
         error(403);
191 191
     }
192
-    $Time = '(xfu.mtime - xfu.timespent)';
193
-    $UserField = 'xfu.uid';
192
+    $Time = '(xfu.`mtime` - xfu.`timespent`)';
193
+    $UserField = 'xfu.`uid`';
194 194
     $ExtraWhere = '
195
-      AND xfu.active = 1
196
-      AND xfu.Remaining > 0';
195
+      AND xfu.`active` = 1
196
+      AND xfu.`Remaining` > 0';
197 197
     $From = "
198
-      xbt_files_users AS xfu
199
-        JOIN torrents AS t ON t.ID = xfu.fid";
198
+      `xbt_files_users` AS xfu
199
+        JOIN `torrents` AS t ON t.`ID` = xfu.`fid`";
200 200
     break;
201 201
 
202 202
   case 'uploaded':
203 203
     if ((empty($_GET['filter']) || $_GET['filter'] !== 'perfectflac') && !check_paranoia('uploads', $User['Paranoia'], $UserClass, $UserID)) {
204 204
         error(403);
205 205
     }
206
-    $Time = 'unix_timestamp(t.Time)';
207
-    $UserField = 't.UserID';
206
+    $Time = 'unix_timestamp(t.`Time`)';
207
+    $UserField = 't.`UserID`';
208 208
     $ExtraWhere = '';
209
-    $From = "torrents AS t";
209
+    $From = "`torrents` AS t";
210 210
     break;
211 211
 
212 212
   case 'downloaded':
213 213
     if (!check_perms('site_view_torrent_snatchlist')) {
214 214
         error(403);
215 215
     }
216
-    $Time = 'unix_timestamp(ud.Time)';
217
-    $UserField = 'ud.UserID';
216
+    $Time = 'unix_timestamp(ud.`Time`)';
217
+    $UserField = 'ud.`UserID`';
218 218
     $ExtraWhere = '';
219 219
     $From = "
220
-      users_downloads AS ud
221
-        JOIN torrents AS t ON t.ID = ud.TorrentID";
220
+      `users_downloads` AS ud
221
+        JOIN `torrents` AS t ON t.`ID` = ud.`TorrentID`";
222 222
     break;
223 223
     
224 224
   default:
@@ -226,7 +226,7 @@ switch ($_GET['type']) {
226 226
 }
227 227
 
228 228
 if (empty($GroupBy)) {
229
-    $GroupBy = 't.ID';
229
+    $GroupBy = 't.`ID`';
230 230
 }
231 231
 
232 232
 if ((empty($_GET['search'])
@@ -234,13 +234,13 @@ if ((empty($_GET['search'])
234 234
     $SQL = "
235 235
       SELECT
236 236
         SQL_CALC_FOUND_ROWS
237
-        t.GroupID,
238
-        t.ID AS TorrentID,
237
+        t.`GroupID`,
238
+        t.`ID` AS TorrentID,
239 239
         $Time AS Time,
240
-        COALESCE(NULLIF(tg.Name, ''), NULLIF(tg.Title2, ''), tg.NameJP) AS Name,
241
-        tg.CategoryID
240
+        COALESCE(NULLIF(tg.`title`, ''), NULLIF(tg. subject, ''), tg.`object`) AS Name,
241
+        tg.`category_id`
242 242
       FROM $From
243
-        JOIN torrents_group AS tg ON tg.ID = t.GroupID
243
+        JOIN `torrents_group` AS tg ON tg.`id` = t.`GroupID`
244 244
       WHERE $UserField = '$UserID'
245 245
         $ExtraWhere
246 246
         $SearchWhere
@@ -249,38 +249,38 @@ if ((empty($_GET['search'])
249 249
       LIMIT $Limit";
250 250
 } else {
251 251
     $DB->query("
252
-      CREATE TEMPORARY TABLE temp_sections_torrents_user (
253
-        GroupID int(10) unsigned not null,
254
-        TorrentID int(10) unsigned not null,
255
-        Time int(12) unsigned not null,
256
-        CategoryID int(3) unsigned,
257
-        Seeders int(6) unsigned,
258
-        Leechers int(6) unsigned,
259
-        Snatched int(10) unsigned,
260
-        Name mediumtext,
261
-        Size bigint(12) unsigned,
262
-      PRIMARY KEY (TorrentID)) CHARSET=utf8");
252
+      CREATE TEMPORARY TABLE `temp_sections_torrents_user` (
253
+        `GroupID` int(10) unsigned not null,
254
+        `TorrentID` int(10) unsigned not null,
255
+        `Time` int(12) unsigned not null,
256
+        `CategoryID` int(3) unsigned,
257
+        `Seeders` int(6) unsigned,
258
+        `Leechers` int(6) unsigned,
259
+        `Snatched` int(10) unsigned,
260
+        `Name` mediumtext,
261
+        `Size` bigint(12) unsigned,
262
+      PRIMARY KEY (`TorrentID`)) CHARSET=utf8");
263 263
 
264 264
     $DB->query("
265
-      INSERT IGNORE INTO temp_sections_torrents_user
265
+      INSERT IGNORE INTO `temp_sections_torrents_user`
266 266
       SELECT
267
-        t.GroupID,
268
-        t.ID AS TorrentID,
267
+        t.`GroupID`,
268
+        t.`ID` AS TorrentID,
269 269
         $Time AS Time,
270
-        tg.CategoryID,
271
-        t.Seeders,
272
-        t.Leechers,
273
-        t.Snatched,
274
-        CONCAT_WS(' ', GROUP_CONCAT(ag.Name SEPARATOR ' '), ' ', COALESCE(NULLIF(tg.Name,''), NULLIF(tg.Title2,''), tg.NameJP), ' ', tg.Year, ' ') AS Name,
275
-        t.Size
270
+        tg.`category_id`,
271
+        t.`Seeders`,
272
+        t.`Leechers`,
273
+        t.`Snatched`,
274
+        CONCAT_WS(' ', GROUP_CONCAT(ag.`Name` SEPARATOR ' '), ' ', COALESCE(NULLIF(tg.`title`,''), NULLIF(tg.`subject`,''), tg.`object`), ' ', tg.`year`, ' ') AS Name,
275
+        t.`Size`
276 276
       FROM $From
277
-        JOIN torrents_group AS tg ON tg.ID = t.GroupID
278
-        LEFT JOIN torrents_artists AS ta ON ta.GroupID = tg.ID
279
-        LEFT JOIN artists_group AS ag ON ag.ArtistID = ta.ArtistID
277
+        JOIN `torrents_group` AS tg ON tg.`id` = t.`GroupID`
278
+        LEFT JOIN `torrents_artists` AS ta ON ta.`GroupID` = tg.`id`
279
+        LEFT JOIN `artists_group` AS ag ON ag.`ArtistID` = ta.`ArtistID`
280 280
       WHERE $UserField = '$UserID'
281 281
         $ExtraWhere
282 282
         $SearchWhere
283
-      GROUP BY TorrentID, Time");
283
+      GROUP BY `TorrentID`, `Time`");
284 284
 
285 285
     if (!empty($_GET['search']) && trim($_GET['search']) !== '') {
286 286
         $Words = array_unique(explode(' ', db_string($_GET['search'])));
@@ -289,15 +289,15 @@ if ((empty($_GET['search'])
289 289
     $SQL = "
290 290
       SELECT
291 291
         SQL_CALC_FOUND_ROWS
292
-        GroupID,
293
-        TorrentID,
294
-        Time,
295
-        CategoryID
296
-      FROM temp_sections_torrents_user";
292
+        `GroupID`,
293
+        `TorrentID`,
294
+        `Time`,
295
+        `CategoryID`
296
+      FROM `temp_sections_torrents_user`";
297 297
 
298 298
     if (!empty($Words)) {
299 299
         $SQL .= "
300
-          WHERE Name LIKE '%".implode("%' AND Name LIKE '%", $Words)."%'";
300
+          WHERE `Name` LIKE '%".implode("%' AND `Name` LIKE '%", $Words)."%'";
301 301
     }
302 302
 
303 303
     $SQL .= "
@@ -470,7 +470,7 @@ foreach ($Categories as $CatKey => $CatName) {
470 470
           <?= number_format($TorrentCount) ?>
471 471
           Results
472 472
         </span>
473
-        <input type="submit" value="Search" />
473
+        <input type="submit" class="button-primary" value="Search" />
474 474
       </div>
475 475
     </form>
476 476
   </div>

+ 2
- 2
sections/upload/index.php View File

@@ -3,11 +3,11 @@ declare(strict_types=1);
3 3
 
4 4
 enforce_login();
5 5
 if (!check_perms('site_upload')) {
6
-    error(403);
6
+    error('Please read the site wiki for information on how to become a Member and gain upload privileges.', $Debug = false);
7 7
 }
8 8
 
9 9
 if ($LoggedUser['DisableUpload']) {
10
-    error('Your upload privileges have been revoked.');
10
+    error('Your upload privileges have been revoked.', $Debug = false);
11 11
 }
12 12
 
13 13
 // Build the page

+ 21
- 17
sections/user/notify_edit.php View File

@@ -4,6 +4,7 @@
4 4
 if (!check_perms('site_torrents_notify')) {
5 5
     error(403);
6 6
 }
7
+
7 8
 View::show_header(
8 9
     'Manage notifications',
9 10
     'vendor/jquery.validate.min,form_validate'
@@ -21,22 +22,23 @@ View::show_header(
21 22
   <?php
22 23
 $DB->query("
23 24
   SELECT
24
-    ID,
25
-    Label,
26
-    Artists,
27
-    NewGroupsOnly,
28
-    Tags,
29
-    NotTags,
30
-    ReleaseTypes,
31
-    Categories,
32
-    Formats,
33
-    Encodings,
34
-    Media,
35
-    FromYear,
36
-    ToYear,
37
-    Users
38
-  FROM users_notify_filters
39
-  WHERE UserID=$LoggedUser[ID]");
25
+    `ID`,
26
+    `Label`,
27
+    `Artists`,
28
+    `NewGroupsOnly`,
29
+    `Tags`,
30
+    `NotTags`,
31
+    `ReleaseTypes`,
32
+    `Categories`,
33
+    `Formats`,
34
+    `Encodings`,
35
+    `Media`,
36
+    `FromYear`,
37
+    `ToYear`,
38
+    `Users`
39
+  FROM `users_notify_filters`
40
+  WHERE `UserID` = $LoggedUser[ID]
41
+");
40 42
 
41 43
 $NumFilters = $DB->record_count();
42 44
 
@@ -82,9 +84,11 @@ foreach ($Notifications as $N) { // $N stands for Notifications
82 84
     if ($N['FromYear'] === 0) {
83 85
         $N['FromYear'] = '';
84 86
     }
87
+
85 88
     if ($N['ToYear'] === 0) {
86 89
         $N['ToYear'] = '';
87 90
     }
91
+
88 92
     if ($NewFilter && $NumFilters > 0) {
89 93
         ?>
90 94
   <br><br>
@@ -207,7 +211,7 @@ foreach ($Notifications as $N) { // $N stands for Notifications
207 211
 
208 212
       <tr>
209 213
         <td colspan="2" class="center">
210
-          <input type="submit"
214
+          <input type="submit" class="button-primary"
211 215
             value="<?=($NewFilter ? 'Create' : 'Update')?>">
212 216
         </td>
213 217
       </tr>

+ 2
- 2
sections/user/user.php View File

@@ -1514,7 +1514,7 @@ if (!$DisablePoints) {
1514 1514
       <?php } ?>
1515 1515
     </table>
1516 1516
     <?php if (check_perms('users_disable_any')) { ?>
1517
-    <table class="layout box">
1517
+    <table class="layout box" id="user_lock_account">
1518 1518
       <tr class="colhead">
1519 1519
         <td colspan="2">
1520 1520
           Lock Account
@@ -1703,7 +1703,7 @@ if (!$DisablePoints) {
1703 1703
 
1704 1704
       <tr>
1705 1705
         <td align="right" colspan="2">
1706
-          <input type="submit" value="Save changes" />
1706
+          <input type="submit" class="button-primary" value="Save changes" />
1707 1707
         </td>
1708 1708
       </tr>
1709 1709
     </table>

+ 59
- 55
sections/userhistory/subscriptions.php View File

@@ -1,7 +1,7 @@
1 1
 <?php
2 2
 #declare(strict_types=1);
3 3
 
4
-/*
4
+/**
5 5
  * User subscription page
6 6
  */
7 7
 
@@ -38,54 +38,54 @@ $ShowCollapsed = (!isset($_GET['collapse']) && !isset($HeavyInfo['SubscriptionsC
38 38
 $DB->query("
39 39
   (SELECT
40 40
     SQL_CALC_FOUND_ROWS
41
-    s.Page,
42
-    s.PageID,
43
-    lr.PostID,
41
+    s.`Page`,
42
+    s.`PageID`,
43
+    lr.`PostID`,
44 44
     null AS ForumID,
45 45
     null AS ForumName,
46
-    IF(s.Page = 'artist', a.Name, co.Name) AS Name,
47
-    c.ID AS LastPost,
48
-    c.AddedTime AS LastPostTime,
49
-    c_lr.Body AS LastReadBody,
50
-    c_lr.EditedTime AS LastReadEditedTime,
51
-    um.ID AS LastReadUserID,
52
-    um.Username AS LastReadUsername,
53
-    ui.Avatar AS LastReadAvatar,
54
-    c_lr.EditedUserID AS LastReadEditedUserID
55
-  FROM users_subscriptions_comments AS s
56
-    LEFT JOIN users_comments_last_read AS lr ON lr.UserID = $LoggedUser[ID] AND lr.Page = s.Page AND lr.PageID = s.PageID
57
-    LEFT JOIN artists_group AS a ON s.Page = 'artist' AND a.ArtistID = s.PageID
58
-    LEFT JOIN collages AS co ON s.Page = 'collages' AND co.ID = s.PageID
59
-    LEFT JOIN comments AS c ON c.ID = (
60
-          SELECT MAX(ID)
61
-          FROM comments
62
-          WHERE Page = s.Page
63
-            AND PageID = s.PageID
46
+    IF(s.`Page` = 'artist', a.`Name`, co.`Name`) AS Name,
47
+    c.`ID` AS LastPost,
48
+    c.`AddedTime` AS LastPostTime,
49
+    c_lr.`Body` AS LastReadBody,
50
+    c_lr.`EditedTime` AS LastReadEditedTime,
51
+    um.`ID` AS LastReadUserID,
52
+    um.`Username` AS LastReadUsername,
53
+    ui.`Avatar` AS LastReadAvatar,
54
+    c_lr.`EditedUserID` AS LastReadEditedUserID
55
+  FROM `users_subscriptions_comments` AS s
56
+    LEFT JOIN `users_comments_last_read` AS lr ON lr.`UserID` = $LoggedUser[ID] AND lr.`Page` = s.`Page` AND lr.`PageID` = s.`PageID`
57
+    LEFT JOIN `artists_group` AS a ON s.`Page` = 'artist' AND a.`ArtistID` = s.`PageID`
58
+    LEFT JOIN `collages` AS co ON s.`Page` = 'collages' AND co.`ID` = s.`PageID`
59
+    LEFT JOIN `comments` AS c ON c.`ID` = (
60
+          SELECT MAX(`ID`)
61
+          FROM `comments`
62
+          WHERE `Page` = s.`Page`
63
+            AND `PageID` = s.`PageID`
64 64
         )
65
-    LEFT JOIN comments AS c_lr ON c_lr.ID = lr.PostID
66
-    LEFT JOIN users_main AS um ON um.ID = c_lr.AuthorID
67
-    LEFT JOIN users_info AS ui ON ui.UserID = um.ID
68
-  WHERE s.UserID = $LoggedUser[ID] AND s.Page IN ('artist', 'collages', 'requests', 'torrents') AND (s.Page != 'collages' OR co.Deleted = '0')" . ($ShowUnread ? ' AND c.ID > IF(lr.PostID IS NULL, 0, lr.PostID)' : '') . "
69
-  GROUP BY s.PageID)
65
+    LEFT JOIN `comments` AS c_lr ON c_lr.`ID` = lr.`PostID`
66
+    LEFT JOIN `users_main` AS um ON um.`ID` = c_lr.`AuthorID`
67
+    LEFT JOIN `users_info` AS ui ON ui.`UserID` = um.`ID`
68
+  WHERE s.`UserID` = $LoggedUser[ID] AND s.`Page` IN ('artist', 'collages', 'requests', 'torrents') AND (s.`Page` != 'collages' OR co.`Deleted` = '0')" . ($ShowUnread ? ' AND c.`ID` > IF(lr.`PostID` IS NULL, 0, lr.`PostID`)' : '') . "
69
+  GROUP BY s.`PageID`)
70 70
   UNION ALL
71
-  (SELECT 'forums', s.TopicID, lr.PostID, f.ID, f.Name, t.Title, p.ID, p.AddedTime, p_lr.Body, p_lr.EditedTime, um.ID, um.Username, ui.Avatar, p_lr.EditedUserID
72
-  FROM users_subscriptions AS s
73
-    LEFT JOIN forums_last_read_topics AS lr ON lr.UserID = $LoggedUser[ID] AND s.TopicID = lr.TopicID
74
-    LEFT JOIN forums_topics AS t ON t.ID = s.TopicID
75
-    LEFT JOIN forums AS f ON f.ID = t.ForumID
76
-    LEFT JOIN forums_posts AS p ON p.ID = (
77
-          SELECT MAX(ID)
78
-          FROM forums_posts
79
-          WHERE TopicID = s.TopicID
71
+  (SELECT 'forums', s.`TopicID`, lr.`PostID`, f.`ID`, f.`Name`, t.`Title`, p.`ID`, p.`AddedTime`, p_lr.`Body`, p_lr.`EditedTime`, um.`ID`, um.`Username`, ui.`Avatar`, p_lr.`EditedUserID`
72
+  FROM `users_subscriptions` AS s
73
+    LEFT JOIN `forums_last_read_topics` AS lr ON lr.`UserID` = $LoggedUser[ID] AND s.`TopicID` = lr.`TopicID`
74
+    LEFT JOIN `forums_topics` AS t ON t.`ID` = s.`TopicID`
75
+    LEFT JOIN `forums` AS f ON f.`ID` = t.`ForumID`
76
+    LEFT JOIN `forums_posts` AS p ON p.`ID` = (
77
+          SELECT MAX(`ID`)
78
+          FROM `forums_posts`
79
+          WHERE `TopicID` = s.`TopicID`
80 80
         )
81
-    LEFT JOIN forums_posts AS p_lr ON p_lr.ID = lr.PostID
82
-    LEFT JOIN users_main AS um ON um.ID = p_lr.AuthorID
83
-    LEFT JOIN users_info AS ui ON ui.UserID = um.ID
84
-  WHERE s.UserID = $LoggedUser[ID]" .
85
-    ($ShowUnread ? " AND p.ID > IF(t.IsLocked = '1' AND t.IsSticky = '0'" . ", p.ID, IF(lr.PostID IS NULL, 0, lr.PostID))" : '') .
81
+    LEFT JOIN `forums_posts` AS p_lr ON p_lr.`ID` = lr.`PostID`
82
+    LEFT JOIN `users_main` AS um ON um.`ID` = p_lr.`AuthorID`
83
+    LEFT JOIN `users_info` AS ui ON ui.`UserID` = um.`ID`
84
+  WHERE s.`UserID` = $LoggedUser[ID]" .
85
+    ($ShowUnread ? " AND p.`ID` > IF(t.`IsLocked` = '1' AND t.`IsSticky` = '0'" . ", p.`ID`, IF(lr.`PostID` IS NULL, 0, lr.`PostID`))" : '') .
86 86
     ' AND ' . Forums::user_forums_sql() . "
87
-  GROUP BY t.ID)
88
-  ORDER BY LastPostTime DESC
87
+  GROUP BY t.`ID`)
88
+  ORDER BY `LastPostTime` DESC
89 89
   LIMIT $Limit");
90 90
 
91 91
 $Results = $DB->to_array(false, MYSQLI_ASSOC, false);
@@ -162,41 +162,44 @@ if (!$NumResults) {
162 162
         $Links = 'Artist: <a href="artist.php?id=' . $Result['PageID'] . '">' . display_str($Result['Name']) . '</a>';
163 163
         $JumpLink = 'artist.php?id=' . $Result['PageID'] . '&amp;postid=' . $Result['PostID'] . '#post' . $Result['PostID'];
164 164
         break;
165
+
166
+
165 167
       case 'collages':
166 168
         $Links = 'Collage: <a href="collages.php?id=' . $Result['PageID'] . '">' . display_str($Result['Name']) . '</a>';
167 169
         $JumpLink = 'collages.php?action=comments&collageid=' . $Result['PageID'] . '&amp;postid=' . $Result['PostID'] . '#post' . $Result['PostID'];
168 170
         break;
171
+
172
+
169 173
       case 'requests':
170 174
         if (!isset($Requests[$Result['PageID']])) {
171 175
             continue;
172 176
         }
177
+
173 178
         $Request = $Requests[$Result['PageID']];
174 179
         $CategoryName = $Categories[$CategoryID - 1];
175 180
 
176 181
         $Links = 'Request: ';
177
-        /*
178
-        if ($CategoryName == 'Music' || $CategoryName == 'Audiobooks' || $CategoryName == 'Comedy') {
179
-            $Links .= ($CategoryName == 'Music' ? Artists::display_artists(Requests::get_artists($Result['PageID'])) : '') . '<a href="requests.php?action=view&amp;id=' . $Result['PageID'] . '" dir="ltr">' . $Request['Title'] . " [" . $Request['Year'] . "]</a>";
180
-        } else {
181
-          */
182 182
             $Links .= '<a href="requests.php?action=view&amp;id=' . $Result['PageID'] . '">' . $Request['Title'] . "</a>";
183
-        #} # else
184 183
         $JumpLink = 'requests.php?action=view&amp;id=' . $Result['PageID'] . '&amp;postid=' . $Result['PostID'] . '#post' . $Result['PostID'];
185 184
         break;
185
+
186
+
186 187
       case 'torrents':
187 188
         if (!isset($TorrentGroups[$Result['PageID']])) {
188 189
             continue;
189 190
         }
191
+
190 192
         $GroupInfo = $TorrentGroups[$Result['PageID']];
191
-        $Links = 'Torrent: ' . Artists::display_artists($GroupInfo['ExtendedArtists']) . '<a href="torrents.php?id=' . $GroupInfo['ID'] . '" dir="ltr">' . $GroupInfo['Name'] . '</a>';
192
-        if ($GroupInfo['Year'] > 0) {
193
-            $Links .= " [" . $GroupInfo['Year'] . "]";
194
-        }
195
-        if ($GroupInfo['ReleaseType'] > 0) {
196
-            $Links .= " [" . $ReleaseTypes[$GroupInfo['ReleaseType']] . "]";
193
+        $Links = 'Torrent: ' . Artists::display_artists($GroupInfo['ExtendedArtists']) . '<a href="torrents.php?id=' . $GroupInfo['id'] . '" dir="ltr">' . $GroupInfo['title'] . '</a>';
194
+       
195
+        if ($GroupInfo['year'] > 0) {
196
+            $Links .= " [" . $GroupInfo['year'] . "]";
197 197
         }
198
+
198 199
         $JumpLink = 'torrents.php?id=' . $GroupInfo['ID'] . '&amp;postid=' . $Result['PostID'] . '#post' . $Result['PostID'];
199 200
         break;
201
+
202
+
200 203
       case 'forums':
201 204
         $Links = 'Forums: <a href="forums.php?action=viewforum&amp;forumid=' . $Result['ForumID'] . '">' . display_str($Result['ForumName']) . '</a> &gt; ' .
202 205
           '<a href="forums.php?action=viewthread&amp;threadid=' . $Result['PageID'] .
@@ -205,6 +208,7 @@ if (!$NumResults) {
205 208
           '</a>';
206 209
         $JumpLink = 'forums.php?action=viewthread&amp;threadid=' . $Result['PageID'] . '&amp;postid=' . $Result['PostID'] . '#post' . $Result['PostID'];
207 210
         break;
211
+
208 212
       default:
209 213
         error(0);
210 214
     } ?>

+ 1
- 1
sections/wiki/article.php View File

@@ -83,7 +83,7 @@ View::show_header($Title, 'wiki,bbcode');
83 83
         <form class="search_form" name="articles" action="wiki.php" method="get">
84 84
           <input type="hidden" name="action" value="search" />
85 85
           <input type="search" placeholder="Search articles" name="search" size="20" />
86
-          <input value="Search" type="submit" class="hidden" />
86
+          <input value="Search" type="submit" class="hidden button-primary" />
87 87
         </form>
88 88
 
89 89
         <br style="line-height: 10px;" />

+ 1
- 1
sections/wiki/wiki_browse.php View File

@@ -68,7 +68,7 @@ while (list($ID, $Title, $Date, $UserID) = $DB->next_record()) { ?>
68 68
       <input type="hidden" name="action" value="search" />
69 69
       <input type="hidden" name="nojump" value="1" />
70 70
       <input type="search" name="search" size="80" />
71
-      <input value="Search" type="submit" class="hidden" />
71
+      <input value="Search" type="submit" class="hidden button-primary" />
72 72
     </form>
73 73
     <br />
74 74
 

BIN
static/common/logos/torrents.bio.png View File


+ 254
- 217
static/functions/upload.js View File

@@ -1,136 +1,163 @@
1 1
 /**
2 2
  * Categories
3
- * 
3
+ *
4 4
  * Toggle category metadata.
5 5
  * Displays dynamic selects on upload.php.
6 6
  * These change with each category.
7 7
  */
8 8
 function Categories() {
9 9
   let def = [
10
-    'javdb', // Accession Number
11
-    'audio', // Version
12
-    'title', // Torrent Title
13
-    'title_rj', // Organism
14
-    'title_jp', // Strain/Variety
15
-    'artists', // Authors(s)
16
-    'studio', // Department/Lab
17
-    'series', // Location
18
-    'year', // Year
19
-    'codec', // License
10
+    "javdb", // Accession Number
11
+    "audio", // Version
12
+    "title", // Torrent Title
13
+    "title_rj", // Organism
14
+    "title_jp", // Strain/Variety
15
+    "artists", // Authors(s)
16
+    "studio", // Department/Lab
17
+    "series", // Location
18
+    "year", // Year
19
+    "codec", // License
20 20
     // Platform *changes below*
21
-    'resolution', // Scope *changes below*
21
+    "resolution", // Scope *changes below*
22 22
     // Format *changes below*
23
-    'archive', // Archive
24
-    'tags', // Tags
25
-    'cover', // Picture
26
-    'mirrors', // Mirrors
27
-    'screenshots', // Publications
28
-    'group_desc', // Torrent Group Description
29
-    'release_desc', // Torrent Description
30
-    'censored', // Aligned/Annotated
31
-    'anon', // Upload Anonymously
32
-  ]
23
+    "archive", // Archive
24
+    "tags", // Tags
25
+    "cover", // Picture
26
+    "mirrors", // Mirrors
27
+    "screenshots", // Publications
28
+    //'seqhash', // Seqhash
29
+    "group_desc", // Torrent Group Description
30
+    "release_desc", // Torrent Description
31
+    "censored", // Aligned/Annotated
32
+    "anon", // Upload Anonymously
33
+  ];
33 34
 
34 35
   let cats = [
35
-    { // Sequences
36
-      'media': {}, // Platform
37
-      'container': {}, // Format
36
+    {
37
+      // Sequences
38
+      media: {}, // Platform
39
+      container: {}, // Format
40
+      seqhash: {}, // Seqhash
38 41
     },
39
-    { // Graphs
40
-      'media_graphs': {}, // Platform
41
-      'container_graphs': {}, // Format
42
+    {
43
+      // Graphs
44
+      media_graphs: {}, // Platform
45
+      container_graphs: {}, // Format
42 46
     },
43
-    { // Systems
44
-      'media_graphs': {}, // Platform
45
-      'container_graphs': {}, // Format
47
+    {
48
+      // Systems
49
+      media_graphs: {}, // Platform
50
+      container_graphs: {}, // Format
46 51
     },
47
-    { // Geometric
48
-      'media_graphs': {}, // Platform
49
-      'container_graphs': {}, // Format
52
+    {
53
+      // Geometric
54
+      media_graphs: {}, // Platform
55
+      container_graphs: {}, // Format
50 56
     },
51
-    { // Scalars/Vectors
52
-      'media_scalars_vectors': {}, // Platform
53
-      'container_scalars_vectors': {}, // Format
57
+    {
58
+      // Scalars/Vectors
59
+      media_scalars_vectors: {}, // Platform
60
+      container_scalars_vectors: {}, // Format
54 61
     },
55
-    { // Patterns
56
-      'media_graphs': {}, // Platform
57
-      'container_graphs': {}, // Format
62
+    {
63
+      // Patterns
64
+      media_graphs: {}, // Platform
65
+      container_graphs: {}, // Format
58 66
     },
59
-    { // Constraints
60
-      'media_graphs': {}, // Platform
61
-      'container_graphs': {}, // Format
67
+    {
68
+      // Constraints
69
+      media_graphs: {}, // Platform
70
+      container_graphs: {}, // Format
62 71
     },
63
-    { // Images
64
-      'media_images': {}, // Platform
65
-      'container_images': {}, // Format
72
+    {
73
+      // Images
74
+      media_images: {}, // Platform
75
+      container_images: {}, // Format
66 76
     },
67
-    { // Spatial
68
-      'media_graphs': {}, // Platform
69
-      'container_spatial': {}, // Format
77
+    {
78
+      // Spatial
79
+      media_graphs: {}, // Platform
80
+      container_spatial: {}, // Format
70 81
     },
71
-    { // Models
72
-      'media_graphs': {}, // Platform
73
-      'container_spatial': {}, // Format
82
+    {
83
+      // Models
84
+      media_graphs: {}, // Platform
85
+      container_spatial: {}, // Format
74 86
     },
75
-    { // Documents
76
-      'media_documents': {}, // Platform
77
-      'container_documents': {}, // Format
87
+    {
88
+      // Documents
89
+      media_documents: {}, // Platform
90
+      container_documents: {}, // Format
78 91
     },
79
-    { // Machine Data
80
-      'media_machine_data': {}, // Platform
81
-      'container': {}, // Format
92
+    {
93
+      // Machine Data
94
+      media_machine_data: {}, // Platform
95
+      container: {}, // Format
82 96
     },
83
-  ]
84
-
85
-  let active = {}
86
-  for (let field of def) active[field] = {}
87
-
88
-  let category = 0
89
-  if ($('input[name="type"]').raw()) category = $('input[name="type"]').raw().value
90
-  if ($('#categories').raw()) category = $('#categories').raw().value
91
-  active = Object.assign(active, cats[category])
92
-
93
-  let hide = el => {
94
-    Array.from($(`#${el.id} input, #${el.id} select, #${el.id} textarea`)).forEach(inp => inp.disabled = true)
95
-    $(el).ghide()
96
-  }
97
-
98
-  let show = el => {
99
-    Array.from($(`#${el.id} input, #${el.id} select, #${el.id} textarea`)).forEach(inp => inp.disabled = false)
100
-    $(el).gshow()
101
-  }
102
-
103
-  let trs = $('#dynamic_form tr')
97
+  ];
98
+
99
+  let active = {};
100
+  for (let field of def) active[field] = {};
101
+
102
+  let category = 0;
103
+  if ($('input[name="type"]').raw())
104
+    category = $('input[name="type"]').raw().value;
105
+  if ($("#categories").raw()) category = $("#categories").raw().value;
106
+  active = Object.assign(active, cats[category]);
107
+
108
+  let hide = (el) => {
109
+    Array.from(
110
+      $(`#${el.id} input, #${el.id} select, #${el.id} textarea`)
111
+    ).forEach((inp) => (inp.disabled = true));
112
+    $(el).ghide();
113
+  };
114
+
115
+  let show = (el) => {
116
+    Array.from(
117
+      $(`#${el.id} input, #${el.id} select, #${el.id} textarea`)
118
+    ).forEach((inp) => (inp.disabled = false));
119
+    $(el).gshow();
120
+  };
121
+
122
+  let trs = $("#dynamic_form tr");
104 123
   for (let tr of trs) {
105
-    let field = tr.id.slice(0, -3)
124
+    let field = tr.id.slice(0, -3);
106 125
     if (active[field]) {
107 126
       if (active[field].name) {
108
-        tr.children[0].innerHTML = active[field].name
127
+        tr.children[0].innerHTML = active[field].name;
109 128
       }
110 129
 
111
-      let notes = $(`#${tr.id} p.notes`).raw()
112
-      if (notes) notes.innerHTML = active[field].notes || ''
113
-      show(tr)
130
+      let notes = $(`#${tr.id} p.notes`).raw();
131
+      if (notes) notes.innerHTML = active[field].notes || "";
132
+      show(tr);
114 133
     } else {
115
-      hide(tr)
134
+      hide(tr);
116 135
     }
117 136
   }
118 137
 }
119 138
 
120
-
121 139
 /**
122 140
  * add_tag
123 141
  */
124 142
 function add_tag() {
125
-  if ($('#tags').raw().value == "") {
126
-    $('#tags').raw().value = $('#genre_tags').raw().options[$('#genre_tags').raw().selectedIndex].value;
127
-  } else if ($('#genre_tags').raw().options[$('#genre_tags').raw().selectedIndex].value == '---') {
143
+  if ($("#tags").raw().value == "") {
144
+    $("#tags").raw().value =
145
+      $("#genre_tags").raw().options[
146
+        $("#genre_tags").raw().selectedIndex
147
+      ].value;
148
+  } else if (
149
+    $("#genre_tags").raw().options[$("#genre_tags").raw().selectedIndex]
150
+      .value == "---"
151
+  ) {
128 152
   } else {
129
-    $('#tags').raw().value = $('#tags').raw().value + ', ' + $('#genre_tags').raw().options[$('#genre_tags').raw().selectedIndex].value;
153
+    $("#tags").raw().value =
154
+      $("#tags").raw().value +
155
+      ", " +
156
+      $("#genre_tags").raw().options[$("#genre_tags").raw().selectedIndex]
157
+        .value;
130 158
   }
131 159
 }
132 160
 
133
-
134 161
 /**
135 162
  * AddLogField
136 163
  */
@@ -146,13 +173,12 @@ function AddLogField() {
146 173
   LogField.name = "logfiles[]";
147 174
   LogField.size = 50;
148 175
 
149
-  var x = $('#logfields').raw();
176
+  var x = $("#logfields").raw();
150 177
   x.appendChild(document.createElement("br"));
151 178
   x.appendChild(LogField);
152 179
   LogCount++;
153 180
 }
154 181
 
155
-
156 182
 /**
157 183
  * RemoveLogField
158 184
  */
@@ -161,14 +187,13 @@ function RemoveLogField() {
161 187
     return;
162 188
   }
163 189
 
164
-  var x = $('#logfields').raw();
190
+  var x = $("#logfields").raw();
165 191
   for (i = 0; i < 2; i++) {
166 192
     x.removeChild(x.lastChild);
167 193
   }
168 194
   LogCount--;
169 195
 }
170 196
 
171
-
172 197
 /**
173 198
  * AddExtraLogField
174 199
  */
@@ -184,13 +209,12 @@ function AddExtraLogField(id) {
184 209
   LogField.name = "logfiles_" + id + "[]";
185 210
   LogField.size = 50;
186 211
 
187
-  var x = $('#logfields_' + id).raw();
212
+  var x = $("#logfields_" + id).raw();
188 213
   x.appendChild(document.createElement("br"));
189 214
   x.appendChild(LogField);
190 215
   LogCount++;
191 216
 }
192 217
 
193
-
194 218
 /**
195 219
  * RemoveLogField
196 220
  */
@@ -199,14 +223,13 @@ function RemoveLogField() {
199 223
     return;
200 224
   }
201 225
 
202
-  var x = $('#logfields').raw();
226
+  var x = $("#logfields").raw();
203 227
   for (i = 0; i < 2; i++) {
204 228
     x.removeChild(x.lastChild);
205 229
   }
206 230
   LogCount--;
207 231
 }
208 232
 
209
-
210 233
 /**
211 234
  * AddFormat
212 235
  */
@@ -217,11 +240,14 @@ function AddFormat() {
217 240
   }
218 241
 
219 242
   FormatCount++;
220
-  $('#extras').raw().value = FormatCount;
243
+  $("#extras").raw().value = FormatCount;
221 244
 
222 245
   var NewRow = document.createElement("tr");
223 246
   NewRow.id = "new_torrent_row" + FormatCount;
224
-  NewRow.setAttribute("style", "border-top-width: 5px; border-left-width: 5px; border-right-width: 5px;");
247
+  NewRow.setAttribute(
248
+    "style",
249
+    "border-top-width: 5px; border-left-width: 5px; border-right-width: 5px;"
250
+  );
225 251
 
226 252
   var NewCell1 = document.createElement("td");
227 253
   NewCell1.setAttribute("class", "label");
@@ -240,13 +266,17 @@ function AddFormat() {
240 266
 
241 267
   NewRow = document.createElement("tr");
242 268
   NewRow.id = "new_format_row" + FormatCount;
243
-  NewRow.setAttribute("style", "border-left-width: 5px; border-right-width: 5px;");
269
+  NewRow.setAttribute(
270
+    "style",
271
+    "border-left-width: 5px; border-right-width: 5px;"
272
+  );
244 273
   NewCell1 = document.createElement("td");
245 274
   NewCell1.setAttribute("class", "label");
246 275
   NewCell1.innerHTML = "Extra Format / Bitrate";
247 276
 
248 277
   NewCell2 = document.createElement("td");
249
-  tmp = '<select id="releasetype" name="extra_formats[]"><option value="">---</option>';
278
+  tmp =
279
+    '<select id="releasetype" name="extra_formats[]"><option value="">---</option>';
250 280
   var formats = ["Saab", "Volvo", "BMW"];
251 281
 
252 282
   for (var i in formats) {
@@ -255,7 +285,8 @@ function AddFormat() {
255 285
 
256 286
   tmp += "</select>";
257 287
   var bitrates = ["1", "2", "3"];
258
-  tmp += '<select id="releasetype" name="extra_bitrates[]"><option value="">---</option>';
288
+  tmp +=
289
+    '<select id="releasetype" name="extra_bitrates[]"><option value="">---</option>';
259 290
 
260 291
   for (var i in bitrates) {
261 292
     tmp += '<option value="' + bitrates[i] + '">' + bitrates[i] + "</option>\n";
@@ -266,22 +297,24 @@ function AddFormat() {
266 297
   NewRow.appendChild(NewCell1);
267 298
   NewRow.appendChild(NewCell2);
268 299
 
269
-
270 300
   NewRow = document.createElement("tr");
271 301
   NewRow.id = "new_description_row" + FormatCount;
272
-  NewRow.setAttribute("style", "border-bottom-width: 5px; border-left-width: 5px; border-right-width: 5px;");
302
+  NewRow.setAttribute(
303
+    "style",
304
+    "border-bottom-width: 5px; border-left-width: 5px; border-right-width: 5px;"
305
+  );
273 306
   NewCell1 = document.createElement("td");
274 307
   NewCell1.setAttribute("class", "label");
275 308
   NewCell1.innerHTML = "Extra Release Description";
276 309
 
277 310
   NewCell2 = document.createElement("td");
278
-  NewCell2.innerHTML = '<textarea name="extra_release_desc[]" id="release_desc" cols="60" rows="4"></textarea>';
311
+  NewCell2.innerHTML =
312
+    '<textarea name="extra_release_desc[]" id="release_desc" cols="60" rows="4"></textarea>';
279 313
 
280 314
   NewRow.appendChild(NewCell1);
281 315
   NewRow.appendChild(NewCell2);
282 316
 }
283 317
 
284
-
285 318
 /**
286 319
  * RemoveFormat
287 320
  */
@@ -290,27 +323,26 @@ function RemoveFormat() {
290 323
     return;
291 324
   }
292 325
 
293
-  $('#extras').raw().value = FormatCount;
326
+  $("#extras").raw().value = FormatCount;
294 327
 
295
-  var x = $('#new_torrent_row' + FormatCount).raw();
328
+  var x = $("#new_torrent_row" + FormatCount).raw();
296 329
   x.parentNode.removeChild(x);
297 330
 
298
-  x = $('#new_format_row' + FormatCount).raw();
331
+  x = $("#new_format_row" + FormatCount).raw();
299 332
   x.parentNode.removeChild(x);
300 333
 
301
-  x = $('#new_description_row' + FormatCount).raw();
334
+  x = $("#new_description_row" + FormatCount).raw();
302 335
   x.parentNode.removeChild(x);
303 336
 
304 337
   FormatCount--;
305 338
 }
306 339
 
307
-
308 340
 /**
309 341
  * AddArtistField
310 342
  */
311 343
 var ArtistCount = 1;
312 344
 function AddArtistField() {
313
-  window.getSelection().removeAllRanges()
345
+  window.getSelection().removeAllRanges();
314 346
   ArtistCount = $('input[name="artists[]"]').length;
315 347
 
316 348
   if (ArtistCount >= 200) {
@@ -323,47 +355,45 @@ function AddArtistField() {
323 355
   ArtistField.name = "artists[]";
324 356
   ArtistField.size = 45;
325 357
 
326
-  var x = $('#artistfields').raw();
358
+  var x = $("#artistfields").raw();
327 359
   x.appendChild(document.createElement("br"));
328 360
   x.appendChild(ArtistField);
329
-  x.appendChild(document.createTextNode('\n'));
361
+  x.appendChild(document.createTextNode("\n"));
330 362
 
331 363
   if ($("#artist_0").data("gazelle-autocomplete")) {
332
-    $(ArtistField).on('focus', function () {
364
+    $(ArtistField).on("focus", function () {
333 365
       $(ArtistField).autocomplete({
334
-        serviceUrl: ARTIST_AUTOCOMPLETE_URL
366
+        serviceUrl: ARTIST_AUTOCOMPLETE_URL,
335 367
       });
336 368
     });
337 369
   }
338 370
   ArtistCount++;
339 371
 }
340 372
 
341
-
342 373
 /**
343 374
  * RemoveArtistField
344 375
  */
345 376
 function RemoveArtistField() {
346
-  window.getSelection().removeAllRanges()
377
+  window.getSelection().removeAllRanges();
347 378
   ArtistCount = $('input[name="artists[]"]').length;
348 379
 
349 380
   if (ArtistCount == 1) {
350 381
     return;
351 382
   }
352 383
 
353
-  var x = $('#artistfields').raw();
384
+  var x = $("#artistfields").raw();
354 385
   for (i = 0; i < 3; i++) {
355 386
     x.removeChild(x.lastChild);
356 387
   }
357 388
   ArtistCount--;
358 389
 }
359 390
 
360
-
361 391
 /**
362 392
  * AddScreenshotField
363 393
  */
364 394
 function AddScreenshotField() {
365
-  var sss = $('[name="screenshots[]"]')
366
-  if (sss.length >= 10) return
395
+  var sss = $('[name="screenshots[]"]');
396
+  if (sss.length >= 10) return;
367 397
 
368 398
   var ScreenshotField = document.createElement("input");
369 399
   ScreenshotField.type = "text";
@@ -371,177 +401,184 @@ function AddScreenshotField() {
371 401
   ScreenshotField.name = "screenshots[]";
372 402
   ScreenshotField.size = 45;
373 403
 
374
-  var a = document.createElement("a")
375
-  a.className = "brackets"
376
-  a.innerHTML = "−"
377
-  a.onclick = function () { RemoveScreenshotField(this) }
404
+  var a = document.createElement("a");
405
+  a.className = "brackets";
406
+  a.innerHTML = "−";
407
+  a.onclick = function () {
408
+    RemoveScreenshotField(this);
409
+  };
378 410
 
379
-  var x = $('#screenshots').raw()
380
-  var y = document.createElement("div")
411
+  var x = $("#screenshots").raw();
412
+  var y = document.createElement("div");
381 413
   y.appendChild(ScreenshotField);
382
-  y.appendChild(document.createTextNode('\n'));
414
+  y.appendChild(document.createTextNode("\n"));
383 415
   y.appendChild(a);
384 416
   x.appendChild(y);
385 417
 }
386 418
 function RemoveScreenshotField(el) {
387
-  var sss = $('[name="screenshots[]"]')
388
-  el.parentElement.remove()
419
+  var sss = $('[name="screenshots[]"]');
420
+  el.parentElement.remove();
389 421
 }
390 422
 
391
-
392 423
 /**
393 424
  * AnimeAutofill
394 425
  */
395 426
 function AnimeAutofill() {
396 427
   var map = {
397
-    artist: 'artist_0',
398
-    title: 'title',
399
-    title_rj: 'title_rj',
400
-    title_jp: 'title_jp',
401
-    year: 'year',
402
-    description: 'album_desc'
403
-  }
404
-
405
-  var aid = $('#anidb').raw().value
406
-  $.getJSON('/api.php?action=autofill&cat=anime&aid=' + aid, function (data) {
407
-    if (data.status != "success") return
428
+    artist: "artist_0",
429
+    title: "title",
430
+    title_rj: "title_rj",
431
+    title_jp: "title_jp",
432
+    year: "year",
433
+    description: "album_desc",
434
+  };
435
+
436
+  var aid = $("#anidb").raw().value;
437
+  $.getJSON("/api.php?action=autofill&cat=anime&aid=" + aid, function (data) {
438
+    if (data.status != "success") return;
408 439
     for (i in data.response) {
409
-      if (map[i] && !($('#' + map[i]).raw().value)) {
410
-        $('#' + map[i]).raw().value = data.response[i]
440
+      if (map[i] && !$("#" + map[i]).raw().value) {
441
+        $("#" + map[i]).raw().value = data.response[i];
411 442
       }
412 443
     }
413
-  })
444
+  });
414 445
 }
415 446
 
416
-
417 447
 /**
418 448
  * JavAutofill
419 449
  */
420 450
 function JavAutofill() {
421 451
   var map = {
422
-    cn: 'javdb',
423
-    artists: 'artists',
424
-    title: 'title',
425
-    title_jp: 'title_jp',
426
-    year: 'year',
427
-    studio: 'studio',
428
-    image: 'image',
429
-    tags: 'tags',
430
-    description: 'album_desc'
431
-  }
432
-
433
-  var cn = $('#javdb_tr #catalogue').raw().value.toUpperCase()
434
-  $.getJSON('/api.php?action=autofill&cat=jav&cn=' + cn, function (data) {
452
+    cn: "javdb",
453
+    artists: "artists",
454
+    title: "title",
455
+    title_jp: "title_jp",
456
+    year: "year",
457
+    studio: "studio",
458
+    image: "image",
459
+    tags: "tags",
460
+    description: "album_desc",
461
+  };
462
+
463
+  var cn = $("#javdb_tr #catalogue").raw().value.toUpperCase();
464
+  $.getJSON("/api.php?action=autofill&cat=jav&cn=" + cn, function (data) {
435 465
     if (data.status != "success") {
436
-      $('#catalogue').raw().value = 'Failed'
437
-      return
466
+      $("#catalogue").raw().value = "Failed";
467
+      return;
438 468
     } else {
439
-      $('#catalogue').raw().value = data.response.cn
469
+      $("#catalogue").raw().value = data.response.cn;
440 470
     }
441 471
 
442 472
     for (i in data.response) {
443 473
       if (Array.isArray(data.response[i])) {
444 474
         for (j in data.response[i]) {
445
-          if (i == 'artists') {
446
-            if (!($('#' + map[i] + '_' + j).raw())) {
447
-              AddArtistField()
475
+          if (i == "artists") {
476
+            if (!$("#" + map[i] + "_" + j).raw()) {
477
+              AddArtistField();
448 478
             }
449
-            $('#' + map[i] + '_' + j).raw().value = data.response[i][j]
479
+            $("#" + map[i] + "_" + j).raw().value = data.response[i][j];
450 480
           }
451
-          if (map[i] == 'tags' && !($('#' + map[i]).raw().value)) {
452
-            $('#' + map[i]).raw().value = data.response[i].join(', ')
481
+          if (map[i] == "tags" && !$("#" + map[i]).raw().value) {
482
+            $("#" + map[i]).raw().value = data.response[i].join(", ");
453 483
           }
454 484
         }
455 485
       }
456 486
 
457
-      if (map[i] && $('#' + map[i]).raw() && !($('#' + map[i]).raw().value)) {
458
-        $('#' + map[i]).raw().value = data.response[i]
487
+      if (map[i] && $("#" + map[i]).raw() && !$("#" + map[i]).raw().value) {
488
+        $("#" + map[i]).raw().value = data.response[i];
459 489
       }
460 490
     }
461 491
 
462 492
     if (data.response.screens.length) {
463
-      $('#album_desc').raw().value = ('[spoiler=Automatically located thumbs][img]' + data.response.screens.join('[/img][img]') + '[/img][/spoiler]\n\n') + $('#album_desc').raw().value
493
+      $("#album_desc").raw().value =
494
+        "[spoiler=Automatically located thumbs][img]" +
495
+        data.response.screens.join("[/img][img]") +
496
+        "[/img][/spoiler]\n\n" +
497
+        $("#album_desc").raw().value;
464 498
     }
465
-  })
499
+  });
466 500
 }
467 501
 
468
-
469 502
 /**
470 503
  * MangaAutofill
471 504
  */
472 505
 function MangaAutofill() {
473 506
   var map = {
474
-    artists: 'artists',
475
-    title: 'title',
476
-    title_jp: 'title_jp',
477
-    year: 'year',
478
-    tags: 'tags',
479
-    lang: 'lang',
480
-    cover: 'image',
481
-    circle: 'series',
482
-    pages: 'pages',
483
-    description: 'release_desc'
484
-  }
485
-
486
-  var nh = $('#ehentai_tr #catalogue').raw().value
487
-  $.getJSON('/api.php?action=autofill&cat=manga&url=' + nh, function (data) {
507
+    artists: "artists",
508
+    title: "title",
509
+    title_jp: "title_jp",
510
+    year: "year",
511
+    tags: "tags",
512
+    lang: "lang",
513
+    cover: "image",
514
+    circle: "series",
515
+    pages: "pages",
516
+    description: "release_desc",
517
+  };
518
+
519
+  var nh = $("#ehentai_tr #catalogue").raw().value;
520
+  $.getJSON("/api.php?action=autofill&cat=manga&url=" + nh, function (data) {
488 521
     if (data.status != "success") {
489
-      $('#catalogue').raw().value = 'Failed'
490
-      return
522
+      $("#catalogue").raw().value = "Failed";
523
+      return;
491 524
     }
492 525
 
493 526
     for (i in data.response) {
494 527
       if (Array.isArray(data.response[i])) {
495 528
         for (j in data.response[i]) {
496
-          if (i == 'artists') {
497
-            if (!($('#' + map[i] + '_' + j).raw())) {
498
-              AddArtistField()
529
+          if (i == "artists") {
530
+            if (!$("#" + map[i] + "_" + j).raw()) {
531
+              AddArtistField();
499 532
             }
500
-            $('#' + map[i] + '_' + j).raw().value = data.response[i][j]
533
+            $("#" + map[i] + "_" + j).raw().value = data.response[i][j];
501 534
           }
502
-          if (map[i] == 'tags' && !($('#' + map[i]).raw().value)) {
503
-            $('#' + map[i]).raw().value = data.response[i].join(', ')
535
+          if (map[i] == "tags" && !$("#" + map[i]).raw().value) {
536
+            $("#" + map[i]).raw().value = data.response[i].join(", ");
504 537
           }
505 538
         }
506 539
       }
507 540
 
508
-      if (map[i] && $('#' + map[i]).raw() && (!($('#' + map[i]).raw().value) || $('#' + map[i]).raw().value == '---')) {
509
-        $('#' + map[i]).raw().value = data.response[i]
541
+      if (
542
+        map[i] &&
543
+        $("#" + map[i]).raw() &&
544
+        (!$("#" + map[i]).raw().value || $("#" + map[i]).raw().value == "---")
545
+      ) {
546
+        $("#" + map[i]).raw().value = data.response[i];
510 547
       }
511 548
     }
512
-  })
549
+  });
513 550
 }
514 551
 
515
-
516 552
 /**
517 553
  * SetResolution
518 554
  */
519 555
 function SetResolution() {
520
-  if ($('#ressel').raw().value != 'Other') {
521
-    $('#resolution').raw().value = $('#ressel').raw().value
522
-    $('#resolution').ghide()
556
+  if ($("#ressel").raw().value != "Other") {
557
+    $("#resolution").raw().value = $("#ressel").raw().value;
558
+    $("#resolution").ghide();
523 559
   } else {
524
-    $('#resolution').raw().value = ''
525
-    $('#resolution').gshow()
526
-    $('#resolution').raw().readOnly = false
560
+    $("#resolution").raw().value = "";
561
+    $("#resolution").gshow();
562
+    $("#resolution").raw().readOnly = false;
527 563
   }
528 564
 }
529 565
 
530
-
531 566
 /**
532 567
  * initAutofill
533 568
  */
534 569
 function initAutofill() {
535
-  $('[autofill]').each(function (i, el) {
536
-    el.addEventListener('click', function (event) {
537
-      ({ 'douj': MangaAutofill, 'anime': AnimeAutofill, 'jav': JavAutofill })[el.attributes['autofill'].value]()
538
-    })
539
-  })
570
+  $("[autofill]").each(function (i, el) {
571
+    el.addEventListener("click", function (event) {
572
+      ({ douj: MangaAutofill, anime: AnimeAutofill, jav: JavAutofill }[
573
+        el.attributes["autofill"].value
574
+      ]());
575
+    });
576
+  });
540 577
 }
541 578
 
542 579
 $(function () {
543 580
   Categories();
544 581
   initAutofill();
545
-  $(document).on('click', '.add_artist_button', AddArtistField);
546
-  $(document).on('click', '.remove_artist_button', RemoveArtistField);
547
-})
582
+  $(document).on("click", ".add_artist_button", AddArtistField);
583
+  $(document).on("click", ".remove_artist_button", RemoveArtistField);
584
+});

+ 0
- 23
static/functions/vendor/biojs/cytoscape.js
File diff suppressed because it is too large
View File


+ 0
- 1335
static/functions/vendor/biojs/ntseq.js
File diff suppressed because it is too large
View File


+ 30
- 72
static/styles/bookish/scss/colors.scss View File

@@ -17,6 +17,11 @@ $lb700: #0288d1;
17 17
 $lb800: #0277bd;
18 18
 $lb900: #01579b;
19 19
 
20
+/* Skeleton CSS */
21
+$SkeletonDefault: #33c3f0;
22
+$SkeletonFocus: #1eaedb;
23
+$SkeletonHalfdark: scale-color($SkeletonFocus, $lightness: -50%);
24
+
20 25
 /* The shadow under floating elements */
21 26
 $shadow: 2px 2px 10px -2px slategray;
22 27
 
@@ -24,21 +29,6 @@ $shadow: 2px 2px 10px -2px slategray;
24 29
  * Common elements
25 30
  */
26 31
 
27
-.head {
28
-    background: #b3e5fc;
29
-    color: black;
30
-    padding: 0.5em 1rem;
31
-}
32
-
33
-/* Alternating tables */
34
-#request_table .request:nth-of-type(even) {
35
-    background: white;
36
-}
37
-
38
-#request_table .request:nth-of-type(odd) {
39
-    background: whitesmoke;
40
-}
41
-
42 32
 /**
43 33
  * RGB color intensity border
44 34
  * For semi-transparent elements,
@@ -51,37 +41,6 @@ $shadow: 2px 2px 10px -2px slategray;
51 41
 /**
52 42
  * Fancy torrent search input
53 43
  */
54
-@mixin common-elements() {
55
-    border: none;
56
-    background: white;
57
-    font-size: 100%;
58
-    margin: 0 0.25rem;
59
-    padding: 0.5rem;
60
-    outline: none;
61
-}
62
-
63
-input,
64
-input[type="search"],
65
-input[type="text"] {
66
-    @include common-elements;
67
-    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
68
-    transition: ease-in-out 0.1s;
69
-
70
-    &:focus {
71
-        border-bottom: 1px solid $lb100;
72
-    }
73
-}
74
-
75
-select,
76
-input[type="select"] {
77
-    @include common-elements;
78
-    border: 1px solid rgba(0, 0, 0, 0.1);
79
-    border-radius: 0;
80
-
81
-    appearance: none;
82
-    -webkit-appearance: none;
83
-    -moz-appearance: none;
84
-}
85 44
 
86 45
 checkbox,
87 46
 input[type="checkbox"] {
@@ -93,58 +52,57 @@ input[type="file"] {
93 52
     border: none;
94 53
 }
95 54
 
96
-/* Buttons */
97
-button:not(.editor-toolbar button),
98
-input[type="button"],
99
-input[type="submit"] {
100
-    background: $lb200;
101
-    border: none;
102
-    border-radius: 0.25rem;
103
-    box-shadow: $shadow;
104
-    margin: 0 0.25rem;
105
-    padding: 0.75rem 1rem;
106
-    cursor: pointer;
107
-
108
-    &:hover {
109
-        background: $lb50;
110
-    }
111
-
112
-    &:focus {
113
-        background: $lb300;
114
-    }
115
-}
116
-
117 55
 /**
118 56
  * Alerts, Toolbox, etc.
119 57
  * Needs one unified error display
120 58
  * (torrent form, API keys use their own)
121 59
  */
60
+@mixin alertbar($bg) {
61
+    background: change-color($bg, $alpha: 0.25);
62
+    /* box-shadow: $shadow; */
63
+    text-align: center;
64
+    color: black;
65
+    font-weight: bold;
66
+    /* font-size: 0.95rem; */
67
+    width: 33%;
68
+    margin: 2em auto;
69
+    padding: 1rem;
70
+    border-radius: 4px;
71
+    border: 1px solid $bg;
72
+}
73
+
74
+/*
122 75
 @mixin alertbar($bg) {
123 76
     background: $bg;
124 77
     box-shadow: $shadow;
125 78
     text-align: center;
126 79
     color: black;
127 80
     font-weight: bold;
128
-    /* font-size: 0.95rem; */
81
+    /* font-size: 0.95rem; * /
129 82
     width: 33%;
130 83
     margin: 2em auto;
131 84
     padding: 1rem;
132 85
 }
86
+*/
133 87
 
134 88
 .alertbar {
135
-    @include alertbar($lb100);
89
+    @include alertbar(gold);
90
+    /* @include alertbar($lb100); */
136 91
 
137 92
     .warning {
138
-        background: #ffe0b2;
93
+        background: orange;
94
+        /* background: #ffe0b2; */
139 95
     }
140 96
 
141 97
     .error {
142
-        background: #ffcdd2;
98
+        background: red;
99
+        /* background: #ffcdd2; */
143 100
     }
144 101
 }
145 102
 
146 103
 .token_error {
147
-    @include alertbar(#ffcdd2);
104
+    @include alertbar(pink);
105
+    /* @include alertbar(#ffcdd2); */
148 106
 }
149 107
 
150 108
 .modbar a {

+ 11
- 2
static/styles/bookish/scss/fonts.scss View File

@@ -27,6 +27,14 @@ header,
27 27
     text-align: center;
28 28
 }
29 29
 
30
+/* Section headers ("box" class heading) */
31
+.head {
32
+    padding: 0.5em 0;
33
+    font-size: 120%;
34
+    border-bottom: 1px solid #e1e1e1;
35
+    margin-bottom: 1rem;
36
+}
37
+
30 38
 /* Links */
31 39
 a {
32 40
     color: black;
@@ -34,7 +42,8 @@ a {
34 42
 }
35 43
 
36 44
 a:hover {
37
-    color: $lb900;
45
+    color: $SkeletonFocus;
46
+    /* color: $lb900; */
38 47
     text-decoration: none;
39 48
 }
40 49
 
@@ -94,7 +103,7 @@ pre {
94 103
 }
95 104
 
96 105
 ul {
97
-    margin-left: 1rem;
106
+    margin-left: 0.5rem;
98 107
 }
99 108
 
100 109
 /* Markdown Extra new features */

+ 20
- 72
static/styles/bookish/scss/layout.scss View File

@@ -1,20 +1,3 @@
1
-/*
2
- * Body
3
- */
4
-
5
-* {
6
-    margin: 0;
7
-    padding: 0;
8
-}
9
-
10
-body {
11
-    /* min-width: 800px; */
12
-}
13
-
14
-ol {
15
-    margin-left: 1rem;
16
-}
17
-
18 1
 /*
19 2
  * Basic structure
20 3
  */
@@ -26,10 +9,6 @@ ol {
26 9
     width: 100%;
27 10
 }
28 11
 
29
-.head {
30
-    margin-bottom: 0.5rem;
31
-}
32
-
33 12
 #content {
34 13
     margin: auto;
35 14
     margin-top: 2rem;
@@ -47,11 +26,11 @@ ol {
47 26
 
48 27
 /* Logo */
49 28
 #logo {
50
-    background: url("/static/common/logos/bookish.png") no-repeat center;
29
+    background: url("/static/common/logos/torrents.bio.png") no-repeat center;
51 30
     background-size: contain;
52 31
     width: 250px;
53 32
     height: 50px;
54
-    margin: 0 0 0 10%;
33
+    margin: 0.5rem 0 0.25rem 10%;
55 34
 
56 35
     a {
57 36
         border: none;
@@ -65,15 +44,6 @@ ol {
65 44
     }
66 45
 }
67 46
 
68
-/* Content container */
69
-.box {
70
-    background-color: white;
71
-    /* border: 2px solid rgba(0, 0, 0, 0.01); */
72
-    margin: auto;
73
-    margin-bottom: 1rem;
74
-    width: 100%;
75
-}
76
-
77 47
 /* Main column and sidebar */
78 48
 @mixin column-flex($width) {
79 49
     display: flex;
@@ -85,7 +55,7 @@ ol {
85 55
 }
86 56
 
87 57
 .main_column {
88
-    @include column-flex(65%);
58
+    @include column-flex(64%);
89 59
 
90 60
     table {
91 61
         margin-bottom: 1rem;
@@ -93,27 +63,21 @@ ol {
93 63
 }
94 64
 
95 65
 .sidebar {
96
-    @include column-flex(35%);
66
+    @include column-flex(34%);
97 67
     float: right;
98 68
 }
99 69
 
70
+/* Box: soon to be <section> */
71
+.box {
72
+    margin-bottom: 1rem;
73
+}
74
+
100 75
 /* Links */
101 76
 div.linkbox {
102 77
     text-align: center;
103 78
     padding: 0.5rem;
104 79
 }
105 80
 
106
-.pad {
107
-    padding: 0 !important;
108
-    /* padding: 1rem; */
109
-
110
-    h3,
111
-    h4 {
112
-        margin-top: 0;
113
-        padding-top: 0;
114
-    }
115
-}
116
-
117 81
 /* Misc */
118 82
 .torrents_nomatch {
119 83
     margin-top: 1rem;
@@ -128,7 +92,10 @@ div.linkbox {
128 92
     margin-top: 1rem;
129 93
 }
130 94
 
131
-/* Torrents page */
95
+/**
96
+ * Torrents page
97
+ */
98
+
132 99
 .show_torrents {
133 100
     width: 21px;
134 101
     height: 28px;
@@ -171,35 +138,20 @@ div.linkbox {
171 138
     border: none;
172 139
 }
173 140
 
174
-.torrent_table tr {
175
-    /* vertical-align: top; */
176
-    vertical-align: middle;
177
-}
178
-
179 141
 .torrent_table .number_column {
180 142
     text-align: center;
181 143
 }
182 144
 
183
-.torrent_table,
184
-.torrent_table td {
185
-    border: none;
186
-}
187
-
188
-/* Text elements */
189
-h1,
190
-h2,
191
-h3,
192
-h4 {
193
-    margin: 0.5em 0;
194
-    font-weight: bold;
195
-}
145
+/**
146
+ * Text elements
147
+ */
196 148
 
197 149
 p {
198
-    margin: 1em 0.5rem;
150
+    margin-bottom: 1rem;
199 151
 }
200 152
 
201 153
 li {
202
-    margin: 0.5em 2rem;
154
+    margin: 0 1rem;
203 155
 }
204 156
 
205 157
 .torrent_title {
@@ -286,7 +238,8 @@ ul .invitetree {
286 238
 
287 239
 .center_poll {
288 240
     height: 0.75rem;
289
-    background: $lb50;
241
+    background: $SkeletonDefault;
242
+    /* background: $lb50; */
290 243
     border-radius: 0;
291 244
     float: left;
292 245
     margin: 0.25rem 0;
@@ -355,8 +308,3 @@ ul .invitetree {
355 308
     }
356 309
     */
357 310
 }
358
-
359
-/* User and torrent stats */
360
-.chart {
361
-    max-height: 30rem;
362
-}

+ 11
- 10
static/styles/bookish/scss/menus.scss View File

@@ -3,7 +3,8 @@
3 3
  */
4 4
 
5 5
 #menu {
6
-    background-color: $lb900;
6
+    background-color: $SkeletonHalfdark;
7
+    /* background-color: $lb900; */
7 8
     font-size: 1rem;
8 9
     text-align: center;
9 10
     width: 100%;
@@ -36,26 +37,28 @@
36 37
     max-width: 2.5rem;
37 38
 }
38 39
 
39
-#menu ul li a.active {
40
-    background-color: $lb700;
40
+#menu ul li a:active {
41
+    background-color: $SkeletonFocus;
42
+    /* background-color: $lb700; */
41 43
 }
42 44
 
43 45
 #menu ul li a:hover {
44
-    background-color: $lb700;
46
+    background-color: $SkeletonFocus;
47
+    /* background-color: $lb700; */
45 48
     color: white;
46 49
     text-decoration: none;
47 50
 }
48 51
 
49 52
 /* Dropdown */
50 53
 #menu .nav_dropdown {
51
-    background: #01579b;
54
+    background-color: $SkeletonHalfdark;
52 55
     margin-top: 0;
53 56
 }
54 57
 
55 58
 .nav_dropdown > div {
56 59
     box-shadow: $shadow;
57 60
     position: absolute;
58
-    background-color: #01579b;
61
+    background-color: $SkeletonHalfdark;
59 62
     width: 100%;
60 63
     z-index: 99999;
61 64
     margin-top: 2.5rem;
@@ -85,8 +88,6 @@
85 88
 
86 89
 #searchbars {
87 90
     text-align: center;
88
-    background-color: $lb200;
89
-    box-shadow: $shadow;
90 91
     box-sizing: content-box;
91 92
     padding: 0.5rem 10%;
92 93
     display: flex;
@@ -133,7 +134,7 @@
133 134
 }
134 135
 
135 136
 #searchbars ul li ul li {
136
-    margin: 0 0 0 0;
137
+    margin: 0;
137 138
     padding: 0;
138 139
     display: block;
139 140
     width: 100%;
@@ -152,7 +153,7 @@
152 153
  */
153 154
 #userinfo {
154 155
     color: black;
155
-    padding: 0.5em 0;
156
+    /* padding: 0.5em 0; */
156 157
     width: 100%;
157 158
     text-align: center;
158 159
 }

+ 65
- 76
static/styles/bookish/scss/tables.scss View File

@@ -1,31 +1,60 @@
1
-@mixin center-all {
1
+/**
2
+ * Tables
3
+ */
4
+
5
+@mixin alternating-rows {
6
+    tr:nth-child(2n) {
7
+        background: whitesmoke;
8
+    }
9
+
10
+    tr:nth-child(2n-1) {
11
+        background: white;
12
+    }
2 13
 }
3 14
 
15
+/* Every table */
4 16
 table {
5
-    /* border: 2px solid rgba(0, 0, 0, 0.01); */
6
-    border-collapse: collapse;
7 17
     width: 100%;
8 18
 
9
-    /*
10
-    * {
11
-        vertical-align: middle;
19
+    th {
20
+        font-size: 120%;
12 21
     }
13
-    */
14 22
 
15
-    tr {
16
-        background-color: white;
23
+    td,
24
+    td:first-child {
25
+        padding: 0.5rem !important;
17 26
     }
27
+}
18 28
 
19
-    td,
20
-    th {
21
-        padding: 0.5rem;
22
-        text-align: left;
29
+/* Special tables */
30
+.torrent_table,
31
+.collage_table,
32
+.request_table,
33
+.top10_table {
34
+    @include alternating-rows;
35
+
36
+    th,
37
+    td {
38
+        border-bottom: 1px solid #e1e1e1;
39
+    }
40
+}
41
+
42
+.torrent_table,
43
+.collage_table {
44
+    div.tags {
45
+        font-weight: normal;
46
+        max-width: 500px;
47
+    }
48
+
49
+    span {
50
+        float: right;
23 51
     }
24 52
 }
25 53
 
26 54
 /**
27 55
  * Torrent form
28 56
  */
57
+
29 58
 .torrent_form,
30 59
 #dynamic_form {
31 60
     /* margin-bottom: 2rem; */
@@ -39,18 +68,16 @@ table {
39 68
     }
40 69
 }
41 70
 
42
-/* Classes */
71
+/**
72
+ * colhead
73
+ * The main table heading.
74
+ */
75
+
43 76
 .colhead {
44
-    background: $lb100;
77
+    padding: 0.5em 0;
78
+    border-bottom: 1px solid #e1e1e1;
79
+    font-size: 120%;
45 80
     font-weight: bold;
46
-    color: black;
47
-}
48
-
49
-td.colhead,
50
-.colhead td,
51
-.colhead th {
52
-    padding-left: 10px;
53
-    padding-right: 10px;
54 81
 }
55 82
 
56 83
 .colhead .sign,
@@ -66,72 +93,34 @@ td.colhead,
66 93
     font-weight: bold;
67 94
 }
68 95
 
69
-.colhead_dark {
70
-    background: $lb100;
71
-    color: black;
72
-}
73
-
74 96
 /* Torrent and collage tables */
75
-.torrent_table,
76
-.collage_table {
77
-    tr.group {
78
-        background-color: white;
79
-
80
-        td.center:first-child {
81
-            padding: 3px;
82
-            width: 21px;
83
-        }
84
-    }
85
-
86
-    tr.group_torrent {
87
-        background-color: white;
88
-
89
-        span {
90
-            float: right;
91
-        }
92
-    }
93
-
94
-    tr.torrent {
95
-        background-color: white;
96
-    }
97
-
98
-    tr.torrent:nth-child(2n),
99
-    tr.row:nth-child(2n) {
100
-        background-color: whitesmoke;
101
-    }
102
-
103
-    tr.torrent:nth-child(2n-1),
104
-    tr.row:nth-child(2n-1) {
105
-        background-color: white;
106
-    }
107
-
108
-    tr .center,
109
-    td {
110
-        vertical-align: middle;
111
-        /* text-align: center; */
112
-    }
113
-    div.tags {
114
-        font-weight: normal;
115
-        max-width: 500px;
116
-    }
117
-}
118
-
119 97
 .torrent_table .group_torrent .torrent span {
120 98
     font-weight: normal;
121 99
     float: right;
122 100
 }
123 101
 
124
-/* Forums */
102
+/**
103
+ * Forums
104
+ */
105
+
106
+@mixin forum-post($color) {
107
+    background-color: $color;
108
+    border-bottom: 1px solid #e1e1e1;
109
+    font-size: 120%;
110
+}
111
+
125 112
 .forum_post .colhead_dark {
126
-    background: $lb100;
113
+    @include forum-post(white);
114
+    /* background: $lb100; */
127 115
 }
128 116
 
129 117
 .forum_post.staff_post .colhead_dark {
130
-    background: $lb200;
118
+    @include forum-post(whitesmoke);
119
+    /* background: $lb200; */
131 120
 }
132 121
 
133 122
 .forum_post.sticky_post {
134
-    border: 2px solid $lb200;
123
+    border: 2px solid $SkeletonDefault;
135 124
 }
136 125
 
137 126
 td.label {

+ 1
- 0
static/styles/global/global.scss View File

@@ -8,4 +8,5 @@
8 8
 @import "scss/layout";
9 9
 @import "scss/log";
10 10
 @import "scss/settings";
11
+@import "scss/skeleton-fixes";
11 12
 @import "scss/tables";

+ 1
- 1
static/styles/global/scss/debug.scss View File

@@ -29,7 +29,7 @@
29 29
     border-radius: 100px;
30 30
 }
31 31
 
32
-/*
32
+/**
33 33
  * Fix long filename tables overflowing (Chrome only).
34 34
  * Stop various release page containers from overflowing with long input.
35 35
  * !! Be sure to test all major browsers before changing this section. !!

+ 0
- 1
static/styles/global/scss/fonts.scss View File

@@ -1,7 +1,6 @@
1 1
 html {
2 2
     font-size: 16px;
3 3
     line-height: 1.6;
4
-    /* line-height: 1.6; */
5 4
 }
6 5
 
7 6
 /*

+ 28
- 0
static/styles/global/scss/layout.scss View File

@@ -1,3 +1,12 @@
1
+/*
2
+ * Body
3
+ */
4
+
5
+* {
6
+    margin: 0;
7
+    padding: 0;
8
+}
9
+
1 10
 /*
2 11
  * Flex elements
3 12
  */
@@ -50,6 +59,7 @@ aside {
50 59
     &.upload_notice {
51 60
         @include transparent-border($R: 255, $A: 0.5);
52 61
         margin: 1rem auto;
62
+        padding-top: 1rem;
53 63
         text-align: center;
54 64
     }
55 65
 
@@ -67,6 +77,19 @@ aside {
67 77
     }
68 78
 }
69 79
 
80
+/**
81
+ * Footer
82
+ */
83
+
84
+footer {
85
+    margin-top: 2rem;
86
+    width: 100%;
87
+
88
+    p {
89
+        text-align: center;
90
+    }
91
+}
92
+
70 93
 /*
71 94
  * Misc
72 95
  */
@@ -184,3 +207,8 @@ img {
184 207
         height: 2rem;
185 208
     }
186 209
 }
210
+
211
+/* User and torrent stats */
212
+.chart {
213
+    max-height: 30rem;
214
+}

+ 20
- 0
static/styles/global/scss/legacy.scss View File

@@ -47,6 +47,7 @@ textarea {
47 47
     outline: none;
48 48
 }
49 49
 
50
+/* 2021-07-24
50 51
 select {
51 52
     padding: 5px 10px;
52 53
     background-color: white;
@@ -58,6 +59,7 @@ select {
58 59
     -moz-appearance: none;
59 60
     appearance: none;
60 61
 }
62
+*/
61 63
 
62 64
 h2 .group_cat {
63 65
     height: 16px;
@@ -129,6 +131,7 @@ div.collage_image {
129 131
     cursor: pointer;
130 132
 }
131 133
 
134
+/* 2021-07-24
132 135
 button,
133 136
 input[type="button"],
134 137
 input[type="submit"] {
@@ -139,6 +142,7 @@ input[type="submit"] {
139 142
     border: none;
140 143
     color: #000;
141 144
 }
145
+*/
142 146
 
143 147
 .spoilerButton {
144 148
     cursor: pointer;
@@ -582,6 +586,7 @@ tr.torrent .bookmark > a:after {
582 586
  * Fix long release descriptions overflowing containers (all browsers).
583 587
  * Fix flowing issues in the report resolving pages.
584 588
  */
589
+/* 2021-07-24
585 590
 .wrap_overflow,
586 591
 .filelist_table td,
587 592
 .reportinfo_table,
@@ -593,6 +598,7 @@ tr.torrent .bookmark > a:after {
593 598
     word-break: break-word;
594 599
     hyphens: auto;
595 600
 }
601
+*/
596 602
 
597 603
 .filelist_table td:first-child {
598 604
     word-break: break-all;
@@ -1051,21 +1057,29 @@ div.torrent_artists {
1051 1057
 }
1052 1058
 */
1053 1059
 
1060
+/* 2021-07-24
1054 1061
 .flex {
1055 1062
     display: flex;
1056 1063
 }
1064
+*/
1057 1065
 
1066
+/* 2021-07-24
1058 1067
 .flex > .grow {
1059 1068
     flex-grow: 1;
1060 1069
 }
1070
+*/
1061 1071
 
1072
+/* 2021-07-24
1062 1073
 .flex > .shrink {
1063 1074
     flex-shrink: 1;
1064 1075
 }
1076
+*/
1065 1077
 
1078
+/* 2021-07-24
1066 1079
 input[type="search"] {
1067 1080
     -webkit-appearance: textfield;
1068 1081
 }
1082
+*/
1069 1083
 
1070 1084
 #lightbox > img {
1071 1085
     max-width: 100%;
@@ -1089,10 +1103,12 @@ input[type="search"] {
1089 1103
     display: flex;
1090 1104
 }
1091 1105
 
1106
+/* 2021-07-24
1092 1107
 #publickey {
1093 1108
     width: initial;
1094 1109
     font-family: monospace;
1095 1110
 }
1111
+*/
1096 1112
 
1097 1113
 .hidden {
1098 1114
     display: none;
@@ -1103,12 +1119,15 @@ form.edit_form[name="screenshots_form"] img {
1103 1119
     width: 400px;
1104 1120
 }
1105 1121
 
1122
+/* 2021-07-24
1106 1123
 #dbcrypt {
1107 1124
     position: fixed;
1108 1125
     top: 10px;
1109 1126
     right: 10px;
1110 1127
 }
1128
+*/
1111 1129
 
1130
+/* 2021-07-24
1112 1131
 #dbcrypt:after {
1113 1132
     content: "!";
1114 1133
     display: block;
@@ -1122,3 +1141,4 @@ form.edit_form[name="screenshots_form"] img {
1122 1141
     background: red;
1123 1142
     border-radius: 100px;
1124 1143
 }
1144
+*/

+ 162
- 0
static/styles/global/scss/skeleton-fixes.scss View File

@@ -0,0 +1,162 @@
1
+/**
2
+ * Fixes needed to use skeleton.css
3
+ * to its best no-fuss advantage
4
+ */
5
+
6
+/* Set heading fonts 50% of default and bump down a level */
7
+@mixin heading-attributes {
8
+    letter-spacing: -1px !important;
9
+    margin: 1rem 0 !important;
10
+}
11
+
12
+h1:not(#logo) {
13
+    font-size: 1.8rem !important;
14
+    @include heading-attributes;
15
+}
16
+
17
+h2 {
18
+    font-size: 1.5rem !important;
19
+    @include heading-attributes;
20
+}
21
+
22
+h3 {
23
+    font-size: 1.2rem !important;
24
+    @include heading-attributes;
25
+}
26
+
27
+h4 {
28
+    font-size: 0.9rem !important;
29
+    @include heading-attributes;
30
+}
31
+
32
+h5 {
33
+    font-size: 0.75rem !important;
34
+    @include heading-attributes;
35
+}
36
+
37
+h6 {
38
+    font-size: 0.75rem !important;
39
+    @include heading-attributes;
40
+}
41
+
42
+/* Larger than phablet */
43
+@media (min-width: 550px) {
44
+    h1 {
45
+        font-size: 1.8rem !important;
46
+    }
47
+
48
+    h2 {
49
+        font-size: 1.5rem !important;
50
+    }
51
+
52
+    h3 {
53
+        font-size: 1.2rem !important;
54
+    }
55
+
56
+    h4 {
57
+        font-size: 0.9rem !important;
58
+    }
59
+
60
+    h5 {
61
+        font-size: 0.75rem !important;
62
+    }
63
+
64
+    h6 {
65
+        font-size: 0.75rem !important;
66
+    }
67
+}
68
+
69
+/* Forum list headings */
70
+table.forum_index {
71
+    h4 {
72
+        margin: 0 !important;
73
+    }
74
+}
75
+
76
+/* Checkbox and radio labels */
77
+label,
78
+legend {
79
+    display: inline !important;
80
+}
81
+
82
+/* Tables usually containing forms */
83
+/* browse */
84
+table.torrent_search,
85
+/* request search */ table.torrent_requests,
86
+/* forum list */ table.forum_index,
87
+/* upload form */ table.torrent_form,
88
+/* requests? */ table.request_form,
89
+/* new request */ form#request_form,
90
+/* forum thread */ table.new_thread,
91
+/* toolbox */ table.admin_tools,
92
+/* BP */ table.store_table,
93
+/* rule sections */ div.rule_table,
94
+/* client rules */ table.clients_table,
95
+/* login */ table.login_form,
96
+/* requests? */form.create_form,
97
+/* top10 */ form.search_form,
98
+/* edit collage */ table.collage_edit,
99
+/* start user management */
100
+table#user_info_box,
101
+table#warn_user_box,
102
+table#user_lock_account,
103
+table#user_privs_box,
104
+table#session_box,
105
+table#donation_box,
106
+table#donor_points_box,
107
+table#submit_box,
108
+/* end user management */
109
+/* notif filters */ form[name="notification"],
110
+/* wiki search */ table.wiki_browse,
111
+/* better.php */ table.better_list {
112
+    th,
113
+    td {
114
+        border-bottom: 0 !important;
115
+        padding: 0.25rem !important;
116
+    }
117
+}
118
+
119
+/* Duplicate input rules here */
120
+input,
121
+input[type="search"],
122
+input[type="text"] {
123
+    margin: 0 !important;
124
+}
125
+
126
+input,
127
+textarea,
128
+select,
129
+fieldset {
130
+    margin-bottom: 0 !important;
131
+}
132
+
133
+/* Block elements */
134
+pre,
135
+blockquote,
136
+dl,
137
+figure,
138
+table,
139
+ul,
140
+ol,
141
+form {
142
+    margin-bottom: 0 !important;
143
+}
144
+
145
+/* Inline code */
146
+code {
147
+    padding: 0 !important;
148
+}
149
+
150
+/* Unordered lists */
151
+ul {
152
+    list-style: circle outside !important;
153
+}
154
+
155
+/* Nested lists */
156
+ul ul,
157
+ul ol,
158
+ol ol,
159
+ol ul {
160
+    margin: 0 !important;
161
+    font-size: 100% !important;
162
+}

+ 19
- 9
static/styles/public/scss/public.scss View File

@@ -1,3 +1,8 @@
1
+/* Skeleton CSS */
2
+$SkeletonDefault: #33c3f0;
3
+$SkeletonFocus: #1eaedb;
4
+$SkeletonHalfdark: scale-color($SkeletonFocus, $lightness: -50%);
5
+
1 6
 * {
2 7
     margin: 0;
3 8
     padding: 0;
@@ -49,7 +54,11 @@ p {
49 54
 }
50 55
 
51 56
 ul {
52
-    margin-left: 2rem;
57
+    margin-left: 0.5rem;
58
+
59
+    li {
60
+        margin-bottom: 0;
61
+    }
53 62
 
54 63
     &.p li {
55 64
         margin-bottom: 1rem;
@@ -64,7 +73,7 @@ h2 {
64 73
 /**
65 74
  * Inputs
66 75
  */
67
-
76
+/*
68 77
 input[type="text"],
69 78
 input[type="password"],
70 79
 input[type="email"] {
@@ -119,6 +128,7 @@ input[type="submit"]:hover {
119 128
     text-align: right;
120 129
     padding-right: 5px;
121 130
 }
131
+*/
122 132
 
123 133
 /**
124 134
  * Layout
@@ -126,10 +136,10 @@ input[type="submit"]:hover {
126 136
 
127 137
 header,
128 138
 footer {
129
-    height: 2rem;
130
-    line-height: 2rem;
139
+    height: 2.5rem;
140
+    line-height: 2.5rem;
131 141
     width: 100%;
132
-    background: #01579b;
142
+    background: $SkeletonHalfdark;
133 143
     position: fixed;
134 144
     left: 0;
135 145
 
@@ -156,16 +166,16 @@ footer {
156 166
 }
157 167
 
158 168
 main {
159
-    width: 250px;
169
+    width: 25%;
160 170
     height: calc(80% - 60px);
161 171
     margin: 0 auto;
162 172
     padding: 10% 0;
163 173
 }
164 174
 
165 175
 #logo {
166
-    width: 250px;
176
+    /* width: 250px; */
167 177
     height: 50px;
168
-    background-image: url("/static/common/logos/bookish.png");
178
+    background-image: url("/static/common/logos/torrents.bio.png");
169 179
     background-repeat: no-repeat;
170 180
     background-position: center;
171 181
     background-size: contain;
@@ -215,5 +225,5 @@ main {
215 225
     content: "℠";
216 226
     font-size: 0.75rem;
217 227
     font-weight: normal;
218
-    margin-left: 100%;
228
+    margin-left: 93%;
219 229
 }

+ 24
- 0
templates/input/passphrase.html View File

@@ -0,0 +1,24 @@
1
+<input
2
+  type="password"
3
+  name="{{ name|default('password') }}"
4
+  id="{{ id|default('password') }}"
5
+  placeholder="{{ placeholder|default('passphrase') }}"
6
+  minlength="{{ pw_min|default('15') }}"
7
+  maxlength="{{ pw_max|default('10000') }}"
8
+  pattern=".{ {{ pw_min }},{{ pw_max }} }"
9
+  class="inputtext"
10
+  autocomplete="off"
11
+  required="required"
12
+/>
13
+
14
+<strong id="pass_match"></strong>
15
+
16
+{% if advice == true %}
17
+<p>
18
+  Any password {{ pw_min }} characters or longer is accepted, but a strong password
19
+  <ul>
20
+    <li>is a pass<em>phrase</em> of mixed case with many small words,</li>
21
+    <li>that contains complex characters including Unicode and emoji.</li>
22
+  </ul>
23
+</p>
24
+{% endif %}

+ 14
- 0
templates/torrent_form/mirrors.html View File

@@ -0,0 +1,14 @@
1
+<tr id="mirrors_tr">
2
+  <td>
3
+    <label for="mirrors">{{ db.name }}</label>
4
+  </td>
5
+
6
+  <td>
7
+    <textarea
8
+      rows="2"
9
+      name="mirrors"
10
+      id="mirrors"
11
+      {# Needs to be all on one line #}
12
+      placeholder="{{ db.desc }}">{{ mirrors }}</textarea>
13
+  </td>
14
+</tr>

+ 16
- 0
templates/torrent_form/picture.html View File

@@ -0,0 +1,16 @@
1
+<tr id="cover_tr">
2
+  <td>
3
+    <label for="image">{{db.name }}</label>
4
+  </td>
5
+
6
+  <td>
7
+    <input
8
+      type="text"
9
+      id="image"
10
+      name="image"
11
+      size="60"
12
+      placeholder="{{ db.desc }}"
13
+      value="{{ picture }}"
14
+    />
15
+  </td>
16
+</tr>

+ 54
- 0
templates/torrent_form/seqhash.html View File

@@ -0,0 +1,54 @@
1
+<tr id="seqhash_tr">
2
+  <td>
3
+    <label for="seqhash">{{ db.name }}</label>
4
+    {#
5
+    <br />
6
+    <a class="add_artist_button brackets" onclick="AddArtistField()">+</a>
7
+    <a class="remove_artist_button brackets" onclick="RemoveArtistField()">&minus;</a>
8
+    #}
9
+  </td>
10
+
11
+  <td>
12
+    <textarea
13
+      rows="2"
14
+      name="seqhash"
15
+      id="seqhash"
16
+      {# Needs to be all on one line #}
17
+      placeholder="{{ db.desc }}">{{ seqhash }}</textarea>
18
+
19
+    <input type="radio" id="dna" name="seqhash_meta1" value="DNA" checked /> DNA
20
+    {# <label for="dna">DNA</label> #}
21
+
22
+    &emsp;
23
+
24
+    <input type="radio" id="rna" name="seqhash_meta1" value="RNA" /> RNA
25
+    {# <label for="rna">RNA</label> #}
26
+
27
+    &emsp;
28
+
29
+    <input type="radio" id="protein" name="seqhash_meta1" value="PROTEIN" /> Protein
30
+    {# <label for="protein">Protein</label> #}
31
+
32
+    <br />
33
+
34
+    <input type="radio" id="linear" name="seqhash_meta2" value="false" checked /> Linear
35
+    {# <label for="linear">Linear</label> #}
36
+
37
+    &emsp;
38
+
39
+    <input type="radio" id="circular" name="seqhash_meta2" value="true" /> Circular
40
+    {# <label for="circular">Circular</label> #}
41
+
42
+    <br />
43
+
44
+    <input type="radio" id="double_stranded" name="seqhash_meta3" value="true" checked /> Double-Stranded
45
+    {# <label for="double_stranded">Double-Stranded</label> #}
46
+
47
+    &emsp;
48
+
49
+    <input type="radio" id="single_stranded" name="seqhash_meta3" value="false" /> Single-Stranded
50
+    {# <label for="single_stranded">Single-Stranded</label> #}
51
+
52
+    <p>{{ db.note|raw }}</p>
53
+  </td>
54
+</tr>

+ 2
- 2
templates/torrent_form/version.html View File

@@ -10,10 +10,10 @@
10 10
       name="version"
11 11
       size="12"
12 12
       pattern="\d+\.*\d*\.*\d*"
13
-      placeholder="{{ db.desc}}"
13
+      placeholder="{{ db.desc }}"
14 14
       value="{{ version }}"
15 15
     />
16 16
 
17
-    <p>{{ note }}</p>
17
+    <p>{{ db.note|raw }}</p>
18 18
   </td>
19 19
 </tr>

+ 53
- 0
templates/wiki/browse.html View File

@@ -0,0 +1,53 @@
1
+<section class="wiki_search">
2
+  <p>Search the wiki for user created tutorials and information.</p>
3
+
4
+  <form class="search_form" name="wiki" action="wiki.php" method="get">
5
+    <input type="hidden" name="action" value="search" />
6
+    <input type="hidden" name="nojump" value="1" />
7
+    <input type="search" name="search" size="80" />
8
+    <input value="Search" type="submit" class="hidden button-primary" />
9
+  </form>
10
+  <br />
11
+
12
+  <p>
13
+    Additionally, you can manually browse through the articles by their first letter.
14
+  </p>
15
+  
16
+  <span>
17
+    {% for letter in 'a'..'z' %}
18
+    <a href="wiki.php?action=browse&amp;letter={{ letter }}"
19
+      >{{ letter|upper }}</a
20
+    >&nbsp;&nbsp; {% endfor %}
21
+    <a href="wiki.php?action=browse&amp;letter=1">All</a>&nbsp;&nbsp;
22
+  </span>
23
+</section>
24
+
25
+<section class="wiki_results">
26
+  <div class="header">
27
+    <h2>{{ title }}</h2>
28
+  </div>
29
+  <div class="linkbox">
30
+    <a href="wiki.php?action=create" class="brackets">Create</a>
31
+  </div>
32
+
33
+
34
+  <table width="100%" style="margin-bottom: 10px">
35
+    <tr class="colhead">
36
+      <td>Article</td>
37
+      <td>Last updated on</td>
38
+      <td>Last edited by</td>
39
+    </tr>
40
+    {% for article in articles %}
41
+    <tr>
42
+      <td>
43
+        <a href="wiki.php?action=article&amp;id={{ article.ID }}"
44
+          >{{ article.Title }}</a
45
+        >
46
+      </td>
47
+      <td>{{ article.Date }}</td>
48
+      <td>{{ article.Author|user_url }}</td>
49
+    </tr>
50
+    {% endfor %}
51
+  </table>
52
+
53
+</section>

+ 0
- 49
templates/wiki/browse.twig View File

@@ -1,49 +0,0 @@
1
-{% macro letter_box(show_search = true) %}
2
-    <div class="box pad center">
3
-        {% if show_search %}
4
-        <p>Search the wiki for user created tutorials and information.</p>
5
-        <form class="search_form" name="wiki" action="wiki.php" method="get">
6
-            <input type="hidden" name="action" value="search" />
7
-            <input type="hidden" name="nojump" value="1" />
8
-            <input type="search" name="search" size="80" />
9
-            <input value="Search" type="submit" class="hidden" />
10
-        </form>
11
-        <br />
12
-        <p>Additionally, you can manually browse through the articles by their first letter.</p>
13
-        {% endif %}
14
-        <span>
15
-            {% for letter in 'a'..'z' %}
16
-            <a href="wiki.php?action=browse&amp;letter={{ letter }}">{{ letter|upper }}</a>&nbsp;&nbsp;
17
-            {% endfor %}
18
-            <a href="wiki.php?action=browse&amp;letter=1">All</a>&nbsp;&nbsp;
19
-        </span>
20
-    </div>
21
-{% endmacro %}
22
-
23
-<div class="thin">
24
-    <div class="header">
25
-        <h2>{{ title }}</h2>
26
-    </div>
27
-    <div class="linkbox">
28
-        <a href="wiki.php?action=create" class="brackets">Create</a>
29
-    </div>
30
-
31
-    {{ _self.letter_box() }}
32
-
33
-    <table width="100%" style="margin-bottom: 10px;">
34
-        <tr class="colhead">
35
-            <td>Article</td>
36
-            <td>Last updated on</td>
37
-            <td>Last edited by</td>
38
-        </tr>
39
-        {% for article in articles %}
40
-        <tr>
41
-            <td><a href="wiki.php?action=article&amp;id={{ article.ID }}">{{ article.Title }}</a></td>
42
-            <td>{{ article.Date }}</td>
43
-            <td>{{ article.Author|user_url }}</td>
44
-        </tr>
45
-        {% endfor %}
46
-    </table>
47
-
48
-    {{ _self.letter_box(false) }}
49
-</div>

Loading…
Cancel
Save