@irfanshadikrishad/anilist 1.3.0-forbidden.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{LICENSE.md → LICENSE} +115 -124
- package/README.md +79 -53
- package/bin/helpers/auth.d.ts +13 -7
- package/bin/helpers/auth.js +282 -385
- package/bin/helpers/lists.d.ts +5 -1
- package/bin/helpers/lists.js +274 -126
- package/bin/helpers/mutations.d.ts +1 -2
- package/bin/helpers/mutations.js +1 -6
- package/bin/helpers/queries.d.ts +10 -9
- package/bin/helpers/queries.js +27 -30
- package/bin/helpers/types.d.ts +206 -36
- package/bin/helpers/validation.d.ts +29 -0
- package/bin/helpers/validation.js +117 -0
- package/bin/helpers/workers.d.ts +19 -10
- package/bin/helpers/workers.js +92 -28
- package/bin/index.js +30 -6
- package/package.json +20 -16
package/bin/helpers/lists.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ declare class AniList {
|
|
|
10
10
|
static getUpcomingAnime(count: number): Promise<void>;
|
|
11
11
|
static getUserByUsername(username: string): Promise<void>;
|
|
12
12
|
static getAnimeDetailsByID(anilistID: number): Promise<void>;
|
|
13
|
+
static getMangaDetailsByID(mangaID: number): Promise<void>;
|
|
13
14
|
static searchAnime(search: string, count: number): Promise<void>;
|
|
14
15
|
static searchManga(search: string, count: number): Promise<void>;
|
|
15
16
|
}
|
|
@@ -19,4 +20,7 @@ declare class MyAnimeList {
|
|
|
19
20
|
static exportAnime(): Promise<void>;
|
|
20
21
|
static exportManga(): Promise<void>;
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
declare class AniDB {
|
|
24
|
+
static importAnime(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export { AniDB, AniList, MyAnimeList };
|
package/bin/helpers/lists.js
CHANGED
|
@@ -8,23 +8,32 @@ 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
|
|
11
|
+
import { readFile } from "fs/promises";
|
|
12
12
|
import inquirer from "inquirer";
|
|
13
|
+
import { jsonrepair } from "jsonrepair";
|
|
13
14
|
import { join } from "path";
|
|
14
15
|
import { Auth } from "./auth.js";
|
|
15
16
|
import { fetcher } from "./fetcher.js";
|
|
16
17
|
import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, } from "./mutations.js";
|
|
17
|
-
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";
|
|
18
19
|
import { AniListMediaStatus, } from "./types.js";
|
|
19
|
-
import {
|
|
20
|
+
import { Validate } from "./validation.js";
|
|
21
|
+
import { anidbToanilistMapper, formatDateObject, getDownloadFolderPath, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, selectFile, simpleDateFormat, timestampToTimeAgo, } from "./workers.js";
|
|
20
22
|
class AniList {
|
|
21
23
|
static importAnime() {
|
|
22
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23
25
|
try {
|
|
24
26
|
const filename = yield selectFile(".json");
|
|
27
|
+
if (!filename) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
25
30
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
26
31
|
const fileContent = yield readFile(filePath, "utf8");
|
|
27
32
|
const importedData = JSON.parse(fileContent);
|
|
33
|
+
if (!Validate.Import_JSON(importedData)) {
|
|
34
|
+
console.error(`\nInvalid JSON file.`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
28
37
|
let count = 0;
|
|
29
38
|
const batchSize = 1; // Number of requests in each batch
|
|
30
39
|
const delay = 1100; // delay to avoid rate-limiting
|
|
@@ -68,9 +77,16 @@ class AniList {
|
|
|
68
77
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
78
|
try {
|
|
70
79
|
const filename = yield selectFile(".json");
|
|
80
|
+
if (!filename) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
71
83
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
72
84
|
const fileContent = yield readFile(filePath, "utf8");
|
|
73
85
|
const importedData = JSON.parse(fileContent);
|
|
86
|
+
if (!Validate.Import_JSON(importedData)) {
|
|
87
|
+
console.error(`\nInvalid JSON file.`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
74
90
|
let count = 0;
|
|
75
91
|
const batchSize = 1; // Adjust batch size as per rate-limit constraints
|
|
76
92
|
const delay = 1100; // 2 seconds delay to avoid rate-limit
|
|
@@ -112,7 +128,76 @@ class AniList {
|
|
|
112
128
|
static exportAnime() {
|
|
113
129
|
return __awaiter(this, void 0, void 0, function* () {
|
|
114
130
|
var _a, _b, _c;
|
|
115
|
-
if (yield Auth.isLoggedIn()) {
|
|
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,
|
|
146
|
+
},
|
|
147
|
+
]);
|
|
148
|
+
const animeList = yield fetcher(currentUserAnimeList, {
|
|
149
|
+
id: yield Auth.MyUserId(),
|
|
150
|
+
});
|
|
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,
|
|
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;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
console.error(`\nNo anime(s) found in your lists.`);
|
|
182
|
+
}
|
|
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(),
|
|
194
|
+
});
|
|
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) {
|
|
116
201
|
const { exportType } = yield inquirer.prompt([
|
|
117
202
|
{
|
|
118
203
|
type: "list",
|
|
@@ -126,111 +211,35 @@ class AniList {
|
|
|
126
211
|
pageSize: 10,
|
|
127
212
|
},
|
|
128
213
|
]);
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
break;
|
|
155
|
-
case 3:
|
|
156
|
-
yield MyAnimeList.exportAnime();
|
|
157
|
-
break;
|
|
158
|
-
default:
|
|
159
|
-
console.log(`\nInvalid export type. ${exportType}`);
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
console.error(`\nNo anime(s) found in your lists.`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
console.error(`\nMust login to use this feature.`);
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
static exportManga() {
|
|
173
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
var _a, _b;
|
|
175
|
-
if (yield Auth.isLoggedIn()) {
|
|
176
|
-
const mangaLists = yield fetcher(currentUserMangaList, {
|
|
177
|
-
id: yield Auth.MyUserId(),
|
|
178
|
-
});
|
|
179
|
-
if (mangaLists) {
|
|
180
|
-
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) || [];
|
|
181
|
-
if (lists.length > 0) {
|
|
182
|
-
const { exportType } = yield inquirer.prompt([
|
|
183
|
-
{
|
|
184
|
-
type: "list",
|
|
185
|
-
name: "exportType",
|
|
186
|
-
message: "Choose export type:",
|
|
187
|
-
choices: [
|
|
188
|
-
{ name: "CSV", value: 1 },
|
|
189
|
-
{ name: "JSON", value: 2 },
|
|
190
|
-
{ name: "XML (MyAnimeList)", value: 3 },
|
|
191
|
-
],
|
|
192
|
-
pageSize: 10,
|
|
193
|
-
},
|
|
194
|
-
]);
|
|
195
|
-
const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
|
|
196
|
-
var _a, _b, _c;
|
|
197
|
-
return ({
|
|
198
|
-
id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
|
|
199
|
-
title: exportType === 1
|
|
200
|
-
? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
|
|
201
|
-
: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
|
|
202
|
-
private: entry.private,
|
|
203
|
-
chapters: entry.media.chapters,
|
|
204
|
-
progress: entry.progress,
|
|
205
|
-
status: entry === null || entry === void 0 ? void 0 : entry.status,
|
|
206
|
-
hiddenFromStatusLists: entry.hiddenFromStatusLists,
|
|
207
|
-
});
|
|
208
|
-
}));
|
|
209
|
-
switch (exportType) {
|
|
210
|
-
case 1:
|
|
211
|
-
yield saveJSONasCSV(mediaWithProgress, "manga");
|
|
212
|
-
break;
|
|
213
|
-
case 2:
|
|
214
|
-
yield saveJSONasJSON(mediaWithProgress, "manga");
|
|
215
|
-
break;
|
|
216
|
-
case 3:
|
|
217
|
-
yield MyAnimeList.exportManga();
|
|
218
|
-
break;
|
|
219
|
-
default:
|
|
220
|
-
console.log(`\nInvalid export type. ${exportType}`);
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
console.log(`\nList seems to be empty.`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
console.error(`\nCould not get manga list.`);
|
|
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,
|
|
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;
|
|
230
239
|
}
|
|
231
240
|
}
|
|
232
241
|
else {
|
|
233
|
-
console.
|
|
242
|
+
console.log(`\nList seems to be empty.`);
|
|
234
243
|
}
|
|
235
244
|
});
|
|
236
245
|
}
|
|
@@ -241,11 +250,10 @@ class AniList {
|
|
|
241
250
|
if (!(yield Auth.isLoggedIn())) {
|
|
242
251
|
return console.error(`\nPlease log in first to access your lists.`);
|
|
243
252
|
}
|
|
244
|
-
|
|
245
|
-
if (!userId) {
|
|
253
|
+
if (!(yield Auth.MyUserId())) {
|
|
246
254
|
return console.log(`\nFailed getting current user Id.`);
|
|
247
255
|
}
|
|
248
|
-
const data = yield fetcher(currentUserAnimeList, { id:
|
|
256
|
+
const data = yield fetcher(currentUserAnimeList, { id: yield Auth.MyUserId() });
|
|
249
257
|
if (data === null || data === void 0 ? void 0 : data.errors) {
|
|
250
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}`);
|
|
251
259
|
}
|
|
@@ -612,7 +620,7 @@ class AniList {
|
|
|
612
620
|
}
|
|
613
621
|
static getUserByUsername(username) {
|
|
614
622
|
return __awaiter(this, void 0, void 0, function* () {
|
|
615
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
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;
|
|
616
624
|
try {
|
|
617
625
|
const response = yield fetcher(userQuery, { username });
|
|
618
626
|
if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
|
|
@@ -625,6 +633,15 @@ class AniList {
|
|
|
625
633
|
perPage: 10,
|
|
626
634
|
});
|
|
627
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;
|
|
628
645
|
console.log(`\nID:\t\t${user.id}`);
|
|
629
646
|
console.log(`Name:\t\t${user.name}`);
|
|
630
647
|
console.log(`Site URL:\t${user.siteUrl}`);
|
|
@@ -635,10 +652,12 @@ class AniList {
|
|
|
635
652
|
console.log(`Blocked:\t${user.isBlocked}`);
|
|
636
653
|
console.log(`Follower:\t${user.isFollower}`);
|
|
637
654
|
console.log(`Following:\t${user.isFollowing}`);
|
|
638
|
-
console.log(`Profile Color:\t${(
|
|
639
|
-
console.log(`Timezone:\t${(
|
|
640
|
-
console.log(`\
|
|
641
|
-
console.log(`
|
|
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}`);
|
|
642
661
|
if (activities.length > 0) {
|
|
643
662
|
console.log(`\nRecent Activities:`);
|
|
644
663
|
activities.forEach(({ status, progress, media, createdAt }) => {
|
|
@@ -678,6 +697,33 @@ class AniList {
|
|
|
678
697
|
}
|
|
679
698
|
});
|
|
680
699
|
}
|
|
700
|
+
static getMangaDetailsByID(mangaID) {
|
|
701
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
702
|
+
var _a;
|
|
703
|
+
try {
|
|
704
|
+
const response = yield fetcher(mangaDetailsQuery, {
|
|
705
|
+
id: mangaID,
|
|
706
|
+
});
|
|
707
|
+
if (response === null || response === void 0 ? void 0 : response.errors) {
|
|
708
|
+
console.error(`${response.errors[0].message}`);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const manga = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Media;
|
|
712
|
+
if (manga) {
|
|
713
|
+
console.log(`\n[${getTitle(manga.title)}]`);
|
|
714
|
+
console.log(`${manga.description}`);
|
|
715
|
+
console.log(`Chapters: ${manga.chapters}\t Volumes: ${manga.volumes}`);
|
|
716
|
+
console.log(`Status:\t${manga.status}`);
|
|
717
|
+
console.log(`Genres:\t${manga.genres.join(", ")}`);
|
|
718
|
+
console.log(`Start:\t${simpleDateFormat(manga.startDate)}`);
|
|
719
|
+
console.log(`End:\t${simpleDateFormat(manga.endDate)}`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
console.error(`${error.message}`);
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
}
|
|
681
727
|
static searchAnime(search, count) {
|
|
682
728
|
return __awaiter(this, void 0, void 0, function* () {
|
|
683
729
|
var _a, _b, _c;
|
|
@@ -804,8 +850,15 @@ class MyAnimeList {
|
|
|
804
850
|
var _a, _b, _c, _d, _e;
|
|
805
851
|
try {
|
|
806
852
|
const filename = yield selectFile(".xml");
|
|
853
|
+
if (!filename) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
807
856
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
808
857
|
const fileContent = yield readFile(filePath, "utf8");
|
|
858
|
+
if (!(yield Validate.Import_AnimeXML(fileContent))) {
|
|
859
|
+
console.error(`\nInvalid XML file.`);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
809
862
|
const parser = new XMLParser();
|
|
810
863
|
if (fileContent) {
|
|
811
864
|
const XMLObject = parser.parse(fileContent);
|
|
@@ -869,8 +922,15 @@ class MyAnimeList {
|
|
|
869
922
|
var _a, _b, _c, _d, _e;
|
|
870
923
|
try {
|
|
871
924
|
const filename = yield selectFile(".xml");
|
|
925
|
+
if (!filename) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
872
928
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
873
929
|
const fileContent = yield readFile(filePath, "utf8");
|
|
930
|
+
if (!(yield Validate.Import_MangaXML(fileContent))) {
|
|
931
|
+
console.error(`\nInvalid XML file.`);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
874
934
|
const parser = new XMLParser();
|
|
875
935
|
if (fileContent) {
|
|
876
936
|
const XMLObject = parser.parse(fileContent);
|
|
@@ -941,7 +1001,7 @@ class MyAnimeList {
|
|
|
941
1001
|
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) {
|
|
942
1002
|
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;
|
|
943
1003
|
const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
|
|
944
|
-
var _a, _b, _c, _d, _e;
|
|
1004
|
+
var _a, _b, _c, _d, _e, _f;
|
|
945
1005
|
return ({
|
|
946
1006
|
id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
|
|
947
1007
|
malId: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.idMal,
|
|
@@ -951,13 +1011,10 @@ class MyAnimeList {
|
|
|
951
1011
|
progress: entry.progress,
|
|
952
1012
|
status: entry === null || entry === void 0 ? void 0 : entry.status,
|
|
953
1013
|
hiddenFromStatusLists: false,
|
|
1014
|
+
format: (_f = entry === null || entry === void 0 ? void 0 : entry.media) === null || _f === void 0 ? void 0 : _f.format,
|
|
954
1015
|
});
|
|
955
1016
|
}));
|
|
956
|
-
|
|
957
|
-
const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(anime)-${getFormattedDate()}.xml`);
|
|
958
|
-
yield writeFile(path, yield xmlContent, "utf8");
|
|
959
|
-
console.log(`Generated XML for MyAnimeList.`);
|
|
960
|
-
open(getDownloadFolderPath());
|
|
1017
|
+
yield saveJSONasXML(mediaWithProgress, 0);
|
|
961
1018
|
}
|
|
962
1019
|
else {
|
|
963
1020
|
console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
|
|
@@ -992,11 +1049,7 @@ class MyAnimeList {
|
|
|
992
1049
|
status: entry.status,
|
|
993
1050
|
hiddenFromStatusLists: entry.hiddenFromStatusLists,
|
|
994
1051
|
})));
|
|
995
|
-
|
|
996
|
-
const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(manga)-${getFormattedDate()}.xml`);
|
|
997
|
-
yield writeFile(path, yield XMLContent, "utf8");
|
|
998
|
-
console.log(`Generated XML for MyAnimeList.`);
|
|
999
|
-
open(getDownloadFolderPath());
|
|
1052
|
+
yield saveJSONasXML(mediaWithProgress, 1);
|
|
1000
1053
|
}
|
|
1001
1054
|
else {
|
|
1002
1055
|
console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
|
|
@@ -1008,4 +1061,99 @@ class MyAnimeList {
|
|
|
1008
1061
|
});
|
|
1009
1062
|
}
|
|
1010
1063
|
}
|
|
1011
|
-
|
|
1064
|
+
class AniDB {
|
|
1065
|
+
static importAnime() {
|
|
1066
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1067
|
+
var _a, _b;
|
|
1068
|
+
try {
|
|
1069
|
+
const filename = yield selectFile(".json");
|
|
1070
|
+
if (!filename) {
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
const filePath = join(getDownloadFolderPath(), filename);
|
|
1074
|
+
const fileContent = yield readFile(filePath, "utf8");
|
|
1075
|
+
const js0n_repaired = jsonrepair(fileContent);
|
|
1076
|
+
if (!(yield Validate.Import_AniDBJSONLarge(js0n_repaired))) {
|
|
1077
|
+
console.error(`\nInvalid JSON Large file.`);
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
if (js0n_repaired) {
|
|
1081
|
+
const obj3ct = yield JSON.parse(js0n_repaired);
|
|
1082
|
+
const animeList = obj3ct === null || obj3ct === void 0 ? void 0 : obj3ct.anime;
|
|
1083
|
+
if ((animeList === null || animeList === void 0 ? void 0 : animeList.length) > 0) {
|
|
1084
|
+
let count = 0;
|
|
1085
|
+
let iteration = 0;
|
|
1086
|
+
let missed = [];
|
|
1087
|
+
for (const anime of animeList) {
|
|
1088
|
+
iteration++;
|
|
1089
|
+
const anidbId = anime.id;
|
|
1090
|
+
const released = anime.broadcastDate; // DD-MM-YYYY (eg: "23.07.2016")
|
|
1091
|
+
const status = anime.status;
|
|
1092
|
+
// const type = anime.type
|
|
1093
|
+
const totalEpisodes = anime.totalEpisodes;
|
|
1094
|
+
const ownEpisodes = anime.ownEpisodes;
|
|
1095
|
+
const romanjiName = anime.romanjiName;
|
|
1096
|
+
const englishName = anime.englishName;
|
|
1097
|
+
function getStatus(anidbStatus, episodesSeen) {
|
|
1098
|
+
if (anidbStatus === "complete") {
|
|
1099
|
+
return AniListMediaStatus.COMPLETED;
|
|
1100
|
+
}
|
|
1101
|
+
else if (anidbStatus === "incomplete" &&
|
|
1102
|
+
Number(episodesSeen) > 0) {
|
|
1103
|
+
return AniListMediaStatus.CURRENT;
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
return AniListMediaStatus.PLANNING;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
let anilistId = yield anidbToanilistMapper(romanjiName, Number(released.split(".")[2]), englishName);
|
|
1110
|
+
if (anilistId) {
|
|
1111
|
+
try {
|
|
1112
|
+
const saveResponse = yield fetcher(saveAnimeWithProgressMutation, {
|
|
1113
|
+
mediaId: anilistId,
|
|
1114
|
+
progress: ownEpisodes - 2,
|
|
1115
|
+
status: getStatus(status, ownEpisodes),
|
|
1116
|
+
hiddenFromStatusLists: false,
|
|
1117
|
+
private: false,
|
|
1118
|
+
});
|
|
1119
|
+
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;
|
|
1120
|
+
if (entryId) {
|
|
1121
|
+
count++;
|
|
1122
|
+
console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
|
|
1123
|
+
}
|
|
1124
|
+
// Rate limit each API call to avoid server overload
|
|
1125
|
+
// await new Promise((resolve) => setTimeout(resolve, 1100))
|
|
1126
|
+
}
|
|
1127
|
+
catch (error) {
|
|
1128
|
+
console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
missed.push({
|
|
1133
|
+
anidbId: anidbId,
|
|
1134
|
+
englishTitle: englishName,
|
|
1135
|
+
romajiTitle: romanjiName,
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
console.log(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
|
|
1140
|
+
if (missed.length > 0) {
|
|
1141
|
+
console.log(`Exporting missed entries to JSON file, Please add them manually.`);
|
|
1142
|
+
yield saveJSONasJSON(missed, "anidb-missed");
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
else {
|
|
1146
|
+
console.log(`\nNo anime list found in the file.`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
console.log(`\nNo content found in the file or unable to read.`);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
catch (error) {
|
|
1154
|
+
console.error(`\nError in AniDB import process: ${error.message}`);
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
export { AniDB, AniList, MyAnimeList };
|
|
@@ -4,5 +4,4 @@ declare const deleteActivityMutation = "\nmutation($id: Int!) {\n DeleteActivit
|
|
|
4
4
|
declare const saveTextActivityMutation = "\nmutation SaveTextActivity($status: String!) {\n SaveTextActivity(text: $status) { id text userId createdAt }\n}\n";
|
|
5
5
|
declare const saveAnimeWithProgressMutation = "\nmutation ($mediaId: Int, $progress: Int, $status: MediaListStatus, $hiddenFromStatusLists: Boolean) {\n SaveMediaListEntry(mediaId: $mediaId, progress: $progress, status: $status, hiddenFromStatusLists: $hiddenFromStatusLists) {\n id progress hiddenFromStatusLists\n }\n}\n";
|
|
6
6
|
declare const saveMangaWithProgressMutation = "\nmutation ($mediaId: Int, $progress: Int, $status: MediaListStatus, $hiddenFromStatusLists: Boolean, $private: Boolean) {\n SaveMediaListEntry( mediaId: $mediaId, progress: $progress, status: $status, hiddenFromStatusLists: $hiddenFromStatusLists, private: $private\n ) { id progress hiddenFromStatusLists private }\n}\n";
|
|
7
|
-
|
|
8
|
-
export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
|
|
7
|
+
export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
|
package/bin/helpers/mutations.js
CHANGED
|
@@ -35,9 +35,4 @@ mutation ($mediaId: Int, $progress: Int, $status: MediaListStatus, $hiddenFromSt
|
|
|
35
35
|
) { id progress hiddenFromStatusLists private }
|
|
36
36
|
}
|
|
37
37
|
`;
|
|
38
|
-
|
|
39
|
-
mutation($activityId: Int!) {
|
|
40
|
-
ToggleLike(id: $activityId, type: ACTIVITY) { id }
|
|
41
|
-
}
|
|
42
|
-
`;
|
|
43
|
-
export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
|
|
38
|
+
export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
|
package/bin/helpers/queries.d.ts
CHANGED
|
@@ -2,14 +2,14 @@ declare const currentUserQuery = "{\n Viewer {\n id name about bans siteUrl
|
|
|
2
2
|
declare const trendingQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: TRENDING_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
|
|
3
3
|
declare const popularQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: POPULARITY_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
|
|
4
4
|
declare const userQuery = "query ($username: String) {\n User(name: $username) {\n id name siteUrl donatorTier donatorBadge createdAt updatedAt previousNames { name createdAt updatedAt }\n isBlocked isFollower isFollowing options { profileColor timezone activityMergeTime }\n statistics { anime { count episodesWatched minutesWatched } manga { count chaptersRead volumesRead } }\n }\n}";
|
|
5
|
-
declare const currentUserAnimeList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english } status episodes siteUrl } } }\n }\n}\n";
|
|
6
|
-
declare const currentUserMangaList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english } status chapters } } }\n }\n}\n";
|
|
5
|
+
declare const currentUserAnimeList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english native userPreferred } status episodes siteUrl format } } }\n }\n}\n";
|
|
6
|
+
declare const currentUserMangaList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english native userPreferred } status chapters } } }\n }\n}\n";
|
|
7
7
|
declare const deleteMediaEntryMutation = "mutation($id: Int!) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
|
|
8
8
|
declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
|
|
9
9
|
declare const upcomingAnimesQuery = "query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {\n Page(perPage: $perPage) {\n media(season: $nextSeason, seasonYear: $nextYear, type: ANIME, sort: POPULARITY_DESC) {\n id title { romaji english native userPreferred } season seasonYear startDate { year month day }\n episodes description genres\n }\n }\n}";
|
|
10
10
|
declare const animeDetailsQuery = "query ($id: Int) {\n Media(id: $id) {\n id idMal title { romaji english native userPreferred } episodes nextAiringEpisode { id }\n duration startDate { year month day } endDate { year month day } countryOfOrigin description isAdult status season format genres siteUrl\n stats { scoreDistribution { score amount } statusDistribution { status amount } }\n }\n}";
|
|
11
11
|
declare const userActivityQuery = "query ($id: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $id, type_in: [ANIME_LIST, MANGA_LIST], sort: ID_DESC) {\n ... on ListActivity { id status progress createdAt media { id title { romaji english } } }\n }\n }\n}";
|
|
12
|
-
declare const animeSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: ANIME) { id title { romaji english native userPreferred } episodes status description }\n }\n}";
|
|
12
|
+
declare const animeSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: ANIME) { id title { romaji english native userPreferred } startDate { day month year } episodes status description }\n }\n}";
|
|
13
13
|
declare const mangaSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: MANGA) { id title { romaji english native userPreferred } chapters status description }\n }\n}";
|
|
14
14
|
declare const activityTextQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: TEXT, sort: ID_DESC) {\n ... on TextActivity { id type text createdAt user { id name } }\n }\n }\n}";
|
|
15
15
|
declare const activityAnimeListQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: ANIME_LIST, sort: ID_DESC) {\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n }\n }\n}";
|
|
@@ -17,9 +17,10 @@ declare const activityMangaListQuery = "query ($userId: Int, $page: Int, $perPag
|
|
|
17
17
|
declare const activityMessageQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: MESSAGE, sort: ID_DESC) {\n ... on MessageActivity { id type message recipient { id name } createdAt }\n }\n }\n}";
|
|
18
18
|
declare const activityAllQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, sort: ID_DESC) {\n ... on TextActivity { id type text createdAt user { id name } }\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n ... on MessageActivity { id type message recipient { id name } createdAt }\n }\n }\n}";
|
|
19
19
|
declare const activityMediaList = "query ($userId: Int, $page: Int, $perPage: Int, $type: ActivityType) {\n Page(page: $page, perPage: $perPage) {\n pageInfo { total currentPage lastPage hasNextPage perPage }\n activities(userId: $userId, type: $type, sort: ID_DESC) {\n ... on ListActivity { id type status progress media { id title { romaji english native } format } createdAt }\n }\n }\n}";
|
|
20
|
-
declare const malIdToAnilistAnimeId = "query ($malId: Int) {\n Media(idMal: $malId, type: ANIME) {
|
|
21
|
-
declare const malIdToAnilistMangaId = "query ($malId: Int) {\n Media(idMal: $malId, type: MANGA) {
|
|
22
|
-
declare const
|
|
23
|
-
declare const
|
|
24
|
-
declare const
|
|
25
|
-
|
|
20
|
+
declare const malIdToAnilistAnimeId = "query ($malId: Int) {\n Media(idMal: $malId, type: ANIME) {\n id title { romaji english } } \n}\n";
|
|
21
|
+
declare const malIdToAnilistMangaId = "query ($malId: Int) {\n Media(idMal: $malId, type: MANGA) {\n id title { romaji english } } \n}\n";
|
|
22
|
+
declare const userFollowingQuery = "query ($userId: Int!, $page: Int) {\n Page (page: $page) {\n pageInfo { total perPage currentPage lastPage hasNextPage }\n following(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage isFollowing isFollower }\n }\n}\n";
|
|
23
|
+
declare const userFollowersQuery = "query ($userId: Int!, $page: Int) {\n Page (page: $page) {\n pageInfo { total perPage currentPage lastPage hasNextPage }\n followers(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage isFollowing isFollower }\n }\n}\n";
|
|
24
|
+
declare const toggleFollowMutation = "mutation ($userId: Int!) {\n ToggleFollow(userId: $userId) { id name isFollower isFollowing }\n}\n";
|
|
25
|
+
declare const mangaDetailsQuery = "query ($id: Int) {\n Media(id: $id, type: MANGA) {\n id title { romaji english native userPreferred } coverImage { color medium large extraLarge } \n bannerImage description chapters volumes status genres\n startDate { year month day } endDate { year month day }\n }\n}\n";
|
|
26
|
+
export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, toggleFollowMutation, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
|