@cyanheads/anime-mcp-server 0.1.1
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/AGENTS.md +346 -0
- package/CLAUDE.md +346 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +313 -0
- package/changelog/0.1.x/0.1.1.md +42 -0
- package/changelog/template.md +127 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/prompts/index.d.ts +7 -0
- package/dist/mcp-server/prompts/index.d.ts.map +1 -0
- package/dist/mcp-server/prompts/index.js +7 -0
- package/dist/mcp-server/prompts/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/anime-media.resource.d.ts +31 -0
- package/dist/mcp-server/resources/definitions/anime-media.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/anime-media.resource.js +100 -0
- package/dist/mcp-server/resources/definitions/anime-media.resource.js.map +1 -0
- package/dist/mcp-server/resources/index.d.ts +29 -0
- package/dist/mcp-server/resources/index.d.ts.map +1 -0
- package/dist/mcp-server/resources/index.js +7 -0
- package/dist/mcp-server/resources/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-find-characters.tool.d.ts +77 -0
- package/dist/mcp-server/tools/definitions/anime-find-characters.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-find-characters.tool.js +308 -0
- package/dist/mcp-server/tools/definitions/anime-find-characters.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-media.tool.d.ts +92 -0
- package/dist/mcp-server/tools/definitions/anime-get-media.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-media.tool.js +425 -0
- package/dist/mcp-server/tools/definitions/anime-get-media.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.d.ts +73 -0
- package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.js +154 -0
- package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.d.ts +35 -0
- package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.js +174 -0
- package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-relations.tool.d.ts +43 -0
- package/dist/mcp-server/tools/definitions/anime-get-relations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-relations.tool.js +245 -0
- package/dist/mcp-server/tools/definitions/anime-get-relations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.d.ts +51 -0
- package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.js +196 -0
- package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-studio.tool.d.ts +50 -0
- package/dist/mcp-server/tools/definitions/anime-get-studio.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-get-studio.tool.js +163 -0
- package/dist/mcp-server/tools/definitions/anime-get-studio.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-search-media.tool.d.ts +73 -0
- package/dist/mcp-server/tools/definitions/anime-search-media.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/anime-search-media.tool.js +229 -0
- package/dist/mcp-server/tools/definitions/anime-search-media.tool.js.map +1 -0
- package/dist/mcp-server/tools/index.d.ts +435 -0
- package/dist/mcp-server/tools/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/index.js +23 -0
- package/dist/mcp-server/tools/index.js.map +1 -0
- package/dist/services/anilist/anilist-service.d.ts +90 -0
- package/dist/services/anilist/anilist-service.d.ts.map +1 -0
- package/dist/services/anilist/anilist-service.js +496 -0
- package/dist/services/anilist/anilist-service.js.map +1 -0
- package/dist/services/anilist/types.d.ts +255 -0
- package/dist/services/anilist/types.d.ts.map +1 -0
- package/dist/services/anilist/types.js +6 -0
- package/dist/services/anilist/types.js.map +1 -0
- package/dist/services/jikan/jikan-service.d.ts +22 -0
- package/dist/services/jikan/jikan-service.d.ts.map +1 -0
- package/dist/services/jikan/jikan-service.js +89 -0
- package/dist/services/jikan/jikan-service.js.map +1 -0
- package/dist/services/jikan/types.d.ts +85 -0
- package/dist/services/jikan/types.d.ts.map +1 -0
- package/dist/services/jikan/types.js +6 -0
- package/dist/services/jikan/types.js.map +1 -0
- package/dist/services/kitsu/kitsu-service.d.ts +14 -0
- package/dist/services/kitsu/kitsu-service.d.ts.map +1 -0
- package/dist/services/kitsu/kitsu-service.js +94 -0
- package/dist/services/kitsu/kitsu-service.js.map +1 -0
- package/dist/services/kitsu/types.d.ts +17 -0
- package/dist/services/kitsu/types.d.ts.map +1 -0
- package/dist/services/kitsu/types.js +6 -0
- package/dist/services/kitsu/types.js.map +1 -0
- package/package.json +103 -0
- package/server.json +99 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview AniList service — GraphQL client wrapping https://graphql.anilist.co.
|
|
3
|
+
* Primary source for all anime/manga data: search, detail, relations, schedule,
|
|
4
|
+
* characters, recommendations, rankings, and studio filmography.
|
|
5
|
+
* @module services/anilist/anilist-service
|
|
6
|
+
*/
|
|
7
|
+
import { JsonRpcErrorCode, McpError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { fetchWithTimeout, requestContextService, withRetry } from '@cyanheads/mcp-ts-core/utils';
|
|
9
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
10
|
+
const ANILIST_URL = 'https://graphql.anilist.co';
|
|
11
|
+
const TIMEOUT_MS = 15_000;
|
|
12
|
+
const REQUEST_CONTEXT = requestContextService.createRequestContext({
|
|
13
|
+
operation: 'anilist-service',
|
|
14
|
+
});
|
|
15
|
+
// ─── Rate-limit state ─────────────────────────────────────────────────────────
|
|
16
|
+
/** Simple in-process rate-limit guard: 30 req / 30s. */
|
|
17
|
+
let _windowStart = 0;
|
|
18
|
+
let _windowCount = 0;
|
|
19
|
+
/**
|
|
20
|
+
* Block if we've hit the AniList rate limit.
|
|
21
|
+
* Waits out the current 30s window before resuming.
|
|
22
|
+
*/
|
|
23
|
+
async function checkRateLimit() {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
if (now - _windowStart > 30_000) {
|
|
26
|
+
_windowStart = now;
|
|
27
|
+
_windowCount = 0;
|
|
28
|
+
}
|
|
29
|
+
_windowCount++;
|
|
30
|
+
if (_windowCount > 29) {
|
|
31
|
+
const wait = 30_000 - (now - _windowStart) + 100;
|
|
32
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
33
|
+
_windowStart = Date.now();
|
|
34
|
+
_windowCount = 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ─── Core query executor ──────────────────────────────────────────────────────
|
|
38
|
+
/** Execute a GraphQL query against AniList. Returns the `data` payload. */
|
|
39
|
+
async function query(gql, variables) {
|
|
40
|
+
await checkRateLimit();
|
|
41
|
+
return withRetry(async () => {
|
|
42
|
+
const resp = await fetchWithTimeout(ANILIST_URL, TIMEOUT_MS, REQUEST_CONTEXT, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
45
|
+
body: JSON.stringify({ query: gql, variables }),
|
|
46
|
+
});
|
|
47
|
+
if (resp.status === 429) {
|
|
48
|
+
// Back off the full 30s window
|
|
49
|
+
await new Promise((r) => setTimeout(r, 30_000));
|
|
50
|
+
throw serviceUnavailable('AniList rate limit exceeded', { status: 429 });
|
|
51
|
+
}
|
|
52
|
+
// AniList sends 404 with data.{entity}: null for nonexistent IDs — read the body
|
|
53
|
+
// before deciding whether to treat it as an error.
|
|
54
|
+
if (!resp.ok && resp.status !== 200 && resp.status !== 404) {
|
|
55
|
+
throw serviceUnavailable(`AniList returned HTTP ${resp.status}`, { status: resp.status });
|
|
56
|
+
}
|
|
57
|
+
const json = (await resp.json());
|
|
58
|
+
// AniList returns HTTP 200 (or 404) even on GraphQL errors.
|
|
59
|
+
// When data is present (e.g. data.Media: null on not-found), return it so
|
|
60
|
+
// callers can check for null and throw the appropriate domain error.
|
|
61
|
+
if (json.errors?.length && !json.data) {
|
|
62
|
+
const firstErr = json.errors[0];
|
|
63
|
+
throw serviceUnavailable(`AniList GraphQL error: ${firstErr?.message ?? 'unknown'}`, {
|
|
64
|
+
status: firstErr?.status,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return json.data;
|
|
68
|
+
}, {
|
|
69
|
+
maxRetries: 3,
|
|
70
|
+
baseDelayMs: 1000,
|
|
71
|
+
maxDelayMs: 30_000,
|
|
72
|
+
operation: 'anilist-query',
|
|
73
|
+
context: REQUEST_CONTEXT,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// ─── GraphQL fragments ────────────────────────────────────────────────────────
|
|
77
|
+
const MEDIA_NODE_FRAGMENT = `
|
|
78
|
+
id idMal type format status season seasonYear episodes chapters volumes
|
|
79
|
+
isAdult meanScore
|
|
80
|
+
title { romaji english native }
|
|
81
|
+
coverImage { extraLarge large medium color }
|
|
82
|
+
`;
|
|
83
|
+
const MEDIA_DETAIL_FRAGMENT = `
|
|
84
|
+
${MEDIA_NODE_FRAGMENT}
|
|
85
|
+
description(asHtml: false)
|
|
86
|
+
source hashtag bannerImage
|
|
87
|
+
averageScore popularity favourites isFavourite
|
|
88
|
+
startDate { year month day }
|
|
89
|
+
endDate { year month day }
|
|
90
|
+
genres
|
|
91
|
+
tags { id name description category rank isGeneralSpoiler isAdult }
|
|
92
|
+
studios { edges { isMain node { id name isAnimationStudio } } }
|
|
93
|
+
externalLinks { id url site siteId type language icon color isDisabled }
|
|
94
|
+
relations { edges { relationType node { ${MEDIA_NODE_FRAGMENT} } } }
|
|
95
|
+
siteUrl
|
|
96
|
+
trailer { id site }
|
|
97
|
+
nextAiringEpisode { airingAt episode timeUntilAiring }
|
|
98
|
+
`;
|
|
99
|
+
// ─── Service methods ──────────────────────────────────────────────────────────
|
|
100
|
+
/** Search anime or manga by various filters. Returns a page of results. */
|
|
101
|
+
export async function searchMedia(params) {
|
|
102
|
+
const gql = `
|
|
103
|
+
query SearchMedia(
|
|
104
|
+
$type: MediaType, $search: String, $genre: String, $tag: String,
|
|
105
|
+
$season: MediaSeason, $seasonYear: Int, $format: MediaFormat,
|
|
106
|
+
$status: MediaStatus, $sort: [MediaSort], $page: Int, $perPage: Int,
|
|
107
|
+
$isAdult: Boolean
|
|
108
|
+
) {
|
|
109
|
+
Page(page: $page, perPage: $perPage) {
|
|
110
|
+
pageInfo { total currentPage lastPage hasNextPage perPage }
|
|
111
|
+
media(
|
|
112
|
+
type: $type, search: $search, genre: $genre, tag: $tag,
|
|
113
|
+
season: $season, seasonYear: $seasonYear, format: $format,
|
|
114
|
+
status: $status, sort: $sort, isAdult: $isAdult
|
|
115
|
+
) { ${MEDIA_NODE_FRAGMENT} }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
const data = await query(gql, {
|
|
120
|
+
type: params.mediaType,
|
|
121
|
+
search: params.query || undefined,
|
|
122
|
+
genre: params.genre || undefined,
|
|
123
|
+
tag: params.tag || undefined,
|
|
124
|
+
season: params.season || undefined,
|
|
125
|
+
seasonYear: params.seasonYear || undefined,
|
|
126
|
+
format: params.format || undefined,
|
|
127
|
+
status: params.status || undefined,
|
|
128
|
+
sort: params.sort || ['SEARCH_MATCH'],
|
|
129
|
+
page: params.page ?? 1,
|
|
130
|
+
perPage: Math.min(params.perPage ?? 20, 50),
|
|
131
|
+
isAdult: params.includeAdult ? undefined : false,
|
|
132
|
+
});
|
|
133
|
+
return data.Page;
|
|
134
|
+
}
|
|
135
|
+
/** Get full detail for one media item by AniList ID. Returns null if not found. */
|
|
136
|
+
export async function getMediaById(id, includeAdult = false) {
|
|
137
|
+
const gql = `
|
|
138
|
+
query GetMedia($id: Int, $isAdult: Boolean) {
|
|
139
|
+
Media(id: $id, isAdult: $isAdult) { ${MEDIA_DETAIL_FRAGMENT} }
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
try {
|
|
143
|
+
const data = await query(gql, {
|
|
144
|
+
id,
|
|
145
|
+
isAdult: includeAdult ? undefined : false,
|
|
146
|
+
});
|
|
147
|
+
return data.Media;
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
// AniList sends HTTP 404 for nonexistent IDs — fetchWithTimeout converts this to
|
|
151
|
+
// a NotFound McpError before we can read the body. Translate to null so callers
|
|
152
|
+
// can throw the appropriate domain error.
|
|
153
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
154
|
+
return null;
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Get relation edges for a media entry (one hop). Returns null if not found. */
|
|
159
|
+
export async function getMediaRelations(id) {
|
|
160
|
+
const gql = `
|
|
161
|
+
query GetRelations($id: Int) {
|
|
162
|
+
Media(id: $id) {
|
|
163
|
+
id
|
|
164
|
+
relations { edges { relationType node { ${MEDIA_NODE_FRAGMENT} } } }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`;
|
|
168
|
+
try {
|
|
169
|
+
const data = await query(gql, { id });
|
|
170
|
+
return data.Media?.relations.edges ?? null;
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
174
|
+
return null;
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Get seasonal airing schedule. */
|
|
179
|
+
export async function getSeasonSchedule(params) {
|
|
180
|
+
const gql = `
|
|
181
|
+
query SeasonSchedule(
|
|
182
|
+
$season: MediaSeason!, $seasonYear: Int!, $page: Int, $perPage: Int, $isAdult: Boolean
|
|
183
|
+
) {
|
|
184
|
+
Page(page: $page, perPage: $perPage) {
|
|
185
|
+
pageInfo { total currentPage lastPage hasNextPage perPage }
|
|
186
|
+
media(
|
|
187
|
+
type: ANIME, season: $season, seasonYear: $seasonYear,
|
|
188
|
+
sort: [POPULARITY_DESC], isAdult: $isAdult
|
|
189
|
+
) {
|
|
190
|
+
${MEDIA_NODE_FRAGMENT}
|
|
191
|
+
nextAiringEpisode { airingAt episode timeUntilAiring }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
const data = await query(gql, {
|
|
197
|
+
season: params.season,
|
|
198
|
+
seasonYear: params.seasonYear,
|
|
199
|
+
page: params.page ?? 1,
|
|
200
|
+
perPage: Math.min(params.perPage ?? 20, 50),
|
|
201
|
+
isAdult: params.includeAdult ? undefined : false,
|
|
202
|
+
});
|
|
203
|
+
return data.Page;
|
|
204
|
+
}
|
|
205
|
+
/** Get upcoming airing episodes within a time window. */
|
|
206
|
+
export async function getUpcomingEpisodes(params) {
|
|
207
|
+
const now = Math.floor(Date.now() / 1000);
|
|
208
|
+
const end = now + (params.daysAhead ?? 7) * 86_400;
|
|
209
|
+
const gql = `
|
|
210
|
+
query UpcomingEpisodes($greaterThan: Int!, $lessThan: Int!, $page: Int, $perPage: Int) {
|
|
211
|
+
Page(page: $page, perPage: $perPage) {
|
|
212
|
+
airingSchedules(airingAt_greater: $greaterThan, airingAt_lesser: $lessThan) {
|
|
213
|
+
id airingAt episode timeUntilAiring
|
|
214
|
+
media { ${MEDIA_NODE_FRAGMENT} }
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`;
|
|
219
|
+
const data = await query(gql, {
|
|
220
|
+
greaterThan: now,
|
|
221
|
+
lessThan: end,
|
|
222
|
+
page: params.page ?? 1,
|
|
223
|
+
perPage: Math.min(params.perPage ?? 50, 50),
|
|
224
|
+
});
|
|
225
|
+
return data.Page.airingSchedules;
|
|
226
|
+
}
|
|
227
|
+
/** Get characters for a media item. */
|
|
228
|
+
export async function getMediaCharacters(params) {
|
|
229
|
+
const gql = `
|
|
230
|
+
query GetCharacters($id: Int!, $language: StaffLanguage, $page: Int, $perPage: Int) {
|
|
231
|
+
Media(id: $id) {
|
|
232
|
+
characters(page: $page, perPage: $perPage, sort: [ROLE, RELEVANCE]) {
|
|
233
|
+
pageInfo { hasNextPage }
|
|
234
|
+
edges {
|
|
235
|
+
role
|
|
236
|
+
node {
|
|
237
|
+
id
|
|
238
|
+
name { full native }
|
|
239
|
+
image { large medium }
|
|
240
|
+
description(asHtml: false)
|
|
241
|
+
siteUrl
|
|
242
|
+
}
|
|
243
|
+
voiceActors(language: $language, sort: [RELEVANCE]) {
|
|
244
|
+
id
|
|
245
|
+
name { full native }
|
|
246
|
+
language
|
|
247
|
+
image { large medium }
|
|
248
|
+
siteUrl
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
`;
|
|
255
|
+
try {
|
|
256
|
+
const data = await query(gql, {
|
|
257
|
+
id: params.mediaId,
|
|
258
|
+
language: params.language || undefined,
|
|
259
|
+
page: params.page ?? 1,
|
|
260
|
+
perPage: Math.min(params.perPage ?? 25, 25),
|
|
261
|
+
});
|
|
262
|
+
if (!data.Media)
|
|
263
|
+
return { characters: [], hasNextPage: false };
|
|
264
|
+
return {
|
|
265
|
+
characters: data.Media.characters.edges,
|
|
266
|
+
hasNextPage: data.Media.characters.pageInfo.hasNextPage,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
271
|
+
return { characters: [], hasNextPage: false };
|
|
272
|
+
throw err;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** Search for a character by name. */
|
|
276
|
+
export async function searchCharacter(name) {
|
|
277
|
+
const gql = `
|
|
278
|
+
query SearchCharacter($search: String!, $page: Int, $perPage: Int) {
|
|
279
|
+
Character(search: $search) {
|
|
280
|
+
id
|
|
281
|
+
name { full native }
|
|
282
|
+
image { large medium }
|
|
283
|
+
description(asHtml: false)
|
|
284
|
+
siteUrl
|
|
285
|
+
media(page: $page, perPage: $perPage, sort: [POPULARITY_DESC]) {
|
|
286
|
+
pageInfo { hasNextPage currentPage }
|
|
287
|
+
nodes { ${MEDIA_NODE_FRAGMENT} }
|
|
288
|
+
edges {
|
|
289
|
+
characterRole
|
|
290
|
+
voiceActors(sort: [RELEVANCE]) {
|
|
291
|
+
id name { full native } language image { large medium } siteUrl
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
`;
|
|
298
|
+
try {
|
|
299
|
+
const data = await query(gql, {
|
|
300
|
+
search: name,
|
|
301
|
+
page: 1,
|
|
302
|
+
perPage: 10,
|
|
303
|
+
});
|
|
304
|
+
return data.Character;
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
308
|
+
return null;
|
|
309
|
+
throw err;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/** Search for a voice actor (staff) by name. */
|
|
313
|
+
export async function searchStaff(name, page = 1, perPage = 10) {
|
|
314
|
+
const gql = `
|
|
315
|
+
query SearchStaff($search: String!, $page: Int, $perPage: Int) {
|
|
316
|
+
Staff(search: $search) {
|
|
317
|
+
id
|
|
318
|
+
name { full native }
|
|
319
|
+
language
|
|
320
|
+
image { large medium }
|
|
321
|
+
description(asHtml: false)
|
|
322
|
+
siteUrl
|
|
323
|
+
characterMedia(page: $page, perPage: $perPage, sort: [POPULARITY_DESC]) {
|
|
324
|
+
pageInfo { hasNextPage currentPage }
|
|
325
|
+
edges {
|
|
326
|
+
characterRole
|
|
327
|
+
node { ${MEDIA_NODE_FRAGMENT} }
|
|
328
|
+
characters { id name { full native } }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
`;
|
|
334
|
+
try {
|
|
335
|
+
const data = await query(gql, {
|
|
336
|
+
search: name,
|
|
337
|
+
page,
|
|
338
|
+
perPage,
|
|
339
|
+
});
|
|
340
|
+
return data.Staff;
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
344
|
+
return null;
|
|
345
|
+
throw err;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/** Get recommendations for a media entry. */
|
|
349
|
+
export async function getRecommendations(params) {
|
|
350
|
+
const gql = `
|
|
351
|
+
query GetRecommendations($id: Int!, $page: Int, $perPage: Int) {
|
|
352
|
+
Media(id: $id) {
|
|
353
|
+
idMal
|
|
354
|
+
recommendations(page: $page, perPage: $perPage, sort: [RATING_DESC]) {
|
|
355
|
+
pageInfo { hasNextPage }
|
|
356
|
+
nodes {
|
|
357
|
+
rating
|
|
358
|
+
mediaRecommendation { ${MEDIA_NODE_FRAGMENT} }
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
`;
|
|
364
|
+
try {
|
|
365
|
+
const data = await query(gql, {
|
|
366
|
+
id: params.mediaId,
|
|
367
|
+
page: params.page ?? 1,
|
|
368
|
+
perPage: Math.min(params.perPage ?? 25, 25),
|
|
369
|
+
});
|
|
370
|
+
if (!data.Media)
|
|
371
|
+
return { nodes: [], hasNextPage: false };
|
|
372
|
+
return {
|
|
373
|
+
nodes: data.Media.recommendations.nodes,
|
|
374
|
+
hasNextPage: data.Media.recommendations.pageInfo.hasNextPage,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
379
|
+
return { nodes: [], hasNextPage: false };
|
|
380
|
+
throw err;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/** Get rankings by mode: top, trending, or seasonal. */
|
|
384
|
+
export async function getRankings(params) {
|
|
385
|
+
let sort;
|
|
386
|
+
let season = params.season;
|
|
387
|
+
let seasonYear = params.seasonYear;
|
|
388
|
+
switch (params.mode) {
|
|
389
|
+
case 'top':
|
|
390
|
+
sort = ['SCORE_DESC'];
|
|
391
|
+
break;
|
|
392
|
+
case 'trending':
|
|
393
|
+
sort = ['TRENDING_DESC'];
|
|
394
|
+
break;
|
|
395
|
+
case 'seasonal':
|
|
396
|
+
sort = ['POPULARITY_DESC'];
|
|
397
|
+
// Default to current season if not specified
|
|
398
|
+
if (!season || !seasonYear) {
|
|
399
|
+
const now = new Date();
|
|
400
|
+
const month = now.getMonth() + 1;
|
|
401
|
+
seasonYear = now.getFullYear();
|
|
402
|
+
if (month <= 3)
|
|
403
|
+
season = 'WINTER';
|
|
404
|
+
else if (month <= 6)
|
|
405
|
+
season = 'SPRING';
|
|
406
|
+
else if (month <= 9)
|
|
407
|
+
season = 'SUMMER';
|
|
408
|
+
else
|
|
409
|
+
season = 'FALL';
|
|
410
|
+
}
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
const gql = `
|
|
414
|
+
query GetRankings(
|
|
415
|
+
$type: MediaType!, $sort: [MediaSort]!, $format: MediaFormat, $genre: String,
|
|
416
|
+
$season: MediaSeason, $seasonYear: Int, $page: Int, $perPage: Int, $isAdult: Boolean
|
|
417
|
+
) {
|
|
418
|
+
Page(page: $page, perPage: $perPage) {
|
|
419
|
+
pageInfo { total currentPage lastPage hasNextPage perPage }
|
|
420
|
+
media(
|
|
421
|
+
type: $type, sort: $sort, format: $format, genre: $genre,
|
|
422
|
+
season: $season, seasonYear: $seasonYear, isAdult: $isAdult
|
|
423
|
+
) { ${MEDIA_NODE_FRAGMENT} }
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
const data = await query(gql, {
|
|
428
|
+
type: params.mediaType,
|
|
429
|
+
sort,
|
|
430
|
+
format: params.format || undefined,
|
|
431
|
+
genre: params.genre || undefined,
|
|
432
|
+
season: season || undefined,
|
|
433
|
+
seasonYear: seasonYear || undefined,
|
|
434
|
+
page: params.page ?? 1,
|
|
435
|
+
perPage: Math.min(params.perPage ?? 25, 50),
|
|
436
|
+
isAdult: params.includeAdult ? undefined : false,
|
|
437
|
+
});
|
|
438
|
+
return data.Page;
|
|
439
|
+
}
|
|
440
|
+
/** Look up a studio by name (search) and return its filmography. */
|
|
441
|
+
export async function searchStudio(params) {
|
|
442
|
+
const gql = `
|
|
443
|
+
query SearchStudio($search: String!, $mediaSort: [MediaSort], $page: Int, $perPage: Int) {
|
|
444
|
+
Studio(search: $search) {
|
|
445
|
+
id name isAnimationStudio siteUrl
|
|
446
|
+
media(page: $page, perPage: $perPage, sort: $mediaSort) {
|
|
447
|
+
pageInfo { total currentPage lastPage hasNextPage }
|
|
448
|
+
nodes { ${MEDIA_NODE_FRAGMENT} }
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
`;
|
|
453
|
+
try {
|
|
454
|
+
const data = await query(gql, {
|
|
455
|
+
search: params.name,
|
|
456
|
+
mediaSort: params.sort ? [params.sort] : ['POPULARITY_DESC'],
|
|
457
|
+
page: params.page ?? 1,
|
|
458
|
+
perPage: Math.min(params.perPage ?? 25, 50),
|
|
459
|
+
});
|
|
460
|
+
return data.Studio;
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
464
|
+
return null;
|
|
465
|
+
throw err;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/** Get studio by AniList ID. */
|
|
469
|
+
export async function getStudioById(params) {
|
|
470
|
+
const gql = `
|
|
471
|
+
query GetStudio($id: Int!, $mediaSort: [MediaSort], $page: Int, $perPage: Int) {
|
|
472
|
+
Studio(id: $id) {
|
|
473
|
+
id name isAnimationStudio siteUrl
|
|
474
|
+
media(page: $page, perPage: $perPage, sort: $mediaSort) {
|
|
475
|
+
pageInfo { total currentPage lastPage hasNextPage }
|
|
476
|
+
nodes { ${MEDIA_NODE_FRAGMENT} }
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
`;
|
|
481
|
+
try {
|
|
482
|
+
const data = await query(gql, {
|
|
483
|
+
id: params.id,
|
|
484
|
+
mediaSort: params.sort ? [params.sort] : ['POPULARITY_DESC'],
|
|
485
|
+
page: params.page ?? 1,
|
|
486
|
+
perPage: Math.min(params.perPage ?? 25, 50),
|
|
487
|
+
});
|
|
488
|
+
return data.Studio;
|
|
489
|
+
}
|
|
490
|
+
catch (err) {
|
|
491
|
+
if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
|
|
492
|
+
return null;
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=anilist-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anilist-service.js","sourceRoot":"","sources":["../../../src/services/anilist/anilist-service.ts"],"names":[],"mappings":"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"}
|