@irfanshadikrishad/anilist 1.0.0-forbidden.6 → 1.0.0-forbidden.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { MediaTitle } from "./types.js";
1
+ import { MediaTitle, User } from "./types.js";
2
2
  declare class Auth {
3
3
  /**
4
4
  * Get access-token from user
@@ -7,35 +7,7 @@ declare class Auth {
7
7
  static StoreAccessToken(token: string): Promise<void>;
8
8
  static RetriveAccessToken(): Promise<string | null>;
9
9
  static Login(clientId: number, clientSecret: string): Promise<void>;
10
- static Myself(): Promise<{
11
- id: number;
12
- name: string;
13
- siteUrl: string;
14
- options: {
15
- profileColor: string;
16
- timezone: string;
17
- activityMergeTime: string;
18
- };
19
- donatorTier: string;
20
- donatorBadge: string;
21
- unreadNotificationCount: number;
22
- createdAt: number;
23
- updatedAt: number;
24
- statistics: {
25
- anime: {
26
- count: number;
27
- meanScore: string;
28
- minutesWatched: string;
29
- episodesWatched: number;
30
- };
31
- manga: {
32
- count: number;
33
- meanScore: string;
34
- chaptersRead: number;
35
- volumesRead: number;
36
- };
37
- };
38
- }>;
10
+ static Myself(): Promise<User>;
39
11
  static isLoggedIn(): Promise<boolean>;
40
12
  static Logout(): Promise<void>;
41
13
  static MyUserId(): Promise<number>;
@@ -7,6 +7,7 @@ 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 { Cipher } from "@irfanshadikrishad/cipher";
10
11
  import fs from "fs";
11
12
  import inquirer from "inquirer";
12
13
  import fetch from "node-fetch";
@@ -17,13 +18,14 @@ import { exit } from "process";
17
18
  import Spinner from "tiny-spinner";
18
19
  import { fetcher } from "./fetcher.js";
19
20
  import { AniDB, AniList, MyAnimeList } from "./lists.js";
20
- import { deleteActivityMutation, likeActivityMutation, saveTextActivityMutation, } from "./mutations.js";
21
- import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, followingActivitiesQuery, globalActivitiesQuery, specificUserActivitiesQuery, toggleFollowMutation, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
21
+ import { deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, likeActivityMutation, saveTextActivityMutation, toggleFollowMutation, } from "./mutations.js";
22
+ import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, followingActivitiesQuery, globalActivitiesQuery, specificUserActivitiesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
22
23
  import { responsiveOutput } from "./truncate.js";
23
24
  import { activityBy, aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from "./workers.js";
24
25
  const home_dir = os.homedir();
25
26
  const save_path = path.join(home_dir, ".anilist_token");
26
27
  const spinner = new Spinner();
28
+ const vigenere = new Cipher.Vigenere("anilist");
27
29
  class Auth {
28
30
  /**
29
31
  * Get access-token from user
@@ -57,7 +59,7 @@ class Auth {
57
59
  console.warn("\nNo token provided. Nothing to store.");
58
60
  return;
59
61
  }
60
- fs.writeFileSync(save_path, token, { encoding: "utf8" });
62
+ fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: "utf8" });
61
63
  }
62
64
  catch (error) {
63
65
  console.error(`\nError storing access token: ${error.message}`);
@@ -68,7 +70,7 @@ class Auth {
68
70
  return __awaiter(this, void 0, void 0, function* () {
69
71
  try {
70
72
  if (fs.existsSync(save_path)) {
71
- return fs.readFileSync(save_path, { encoding: "utf8" });
73
+ return vigenere.decrypt(fs.readFileSync(save_path, { encoding: "utf8" }));
72
74
  }
73
75
  else {
74
76
  return null;
@@ -153,33 +155,33 @@ class Auth {
153
155
  });
154
156
  const followersCount = ((_e = (_d = (_c = req_followers === null || req_followers === void 0 ? void 0 : req_followers.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.pageInfo) === null || _e === void 0 ? void 0 : _e.total) || 0;
155
157
  const followingCount = ((_h = (_g = (_f = req_following === null || req_following === void 0 ? void 0 : req_following.data) === null || _f === void 0 ? void 0 : _f.Page) === null || _g === void 0 ? void 0 : _g.pageInfo) === null || _h === void 0 ? void 0 : _h.total) || 0;
156
- console.log(`
157
- ID: ${user === null || user === void 0 ? void 0 : user.id}
158
- Name: ${user === null || user === void 0 ? void 0 : user.name}
159
- siteUrl: ${user === null || user === void 0 ? void 0 : user.siteUrl}
160
- profileColor: ${(_j = user === null || user === void 0 ? void 0 : user.options) === null || _j === void 0 ? void 0 : _j.profileColor}
161
- timeZone: ${(_k = user === null || user === void 0 ? void 0 : user.options) === null || _k === void 0 ? void 0 : _k.timezone}
162
- activityMergeTime: ${(_l = user === null || user === void 0 ? void 0 : user.options) === null || _l === void 0 ? void 0 : _l.activityMergeTime}
163
- donatorTier: ${user === null || user === void 0 ? void 0 : user.donatorTier}
164
- donatorBadge: ${user === null || user === void 0 ? void 0 : user.donatorBadge}
165
- unreadNotificationCount:${user === null || user === void 0 ? void 0 : user.unreadNotificationCount}
166
- Account Created: ${new Date((user === null || user === void 0 ? void 0 : user.createdAt) * 1000).toUTCString()}
167
- Account Updated: ${new Date((user === null || user === void 0 ? void 0 : user.updatedAt) * 1000).toUTCString()}
168
-
169
- Followers: ${followersCount}
170
- Following: ${followingCount}
171
-
172
- Statistics (Anime):
173
- Count: ${(_o = (_m = user === null || user === void 0 ? void 0 : user.statistics) === null || _m === void 0 ? void 0 : _m.anime) === null || _o === void 0 ? void 0 : _o.count}
174
- Mean Score: ${(_q = (_p = user === null || user === void 0 ? void 0 : user.statistics) === null || _p === void 0 ? void 0 : _p.anime) === null || _q === void 0 ? void 0 : _q.meanScore}
175
- Minutes Watched: ${(_s = (_r = user === null || user === void 0 ? void 0 : user.statistics) === null || _r === void 0 ? void 0 : _r.anime) === null || _s === void 0 ? void 0 : _s.minutesWatched}
176
- Episodes Watched: ${(_u = (_t = user === null || user === void 0 ? void 0 : user.statistics) === null || _t === void 0 ? void 0 : _t.anime) === null || _u === void 0 ? void 0 : _u.episodesWatched}
177
-
178
- Statistics (Manga):
179
- Count: ${(_w = (_v = user === null || user === void 0 ? void 0 : user.statistics) === null || _v === void 0 ? void 0 : _v.manga) === null || _w === void 0 ? void 0 : _w.count}
180
- Mean Score: ${(_y = (_x = user === null || user === void 0 ? void 0 : user.statistics) === null || _x === void 0 ? void 0 : _x.manga) === null || _y === void 0 ? void 0 : _y.meanScore}
181
- Chapters Read: ${(_0 = (_z = user === null || user === void 0 ? void 0 : user.statistics) === null || _z === void 0 ? void 0 : _z.manga) === null || _0 === void 0 ? void 0 : _0.chaptersRead}
182
- Volumes Read: ${(_2 = (_1 = user === null || user === void 0 ? void 0 : user.statistics) === null || _1 === void 0 ? void 0 : _1.manga) === null || _2 === void 0 ? void 0 : _2.volumesRead}
158
+ console.log(`
159
+ ID: ${user === null || user === void 0 ? void 0 : user.id}
160
+ Name: ${user === null || user === void 0 ? void 0 : user.name}
161
+ siteUrl: ${user === null || user === void 0 ? void 0 : user.siteUrl}
162
+ profileColor: ${(_j = user === null || user === void 0 ? void 0 : user.options) === null || _j === void 0 ? void 0 : _j.profileColor}
163
+ timeZone: ${(_k = user === null || user === void 0 ? void 0 : user.options) === null || _k === void 0 ? void 0 : _k.timezone}
164
+ activityMergeTime: ${(_l = user === null || user === void 0 ? void 0 : user.options) === null || _l === void 0 ? void 0 : _l.activityMergeTime}
165
+ donatorTier: ${user === null || user === void 0 ? void 0 : user.donatorTier}
166
+ donatorBadge: ${user === null || user === void 0 ? void 0 : user.donatorBadge}
167
+ unreadNotificationCount:${user === null || user === void 0 ? void 0 : user.unreadNotificationCount}
168
+ Account Created: ${new Date((user === null || user === void 0 ? void 0 : user.createdAt) * 1000).toUTCString()}
169
+ Account Updated: ${new Date((user === null || user === void 0 ? void 0 : user.updatedAt) * 1000).toUTCString()}
170
+
171
+ Followers: ${followersCount}
172
+ Following: ${followingCount}
173
+
174
+ Statistics (Anime):
175
+ Count: ${(_o = (_m = user === null || user === void 0 ? void 0 : user.statistics) === null || _m === void 0 ? void 0 : _m.anime) === null || _o === void 0 ? void 0 : _o.count}
176
+ Mean Score: ${(_q = (_p = user === null || user === void 0 ? void 0 : user.statistics) === null || _p === void 0 ? void 0 : _p.anime) === null || _q === void 0 ? void 0 : _q.meanScore}
177
+ Minutes Watched: ${(_s = (_r = user === null || user === void 0 ? void 0 : user.statistics) === null || _r === void 0 ? void 0 : _r.anime) === null || _s === void 0 ? void 0 : _s.minutesWatched}
178
+ Episodes Watched: ${(_u = (_t = user === null || user === void 0 ? void 0 : user.statistics) === null || _t === void 0 ? void 0 : _t.anime) === null || _u === void 0 ? void 0 : _u.episodesWatched}
179
+
180
+ Statistics (Manga):
181
+ Count: ${(_w = (_v = user === null || user === void 0 ? void 0 : user.statistics) === null || _v === void 0 ? void 0 : _v.manga) === null || _w === void 0 ? void 0 : _w.count}
182
+ Mean Score: ${(_y = (_x = user === null || user === void 0 ? void 0 : user.statistics) === null || _x === void 0 ? void 0 : _x.manga) === null || _y === void 0 ? void 0 : _y.meanScore}
183
+ Chapters Read: ${(_0 = (_z = user === null || user === void 0 ? void 0 : user.statistics) === null || _z === void 0 ? void 0 : _z.manga) === null || _0 === void 0 ? void 0 : _0.chaptersRead}
184
+ Volumes Read: ${(_2 = (_1 = user === null || user === void 0 ? void 0 : user.statistics) === null || _1 === void 0 ? void 0 : _1.manga) === null || _2 === void 0 ? void 0 : _2.volumesRead}
183
185
  `);
184
186
  console.log(`\nRecent Activities:`);
185
187
  if (activities.length > 0) {
@@ -764,7 +766,9 @@ Statistics (Manga):
764
766
  let hasNextPage = true;
765
767
  let page = 1;
766
768
  let liked = 0;
769
+ // ------------------------
767
770
  // Fetch all following users
771
+ // ------------------------
768
772
  spinner.start(`Gathering following information...`);
769
773
  while (hasNextPage) {
770
774
  spinner.update(`Fetched page ${page}...`);
@@ -783,10 +787,28 @@ Statistics (Manga):
783
787
  spinner.stop(`Got ${allFollowingUsers.length} following user.`);
784
788
  // Extract the IDs of all following users
785
789
  const followingUserIds = allFollowingUsers.map((user) => user.id);
786
- console.log(`\nTotal Following: ${followingUserIds.length}\nApproximately ${followingUserIds.length * perPage} activities to like.\nWill take around ${((followingUserIds.length * perPage * 1200) /
787
- 1000 /
788
- 60).toFixed(2)} minutes.`);
789
- // Traverse the array and fetch users' activities one by one
790
+ // --------------------
791
+ // APPROXIMATE TIME
792
+ // --------------------
793
+ const totalActivities = followingUserIds.length * perPage;
794
+ const perActivityTimeInSec = 1;
795
+ const rateLimitTimeInSec = 60;
796
+ const batchSize = 29;
797
+ const batches = Math.floor(totalActivities / batchSize);
798
+ const remaining = totalActivities % batchSize;
799
+ const processingTime = batches * batchSize * perActivityTimeInSec +
800
+ remaining * perActivityTimeInSec;
801
+ const waitTime = (batches - 1) * rateLimitTimeInSec;
802
+ const totalWaitTimeInSec = processingTime + (batches > 0 ? waitTime : 0);
803
+ const hours = Math.floor(totalWaitTimeInSec / 3600);
804
+ const minutes = Math.floor((totalWaitTimeInSec % 3600) / 60);
805
+ const seconds = totalWaitTimeInSec % 60;
806
+ const time = `${String(hours).padStart(2, "0")}h ${String(minutes).padStart(2, "0")}m ${String(seconds).padStart(2, "0")}s`;
807
+ console.log(`\nTotal following: ${followingUserIds.length}\nApproximately ${totalActivities} to like.\nWill take around ${time}`);
808
+ // -------------------
809
+ // Traverse the array and
810
+ // fetch users' activities one by one
811
+ // -------------------
790
812
  let userNumber = 0;
791
813
  for (const userId of followingUserIds) {
792
814
  userNumber++;
@@ -845,9 +867,10 @@ Statistics (Manga):
845
867
  name: "activityType",
846
868
  message: "Select activity type:",
847
869
  choices: [
848
- { name: "Following", value: 1 },
849
- { name: "Global", value: 2 },
850
- { name: "Specific User", value: 3 },
870
+ { name: "Following • v1", value: 1 },
871
+ { name: "Following • v2", value: 2 },
872
+ { name: "Global", value: 3 },
873
+ { name: "Specific User", value: 4 },
851
874
  ],
852
875
  pageSize: 10,
853
876
  },
@@ -856,10 +879,21 @@ Statistics (Manga):
856
879
  case 1:
857
880
  yield this.LikeFollowing();
858
881
  break;
859
- case 2:
860
- yield this.LikeGlobal();
882
+ case 2: {
883
+ const { count } = yield inquirer.prompt([
884
+ {
885
+ type: "number",
886
+ name: "count",
887
+ message: "Likes to give:",
888
+ },
889
+ ]);
890
+ yield this.LikeFollowingActivityV2(count);
861
891
  break;
892
+ }
862
893
  case 3:
894
+ yield this.LikeGlobal();
895
+ break;
896
+ case 4:
863
897
  yield this.LikeSpecificUser();
864
898
  break;
865
899
  default:
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import fetch from "node-fetch";
11
11
  import { Auth } from "./auth.js";
12
- import { aniListEndpoint } from "./workers.js";
12
+ import { aniListEndpoint, handleRateLimitRetry } from "./workers.js";
13
13
  /**
14
14
  * Sends a GraphQL request to the AniList API.
15
15
  *
@@ -28,9 +28,11 @@ function fetcher(query, variables) {
28
28
  const headers = {
29
29
  "content-type": "application/json",
30
30
  };
31
- if (yield Auth.isLoggedIn()) {
32
- headers["Authorization"] = `Bearer ${yield Auth.RetriveAccessToken()}`;
33
- }
31
+ const token = (yield Auth.isLoggedIn())
32
+ ? yield Auth.RetriveAccessToken()
33
+ : null;
34
+ if (token)
35
+ headers["Authorization"] = `Bearer ${token}`;
34
36
  const request = yield fetch(aniListEndpoint, {
35
37
  method: "POST",
36
38
  headers: headers,
@@ -41,9 +43,8 @@ function fetcher(query, variables) {
41
43
  return response;
42
44
  }
43
45
  else if (request.status === 429) {
44
- console.warn("Rate limit reached. Retrying in 1 minute...");
45
- yield new Promise((resolve) => setTimeout(resolve, 60000)); // Wait for 1 minute
46
- return yield fetcher(query, variables); // Retry the request
46
+ yield handleRateLimitRetry(60);
47
+ return yield fetcher(query, variables);
47
48
  }
48
49
  else {
49
50
  console.error(`\n${request.status} ${((_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"}.`);
@@ -19,7 +19,7 @@ import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserM
19
19
  import { responsiveOutput } from "./truncate.js";
20
20
  import { AniListMediaStatus, } from "./types.js";
21
21
  import { Validate } from "./validation.js";
22
- import { anidbToanilistMapper, formatDateObject, getDownloadFolderPath, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, selectFile, simpleDateFormat, timestampToTimeAgo, } from "./workers.js";
22
+ import { anidbToanilistMapper, formatDateObject, getDownloadFolderPath, getNextSeasonAndYear, getTitle, logUserDetails, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, selectFile, simpleDateFormat, timestampToTimeAgo, } from "./workers.js";
23
23
  class AniList {
24
24
  static importAnime() {
25
25
  return __awaiter(this, void 0, void 0, function* () {
@@ -36,8 +36,7 @@ class AniList {
36
36
  return;
37
37
  }
38
38
  let count = 0;
39
- const batchSize = 1; // Number of requests in each batch
40
- const delay = 1100; // delay to avoid rate-limiting
39
+ const batchSize = 1;
41
40
  for (let i = 0; i < importedData.length; i += batchSize) {
42
41
  const batch = importedData.slice(i, i + batchSize);
43
42
  yield Promise.all(batch.map((anime) => __awaiter(this, void 0, void 0, function* () {
@@ -64,8 +63,6 @@ class AniList {
64
63
  console.error(`\nError saving ${anime === null || anime === void 0 ? void 0 : anime.id}: ${error.message}`);
65
64
  }
66
65
  })));
67
- // Avoid rate-limiting: Wait before sending the next batch
68
- yield new Promise((resolve) => setTimeout(resolve, delay));
69
66
  }
70
67
  console.log(`\nTotal ${count} anime(s) imported successfully.`);
71
68
  }
@@ -89,9 +86,7 @@ class AniList {
89
86
  return;
90
87
  }
91
88
  let count = 0;
92
- const batchSize = 1; // Adjust batch size as per rate-limit constraints
93
- const delay = 1100; // 2 seconds delay to avoid rate-limit
94
- // Process in batches
89
+ const batchSize = 1;
95
90
  for (let i = 0; i < importedData.length; i += batchSize) {
96
91
  const batch = importedData.slice(i, i + batchSize);
97
92
  yield Promise.all(batch.map((manga) => __awaiter(this, void 0, void 0, function* () {
@@ -116,8 +111,6 @@ class AniList {
116
111
  console.error(`\nError saving ${manga === null || manga === void 0 ? void 0 : manga.id}: ${err.message}`);
117
112
  }
118
113
  })));
119
- // Avoid rate-limit by adding delay after processing each batch
120
- yield new Promise((resolve) => setTimeout(resolve, delay));
121
114
  }
122
115
  console.log(`\nTotal ${count} manga(s) imported successfully.`);
123
116
  }
@@ -621,7 +614,7 @@ class AniList {
621
614
  }
622
615
  static getUserByUsername(username) {
623
616
  return __awaiter(this, void 0, void 0, function* () {
624
- 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;
617
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
625
618
  try {
626
619
  const response = yield fetcher(userQuery, { username });
627
620
  if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
@@ -643,22 +636,7 @@ class AniList {
643
636
  });
644
637
  const followersCount = ((_j = (_h = (_g = req_followers === null || req_followers === void 0 ? void 0 : req_followers.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.pageInfo) === null || _j === void 0 ? void 0 : _j.total) || 0;
645
638
  const followingCount = ((_m = (_l = (_k = req_following === null || req_following === void 0 ? void 0 : req_following.data) === null || _k === void 0 ? void 0 : _k.Page) === null || _l === void 0 ? void 0 : _l.pageInfo) === null || _m === void 0 ? void 0 : _m.total) || 0;
646
- console.log(`\nID:\t\t${user.id}`);
647
- console.log(`Name:\t\t${user.name}`);
648
- console.log(`Site URL:\t${user.siteUrl}`);
649
- console.log(`Donator Tier:\t${user.donatorTier}`);
650
- console.log(`Donator Badge:\t${user.donatorBadge}`);
651
- console.log(`Account Created:\t${user.createdAt ? new Date(user.createdAt * 1000).toUTCString() : "N/A"}`);
652
- console.log(`Account Updated:\t${user.updatedAt ? new Date(user.updatedAt * 1000).toUTCString() : "N/A"}`);
653
- console.log(`Blocked:\t${user.isBlocked}`);
654
- console.log(`Follower:\t${user.isFollower}`);
655
- console.log(`Following:\t${user.isFollowing}`);
656
- console.log(`Profile Color:\t${(_o = user.options) === null || _o === void 0 ? void 0 : _o.profileColor}`);
657
- 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"}`);
658
- console.log(`\nFollowers:\t${followersCount}`);
659
- console.log(`Following:\t${followingCount}`);
660
- 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}`);
661
- 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}`);
639
+ logUserDetails(user, followersCount, followingCount);
662
640
  if (activities.length > 0) {
663
641
  console.log(`\nRecent Activities:`);
664
642
  activities.forEach(({ status, progress, media, createdAt }) => {
@@ -895,8 +873,6 @@ class MyAnimeList {
895
873
  count++;
896
874
  console.log(`[${count}] ${entryId} āœ…`);
897
875
  }
898
- // Rate limit each API call to avoid server overload
899
- yield new Promise((resolve) => setTimeout(resolve, 1100));
900
876
  }
901
877
  else {
902
878
  console.error(`Could not retrieve AniList ID for MAL ID ${malId}`);
@@ -1122,8 +1098,6 @@ class AniDB {
1122
1098
  count++;
1123
1099
  responsiveOutput(`[${count}]\t${entryId} āœ…\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
1124
1100
  }
1125
- // Rate limit each API call to avoid server overload
1126
- // await new Promise((resolve) => setTimeout(resolve, 1100))
1127
1101
  }
1128
1102
  catch (error) {
1129
1103
  console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
@@ -1,8 +1,11 @@
1
1
  declare const addAnimeToListMutation = "\nmutation($mediaId: Int, $status: MediaListStatus) {\n SaveMediaListEntry(mediaId: $mediaId, status: $status) { id status }\n}\n";
2
- declare const addMangaToListMutation = "\n mutation($mediaId: Int, $status: MediaListStatus) {\n SaveMediaListEntry(mediaId: $mediaId, status: $status) {\n id\n status\n media { id title { romaji english } }\n }\n }\n";
3
- declare const deleteActivityMutation = "\nmutation($id: Int!) {\n DeleteActivity(id: $id) { deleted }\n}\n";
4
- declare const saveTextActivityMutation = "\nmutation SaveTextActivity($status: String!) {\n SaveTextActivity(text: $status) { id text userId createdAt }\n}\n";
2
+ declare const addMangaToListMutation = "\n mutation($mediaId: Int, $status: MediaListStatus) {\n SaveMediaListEntry(mediaId: $mediaId, status: $status) {\n id status media { id title { romaji english } }\n }\n }\n";
3
+ declare const deleteActivityMutation = "\nmutation($id: Int!) { DeleteActivity(id: $id) { deleted } }\n";
4
+ declare const saveTextActivityMutation = "\nmutation SaveTextActivity($status: String!) { SaveTextActivity(text: $status) { id text userId createdAt } }\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
7
  declare const likeActivityMutation = "\nmutation($activityId: Int!) {\n ToggleLike(id: $activityId, type: ACTIVITY) { id }\n}\n";
8
- export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
8
+ declare const toggleFollowMutation = "mutation ($userId: Int!) { ToggleFollow(userId: $userId) { id name isFollower isFollowing } }";
9
+ declare const deleteMediaEntryMutation = "mutation($id: Int!) { DeleteMediaListEntry(id: $id) { deleted } }";
10
+ declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
11
+ export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, toggleFollowMutation, };
@@ -6,21 +6,15 @@ mutation($mediaId: Int, $status: MediaListStatus) {
6
6
  const addMangaToListMutation = `
7
7
  mutation($mediaId: Int, $status: MediaListStatus) {
8
8
  SaveMediaListEntry(mediaId: $mediaId, status: $status) {
9
- id
10
- status
11
- media { id title { romaji english } }
9
+ id status media { id title { romaji english } }
12
10
  }
13
11
  }
14
12
  `;
15
13
  const deleteActivityMutation = `
16
- mutation($id: Int!) {
17
- DeleteActivity(id: $id) { deleted }
18
- }
14
+ mutation($id: Int!) { DeleteActivity(id: $id) { deleted } }
19
15
  `;
20
16
  const saveTextActivityMutation = `
21
- mutation SaveTextActivity($status: String!) {
22
- SaveTextActivity(text: $status) { id text userId createdAt }
23
- }
17
+ mutation SaveTextActivity($status: String!) { SaveTextActivity(text: $status) { id text userId createdAt } }
24
18
  `;
25
19
  const saveAnimeWithProgressMutation = `
26
20
  mutation ($mediaId: Int, $progress: Int, $status: MediaListStatus, $hiddenFromStatusLists: Boolean) {
@@ -40,4 +34,9 @@ mutation($activityId: Int!) {
40
34
  ToggleLike(id: $activityId, type: ACTIVITY) { id }
41
35
  }
42
36
  `;
43
- export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, };
37
+ const toggleFollowMutation = `mutation ($userId: Int!) { ToggleFollow(userId: $userId) { id name isFollower isFollowing } }`;
38
+ const deleteMediaEntryMutation = `mutation($id: Int!) { DeleteMediaListEntry(id: $id) { deleted } }`;
39
+ const deleteMangaEntryMutation = `mutation($id: Int) {
40
+ DeleteMediaListEntry(id: $id) { deleted }
41
+ }`;
42
+ export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, likeActivityMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, saveTextActivityMutation, toggleFollowMutation, };
@@ -2,10 +2,8 @@ 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";
7
- declare const deleteMediaEntryMutation = "mutation($id: Int!) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
8
- declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\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";
9
7
  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
8
  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
9
  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}";
@@ -24,6 +22,5 @@ declare const globalActivitiesQuery = "\nquery ($page: Int, $perPage: Int) {\n
24
22
  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
23
  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
24
  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
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";
29
- export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, toggleFollowMutation, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
26
+ export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
@@ -26,22 +26,16 @@ const userQuery = `query ($username: String) {
26
26
  }`;
27
27
  const currentUserAnimeList = `query ($id: Int) {
28
28
  MediaListCollection(userId: $id, type: ANIME) {
29
- lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english } status episodes siteUrl } } }
29
+ lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english native userPreferred } status episodes siteUrl format } } }
30
30
  }
31
31
  }
32
32
  `;
33
33
  const currentUserMangaList = `query ($id: Int) {
34
34
  MediaListCollection(userId: $id, type: MANGA) {
35
- lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english } status chapters } } }
35
+ lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english native userPreferred } status chapters } } }
36
36
  }
37
37
  }
38
38
  `;
39
- const deleteMediaEntryMutation = `mutation($id: Int!) {
40
- DeleteMediaListEntry(id: $id) { deleted }
41
- }`;
42
- const deleteMangaEntryMutation = `mutation($id: Int) {
43
- DeleteMediaListEntry(id: $id) { deleted }
44
- }`;
45
39
  const upcomingAnimesQuery = `query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {
46
40
  Page(perPage: $perPage) {
47
41
  media(season: $nextSeason, seasonYear: $nextYear, type: ANIME, sort: POPULARITY_DESC) {
@@ -173,10 +167,6 @@ const userFollowersQuery = `query ($userId: Int!, $page: Int) {
173
167
  }
174
168
  }
175
169
  `;
176
- const toggleFollowMutation = `mutation ($userId: Int!) {
177
- ToggleFollow(userId: $userId) { id name isFollower isFollowing }
178
- }
179
- `;
180
170
  const mangaDetailsQuery = `query ($id: Int) {
181
171
  Media(id: $id, type: MANGA) {
182
172
  id title { romaji english native userPreferred } coverImage { color medium large extraLarge }
@@ -185,4 +175,4 @@ const mangaDetailsQuery = `query ($id: Int) {
185
175
  }
186
176
  }
187
177
  `;
188
- export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, toggleFollowMutation, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
178
+ export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, followingActivitiesQuery, globalActivitiesQuery, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, specificUserActivitiesQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
@@ -1,12 +1,13 @@
1
+ type Error = {
2
+ message: string;
3
+ }[];
1
4
  interface DeleteMangaResponse {
2
5
  data?: {
3
6
  DeleteMediaListEntry?: {
4
7
  deleted?: boolean;
5
8
  };
6
9
  };
7
- errors?: {
8
- message: string;
9
- }[];
10
+ errors?: Error;
10
11
  }
11
12
  declare enum AniListMediaStatus {
12
13
  CURRENT = "CURRENT",
@@ -48,9 +49,7 @@ interface MalIdToAnilistIdResponse {
48
49
  title: MediaTitle;
49
50
  };
50
51
  };
51
- errors?: {
52
- message: string;
53
- }[];
52
+ errors?: Error;
54
53
  }
55
54
  interface saveAnimeWithProgressResponse {
56
55
  data?: {
@@ -60,9 +59,7 @@ interface saveAnimeWithProgressResponse {
60
59
  hiddenFromStatusLists: boolean;
61
60
  };
62
61
  };
63
- errors?: {
64
- message: string;
65
- }[];
62
+ errors?: Error;
66
63
  }
67
64
  declare enum MALAnimeStatus {
68
65
  ON_HOLD = "On-Hold",
@@ -84,9 +81,7 @@ interface AnimeList {
84
81
  lists: MediaList[];
85
82
  };
86
83
  };
87
- errors?: {
88
- message: string;
89
- }[];
84
+ errors?: Error;
90
85
  }
91
86
  interface MediaWithProgress {
92
87
  malId?: number;
@@ -125,9 +120,7 @@ interface SaveTextActivityResponse {
125
120
  createdAt: number;
126
121
  };
127
122
  };
128
- errors?: {
129
- message: string;
130
- }[];
123
+ errors?: Error;
131
124
  }
132
125
  interface MediaListCollectionResponse {
133
126
  data?: {
@@ -135,9 +128,7 @@ interface MediaListCollectionResponse {
135
128
  lists: MediaList[];
136
129
  };
137
130
  };
138
- errors?: {
139
- message: string;
140
- }[];
131
+ errors?: Error;
141
132
  }
142
133
  interface List {
143
134
  name: string;
@@ -151,39 +142,9 @@ interface MediaList {
151
142
  }
152
143
  interface Myself {
153
144
  data?: {
154
- Viewer: {
155
- id: number;
156
- name: string;
157
- siteUrl: string;
158
- options: {
159
- profileColor: string;
160
- timezone: string;
161
- activityMergeTime: string;
162
- };
163
- donatorTier: string;
164
- donatorBadge: string;
165
- unreadNotificationCount: number;
166
- createdAt: number;
167
- updatedAt: number;
168
- statistics: {
169
- anime: {
170
- count: number;
171
- meanScore: string;
172
- minutesWatched: string;
173
- episodesWatched: number;
174
- };
175
- manga: {
176
- count: number;
177
- meanScore: string;
178
- chaptersRead: number;
179
- volumesRead: number;
180
- };
181
- };
182
- };
145
+ Viewer: User;
183
146
  };
184
- errors?: {
185
- message: string;
186
- }[];
147
+ errors?: Error;
187
148
  }
188
149
  interface DateMonthYear {
189
150
  day?: number | null;
@@ -208,9 +169,7 @@ interface AnimeDetails {
208
169
  siteUrl: string;
209
170
  };
210
171
  };
211
- errors?: {
212
- message: string;
213
- }[];
172
+ errors?: Error;
214
173
  }
215
174
  interface SaveMediaListEntryResponse {
216
175
  data?: {
@@ -219,9 +178,7 @@ interface SaveMediaListEntryResponse {
219
178
  status: string;
220
179
  };
221
180
  };
222
- errors?: {
223
- message: string;
224
- }[];
181
+ errors?: Error;
225
182
  }
226
183
  interface MediaListEntry {
227
184
  id?: number;
@@ -245,55 +202,51 @@ type UserActivitiesResponse = {
245
202
  activities: Activity[];
246
203
  };
247
204
  };
248
- errors?: {
249
- message: string;
250
- }[];
205
+ errors?: Error;
251
206
  };
252
207
  type UserResponse = {
253
208
  data?: {
254
- User: {
255
- id: number;
256
- name: string;
257
- siteUrl: string;
258
- donatorTier: string;
259
- donatorBadge: string;
260
- createdAt: number;
261
- updatedAt: number;
262
- isBlocked: boolean;
263
- isFollower: boolean;
264
- isFollowing: boolean;
265
- options: {
266
- profileColor: string;
267
- timezone: string;
268
- };
269
- statistics: {
270
- anime: {
271
- count: number;
272
- episodesWatched: number;
273
- minutesWatched: number;
274
- };
275
- manga: {
276
- count: number;
277
- chaptersRead: number;
278
- volumesRead: number;
279
- };
280
- };
281
- };
209
+ User: User;
282
210
  };
283
- errors?: {
284
- message: string;
285
- }[];
211
+ errors?: Error;
212
+ };
213
+ type Avatar = {
214
+ large?: string;
215
+ medium?: string;
286
216
  };
287
217
  type User = {
288
218
  id: number;
289
- name: string;
290
- avatar: {
291
- large: string;
292
- medium: string;
219
+ name?: string;
220
+ avatar?: Avatar;
221
+ bannerImage?: string;
222
+ isFollower?: boolean;
223
+ isFollowing?: boolean;
224
+ siteUrl?: string;
225
+ donatorTier?: string;
226
+ donatorBadge?: string;
227
+ createdAt?: number;
228
+ updatedAt?: number;
229
+ isBlocked?: boolean;
230
+ unreadNotificationCount?: number;
231
+ options?: {
232
+ profileColor?: string;
233
+ timezone?: string;
234
+ activityMergeTime?: number;
235
+ };
236
+ statistics?: {
237
+ anime?: {
238
+ count?: number;
239
+ episodesWatched?: number;
240
+ minutesWatched?: number;
241
+ meanScore?: number;
242
+ };
243
+ manga?: {
244
+ count?: number;
245
+ chaptersRead?: number;
246
+ volumesRead?: number;
247
+ meanScore?: number;
248
+ };
293
249
  };
294
- bannerImage: string;
295
- isFollower: boolean;
296
- isFollowing: boolean;
297
250
  };
298
251
  type UserFollower = {
299
252
  data?: {
@@ -308,9 +261,7 @@ type UserFollower = {
308
261
  followers: User[];
309
262
  };
310
263
  };
311
- errors?: {
312
- message: string;
313
- }[];
264
+ errors?: Error;
314
265
  };
315
266
  type UserFollowing = {
316
267
  data?: {
@@ -325,9 +276,7 @@ type UserFollowing = {
325
276
  following: User[];
326
277
  };
327
278
  };
328
- errors?: {
329
- message: string;
330
- }[];
279
+ errors?: Error;
331
280
  };
332
281
  type AnimeSearchResponse = {
333
282
  data?: {
@@ -342,9 +291,7 @@ type AnimeSearchResponse = {
342
291
  }[];
343
292
  };
344
293
  };
345
- errors?: {
346
- message: string;
347
- }[];
294
+ errors?: Error;
348
295
  };
349
296
  type ToggleFollowResponse = {
350
297
  data?: {
@@ -355,9 +302,7 @@ type ToggleFollowResponse = {
355
302
  isFollowing: boolean;
356
303
  };
357
304
  };
358
- errors?: {
359
- message: string;
360
- }[];
305
+ errors?: Error;
361
306
  };
362
307
  type DeleteMediaListResponse = {
363
308
  data?: {
@@ -365,9 +310,7 @@ type DeleteMediaListResponse = {
365
310
  deleted: boolean;
366
311
  };
367
312
  };
368
- errors?: {
369
- message: string;
370
- }[];
313
+ errors?: Error;
371
314
  };
372
315
  type Activity = {
373
316
  id: number;
@@ -432,9 +375,6 @@ type SpecificUserActivitiesResponse = {
432
375
  message: string;
433
376
  }[];
434
377
  };
435
- type Error = {
436
- message: string;
437
- }[];
438
378
  type CoverImage = {
439
379
  color: string;
440
380
  medium: string;
@@ -1,4 +1,4 @@
1
- import { DateMonthYear, MALAnimeStatus, MALMangaStatus, MediaWithProgress, TheActivity } from "./types.js";
1
+ import { DateMonthYear, MALAnimeStatus, MALMangaStatus, MediaWithProgress, TheActivity, User } from "./types.js";
2
2
  declare const aniListEndpoint = "https://graphql.anilist.co";
3
3
  declare const redirectUri = "https://anilist.co/api/v2/oauth/pin";
4
4
  declare function getTitle(title: {
@@ -47,4 +47,6 @@ declare function activityBy(activity: TheActivity, count?: number): string;
47
47
  */
48
48
  declare function saveToPath(data_type: string, file_format: string): Promise<string>;
49
49
  declare function simpleDateFormat(date: DateMonthYear): string;
50
- export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, simpleDateFormat, timestampToTimeAgo, };
50
+ declare function handleRateLimitRetry(retryCount: number): Promise<void>;
51
+ declare function logUserDetails(user: User, followersCount: number, followingCount: number): void;
52
+ export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, handleRateLimitRetry, logUserDetails, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, simpleDateFormat, timestampToTimeAgo, };
@@ -27,12 +27,14 @@ import { homedir } from "os";
27
27
  import Papa from "papaparse";
28
28
  import { join } from "path";
29
29
  import process from "process";
30
+ import Spinner from "tiny-spinner";
30
31
  import { Auth } from "./auth.js";
31
32
  import { fetcher } from "./fetcher.js";
32
33
  import { animeSearchQuery } from "./queries.js";
33
34
  import { MALAnimeStatus, MALMangaStatus, } from "./types.js";
34
35
  const aniListEndpoint = `https://graphql.anilist.co`;
35
36
  const redirectUri = "https://anilist.co/api/v2/oauth/pin";
37
+ const spinner = new Spinner();
36
38
  function getTitle(title) {
37
39
  return (title === null || title === void 0 ? void 0 : title.english) || (title === null || title === void 0 ? void 0 : title.romaji) || "???";
38
40
  }
@@ -202,49 +204,49 @@ function selectFile(fileType) {
202
204
  });
203
205
  }
204
206
  function createAnimeXML(malId, progress, status, episodes, title, format) {
205
- return `
206
- <anime>
207
- <series_animedb_id>${malId}</series_animedb_id>
208
- <series_title><![CDATA[${title}]]></series_title>
209
- <series_type>${format}</series_type>
210
- <series_episodes>${episodes}</series_episodes>
211
- <my_id>0</my_id>
212
- <my_watched_episodes>${progress}</my_watched_episodes>
213
- <my_start_date>0000-00-00</my_start_date>
214
- <my_finish_date>0000-00-00</my_finish_date>
215
- <my_score>0</my_score>
216
- <my_storage_value>0.00</my_storage_value>
217
- <my_status>${status}</my_status>
218
- <my_comments><![CDATA[]]></my_comments>
219
- <my_times_watched>0</my_times_watched>
220
- <my_rewatch_value></my_rewatch_value>
221
- <my_priority>LOW</my_priority>
222
- <my_tags><![CDATA[]]></my_tags>
223
- <my_rewatching>0</my_rewatching>
224
- <my_rewatching_ep>0</my_rewatching_ep>
225
- <my_discuss>0</my_discuss>
226
- <my_sns>default</my_sns>
227
- <update_on_import>1</update_on_import>
207
+ return `
208
+ <anime>
209
+ <series_animedb_id>${malId}</series_animedb_id>
210
+ <series_title><![CDATA[${title}]]></series_title>
211
+ <series_type>${format}</series_type>
212
+ <series_episodes>${episodes}</series_episodes>
213
+ <my_id>0</my_id>
214
+ <my_watched_episodes>${progress}</my_watched_episodes>
215
+ <my_start_date>0000-00-00</my_start_date>
216
+ <my_finish_date>0000-00-00</my_finish_date>
217
+ <my_score>0</my_score>
218
+ <my_storage_value>0.00</my_storage_value>
219
+ <my_status>${status}</my_status>
220
+ <my_comments><![CDATA[]]></my_comments>
221
+ <my_times_watched>0</my_times_watched>
222
+ <my_rewatch_value></my_rewatch_value>
223
+ <my_priority>LOW</my_priority>
224
+ <my_tags><![CDATA[]]></my_tags>
225
+ <my_rewatching>0</my_rewatching>
226
+ <my_rewatching_ep>0</my_rewatching_ep>
227
+ <my_discuss>0</my_discuss>
228
+ <my_sns>default</my_sns>
229
+ <update_on_import>1</update_on_import>
228
230
  </anime>`;
229
231
  }
230
232
  function createMangaXML(malId, progress, status, chapters, title) {
231
- return `
232
- <manga>
233
- <manga_mangadb_id>${malId}</manga_mangadb_id>
234
- <manga_title><![CDATA[${title ? title : "unknown"}]]></manga_title>
235
- <manga_volumes>0</manga_volumes>
236
- <manga_chapters>${chapters ? chapters : 0}</manga_chapters>
237
- <my_id>0</my_id>
238
- <my_read_chapters>${progress}</my_read_chapters>
239
- <my_start_date>0000-00-00</my_start_date>
240
- <my_finish_date>0000-00-00</my_finish_date>
241
- <my_score>0</my_score>
242
- <my_status>${status}</my_status>
243
- <my_reread_value></my_reread_value>
244
- <my_priority>LOW</my_priority>
245
- <my_rereading>0</my_rereading>
246
- <my_discuss>0</my_discuss>
247
- <update_on_import>1</update_on_import>
233
+ return `
234
+ <manga>
235
+ <manga_mangadb_id>${malId}</manga_mangadb_id>
236
+ <manga_title><![CDATA[${title ? title : "unknown"}]]></manga_title>
237
+ <manga_volumes>0</manga_volumes>
238
+ <manga_chapters>${chapters ? chapters : 0}</manga_chapters>
239
+ <my_id>0</my_id>
240
+ <my_read_chapters>${progress}</my_read_chapters>
241
+ <my_start_date>0000-00-00</my_start_date>
242
+ <my_finish_date>0000-00-00</my_finish_date>
243
+ <my_score>0</my_score>
244
+ <my_status>${status}</my_status>
245
+ <my_reread_value></my_reread_value>
246
+ <my_priority>LOW</my_priority>
247
+ <my_rereading>0</my_rereading>
248
+ <my_discuss>0</my_discuss>
249
+ <update_on_import>1</update_on_import>
248
250
  </manga>`;
249
251
  }
250
252
  function createAnimeListXML(mediaWithProgress) {
@@ -267,19 +269,19 @@ function createAnimeListXML(mediaWithProgress) {
267
269
  const format = anime.format ? anime.format : "";
268
270
  return createAnimeXML(malId, progress, status, episodes, title, format);
269
271
  });
270
- return `<myanimelist>
271
- <myinfo>
272
- <user_id/>
273
- <user_name>${yield Auth.MyUserName()}</user_name>
274
- <user_export_type>1</user_export_type>
275
- <user_total_anime>0</user_total_anime>
276
- <user_total_watching>0</user_total_watching>
277
- <user_total_completed>0</user_total_completed>
278
- <user_total_onhold>0</user_total_onhold>
279
- <user_total_dropped>0</user_total_dropped>
280
- <user_total_plantowatch>0</user_total_plantowatch>
281
- </myinfo>
282
- \n${xmlEntries.join("\n")}\n
272
+ return `<myanimelist>
273
+ <myinfo>
274
+ <user_id/>
275
+ <user_name>${yield Auth.MyUserName()}</user_name>
276
+ <user_export_type>1</user_export_type>
277
+ <user_total_anime>0</user_total_anime>
278
+ <user_total_watching>0</user_total_watching>
279
+ <user_total_completed>0</user_total_completed>
280
+ <user_total_onhold>0</user_total_onhold>
281
+ <user_total_dropped>0</user_total_dropped>
282
+ <user_total_plantowatch>0</user_total_plantowatch>
283
+ </myinfo>
284
+ \n${xmlEntries.join("\n")}\n
283
285
  </myanimelist>`;
284
286
  });
285
287
  }
@@ -302,19 +304,19 @@ function createMangaListXML(mediaWithProgress) {
302
304
  const status = statusMap[manga.status];
303
305
  return createMangaXML(malId, progress, status, chapters, title);
304
306
  });
305
- return `<myanimelist>
306
- <myinfo>
307
- <user_id/>
308
- <user_name>${yield Auth.MyUserName()}</user_name>
309
- <user_export_type>2</user_export_type>
310
- <user_total_manga>5</user_total_manga>
311
- <user_total_reading>1</user_total_reading>
312
- <user_total_completed>1</user_total_completed>
313
- <user_total_onhold>1</user_total_onhold>
314
- <user_total_dropped>1</user_total_dropped>
315
- <user_total_plantoread>1</user_total_plantoread>
316
- </myinfo>
317
- \n${xmlEntries.join("\n")}\n
307
+ return `<myanimelist>
308
+ <myinfo>
309
+ <user_id/>
310
+ <user_name>${yield Auth.MyUserName()}</user_name>
311
+ <user_export_type>2</user_export_type>
312
+ <user_total_manga>5</user_total_manga>
313
+ <user_total_reading>1</user_total_reading>
314
+ <user_total_completed>1</user_total_completed>
315
+ <user_total_onhold>1</user_total_onhold>
316
+ <user_total_dropped>1</user_total_dropped>
317
+ <user_total_plantoread>1</user_total_plantoread>
318
+ </myinfo>
319
+ \n${xmlEntries.join("\n")}\n
318
320
  </myanimelist>`;
319
321
  });
320
322
  }
@@ -418,4 +420,57 @@ function simpleDateFormat(date) {
418
420
  }
419
421
  return `${date === null || date === void 0 ? void 0 : date.day}/${date === null || date === void 0 ? void 0 : date.month}/${date === null || date === void 0 ? void 0 : date.year}`;
420
422
  }
421
- export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, simpleDateFormat, timestampToTimeAgo, };
423
+ function handleRateLimitRetry(retryCount) {
424
+ return __awaiter(this, void 0, void 0, function* () {
425
+ let seconds = Math.pow(2, retryCount) * 1000;
426
+ const maxWait = 60 * 1000;
427
+ seconds = Math.min(seconds, maxWait);
428
+ spinner.start(`Rate limit reached. Retrying in ${seconds / 1000} sec...`);
429
+ let remainingTime = seconds / 1000;
430
+ const interval = setInterval(() => {
431
+ remainingTime--;
432
+ spinner.update(`Rate limit reached. Retrying in ${remainingTime} sec...`);
433
+ if (remainingTime <= 0)
434
+ clearInterval(interval);
435
+ }, 1000);
436
+ yield new Promise((resolve) => setTimeout(resolve, seconds));
437
+ clearInterval(interval);
438
+ spinner.stop();
439
+ });
440
+ }
441
+ function formatDate(timestamp) {
442
+ return timestamp ? new Date(timestamp * 1000).toUTCString() : "N/A";
443
+ }
444
+ function logUserDetails(user, followersCount, followingCount) {
445
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
446
+ console.log("\nšŸ“Œ User Information:");
447
+ console.table({
448
+ "ID": user.id,
449
+ "Name": user.name,
450
+ "Site URL": user.siteUrl,
451
+ "Donator Tier": user.donatorTier,
452
+ "Donator Badge": user.donatorBadge,
453
+ "Account Created": formatDate(user.createdAt),
454
+ "Account Updated": formatDate(user.updatedAt),
455
+ "Blocked": user.isBlocked,
456
+ "isFollower": user.isFollower,
457
+ "isFollowing": user.isFollowing,
458
+ "Profile Color": ((_a = user.options) === null || _a === void 0 ? void 0 : _a.profileColor) || "N/A",
459
+ "Timezone": ((_b = user.options) === null || _b === void 0 ? void 0 : _b.timezone) || "N/A",
460
+ "Followers": followersCount,
461
+ "Following": followingCount,
462
+ });
463
+ console.log("\nšŸ“Š Anime Statistics:");
464
+ console.table({
465
+ "Count": ((_d = (_c = user.statistics) === null || _c === void 0 ? void 0 : _c.anime) === null || _d === void 0 ? void 0 : _d.count) || 0,
466
+ "Episodes Watched": ((_f = (_e = user.statistics) === null || _e === void 0 ? void 0 : _e.anime) === null || _f === void 0 ? void 0 : _f.episodesWatched) || 0,
467
+ "Minutes Watched": ((_h = (_g = user.statistics) === null || _g === void 0 ? void 0 : _g.anime) === null || _h === void 0 ? void 0 : _h.minutesWatched) || 0,
468
+ });
469
+ console.log("\nšŸ“– Manga Statistics:");
470
+ console.table({
471
+ "Count": ((_k = (_j = user.statistics) === null || _j === void 0 ? void 0 : _j.manga) === null || _k === void 0 ? void 0 : _k.count) || 0,
472
+ "Chapters Read": ((_m = (_l = user.statistics) === null || _l === void 0 ? void 0 : _l.manga) === null || _m === void 0 ? void 0 : _m.chaptersRead) || 0,
473
+ "Volumes Read": ((_p = (_o = user.statistics) === null || _o === void 0 ? void 0 : _o.manga) === null || _p === void 0 ? void 0 : _p.volumesRead) || 0,
474
+ });
475
+ }
476
+ export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, handleRateLimitRetry, logUserDetails, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, simpleDateFormat, timestampToTimeAgo, };
package/bin/index.js CHANGED
@@ -213,16 +213,9 @@ cli
213
213
  cli
214
214
  .command("autolike")
215
215
  .alias("al")
216
- .option("-2, --v2", "Like the activities", false)
217
- .option("-c, --count <number>", "Number of activities to like", "25")
218
216
  .description("Autolike following or global activities.")
219
- .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ v2, count }) {
220
- if (v2) {
221
- yield Auth.LikeFollowingActivityV2(count);
222
- }
223
- else {
224
- yield Auth.AutoLike();
225
- }
217
+ .action(() => __awaiter(void 0, void 0, void 0, function* () {
218
+ yield Auth.AutoLike();
226
219
  }));
227
220
  cli
228
221
  .command("social")
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@irfanshadikrishad/anilist",
3
3
  "description": "Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts",
4
4
  "author": "Irfan Shadik Rishad",
5
- "version": "1.0.0-forbidden.6",
5
+ "version": "1.0.0-forbidden.7",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -55,26 +55,27 @@
55
55
  "license": "MPL-2.0",
56
56
  "devDependencies": {
57
57
  "@babel/preset-env": "^7.26.9",
58
- "@eslint/js": "^9.21.0",
58
+ "@eslint/js": "^9.23.0",
59
59
  "@types/jest": "^29.5.14",
60
- "@types/node": "^22.13.5",
60
+ "@types/node": "^22.13.14",
61
61
  "@types/papaparse": "^5.3.15",
62
62
  "@types/xml2js": "^0.4.14",
63
- "@typescript-eslint/eslint-plugin": "^8.24.1",
64
- "eslint": "^9.21.0",
63
+ "@typescript-eslint/eslint-plugin": "^8.28.0",
64
+ "eslint": "^9.23.0",
65
65
  "globals": "^16.0.0",
66
66
  "jest": "^29.7.0",
67
- "prettier": "^3.5.2",
67
+ "prettier": "^3.5.3",
68
68
  "prettier-plugin-organize-imports": "^4.1.0",
69
- "ts-jest": "^29.2.6",
69
+ "ts-jest": "^29.3.0",
70
70
  "ts-node": "^10.9.2",
71
- "typescript": "^5.7.3"
71
+ "typescript": "^5.8.2"
72
72
  },
73
73
  "dependencies": {
74
+ "@irfanshadikrishad/cipher": "^1.0.7",
74
75
  "cli-truncate": "^4.0.0",
75
76
  "commander": "^13.1.0",
76
- "fast-xml-parser": "^5.0.6",
77
- "inquirer": "^12.4.2",
77
+ "fast-xml-parser": "^5.0.9",
78
+ "inquirer": "^12.5.0",
78
79
  "jsonrepair": "^3.12.0",
79
80
  "node-fetch": "^3.3.2",
80
81
  "open": "^10.1.0",