booru 2.6.9 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/dist/Constants.d.ts +7 -5
- package/dist/Constants.d.ts.map +1 -0
- package/dist/Constants.js +15 -10
- package/dist/Constants.js.map +1 -1
- package/dist/Utils.d.ts +12 -3
- package/dist/Utils.d.ts.map +1 -0
- package/dist/Utils.js +49 -19
- package/dist/Utils.js.map +1 -1
- package/dist/boorus/Booru.d.ts +34 -4
- package/dist/boorus/Booru.d.ts.map +1 -0
- package/dist/boorus/Booru.js +114 -37
- package/dist/boorus/Booru.js.map +1 -1
- package/dist/boorus/Derpibooru.d.ts +4 -10
- package/dist/boorus/Derpibooru.d.ts.map +1 -0
- package/dist/boorus/Derpibooru.js +0 -8
- package/dist/boorus/Derpibooru.js.map +1 -1
- package/dist/boorus/XmlBooru.d.ts +2 -8
- package/dist/boorus/XmlBooru.d.ts.map +1 -0
- package/dist/boorus/XmlBooru.js +0 -8
- package/dist/boorus/XmlBooru.js.map +1 -1
- package/dist/index.d.ts +22 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -5
- package/dist/index.js.map +1 -1
- package/dist/sites.json +231 -1
- package/dist/structures/InternalSearchParameters.d.ts +2 -1
- package/dist/structures/InternalSearchParameters.d.ts.map +1 -0
- package/dist/structures/InternalSearchParameters.js.map +1 -1
- package/dist/structures/Post.d.ts +2 -1
- package/dist/structures/Post.d.ts.map +1 -0
- package/dist/structures/Post.js +46 -44
- package/dist/structures/Post.js.map +1 -1
- package/dist/structures/SearchParameters.d.ts +5 -4
- package/dist/structures/SearchParameters.d.ts.map +1 -0
- package/dist/structures/SearchParameters.js.map +1 -1
- package/dist/structures/SearchResults.d.ts +4 -3
- package/dist/structures/SearchResults.d.ts.map +1 -0
- package/dist/structures/SearchResults.js +20 -12
- package/dist/structures/SearchResults.js.map +1 -1
- package/dist/structures/Site.d.ts +3 -2
- package/dist/structures/Site.d.ts.map +1 -0
- package/dist/structures/Site.js.map +1 -1
- package/dist/structures/SiteApi.d.ts +3 -0
- package/dist/structures/SiteApi.d.ts.map +1 -0
- package/dist/structures/SiteApi.js.map +1 -1
- package/dist/structures/SiteInfo.d.ts +2 -1
- package/dist/structures/SiteInfo.d.ts.map +1 -0
- package/dist/structures/SiteInfo.js.map +1 -1
- package/dist/structures/Tag.d.ts +42 -0
- package/dist/structures/Tag.d.ts.map +1 -0
- package/dist/structures/Tag.js +52 -0
- package/dist/structures/Tag.js.map +1 -0
- package/dist/structures/TagListParameters.d.ts +14 -0
- package/dist/structures/TagListParameters.d.ts.map +1 -0
- package/dist/structures/TagListParameters.js +7 -0
- package/dist/structures/TagListParameters.js.map +1 -0
- package/dist/structures/TagListResults.d.ts +53 -0
- package/dist/structures/TagListResults.d.ts.map +1 -0
- package/dist/structures/TagListResults.js +73 -0
- package/dist/structures/TagListResults.js.map +1 -0
- package/package.json +17 -34
- package/readme.md +22 -5
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* @module Structures
|
|
4
4
|
*/
|
|
5
|
-
import SiteApi from './SiteApi';
|
|
6
|
-
import SiteInfo from './SiteInfo';
|
|
5
|
+
import type SiteApi from './SiteApi';
|
|
6
|
+
import type SiteInfo from './SiteInfo';
|
|
7
7
|
/**
|
|
8
8
|
* Represents a site, mostly used for JSDoc
|
|
9
9
|
*/
|
|
@@ -35,3 +35,4 @@ export default class Site {
|
|
|
35
35
|
defaultTags: string[];
|
|
36
36
|
constructor(data: SiteInfo);
|
|
37
37
|
}
|
|
38
|
+
//# sourceMappingURL=Site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Site.d.ts","sourceRoot":"","sources":["../../src/structures/Site.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,OAAO,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAA;AAEtC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,iFAAiF;IAC1E,MAAM,EAAE,MAAM,CAAA;IACrB,6CAA6C;IACtC,IAAI,EAAE,MAAM,CAAA;IACnB,+BAA+B;IACxB,OAAO,EAAE,MAAM,EAAE,CAAA;IACxB,4CAA4C;IACrC,IAAI,EAAE,OAAO,CAAA;IACpB,kDAAkD;IAC3C,GAAG,EAAE,OAAO,CAAA;IACnB,kDAAkD;IAC3C,QAAQ,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACI,MAAM,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B,mCAAmC;IAC5B,QAAQ,EAAE,MAAM,CAAA;IACvB,qEAAqE;IAC9D,OAAO,EAAE,MAAM,CAAA;IACtB,yCAAyC;IAClC,QAAQ,EAAE,OAAO,CAAA;IACxB,oDAAoD;IAC7C,WAAW,EAAE,MAAM,EAAE,CAAA;gBAEhB,IAAI,EAAE,QAAQ;CAa3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Site.js","sourceRoot":"","sources":["../../src/structures/Site.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAKH;;GAEG;AACH,MAAqB,IAAI;IACvB,iFAAiF;IAC1E,MAAM,CAAQ;IACrB,6CAA6C;IACtC,IAAI,CAAQ;IACnB,+BAA+B;IACxB,OAAO,CAAU;IACxB,4CAA4C;IACrC,IAAI,CAAS;IACpB,kDAAkD;IAC3C,GAAG,CAAS;IACnB,kDAAkD;IAC3C,QAAQ,CAAQ;IACvB;;;OAGG;IACI,MAAM,CAAkB;IAC/B,mCAAmC;IAC5B,QAAQ,CAAQ;IACvB,qEAAqE;IAC9D,OAAO,CAAQ;IACtB,yCAAyC;IAClC,QAAQ,CAAS;IACxB,oDAAoD;IAC7C,WAAW,CAAU;IAE5B,YAAY,IAAc;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA;QACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAA;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAA;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAA;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,GAAG,CAAA;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAA;QACtC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA;IAC3C,CAAC;CACF;AAxCD,uBAwCC"}
|
|
1
|
+
{"version":3,"file":"Site.js","sourceRoot":"","sources":["../../src/structures/Site.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAKH;;GAEG;AACH,MAAqB,IAAI;IACvB,iFAAiF;IAC1E,MAAM,CAAQ;IACrB,6CAA6C;IACtC,IAAI,CAAQ;IACnB,+BAA+B;IACxB,OAAO,CAAU;IACxB,4CAA4C;IACrC,IAAI,CAAS;IACpB,kDAAkD;IAC3C,GAAG,CAAS;IACnB,kDAAkD;IAC3C,QAAQ,CAAQ;IACvB;;;OAGG;IACI,MAAM,CAAkB;IAC/B,mCAAmC;IAC5B,QAAQ,CAAQ;IACvB,qEAAqE;IAC9D,OAAO,CAAQ;IACtB,yCAAyC;IAClC,QAAQ,CAAS;IACxB,oDAAoD;IAC7C,WAAW,CAAU;IAE5B,YAAY,IAAc;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA;QACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAA;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAA;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAA;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,GAAG,CAAA;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAA;QACtC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA;IAC3C,CAAC;CACF;AAxCD,uBAwCC","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\nimport type SiteApi from './SiteApi'\nimport type SiteInfo from './SiteInfo'\n\n/**\n * Represents a site, mostly used for JSDoc\n */\nexport default class Site {\n /** The domain of the Site (the \"google.com\" part of \"https://google.com/foo\") */\n public domain: string\n /** The type of this site (json/xml/derpi) */\n public type: string\n /** The aliases of this site */\n public aliases: string[]\n /** If this site serves NSFW posts or not */\n public nsfw: boolean\n /** An object representing the api of this site */\n public api: SiteApi\n /** The url query param to paginate on the site */\n public paginate: string\n /**\n * If the site supports `order:random`.\n * If a string, this means a custom random system is used :/\n */\n public random: boolean | string\n /** The url query param for tags */\n public tagQuery: string\n /** The character to use to join tags when creating the search url */\n public tagJoin: string\n /** If this site supports only http:// */\n public insecure: boolean\n /** Tags to add to every request, if not included */\n public defaultTags: string[]\n\n constructor(data: SiteInfo) {\n this.domain = data.domain\n this.type = data.type ?? 'json'\n this.aliases = data.aliases ?? []\n this.nsfw = data.nsfw\n this.api = data.api ?? {}\n this.paginate = data.paginate ?? 'page'\n this.random = data.random ?? false\n this.tagQuery = data.tagQuery ?? 'tags'\n this.tagJoin = data.tagJoin ?? '+'\n this.insecure = data.insecure ?? false\n this.defaultTags = data.defaultTags ?? []\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SiteApi.d.ts","sourceRoot":"","sources":["../../src/structures/SiteApi.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,OAAO,WAAW,OAAO;IAC9B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SiteApi.js","sourceRoot":"","sources":["../../src/structures/SiteApi.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
|
1
|
+
{"version":3,"file":"SiteApi.js","sourceRoot":"","sources":["../../src/structures/SiteApi.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\n/**\n * Represents the api of a {@link Site}\n * <p>Each property is a path on the {@link Site}\n */\nexport default interface SiteApi {\n /** The path to search for posts */\n search: string\n /** The path to view a post by ID */\n postView: string\n /** The path to retrieve a list of tags */\n tagList?: string\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* @module Structures
|
|
4
4
|
*/
|
|
5
|
-
import SiteApi from './SiteApi';
|
|
5
|
+
import type SiteApi from './SiteApi';
|
|
6
6
|
/**
|
|
7
7
|
* Represents the info needed to create a new {@link Site}
|
|
8
8
|
* <p>Same properties as {@link Site}, but some optional</p>
|
|
@@ -32,3 +32,4 @@ export default interface SiteInfo {
|
|
|
32
32
|
/** Tags to add to every request, if not included */
|
|
33
33
|
defaultTags?: string[];
|
|
34
34
|
}
|
|
35
|
+
//# sourceMappingURL=SiteInfo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SiteInfo.d.ts","sourceRoot":"","sources":["../../src/structures/SiteInfo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,OAAO,MAAM,WAAW,CAAA;AAEpC;;;;GAIG;AACH,MAAM,CAAC,OAAO,WAAW,QAAQ;IAC/B,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,4CAA4C;IAC5C,IAAI,EAAE,OAAO,CAAA;IACb,kDAAkD;IAClD,GAAG,EAAE,OAAO,CAAA;IACZ,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,MAAM,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SiteInfo.js","sourceRoot":"","sources":["../../src/structures/SiteInfo.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
|
1
|
+
{"version":3,"file":"SiteInfo.js","sourceRoot":"","sources":["../../src/structures/SiteInfo.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\nimport type SiteApi from './SiteApi'\n\n/**\n * Represents the info needed to create a new {@link Site}\n * <p>Same properties as {@link Site}, but some optional</p>\n * <p>Mostly just here to reflect what sites.json should look like\n */\nexport default interface SiteInfo {\n /** The domain of the Site (the \"google.com\" part of \"https://google.com/foo\") */\n domain: string\n /** The type of this site (json/xml/derpi) */\n type: string\n /** The aliases of this site */\n aliases: string[]\n /** If this site serves NSFW posts or not */\n nsfw: boolean\n /** An object representing the api of this site */\n api: SiteApi\n /** The url query param to paginate on the site */\n paginate?: string\n /** If the site supports `order:random` */\n random: boolean | string\n /** The url query param for tags */\n tagQuery?: string\n /** The character to use to join tags when creating the search url */\n tagJoin?: string\n /** If this site supports only http:// */\n insecure?: boolean\n /** Tags to add to every request, if not included */\n defaultTags?: string[]\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module Structures
|
|
4
|
+
*/
|
|
5
|
+
import type Booru from '../boorus/Booru';
|
|
6
|
+
/**
|
|
7
|
+
* A tag from a booru with a few common props
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```
|
|
11
|
+
* Tag {
|
|
12
|
+
* name: 'tag_name',
|
|
13
|
+
* count: 1234,
|
|
14
|
+
* type: 0,
|
|
15
|
+
* ambiguous: false,
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export default class Tag {
|
|
20
|
+
/** The {@link Booru} it came from */
|
|
21
|
+
booru: Booru;
|
|
22
|
+
/** The id of the tag */
|
|
23
|
+
id: number | string;
|
|
24
|
+
/** The name of the tag */
|
|
25
|
+
name: string;
|
|
26
|
+
/** The count of the tag */
|
|
27
|
+
count: number;
|
|
28
|
+
/** If the tag is a meta tag */
|
|
29
|
+
type: number;
|
|
30
|
+
/** If the tag is ambiguous */
|
|
31
|
+
ambiguous?: boolean | null;
|
|
32
|
+
/** All the data given by the booru @private */
|
|
33
|
+
protected data: any;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new tag from the data given by the booru
|
|
36
|
+
*
|
|
37
|
+
* @param data The data from the booru
|
|
38
|
+
* @param booru The booru this tag is from
|
|
39
|
+
*/
|
|
40
|
+
constructor(data: any, booru: Booru);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=Tag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tag.d.ts","sourceRoot":"","sources":["../../src/structures/Tag.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,OAAO,GAAG;IACtB,qCAAqC;IAC9B,KAAK,EAAE,KAAK,CAAA;IACnB,wBAAwB;IACjB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,0BAA0B;IACnB,IAAI,EAAE,MAAM,CAAA;IACnB,2BAA2B;IACpB,KAAK,EAAE,MAAM,CAAA;IACpB,+BAA+B;IACxB,IAAI,EAAE,MAAM,CAAA;IACnB,8BAA8B;IACvB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAEjC,+CAA+C;IAC/C,SAAS,CAAC,IAAI,EAAE,GAAG,CAAA;IAEnB;;;;;OAKG;gBACS,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK;CAUpC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
* @module Structures
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
/**
|
|
8
|
+
* A tag from a booru with a few common props
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```
|
|
12
|
+
* Tag {
|
|
13
|
+
* name: 'tag_name',
|
|
14
|
+
* count: 1234,
|
|
15
|
+
* type: 0,
|
|
16
|
+
* ambiguous: false,
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
class Tag {
|
|
21
|
+
/** The {@link Booru} it came from */
|
|
22
|
+
booru;
|
|
23
|
+
/** The id of the tag */
|
|
24
|
+
id;
|
|
25
|
+
/** The name of the tag */
|
|
26
|
+
name;
|
|
27
|
+
/** The count of the tag */
|
|
28
|
+
count;
|
|
29
|
+
/** If the tag is a meta tag */
|
|
30
|
+
type;
|
|
31
|
+
/** If the tag is ambiguous */
|
|
32
|
+
ambiguous;
|
|
33
|
+
/** All the data given by the booru @private */
|
|
34
|
+
data;
|
|
35
|
+
/**
|
|
36
|
+
* Create a new tag from the data given by the booru
|
|
37
|
+
*
|
|
38
|
+
* @param data The data from the booru
|
|
39
|
+
* @param booru The booru this tag is from
|
|
40
|
+
*/
|
|
41
|
+
constructor(data, booru) {
|
|
42
|
+
this.data = data;
|
|
43
|
+
this.booru = booru;
|
|
44
|
+
this.id = data.id;
|
|
45
|
+
this.name = data.name;
|
|
46
|
+
this.count = data.count ?? data.post_count ?? 0;
|
|
47
|
+
this.type = data.type ?? data.category ?? 0;
|
|
48
|
+
this.ambiguous = data.ambiguous ? data.ambiguous !== 'false' : null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.default = Tag;
|
|
52
|
+
//# sourceMappingURL=Tag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tag.js","sourceRoot":"","sources":["../../src/structures/Tag.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAIH;;;;;;;;;;;;GAYG;AACH,MAAqB,GAAG;IACtB,qCAAqC;IAC9B,KAAK,CAAO;IACnB,wBAAwB;IACjB,EAAE,CAAiB;IAC1B,0BAA0B;IACnB,IAAI,CAAQ;IACnB,2BAA2B;IACpB,KAAK,CAAQ;IACpB,+BAA+B;IACxB,IAAI,CAAQ;IACnB,8BAA8B;IACvB,SAAS,CAAiB;IAEjC,+CAA+C;IACrC,IAAI,CAAK;IAEnB;;;;;OAKG;IACH,YAAY,IAAS,EAAE,KAAY;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAElB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAA;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,CAAA;QAC/C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAA;QAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;IACrE,CAAC;CACF;AAjCD,sBAiCC","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\nimport type Booru from '../boorus/Booru'\n\n/**\n * A tag from a booru with a few common props\n *\n * @example\n * ```\n * Tag {\n * name: 'tag_name',\n * count: 1234,\n * type: 0,\n * ambiguous: false,\n * }\n * ```\n */\nexport default class Tag {\n /** The {@link Booru} it came from */\n public booru: Booru\n /** The id of the tag */\n public id: number | string\n /** The name of the tag */\n public name: string\n /** The count of the tag */\n public count: number\n /** If the tag is a meta tag */\n public type: number\n /** If the tag is ambiguous */\n public ambiguous?: boolean | null\n\n /** All the data given by the booru @private */\n protected data: any\n\n /**\n * Create a new tag from the data given by the booru\n *\n * @param data The data from the booru\n * @param booru The booru this tag is from\n */\n constructor(data: any, booru: Booru) {\n this.data = data\n this.booru = booru\n\n this.id = data.id\n this.name = data.name\n this.count = data.count ?? data.post_count ?? 0\n this.type = data.type ?? data.category ?? 0\n this.ambiguous = data.ambiguous ? data.ambiguous !== 'false' : null\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module Structures
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Just an interface for {@link Booru}'s tag list params :)
|
|
7
|
+
*/
|
|
8
|
+
export default interface SearchParameters {
|
|
9
|
+
/** The limit on *max* tags to show, you might get less tags than this */
|
|
10
|
+
limit?: number | undefined;
|
|
11
|
+
/** Which page of results to fetch */
|
|
12
|
+
page?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=TagListParameters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagListParameters.d.ts","sourceRoot":"","sources":["../../src/structures/TagListParameters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,gBAAgB;IACvC,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagListParameters.js","sourceRoot":"","sources":["../../src/structures/TagListParameters.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\n/**\n * Just an interface for {@link Booru}'s tag list params :)\n */\nexport default interface SearchParameters {\n /** The limit on *max* tags to show, you might get less tags than this */\n limit?: number | undefined\n /** Which page of results to fetch */\n page?: number | undefined\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module Structures
|
|
4
|
+
*/
|
|
5
|
+
import type Booru from '../boorus/Booru';
|
|
6
|
+
import type Tag from './Tag';
|
|
7
|
+
import type TagListParameters from './TagListParameters';
|
|
8
|
+
/**
|
|
9
|
+
* Represents a page of tag list results, works like an array of {@link Tag}
|
|
10
|
+
* <p> Usable like an array and allows to easily get the next page
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```
|
|
14
|
+
* const Booru = require('booru')
|
|
15
|
+
* // Safebooru
|
|
16
|
+
* const sb = new Booru('sb')
|
|
17
|
+
*
|
|
18
|
+
* const tags = await sb.tagList()
|
|
19
|
+
*
|
|
20
|
+
* // Log the tags from the first page, then from the second
|
|
21
|
+
* tags.forEach(t => console.log(t.name))
|
|
22
|
+
* const tags2 = await tags.nextPage()
|
|
23
|
+
* tags2.forEach(t => console.log(t.name))
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export default class TagListResults extends Array<Tag> {
|
|
27
|
+
/** The booru used for this tag list */
|
|
28
|
+
booru: Booru;
|
|
29
|
+
/** The page of this tag list */
|
|
30
|
+
page: number;
|
|
31
|
+
/** The options used for this tag list */
|
|
32
|
+
readonly options: TagListParameters;
|
|
33
|
+
/** The tags from this tag list result */
|
|
34
|
+
readonly tags: Tag[];
|
|
35
|
+
/** @private */
|
|
36
|
+
constructor(tags: Tag[], options: TagListParameters, booru: Booru);
|
|
37
|
+
/**
|
|
38
|
+
* Get the first tag in this result set
|
|
39
|
+
* @return {Tag}
|
|
40
|
+
*/
|
|
41
|
+
get first(): Tag;
|
|
42
|
+
/**
|
|
43
|
+
* Get the last tag in this result set
|
|
44
|
+
* @return {Tag}
|
|
45
|
+
*/
|
|
46
|
+
get last(): Tag;
|
|
47
|
+
/**
|
|
48
|
+
* Get the next page of results
|
|
49
|
+
* @returns {Promise<TagListResults>} The next page of results
|
|
50
|
+
*/
|
|
51
|
+
nextPage(): Promise<TagListResults>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=TagListResults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagListResults.d.ts","sourceRoot":"","sources":["../../src/structures/TagListResults.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAA;AAC5B,OAAO,KAAK,iBAAiB,MAAM,qBAAqB,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,KAAK,CAAC,GAAG,CAAC;IACpD,uCAAuC;IAChC,KAAK,EAAE,KAAK,CAAA;IACnB,gCAAgC;IACzB,IAAI,EAAE,MAAM,CAAA;IACnB,yCAAyC;IACzC,SAAgB,OAAO,EAAE,iBAAiB,CAAA;IAC1C,yCAAyC;IACzC,SAAgB,IAAI,EAAE,GAAG,EAAE,CAAA;IAE3B,eAAe;gBACH,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK;IAajE;;;OAGG;IACH,IAAI,KAAK,IAAI,GAAG,CAEf;IAED;;;OAGG;IACH,IAAI,IAAI,IAAI,GAAG,CAEd;IAED;;;OAGG;IACU,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;CAYjD"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
* @module Structures
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
/**
|
|
8
|
+
* Represents a page of tag list results, works like an array of {@link Tag}
|
|
9
|
+
* <p> Usable like an array and allows to easily get the next page
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```
|
|
13
|
+
* const Booru = require('booru')
|
|
14
|
+
* // Safebooru
|
|
15
|
+
* const sb = new Booru('sb')
|
|
16
|
+
*
|
|
17
|
+
* const tags = await sb.tagList()
|
|
18
|
+
*
|
|
19
|
+
* // Log the tags from the first page, then from the second
|
|
20
|
+
* tags.forEach(t => console.log(t.name))
|
|
21
|
+
* const tags2 = await tags.nextPage()
|
|
22
|
+
* tags2.forEach(t => console.log(t.name))
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
class TagListResults extends Array {
|
|
26
|
+
/** The booru used for this tag list */
|
|
27
|
+
booru;
|
|
28
|
+
/** The page of this tag list */
|
|
29
|
+
page;
|
|
30
|
+
/** The options used for this tag list */
|
|
31
|
+
options;
|
|
32
|
+
/** The tags from this tag list result */
|
|
33
|
+
tags;
|
|
34
|
+
/** @private */
|
|
35
|
+
constructor(tags, options, booru) {
|
|
36
|
+
super(tags.length);
|
|
37
|
+
for (let i = 0; i < tags.length; i++) {
|
|
38
|
+
this[i] = tags[i];
|
|
39
|
+
}
|
|
40
|
+
this.tags = tags;
|
|
41
|
+
this.options = options;
|
|
42
|
+
this.booru = booru;
|
|
43
|
+
this.page = options ? (options.page ?? 0) : 0;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the first tag in this result set
|
|
47
|
+
* @return {Tag}
|
|
48
|
+
*/
|
|
49
|
+
get first() {
|
|
50
|
+
return this[0];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the last tag in this result set
|
|
54
|
+
* @return {Tag}
|
|
55
|
+
*/
|
|
56
|
+
get last() {
|
|
57
|
+
return this[this.length - 1];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the next page of results
|
|
61
|
+
* @returns {Promise<TagListResults>} The next page of results
|
|
62
|
+
*/
|
|
63
|
+
async nextPage() {
|
|
64
|
+
const nextPage = this.page + 1;
|
|
65
|
+
const newTags = await this.booru.tagList({
|
|
66
|
+
limit: this.options.limit,
|
|
67
|
+
page: nextPage,
|
|
68
|
+
});
|
|
69
|
+
return new TagListResults(newTags, { ...this.options, page: nextPage }, this.booru);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.default = TagListResults;
|
|
73
|
+
//# sourceMappingURL=TagListResults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagListResults.js","sourceRoot":"","sources":["../../src/structures/TagListResults.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAqB,cAAe,SAAQ,KAAU;IACpD,uCAAuC;IAChC,KAAK,CAAO;IACnB,gCAAgC;IACzB,IAAI,CAAQ;IACnB,yCAAyC;IACzB,OAAO,CAAmB;IAC1C,yCAAyC;IACzB,IAAI,CAAO;IAE3B,eAAe;IACf,YAAY,IAAW,EAAE,OAA0B,EAAE,KAAY;QAC/D,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,CAAC;IAED;;;OAGG;IACH,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,CAAC,CAAC,CAAA;IAChB,CAAC;IAED;;;OAGG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,QAAQ;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;QAC9B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YACvC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;YACzB,IAAI,EAAE,QAAQ;SACf,CAAC,CAAA;QACF,OAAO,IAAI,cAAc,CACvB,OAAO,EACP,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EACnC,IAAI,CAAC,KAAK,CACX,CAAA;IACH,CAAC;CACF;AAxDD,iCAwDC","sourcesContent":["/**\n * @packageDocumentation\n * @module Structures\n */\n\nimport type Booru from '../boorus/Booru'\nimport type Tag from './Tag'\nimport type TagListParameters from './TagListParameters'\n\n/**\n * Represents a page of tag list results, works like an array of {@link Tag}\n * <p> Usable like an array and allows to easily get the next page\n *\n * @example\n * ```\n * const Booru = require('booru')\n * // Safebooru\n * const sb = new Booru('sb')\n *\n * const tags = await sb.tagList()\n *\n * // Log the tags from the first page, then from the second\n * tags.forEach(t => console.log(t.name))\n * const tags2 = await tags.nextPage()\n * tags2.forEach(t => console.log(t.name))\n * ```\n */\nexport default class TagListResults extends Array<Tag> {\n /** The booru used for this tag list */\n public booru: Booru\n /** The page of this tag list */\n public page: number\n /** The options used for this tag list */\n public readonly options: TagListParameters\n /** The tags from this tag list result */\n public readonly tags: Tag[]\n\n /** @private */\n constructor(tags: Tag[], options: TagListParameters, booru: Booru) {\n super(tags.length)\n\n for (let i = 0; i < tags.length; i++) {\n this[i] = tags[i]\n }\n\n this.tags = tags\n this.options = options\n this.booru = booru\n this.page = options ? (options.page ?? 0) : 0\n }\n\n /**\n * Get the first tag in this result set\n * @return {Tag}\n */\n get first(): Tag {\n return this[0]\n }\n\n /**\n * Get the last tag in this result set\n * @return {Tag}\n */\n get last(): Tag {\n return this[this.length - 1]\n }\n\n /**\n * Get the next page of results\n * @returns {Promise<TagListResults>} The next page of results\n */\n public async nextPage(): Promise<TagListResults> {\n const nextPage = this.page + 1\n const newTags = await this.booru.tagList({\n limit: this.options.limit,\n page: nextPage,\n })\n return new TagListResults(\n newTags,\n { ...this.options, page: nextPage },\n this.booru,\n )\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "booru",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Search (and do other things) on a bunch of different boorus!",
|
|
5
5
|
"author": "AtoraSuunva (https://github.com/AtoraSuunva/)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,16 +14,6 @@
|
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/AtoraSuunva/booru/issues"
|
|
16
16
|
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"file": "node --loader ts-node/esm",
|
|
19
|
-
"test": "jest",
|
|
20
|
-
"lint": "eslint --ext .ts src/ && prettier --check 'src/**/*.ts' && tsc --noEmit",
|
|
21
|
-
"lint:fix": "eslint --ext .ts src/ && prettier --write 'src/**/*.ts' && tsc --noEmit",
|
|
22
|
-
"prebuild": "npm run lint",
|
|
23
|
-
"build": "tsc",
|
|
24
|
-
"postbuild": "node ./minify.js",
|
|
25
|
-
"prepublishOnly": "npm run build"
|
|
26
|
-
},
|
|
27
17
|
"keywords": [
|
|
28
18
|
"booru",
|
|
29
19
|
"e621",
|
|
@@ -40,31 +30,17 @@
|
|
|
40
30
|
"derpibooru"
|
|
41
31
|
],
|
|
42
32
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
33
|
+
"node": ">=20"
|
|
44
34
|
},
|
|
45
35
|
"dependencies": {
|
|
46
|
-
"fast-xml-parser": "^
|
|
47
|
-
"undici": "^
|
|
36
|
+
"fast-xml-parser": "^5.2.5",
|
|
37
|
+
"undici": "^7.2.0"
|
|
48
38
|
},
|
|
49
39
|
"devDependencies": {
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"@swc/core": "^1.7.42",
|
|
55
|
-
"@types/jest": "^29.5.14",
|
|
56
|
-
"@types/node": "^22.8.7",
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
|
58
|
-
"@typescript-eslint/parser": "^7.17.0",
|
|
59
|
-
"eslint": "^8.57.0",
|
|
60
|
-
"eslint-config-prettier": "^9.1.0",
|
|
61
|
-
"eslint-plugin-import": "^2.31.0",
|
|
62
|
-
"eslint-plugin-jsdoc": "^48.8.3",
|
|
63
|
-
"jest": "^29.7.0",
|
|
64
|
-
"prettier": "^3.3.3",
|
|
65
|
-
"terser": "^5.36.0",
|
|
66
|
-
"ts-node": "^10.9.2",
|
|
67
|
-
"typescript": "^5.6.3"
|
|
40
|
+
"@biomejs/biome": "^2.0.5",
|
|
41
|
+
"@types/node": "^24.0.3",
|
|
42
|
+
"tsx": "^4.19.2",
|
|
43
|
+
"typescript": "^5.7.2"
|
|
68
44
|
},
|
|
69
45
|
"files": [
|
|
70
46
|
"dist/"
|
|
@@ -90,5 +66,12 @@
|
|
|
90
66
|
"name": "AtoraSuunva",
|
|
91
67
|
"url": "https://github.com/AtoraSuunva"
|
|
92
68
|
}
|
|
93
|
-
]
|
|
94
|
-
|
|
69
|
+
],
|
|
70
|
+
"scripts": {
|
|
71
|
+
"test": "tsx --test",
|
|
72
|
+
"lint": "biome check && tsc --noEmit",
|
|
73
|
+
"lint:fix": "biome check --write && tsc --noEmit",
|
|
74
|
+
"prebuild": "pnpm run lint",
|
|
75
|
+
"build": "tsc --build"
|
|
76
|
+
}
|
|
77
|
+
}
|
package/readme.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> _A node package to search boorus_
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
  
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Only [non-EoL](https://nodejs.org/en/about/previous-releases) versions of Node.js are tested and officially supported. EoL versions are unsupported. Other runtimes (like web, Deno, and Bun) aren't _officially_ supported but issues and PRs are accepted for them.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
```sh
|
|
26
26
|
npm add booru
|
|
27
27
|
# or
|
|
28
|
+
pnpm add booru
|
|
29
|
+
# or
|
|
28
30
|
yarn add booru
|
|
29
31
|
```
|
|
30
32
|
|
|
@@ -33,6 +35,18 @@ yarn add booru
|
|
|
33
35
|
## Usage
|
|
34
36
|
|
|
35
37
|
```js
|
|
38
|
+
import { search, forSite } from 'booru'
|
|
39
|
+
|
|
40
|
+
const posts = await search('safebooru', ['glaceon'], {
|
|
41
|
+
limit: 3,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
for (const post of posts) {
|
|
45
|
+
console.log(post.fileUrl, post.postView)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Or, using alias support and creating
|
|
49
|
+
|
|
36
50
|
const Booru = require('booru')
|
|
37
51
|
|
|
38
52
|
Booru.search('safebooru', ['glaceon'], { limit: 3, random: true }).then(
|
|
@@ -42,9 +56,9 @@ Booru.search('safebooru', ['glaceon'], { limit: 3, random: true }).then(
|
|
|
42
56
|
)
|
|
43
57
|
|
|
44
58
|
// or (using alias support and creating boorus)
|
|
45
|
-
const sb =
|
|
59
|
+
const sb = forSite('sb')
|
|
46
60
|
|
|
47
|
-
sb.search(['cat', 'dog'], { limit: 2 })
|
|
61
|
+
const petPosts = await sb.search(['cat', 'dog'], { limit: 2 })
|
|
48
62
|
```
|
|
49
63
|
|
|
50
64
|
See [example.js](./example.js) for more examples
|
|
@@ -92,7 +106,7 @@ Derpibooru has `Safe, Suggestive, Questionable, Explicit`, although `Suggestive`
|
|
|
92
106
|
|
|
93
107
|
Sure! Just fork this repo, push your changes, and then make a PR.
|
|
94
108
|
|
|
95
|
-
I'll accept PR based on what they do
|
|
109
|
+
I'll accept PR based on what they do. Make sure your changes pass the lint (`pnpm run lint:fix`) and tests (`pnpm run test`).
|
|
96
110
|
|
|
97
111
|
### Why?
|
|
98
112
|
|
|
@@ -129,4 +143,7 @@ Why not?
|
|
|
129
143
|
|
|
130
144
|
> [Copy tags argument so it's not modified](https://github.com/AtoraSuunva/booru/pull/103)
|
|
131
145
|
|
|
146
|
+
[ColonelBologna](https://github.com/ColonelBologna)
|
|
147
|
+
|
|
148
|
+
> [Tag list](https://github.com/AtoraSuunva/booru/pull/114)
|
|
132
149
|
---
|