nekosia.js 0.1.4 β†’ 0.2.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/README.md CHANGED
@@ -3,10 +3,10 @@
3
3
  </div>
4
4
 
5
5
  Nekosia.js is a Node.js module that provides easy access to the Nekosia API, a rich source of anime-themed images.
6
- The API offers a wide range of categories, allowing you to quickly and flexibly search for images according to your preferences and needs.
7
- You decide what images you want to retrieve, which makes our API stand out from others.
6
+ The API offers a wide range of categories, allowing you to quickly and flexibly search for images based on your preferences and needs.
7
+ You have full control over the images you retrieve, which sets our API apart from others.
8
8
 
9
- But that's not all! The API also supports sessions (based on user ID or IP address), helping to avoid repeated images.
9
+ But that's not all! The API also supports sessions (based on user ID or IP address), helping to prevent repeated images.
10
10
 
11
11
  <div align="center">
12
12
  <a href="https://www.npmjs.com/package/nekosia.js">
@@ -24,18 +24,18 @@ But that's not all! The API also supports sessions (based on user ID or IP addre
24
24
 
25
25
 
26
26
  ## πŸ” Key Features of the API
27
- - **Wide range of categories:** Nekosia API offers [virtually every kind of anime graphic](https://nekosia.cat/documentation?page=api-endpoints#main-categories), not limited to neko images.
28
- - **High image quality:** All images are carefully selected and checked for quality and appropriateness.
29
- - **Sessions:** The API supports sessions (based on ID or IP address), which helps avoid duplicate images.
27
+ - **Wide range of categories:** Nekosia API offers [virtually every kind of anime graphic](https://nekosia.cat/documentation?page=api-endpoints#main-categories), not just neko images.
28
+ - **High image quality:** All images are carefully selected and checked for both quality and appropriateness.
29
+ - **Sessions:** The API supports sessions (based on ID or IP address), helping to avoid duplicate images.
30
30
  - **Dominant colors:** The API returns a palette of dominant colors for each image.
31
- - **Image compression:** JSON responses include a link to a compressed image that is much smaller than the original. This can be useful if you want images to load quickly on client devices without sacrificing quality.
32
- - **Security:** Nekosia API ensures that all provided content is free from NSFW material, making it one of the most trusted sources of anime-themed images.
31
+ - **Image compression:** JSON responses include a link to a compressed image with a significantly reduced file size compared to the original. This ensures faster load times on client devices without sacrificing quality.
32
+ - **Security:** Nekosia API guarantees that all content is free from NSFW material, making it one of the most trusted sources for anime-themed images.
33
33
 
34
34
  ...and that’s not all!
35
35
 
36
36
 
37
37
  ## πŸ“˜ Best Anime Booru
38
- Nekosia also offers its own [Booru](https://nekosia.cat/booru), allowing you to browse images returned by the API.
38
+ Nekosia also offers its own [Booru](https://nekosia.cat/booru), allowing you to browse images returned by the API.
39
39
  Users can edit image information, such as tags, which are crucial for us.
40
40
 
41
41
 
@@ -47,7 +47,7 @@ Check out the [official documentation](https://nekosia.cat/documentation) to lea
47
47
  To install the Nekosia.js module, use the following command:
48
48
 
49
49
  ```bash
50
- npm install neksosia.js
50
+ npm install nekosia.js
51
51
  ```
52
52
 
53
53
 
@@ -63,20 +63,24 @@ The full list of tags is available [on the Booru site](https://nekosia.cat/booru
63
63
  const { NekosiaAPI } = require('nekosia.js');
64
64
 
65
65
  (async () => {
66
- const response = await NekosiaAPI.fetchImages('catgirl');
67
- console.log(response); // Sample response: https://nekosia.cat/documentation?page=api-endpoints#example-response
66
+ const response1 = await NekosiaAPI.fetchCategoryImages('catgirl');
67
+ console.log(response1);
68
+
69
+ const response2 = await NekosiaAPI.fetchImages({ session: 'ip', count: 1, tags: ['cute', 'blue-hair'], blacklist: ['yellow-hair'] });
70
+ console.log(response2);
71
+
72
+ // https://nekosia.cat/documentation?page=api-endpoints#example-response
68
73
  })();
69
74
  ```
70
75
 
71
-
72
76
  ### IP-based Sessions
73
- In this example, we used an IP-based session. What does this mean? Thanks to this solution, a user with a specific IP address will not encounter duplicates when randomly selecting images.
77
+ In this example, we used an IP-based session. What does this mean? Thanks to this solution, a user with a specific IP address will not encounter duplicate images when selecting them randomly.
74
78
 
75
79
  ```js
76
80
  const { NekosiaAPI } = require('nekosia.js');
77
81
 
78
82
  (async () => {
79
- const response = await NekosiaAPI.fetchImages('catgirl', {
83
+ const response = await NekosiaAPI.fetchCategoryImages('catgirl', {
80
84
  session: 'ip',
81
85
  count: 1,
82
86
  additionalTags: [],
@@ -88,13 +92,13 @@ const { NekosiaAPI } = require('nekosia.js');
88
92
  ```
89
93
 
90
94
  ### ID-based Sessions
91
- You can also use `id`, but this will require providing a user identifier (e.g., from Discord). Pass this information in `id` as a string.
95
+ You can also use `id`, but this requires providing a user identifier (e.g., from Discord). Pass this information in `id` as a string.
92
96
 
93
97
  ```js
94
98
  const { NekosiaAPI } = require('nekosia.js');
95
99
 
96
100
  (async () => {
97
- const response = await NekosiaAPI.fetchImages('catgirl', {
101
+ const response = await NekosiaAPI.fetchCategoryImages('catgirl', {
98
102
  session: 'id',
99
103
  id: '561621386765971781',
100
104
  count: 1,
@@ -110,6 +114,16 @@ const { NekosiaAPI } = require('nekosia.js');
110
114
  https://github.com/Nekosia-API/nekosia.js/tree/main/examples
111
115
 
112
116
 
117
+ ## Tags
118
+ ```js
119
+ const { NekosiaAPI } = require('nekosia.js');
120
+
121
+ (async () => {
122
+ console.log(await NekosiaAPI.fetchTags()); // Simply returns all available tags, etc.
123
+ })();
124
+ ```
125
+
126
+
113
127
  ## Versions
114
128
  ```js
115
129
  const { NekosiaVersion } = require('nekosia.js');
@@ -122,8 +136,8 @@ const { NekosiaVersion } = require('nekosia.js');
122
136
 
123
137
 
124
138
  ## ⭐ Β» Thanks
125
- If you find the API or this module useful, consider giving a star to the [repository](https://github.com/sefinek24/nekosia.js).
126
- If you have questions or issues, create a new [Issue](https://github.com/Nekosia-API/nekosia.js/issues/new) or join the [Discord server](https://discord.gg/pba76vJhcP).
139
+ If you find the API or this module useful, consider giving a star to the [repository](https://github.com/Nekosia-API/nekosia.js).
140
+ If you have any questions or issues, create a new [Issue](https://github.com/Nekosia-API/nekosia.js/issues/new) or join the [Discord server](https://discord.gg/pba76vJhcP).
127
141
 
128
142
 
129
143
  ## πŸ“‘ Β» MIT License
@@ -2,7 +2,7 @@ const { NekosiaAPI } = require('../index.js');
2
2
 
3
3
  const fetchImages = async (category, options = {}) => {
4
4
  try {
5
- const response = await NekosiaAPI.fetchImages(category, options);
5
+ const response = await NekosiaAPI.fetchCategoryImages(category, options);
6
6
  console.log(`${category.toUpperCase()}:`, response);
7
7
  } catch (err) {
8
8
  console.error(`Error fetching ${category} images:`, err);
@@ -12,4 +12,5 @@ const fetchImages = async (category, options = {}) => {
12
12
  (async () => {
13
13
  await fetchImages('catgirl');
14
14
  await fetchImages('foxgirl', { session: 'id', id: 'user123', count: 2 });
15
+ await fetchImages('catgirl', { tags: 'animal-ears' });
15
16
  })();
@@ -1,11 +1,11 @@
1
1
  const { NekosiaAPI } = require('../index.js');
2
2
 
3
3
  (async () => {
4
- const response = await NekosiaAPI.fetchImages('foxgirl', {
4
+ const response = await NekosiaAPI.fetchCategoryImages('foxgirl', {
5
5
  session: 'ip',
6
6
  count: 1,
7
7
  additionalTags: ['cute', 'sakura', 'cherry-blossom'],
8
- blacklistedTags: ['beret']
8
+ blacklistedTags: ['beret'],
9
9
  });
10
10
 
11
11
  console.log(response);
@@ -0,0 +1,6 @@
1
+ const { NekosiaAPI } = require('../index.js');
2
+
3
+ (async () => {
4
+ const response = await NekosiaAPI.fetchImages({ session: 'ip', count: 1, tags: ['cute', 'blue-hair'], blacklist: ['yellow-hair'] });
5
+ console.log(response);
6
+ })();
@@ -0,0 +1,6 @@
1
+ const { NekosiaAPI } = require('../index.js');
2
+
3
+ (async () => {
4
+ const json = await NekosiaAPI.fetchTags();
5
+ console.log(json);
6
+ })();
@@ -1,6 +1,8 @@
1
1
  const { NekosiaVersion } = require('../index.js');
2
2
 
3
3
  (async () => {
4
- console.log(NekosiaVersion.module);
5
- console.log(await NekosiaVersion.api());
4
+ console.log(`Nekosia.js: v${NekosiaVersion.module}`);
5
+
6
+ const data = await NekosiaVersion.api();
7
+ console.log(`API: v${data.version}`);
6
8
  })();
package/index.js CHANGED
@@ -25,9 +25,9 @@ class NekosiaAPI {
25
25
  }
26
26
  }
27
27
 
28
- async fetchImages(category, options = {}) {
28
+ async fetchCategoryImages(category, options = {}) {
29
29
  if (!category) {
30
- throw new Error('The image category is required. For example, use fetchImages(\'catgirl\').');
30
+ throw new Error('The image category is required. For example, use fetchCategoryImages(\'catgirl\').');
31
31
  }
32
32
 
33
33
  if (options.session && !['id', 'ip'].includes(options.session)) {
@@ -38,24 +38,29 @@ class NekosiaAPI {
38
38
  throw new Error('`id` is not required if the session is `null` or `undefined`');
39
39
  }
40
40
 
41
- const queryString = this.buildQueryParams({
42
- session: null,
43
- id: null,
44
- count: 1,
45
- additionalTags: [],
46
- blacklistedTags: [],
47
- ...options
48
- });
49
-
50
- return this.makeHttpRequest(`${API_URL}/images/${category}?${queryString}`);
41
+ return this.makeHttpRequest(`${API_URL}/images/${category}?${this.buildQueryParams(options)}`);
51
42
  }
52
43
 
53
- async fetchShadowImages(options = {}) {
54
- if (!Array.isArray(options.additionalTags) || options.additionalTags.length === 0) {
55
- throw new Error('`additionalTags` must be a non-empty array for the shadow category');
44
+ async fetchImages(options = {}) {
45
+ if (!Array.isArray(options.tags) || options.tags.length === 0) {
46
+ throw new Error('`tags` must be a non-empty array');
47
+ }
48
+
49
+ if (Array.isArray(options.blacklistedTags)) {
50
+ throw new Error('Unexpected `blacklistedTags` in `fetchImages()`, use `blacklist` instead');
56
51
  }
57
52
 
58
- return this.fetchImages('shadow', options);
53
+ return this.fetchCategoryImages('nothing', {
54
+ session: options.session,
55
+ id: options.id,
56
+ count: options.count,
57
+ additionalTags: options.tags,
58
+ blacklistedTags: options.blacklist,
59
+ });
60
+ }
61
+
62
+ async fetchTags() {
63
+ return this.makeHttpRequest(`${API_URL}/tags`);
59
64
  }
60
65
 
61
66
  async fetchById(id) {
@@ -67,12 +72,10 @@ class NekosiaAPI {
67
72
 
68
73
  const NekosiaVersion = {
69
74
  module: https.version,
70
- api: async () => {
71
- return await https.get(BASE_URL);
72
- }
75
+ api: async () => https.get(BASE_URL),
73
76
  };
74
77
 
75
78
  module.exports = {
76
79
  NekosiaAPI: new NekosiaAPI(),
77
- NekosiaVersion
80
+ NekosiaVersion,
78
81
  };
package/package.json CHANGED
@@ -1,60 +1,64 @@
1
- {
2
- "name": "nekosia.js",
3
- "version": "0.1.4",
4
- "description": "A simple wrapper for the Nekosia API that provides easy access to random anime images. Enhance your projects with the magic of anime and a touch of feline charm meow~~! Discover why switching to Nekosia is the purrfect choice!",
5
- "keywords": [
6
- "anime api",
7
- "anime art",
8
- "anime characters",
9
- "anime gifs",
10
- "anime images",
11
- "anime library",
12
- "anime wallpaper",
13
- "anime",
14
- "anime-api",
15
- "api wrapper",
16
- "cat ears",
17
- "cat",
18
- "catgirl",
19
- "catgirls",
20
- "cute-animals",
21
- "feline",
22
- "image api",
23
- "japan",
24
- "javascript",
25
- "js library",
26
- "kawaii",
27
- "manga",
28
- "moe",
29
- "neko girls",
30
- "neko",
31
- "nekos",
32
- "nekosia api",
33
- "nekosia",
34
- "otaku",
35
- "random-anime",
36
- "typescript",
37
- "waifu"
38
- ],
39
- "homepage": "https://nekosia.cat",
40
- "bugs": {
41
- "url": "https://github.com/Nekosia-API/nekosia.js/issues"
42
- },
43
- "repository": {
44
- "type": "git",
45
- "url": "git+https://github.com/Nekosia-API/nekosia.js.git"
46
- },
47
- "license": "ISC",
48
- "author": "Sefinek <contact@sefinek.net> (https://sefinek.net)",
49
- "main": "index.js",
50
- "typings": "types/index.d.ts",
51
- "scripts": {
52
- "test": "jest",
53
- "up": "ncu -u && npm install && npm update && npm audit fix"
54
- },
55
- "devDependencies": {
56
- "@eslint/js": "^9.10.0",
57
- "globals": "^15.9.0",
58
- "jest": "^29.7.0"
59
- }
60
- }
1
+ {
2
+ "name": "nekosia.js",
3
+ "version": "0.2.0",
4
+ "description": "A simple wrapper for the Nekosia API that offers seamless access to random anime images. Add a touch of anime magic and feline charm to your projects, meow~~! Find out why Nekosia is the purrfect choice!",
5
+ "keywords": [
6
+ "anime api",
7
+ "anime art",
8
+ "anime catgirls",
9
+ "anime characters",
10
+ "anime gifs",
11
+ "anime images",
12
+ "anime library",
13
+ "anime nekos",
14
+ "anime wallpaper",
15
+ "anime",
16
+ "anime-api",
17
+ "api wrapper",
18
+ "api-wrapper",
19
+ "cat ears",
20
+ "cat",
21
+ "catgirl",
22
+ "catgirls",
23
+ "cute animals",
24
+ "cute nekos",
25
+ "feline",
26
+ "girl",
27
+ "girls",
28
+ "image api",
29
+ "javascript",
30
+ "js library",
31
+ "kawaii",
32
+ "manga",
33
+ "moe",
34
+ "neko girls",
35
+ "neko",
36
+ "nekos",
37
+ "nekosia api",
38
+ "nekosia",
39
+ "otaku",
40
+ "random anime",
41
+ "waifu"
42
+ ],
43
+ "homepage": "https://nekosia.cat",
44
+ "bugs": {
45
+ "url": "https://github.com/Nekosia-API/nekosia.js/issues"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/Nekosia-API/nekosia.js.git"
50
+ },
51
+ "license": "MIT",
52
+ "author": "Sefinek <contact@sefinek.net> (https://sefinek.net)",
53
+ "main": "index.js",
54
+ "types": "types/index.d.ts",
55
+ "scripts": {
56
+ "test": "jest",
57
+ "up": "ncu -u && npm install && npm update && npm audit fix"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "^9.17.0",
61
+ "globals": "^15.13.0",
62
+ "jest": "^29.7.0"
63
+ }
64
+ }
package/services/https.js CHANGED
@@ -7,39 +7,43 @@ const headers = {
7
7
  'Content-Type': 'application/json',
8
8
  'Cache-Control': 'no-cache',
9
9
  'Connection': 'keep-alive',
10
- 'DNT': '1'
10
+ 'DNT': '1',
11
11
  };
12
12
 
13
- const makeRequest = url => new Promise((resolve, reject) => {
14
- const req = https.get(url, { headers, timeout: 9000 }, res => {
15
- let data = '';
13
+ const timeout = 25000;
16
14
 
17
- res.on('data', chunk => {
18
- data += chunk;
19
- });
15
+ const get = async url => {
16
+ if (!url || typeof url !== 'string') throw new Error('Missing URL, expected a string.');
20
17
 
21
- res.on('end', () => {
22
- if ((res.statusCode < 200 || res.statusCode >= 300) && res.statusCode !== 400) {
23
- return reject(new Error(`HTTP Status Code: ${res.statusCode}`));
18
+ return new Promise((resolve, reject) => {
19
+ const req = https.get(url, { headers, timeout }, res => {
20
+ const { statusCode } = res;
21
+ if ((statusCode < 200 || statusCode >= 300) && statusCode !== 400) {
22
+ req.destroy();
23
+ return reject(new Error(`Unexpected HTTP Status Code: ${statusCode || 'unknown'}`));
24
24
  }
25
25
 
26
- try {
27
- const parsedData = JSON.parse(data);
28
- resolve(parsedData);
29
- } catch (err) {
30
- reject(new Error(`Failed to parse JSON: ${err.message}. Response: ${data}`));
31
- }
26
+ let data = '';
27
+ res.on('data', chunk => data += chunk);
28
+ res.on('end', () => {
29
+ try {
30
+ resolve(JSON.parse(data));
31
+ } catch (err) {
32
+ reject(err);
33
+ }
34
+ });
32
35
  });
33
- });
34
36
 
35
- req.on('error', err => reject(new Error(`Request error: ${err.message}`)));
37
+ req.on('error', err => {
38
+ req.destroy();
39
+ reject(err);
40
+ });
36
41
 
37
- req.on('timeout', () => {
38
- req.destroy();
39
- reject(new Error('Timeout error'));
42
+ req.on('timeout', () => {
43
+ req.destroy();
44
+ reject(new Error(`Request timed out after ${timeout} ms.`));
45
+ });
40
46
  });
47
+ };
41
48
 
42
- req.end();
43
- });
44
-
45
- module.exports = { get: makeRequest, version };
49
+ module.exports = { get, version };
package/test/api.test.js CHANGED
@@ -2,9 +2,9 @@ const { NekosiaAPI } = require('../index.js');
2
2
 
3
3
  describe('NekosiaAPI (API Tests)', () => {
4
4
 
5
- describe('fetchImages', () => {
5
+ describe('fetchCategoryImages', () => {
6
6
  it('should fetch images for the given category', async () => {
7
- const res = await NekosiaAPI.fetchImages('catgirl', { count: 1 });
7
+ const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
8
8
 
9
9
  expect(res).toBeInstanceOf(Object);
10
10
  expect(res.success).toBe(true);
@@ -43,48 +43,47 @@ describe('NekosiaAPI (API Tests)', () => {
43
43
  });
44
44
 
45
45
  it('should return an error for an invalid category', async () => {
46
- const res = await NekosiaAPI.fetchImages('invalid-category', { count: 1 });
46
+ const res = await NekosiaAPI.fetchCategoryImages('invalid-category', { count: 1 });
47
47
 
48
48
  expect(res.success).toBe(false);
49
49
  expect(res.status).toBe(400);
50
50
  });
51
51
 
52
52
  it('should return a specified number of images', async () => {
53
- const res = await NekosiaAPI.fetchImages('catgirl', { count: 3 });
53
+ const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 3 });
54
54
 
55
55
  expect(res).toBeInstanceOf(Object);
56
56
  expect(res.success).toBe(true);
57
57
  expect(res.status).toBe(200);
58
- expect(res.count).toBe(3);
59
58
  expect(res).toHaveProperty('images');
60
59
  expect(res.images).toBeInstanceOf(Array);
61
60
  expect(res.images.length).toBe(3);
62
61
  });
63
62
  });
64
63
 
65
- describe('fetchShadowImages', () => {
66
- it('should handle no images found for shadow category with additional tags', async () => {
67
- const res = await NekosiaAPI.fetchShadowImages({ count: 1, additionalTags: ['wTbf8J0TirS6a4fO5uyKcRazZOlO5h6o', 'xX9f9pwDAgsM3Li1LwsJ3tXQfGKW4WA0'] });
64
+ describe('fetchImages', () => {
65
+ it('should handle no images found for nothing category with additional tags', async () => {
66
+ const res = await NekosiaAPI.fetchImages({ count: 1, tags: ['wTbf8J0TirS6a4fO5uyKcRazZOlO5h6o', 'xX9f9pwDAgsM3Li1LwsJ3tXQfGKW4WA0'] });
68
67
 
69
68
  expect(res.success).toBe(false);
70
69
  expect(res.status).toBe(400);
71
70
  });
72
71
 
73
72
  it('should throw an error if additionalTagsArray is empty', async () => {
74
- await expect(NekosiaAPI.fetchShadowImages([])).rejects.toThrow('`additionalTags` must be a non-empty array for the shadow category');
73
+ await expect(NekosiaAPI.fetchImages([])).rejects.toThrow('`tags` must be a non-empty array');
75
74
  });
76
75
 
77
76
  it('should return an error response for invalid count parameter', async () => {
78
- const res = await NekosiaAPI.fetchImages('catgirl', { count: 'invalid' });
77
+ const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 'invalid' });
79
78
  expect(res.success).toBe(false);
80
79
  expect(res.status).toBe(400);
81
- expect(res.message).toBe('Invalid count parameter. Expected a number between 1 and 48.');
80
+ expect(res.message).toBe('Invalid count parameter. Expected a number between 1 and 48 (>48).');
82
81
  });
83
82
  });
84
83
 
85
84
  describe('fetchById', () => {
86
85
  it('should fetch an image by ID if it exists', async () => {
87
- const res = await NekosiaAPI.fetchImages('catgirl', { count: 1 });
86
+ const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
88
87
 
89
88
  if (res.success && res.id) {
90
89
  const id = res.id;
@@ -100,10 +99,10 @@ describe('NekosiaAPI (API Tests)', () => {
100
99
  });
101
100
 
102
101
  it('should return an error response for invalid ID format', async () => {
103
- const res = await NekosiaAPI.fetchById('12345');
102
+ const res = await NekosiaAPI.fetchCategoryImages('12345');
104
103
  expect(res.success).toBe(false);
105
104
  expect(res.status).toBe(400);
106
- expect(res.message).toBe('The image with the provided identifier was not found.');
105
+ expect(res.message).toBe('No images matching the specified criteria were found. See https://nekosia.cat/documentation?page=api-endpoints#tags-and-categories');
107
106
  });
108
107
  });
109
108
 
@@ -43,30 +43,30 @@ describe('NekosiaAPI', () => {
43
43
  });
44
44
  });
45
45
 
46
- describe('fetchImages', () => {
46
+ describe('fetchCategoryImages', () => {
47
47
  it('should build correct endpoint and make request for given category', async () => {
48
48
  const mockResponse = { data: { results: [] } };
49
49
  https.get.mockResolvedValue(mockResponse);
50
50
 
51
51
  const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl?count=2&additionalTags=cute';
52
- const res = await NekosiaAPI.fetchImages('catgirl', { count: 2, additionalTags: 'cute' });
52
+ const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 2, additionalTags: 'cute' });
53
53
 
54
54
  expect(res).toEqual(mockResponse);
55
55
  expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
56
56
  });
57
57
  });
58
58
 
59
- describe('fetchShadowImages', () => {
59
+ describe('fetchImages', () => {
60
60
  it('should throw an error if additionalTags is empty', async () => {
61
- await expect(NekosiaAPI.fetchShadowImages({})).rejects.toThrow('`additionalTags` must be a non-empty array for the shadow category');
61
+ await expect(NekosiaAPI.fetchImages({})).rejects.toThrow('`tags` must be a non-empty array');
62
62
  });
63
63
 
64
64
  it('should correctly call fetchImages with additionalTags', async () => {
65
65
  const mockResponse = { data: { results: [] } };
66
66
  https.get.mockResolvedValue(mockResponse);
67
67
 
68
- const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/shadow?count=1&additionalTags=dark,shadow';
69
- const res = await NekosiaAPI.fetchShadowImages({ count: 1, additionalTags: ['dark', 'shadow'] });
68
+ const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/nothing?count=1&additionalTags=dark,shadow';
69
+ const res = await NekosiaAPI.fetchImages({ count: 1, tags: ['dark', 'shadow'] });
70
70
 
71
71
  expect(res).toEqual(mockResponse);
72
72
  expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
package/types/index.d.ts CHANGED
@@ -5,43 +5,48 @@ declare module 'nekosia.js' {
5
5
  type AllTagsList = typeof TAGS[number];
6
6
 
7
7
  /**
8
- * Configuration options for the `fetchImages` function.
8
+ * Configuration options for the `fetchCategoryImages` function.
9
9
  */
10
- interface FetchImagesOptions {
10
+ interface FetchImagesCategoryOptions {
11
11
  /**
12
12
  * Session type:
13
- * - `id` - Session identified by the `id` value (requires the `id` field to be set).
13
+ * - `id` - Session identified by its `id` value (requires the `id` field to be set).
14
14
  * - `ip` - Session identified by the user's IP address.
15
+ * @type String
15
16
  * @default undefined
16
17
  */
17
18
  session?: 'id' | 'ip';
18
19
 
19
20
  /**
20
21
  * Identifier of the fetched image.
21
- * @example 66ae26a07886f165901e8a3f
22
+ * @type String
23
+ * @example "66ae26a07886f165901e8a3f"
22
24
  */
23
25
  id?: string;
24
26
 
25
27
  /**
26
- * The number of images to fetch. WARNING! The higher the number, the more data the server will need to process, which will result in a longer response time.
28
+ * The number of images to fetch. WARNING! The higher the number, the more data the server will need to process, leading to longer response times.
27
29
  *
28
30
  * - Minimum - 1
29
31
  * - Maximum - 48
32
+ * @type Number
30
33
  * @default 1
31
34
  */
32
35
  count?: number;
33
36
 
34
37
  /**
35
38
  * Additional tags to include in the image search.
36
- * This can be a single string with one tag or an array of strings with multiple tags.
39
+ * This can be a single string representing one tag or an array of strings for multiple tags.
40
+ * @type Array
37
41
  * @example ["cute", "sakura", "cherry-blossom"]
38
42
  * @default []
39
43
  */
40
44
  additionalTags?: AllTagsList | AllTagsList[];
41
45
 
42
46
  /**
43
- * Tags to exclude during the image search.
44
- * This can be a single string with one tag or an array of strings with multiple tags.
47
+ * Tags to exclude from the image search.
48
+ * This can be a single string representing one tag or an array of strings for multiple tags.
49
+ * @type Array
45
50
  * @example ["beret", "hat", "short-hair"]
46
51
  * @default []
47
52
  */
@@ -53,10 +58,76 @@ declare module 'nekosia.js' {
53
58
  *
54
59
  * Possible values:
55
60
  * - `safe`: Suitable for all audiences, contains no explicit or questionable content.
56
- * - `questionable`: Contains content that may be sensitive or inappropriate for younger audiences, but not explicit.
61
+ * - `questionable`: May contain content sensitive or inappropriate for younger audiences, but not explicit.
57
62
  * - `nsfw`: Contains explicit content, not safe for work (NSFW).
58
63
  *
59
64
  * The default value is ALWAYS `safe`.
65
+ * @type String
66
+ * @example safe
67
+ * @default safe
68
+ */
69
+ rating?: 'safe' | 'questionable' | 'nsfw';
70
+ }
71
+
72
+ /**
73
+ * Configuration options for the `fetchImages` function.
74
+ */
75
+ interface FetchImagesOptions {
76
+ /**
77
+ * Session type:
78
+ * - `id` - Session identified by its `id` value (requires the `id` field to be set).
79
+ * - `ip` - Session identified by the user's IP address.
80
+ * @type String
81
+ * @default undefined
82
+ */
83
+ session?: 'id' | 'ip';
84
+
85
+ /**
86
+ * Identifier of the fetched image.
87
+ * @type String
88
+ * @example "66ae26a07886f165901e8a3f"
89
+ */
90
+ id?: string;
91
+
92
+ /**
93
+ * The number of images to fetch. WARNING! The higher the number, the more data the server will need to process, leading to longer response times.
94
+ *
95
+ * - Minimum - 1
96
+ * - Maximum - 48
97
+ * @type Number
98
+ * @default 1
99
+ */
100
+ count?: number;
101
+
102
+ /**
103
+ * Additional tags to include in the image search.
104
+ * This can be a single string representing one tag or an array of strings for multiple tags.
105
+ * @type Array
106
+ * @example ["cute", "sakura", "cherry-blossom"]
107
+ * @default []
108
+ */
109
+ tags?: AllTagsList | AllTagsList[];
110
+
111
+ /**
112
+ * Tags to exclude from the image search.
113
+ * This can be a single string representing one tag or an array of strings for multiple tags.
114
+ * @type Array
115
+ * @example ["beret", "hat", "short-hair"]
116
+ * @default []
117
+ */
118
+ blacklist?: AllTagsList | AllTagsList[];
119
+
120
+ /**
121
+ * Defines the content rating of an image.
122
+ * The rating indicates the appropriateness of the content, specifying whether the image is suitable for all audiences or contains content that may be sensitive or inappropriate for certain viewers.
123
+ *
124
+ * Possible values:
125
+ * - `safe`: Suitable for all audiences, contains no explicit or questionable content.
126
+ * - `questionable`: May contain content sensitive or inappropriate for younger audiences, but not explicit.
127
+ * - `nsfw`: Contains explicit content, not safe for work (NSFW).
128
+ *
129
+ * The default value is ALWAYS `safe`.
130
+ * @type String
60
131
  * @example safe
61
132
  * @default safe
62
133
  */
@@ -68,14 +139,16 @@ declare module 'nekosia.js' {
68
139
  */
69
140
  interface ImageDetails {
70
141
  /**
71
- * URL leading to the image.
142
+ * URL of the image.
143
+ * @type String
72
144
  * @example https://cdn.nekosia.cat/images/maid-uniform/66bc6b7481a59a1cf2c79db5.png
73
145
  */
74
146
  url: string;
75
147
 
76
148
  /**
77
149
  * Image file extension.
78
- * @example `png` or `jpg`, etc.
150
+ * @type String
151
+ * @example `png`, `jpg`, etc.
79
152
  */
80
153
  extension: string;
81
154
  }
@@ -86,38 +159,44 @@ declare module 'nekosia.js' {
86
159
  interface ImageMetadata {
87
160
  /**
88
161
  * Image width in pixels.
162
+ * @type Number
89
163
  * @example 1447
90
164
  */
91
165
  width: number;
92
166
 
93
167
  /**
94
168
  * Image height in pixels.
169
+ * @type Number
95
170
  * @example 2046
96
171
  */
97
172
  height: number;
98
173
 
99
174
  /**
100
175
  * Image size in bytes.
176
+ * @type Number
101
177
  * @example 1001991
102
178
  */
103
179
  size: number;
104
180
 
105
181
  /**
106
182
  * Image file extension.
107
- * @example jpeg
183
+ * @type String
184
+ * @example png
108
185
  */
109
186
  extension: string;
110
187
  }
111
188
 
112
189
  interface ImageColors {
113
190
  /**
114
- * Main dominant color of the image in hexadecimal format.
191
+ * The main dominant color of the image in hexadecimal format.
192
+ * @type String
115
193
  * @example #00FF00
116
194
  */
117
195
  main: HexColor;
118
196
 
119
197
  /**
120
- * Palette of the 14 most dominant colors in the image, presented in hexadecimal format.
198
+ * A palette of the 14 most dominant colors in the image, represented in hexadecimal format.
199
+ * @type Array
121
200
  * @example ["#9D78CD", "#454FC0", "#909AEB", "#F5E3F0", "#94498B", "#BEC1EE", "#CD7D67", "#CC98D5", "#E2AE9E", "#F0B4DB", "#2B1C3E", "#4E8DCB", "#F2DABF", "#5CB6C0"]
122
201
  */
123
202
  palette: HexColor[];
@@ -126,37 +205,43 @@ declare module 'nekosia.js' {
126
205
  interface ImageAnime {
127
206
  /**
128
207
  * The title of the anime from which the image originates. `null` if not applicable.
129
- * @example Satsuriku no Tenshi
208
+ * @type String
209
+ * @example "Satsuriku no Tenshi"
130
210
  */
131
211
  title: string | null;
132
212
 
133
213
  /**
134
214
  * The name of the character depicted in the image. `null` if not applicable.
135
- * @example Rachel Gardner
215
+ * @type String
216
+ * @example "Rachel Gardner"
136
217
  */
137
218
  character: string | null;
138
219
  }
139
220
 
140
221
  interface ImageSource {
141
222
  /**
142
- * URL of the source page where the image originates. `null` if not applicable.
223
+ * The URL of the source page where the image originates. `null` if not applicable.
224
+ * @type String
143
225
  */
144
226
  url: string | null;
145
227
 
146
228
  /**
147
- * Direct link to the image. `null` if not applicable.
229
+ * The direct link to the image. `null` if not applicable.
230
+ * @type String
148
231
  */
149
232
  direct: string | null;
150
233
  }
151
234
 
152
235
  interface ArtistDetails {
153
236
  /**
154
- * Artist's username. `null` if not applicable.
237
+ * The artist's username. `null` if not applicable.
238
+ * @type String
155
239
  */
156
240
  username: string | null;
157
241
 
158
242
  /**
159
- * Link to the artist's profile. `null` if not applicable.
243
+ * The link to the artist's profile. `null` if not applicable.
244
+ * @type String
160
245
  */
161
246
  profile: string | null;
162
247
  }
@@ -164,11 +249,13 @@ declare module 'nekosia.js' {
164
249
  interface ImageAttribution {
165
250
  /**
166
251
  * Information about the artist.
252
+ * @type Object
167
253
  */
168
254
  artist: ArtistDetails;
169
255
 
170
256
  /**
171
- * Copyright of the artwork. `null` if not applicable.
257
+ * The copyright of the artwork. `null` if not applicable.
258
+ * @type String
172
259
  */
173
260
  copyright: string | null;
174
261
  }
@@ -179,99 +266,125 @@ declare module 'nekosia.js' {
179
266
  interface ImageResponse {
180
267
  /**
181
268
  * Indicates whether the operation was successful.
269
+ * @type Boolean
182
270
  * @example true
183
271
  */
184
272
  success: boolean;
185
273
 
186
274
  /**
187
275
  * HTTP status code of the response.
276
+ * @type Number
188
277
  * @example 200
189
278
  */
190
279
  status: number;
191
280
 
192
281
  /**
193
282
  * Session key, if applicable, otherwise `null`.
283
+ * @type String
194
284
  */
195
285
  key: string | null;
196
286
 
197
287
  /**
198
288
  * Number of images included in the response.
289
+ * @type Number
199
290
  */
200
291
  count: number;
201
292
 
202
293
  /**
203
- * Image identifier.
294
+ * Unique identifier for the image.
295
+ * @type String
204
296
  */
205
297
  id: string;
206
298
 
207
299
  /**
208
- * Structure containing the dominant colors of the fetched image.
300
+ * Object containing the dominant colors of the fetched image.
301
+ * @type Object
209
302
  */
210
303
  colors: ImageColors;
211
304
 
212
305
  /**
213
- * Structure containing details about the original and compressed images.
306
+ * Object containing details about both the original and compressed images.
214
307
  */
215
308
  image: {
216
309
  /**
217
- * Original uncompressed image. The file includes EXIF data to acknowledge the artist's work.
310
+ * The original uncompressed image. Includes EXIF data to credit the artist.
311
+ * @type Object
218
312
  */
219
313
  original: ImageDetails;
220
314
 
221
315
  /**
222
- * Compressed image with a smaller size, without quality loss. The file includes EXIF data to acknowledge the artist's work.
316
+ * The compressed version of the image, reduced in size without quality loss. Includes EXIF data to credit the artist.
317
+ * @type Object
223
318
  */
224
319
  compressed: ImageDetails;
225
320
  };
226
321
 
227
322
  /**
228
- * Metadata about the original and compressed images.
323
+ * Metadata for both the original and compressed images.
324
+ * @type Object
229
325
  */
230
- metadata: { original: ImageMetadata; compressed: ImageMetadata; };
326
+ metadata: { original: ImageMetadata; compressed: ImageMetadata };
231
327
 
232
328
  /**
233
- * Category to which the image belongs.
234
- * @example catgirl
329
+ * The category the image belongs to.
330
+ * @type String
331
+ * @example "catgirl"
235
332
  */
236
333
  category: string;
237
334
 
238
335
  /**
239
- * Tags assigned to the image.
336
+ * Tags associated with the image.
337
+ * @type Array
240
338
  */
241
339
  tags: string[];
242
340
 
243
341
  /**
244
342
  * Content rating of the image.
245
343
  *
246
- * `safe` - Image safe to display in any situation.
344
+ * `safe` - Image safe for all audiences.
247
345
  *
248
- * `questionable` - Image may contain content inappropriate for some viewers.
346
+ * `questionable` - Image may contain content unsuitable for some viewers.
249
347
  *
250
- * `nsfw` - Image contains content intended for adults only (Not Safe For Work).
348
+ * `nsfw` - Image contains adult content (Not Safe For Work).
251
349
  *
350
+ * @type String
252
351
  * @output 'safe' | 'questionable' | 'nsfw'
253
352
  */
254
353
  rating: 'safe' | 'questionable' | 'nsfw';
255
354
 
256
355
  /**
257
- * Information about the anime (not necessarily an anime) to which the image may belong.
356
+ * Information about the anime (or related media) the image may be associated with.
357
+ * @type Object
258
358
  */
259
359
  anime: ImageAnime;
260
360
 
261
361
  /**
262
- * Information about the source of the image.
362
+ * Details about the source of the image.
363
+ * @type Object
263
364
  */
264
365
  source: ImageSource;
265
366
 
266
367
  /**
267
- * Structure containing information about the artist and associated copyright of the image.
368
+ * Information about the artist and the associated copyright of the image.
369
+ * @type Object
268
370
  */
269
371
  attribution: ImageAttribution;
270
372
  }
271
373
 
374
+ /**
375
+ * GET https://api.nekosia.cat/api/v1/tags
376
+ */
377
+ interface TagsResponse {
378
+ status: number,
379
+ success: boolean,
380
+ tags: string[],
381
+ anime: string[],
382
+ characters: string[]
383
+ }
384
+
272
385
  /**
273
386
  * Nekosia API class, containing methods for fetching images.
274
- * All methods are asynchronous and return a Promise with an `ImageResponse`.
387
+ * All methods are asynchronous and return a Promise resolving to an `ImageResponse`.
275
388
  */
276
389
  export class NekosiaAPI {
277
390
  /**
@@ -280,73 +393,88 @@ declare module 'nekosia.js' {
280
393
  * @param options - Configuration options for the request (optional).
281
394
  * @example
282
395
  * const { NekosiaAPI } = require('nekosia.js');
283
- * await NekosiaAPI.fetchImages('catgirl', {
396
+ * await NekosiaAPI.fetchCategoryImages('catgirl', {
284
397
  * count: 1,
285
398
  * additionalTags: ['cute', 'sakura', 'cherry-blossom'],
286
399
  * blacklistedTags: ['beret']
287
400
  * });
288
- * @returns Promise with an `ImageResponse`.
401
+ * @type Object
402
+ * @returns A Promise resolving to an `ImageResponse`.
289
403
  */
290
- fetchImages(category: AllTagsList, options?: FetchImagesOptions): Promise<ImageResponse>;
404
+ static fetchCategoryImages(category: AllTagsList, options?: FetchImagesCategoryOptions): Promise<ImageResponse>;
291
405
 
292
406
  /**
293
407
  * Fetches images based solely on the tags provided by the user. The main category does not affect the image selection as it is not provided here.
294
408
  * @param options - Configuration options for the request (optional).
295
409
  * @example
296
410
  * const { NekosiaAPI } = require('nekosia.js');
297
- * await NekosiaAPI.fetchShadowImages({
411
+ * await NekosiaAPI.fetchImages({
298
412
  * count: 1,
299
- * additionalTags: ['catgirl', 'foxgirl'],
300
- * blacklistedTags: ['dog-girl']
413
+ * tags: ['catgirl', 'foxgirl'],
414
+ * blacklist: ['dog-girl']
301
415
  * });
302
- * @returns Promise with an `ImageResponse`.
416
+ * @type Object
417
+ * @returns A Promise resolving to an `ImageResponse`.
418
+ */
419
+ static fetchImages(options?: FetchImagesOptions): Promise<ImageResponse>;
420
+
421
+ /**
422
+ * Fetches the latest array with tags, anime titles, and characters
423
+ * @returns A Promise resolving to an `ImageResponse`.
303
424
  */
304
- fetchShadowImages(options?: FetchImagesOptions): Promise<ImageResponse>;
425
+ static fetchTags(id: string): Promise<TagsResponse>;
305
426
 
306
427
  /**
307
428
  * Fetches an image by its identifier.
308
429
  * @param id - The image identifier (e.g., `66ae26a07886f165901e8a3f`).
309
- * @returns Promise with an `ImageResponse`.
430
+ * @type Object
431
+ * @returns A Promise resolving to an `ImageResponse`.
310
432
  */
311
- fetchById(id: string): Promise<ImageResponse>;
433
+ static fetchById(id: string): Promise<ImageResponse>;
312
434
  }
313
435
 
314
436
  /**
315
- * JSON object response from the API regarding the current version of the API and related information.
437
+ * JSON object response from the API containing information about the current version and related details.
316
438
  */
317
439
  interface APIVersion {
318
440
  /**
319
441
  * HTTP status code of the response.
442
+ * @type Number
320
443
  * @example 200
321
444
  */
322
445
  status: number;
323
446
 
324
447
  /**
325
448
  * Indicates whether the request was successful.
449
+ * @type Boolean
326
450
  * @example true
327
451
  */
328
452
  success: boolean;
329
453
 
330
454
  /**
331
455
  * The current version of the API.
332
- * @example 1.0.0
456
+ * @type String
457
+ * @example "1.0.0"
333
458
  */
334
459
  version: string;
335
460
 
336
461
  /**
337
462
  * URL to the API documentation.
338
- * @example https://nekosia.cat/documentation
463
+ * @type String
464
+ * @example "https://nekosia.cat/documentation"
339
465
  */
340
466
  documentation: string;
341
467
 
342
468
  /**
343
- * Contact email.
344
- * @example contact@nekosia.cat
469
+ * Contact email for inquiries.
470
+ * @type String
471
+ * @example "contact@nekosia.cat"
345
472
  */
346
473
  contact: string;
347
474
 
348
475
  /**
349
- * List of available API numbers.
476
+ * List of available API versions.
477
+ * @type Array
350
478
  * @example [1]
351
479
  */
352
480
  apis: number[];
@@ -357,15 +485,17 @@ declare module 'nekosia.js' {
357
485
  */
358
486
  export const NekosiaVersion: {
359
487
  /**
360
- * Get the current version of the module.
361
- * @example 1.1.0
362
- * @returns String with the module version.
488
+ * Retrieves the current version of the module.
489
+ * @example "1.1.0"
490
+ * @type String
491
+ * @returns A string representing the module version.
363
492
  */
364
493
  module: string;
365
494
 
366
495
  /**
367
- * Get the current API version and related information.
368
- * @returns Promise that resolves to an `APIVersion` object.
496
+ * Fetches the current API version and related information.
497
+ * @type Object
498
+ * @returns A Promise that resolves to an `APIVersion` object.
369
499
  */
370
500
  api(): Promise<APIVersion>;
371
501
  };
package/types/tags.ts CHANGED
@@ -1,3 +1,3 @@
1
- export const TAGS = [
2
- 'absolute-territory', 'after-the-rain', 'afternoon-tea', 'ahoge', 'air-comiket', 'ajitani-hifumi', 'akazukin', 'aksktrpg', 'akura', 'alice-in-wonderland', 'alice-margatroid', 'alice-tendou', 'alllisso', 'alluring-face', 'alone', 'amamine', 'amamineko-cafe', 'amashiro-natsuki', 'ame-nochi-yuki', 'ameto-yuki', 'angel', 'angry', 'angry-face', 'apex', 'apple', 'apple-pie', 'apron-dress', 'aqua', 'aquarium', 'areola-slip', 'aria-tsukushi', 'arknights', 'arknights-battle-illustration-contest', 'armed-girls', 'armpits', 'ashen-hair', 'ass', 'assault-rifle', 'autumn', 'autumn-leaves', 'axillary-costume', 'azki', 'azkiart', 'azur-lane', 'azur-lane-fleet', 'baby-face', 'babydoll', 'background', 'balloon', 'balloons', 'bandages', 'bandaid', 'bangtail', 'bare-feet', 'bare-soles', 'barefoot', 'barefoot-school-uniform', 'basketball', 'basketball-uniform', 'bath-time', 'bath-towel', 'beach', 'beach-ball', 'beast-girl', 'beautiful', 'beautiful-breasts', 'beautiful-reimu', 'bed', 'bed-hair', 'bedroom', 'belly', 'belly-glimpse', 'bellybutton', 'bench', 'beret', 'bewitching-thighs', 'big-breasts', 'bikini', 'bikini-top', 'birthday', 'black-and-white', 'black-bikini', 'black-dress', 'black-hair', 'black-hair-with-red-eyes', 'black-knee-high-socks', 'black-ribbon', 'black-sailor-uniform', 'black-shoes', 'black-stockings', 'black-thigh-high-socks', 'black-thigh-highs', 'black-tights', 'black-twintails', 'blazer', 'blonde', 'bloomers', 'blue', 'blue-archive', 'blue-eues', 'blue-eyes', 'blue-hair', 'blue-ribbon', 'blue-ribbono', 'blue-shoes', 'blue-skirt', 'blue-sky', 'bluearchive', 'blushing', 'bocchi-chan', 'botamochi', 'bottomless', 'bouquet', 'boy-cut', 'bra', 'braid', 'breast-hold', 'breasts', 'bride', 'brown-hair', 'bubble-tea', 'bubblegum', 'bue-eyes', 'bunny-ears', 'bunny-girl', 'butterfly', 'by-the-window', 'cable-knitting', 'cake', 'cameltoe', 'camisole', 'camisole-dress', 'canal', 'candy', 'candy-apple', 'car', 'cardigan', 'cardigan-uniform', 'casual-wear', 'cat', 'cat-and-girl', 'cat-ears', 'cat-ears-hat', 'cat-ears-headphones', 'cat-ears-hoodie', 'cat-ears-maid', 'cat-lingerie', 'cat-mouth', 'cat-pose', 'cat-tail', 'catgirl', 'celia-claire', 'celica', 'cheeks', 'cheerleader', 'chericot-rozel', 'cherry', 'cherry-blossom', 'cherry-petals', 'chest-outline', 'chibi', 'chihuahua', 'chin-resting', 'china-dress', 'chinese-lolita', 'chinese-style', 'chino', 'chino-kafuu', 'chitosezaka-suzu', 'chiyu', 'chocolate', 'chocolate-mint', 'choker', 'christmas', 'chuuni', 'classroom', 'cloak', 'closed-eyes', 'clouds', 'coffee', 'collar', 'collarbone', 'comic-treasure', 'confused', 'cookie', 'corset', 'cosmos', 'costume-change', 'crossed-legs', 'crying', 'cuite', 'cutaway-shoulder', 'cute', 'cute-cat', 'cuteness-is-justice', 'cyber', 'dakimakura-cover', 'dango', 'detexted', 'dnf', 'dog-and-girl', 'dog-ears', 'dog-girl', 'doggirl', 'donut', 'doujin', 'drawers', 'drawing-a-sword', 'dress', 'dress-shirt', 'dungeon-fighter-online', 'dvdart', 'ear-cleaning', 'elementary-school-student', 'elevator', 'enticing-brassiere', 'epic-seven', 'epic-seven-fan-art-illustration-contest', 'exposed-back', 'eye-mask', 'eyepatch', 'fairy-eye', 'fairy-tale', 'fallenshadow', 'fan-work', 'fantasy', 'fantasy-girl', 'feather-ears', 'feet', 'felicia-lulufleur', 'festival-of-white', 'fishnets', 'flare-skirt', 'flared-bikini', 'flat-chest', 'flower', 'flowers-and-girls', 'footwear', 'forest', 'fox-ears', 'fox-mask', 'fox-shrine-maiden', 'foxgirl', 'frills', 'fubuki-shiragami', 'fubuki-shiragami-fanart', 'futaba-sharo', 'fuwamoco', 'fuwawa', 'fuwawa-abyssgard', 'fuyoyo', 'fuzzy', 'fwmcpix', 'game', 'game-pad', 'gamer', 'gamer-girl', 'ganbare-ganbare', 'garter', 'garter-ring', 'garter-stockings', 'garterbelt', 'gawr-gura', 'gawrgura', 'gawrt', 'genshin-impact', 'gensokyo-in-spring', 'getting-dressed', 'gijinka', 'girl', 'girls', 'girls-frontline', 'glasses', 'gloves', 'gothic-lolita', 'greek-foot', 'green-eyes', 'green-hair', 'green-ribbon', 'guildcq', 'guitar', 'gun', 'gym-uniform', 'hairdressing', 'hairpin', 'hairstyle-change', 'hakui-koyori', 'half-pants', 'half-pigtails', 'half-up-hairstyle', 'halloween', 'halo', 'hamico', 'hammann', 'han-costume', 'hanami', 'hand-held-pigtails', 'hand-on-crotch', 'handcuffs', 'hands-forming-a-heart', 'harness', 'haruhara-shun', 'hayate-hisakawa', 'hazakura-chikori', 'headband', 'headboard-angle', 'headdress', 'headphone', 'headphones', 'headset', 'heart', 'heart-eyes', 'heartbreak', 'hearts', 'hedgehog', 'heels', 'heterochromia', 'hibiki', 'hibiscus', 'high-angle', 'high-leg-panties', 'high-school-girl', 'high-waisted-skirt', 'hiiro', 'hikaru', 'himura-moritaka', 'hirakata-kana', 'hizuki-miu', 'hizuki-rurufu', 'holding-hands-with-fingers-interlocked', 'holding-ice-in-mouth', 'holoadvent', 'hololive', 'hololive-en', 'hololive-english', 'hololiveen', 'holox', 'hong', 'hood', 'hoodie', 'hoshi', 'hoshino', 'hoshizora-no-memoria', 'hot-pants', 'hot-spring', 'houzuki-michiru', 'hu-tao', 'hutao', 'hyerang', 'ice-cream', 'ichigori-ena', 'idol', 'illumination', 'in-the-train', 'incredibly-cute', 'indie-virtual-youtuber', 'infamous-left-foot-defense', 'inflatable-pool', 'inner-color', 'inugami-korone', 'iochi-mari', 'itigori-ena', 'itou-yuna', 'izayoi-nonomi', 'jagged-sclera', 'japanese-clothes', 'japanese-maid', 'japanese-style', 'japanese-style-maid', 'japanese-umbrella', 'jersey', 'jk', 'joint-work', 'jumper-skirt', 'just-woke-up', 'kabashima-hana', 'kamiko-kana', 'kamioka-chiroru', 'kamisato-ayaka', 'kamiyama-shiki', 'kancolle', 'kantai-collection', 'kanzaki-ririka', 'karyl', 'katana', 'katcolle', 'kazari-rua', 'kigurumi', 'kimono', 'kimono-dress', 'kindergarten-pupil', 'kingdom', 'kirakira-monstars', 'kiryuu-kikyou', 'kitchen', 'knee-high-socks', 'kneeling', 'knockout-knockers', 'koahri', 'kohaku-nene', 'koharu', 'koiko-irori', 'koito-amuno', 'kokoro-amamiya', 'korie-riko', 'korone', 'koyori-hakui', 'koyori-sketch', 'kuda-izuna', 'kuro-namako', 'kuromi-serika', 'kuroneko', 'kurose-kiri', 'kyaru', 'lancat', 'lanmewko', 'lap-pillow', 'laplus-darkness', 'large-breasts', 'lattice-tower', 'leaning-forward', 'left-foot-shield', 'legato', 'leggings', 'lemon', 'leo', 'lifted-clothing', 'lily-of-the-valley', 'lime', 'lingerie', 'little-devil', 'lolicon-bait', 'lolipop-complete', 'lolita', 'lolita-fashion', 'lollipop', 'long-black-hair', 'long-blond-hair', 'long-gloves', 'long-hair', 'long-pink-hair', 'long-red-hair', 'long-white-gloves', 'long-white-hair', 'loungewear', 'lying-down', 'lying-on-one-side', 'macaron', 'machikaze-fuuna', 'mad', 'magical-girl', 'mahiro-oyama', 'maid', 'maid-bikini', 'maid-day', 'maid-uniform', 'makeup', 'mari-iochi', 'marie', 'marine-day', 'marine-look', 'maruro', 'mascot', 'matsumiya-kiseri', 'mayoi-shigure', 'mea-kagura', 'medium-hair', 'metaljelly', 'mf-bunko-j', 'middle-school-student', 'midriff', 'mihoshi-mei', 'miike-chan', 'mika', 'mika-misono', 'mikeneko', 'mikeneko-fanart', 'miko', 'minami-kotone', 'mini-hakama', 'miniskirt', 'miniskirt-miko', 'mirror', 'miu-channel', 'miu-hizuki', 'mizuki', 'mizukiart', 'mococo', 'mococo-abyssgard', 'mofumies', 'mole-under-the-eye', 'moon', 'msi', 'murasaki-shion', 'myoya', 'nachoneko', 'nagi-hisakawa', 'nail-polish', 'naked-navel', 'nap', 'natori-sana', 'navel-piercing', 'necktie', 'necomi', 'needs-to-be-appreciated-more', 'negligee', 'nekoha-shizuku', 'nekokobushi', 'nekomata-okayu', 'new-year', 'newsboy-cap', 'night', 'night-sky', 'nijisanji', 'nikke', 'nine-tailed', 'nkshoujo', 'no-game-no-life', 'noire', 'nolan', 'nonaka-yuu', 'not-wearing-any-panties', 'nurse', 'off-shoulder', 'off-shoulder-dress', 'okomeillust', 'okusora-ayane', 'old-fashioned-school-swimsuit', 'older-girl', 'omochi-box', 'omochi-monaka', 'one-eye-covered', 'one-piece', 'one-piece-swimsuit', 'ookami-mio', 'open-shirt', 'orange-ribbon', 'otokonoko', 'overalls', 'overly-long-sleeves', 'pajama', 'pajamas', 'panchira', 'panties', 'pantsu', 'panty-peek', 'pantyhose', 'parasol', 'parfait', 'patting', 'paw-pads', 'peace-sign', 'pee-holding', 'pekora-usada-fanart', 'personification-of-drinks', 'photo-editing', 'photoshop', 'piink', 'pillow', 'pinching-garments', 'pink', 'pink-eyes', 'pink-hair', 'pink-ribbon', 'pink-shoes', 'pink-skirt', 'pink-sweater', 'pink-twintails', 'plaid-pattern', 'plaid-skirt', 'plastic-bottle', 'platform', 'playing-cards', 'plump-thighs', 'plushie', 'pocky-day', 'pointy-ears', 'ponytail', 'pool', 'pool-at-night', 'porch', 'present', 'princess-connect', 'prone-position', 'psycho', 'purple-ears', 'purple-eyes', 'purple-hair', 'purple-ribbon', 'queen-of-hearts', 'rabbit-girl', 'ragna-doll', 'railroad-crossing', 'railway', 'rain', 'rainy-season', 'ramune', 'randoseru', 'rawr', 're-oekaki', 'red-and-blue', 'red-eyes', 'red-hair', 'red-pigtails', 'red-ribbon', 'red-shoes', 'red-skirt', 'reflected-glare', 'reimu-hakurei', 'remilia-scarlet', 'remiliacn', 'rena-yorumi', 'reverse-sitting', 'rhodes', 'ribbed-fabric', 'ribbon', 'ribbonos', 'ribbons', 'ringo-chan', 'roar', 'rocket-launcher', 'roxanne', 'rribbon', 'rubbib', 'rucaco', 'rukako', 'ruki-roki', 'rumi', 'runa-shinomiya', 'rushia-uruha', 'sad', 'saekiya-sabou', 'saiba-midori', 'saiba-momoi', 'sailor', 'sailor-dress', 'sailor-one-piece', 'sailor-swimsuit', 'sailor-uniform', 'sakamata-chloe', 'sakura', 'sakura-miko', 'sakuraba-moeka', 'sakurai-hana', 'sand', 'sandals', 'santa', 'santa-cosplay', 'sassy-loli', 'scared', 'scarf', 'scenery', 'sch', 'school-girl', 'school-swimsuit', 'school-uniform', 'school-uniform-cardigan', 'school-uniform-hoodie', 'schoolgirl', 'sea', 'see-through', 'selfie', 'serena-hanazono', 'setokane', 'shano-hiyori', 'shanoa-asmr', 'shigure', 'shimapan', 'shiori', 'shirakami-fubuki', 'shirakawa-yumea', 'shirasu-azusa', 'shiroko-terror', 'shiromichan', 'short-boots', 'short-haircut', 'short-pants', 'short-white-hair', 'shouu-kun', 'showgirl', 'side-string-bikini', 'side-tie-panty', 'silver-hair', 'silver-long-hair', 'singer', 'sisters', 'sitting', 'sitting-on-feet', 'sitting-with-hands-around-knees', 'skirt', 'skirt-lift', 'sleep', 'sleep-wear', 'sleeping-face', 'sleepy', 'sleepy-face', 'sleeveless', 'sleeveless-dress', 'sleeveless-parka', 'small-breasts', 'small-fangs', 'smile', 'snack-nili', 'snow', 'snow-leopard', 'snowman', 'socks', 'sofa', 'sole', 'somna', 'sotis', 'spiked-bat', 'spiral-eyes', 'splashes', 'spring', 'squirrel', 'stairs', 'standing-picture', 'starlight-stage', 'starry-sky', 'starry-sky-dress', 'steamed-bun-with-meat-filling', 'stirrup-leggings', 'stockings', 'straight-fringe', 'strap-shoes', 'strapless', 'straw-hat', 'strawberries', 'strawberry', 'string-ribbon', 'striped-bikini', 'striped-knee-highs', 'striped-thigh-high-socks', 'subculture', 'sukumizu', 'summer', 'summer-dress', 'summer-kimono', 'summer-pockets', 'summer-sky', 'sunaookami-shiroko', 'sunflower', 'sunflowers', 'sunglasses', 'sunohara-kokona', 'sunset', 'supine', 'suspender-skirt', 'suzuho-hotaru', 'sweat', 'sweater', 'swim-ring', 'swimsuit', 'swimsuit-parka', 'swimwear', 'sword', 't-shirt', 'tail', 'tail-from-under-skirt', 'tail-with-ribbon', 'taiwan', 'takanashi-hoshino', 'tattoo', 'tea', 'tea-time', 'tears', 'teary-eyed', 'teary-eyes', 'teketi', 'telephone', 'tenshinoikenie', 'the-person-behind', 'the-soles-of-feet-in-socks', 'theriantrope', 'thick-eyebrows', 'thigh-high-socks', 'thigh-highs', 'thighhighs', 'thighs', 'tie-side-bikini', 'tiger', 'tight', 'tired', 'toes', 'tokoshibyra', 'tongue-out', 'touhou', 'touhou-project', 'towel', 'transparency', 'tropical-fish', 'tsugiri-noa', 'tsurara', 'twin-pig-tails', 'twin-ponytails', 'twins', 'twintails', 'two-shot', 'uise-iu', 'umbrella', 'underwater', 'uniform', 'upwards-gaze', 'uruha-rushia-fanart', 'usada-pekora', 'usagigo', 'valentine', 'vampire', 'vdonburi', 'verslll', 'virtual', 'virtual-esports-project', 'vrchat', 'vtuber', 'w-sitting', 'waitress', 'wallpaper', 'water', 'water-surface', 'watermelon', 'wearing-only-a-shirt', 'wedding-dress', 'wet', 'wet-see-through', 'what-is-this-cuteness', 'white', 'white-bikini', 'white-cat', 'white-day', 'white-dress', 'white-hair', 'white-hairpin', 'white-high-socks', 'white-knee-high-socks', 'white-ribbon', 'white-sailor-uniform', 'white-school-swimsuit', 'white-socks', 'white-stockings', 'white-swimsuit', 'white-thigh-high-socks', 'white-tiger', 'white-tights', 'wide-brim-hat', 'wind-chime', 'winer', 'wings', 'wink', 'winter', 'witch', 'wolf-ears', 'wolf-girl', 'women-in-parka', 'yandere', 'yawn', 'year-of-the-tiger', 'yellow-bikini', 'yellow-eyes', 'yellow-hair', 'yellow-ribbon', 'yoko', 'young-girl', 'youtuber', 'yozuki-mofu', 'yuika-shiina', 'yukata', 'yukihana-lamy', 'yukikaze', 'yutori-natsu'
3
- ] as const;
1
+ export const TAGS = ['absolute-territory','after-the-rain','afternoon-tea','ahoge','ajitani-hifumi','akazukin','aksktrpg','akura','alice-in-wonderland','alice-margatroid','alice-tendou','alllisso','alluring-face','alona','alone','amamine','amamineko-cafe','amashiro-natsuki','ame-nochi-yuki','ameto-yuki','angel','angry-face','animal-ears','apex','apple','apple-caramel','apple-pie','apron-dress','aqua','aquarium','areola-slip','aria-tsukushi','arknights','arknights-battle-illustration-contest','armed-girls','armpits','ashen-hair','assault-rifle','autumn','autumn-leaves','axillary-costume','azki','azkiart','azur-lane','babydoll','back-alley','background','balloon','balloons','bandages','bandaid','bangtail','bare-feet','bare-soles','barefoot','basketball','basketball-uniform','bath-time','bath-towel','beach','beach-ball','bear-ears','beargirl','beast-girl','beautiful','beautiful-reimu','bed','bed-hair','bedroom','belly','belly-glimpse','bellybutton','bench','beret','bewitching-thighs','bikini','bikini-top','birthday','black-and-white','black-bikini','black-dress','black-hair','black-hair-with-red-eyes','black-knee-high-socks','black-ribbon','black-sailor-uniform','black-shoes','black-skirt','black-stockings','black-thigh-high-socks','black-thigh-highs','black-tights','blazer','blonde','bloomers','blue-archive','blue-eues','blue-eyes','blue-hair','blue-ribbon','blue-shoes','blue-skirt','blue-sky','blushing','bocchi-chan','bondage','botamochi','bottomless','boy-cut','bra','braid','breast-hold','breasts','bride','brown-hair','bubble-tea','bunny-ears','bunny-girl','butterfly','by-the-window','cable-knitting','cake','cameltoe','camisole','camisole-dress','canal','candy','candy-apple','car','cardigan','cardigan-uniform','casual-wear','cat','cat-and-girl','cat-ears','cat-ears-hat','cat-ears-headphones','cat-ears-hoodie','cat-ears-maid','cat-mouth','cat-paws','cat-pose','cat-tail','catboy','catgirl','cats','celia-claire','celica','cheeks','cheerleader','chericot-rozel','cherry','cherry-blossom','cherry-petals','chess','chest-outline','chibi','chihuahua','chin-resting','chinese-lolita','chinese-style','chino','chino-kafuu','chitosezaka-suzu','chiyu','chocolate','chocolate-mint','choker','christmas','chuuni','classroom','cloak','closed-eyes','clouds','cocoa-hoto','coffee','collar','comic-treasure','confused','cookie','corset','cosmos','costume-change','cross-halter-bikini','crossed-legs','crying','cuite','cutaway-shoulder','cute','cute-cat','cuteness-is-justice','dakimakura-cover','dango','detexted','dog-and-girl','dog-ears','dog-girl','doll','donut','doujin','drawers','drawmei','dress','dress-shirt','dvdart','elementary-school-student','elevator','enticing-brassiere','epic-seven','exposed-back','eye-mask','eyepatch','fairy-eye','fairy-tale','fallenshadow','fantasy','fantasy-girl','feather-ears','feet','felicia-lulufleur','festival-of-white','firefly','fishnets','flare-skirt','flared-bikini','flat-chest','floral-playing-cards','flower','flowers-and-girls','forest','fox','fox-ears','fox-mask','fox-shrine-maiden','foxgirl','frills','fubuki-shiragami','fubuki-shiragami-fanart','fuwamoco','fuwawa-abyssgard','fuyoyo','fuzzy','fwmcpix','game','game-pad','gamer','gamer-girl','ganbare-ganbare','garter','garterbelt','gawr-gura','genshin-impact','gensokyo-in-spring','getting-dressed','gijinka','girl','girls','girls-frontline','glasses','gloves','gothic-lolita','greek-foot','green-eyes','green-hair','green-ribbon','guildcq','guitar','gun','gym-uniform','hairdressing','hairpin','hairstyle-change','hajime-todoroki','hakui-koyori','half-pants','half-pigtails','half-up-hairstyle','halloween','halo','hamico','hammock','han-costume','hanami','hands-forming-a-heart','harness','haruhara-shun','hayate-hisakawa','hazakura-chikori','headband','headboard-angle','headdress','headphone','headphones','headset','heart','heart-eyes','heartbreak','hearts','hedgehog','heels','herta','heterochromia','hibiki','hibiscus','high-angle','high-school-girl','high-waisted-skirt','hiiro','hikaru','himura-moritaka','hizuki-miu','hizuki-rurufu','holding-hands-with-fingers-interlocked','holding-ice-in-mouth','hololive','hololive-en','hololive-english','hololiveen','holox','hong','honkaistarrail','hood','hoodie','hoshi','hoshino','hoshitsuki-neiro','hoshizora-no-memoria','hot-spring','houzuki-michiru','hu-tao','hutao','hydrangea','ice-cream','ichigo','ichigori-ena','idol','illumination','in-the-train','incredibly-cute','indie-virtual-youtuber','indie-vtuber','indoor-shoes','infamous-left-foot-defense','inflatable-pool','inner-color','inugami-korone','itigori-ena','itou-yuna','izayoi-nonomi','jagged-sclera','japanese-clothes','japanese-maid','japanese-style','japanese-style-maid','japanese-umbrella','jersey','jk','jumper-skirt','jumpy','just-woke-up','kabashima-hana','kamiko-kana','kamioka-chiroru','kamisato-ayaka','kamiyama-shiki','kanade-otonose','kancolle','kantai-collection','kanzaki-ririka','karin','karyl','katana','katcolle','kazari-rua','kazueru','kazusa-kyoyama','kigurumi','kimono','kimono-dress','kindergarten-pupil','kingdom','kirakira-monstars','kiryuu-kikyou','kitchen','klee','knee-high-socks','kneeling','knockout-knockers','kohaku-nene','koharu','koiko-irori','koito-amuno','kokoro-amamiya','korie-riko','koyori-hakui','koyori-sketch','kuda-izuna','kuro-namako','kuromi-serika','kuroneko','kyaru','kyouyama-kazusa','lancat','lanmewko','lap-pillow','laplus-darkness','large-breasts','lattice-tower','left-foot-shield','legato','leggings','legs','lemon','leo','lily-of-the-valley','lime','lingerie','little-devil','lolipop-complete','lolita','lolita-fashion','lollipop','long-black-hair','long-blond-hair','long-gloves','long-hair','long-pink-hair','long-red-hair','long-white-gloves','long-white-hair','loungewear','lying-down','lying-on-one-side','macaron','machikaze-fuuna','mad','magical-girl','maid','maid-bikini','maid-uniform','makeup','mari-iochi','marie','marine','marine-day','marine-look','maruro','mascot','matsumiya-kiseri','mayoi-shigure','mea-kagura','medium-hair','mf-bunko-j','middle-school-student','midori-matsukaze','midriff','mihoshi-mei','miike-chan','mika','mika-misono','mikeneko','miko','miku-maekawa','minami-kotone','minato-aqua','mini-hakama','miniskirt','miniskirt-miko','mint','mirror','miu-channel','miu-hizuki','mizukiart','mococo','mococo-abyssgard','mole-under-the-eye','moon','murasaki-shion','muryo','myoya','nachoneko','nagi-hisakawa','nahida','nail-polish','nanashi-mumei','nap','natori-sana','necktie','necomi','needs-to-be-appreciated-more','negligee','nekoha-shizuku','nekomata-okayu','nene-kusanagi','new-year','newsboy-cap','night','night-sky','nijisanji','nikke','nine-tailed','nintendo-switch','nintendoswitch','no-game-no-life','noire','nolan','nonaka-yuu','nurse','off-shoulder','off-shoulder-dress','okomeillust','okusora-ayane','old-fashioned-school-swimsuit','older-girl','omochi-box','omochi-monaka','one-eye-covered','one-piece','one-piece-swimsuit','ookami-mio','open-shirt','orange-hair','orange-ribbon','otokonoko','overalls','overly-long-sleeves','pajamas','panchira','panda-ears','panties','pants','parasol','park','patting','paw-pads','peace-sign','pekora-usada-fanart','personification-of-drinks','photo-editing','pigtails','pillow','pinching-garments','pink','pink-eyes','pink-hair','pink-ribbon','pink-shoes','pink-skirt','pink-sweater','pink-twintails','plaid-pattern','plaid-skirt','plastic-bottle','platform','playing-cards','plump-thighs','plushie','pocky','pointy-ears','polar-bear','ponytail','pool','pool-at-night','porch','present','princess-connect','project-sekai','prone-position','psycho','pu-ht','purple-ears','purple-eyes','purple-hair','purple-ribbon','purple-skirt','queen-of-hearts','rabbit-girl','ragna-doll','railroad-crossing','railway','rain','rainy-season','ramune','randoseru','rawr','re-oekaki','red-and-blue','red-eyes','red-hair','red-pigtails','red-ribbon','red-ribbons','red-skirt','reflected-glare','regloss','reimu-hakurei','reisa-uzawa','remilia-scarlet','rena-yorumi','reverse-sitting','rhodes','ribbed-fabric','ribbon','ribbonos','ribbons','ringo-chan','roar','rocket-launcher','roxanne','rribbon','rubbib','rucaco','rukako','ruki-roki','rumi','runa-shinomiya','rurudo','rurudo-lion','rushia-uruha','sad','saekiya-sabou','saiba-midori','saiba-momoi','sailor','sailor-dress','sailor-one-piece','sailor-swimsuit','sailor-uniform','sakamata-chloe','sakura','sakura-miko','sakuraba-moeka','sakurada-hane','sakuradahane','sakurai-hana','sand','santa','santa-cosplay','sassy-loli','scared','scarf','scenery','school-swimsuit','school-uniform','school-uniform-cardigan','school-uniform-hoodie','schoolgirl','scornful-eyes','sea','see-through','selfie','setokane','shano-hiyori','shanoa-asmr','shigure','shiori','shirai-tanuki','shirakami-fubuki','shirakawa-yumea','shirasu-azusa','shiroko','shiroko-terror','shiromichan','shooting-star','short-boots','short-haircut','short-pants','short-white-hair','shouu-kun','showgirl','shy','side-string-bikini','side-tie-panty','silver-hair','silver-long-hair','singer','sisters','sitting','sitting-on-feet','sitting-with-hands-around-knees','skirt','skirt-lift','skirtm','sleep','sleep-wear','sleeping-face','sleepy','sleepy-face','sleeveless','sleeveless-dress','sleeveless-parka','small-breasts','small-fangs','smile','snack-nili','sneakers','snow','snow-leopard','snowman','snowy-landscape','socks','sofa','sole','somna','sorasaki-hina','spiral-eyes','splashes','spring','squirrel','stairs','standing-picture','starlight-stage','starry-sky','starry-sky-dress','steamed-bun-with-meat-filling','stockings','straight-fringe','strap-shoes','straw-hat','strawberries','strawberry','streaked-hair','string-ribbon','striped-bikini','striped-thigh-high-socks','sukumizu','summer','summer-dress','summer-kimono','summer-pockets','sunaookami-shiroko','sunflowers','sunglasses','sunohara-kokona','sunset','supine','suspender-skirt','suzuho-hotaru','sweat','sweater','sweets','swim-ring','swimsuit','swimsuit-parka','swimwear','swing','sword','t-shirt','tail','tail-from-under-skirt','tail-holding','tail-with-ribbon','taiwan','takanashi','takanashi-hoshino','tattoo','tea','tea-time','tears','teary-eyed','teary-eyes','telephone','tenshinoikenie','test','the-person-behind','the-soles-of-feet-in-socks','theriantrope','thick-eyebrows','thigh-high-socks','thigh-highs','thighhighs','thighs','tie-side-bikini','tiered-dress','tiger','tights','tired','tobu-railway','toes','tokoshibyra','tongue-out','touhou','touhou-project','towel','transparency','trick-or-treat','tropical-fish','tsugiri-noa','twins','twintails','uise-iu','umbrella','underwater','uniform','upwards-gaze','uruha-rushia-fanart','usada-pekora','usagigo','valentine','vampire','vdonburi','vrchat','vtuber','w-sitting','wa-lolita','waitress','wallpaper','water','water-surface','watermelon','weapon','wearing-only-a-shirt','wedding-dress','wet','wet-see-through','white-bikini','white-cat','white-day','white-dress','white-hair','white-hairpin','white-hait','white-high-socks','white-knee-high-socks','white-ribbon','white-sailor-uniform','white-school-swimsuit','white-skirt','white-socks','white-stockings','white-swimsuit','white-thigh-high-socks','white-tiger','white-tights','white-twintails','wings','wink','winter','witch','wolf-ears','wolf-girl','yandere','yaoyao','yawn','yellow-eyes','yellow-hair','yellow-ribbon','yoko','young-boy','young-girl','yuika-shiina','yukata','yukihana-lamy','yukinoshita-peo','yutori-natsu','yuuki-sakuna'] as const;
2
+
3
+ // https://api.nekosia.cat/api/v1/tags
@@ -1,6 +0,0 @@
1
- const { NekosiaAPI } = require('../index.js');
2
-
3
- (async () => {
4
- const response = await NekosiaAPI.fetchShadowImages({ session: 'ip', count: 1, additionalTags: ['cute', 'blue-hair'] });
5
- console.log(response);
6
- })();