@irfanshadikrishad/anilist 1.2.1-forbidden.1 → 1.2.1-forbidden.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -52
- package/bin/helpers/auth.d.ts +14 -3
- package/bin/helpers/auth.js +400 -222
- package/bin/helpers/lists.d.ts +4 -1
- package/bin/helpers/lists.js +247 -114
- package/bin/helpers/queries.d.ts +6 -3
- package/bin/helpers/queries.js +22 -3
- package/bin/helpers/types.d.ts +241 -4
- package/bin/helpers/validation.d.ts +29 -0
- package/bin/helpers/validation.js +117 -0
- package/bin/helpers/workers.d.ts +7 -5
- package/bin/helpers/workers.js +62 -6
- package/bin/index.js +34 -3
- package/package.json +84 -80
- package/assets/binance.jpg +0 -0
package/bin/helpers/lists.d.ts
CHANGED
package/bin/helpers/lists.js
CHANGED
|
@@ -10,21 +10,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { XMLParser } from "fast-xml-parser";
|
|
11
11
|
import { readFile, writeFile } from "fs/promises";
|
|
12
12
|
import inquirer from "inquirer";
|
|
13
|
+
import { jsonrepair } from "jsonrepair";
|
|
14
|
+
import open from "open";
|
|
13
15
|
import { join } from "path";
|
|
14
16
|
import { Auth } from "./auth.js";
|
|
15
17
|
import { fetcher } from "./fetcher.js";
|
|
16
18
|
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";
|
|
19
|
+
import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
|
|
18
20
|
import { AniListMediaStatus, } from "./types.js";
|
|
19
|
-
import {
|
|
21
|
+
import { Validate } from "./validation.js";
|
|
22
|
+
import { anidbToanilistMapper, createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, } from "./workers.js";
|
|
20
23
|
class AniList {
|
|
21
24
|
static importAnime() {
|
|
22
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23
26
|
try {
|
|
24
27
|
const filename = yield selectFile(".json");
|
|
28
|
+
if (!filename) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
25
31
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
26
32
|
const fileContent = yield readFile(filePath, "utf8");
|
|
27
33
|
const importedData = JSON.parse(fileContent);
|
|
34
|
+
if (!Validate.Import_JSON(importedData)) {
|
|
35
|
+
console.error(`\nInvalid JSON file.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
28
38
|
let count = 0;
|
|
29
39
|
const batchSize = 1; // Number of requests in each batch
|
|
30
40
|
const delay = 1100; // delay to avoid rate-limiting
|
|
@@ -68,9 +78,16 @@ class AniList {
|
|
|
68
78
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
79
|
try {
|
|
70
80
|
const filename = yield selectFile(".json");
|
|
81
|
+
if (!filename) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
71
84
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
72
85
|
const fileContent = yield readFile(filePath, "utf8");
|
|
73
86
|
const importedData = JSON.parse(fileContent);
|
|
87
|
+
if (!Validate.Import_JSON(importedData)) {
|
|
88
|
+
console.error(`\nInvalid JSON file.`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
74
91
|
let count = 0;
|
|
75
92
|
const batchSize = 1; // Adjust batch size as per rate-limit constraints
|
|
76
93
|
const delay = 1100; // 2 seconds delay to avoid rate-limit
|
|
@@ -112,7 +129,78 @@ class AniList {
|
|
|
112
129
|
static exportAnime() {
|
|
113
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
114
131
|
var _a, _b, _c;
|
|
115
|
-
if (yield Auth.isLoggedIn()) {
|
|
132
|
+
if (!(yield Auth.isLoggedIn())) {
|
|
133
|
+
console.error(`\nMust login to use this feature.`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const { exportType } = yield inquirer.prompt([
|
|
137
|
+
{
|
|
138
|
+
type: "list",
|
|
139
|
+
name: "exportType",
|
|
140
|
+
message: "Choose export type:",
|
|
141
|
+
choices: [
|
|
142
|
+
{ name: "CSV", value: 1 },
|
|
143
|
+
{ name: "JSON", value: 2 },
|
|
144
|
+
{ name: "XML (MyAnimeList/AniDB)", value: 3 },
|
|
145
|
+
],
|
|
146
|
+
pageSize: 10,
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
const animeList = yield fetcher(currentUserAnimeList, {
|
|
150
|
+
id: yield Auth.MyUserId(),
|
|
151
|
+
});
|
|
152
|
+
if (animeList) {
|
|
153
|
+
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 : [];
|
|
154
|
+
const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
|
|
155
|
+
var _a, _b, _c, _d, _e;
|
|
156
|
+
return ({
|
|
157
|
+
id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
|
|
158
|
+
title: exportType === 1
|
|
159
|
+
? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
|
|
160
|
+
: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
|
|
161
|
+
episodes: (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.episodes,
|
|
162
|
+
siteUrl: (_e = entry === null || entry === void 0 ? void 0 : entry.media) === null || _e === void 0 ? void 0 : _e.siteUrl,
|
|
163
|
+
progress: entry.progress,
|
|
164
|
+
status: entry === null || entry === void 0 ? void 0 : entry.status,
|
|
165
|
+
hiddenFromStatusLists: entry.hiddenFromStatusLists,
|
|
166
|
+
});
|
|
167
|
+
}));
|
|
168
|
+
switch (exportType) {
|
|
169
|
+
case 1:
|
|
170
|
+
yield saveJSONasCSV(mediaWithProgress, "anime");
|
|
171
|
+
break;
|
|
172
|
+
case 2:
|
|
173
|
+
yield saveJSONasJSON(mediaWithProgress, "anime");
|
|
174
|
+
break;
|
|
175
|
+
case 3:
|
|
176
|
+
yield MyAnimeList.exportAnime();
|
|
177
|
+
break;
|
|
178
|
+
default:
|
|
179
|
+
console.log(`\nInvalid export type. ${exportType}`);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.error(`\nNo anime(s) found in your lists.`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
static exportManga() {
|
|
189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
var _a, _b;
|
|
191
|
+
if (!(yield Auth.isLoggedIn())) {
|
|
192
|
+
console.error(`\nPlease login to use this feature.`);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const mangaLists = yield fetcher(currentUserMangaList, {
|
|
196
|
+
id: yield Auth.MyUserId(),
|
|
197
|
+
});
|
|
198
|
+
if (!(mangaLists === null || mangaLists === void 0 ? void 0 : mangaLists.data)) {
|
|
199
|
+
console.error(`\nCould not get manga list.`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
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) || [];
|
|
203
|
+
if (lists.length > 0) {
|
|
116
204
|
const { exportType } = yield inquirer.prompt([
|
|
117
205
|
{
|
|
118
206
|
type: "list",
|
|
@@ -126,111 +214,37 @@ class AniList {
|
|
|
126
214
|
pageSize: 10,
|
|
127
215
|
},
|
|
128
216
|
]);
|
|
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
|
-
|
|
155
|
-
|
|
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.`);
|
|
217
|
+
const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
|
|
218
|
+
var _a, _b, _c;
|
|
219
|
+
return ({
|
|
220
|
+
id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
|
|
221
|
+
title: exportType === 1
|
|
222
|
+
? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
|
|
223
|
+
: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
|
|
224
|
+
private: entry.private,
|
|
225
|
+
chapters: entry.media.chapters,
|
|
226
|
+
progress: entry.progress,
|
|
227
|
+
status: entry === null || entry === void 0 ? void 0 : entry.status,
|
|
228
|
+
hiddenFromStatusLists: entry.hiddenFromStatusLists,
|
|
229
|
+
});
|
|
230
|
+
}));
|
|
231
|
+
switch (exportType) {
|
|
232
|
+
case 1:
|
|
233
|
+
yield saveJSONasCSV(mediaWithProgress, "manga");
|
|
234
|
+
break;
|
|
235
|
+
case 2:
|
|
236
|
+
yield saveJSONasJSON(mediaWithProgress, "manga");
|
|
237
|
+
break;
|
|
238
|
+
case 3:
|
|
239
|
+
yield MyAnimeList.exportManga();
|
|
240
|
+
break;
|
|
241
|
+
default:
|
|
242
|
+
console.log(`\nInvalid export type. ${exportType}`);
|
|
243
|
+
break;
|
|
230
244
|
}
|
|
231
245
|
}
|
|
232
246
|
else {
|
|
233
|
-
console.
|
|
247
|
+
console.log(`\nList seems to be empty.`);
|
|
234
248
|
}
|
|
235
249
|
});
|
|
236
250
|
}
|
|
@@ -241,11 +255,10 @@ class AniList {
|
|
|
241
255
|
if (!(yield Auth.isLoggedIn())) {
|
|
242
256
|
return console.error(`\nPlease log in first to access your lists.`);
|
|
243
257
|
}
|
|
244
|
-
|
|
245
|
-
if (!userId) {
|
|
258
|
+
if (!(yield Auth.MyUserId())) {
|
|
246
259
|
return console.log(`\nFailed getting current user Id.`);
|
|
247
260
|
}
|
|
248
|
-
const data = yield fetcher(currentUserAnimeList, { id:
|
|
261
|
+
const data = yield fetcher(currentUserAnimeList, { id: yield Auth.MyUserId() });
|
|
249
262
|
if (data === null || data === void 0 ? void 0 : data.errors) {
|
|
250
263
|
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
264
|
}
|
|
@@ -612,7 +625,7 @@ class AniList {
|
|
|
612
625
|
}
|
|
613
626
|
static getUserByUsername(username) {
|
|
614
627
|
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;
|
|
628
|
+
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
629
|
try {
|
|
617
630
|
const response = yield fetcher(userQuery, { username });
|
|
618
631
|
if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
|
|
@@ -625,6 +638,15 @@ class AniList {
|
|
|
625
638
|
perPage: 10,
|
|
626
639
|
});
|
|
627
640
|
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 : [];
|
|
641
|
+
// Get follower/following information
|
|
642
|
+
const req_followers = yield fetcher(userFollowersQuery, {
|
|
643
|
+
userId: user === null || user === void 0 ? void 0 : user.id,
|
|
644
|
+
});
|
|
645
|
+
const req_following = yield fetcher(userFollowingQuery, {
|
|
646
|
+
userId: user === null || user === void 0 ? void 0 : user.id,
|
|
647
|
+
});
|
|
648
|
+
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;
|
|
649
|
+
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
650
|
console.log(`\nID:\t\t${user.id}`);
|
|
629
651
|
console.log(`Name:\t\t${user.name}`);
|
|
630
652
|
console.log(`Site URL:\t${user.siteUrl}`);
|
|
@@ -635,10 +657,12 @@ class AniList {
|
|
|
635
657
|
console.log(`Blocked:\t${user.isBlocked}`);
|
|
636
658
|
console.log(`Follower:\t${user.isFollower}`);
|
|
637
659
|
console.log(`Following:\t${user.isFollowing}`);
|
|
638
|
-
console.log(`Profile Color:\t${(
|
|
639
|
-
console.log(`Timezone:\t${(
|
|
640
|
-
console.log(`\
|
|
641
|
-
console.log(`
|
|
660
|
+
console.log(`Profile Color:\t${(_o = user.options) === null || _o === void 0 ? void 0 : _o.profileColor}`);
|
|
661
|
+
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"}`);
|
|
662
|
+
console.log(`\nFollowers:\t${followersCount}`);
|
|
663
|
+
console.log(`Following:\t${followingCount}`);
|
|
664
|
+
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}`);
|
|
665
|
+
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
666
|
if (activities.length > 0) {
|
|
643
667
|
console.log(`\nRecent Activities:`);
|
|
644
668
|
activities.forEach(({ status, progress, media, createdAt }) => {
|
|
@@ -804,8 +828,15 @@ class MyAnimeList {
|
|
|
804
828
|
var _a, _b, _c, _d, _e;
|
|
805
829
|
try {
|
|
806
830
|
const filename = yield selectFile(".xml");
|
|
831
|
+
if (!filename) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
807
834
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
808
835
|
const fileContent = yield readFile(filePath, "utf8");
|
|
836
|
+
if (!(yield Validate.Import_AnimeXML(fileContent))) {
|
|
837
|
+
console.error(`\nInvalid XML file.`);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
809
840
|
const parser = new XMLParser();
|
|
810
841
|
if (fileContent) {
|
|
811
842
|
const XMLObject = parser.parse(fileContent);
|
|
@@ -869,8 +900,15 @@ class MyAnimeList {
|
|
|
869
900
|
var _a, _b, _c, _d, _e;
|
|
870
901
|
try {
|
|
871
902
|
const filename = yield selectFile(".xml");
|
|
903
|
+
if (!filename) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
872
906
|
const filePath = join(getDownloadFolderPath(), filename);
|
|
873
907
|
const fileContent = yield readFile(filePath, "utf8");
|
|
908
|
+
if (!(yield Validate.Import_MangaXML(fileContent))) {
|
|
909
|
+
console.error(`\nInvalid XML file.`);
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
874
912
|
const parser = new XMLParser();
|
|
875
913
|
if (fileContent) {
|
|
876
914
|
const XMLObject = parser.parse(fileContent);
|
|
@@ -1008,4 +1046,99 @@ class MyAnimeList {
|
|
|
1008
1046
|
});
|
|
1009
1047
|
}
|
|
1010
1048
|
}
|
|
1011
|
-
|
|
1049
|
+
class AniDB {
|
|
1050
|
+
static importAnime() {
|
|
1051
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1052
|
+
var _a, _b;
|
|
1053
|
+
try {
|
|
1054
|
+
const filename = yield selectFile(".json");
|
|
1055
|
+
if (!filename) {
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const filePath = join(getDownloadFolderPath(), filename);
|
|
1059
|
+
const fileContent = yield readFile(filePath, "utf8");
|
|
1060
|
+
const js0n_repaired = jsonrepair(fileContent);
|
|
1061
|
+
if (!(yield Validate.Import_AniDBJSONLarge(js0n_repaired))) {
|
|
1062
|
+
console.error(`\nInvalid JSON Large file.`);
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (js0n_repaired) {
|
|
1066
|
+
const obj3ct = yield JSON.parse(js0n_repaired);
|
|
1067
|
+
const animeList = obj3ct === null || obj3ct === void 0 ? void 0 : obj3ct.anime;
|
|
1068
|
+
if ((animeList === null || animeList === void 0 ? void 0 : animeList.length) > 0) {
|
|
1069
|
+
let count = 0;
|
|
1070
|
+
let iteration = 0;
|
|
1071
|
+
let missed = [];
|
|
1072
|
+
for (const anime of animeList) {
|
|
1073
|
+
iteration++;
|
|
1074
|
+
const anidbId = anime.id;
|
|
1075
|
+
const released = anime.broadcastDate; // DD-MM-YYYY (eg: "23.07.2016")
|
|
1076
|
+
const status = anime.status;
|
|
1077
|
+
// const type = anime.type
|
|
1078
|
+
const totalEpisodes = anime.totalEpisodes;
|
|
1079
|
+
const ownEpisodes = anime.ownEpisodes;
|
|
1080
|
+
const romanjiName = anime.romanjiName;
|
|
1081
|
+
const englishName = anime.englishName;
|
|
1082
|
+
function getStatus(anidbStatus, episodesSeen) {
|
|
1083
|
+
if (anidbStatus === "complete") {
|
|
1084
|
+
return AniListMediaStatus.COMPLETED;
|
|
1085
|
+
}
|
|
1086
|
+
else if (anidbStatus === "incomplete" &&
|
|
1087
|
+
Number(episodesSeen) > 0) {
|
|
1088
|
+
return AniListMediaStatus.CURRENT;
|
|
1089
|
+
}
|
|
1090
|
+
else {
|
|
1091
|
+
return AniListMediaStatus.PLANNING;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
let anilistId = yield anidbToanilistMapper(romanjiName, Number(released.split(".")[2]), englishName);
|
|
1095
|
+
if (anilistId) {
|
|
1096
|
+
try {
|
|
1097
|
+
const saveResponse = yield fetcher(saveAnimeWithProgressMutation, {
|
|
1098
|
+
mediaId: anilistId,
|
|
1099
|
+
progress: ownEpisodes - 2,
|
|
1100
|
+
status: getStatus(status, ownEpisodes),
|
|
1101
|
+
hiddenFromStatusLists: false,
|
|
1102
|
+
private: false,
|
|
1103
|
+
});
|
|
1104
|
+
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;
|
|
1105
|
+
if (entryId) {
|
|
1106
|
+
count++;
|
|
1107
|
+
console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
|
|
1108
|
+
}
|
|
1109
|
+
// Rate limit each API call to avoid server overload
|
|
1110
|
+
// await new Promise((resolve) => setTimeout(resolve, 1100))
|
|
1111
|
+
}
|
|
1112
|
+
catch (error) {
|
|
1113
|
+
console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
missed.push({
|
|
1118
|
+
anidbId: anidbId,
|
|
1119
|
+
englishTitle: englishName,
|
|
1120
|
+
romajiTitle: romanjiName,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
console.log(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
|
|
1125
|
+
if (missed.length > 0) {
|
|
1126
|
+
console.log(`Exporting missed entries to JSON file, Please add them manually.`);
|
|
1127
|
+
yield saveJSONasJSON(missed, "anidb-missed");
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
console.log(`\nNo anime list found in the file.`);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
else {
|
|
1135
|
+
console.log(`\nNo content found in the file or unable to read.`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
catch (error) {
|
|
1139
|
+
console.error(`\nError in AniDB import process: ${error.message}`);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
export { AniDB, AniList, MyAnimeList };
|
package/bin/helpers/queries.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaLis
|
|
|
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}";
|
|
@@ -21,5 +21,8 @@ declare const malIdToAnilistAnimeId = "query ($malId: Int) {\n Media(idMal: $ma
|
|
|
21
21
|
declare const malIdToAnilistMangaId = "query ($malId: Int) {\n Media(idMal: $malId, type: MANGA) { id title { romaji english } } }\n";
|
|
22
22
|
declare const followingActivitiesQuery = "\nquery ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(isFollowing: true, sort: ID_DESC) {\n ... on TextActivity { id type isLiked createdAt user { id name } }\n ... on ListActivity { id type isLiked status progress media { title { userPreferred } } createdAt user { id name } }\n ... on MessageActivity { id type isLiked message createdAt recipient { id name } }\n }\n }\n}\n";
|
|
23
23
|
declare const globalActivitiesQuery = "\nquery ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(sort: ID_DESC) {\n ... on TextActivity { id type isLiked createdAt user { id name } }\n ... on ListActivity { id type isLiked status progress media { title { userPreferred } } createdAt user { id name } }\n ... on MessageActivity { id type isLiked message createdAt recipient { id name } }\n }\n }\n}\n";
|
|
24
|
-
declare const specificUserActivitiesQuery = "\nquery ($page: Int, $perPage: Int, $userId: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, sort: ID_DESC) {\n ... on TextActivity { id type isLiked createdAt user { id name } }\n ... on ListActivity { id type isLiked status progress media { title { userPreferred } } createdAt user { id name } }\n ... on MessageActivity { id type isLiked message createdAt recipient { id name } }\n }\n }\n}\n";
|
|
25
|
-
|
|
24
|
+
declare const specificUserActivitiesQuery = "\nquery ($page: Int, $perPage: Int, $userId: Int) {\n Page(page: $page, perPage: $perPage) {\n pageInfo { total perPage currentPage lastPage hasNextPage }\n activities(userId: $userId, sort: ID_DESC) {\n ... on TextActivity { id type isLiked createdAt user { id name } }\n ... on ListActivity { id type isLiked status progress media { title { userPreferred } } createdAt user { id name } }\n ... on MessageActivity { messenger { name } id type isLiked message createdAt recipient { id name } }\n }\n }\n}\n";
|
|
25
|
+
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";
|
|
26
|
+
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";
|
|
27
|
+
declare const toggleFollowMutation = "mutation ($userId: Int!) {\n ToggleFollow(userId: $userId) { id name isFollower isFollowing }\n}\n";
|
|
28
|
+
export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, toggleFollowMutation, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
|
package/bin/helpers/queries.js
CHANGED
|
@@ -66,7 +66,7 @@ const userActivityQuery = `query ($id: Int, $page: Int, $perPage: Int) {
|
|
|
66
66
|
}`;
|
|
67
67
|
const animeSearchQuery = `query ($search: String, $perPage: Int) {
|
|
68
68
|
Page(perPage: $perPage) {
|
|
69
|
-
media(search: $search, type: ANIME) { id title { romaji english native userPreferred } episodes status description }
|
|
69
|
+
media(search: $search, type: ANIME) { id title { romaji english native userPreferred } startDate { day month year } episodes status description }
|
|
70
70
|
}
|
|
71
71
|
}`;
|
|
72
72
|
const mangaSearchQuery = `query ($search: String, $perPage: Int) {
|
|
@@ -150,12 +150,31 @@ query ($page: Int, $perPage: Int) {
|
|
|
150
150
|
const specificUserActivitiesQuery = `
|
|
151
151
|
query ($page: Int, $perPage: Int, $userId: Int) {
|
|
152
152
|
Page(page: $page, perPage: $perPage) {
|
|
153
|
+
pageInfo { total perPage currentPage lastPage hasNextPage }
|
|
153
154
|
activities(userId: $userId, sort: ID_DESC) {
|
|
154
155
|
... on TextActivity { id type isLiked createdAt user { id name } }
|
|
155
156
|
... on ListActivity { id type isLiked status progress media { title { userPreferred } } createdAt user { id name } }
|
|
156
|
-
... on MessageActivity { id type isLiked message createdAt recipient { id name } }
|
|
157
|
+
... on MessageActivity { messenger { name } id type isLiked message createdAt recipient { id name } }
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
`;
|
|
161
|
-
|
|
162
|
+
const userFollowingQuery = `query ($userId: Int!, $page: Int) {
|
|
163
|
+
Page (page: $page) {
|
|
164
|
+
pageInfo { total perPage currentPage lastPage hasNextPage }
|
|
165
|
+
following(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage isFollowing isFollower }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
const userFollowersQuery = `query ($userId: Int!, $page: Int) {
|
|
170
|
+
Page (page: $page) {
|
|
171
|
+
pageInfo { total perPage currentPage lastPage hasNextPage }
|
|
172
|
+
followers(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage isFollowing isFollower }
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
`;
|
|
176
|
+
const toggleFollowMutation = `mutation ($userId: Int!) {
|
|
177
|
+
ToggleFollow(userId: $userId) { id name isFollower isFollowing }
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, toggleFollowMutation, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
|