@irfanshadikrishad/anilist 1.0.11 → 1.1.0-forbidden.7

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.
@@ -8,27 +8,35 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { XMLParser } from "fast-xml-parser";
11
- import { readFile, writeFile } from "fs/promises";
11
+ import { readFile } from "fs/promises";
12
12
  import inquirer from "inquirer";
13
- import fetch from "node-fetch";
13
+ import { jsonrepair } from "jsonrepair";
14
14
  import { join } from "path";
15
15
  import { Auth } from "./auth.js";
16
16
  import { fetcher } from "./fetcher.js";
17
17
  import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, } from "./mutations.js";
18
- import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userQuery, } from "./queries.js";
18
+ import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
19
+ import { responsiveOutput } from "./truncate.js";
19
20
  import { AniListMediaStatus, } from "./types.js";
20
- import { aniListEndpoint, createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, } from "./workers.js";
21
+ import { Validate } from "./validation.js";
22
+ import { anidbToanilistMapper, formatDateObject, getDownloadFolderPath, getNextSeasonAndYear, getTitle, logUserDetails, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, selectFile, simpleDateFormat, timestampToTimeAgo, } from "./workers.js";
21
23
  class AniList {
22
24
  static importAnime() {
23
25
  return __awaiter(this, void 0, void 0, function* () {
24
26
  try {
25
27
  const filename = yield selectFile(".json");
28
+ if (!filename) {
29
+ return;
30
+ }
26
31
  const filePath = join(getDownloadFolderPath(), filename);
27
32
  const fileContent = yield readFile(filePath, "utf8");
28
33
  const importedData = JSON.parse(fileContent);
34
+ if (!Validate.Import_JSON(importedData)) {
35
+ console.error(`\nInvalid JSON file.`);
36
+ return;
37
+ }
29
38
  let count = 0;
30
- const batchSize = 1; // Number of requests in each batch
31
- const delay = 1100; // delay to avoid rate-limiting
39
+ const batchSize = 1;
32
40
  for (let i = 0; i < importedData.length; i += batchSize) {
33
41
  const batch = importedData.slice(i, i + batchSize);
34
42
  yield Promise.all(batch.map((anime) => __awaiter(this, void 0, void 0, function* () {
@@ -45,7 +53,7 @@ class AniList {
45
53
  if (save) {
46
54
  const id = (_b = (_a = save === null || save === void 0 ? void 0 : save.data) === null || _a === void 0 ? void 0 : _a.SaveMediaListEntry) === null || _b === void 0 ? void 0 : _b.id;
47
55
  count++;
48
- console.log(`[${count}] ${anime === null || anime === void 0 ? void 0 : anime.id}-${id} ✅`);
56
+ console.log(`[${count}]\t${id}\t${anime === null || anime === void 0 ? void 0 : anime.id} ✅`);
49
57
  }
50
58
  else {
51
59
  console.error(`\nError saving ${anime === null || anime === void 0 ? void 0 : anime.id}`);
@@ -55,8 +63,6 @@ class AniList {
55
63
  console.error(`\nError saving ${anime === null || anime === void 0 ? void 0 : anime.id}: ${error.message}`);
56
64
  }
57
65
  })));
58
- // Avoid rate-limiting: Wait before sending the next batch
59
- yield new Promise((resolve) => setTimeout(resolve, delay));
60
66
  }
61
67
  console.log(`\nTotal ${count} anime(s) imported successfully.`);
62
68
  }
@@ -69,13 +75,18 @@ class AniList {
69
75
  return __awaiter(this, void 0, void 0, function* () {
70
76
  try {
71
77
  const filename = yield selectFile(".json");
78
+ if (!filename) {
79
+ return;
80
+ }
72
81
  const filePath = join(getDownloadFolderPath(), filename);
73
82
  const fileContent = yield readFile(filePath, "utf8");
74
83
  const importedData = JSON.parse(fileContent);
84
+ if (!Validate.Import_JSON(importedData)) {
85
+ console.error(`\nInvalid JSON file.`);
86
+ return;
87
+ }
75
88
  let count = 0;
76
- const batchSize = 1; // Adjust batch size as per rate-limit constraints
77
- const delay = 1100; // 2 seconds delay to avoid rate-limit
78
- // Process in batches
89
+ const batchSize = 1;
79
90
  for (let i = 0; i < importedData.length; i += batchSize) {
80
91
  const batch = importedData.slice(i, i + batchSize);
81
92
  yield Promise.all(batch.map((manga) => __awaiter(this, void 0, void 0, function* () {
@@ -93,15 +104,13 @@ class AniList {
93
104
  if (save) {
94
105
  const id = (_b = (_a = save === null || save === void 0 ? void 0 : save.data) === null || _a === void 0 ? void 0 : _a.SaveMediaListEntry) === null || _b === void 0 ? void 0 : _b.id;
95
106
  count++;
96
- console.log(`[${count}] ${manga === null || manga === void 0 ? void 0 : manga.id}-${id} ✅`);
107
+ console.log(`[${count}]\t${id}\t${manga === null || manga === void 0 ? void 0 : manga.id} ✅`);
97
108
  }
98
109
  }
99
110
  catch (err) {
100
111
  console.error(`\nError saving ${manga === null || manga === void 0 ? void 0 : manga.id}: ${err.message}`);
101
112
  }
102
113
  })));
103
- // Avoid rate-limit by adding delay after processing each batch
104
- yield new Promise((resolve) => setTimeout(resolve, delay));
105
114
  }
106
115
  console.log(`\nTotal ${count} manga(s) imported successfully.`);
107
116
  }
@@ -113,7 +122,76 @@ class AniList {
113
122
  static exportAnime() {
114
123
  return __awaiter(this, void 0, void 0, function* () {
115
124
  var _a, _b, _c;
116
- if (yield Auth.isLoggedIn()) {
125
+ if (!(yield Auth.isLoggedIn())) {
126
+ console.error(`\nMust login to use this feature.`);
127
+ return;
128
+ }
129
+ const { exportType } = yield inquirer.prompt([
130
+ {
131
+ type: "list",
132
+ name: "exportType",
133
+ message: "Choose export type:",
134
+ choices: [
135
+ { name: "CSV", value: 1 },
136
+ { name: "JSON", value: 2 },
137
+ { name: "XML (MyAnimeList/AniDB)", value: 3 },
138
+ ],
139
+ pageSize: 10,
140
+ },
141
+ ]);
142
+ const animeList = yield fetcher(currentUserAnimeList, {
143
+ id: yield Auth.MyUserId(),
144
+ });
145
+ if (animeList) {
146
+ const lists = (_c = (_b = (_a = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists) !== null && _c !== void 0 ? _c : [];
147
+ const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
148
+ var _a, _b, _c, _d;
149
+ return ({
150
+ id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
151
+ title: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title,
152
+ episodes: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.episodes,
153
+ siteUrl: (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.siteUrl,
154
+ progress: entry.progress,
155
+ status: entry === null || entry === void 0 ? void 0 : entry.status,
156
+ hiddenFromStatusLists: entry.hiddenFromStatusLists,
157
+ });
158
+ }));
159
+ switch (exportType) {
160
+ case 1:
161
+ yield saveJSONasCSV(mediaWithProgress, "anime");
162
+ break;
163
+ case 2:
164
+ yield saveJSONasJSON(mediaWithProgress, "anime");
165
+ break;
166
+ case 3:
167
+ yield MyAnimeList.exportAnime();
168
+ break;
169
+ default:
170
+ console.log(`\nInvalid export type. ${exportType}`);
171
+ break;
172
+ }
173
+ }
174
+ else {
175
+ console.error(`\nNo anime(s) found in your lists.`);
176
+ }
177
+ });
178
+ }
179
+ static exportManga() {
180
+ return __awaiter(this, void 0, void 0, function* () {
181
+ var _a, _b;
182
+ if (!(yield Auth.isLoggedIn())) {
183
+ console.error(`\nPlease login to use this feature.`);
184
+ return;
185
+ }
186
+ const mangaLists = yield fetcher(currentUserMangaList, {
187
+ id: yield Auth.MyUserId(),
188
+ });
189
+ if (!(mangaLists === null || mangaLists === void 0 ? void 0 : mangaLists.data)) {
190
+ console.error(`\nCould not get manga list.`);
191
+ return;
192
+ }
193
+ const lists = ((_b = (_a = mangaLists === null || mangaLists === void 0 ? void 0 : mangaLists.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists) || [];
194
+ if (lists.length > 0) {
117
195
  const { exportType } = yield inquirer.prompt([
118
196
  {
119
197
  type: "list",
@@ -127,141 +205,53 @@ class AniList {
127
205
  pageSize: 10,
128
206
  },
129
207
  ]);
130
- const animeList = yield fetcher(currentUserAnimeList, {
131
- id: yield Auth.MyUserId(),
132
- });
133
- if (animeList) {
134
- const lists = (_c = (_b = (_a = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists) !== null && _c !== void 0 ? _c : [];
135
- const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
136
- var _a, _b, _c, _d, _e;
137
- return ({
138
- id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
139
- title: exportType === 1
140
- ? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
141
- : (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
142
- episodes: (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.episodes,
143
- siteUrl: (_e = entry === null || entry === void 0 ? void 0 : entry.media) === null || _e === void 0 ? void 0 : _e.siteUrl,
144
- progress: entry.progress,
145
- status: entry === null || entry === void 0 ? void 0 : entry.status,
146
- hiddenFromStatusLists: entry.hiddenFromStatusLists,
147
- });
148
- }));
149
- switch (exportType) {
150
- case 1:
151
- yield saveJSONasCSV(mediaWithProgress, "anime");
152
- break;
153
- case 2:
154
- yield saveJSONasJSON(mediaWithProgress, "anime");
155
- break;
156
- case 3:
157
- yield MyAnimeList.exportAnime();
158
- break;
159
- default:
160
- console.log(`\nInvalid export type. ${exportType}`);
161
- break;
162
- }
163
- }
164
- else {
165
- console.error(`\nNo anime(s) found in your lists.`);
166
- }
167
- }
168
- else {
169
- console.error(`\nMust login to use this feature.`);
170
- }
171
- });
172
- }
173
- static exportManga() {
174
- return __awaiter(this, void 0, void 0, function* () {
175
- var _a, _b;
176
- if (yield Auth.isLoggedIn()) {
177
- const mangaLists = yield fetcher(currentUserMangaList, {
178
- id: yield Auth.MyUserId(),
179
- });
180
- if (mangaLists) {
181
- const lists = ((_b = (_a = mangaLists === null || mangaLists === void 0 ? void 0 : mangaLists.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists) || [];
182
- if (lists.length > 0) {
183
- const { exportType } = yield inquirer.prompt([
184
- {
185
- type: "list",
186
- name: "exportType",
187
- message: "Choose export type:",
188
- choices: [
189
- { name: "CSV", value: 1 },
190
- { name: "JSON", value: 2 },
191
- { name: "XML (MyAnimeList)", value: 3 },
192
- ],
193
- pageSize: 10,
194
- },
195
- ]);
196
- const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
197
- var _a, _b, _c;
198
- return ({
199
- id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
200
- title: exportType === 1
201
- ? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
202
- : (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
203
- private: entry.private,
204
- chapters: entry.media.chapters,
205
- progress: entry.progress,
206
- status: entry === null || entry === void 0 ? void 0 : entry.status,
207
- hiddenFromStatusLists: entry.hiddenFromStatusLists,
208
- });
209
- }));
210
- switch (exportType) {
211
- case 1:
212
- yield saveJSONasCSV(mediaWithProgress, "manga");
213
- break;
214
- case 2:
215
- yield saveJSONasJSON(mediaWithProgress, "manga");
216
- break;
217
- case 3:
218
- yield MyAnimeList.exportManga();
219
- break;
220
- default:
221
- console.log(`\nInvalid export type. ${exportType}`);
222
- break;
223
- }
224
- }
225
- else {
226
- console.log(`\nList seems to be empty.`);
227
- }
228
- }
229
- else {
230
- console.error(`\nCould not get manga list.`);
208
+ const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
209
+ var _a, _b;
210
+ return ({
211
+ id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
212
+ title: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title,
213
+ private: entry.private,
214
+ chapters: entry.media.chapters,
215
+ progress: entry.progress,
216
+ status: entry === null || entry === void 0 ? void 0 : entry.status,
217
+ hiddenFromStatusLists: entry.hiddenFromStatusLists,
218
+ });
219
+ }));
220
+ switch (exportType) {
221
+ case 1:
222
+ yield saveJSONasCSV(mediaWithProgress, "manga");
223
+ break;
224
+ case 2:
225
+ yield saveJSONasJSON(mediaWithProgress, "manga");
226
+ break;
227
+ case 3:
228
+ yield MyAnimeList.exportManga();
229
+ break;
230
+ default:
231
+ console.log(`\nInvalid export type. ${exportType}`);
232
+ break;
231
233
  }
232
234
  }
233
235
  else {
234
- console.error(`\nPlease login to use this feature.`);
236
+ console.log(`\nList seems to be empty.`);
235
237
  }
236
238
  });
237
239
  }
238
240
  static MyAnime() {
239
241
  return __awaiter(this, void 0, void 0, function* () {
240
- var _a, _b, _c;
242
+ var _a, _b, _c, _d, _e;
241
243
  try {
242
244
  if (!(yield Auth.isLoggedIn())) {
243
245
  return console.error(`\nPlease log in first to access your lists.`);
244
246
  }
245
- const userId = yield Auth.MyUserId();
246
- if (!userId) {
247
+ if (!(yield Auth.MyUserId())) {
247
248
  return console.log(`\nFailed getting current user Id.`);
248
249
  }
249
- const request = yield fetch(aniListEndpoint, {
250
- method: "POST",
251
- headers: {
252
- "content-type": "application/json",
253
- "Authorization": `Bearer ${yield Auth.RetriveAccessToken()}`,
254
- },
255
- body: JSON.stringify({
256
- query: currentUserAnimeList,
257
- variables: { id: userId },
258
- }),
259
- });
260
- const { data, errors } = yield request.json();
261
- if (request.status !== 200 || errors) {
262
- return console.log(`\nSomething went wrong. ${(_a = errors === null || errors === void 0 ? void 0 : errors[0]) === null || _a === void 0 ? void 0 : _a.message}`);
250
+ const data = yield fetcher(currentUserAnimeList, { id: yield Auth.MyUserId() });
251
+ if (data === null || data === void 0 ? void 0 : data.errors) {
252
+ return console.log(`\nSomething went wrong. ${(_b = (_a = data === null || data === void 0 ? void 0 : data.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message}`);
263
253
  }
264
- const lists = (_b = data === null || data === void 0 ? void 0 : data.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists;
254
+ const lists = (_d = (_c = data === null || data === void 0 ? void 0 : data.data) === null || _c === void 0 ? void 0 : _c.MediaListCollection) === null || _d === void 0 ? void 0 : _d.lists;
265
255
  if (!lists || lists.length === 0) {
266
256
  return console.log(`\nYou seem to have no anime(s) in your lists.`);
267
257
  }
@@ -304,11 +294,12 @@ class AniList {
304
294
  ],
305
295
  },
306
296
  ]);
307
- const query = addAnimeToListMutation;
308
- const variables = { mediaId: selectedAnime, status: selectedListType };
309
- const saveResponse = yield fetcher(query, variables);
297
+ const saveResponse = yield fetcher(addAnimeToListMutation, {
298
+ mediaId: selectedAnime,
299
+ status: selectedListType,
300
+ });
310
301
  if (saveResponse) {
311
- const savedEntry = (_c = saveResponse.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
302
+ const savedEntry = (_e = saveResponse.data) === null || _e === void 0 ? void 0 : _e.SaveMediaListEntry;
312
303
  console.log(`\nEntry ${savedEntry === null || savedEntry === void 0 ? void 0 : savedEntry.id}. Saved as ${savedEntry === null || savedEntry === void 0 ? void 0 : savedEntry.status}.`);
313
304
  }
314
305
  else {
@@ -322,7 +313,7 @@ class AniList {
322
313
  }
323
314
  static MyManga() {
324
315
  return __awaiter(this, void 0, void 0, function* () {
325
- var _a, _b, _c, _d, _e;
316
+ var _a, _b, _c, _d, _e, _f, _g;
326
317
  try {
327
318
  if (!(yield Auth.isLoggedIn())) {
328
319
  return console.error(`\nPlease log in first to access your lists.`);
@@ -331,23 +322,11 @@ class AniList {
331
322
  if (!userId) {
332
323
  return console.error(`\nFailed to get the current user ID.`);
333
324
  }
334
- const token = yield Auth.RetriveAccessToken();
335
- const request = yield fetch(aniListEndpoint, {
336
- method: "POST",
337
- headers: {
338
- "Content-Type": "application/json",
339
- "Authorization": `Bearer ${token}`,
340
- },
341
- body: JSON.stringify({
342
- query: currentUserMangaList,
343
- variables: { id: userId },
344
- }),
345
- });
346
- const { data, errors } = yield request.json();
347
- if (request.status !== 200 || errors) {
348
- return console.error(`\nFailed to fetch manga lists. ${((_a = errors === null || errors === void 0 ? void 0 : errors[0]) === null || _a === void 0 ? void 0 : _a.message) || "Unknown error"}`);
325
+ const response = yield fetcher(currentUserMangaList, { id: userId });
326
+ if (!(response === null || response === void 0 ? void 0 : response.data)) {
327
+ return console.error(`\nFailed to fetch manga lists. ${((_b = (_a = response === null || response === void 0 ? void 0 : response.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) || "Unknown error"}`);
349
328
  }
350
- const lists = (_b = data === null || data === void 0 ? void 0 : data.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists;
329
+ const lists = (_d = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.MediaListCollection) === null || _d === void 0 ? void 0 : _d.lists;
351
330
  if (!lists || lists.length === 0) {
352
331
  return console.log("\nYou don't seem to have any manga in your lists.");
353
332
  }
@@ -393,24 +372,16 @@ class AniList {
393
372
  ],
394
373
  },
395
374
  ]);
396
- const saveRequest = yield fetch(aniListEndpoint, {
397
- method: "POST",
398
- headers: {
399
- "Content-Type": "application/json",
400
- "Authorization": `Bearer ${token}`,
401
- },
402
- body: JSON.stringify({
403
- query: addMangaToListMutation,
404
- variables: { mediaId: selectedManga, status: selectedListType },
405
- }),
375
+ const saveResponse = yield fetcher(addMangaToListMutation, {
376
+ mediaId: selectedManga,
377
+ status: selectedListType,
406
378
  });
407
- const saveResponse = yield saveRequest.json();
408
- const saved = (_c = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
379
+ const saved = (_e = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _e === void 0 ? void 0 : _e.SaveMediaListEntry;
409
380
  if (saved) {
410
381
  console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
411
382
  }
412
383
  else {
413
- console.error(`\nFailed to save the manga. ${((_e = (_d = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.message) || "Unknown error"}`);
384
+ console.error(`\nFailed to save the manga. ${((_g = (_f = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.message) || "Unknown error"}`);
414
385
  }
415
386
  }
416
387
  catch (error) {
@@ -420,63 +391,70 @@ class AniList {
420
391
  }
421
392
  static getTrendingAnime(count) {
422
393
  return __awaiter(this, void 0, void 0, function* () {
423
- var _a, _b, _c, _d, _e;
394
+ var _a, _b, _c, _d, _e, _f, _g;
424
395
  try {
425
- const request = yield fetch(aniListEndpoint, {
426
- method: "POST",
427
- headers: {
428
- "Content-Type": "application/json",
429
- },
430
- body: JSON.stringify({
431
- query: trendingQuery,
432
- variables: { page: 1, perPage: count },
433
- }),
434
- });
435
- const { data, errors } = yield request.json();
436
- if (request.status !== 200 || errors) {
437
- return console.log(`\nSomething went wrong. ${((_a = errors === null || errors === void 0 ? void 0 : errors[0]) === null || _a === void 0 ? void 0 : _a.message) || "Unknown error"}`);
438
- }
439
- const media = (_b = data === null || data === void 0 ? void 0 : data.Page) === null || _b === void 0 ? void 0 : _b.media;
440
- if (!media || media.length === 0) {
441
- return console.log(`\nNo trending available at the moment.`);
442
- }
443
- const { selectedAnime } = yield inquirer.prompt([
444
- {
445
- type: "list",
446
- name: "selectedAnime",
447
- message: "Select anime to add to the list:",
448
- choices: media.map((anime, idx) => ({
449
- name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
450
- value: anime === null || anime === void 0 ? void 0 : anime.id,
451
- })),
452
- pageSize: 10,
453
- },
454
- ]);
455
- const { selectedListType } = yield inquirer.prompt([
456
- {
457
- type: "list",
458
- name: "selectedListType",
459
- message: "Select the list where you want to save this anime:",
460
- choices: [
461
- { name: "Planning", value: "PLANNING" },
462
- { name: "Watching", value: "CURRENT" },
463
- { name: "Completed", value: "COMPLETED" },
464
- { name: "Paused", value: "PAUSED" },
465
- { name: "Dropped", value: "DROPPED" },
466
- ],
467
- },
468
- ]);
469
- if (!(yield Auth.isLoggedIn())) {
470
- return console.error(`\nPlease log in first to use this feature.`);
471
- }
472
- const variables = { mediaId: selectedAnime, status: selectedListType };
473
- const saveResponse = yield fetcher(addAnimeToListMutation, variables);
474
- const saved = (_c = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
475
- if (saved) {
476
- console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
477
- }
478
- else {
479
- console.error(`\nFailed to save the anime. ${((_e = (_d = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.message) || "Unknown error"}`);
396
+ let page = 1;
397
+ let allTrending = [];
398
+ while (true) {
399
+ const response = yield fetcher(trendingQuery, { page, perPage: count });
400
+ if (response === null || response === void 0 ? void 0 : response.errors) {
401
+ console.error(`\nSomething went wrong. ${((_b = (_a = response === null || response === void 0 ? void 0 : response.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) || "Unknown error"}`);
402
+ return;
403
+ }
404
+ const media = (_d = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.media;
405
+ if (!media || media.length === 0) {
406
+ console.log(`\nNo more trending anime available.`);
407
+ break;
408
+ }
409
+ allTrending = [...allTrending, ...media];
410
+ const choices = allTrending.map((anime, idx) => ({
411
+ name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
412
+ value: String(anime === null || anime === void 0 ? void 0 : anime.id),
413
+ }));
414
+ choices.push({ name: "See more", value: "see_more" });
415
+ const { selectedAnime } = yield inquirer.prompt([
416
+ {
417
+ type: "list",
418
+ name: "selectedAnime",
419
+ message: "Select anime to add to the list:",
420
+ choices,
421
+ pageSize: choices.length + 1,
422
+ },
423
+ ]);
424
+ if (selectedAnime === "see_more") {
425
+ page++;
426
+ continue;
427
+ }
428
+ else {
429
+ const { selectedListType } = yield inquirer.prompt([
430
+ {
431
+ type: "list",
432
+ name: "selectedListType",
433
+ message: "Select the list where you want to save this anime:",
434
+ choices: [
435
+ { name: "Planning", value: "PLANNING" },
436
+ { name: "Watching", value: "CURRENT" },
437
+ { name: "Completed", value: "COMPLETED" },
438
+ { name: "Paused", value: "PAUSED" },
439
+ { name: "Dropped", value: "DROPPED" },
440
+ ],
441
+ },
442
+ ]);
443
+ if (!(yield Auth.isLoggedIn())) {
444
+ console.error(`\nPlease log in first to use this feature.`);
445
+ return;
446
+ }
447
+ const variables = { mediaId: selectedAnime, status: selectedListType };
448
+ const saveResponse = yield fetcher(addAnimeToListMutation, variables);
449
+ const saved = (_e = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _e === void 0 ? void 0 : _e.SaveMediaListEntry;
450
+ if (saved) {
451
+ console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
452
+ }
453
+ else {
454
+ console.error(`\nFailed to save the anime. ${((_g = (_f = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.message) || "Unknown error"}`);
455
+ }
456
+ break;
457
+ }
480
458
  }
481
459
  }
482
460
  catch (error) {
@@ -486,63 +464,69 @@ class AniList {
486
464
  }
487
465
  static getPopularAnime(count) {
488
466
  return __awaiter(this, void 0, void 0, function* () {
489
- var _a, _b, _c, _d, _e;
467
+ var _a, _b, _c, _d, _e, _f, _g;
490
468
  try {
491
- const request = yield fetch(aniListEndpoint, {
492
- method: "POST",
493
- headers: {
494
- "Content-Type": "application/json",
495
- },
496
- body: JSON.stringify({
497
- query: popularQuery,
498
- variables: { page: 1, perPage: count },
499
- }),
500
- });
501
- const { data, errors } = yield request.json();
502
- if (request.status !== 200 || errors) {
503
- return console.log(`\nSomething went wrong. ${((_a = errors === null || errors === void 0 ? void 0 : errors[0]) === null || _a === void 0 ? void 0 : _a.message) || "Unknown error"}`);
504
- }
505
- const media = (_b = data === null || data === void 0 ? void 0 : data.Page) === null || _b === void 0 ? void 0 : _b.media;
506
- if (!media || media.length === 0) {
507
- return console.log(`\nNo popular anime available at the moment.`);
508
- }
509
- const { selectedAnime } = yield inquirer.prompt([
510
- {
511
- type: "list",
512
- name: "selectedAnime",
513
- message: "Select anime to add to the list:",
514
- choices: media.map((anime, idx) => ({
515
- name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
516
- value: anime === null || anime === void 0 ? void 0 : anime.id,
517
- })),
518
- pageSize: 10,
519
- },
520
- ]);
521
- const { selectedListType } = yield inquirer.prompt([
522
- {
523
- type: "list",
524
- name: "selectedListType",
525
- message: "Select the list where you want to save this anime:",
526
- choices: [
527
- { name: "Planning", value: "PLANNING" },
528
- { name: "Watching", value: "CURRENT" },
529
- { name: "Completed", value: "COMPLETED" },
530
- { name: "Paused", value: "PAUSED" },
531
- { name: "Dropped", value: "DROPPED" },
532
- ],
533
- },
534
- ]);
535
- if (!(yield Auth.isLoggedIn())) {
536
- return console.error(`\nPlease log in first to use this feature.`);
537
- }
538
- const variables = { mediaId: selectedAnime, status: selectedListType };
539
- const saveResponse = yield fetcher(addAnimeToListMutation, variables);
540
- const saved = (_c = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
541
- if (saved) {
542
- console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
543
- }
544
- else {
545
- console.error(`\nFailed to save the anime. ${((_e = (_d = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.message) || "Unknown error"}`);
469
+ let page = 1;
470
+ let allMedia = [];
471
+ while (true) {
472
+ const response = yield fetcher(popularQuery, { page, perPage: count });
473
+ if (!(response === null || response === void 0 ? void 0 : response.data)) {
474
+ console.error(`\nSomething went wrong. ${((_b = (_a = response === null || response === void 0 ? void 0 : response.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) || "Unknown error"}`);
475
+ return;
476
+ }
477
+ const newMedia = (_d = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.media;
478
+ if (!newMedia || newMedia.length === 0) {
479
+ console.log(`\nNo more popular anime available.`);
480
+ break;
481
+ }
482
+ allMedia = [...allMedia, ...newMedia];
483
+ const choices = allMedia.map((anime, idx) => ({
484
+ name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
485
+ value: String(anime === null || anime === void 0 ? void 0 : anime.id),
486
+ }));
487
+ choices.push({ name: "See more", value: "see_more" });
488
+ const { selectedAnime } = yield inquirer.prompt([
489
+ {
490
+ type: "list",
491
+ name: "selectedAnime",
492
+ message: "Select anime to add to the list:",
493
+ choices,
494
+ pageSize: choices.length,
495
+ },
496
+ ]);
497
+ if (selectedAnime === "see_more") {
498
+ page++;
499
+ continue;
500
+ }
501
+ else {
502
+ const { selectedListType } = yield inquirer.prompt([
503
+ {
504
+ type: "list",
505
+ name: "selectedListType",
506
+ message: "Select the list where you want to save this anime:",
507
+ choices: [
508
+ { name: "Planning", value: "PLANNING" },
509
+ { name: "Watching", value: "CURRENT" },
510
+ { name: "Completed", value: "COMPLETED" },
511
+ { name: "Paused", value: "PAUSED" },
512
+ { name: "Dropped", value: "DROPPED" },
513
+ ],
514
+ },
515
+ ]);
516
+ if (!(yield Auth.isLoggedIn())) {
517
+ return console.error(`\nPlease log in first to use this feature.`);
518
+ }
519
+ const variables = { mediaId: selectedAnime, status: selectedListType };
520
+ const saveResponse = yield fetcher(addAnimeToListMutation, variables);
521
+ const saved = (_e = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _e === void 0 ? void 0 : _e.SaveMediaListEntry;
522
+ if (saved) {
523
+ console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
524
+ }
525
+ else {
526
+ console.error(`\nFailed to save the anime. ${((_g = (_f = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.message) || "Unknown error"}`);
527
+ }
528
+ break;
529
+ }
546
530
  }
547
531
  }
548
532
  catch (error) {
@@ -555,55 +539,72 @@ class AniList {
555
539
  var _a, _b, _c, _d, _e, _f;
556
540
  try {
557
541
  const { nextSeason, nextYear } = getNextSeasonAndYear();
558
- const request = yield fetcher(upcomingAnimesQuery, {
559
- nextSeason,
560
- nextYear,
561
- perPage: count,
562
- });
563
- if (!request || !request.data) {
564
- return console.error(`\nSomething went wrong. ${((_b = (_a = request === null || request === void 0 ? void 0 : request.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) || "Unknown error"}`);
565
- }
566
- const upcoming = (_c = request.data.Page.media) !== null && _c !== void 0 ? _c : [];
567
- if (upcoming.length === 0) {
568
- return console.log(`\nNo upcoming anime available.`);
569
- }
570
- const { selectedAnime } = yield inquirer.prompt([
571
- {
572
- type: "list",
573
- name: "selectedAnime",
574
- message: "Select anime to add to the list:",
575
- choices: upcoming.map((anime, idx) => ({
576
- name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
577
- value: anime === null || anime === void 0 ? void 0 : anime.id,
578
- })),
579
- pageSize: 10,
580
- },
581
- ]);
582
- const { selectedListType } = yield inquirer.prompt([
583
- {
584
- type: "list",
585
- name: "selectedListType",
586
- message: "Select the list where you want to save this anime:",
587
- choices: [
588
- { name: "Planning", value: "PLANNING" },
589
- { name: "Watching", value: "CURRENT" },
590
- { name: "Completed", value: "COMPLETED" },
591
- { name: "Paused", value: "PAUSED" },
592
- { name: "Dropped", value: "DROPPED" },
593
- ],
594
- },
595
- ]);
596
- if (!(yield Auth.isLoggedIn())) {
597
- return console.error(`\nPlease log in first to use this feature.`);
598
- }
599
- const variables = { mediaId: selectedAnime, status: selectedListType };
600
- const saveResponse = yield fetcher(addAnimeToListMutation, variables);
601
- const saved = (_d = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _d === void 0 ? void 0 : _d.SaveMediaListEntry;
602
- if (saved) {
603
- console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
604
- }
605
- else {
606
- console.error(`\nFailed to save the anime. ${((_f = (_e = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.message) || "Unknown error"}`);
542
+ let page = 1;
543
+ let allUpcoming = [];
544
+ while (true) {
545
+ const request = yield fetcher(upcomingAnimesQuery, {
546
+ nextSeason,
547
+ nextYear,
548
+ page,
549
+ perPage: count,
550
+ });
551
+ if (!request || !request.data) {
552
+ console.error(`\nSomething went wrong. ${((_b = (_a = request === null || request === void 0 ? void 0 : request.errors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) || "Unknown error"}`);
553
+ return;
554
+ }
555
+ const newUpcoming = (_c = request.data.Page.media) !== null && _c !== void 0 ? _c : [];
556
+ if (newUpcoming.length === 0) {
557
+ console.log(`\nNo more upcoming anime available.`);
558
+ break;
559
+ }
560
+ allUpcoming = [...allUpcoming, ...newUpcoming];
561
+ const choices = allUpcoming.map((anime, idx) => ({
562
+ name: `[${idx + 1}] ${getTitle(anime === null || anime === void 0 ? void 0 : anime.title)}`,
563
+ value: String(anime === null || anime === void 0 ? void 0 : anime.id),
564
+ }));
565
+ choices.push({ name: "See more", value: "see_more" });
566
+ const { selectedAnime } = yield inquirer.prompt([
567
+ {
568
+ type: "list",
569
+ name: "selectedAnime",
570
+ message: "Select anime to add to the list:",
571
+ choices,
572
+ pageSize: choices.length + 2,
573
+ },
574
+ ]);
575
+ if (selectedAnime === "see_more") {
576
+ page++;
577
+ continue;
578
+ }
579
+ else {
580
+ const { selectedListType } = yield inquirer.prompt([
581
+ {
582
+ type: "list",
583
+ name: "selectedListType",
584
+ message: "Select the list where you want to save this anime:",
585
+ choices: [
586
+ { name: "Planning", value: "PLANNING" },
587
+ { name: "Watching", value: "CURRENT" },
588
+ { name: "Completed", value: "COMPLETED" },
589
+ { name: "Paused", value: "PAUSED" },
590
+ { name: "Dropped", value: "DROPPED" },
591
+ ],
592
+ },
593
+ ]);
594
+ if (!(yield Auth.isLoggedIn())) {
595
+ return console.error(`\nPlease log in first to use this feature.`);
596
+ }
597
+ const variables = { mediaId: selectedAnime, status: selectedListType };
598
+ const saveResponse = yield fetcher(addAnimeToListMutation, variables);
599
+ const saved = (_d = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _d === void 0 ? void 0 : _d.SaveMediaListEntry;
600
+ if (saved) {
601
+ console.log(`\nEntry ${saved.id}. Saved as ${saved.status}.`);
602
+ }
603
+ else {
604
+ console.error(`\nFailed to save the anime. ${((_f = (_e = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.errors) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.message) || "Unknown error"}`);
605
+ }
606
+ break;
607
+ }
607
608
  }
608
609
  }
609
610
  catch (error) {
@@ -613,22 +614,11 @@ class AniList {
613
614
  }
614
615
  static getUserByUsername(username) {
615
616
  return __awaiter(this, void 0, void 0, function* () {
616
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
617
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
617
618
  try {
618
- const headers = {
619
- "Content-Type": "application/json",
620
- };
621
- if (yield Auth.isLoggedIn()) {
622
- headers["Authorization"] = `Bearer ${yield Auth.RetriveAccessToken()}`;
623
- }
624
- const request = yield fetch(aniListEndpoint, {
625
- method: "POST",
626
- headers,
627
- body: JSON.stringify({ query: userQuery, variables: { username } }),
628
- });
629
- const response = yield request.json();
630
- if (request.status !== 200 || !((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
631
- return console.error(`\n${request.status} ${((_c = (_b = response === null || response === void 0 ? void 0 : response.errors) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) || "Unknown error"}`);
619
+ const response = yield fetcher(userQuery, { username });
620
+ if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
621
+ return console.error(`\n${((_c = (_b = response === null || response === void 0 ? void 0 : response.errors) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) || "Unknown error"}`);
632
622
  }
633
623
  const user = response.data.User;
634
624
  const userActivityResponse = yield fetcher(userActivityQuery, {
@@ -637,24 +627,20 @@ class AniList {
637
627
  perPage: 10,
638
628
  });
639
629
  const activities = (_f = (_e = (_d = userActivityResponse === null || userActivityResponse === void 0 ? void 0 : userActivityResponse.data) === null || _d === void 0 ? void 0 : _d.Page) === null || _e === void 0 ? void 0 : _e.activities) !== null && _f !== void 0 ? _f : [];
640
- console.log(`\nID:\t\t${user.id}`);
641
- console.log(`Name:\t\t${user.name}`);
642
- console.log(`Site URL:\t${user.siteUrl}`);
643
- console.log(`Donator Tier:\t${user.donatorTier}`);
644
- console.log(`Donator Badge:\t${user.donatorBadge}`);
645
- console.log(`Account Created:\t${user.createdAt ? new Date(user.createdAt * 1000).toUTCString() : "N/A"}`);
646
- console.log(`Account Updated:\t${user.updatedAt ? new Date(user.updatedAt * 1000).toUTCString() : "N/A"}`);
647
- console.log(`Blocked:\t${user.isBlocked}`);
648
- console.log(`Follower:\t${user.isFollower}`);
649
- console.log(`Following:\t${user.isFollowing}`);
650
- console.log(`Profile Color:\t${(_g = user.options) === null || _g === void 0 ? void 0 : _g.profileColor}`);
651
- console.log(`Timezone:\t${(_h = user.options) === null || _h === void 0 ? void 0 : _h.timezone}`);
652
- console.log(`\nStatistics (Anime)\nCount: ${((_k = (_j = user.statistics) === null || _j === void 0 ? void 0 : _j.anime) === null || _k === void 0 ? void 0 : _k.count) || 0} Episodes Watched: ${((_m = (_l = user.statistics) === null || _l === void 0 ? void 0 : _l.anime) === null || _m === void 0 ? void 0 : _m.episodesWatched) || 0} Minutes Watched: ${((_p = (_o = user.statistics) === null || _o === void 0 ? void 0 : _o.anime) === null || _p === void 0 ? void 0 : _p.minutesWatched) || 0}`);
653
- console.log(`Statistics (Manga)\nCount: ${((_r = (_q = user.statistics) === null || _q === void 0 ? void 0 : _q.manga) === null || _r === void 0 ? void 0 : _r.count) || 0} Chapters Read: ${((_t = (_s = user.statistics) === null || _s === void 0 ? void 0 : _s.manga) === null || _t === void 0 ? void 0 : _t.chaptersRead) || 0} Volumes Read: ${((_v = (_u = user.statistics) === null || _u === void 0 ? void 0 : _u.manga) === null || _v === void 0 ? void 0 : _v.volumesRead) || 0}`);
630
+ // Get follower/following information
631
+ const req_followers = yield fetcher(userFollowersQuery, {
632
+ userId: user === null || user === void 0 ? void 0 : user.id,
633
+ });
634
+ const req_following = yield fetcher(userFollowingQuery, {
635
+ userId: user === null || user === void 0 ? void 0 : user.id,
636
+ });
637
+ const followersCount = ((_j = (_h = (_g = req_followers === null || req_followers === void 0 ? void 0 : req_followers.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.pageInfo) === null || _j === void 0 ? void 0 : _j.total) || 0;
638
+ const followingCount = ((_m = (_l = (_k = req_following === null || req_following === void 0 ? void 0 : req_following.data) === null || _k === void 0 ? void 0 : _k.Page) === null || _l === void 0 ? void 0 : _l.pageInfo) === null || _m === void 0 ? void 0 : _m.total) || 0;
639
+ logUserDetails(user, followersCount, followingCount);
654
640
  if (activities.length > 0) {
655
641
  console.log(`\nRecent Activities:`);
656
- activities.forEach(({ status, progress, media }) => {
657
- console.log(`${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
642
+ activities.forEach(({ status, progress, media, createdAt }) => {
643
+ responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
658
644
  });
659
645
  }
660
646
  else {
@@ -669,9 +655,9 @@ class AniList {
669
655
  static getAnimeDetailsByID(anilistID) {
670
656
  return __awaiter(this, void 0, void 0, function* () {
671
657
  var _a;
672
- const query = animeDetailsQuery;
673
- const variables = { id: anilistID };
674
- const details = yield fetcher(query, variables);
658
+ const details = yield fetcher(animeDetailsQuery, {
659
+ id: anilistID,
660
+ });
675
661
  if ((_a = details === null || details === void 0 ? void 0 : details.data) === null || _a === void 0 ? void 0 : _a.Media) {
676
662
  const { id, title, description, duration, startDate, endDate, countryOfOrigin, isAdult, status, season, format, genres, siteUrl, } = details.data.Media;
677
663
  console.log(`\nID: ${id}`);
@@ -690,12 +676,41 @@ class AniList {
690
676
  }
691
677
  });
692
678
  }
679
+ static getMangaDetailsByID(mangaID) {
680
+ return __awaiter(this, void 0, void 0, function* () {
681
+ var _a;
682
+ try {
683
+ const response = yield fetcher(mangaDetailsQuery, {
684
+ id: mangaID,
685
+ });
686
+ if (response === null || response === void 0 ? void 0 : response.errors) {
687
+ console.error(`${response.errors[0].message}`);
688
+ return;
689
+ }
690
+ const manga = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Media;
691
+ if (manga) {
692
+ console.log(`\n[${getTitle(manga.title)}]`);
693
+ console.log(`${manga.description}`);
694
+ console.log(`Chapters: ${manga.chapters}\t Volumes: ${manga.volumes}`);
695
+ console.log(`Status:\t${manga.status}`);
696
+ console.log(`Genres:\t${manga.genres.join(", ")}`);
697
+ console.log(`Start:\t${simpleDateFormat(manga.startDate)}`);
698
+ console.log(`End:\t${simpleDateFormat(manga.endDate)}`);
699
+ }
700
+ }
701
+ catch (error) {
702
+ console.error(`${error.message}`);
703
+ }
704
+ });
705
+ }
693
706
  static searchAnime(search, count) {
694
707
  return __awaiter(this, void 0, void 0, function* () {
695
708
  var _a, _b, _c;
696
- const query = animeSearchQuery;
697
- const variables = { search, page: 1, perPage: count };
698
- const searchResults = yield fetcher(query, variables);
709
+ const searchResults = yield fetcher(animeSearchQuery, {
710
+ search,
711
+ page: 1,
712
+ perPage: count,
713
+ });
699
714
  if (searchResults) {
700
715
  const results = (_b = (_a = searchResults === null || searchResults === void 0 ? void 0 : searchResults.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
701
716
  if (results.length > 0) {
@@ -727,12 +742,10 @@ class AniList {
727
742
  ]);
728
743
  // Save selected anime to chosen list type
729
744
  if (yield Auth.isLoggedIn()) {
730
- const saveQuery = addAnimeToListMutation;
731
- const saveVariables = {
745
+ const response = yield fetcher(addAnimeToListMutation, {
732
746
  mediaId: selectedAnime,
733
747
  status: selectedListType,
734
- };
735
- const response = yield fetcher(saveQuery, saveVariables);
748
+ });
736
749
  if (response) {
737
750
  const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
738
751
  console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
@@ -754,9 +767,11 @@ class AniList {
754
767
  static searchManga(search, count) {
755
768
  return __awaiter(this, void 0, void 0, function* () {
756
769
  var _a, _b, _c;
757
- const query = mangaSearchQuery;
758
- const variables = { search, page: 1, perPage: count };
759
- const mangaSearchResult = yield fetcher(query, variables);
770
+ const mangaSearchResult = yield fetcher(mangaSearchQuery, {
771
+ search,
772
+ page: 1,
773
+ perPage: count,
774
+ });
760
775
  if (mangaSearchResult) {
761
776
  const results = (_b = (_a = mangaSearchResult === null || mangaSearchResult === void 0 ? void 0 : mangaSearchResult.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
762
777
  // List of manga search results
@@ -789,9 +804,10 @@ class AniList {
789
804
  ]);
790
805
  // If logged in save to the list
791
806
  if (yield Auth.isLoggedIn()) {
792
- const mutation = addMangaToListMutation;
793
- const variables = { mediaId: selectedMangaId, status: selectedListType };
794
- const response = yield fetcher(mutation, variables);
807
+ const response = yield fetcher(addMangaToListMutation, {
808
+ mediaId: selectedMangaId,
809
+ status: selectedListType,
810
+ });
795
811
  if (response) {
796
812
  const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
797
813
  console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
@@ -813,8 +829,15 @@ class MyAnimeList {
813
829
  var _a, _b, _c, _d, _e;
814
830
  try {
815
831
  const filename = yield selectFile(".xml");
832
+ if (!filename) {
833
+ return;
834
+ }
816
835
  const filePath = join(getDownloadFolderPath(), filename);
817
836
  const fileContent = yield readFile(filePath, "utf8");
837
+ if (!(yield Validate.Import_AnimeXML(fileContent))) {
838
+ console.error(`\nInvalid XML file.`);
839
+ return;
840
+ }
818
841
  const parser = new XMLParser();
819
842
  if (fileContent) {
820
843
  const XMLObject = parser.parse(fileContent);
@@ -850,8 +873,6 @@ class MyAnimeList {
850
873
  count++;
851
874
  console.log(`[${count}] ${entryId} ✅`);
852
875
  }
853
- // Rate limit each API call to avoid server overload
854
- yield new Promise((resolve) => setTimeout(resolve, 1100));
855
876
  }
856
877
  else {
857
878
  console.error(`Could not retrieve AniList ID for MAL ID ${malId}`);
@@ -878,8 +899,15 @@ class MyAnimeList {
878
899
  var _a, _b, _c, _d, _e;
879
900
  try {
880
901
  const filename = yield selectFile(".xml");
902
+ if (!filename) {
903
+ return;
904
+ }
881
905
  const filePath = join(getDownloadFolderPath(), filename);
882
906
  const fileContent = yield readFile(filePath, "utf8");
907
+ if (!(yield Validate.Import_MangaXML(fileContent))) {
908
+ console.error(`\nInvalid XML file.`);
909
+ return;
910
+ }
883
911
  const parser = new XMLParser();
884
912
  if (fileContent) {
885
913
  const XMLObject = parser.parse(fileContent);
@@ -950,7 +978,7 @@ class MyAnimeList {
950
978
  if (((_b = (_a = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists.length) > 0) {
951
979
  const lists = (_d = (_c = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _c === void 0 ? void 0 : _c.MediaListCollection) === null || _d === void 0 ? void 0 : _d.lists;
952
980
  const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
953
- var _a, _b, _c, _d, _e;
981
+ var _a, _b, _c, _d, _e, _f;
954
982
  return ({
955
983
  id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
956
984
  malId: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.idMal,
@@ -960,13 +988,10 @@ class MyAnimeList {
960
988
  progress: entry.progress,
961
989
  status: entry === null || entry === void 0 ? void 0 : entry.status,
962
990
  hiddenFromStatusLists: false,
991
+ format: (_f = entry === null || entry === void 0 ? void 0 : entry.media) === null || _f === void 0 ? void 0 : _f.format,
963
992
  });
964
993
  }));
965
- const xmlContent = createAnimeListXML(mediaWithProgress);
966
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(anime)-${getFormattedDate()}.xml`);
967
- yield writeFile(path, yield xmlContent, "utf8");
968
- console.log(`Generated XML for MyAnimeList.`);
969
- open(getDownloadFolderPath());
994
+ yield saveJSONasXML(mediaWithProgress, 0);
970
995
  }
971
996
  else {
972
997
  console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
@@ -991,24 +1016,17 @@ class MyAnimeList {
991
1016
  });
992
1017
  if (mangaList && ((_b = (_a = mangaList === null || mangaList === void 0 ? void 0 : mangaList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists.length) > 0) {
993
1018
  const lists = (_d = (_c = mangaList === null || mangaList === void 0 ? void 0 : mangaList.data) === null || _c === void 0 ? void 0 : _c.MediaListCollection) === null || _d === void 0 ? void 0 : _d.lists;
994
- const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
995
- var _a, _b, _c;
996
- return ({
997
- id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
998
- malId: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.idMal,
999
- title: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
1000
- private: entry.private,
1001
- chapters: entry.media.chapters,
1002
- progress: entry.progress,
1003
- status: entry === null || entry === void 0 ? void 0 : entry.status,
1004
- hiddenFromStatusLists: entry.hiddenFromStatusLists,
1005
- });
1006
- }));
1007
- const XMLContent = createMangaListXML(mediaWithProgress);
1008
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(manga)-${getFormattedDate()}.xml`);
1009
- yield writeFile(path, yield XMLContent, "utf8");
1010
- console.log(`Generated XML for MyAnimeList.`);
1011
- open(getDownloadFolderPath());
1019
+ const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => ({
1020
+ id: entry.media.id,
1021
+ malId: entry.media.idMal,
1022
+ title: entry.media.title,
1023
+ private: entry.private,
1024
+ chapters: entry.media.chapters,
1025
+ progress: entry.progress,
1026
+ status: entry.status,
1027
+ hiddenFromStatusLists: entry.hiddenFromStatusLists,
1028
+ })));
1029
+ yield saveJSONasXML(mediaWithProgress, 1);
1012
1030
  }
1013
1031
  else {
1014
1032
  console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
@@ -1020,4 +1038,97 @@ class MyAnimeList {
1020
1038
  });
1021
1039
  }
1022
1040
  }
1023
- export { AniList, MyAnimeList };
1041
+ class AniDB {
1042
+ static importAnime() {
1043
+ return __awaiter(this, void 0, void 0, function* () {
1044
+ var _a, _b;
1045
+ try {
1046
+ const filename = yield selectFile(".json");
1047
+ if (!filename) {
1048
+ return;
1049
+ }
1050
+ const filePath = join(getDownloadFolderPath(), filename);
1051
+ const fileContent = yield readFile(filePath, "utf8");
1052
+ const js0n_repaired = jsonrepair(fileContent);
1053
+ if (!(yield Validate.Import_AniDBJSONLarge(js0n_repaired))) {
1054
+ console.error(`\nInvalid JSON Large file.`);
1055
+ return;
1056
+ }
1057
+ if (js0n_repaired) {
1058
+ const obj3ct = yield JSON.parse(js0n_repaired);
1059
+ const animeList = obj3ct === null || obj3ct === void 0 ? void 0 : obj3ct.anime;
1060
+ if ((animeList === null || animeList === void 0 ? void 0 : animeList.length) > 0) {
1061
+ let count = 0;
1062
+ let iteration = 0;
1063
+ let missed = [];
1064
+ for (const anime of animeList) {
1065
+ iteration++;
1066
+ const anidbId = anime.id;
1067
+ const released = anime.broadcastDate; // DD-MM-YYYY (eg: "23.07.2016")
1068
+ const status = anime.status;
1069
+ // const type = anime.type
1070
+ const totalEpisodes = anime.totalEpisodes;
1071
+ const ownEpisodes = anime.ownEpisodes;
1072
+ const romanjiName = anime.romanjiName;
1073
+ const englishName = anime.englishName;
1074
+ function getStatus(anidbStatus, episodesSeen) {
1075
+ if (anidbStatus === "complete") {
1076
+ return AniListMediaStatus.COMPLETED;
1077
+ }
1078
+ else if (anidbStatus === "incomplete" &&
1079
+ Number(episodesSeen) > 0) {
1080
+ return AniListMediaStatus.CURRENT;
1081
+ }
1082
+ else {
1083
+ return AniListMediaStatus.PLANNING;
1084
+ }
1085
+ }
1086
+ let anilistId = yield anidbToanilistMapper(romanjiName, Number(released.split(".")[2]), englishName);
1087
+ if (anilistId) {
1088
+ try {
1089
+ const saveResponse = yield fetcher(saveAnimeWithProgressMutation, {
1090
+ mediaId: anilistId,
1091
+ progress: ownEpisodes - 2,
1092
+ status: getStatus(status, ownEpisodes),
1093
+ hiddenFromStatusLists: false,
1094
+ private: false,
1095
+ });
1096
+ const entryId = (_b = (_a = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _a === void 0 ? void 0 : _a.SaveMediaListEntry) === null || _b === void 0 ? void 0 : _b.id;
1097
+ if (entryId) {
1098
+ count++;
1099
+ responsiveOutput(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
1100
+ }
1101
+ }
1102
+ catch (error) {
1103
+ console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
1104
+ }
1105
+ }
1106
+ else {
1107
+ missed.push({
1108
+ anidbId: anidbId,
1109
+ englishTitle: englishName,
1110
+ romajiTitle: romanjiName,
1111
+ });
1112
+ }
1113
+ }
1114
+ responsiveOutput(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
1115
+ if (missed.length > 0) {
1116
+ responsiveOutput(`Exporting missed entries to JSON file, Please add them manually.`);
1117
+ yield saveJSONasJSON(missed, "anidb-missed");
1118
+ }
1119
+ }
1120
+ else {
1121
+ console.log(`\nNo anime list found in the file.`);
1122
+ }
1123
+ }
1124
+ else {
1125
+ console.log(`\nNo content found in the file or unable to read.`);
1126
+ }
1127
+ }
1128
+ catch (error) {
1129
+ console.error(`\nError in AniDB import process: ${error.message}`);
1130
+ }
1131
+ });
1132
+ }
1133
+ }
1134
+ export { AniDB, AniList, MyAnimeList };