ani-client 1.0.0 → 1.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 +299 -0
- package/dist/index.d.mts +364 -1
- package/dist/index.d.ts +364 -1
- package/dist/index.js +510 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +506 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -46,6 +46,16 @@ declare enum MediaSort {
|
|
|
46
46
|
UPDATED_AT = "UPDATED_AT",
|
|
47
47
|
SEARCH_MATCH = "SEARCH_MATCH"
|
|
48
48
|
}
|
|
49
|
+
declare enum AiringSort {
|
|
50
|
+
ID = "ID",
|
|
51
|
+
ID_DESC = "ID_DESC",
|
|
52
|
+
MEDIA_ID = "MEDIA_ID",
|
|
53
|
+
MEDIA_ID_DESC = "MEDIA_ID_DESC",
|
|
54
|
+
TIME = "TIME",
|
|
55
|
+
TIME_DESC = "TIME_DESC",
|
|
56
|
+
EPISODE = "EPISODE",
|
|
57
|
+
EPISODE_DESC = "EPISODE_DESC"
|
|
58
|
+
}
|
|
49
59
|
declare enum CharacterSort {
|
|
50
60
|
ID = "ID",
|
|
51
61
|
ROLE = "ROLE",
|
|
@@ -91,6 +101,28 @@ interface Studio {
|
|
|
91
101
|
interface StudioConnection {
|
|
92
102
|
nodes: Studio[];
|
|
93
103
|
}
|
|
104
|
+
declare enum MediaRelationType {
|
|
105
|
+
ADAPTATION = "ADAPTATION",
|
|
106
|
+
PREQUEL = "PREQUEL",
|
|
107
|
+
SEQUEL = "SEQUEL",
|
|
108
|
+
PARENT = "PARENT",
|
|
109
|
+
SIDE_STORY = "SIDE_STORY",
|
|
110
|
+
CHARACTER = "CHARACTER",
|
|
111
|
+
SUMMARY = "SUMMARY",
|
|
112
|
+
ALTERNATIVE = "ALTERNATIVE",
|
|
113
|
+
SPIN_OFF = "SPIN_OFF",
|
|
114
|
+
OTHER = "OTHER",
|
|
115
|
+
SOURCE = "SOURCE",
|
|
116
|
+
COMPILATION = "COMPILATION",
|
|
117
|
+
CONTAINS = "CONTAINS"
|
|
118
|
+
}
|
|
119
|
+
interface MediaEdge {
|
|
120
|
+
relationType: MediaRelationType;
|
|
121
|
+
node: Pick<Media, "id" | "title" | "type" | "format" | "status" | "coverImage" | "siteUrl">;
|
|
122
|
+
}
|
|
123
|
+
interface MediaConnection {
|
|
124
|
+
edges: MediaEdge[];
|
|
125
|
+
}
|
|
94
126
|
interface CharacterName {
|
|
95
127
|
first: string | null;
|
|
96
128
|
middle: string | null;
|
|
@@ -135,6 +167,7 @@ interface Media {
|
|
|
135
167
|
trending: number | null;
|
|
136
168
|
tags: MediaTag[];
|
|
137
169
|
studios: StudioConnection;
|
|
170
|
+
relations: MediaConnection | null;
|
|
138
171
|
isAdult: boolean | null;
|
|
139
172
|
siteUrl: string | null;
|
|
140
173
|
}
|
|
@@ -210,6 +243,14 @@ interface User {
|
|
|
210
243
|
manga: UserStatistics;
|
|
211
244
|
} | null;
|
|
212
245
|
}
|
|
246
|
+
interface AiringSchedule {
|
|
247
|
+
id: number;
|
|
248
|
+
airingAt: number;
|
|
249
|
+
timeUntilAiring: number;
|
|
250
|
+
episode: number;
|
|
251
|
+
mediaId: number;
|
|
252
|
+
media: Media;
|
|
253
|
+
}
|
|
213
254
|
interface PageInfo {
|
|
214
255
|
total: number | null;
|
|
215
256
|
perPage: number | null;
|
|
@@ -242,10 +283,162 @@ interface SearchStaffOptions {
|
|
|
242
283
|
page?: number;
|
|
243
284
|
perPage?: number;
|
|
244
285
|
}
|
|
286
|
+
interface PaginatedOptions {
|
|
287
|
+
page?: number;
|
|
288
|
+
perPage?: number;
|
|
289
|
+
}
|
|
245
290
|
interface PagedResult<T> {
|
|
246
291
|
pageInfo: PageInfo;
|
|
247
292
|
results: T[];
|
|
248
293
|
}
|
|
294
|
+
interface GetAiringOptions {
|
|
295
|
+
/** Only show episodes that aired after this UNIX timestamp */
|
|
296
|
+
airingAtGreater?: number;
|
|
297
|
+
/** Only show episodes that aired before this UNIX timestamp */
|
|
298
|
+
airingAtLesser?: number;
|
|
299
|
+
/** Sort order (default: TIME_DESC) */
|
|
300
|
+
sort?: AiringSort[];
|
|
301
|
+
page?: number;
|
|
302
|
+
perPage?: number;
|
|
303
|
+
}
|
|
304
|
+
interface GetRecentChaptersOptions {
|
|
305
|
+
/** Page number (default: 1) */
|
|
306
|
+
page?: number;
|
|
307
|
+
/** Results per page (default: 20, max 50) */
|
|
308
|
+
perPage?: number;
|
|
309
|
+
}
|
|
310
|
+
interface GetPlanningOptions {
|
|
311
|
+
/** Filter by ANIME or MANGA (returns both if omitted) */
|
|
312
|
+
type?: MediaType;
|
|
313
|
+
/** Sort order (default: POPULARITY_DESC) */
|
|
314
|
+
sort?: MediaSort[];
|
|
315
|
+
page?: number;
|
|
316
|
+
perPage?: number;
|
|
317
|
+
}
|
|
318
|
+
declare enum RecommendationSort {
|
|
319
|
+
ID = "ID",
|
|
320
|
+
ID_DESC = "ID_DESC",
|
|
321
|
+
RATING = "RATING",
|
|
322
|
+
RATING_DESC = "RATING_DESC"
|
|
323
|
+
}
|
|
324
|
+
interface Recommendation {
|
|
325
|
+
id: number;
|
|
326
|
+
rating: number | null;
|
|
327
|
+
userRating: string | null;
|
|
328
|
+
mediaRecommendation: Media;
|
|
329
|
+
user: {
|
|
330
|
+
id: number;
|
|
331
|
+
name: string;
|
|
332
|
+
avatar: UserAvatar;
|
|
333
|
+
} | null;
|
|
334
|
+
}
|
|
335
|
+
interface GetRecommendationsOptions {
|
|
336
|
+
/** The AniList media ID to get recommendations for */
|
|
337
|
+
mediaId: number;
|
|
338
|
+
/** Sort order (default: RATING_DESC) */
|
|
339
|
+
sort?: RecommendationSort[];
|
|
340
|
+
page?: number;
|
|
341
|
+
perPage?: number;
|
|
342
|
+
}
|
|
343
|
+
declare enum MediaListStatus {
|
|
344
|
+
CURRENT = "CURRENT",
|
|
345
|
+
PLANNING = "PLANNING",
|
|
346
|
+
COMPLETED = "COMPLETED",
|
|
347
|
+
DROPPED = "DROPPED",
|
|
348
|
+
PAUSED = "PAUSED",
|
|
349
|
+
REPEATING = "REPEATING"
|
|
350
|
+
}
|
|
351
|
+
declare enum MediaListSort {
|
|
352
|
+
MEDIA_ID = "MEDIA_ID",
|
|
353
|
+
MEDIA_ID_DESC = "MEDIA_ID_DESC",
|
|
354
|
+
SCORE = "SCORE",
|
|
355
|
+
SCORE_DESC = "SCORE_DESC",
|
|
356
|
+
STATUS = "STATUS",
|
|
357
|
+
STATUS_DESC = "STATUS_DESC",
|
|
358
|
+
PROGRESS = "PROGRESS",
|
|
359
|
+
PROGRESS_DESC = "PROGRESS_DESC",
|
|
360
|
+
PROGRESS_VOLUMES = "PROGRESS_VOLUMES",
|
|
361
|
+
PROGRESS_VOLUMES_DESC = "PROGRESS_VOLUMES_DESC",
|
|
362
|
+
REPEAT = "REPEAT",
|
|
363
|
+
REPEAT_DESC = "REPEAT_DESC",
|
|
364
|
+
PRIORITY = "PRIORITY",
|
|
365
|
+
PRIORITY_DESC = "PRIORITY_DESC",
|
|
366
|
+
STARTED_ON = "STARTED_ON",
|
|
367
|
+
STARTED_ON_DESC = "STARTED_ON_DESC",
|
|
368
|
+
FINISHED_ON = "FINISHED_ON",
|
|
369
|
+
FINISHED_ON_DESC = "FINISHED_ON_DESC",
|
|
370
|
+
ADDED_TIME = "ADDED_TIME",
|
|
371
|
+
ADDED_TIME_DESC = "ADDED_TIME_DESC",
|
|
372
|
+
UPDATED_TIME = "UPDATED_TIME",
|
|
373
|
+
UPDATED_TIME_DESC = "UPDATED_TIME_DESC",
|
|
374
|
+
MEDIA_TITLE_ROMAJI = "MEDIA_TITLE_ROMAJI",
|
|
375
|
+
MEDIA_TITLE_ROMAJI_DESC = "MEDIA_TITLE_ROMAJI_DESC",
|
|
376
|
+
MEDIA_TITLE_ENGLISH = "MEDIA_TITLE_ENGLISH",
|
|
377
|
+
MEDIA_TITLE_ENGLISH_DESC = "MEDIA_TITLE_ENGLISH_DESC",
|
|
378
|
+
MEDIA_TITLE_NATIVE = "MEDIA_TITLE_NATIVE",
|
|
379
|
+
MEDIA_TITLE_NATIVE_DESC = "MEDIA_TITLE_NATIVE_DESC",
|
|
380
|
+
MEDIA_POPULARITY = "MEDIA_POPULARITY",
|
|
381
|
+
MEDIA_POPULARITY_DESC = "MEDIA_POPULARITY_DESC"
|
|
382
|
+
}
|
|
383
|
+
interface MediaListEntry {
|
|
384
|
+
id: number;
|
|
385
|
+
mediaId: number;
|
|
386
|
+
status: MediaListStatus;
|
|
387
|
+
score: number | null;
|
|
388
|
+
progress: number | null;
|
|
389
|
+
progressVolumes: number | null;
|
|
390
|
+
repeat: number | null;
|
|
391
|
+
priority: number | null;
|
|
392
|
+
private: boolean | null;
|
|
393
|
+
notes: string | null;
|
|
394
|
+
startedAt: FuzzyDate | null;
|
|
395
|
+
completedAt: FuzzyDate | null;
|
|
396
|
+
updatedAt: number | null;
|
|
397
|
+
createdAt: number | null;
|
|
398
|
+
media: Media;
|
|
399
|
+
}
|
|
400
|
+
interface GetSeasonOptions {
|
|
401
|
+
/** The season (WINTER, SPRING, SUMMER, FALL) */
|
|
402
|
+
season: MediaSeason;
|
|
403
|
+
/** The year */
|
|
404
|
+
seasonYear: number;
|
|
405
|
+
/** Filter by ANIME or MANGA (defaults to ANIME) */
|
|
406
|
+
type?: MediaType;
|
|
407
|
+
/** Sort order (default: POPULARITY_DESC) */
|
|
408
|
+
sort?: MediaSort[];
|
|
409
|
+
page?: number;
|
|
410
|
+
perPage?: number;
|
|
411
|
+
}
|
|
412
|
+
interface GetUserMediaListOptions {
|
|
413
|
+
/** User ID (provide either userId or userName) */
|
|
414
|
+
userId?: number;
|
|
415
|
+
/** Username (provide either userId or userName) */
|
|
416
|
+
userName?: string;
|
|
417
|
+
/** ANIME or MANGA */
|
|
418
|
+
type: MediaType;
|
|
419
|
+
/** Filter by list status (CURRENT, COMPLETED, etc.) */
|
|
420
|
+
status?: MediaListStatus;
|
|
421
|
+
/** Sort order */
|
|
422
|
+
sort?: MediaListSort[];
|
|
423
|
+
page?: number;
|
|
424
|
+
perPage?: number;
|
|
425
|
+
}
|
|
426
|
+
interface StudioDetail {
|
|
427
|
+
id: number;
|
|
428
|
+
name: string;
|
|
429
|
+
isAnimationStudio: boolean;
|
|
430
|
+
siteUrl: string | null;
|
|
431
|
+
favourites: number | null;
|
|
432
|
+
media: {
|
|
433
|
+
pageInfo: PageInfo;
|
|
434
|
+
nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
|
|
435
|
+
} | null;
|
|
436
|
+
}
|
|
437
|
+
interface SearchStudioOptions {
|
|
438
|
+
query?: string;
|
|
439
|
+
page?: number;
|
|
440
|
+
perPage?: number;
|
|
441
|
+
}
|
|
249
442
|
interface AniListClientOptions {
|
|
250
443
|
/** Optional AniList OAuth token for authenticated requests */
|
|
251
444
|
token?: string;
|
|
@@ -366,6 +559,176 @@ declare class AniListClient {
|
|
|
366
559
|
* @param variables - Optional variables object
|
|
367
560
|
*/
|
|
368
561
|
raw<T = unknown>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
562
|
+
/**
|
|
563
|
+
* Get recently aired anime episodes.
|
|
564
|
+
*
|
|
565
|
+
* By default returns episodes that aired in the last 24 hours.
|
|
566
|
+
*
|
|
567
|
+
* @param options - Filter / pagination parameters
|
|
568
|
+
* @returns Paginated list of airing schedule entries
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```ts
|
|
572
|
+
* // Episodes that aired in the last 48h
|
|
573
|
+
* const recent = await client.getAiredEpisodes({
|
|
574
|
+
* airingAtGreater: Math.floor(Date.now() / 1000) - 48 * 3600,
|
|
575
|
+
* });
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
|
|
579
|
+
/**
|
|
580
|
+
* Get manga that are currently releasing, sorted by most recently updated.
|
|
581
|
+
*
|
|
582
|
+
* This is the closest equivalent to "recently released chapters" on AniList,
|
|
583
|
+
* since the API does not expose per-chapter airing schedules for manga.
|
|
584
|
+
*
|
|
585
|
+
* @param options - Pagination parameters
|
|
586
|
+
* @returns Paginated list of currently releasing manga
|
|
587
|
+
*
|
|
588
|
+
* @example
|
|
589
|
+
* ```ts
|
|
590
|
+
* const chapters = await client.getAiredChapters({ perPage: 10 });
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
593
|
+
getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
|
|
594
|
+
/**
|
|
595
|
+
* Get upcoming (not yet released) anime and/or manga, sorted by popularity.
|
|
596
|
+
*
|
|
597
|
+
* @param options - Filter / pagination parameters
|
|
598
|
+
* @returns Paginated list of planned media
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```ts
|
|
602
|
+
* import { MediaType } from "ani-client";
|
|
603
|
+
*
|
|
604
|
+
* // Most anticipated upcoming anime
|
|
605
|
+
* const planning = await client.getPlanning({ type: MediaType.ANIME, perPage: 10 });
|
|
606
|
+
* ```
|
|
607
|
+
*/
|
|
608
|
+
getPlanning(options?: GetPlanningOptions): Promise<PagedResult<Media>>;
|
|
609
|
+
/**
|
|
610
|
+
* Get recommendations for a specific media.
|
|
611
|
+
*
|
|
612
|
+
* Returns other anime/manga that users have recommended based on the given media.
|
|
613
|
+
*
|
|
614
|
+
* @param mediaId - The AniList media ID
|
|
615
|
+
* @param options - Optional sort / pagination parameters
|
|
616
|
+
* @returns Paginated list of recommendations
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```ts
|
|
620
|
+
* // Get recommendations for Cowboy Bebop
|
|
621
|
+
* const recs = await client.getRecommendations(1);
|
|
622
|
+
* recs.results.forEach((r) =>
|
|
623
|
+
* console.log(`${r.mediaRecommendation.title.romaji} (rating: ${r.rating})`)
|
|
624
|
+
* );
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
getRecommendations(mediaId: number, options?: Omit<GetRecommendationsOptions, "mediaId">): Promise<PagedResult<Recommendation>>;
|
|
628
|
+
/**
|
|
629
|
+
* Get anime (or manga) for a specific season and year.
|
|
630
|
+
*
|
|
631
|
+
* @param options - Season, year and optional filter / pagination parameters
|
|
632
|
+
* @returns Paginated list of media for the given season
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* import { MediaSeason } from "ani-client";
|
|
637
|
+
*
|
|
638
|
+
* const winter2026 = await client.getMediaBySeason({
|
|
639
|
+
* season: MediaSeason.WINTER,
|
|
640
|
+
* seasonYear: 2026,
|
|
641
|
+
* perPage: 10,
|
|
642
|
+
* });
|
|
643
|
+
* ```
|
|
644
|
+
*/
|
|
645
|
+
getMediaBySeason(options: GetSeasonOptions): Promise<PagedResult<Media>>;
|
|
646
|
+
/**
|
|
647
|
+
* Get a user's anime or manga list.
|
|
648
|
+
*
|
|
649
|
+
* Provide either `userId` or `userName` to identify the user.
|
|
650
|
+
* Requires `type` (ANIME or MANGA). Optionally filter by list status.
|
|
651
|
+
*
|
|
652
|
+
* @param options - User identifier, media type, and optional filters
|
|
653
|
+
* @returns Paginated list of media list entries
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* ```ts
|
|
657
|
+
* import { MediaType, MediaListStatus } from "ani-client";
|
|
658
|
+
*
|
|
659
|
+
* // Get a user's completed anime list
|
|
660
|
+
* const list = await client.getUserMediaList({
|
|
661
|
+
* userName: "AniList",
|
|
662
|
+
* type: MediaType.ANIME,
|
|
663
|
+
* status: MediaListStatus.COMPLETED,
|
|
664
|
+
* });
|
|
665
|
+
* list.results.forEach((entry) =>
|
|
666
|
+
* console.log(`${entry.media.title.romaji} — ${entry.score}/100`)
|
|
667
|
+
* );
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
getUserMediaList(options: GetUserMediaListOptions): Promise<PagedResult<MediaListEntry>>;
|
|
671
|
+
/**
|
|
672
|
+
* Fetch a studio by its AniList ID.
|
|
673
|
+
*
|
|
674
|
+
* Returns studio details along with its most popular productions.
|
|
675
|
+
*
|
|
676
|
+
* @param id - The AniList studio ID
|
|
677
|
+
*/
|
|
678
|
+
getStudio(id: number): Promise<StudioDetail>;
|
|
679
|
+
/**
|
|
680
|
+
* Search for studios by name.
|
|
681
|
+
*
|
|
682
|
+
* @param options - Search / pagination parameters
|
|
683
|
+
* @returns Paginated list of studios
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```ts
|
|
687
|
+
* const studios = await client.searchStudios({ query: "MAPPA" });
|
|
688
|
+
* ```
|
|
689
|
+
*/
|
|
690
|
+
searchStudios(options?: SearchStudioOptions): Promise<PagedResult<StudioDetail>>;
|
|
691
|
+
/**
|
|
692
|
+
* Get all available genres on AniList.
|
|
693
|
+
*
|
|
694
|
+
* @returns Array of genre strings (e.g. "Action", "Adventure", ...)
|
|
695
|
+
*/
|
|
696
|
+
getGenres(): Promise<string[]>;
|
|
697
|
+
/**
|
|
698
|
+
* Get all available media tags on AniList.
|
|
699
|
+
*
|
|
700
|
+
* @returns Array of tag objects with id, name, description, category, isAdult
|
|
701
|
+
*/
|
|
702
|
+
getTags(): Promise<MediaTag[]>;
|
|
703
|
+
/**
|
|
704
|
+
* Auto-paginating async iterator.
|
|
705
|
+
*
|
|
706
|
+
* Wraps any paginated method and yields individual items across all pages.
|
|
707
|
+
* Stops when `hasNextPage` is `false` or `maxPages` is reached.
|
|
708
|
+
*
|
|
709
|
+
* @param fetchPage - A function that takes a page number and returns a `PagedResult<T>`
|
|
710
|
+
* @param maxPages - Maximum number of pages to fetch (default: Infinity)
|
|
711
|
+
* @returns An async iterable iterator of individual items
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* ```ts
|
|
715
|
+
* // Iterate over all search results
|
|
716
|
+
* for await (const anime of client.paginate((page) =>
|
|
717
|
+
* client.searchMedia({ query: "Naruto", page, perPage: 10 })
|
|
718
|
+
* )) {
|
|
719
|
+
* console.log(anime.title.romaji);
|
|
720
|
+
* }
|
|
721
|
+
*
|
|
722
|
+
* // Limit to 3 pages
|
|
723
|
+
* for await (const anime of client.paginate(
|
|
724
|
+
* (page) => client.getTrending(MediaType.ANIME, page, 20),
|
|
725
|
+
* 3,
|
|
726
|
+
* )) {
|
|
727
|
+
* console.log(anime.title.romaji);
|
|
728
|
+
* }
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
paginate<T>(fetchPage: (page: number) => Promise<PagedResult<T>>, maxPages?: number): AsyncGenerator<T, void, undefined>;
|
|
369
732
|
/**
|
|
370
733
|
* Clear the entire response cache.
|
|
371
734
|
*/
|
|
@@ -458,4 +821,4 @@ declare class RateLimiter {
|
|
|
458
821
|
private sleep;
|
|
459
822
|
}
|
|
460
823
|
|
|
461
|
-
export { AniListClient, type AniListClientOptions, AniListError, type CacheOptions, type Character, type CharacterImage, type CharacterName, CharacterSort, type FuzzyDate, type Media, type MediaCoverImage, MediaFormat, MediaSeason, MediaSort, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type RateLimitOptions, RateLimiter, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type Staff, type StaffImage, type StaffName, type Studio, type StudioConnection, type User, type UserAvatar, type UserStatistics };
|
|
824
|
+
export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type CacheOptions, type Character, type CharacterImage, type CharacterName, CharacterSort, type FuzzyDate, type GetAiringOptions, type GetPlanningOptions, type GetRecentChaptersOptions, type GetRecommendationsOptions, type GetSeasonOptions, type GetUserMediaListOptions, type Media, type MediaConnection, type MediaCoverImage, type MediaEdge, MediaFormat, type MediaListEntry, MediaListSort, MediaListStatus, MediaRelationType, MediaSeason, MediaSort, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type PaginatedOptions, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type Staff, type StaffImage, type StaffName, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics };
|