Browse Source

Add Skeleton CSS support, mostly

biotorrents 3 years ago
parent
commit
1530171f7b

+ 1
- 1
classes/config.template.php View File

@@ -382,7 +382,7 @@ ENV::setPub('FEATURE_SET_ENC_KEY_PUBLIC', false);
382 382
 
383 383
 # Attempt to support the Seqhash algorithm
384 384
 # https://blog.libredna.org/post/seqhash/
385
-ENV::setPub('FEATURE_SEQHASH', true);
385
+ENV::setPub('FEATURE_BIOPHP', true);
386 386
 
387 387
 
388 388
 /**

+ 5
- 3
classes/env.class.php View File

@@ -137,9 +137,11 @@ class ENV
137 137
      * toArray
138 138
      *
139 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
140 142
      * @see https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array
141 143
      */
142
-    public function toArray(object $obj)
144
+    public function toArray($obj)
143 145
     {
144 146
         if (is_object($obj)) {
145 147
             $obj = (array) $obj;
@@ -242,10 +244,10 @@ class ENV
242 244
      * string(32) "52963afccc006d2bce3c890ad9e8f73a"
243 245
      *
244 246
      * @param string $fn Callback function
245
-     * @param object $obj Object to operate on
247
+     * @param object|string $obj Object or property to operate on
246 248
      * @return object $RAO Mapped RecursiveArrayObject
247 249
      */
248
-    public function map(string $fn = '', object $obj = null)
250
+    public function map(string $fn = '', $obj = null)
249 251
     {
250 252
         # Set a default function if desired
251 253
         if (empty($fn) && !is_object($fn)) {

+ 1
- 1
classes/security.class.php View File

@@ -65,7 +65,7 @@ class Security
65 65
         }
66 66
 
67 67
         # blake3
68
-        if ($ENV->FEATURE_SEQHASH && !extension_loaded('blake3')) {
68
+        if ($ENV->FEATURE_BIOPHP && !extension_loaded('blake3')) {
69 69
             error('Please install and enable the php-blake3 extension.');
70 70
         }
71 71
 

+ 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
-}

+ 41
- 15
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
 
@@ -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,7 +438,7 @@ HTML;
438 438
 
439 439
 
440 440
         /**
441
-         * Semantic Version
441
+         * Version
442 442
          */
443 443
         
444 444
         $Version = display_str($Torrent['Version']);
@@ -774,6 +774,7 @@ HTML;
774 774
          */
775 775
         function formatSelect($trID = '', $Label = '', $Torrent = [], $FileTypes = [])
776 776
         {
777
+            #var_dump($FileTypes);
777 778
             echo <<<HTML
778 779
             <tr id="$trID">
779 780
               <td>
@@ -781,21 +782,24 @@ HTML;
781 782
                   $Label
782 783
                 <label>
783 784
               </td>
784
-              
785
+
785 786
               <td>
786 787
                 <select id="container" name="container">
787 788
                   <option value="Autofill">Autofill</option>
788 789
 HTML;
789 790
 
790
-            foreach ($FileTypes as $Type => $Extensions) {
791
-                echo "<option value='$Type'";
791
+            foreach ($FileTypes as $FileType) {
792
+                foreach ($FileType as $Type => $Extensions) {
793
+                    echo "<option value='$Type'";
792 794
 
793
-                if ($Type === ($Torrent['Container'] ?? false)) {
794
-                    echo ' selected';
795
-                }
795
+                    if ($Type === ($Torrent['Container'] ?? false)) {
796
+                        echo ' selected';
797
+                    }
796 798
 
797
-                echo ">$Type</option>\n";
799
+                    echo ">$Type</option>\n";
800
+                }
798 801
             }
802
+        
799 803
 
800 804
             echo <<<HTML
801 805
                 </select>
@@ -832,6 +836,7 @@ HTML;
832 836
             $Label = 'Format',
833 837
             $Torrent = $Torrent,
834 838
             #$FileTypes = array_column($ENV->META, $Formats)
839
+            $FileTypes = $ENV->CATS->{2}->Formats
835 840
         );
836 841
 
837 842
 
@@ -842,7 +847,8 @@ HTML;
842 847
             $trID = 'container_scalars_vectors_tr',
843 848
             $Label = 'Format',
844 849
             $Torrent = $Torrent,
845
-            $FileTypes = $ENV->flatten($ENV->CATS->{5}->Formats)
850
+            #$FileTypes = $ENV->flatten($ENV->CATS->{5}->Formats)
851
+            $FileTypes = $ENV->CATS->{5}->Formats
846 852
         );
847 853
 
848 854
 
@@ -853,7 +859,8 @@ HTML;
853 859
             $trID = 'container_images_tr',
854 860
             $Label = 'Format',
855 861
             $Torrent = $Torrent,
856
-            $FileTypes = array_merge($this->ImgFormats, $this->PlainFormats)
862
+            #$FileTypes = array_merge($this->ImgFormats)
863
+            $FileTypes = $ENV->CATS->{8}->Formats
857 864
         );
858 865
 
859 866
 
@@ -864,7 +871,8 @@ HTML;
864 871
             $trID = 'container_spatial_tr',
865 872
             $Label = 'Format',
866 873
             $Torrent = $Torrent,
867
-            $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
868 876
         );
869 877
 
870 878
 
@@ -875,7 +883,8 @@ HTML;
875 883
             $trID = 'container_documents_tr',
876 884
             $Label = 'Format',
877 885
             $Torrent = $Torrent,
878
-            $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
879 888
         );
880 889
 
881 890
 
@@ -886,7 +895,8 @@ HTML;
886 895
             $trID = 'archive_tr',
887 896
             $Label = 'Archive',
888 897
             $Torrent = $Torrent,
889
-            $FileTypes = $this->Archives
898
+            # $ENV->Archives nests -1 deep
899
+            $FileTypes = [$ENV->META->Formats->Archives]
890 900
         );
891 901
 
892 902
 
@@ -1081,6 +1091,22 @@ HTML;
1081 1091
         }
1082 1092
 
1083 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
+
1084 1110
         /**
1085 1111
          * Torrent group description
1086 1112
          *

+ 9
- 1
classes/util.php View File

@@ -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
- 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
         ],

+ 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";

+ 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>

+ 1
- 5
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">

+ 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
 

+ 18
- 18
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">
@@ -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) {

+ 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 }

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

@@ -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)

+ 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
- 58
static/styles/bookish/scss/colors.scss View File

@@ -24,12 +24,6 @@ $shadow: 2px 2px 10px -2px slategray;
24 24
  * Common elements
25 25
  */
26 26
 
27
-.head {
28
-    background: #b3e5fc;
29
-    color: black;
30
-    padding: 0.5em 1rem;
31
-}
32
-
33 27
 /* Alternating tables */
34 28
 #request_table .request:nth-of-type(even) {
35 29
     background: white;
@@ -51,37 +45,6 @@ $shadow: 2px 2px 10px -2px slategray;
51 45
 /**
52 46
  * Fancy torrent search input
53 47
  */
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 48
 
86 49
 checkbox,
87 50
 input[type="checkbox"] {
@@ -93,27 +56,6 @@ input[type="file"] {
93 56
     border: none;
94 57
 }
95 58
 
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 59
 /**
118 60
  * Alerts, Toolbox, etc.
119 61
  * Needs one unified error display

+ 8
- 0
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;

+ 2
- 47
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;
@@ -85,7 +64,7 @@ ol {
85 64
 }
86 65
 
87 66
 .main_column {
88
-    @include column-flex(65%);
67
+    @include column-flex(64%);
89 68
 
90 69
     table {
91 70
         margin-bottom: 1rem;
@@ -93,7 +72,7 @@ ol {
93 72
 }
94 73
 
95 74
 .sidebar {
96
-    @include column-flex(35%);
75
+    @include column-flex(34%);
97 76
     float: right;
98 77
 }
99 78
 
@@ -103,17 +82,6 @@ div.linkbox {
103 82
     padding: 0.5rem;
104 83
 }
105 84
 
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 85
 /* Misc */
118 86
 .torrents_nomatch {
119 87
     margin-top: 1rem;
@@ -171,11 +139,6 @@ div.linkbox {
171 139
     border: none;
172 140
 }
173 141
 
174
-.torrent_table tr {
175
-    /* vertical-align: top; */
176
-    vertical-align: middle;
177
-}
178
-
179 142
 .torrent_table .number_column {
180 143
     text-align: center;
181 144
 }
@@ -186,14 +149,6 @@ div.linkbox {
186 149
 }
187 150
 
188 151
 /* Text elements */
189
-h1,
190
-h2,
191
-h3,
192
-h4 {
193
-    margin: 0.5em 0;
194
-    font-weight: bold;
195
-}
196
-
197 152
 p {
198 153
     margin: 1em 0.5rem;
199 154
 }

+ 33
- 27
static/styles/bookish/scss/tables.scss View File

@@ -2,25 +2,17 @@
2 2
 }
3 3
 
4 4
 table {
5
-    /* border: 2px solid rgba(0, 0, 0, 0.01); */
6
-    border-collapse: collapse;
7 5
     width: 100%;
8 6
 
9
-    /*
10
-    * {
11
-        vertical-align: middle;
7
+    th {
8
+        font-size: 120%;
12 9
     }
13
-    */
14 10
 
11
+    /*
15 12
     tr {
16 13
         background-color: white;
17 14
     }
18
-
19
-    td,
20
-    th {
21
-        padding: 0.5rem;
22
-        text-align: left;
23
-    }
15
+    */
24 16
 }
25 17
 
26 18
 /**
@@ -39,18 +31,15 @@ table {
39 31
     }
40 32
 }
41 33
 
42
-/* Classes */
34
+/**
35
+ * colhead
36
+ * The main table heading.
37
+ */
43 38
 .colhead {
44
-    background: $lb100;
39
+    padding: 0.5em 0;
40
+    border-bottom: 1px solid #e1e1e1;
41
+    font-size: 120%;
45 42
     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 43
 }
55 44
 
56 45
 .colhead .sign,
@@ -66,12 +55,28 @@ td.colhead,
66 55
     font-weight: bold;
67 56
 }
68 57
 
69
-.colhead_dark {
70
-    background: $lb100;
71
-    color: black;
58
+/* Torrent and collage tables */
59
+.torrent_table,
60
+.collage_table {
61
+    tr:nth-child(2n) {
62
+        background-color: whitesmoke;
63
+    }
64
+
65
+    tr:nth-child(2n-1) {
66
+        background-color: white;
67
+    }
68
+
69
+    div.tags {
70
+        font-weight: normal;
71
+        max-width: 500px;
72
+    }
73
+
74
+    span {
75
+        float: right;
76
+    }
72 77
 }
73 78
 
74
-/* Torrent and collage tables */
79
+/*
75 80
 .torrent_table,
76 81
 .collage_table {
77 82
     tr.group {
@@ -108,13 +113,14 @@ td.colhead,
108 113
     tr .center,
109 114
     td {
110 115
         vertical-align: middle;
111
-        /* text-align: center; */
116
+        /* text-align: center; * /
112 117
     }
113 118
     div.tags {
114 119
         font-weight: normal;
115 120
         max-width: 500px;
116 121
     }
117 122
 }
123
+*/
118 124
 
119 125
 .torrent_table .group_torrent .torrent span {
120 126
     font-weight: normal;

+ 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
 /*

+ 9
- 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
  */

+ 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
+*/

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

@@ -0,0 +1,113 @@
1
+/**
2
+ * Fixes needed to use skeleton.css
3
+ * to its best 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
+table.forum_index {
70
+    h4 {
71
+        margin: 0 !important;
72
+    }
73
+}
74
+
75
+label,
76
+legend {
77
+    display: inline !important;
78
+}
79
+
80
+table.torrent_search,
81
+table.torrent_requests {
82
+    th,
83
+    td {
84
+        border-bottom: 0 !important;
85
+        padding: 0.25rem !important;
86
+    }
87
+}
88
+
89
+input,
90
+input[type="search"],
91
+input[type="text"] {
92
+    margin: 0 !important;
93
+}
94
+
95
+ul {
96
+    list-style: circle !important;
97
+}
98
+
99
+pre,
100
+blockquote,
101
+dl,
102
+figure,
103
+table,
104
+p,
105
+ul,
106
+ol,
107
+form {
108
+    margin-bottom: 0 !important;
109
+}
110
+
111
+code {
112
+    padding: 0 !important;
113
+}

+ 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>

Loading…
Cancel
Save