anipub 1.0.4
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 +21 -0
- package/README.md +686 -0
- package/package.json +58 -0
- package/src/index.cjs +385 -0
- package/src/index.d.ts +154 -0
- package/src/index.js +368 -0
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "anipub",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "A full-featured JavaScript/TypeScript client for the AniPub Anime API — search, browse by genre, get streaming links, MAL data, characters & voice actors.",
|
|
5
|
+
"main": "src/index.cjs",
|
|
6
|
+
"module": "src/index.js",
|
|
7
|
+
"types": "src/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./src/index.js",
|
|
12
|
+
"require": "./src/index.cjs",
|
|
13
|
+
"types": "./src/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src/",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "node scripts/build-cjs.js",
|
|
23
|
+
"test": "node test/index.test.js",
|
|
24
|
+
"prepublishOnly": "node scripts/build-cjs.js",
|
|
25
|
+
"example": "node examples/basic.js",
|
|
26
|
+
"example:advanced": "node examples/advanced.js"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"anime",
|
|
30
|
+
"anipub",
|
|
31
|
+
"manga",
|
|
32
|
+
"api",
|
|
33
|
+
"myanimelist",
|
|
34
|
+
"mal",
|
|
35
|
+
"jikan",
|
|
36
|
+
"streaming",
|
|
37
|
+
"search",
|
|
38
|
+
"genre",
|
|
39
|
+
"characters",
|
|
40
|
+
"voice-actors",
|
|
41
|
+
"anime-api",
|
|
42
|
+
"japanese-animation"
|
|
43
|
+
],
|
|
44
|
+
"author": "abdullahaladnan95@gmail.com",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/AnimePub/AniPub-API"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/AnimePub/AniPub-API/#readme",
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/AnimePub/AniPub-API/issues"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"sideEffects": false
|
|
58
|
+
}
|
package/src/index.cjs
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AniPub JS — A full-featured client for the AniPub Anime API
|
|
3
|
+
* Covers all 10 endpoints: info, getAll, find, details (v1), full details,
|
|
4
|
+
* findbyGenre, check, findbyrating, search, searchall
|
|
5
|
+
*
|
|
6
|
+
* @module anipub
|
|
7
|
+
* @see https://api.anipub.xyz
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const BASE_URL = 'https://www.anipub.xyz';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Fix relative image paths by prepending the base domain.
|
|
16
|
+
* @param {string|undefined} path
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
function fixImage(path) {
|
|
20
|
+
if (!path) return '';
|
|
21
|
+
return path.startsWith('https://') ? path : `https://anipub.xyz/${path}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Fix all known image fields in an object.
|
|
26
|
+
* @param {object} obj
|
|
27
|
+
* @returns {object}
|
|
28
|
+
*/
|
|
29
|
+
function fixImages(obj) {
|
|
30
|
+
if (!obj || typeof obj !== 'object') return obj;
|
|
31
|
+
const clone = { ...obj };
|
|
32
|
+
for (const key of ['ImagePath', 'Cover', 'Image', 'image']) {
|
|
33
|
+
if (clone[key]) clone[key] = fixImage(clone[key]);
|
|
34
|
+
}
|
|
35
|
+
return clone;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Internal fetch wrapper with error handling.
|
|
40
|
+
* @param {string} url
|
|
41
|
+
* @param {RequestInit} [options]
|
|
42
|
+
* @returns {Promise<any>}
|
|
43
|
+
*/
|
|
44
|
+
async function apiFetch(url, options = {}) {
|
|
45
|
+
const res = await fetch(url, {
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
...options,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const text = await res.text().catch(() => '');
|
|
52
|
+
throw new AniPubError(res.status, `AniPub API error [${res.status}]: ${res.statusText}. ${text}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return res.json();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AniPubError extends Error {
|
|
61
|
+
/**
|
|
62
|
+
* @param {number} statusCode
|
|
63
|
+
* @param {string} message
|
|
64
|
+
*/
|
|
65
|
+
constructor(statusCode, message) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = 'AniPubError';
|
|
68
|
+
this.statusCode = statusCode;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ─── Endpoints ───────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* GET /api/info/:id
|
|
76
|
+
* Full metadata for one anime by integer ID or kebab-case slug.
|
|
77
|
+
*
|
|
78
|
+
* @param {number|string} idOrSlug - e.g. 61 or "black-clover" or "one-piece"
|
|
79
|
+
* @returns {Promise<AnimeInfo>}
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const anime = await getInfo(61);
|
|
83
|
+
* const anime = await getInfo('black-clover');
|
|
84
|
+
*/
|
|
85
|
+
export async function getInfo(idOrSlug) {
|
|
86
|
+
const data = await apiFetch(`${BASE_URL}/api/info/${encodeURIComponent(idOrSlug)}`);
|
|
87
|
+
return fixImages(data);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* GET /api/getAll
|
|
92
|
+
* Returns the total count of anime in the database.
|
|
93
|
+
* Use to determine the valid integer ID range for getInfo().
|
|
94
|
+
*
|
|
95
|
+
* @returns {Promise<number>}
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* const total = await getTotal();
|
|
99
|
+
* console.log(`IDs 1 to ${total}`);
|
|
100
|
+
*/
|
|
101
|
+
export async function getTotal() {
|
|
102
|
+
return apiFetch(`${BASE_URL}/api/getAll`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* GET /api/find/:name
|
|
107
|
+
* Check if an anime exists by exact name.
|
|
108
|
+
* Returns { exist: true, id, ep } or { exist: false }.
|
|
109
|
+
*
|
|
110
|
+
* @param {string} name - Anime title (will be URL-encoded automatically)
|
|
111
|
+
* @returns {Promise<FindResult>}
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const result = await findByName('One Piece');
|
|
115
|
+
* if (result.exist) console.log(`ID: ${result.id}, Episodes: ${result.ep}`);
|
|
116
|
+
*/
|
|
117
|
+
export async function findByName(name) {
|
|
118
|
+
return apiFetch(`${BASE_URL}/api/find/${encodeURIComponent(name)}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* GET /v1/api/details/:id
|
|
123
|
+
* Returns streaming iframe links per episode.
|
|
124
|
+
* - local.link = Episode 1 (strip "src=" prefix to get the raw URL)
|
|
125
|
+
* - local.ep[] = Episodes 2+ (ep[0] = EP2, ep[1] = EP3, ...)
|
|
126
|
+
*
|
|
127
|
+
* @param {number|string} id - Numeric anime ID
|
|
128
|
+
* @param {object} [options]
|
|
129
|
+
* @param {boolean} [options.stripSrc=true] - Auto-strip "src=" prefix from links
|
|
130
|
+
* @returns {Promise<StreamingDetails>}
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* const { episodes } = await getStreamingLinks(119);
|
|
134
|
+
* // episodes[0] = { ep: 1, src: 'https://...' }
|
|
135
|
+
*/
|
|
136
|
+
export async function getStreamingLinks(id, { stripSrc = true } = {}) {
|
|
137
|
+
const data = await apiFetch(`${BASE_URL}/v1/api/details/${id}`);
|
|
138
|
+
const local = data.local;
|
|
139
|
+
|
|
140
|
+
if (!local) return data;
|
|
141
|
+
|
|
142
|
+
const strip = (link) => (stripSrc && link ? link.replace(/^src=/, '') : link);
|
|
143
|
+
|
|
144
|
+
const episodes = [
|
|
145
|
+
{ ep: 1, src: strip(local.link) },
|
|
146
|
+
...(local.ep || []).map((e, i) => ({ ep: i + 2, src: strip(e.link) })),
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
return { ...data, episodes };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* GET /anime/api/details/:id
|
|
154
|
+
* Full details: local metadata + MAL/Jikan data + characters & voice actors.
|
|
155
|
+
* This is the most complete single-anime endpoint.
|
|
156
|
+
*
|
|
157
|
+
* @param {number|string} id - Numeric anime ID
|
|
158
|
+
* @returns {Promise<FullDetails>}
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const { local, jikan, characters } = await getFullDetails(119);
|
|
162
|
+
* console.log(local.Name, local.MALScore);
|
|
163
|
+
* characters.forEach(c => console.log(c.character.name, c.role));
|
|
164
|
+
*/
|
|
165
|
+
export async function getFullDetails(id) {
|
|
166
|
+
const data = await apiFetch(`${BASE_URL}/anime/api/details/${id}`);
|
|
167
|
+
if (data.local) data.local = fixImages(data.local);
|
|
168
|
+
return data;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* GET /api/findbyGenre/:genre
|
|
173
|
+
* Paginated anime list filtered by genre.
|
|
174
|
+
*
|
|
175
|
+
* @param {string} genre - e.g. "action", "harem", "romance", "ecchi"
|
|
176
|
+
* @param {number} [page=1] - Page number
|
|
177
|
+
* @returns {Promise<GenreResult>}
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* const { currentPage, wholePage } = await findByGenre('action', 1);
|
|
181
|
+
* wholePage.forEach(a => console.log(a.Name));
|
|
182
|
+
*/
|
|
183
|
+
export async function findByGenre(genre, page = 1) {
|
|
184
|
+
const data = await apiFetch(`${BASE_URL}/api/findbyGenre/${encodeURIComponent(genre)}?Page=${page}`);
|
|
185
|
+
if (Array.isArray(data.wholePage)) {
|
|
186
|
+
data.wholePage = data.wholePage.map(fixImages);
|
|
187
|
+
}
|
|
188
|
+
return data;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* POST /api/check
|
|
193
|
+
* Check if an anime exists by name and genre.
|
|
194
|
+
*
|
|
195
|
+
* @param {string} name - Anime title
|
|
196
|
+
* @param {string|string[]} genre - Genre string or array of genres
|
|
197
|
+
* @returns {Promise<any>}
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* await checkAnime('Black Clover', 'Action');
|
|
201
|
+
* await checkAnime('Jujutsu Kaisen', ['Action', 'Drama']);
|
|
202
|
+
*/
|
|
203
|
+
export async function checkAnime(name, genre) {
|
|
204
|
+
return apiFetch(`${BASE_URL}/api/check`, {
|
|
205
|
+
method: 'POST',
|
|
206
|
+
body: JSON.stringify({ Name: name, Genre: genre }),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* GET /api/findbyrating
|
|
212
|
+
* Top-rated anime sorted by MAL score descending, paginated.
|
|
213
|
+
*
|
|
214
|
+
* @param {number} [page=1] - Page number
|
|
215
|
+
* @returns {Promise<RatingResult>}
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* const { AniData, currentPage } = await getTopRated(1);
|
|
219
|
+
* AniData.forEach(a => console.log(a.Name, a.MALScore));
|
|
220
|
+
*/
|
|
221
|
+
export async function getTopRated(page = 1) {
|
|
222
|
+
const data = await apiFetch(`${BASE_URL}/api/findbyrating?page=${page}`);
|
|
223
|
+
if (Array.isArray(data.AniData)) {
|
|
224
|
+
data.AniData = data.AniData.map(fixImages);
|
|
225
|
+
}
|
|
226
|
+
return data;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* GET /api/search/:name
|
|
231
|
+
* Quick search — flat array of matches, ideal for autocomplete.
|
|
232
|
+
* No pagination. Faster than searchAll.
|
|
233
|
+
*
|
|
234
|
+
* @param {string} query - Search query
|
|
235
|
+
* @returns {Promise<SearchResult[]>}
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* const results = await search('One Piece');
|
|
239
|
+
* results.forEach(r => console.log(r.Name, r.Id));
|
|
240
|
+
*/
|
|
241
|
+
export async function search(query) {
|
|
242
|
+
const data = await apiFetch(`${BASE_URL}/api/search/${encodeURIComponent(query)}`);
|
|
243
|
+
return Array.isArray(data) ? data.map(fixImages) : data;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* GET /api/searchall/:name
|
|
248
|
+
* Full paginated search across all anime.
|
|
249
|
+
* Returns more results than search(), with pagination.
|
|
250
|
+
*
|
|
251
|
+
* @param {string} query - Search query
|
|
252
|
+
* @param {number} [page=1] - Page number
|
|
253
|
+
* @returns {Promise<SearchAllResult>}
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* const { AniData, currentPage } = await searchAll('Naruto', 1);
|
|
257
|
+
* AniData.forEach(a => console.log(a.Name, a.MALScore));
|
|
258
|
+
*/
|
|
259
|
+
export async function searchAll(query, page = 1) {
|
|
260
|
+
const data = await apiFetch(
|
|
261
|
+
`${BASE_URL}/api/searchall/${encodeURIComponent(query)}?page=${page}`
|
|
262
|
+
);
|
|
263
|
+
if (Array.isArray(data.AniData)) {
|
|
264
|
+
data.AniData = data.AniData.map(fixImages);
|
|
265
|
+
}
|
|
266
|
+
return data;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ─── Convenience class ───────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* AniPub client class — wraps all endpoints as instance methods.
|
|
273
|
+
* Useful when you want a single import and potential future config options.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* import AniPub from 'anipub';
|
|
277
|
+
* const client = new AniPub();
|
|
278
|
+
* const anime = await client.getInfo('one-piece');
|
|
279
|
+
*/
|
|
280
|
+
class AniPub {
|
|
281
|
+
constructor() {}
|
|
282
|
+
|
|
283
|
+
getInfo(idOrSlug) { return getInfo(idOrSlug); }
|
|
284
|
+
getTotal() { return getTotal(); }
|
|
285
|
+
findByName(name) { return findByName(name); }
|
|
286
|
+
getStreamingLinks(id, opts) { return getStreamingLinks(id, opts); }
|
|
287
|
+
getFullDetails(id) { return getFullDetails(id); }
|
|
288
|
+
findByGenre(genre, page) { return findByGenre(genre, page); }
|
|
289
|
+
checkAnime(name, genre) { return checkAnime(name, genre); }
|
|
290
|
+
getTopRated(page) { return getTopRated(page); }
|
|
291
|
+
search(query) { return search(query); }
|
|
292
|
+
searchAll(query, page) { return searchAll(query, page); }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @typedef {object} AnimeInfo
|
|
301
|
+
* @property {number} _id
|
|
302
|
+
* @property {string} Name
|
|
303
|
+
* @property {string} ImagePath
|
|
304
|
+
* @property {string} Cover
|
|
305
|
+
* @property {string} Synonyms
|
|
306
|
+
* @property {string} Aired
|
|
307
|
+
* @property {string} Premiered
|
|
308
|
+
* @property {number} RatingsNum
|
|
309
|
+
* @property {string[]} Genres
|
|
310
|
+
* @property {string} Studios
|
|
311
|
+
* @property {string} DescripTion
|
|
312
|
+
* @property {string} Duration
|
|
313
|
+
* @property {string} MALScore
|
|
314
|
+
* @property {string} Status
|
|
315
|
+
* @property {number} epCount
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @typedef {object} FindResult
|
|
320
|
+
* @property {boolean} exist
|
|
321
|
+
* @property {number} [id]
|
|
322
|
+
* @property {number} [ep]
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @typedef {object} EpisodeLink
|
|
327
|
+
* @property {number} ep
|
|
328
|
+
* @property {string} src
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* @typedef {object} StreamingDetails
|
|
333
|
+
* @property {object} local
|
|
334
|
+
* @property {EpisodeLink[]} episodes
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @typedef {object} FullDetails
|
|
339
|
+
* @property {AnimeInfo} local
|
|
340
|
+
* @property {object} jikan
|
|
341
|
+
* @property {object[]} characters
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @typedef {object} GenreResult
|
|
346
|
+
* @property {number} currentPage
|
|
347
|
+
* @property {AnimeInfo[]} wholePage
|
|
348
|
+
*/
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @typedef {object} RatingResult
|
|
352
|
+
* @property {number} currentPage
|
|
353
|
+
* @property {AnimeInfo[]} AniData
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @typedef {object} SearchResult
|
|
358
|
+
* @property {string} Name
|
|
359
|
+
* @property {number} Id
|
|
360
|
+
* @property {string} Image
|
|
361
|
+
* @property {string} finder
|
|
362
|
+
*/
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @typedef {object} SearchAllResult
|
|
366
|
+
* @property {number} currentPage
|
|
367
|
+
* @property {AnimeInfo[]} AniData
|
|
368
|
+
*/
|
|
369
|
+
|
|
370
|
+
// CommonJS exports
|
|
371
|
+
module.exports = {
|
|
372
|
+
AniPub,
|
|
373
|
+
AniPubError,
|
|
374
|
+
getInfo,
|
|
375
|
+
getTotal,
|
|
376
|
+
findByName,
|
|
377
|
+
getStreamingLinks,
|
|
378
|
+
getFullDetails,
|
|
379
|
+
findByGenre,
|
|
380
|
+
checkAnime,
|
|
381
|
+
getTopRated,
|
|
382
|
+
search,
|
|
383
|
+
searchAll,
|
|
384
|
+
};
|
|
385
|
+
module.exports.default = AniPub;
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AniPub JS — TypeScript declarations
|
|
3
|
+
* Full-featured client for the AniPub Anime API
|
|
4
|
+
* @see https://api.anipub.xyz
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface AnimeInfo {
|
|
8
|
+
_id: number;
|
|
9
|
+
Name: string;
|
|
10
|
+
ImagePath: string;
|
|
11
|
+
Cover: string;
|
|
12
|
+
Synonyms: string;
|
|
13
|
+
Aired: string;
|
|
14
|
+
Premiered: string;
|
|
15
|
+
RatingsNum: number;
|
|
16
|
+
Genres: string[];
|
|
17
|
+
Studios: string;
|
|
18
|
+
DescripTion: string;
|
|
19
|
+
Duration: string;
|
|
20
|
+
MALScore: string;
|
|
21
|
+
Status: string;
|
|
22
|
+
epCount: number;
|
|
23
|
+
finder?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FindResult {
|
|
27
|
+
exist: boolean;
|
|
28
|
+
id?: number;
|
|
29
|
+
ep?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface EpisodeLink {
|
|
33
|
+
ep: number;
|
|
34
|
+
src: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface StreamingDetails {
|
|
38
|
+
local: {
|
|
39
|
+
name: string;
|
|
40
|
+
link: string;
|
|
41
|
+
ep: Array<{ link: string }>;
|
|
42
|
+
};
|
|
43
|
+
episodes: EpisodeLink[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Character {
|
|
47
|
+
character: {
|
|
48
|
+
mal_id: number;
|
|
49
|
+
url: string;
|
|
50
|
+
images: { jpg: { image_url: string } };
|
|
51
|
+
name: string;
|
|
52
|
+
};
|
|
53
|
+
role: string;
|
|
54
|
+
voice_actors: Array<{
|
|
55
|
+
person: {
|
|
56
|
+
mal_id: number;
|
|
57
|
+
url: string;
|
|
58
|
+
images: { jpg: { image_url: string } };
|
|
59
|
+
name: string;
|
|
60
|
+
};
|
|
61
|
+
language: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface FullDetails {
|
|
66
|
+
local: AnimeInfo;
|
|
67
|
+
jikan: {
|
|
68
|
+
synopsis?: string;
|
|
69
|
+
background?: string;
|
|
70
|
+
[key: string]: unknown;
|
|
71
|
+
} | null;
|
|
72
|
+
characters: Character[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface GenreResult {
|
|
76
|
+
currentPage: number;
|
|
77
|
+
wholePage: AnimeInfo[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface RatingResult {
|
|
81
|
+
currentPage: number;
|
|
82
|
+
AniData: AnimeInfo[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface SearchResult {
|
|
86
|
+
Name: string;
|
|
87
|
+
Id: number;
|
|
88
|
+
Image: string;
|
|
89
|
+
finder: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface SearchAllResult {
|
|
93
|
+
currentPage: number;
|
|
94
|
+
AniData: AnimeInfo[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface StreamingOptions {
|
|
98
|
+
stripSrc?: boolean;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ─── Named exports ─────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
/** GET /api/info/:id — Full metadata by integer ID or slug */
|
|
104
|
+
export function getInfo(idOrSlug: number | string): Promise<AnimeInfo>;
|
|
105
|
+
|
|
106
|
+
/** GET /api/getAll — Total anime count in the database */
|
|
107
|
+
export function getTotal(): Promise<number>;
|
|
108
|
+
|
|
109
|
+
/** GET /api/find/:name — Check existence + episode count by exact name */
|
|
110
|
+
export function findByName(name: string): Promise<FindResult>;
|
|
111
|
+
|
|
112
|
+
/** GET /v1/api/details/:id — Streaming iframe links, normalized by episode */
|
|
113
|
+
export function getStreamingLinks(id: number | string, options?: StreamingOptions): Promise<StreamingDetails>;
|
|
114
|
+
|
|
115
|
+
/** GET /anime/api/details/:id — Full details: local + MAL + characters */
|
|
116
|
+
export function getFullDetails(id: number | string): Promise<FullDetails>;
|
|
117
|
+
|
|
118
|
+
/** GET /api/findbyGenre/:genre — Paginated list by genre */
|
|
119
|
+
export function findByGenre(genre: string, page?: number): Promise<GenreResult>;
|
|
120
|
+
|
|
121
|
+
/** POST /api/check — Verify anime exists by name and genre */
|
|
122
|
+
export function checkAnime(name: string, genre: string | string[]): Promise<unknown>;
|
|
123
|
+
|
|
124
|
+
/** GET /api/findbyrating — Top-rated anime, paginated */
|
|
125
|
+
export function getTopRated(page?: number): Promise<RatingResult>;
|
|
126
|
+
|
|
127
|
+
/** GET /api/search/:name — Quick flat search, great for autocomplete */
|
|
128
|
+
export function search(query: string): Promise<SearchResult[]>;
|
|
129
|
+
|
|
130
|
+
/** GET /api/searchall/:name — Full paginated search */
|
|
131
|
+
export function searchAll(query: string, page?: number): Promise<SearchAllResult>;
|
|
132
|
+
|
|
133
|
+
// ─── Class ─────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
export class AniPubError extends Error {
|
|
136
|
+
statusCode: number;
|
|
137
|
+
constructor(statusCode: number, message: string);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export class AniPub {
|
|
141
|
+
constructor();
|
|
142
|
+
getInfo(idOrSlug: number | string): Promise<AnimeInfo>;
|
|
143
|
+
getTotal(): Promise<number>;
|
|
144
|
+
findByName(name: string): Promise<FindResult>;
|
|
145
|
+
getStreamingLinks(id: number | string, options?: StreamingOptions): Promise<StreamingDetails>;
|
|
146
|
+
getFullDetails(id: number | string): Promise<FullDetails>;
|
|
147
|
+
findByGenre(genre: string, page?: number): Promise<GenreResult>;
|
|
148
|
+
checkAnime(name: string, genre: string | string[]): Promise<unknown>;
|
|
149
|
+
getTopRated(page?: number): Promise<RatingResult>;
|
|
150
|
+
search(query: string): Promise<SearchResult[]>;
|
|
151
|
+
searchAll(query: string, page?: number): Promise<SearchAllResult>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default AniPub;
|