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