@irfanshadikrishad/anilist 1.0.0-forbidden.5 → 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,12 +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";
23
+ import { responsiveOutput } from "./truncate.js";
22
24
  import { activityBy, aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from "./workers.js";
23
25
  const home_dir = os.homedir();
24
26
  const save_path = path.join(home_dir, ".anilist_token");
25
27
  const spinner = new Spinner();
28
+ const vigenere = new Cipher.Vigenere("anilist");
26
29
  class Auth {
27
30
  /**
28
31
  * Get access-token from user
@@ -56,7 +59,7 @@ class Auth {
56
59
  console.warn("\nNo token provided. Nothing to store.");
57
60
  return;
58
61
  }
59
- fs.writeFileSync(save_path, token, { encoding: "utf8" });
62
+ fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: "utf8" });
60
63
  }
61
64
  catch (error) {
62
65
  console.error(`\nError storing access token: ${error.message}`);
@@ -67,7 +70,7 @@ class Auth {
67
70
  return __awaiter(this, void 0, void 0, function* () {
68
71
  try {
69
72
  if (fs.existsSync(save_path)) {
70
- return fs.readFileSync(save_path, { encoding: "utf8" });
73
+ return vigenere.decrypt(fs.readFileSync(save_path, { encoding: "utf8" }));
71
74
  }
72
75
  else {
73
76
  return null;
@@ -183,7 +186,7 @@ Statistics (Manga):
183
186
  console.log(`\nRecent Activities:`);
184
187
  if (activities.length > 0) {
185
188
  activities.map(({ status, progress, media, createdAt }) => {
186
- console.log(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
189
+ responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
187
190
  });
188
191
  }
189
192
  return user;
@@ -596,14 +599,14 @@ Statistics (Manga):
596
599
  if (like === null || like === void 0 ? void 0 : like.data) {
597
600
  likedCount++;
598
601
  }
599
- console.info(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
602
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
600
603
  }
601
604
  catch (error) {
602
605
  console.error(`Activity possibly deleted. ${error.message}`);
603
606
  }
604
607
  }
605
608
  else {
606
- console.log(`🔵 ${activityBy(activ)}`);
609
+ responsiveOutput(`"🔵" ${activityBy(activ, likedCount)}`);
607
610
  }
608
611
  // avoiding rate-limit
609
612
  yield new Promise((resolve) => {
@@ -655,14 +658,14 @@ Statistics (Manga):
655
658
  });
656
659
  // const ToggleLike = like?.data?.ToggleLike
657
660
  likedCount++;
658
- console.info(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
661
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
659
662
  }
660
663
  catch (error) {
661
664
  console.error(`Activity possibly deleted. ${error.message}`);
662
665
  }
663
666
  }
664
667
  else {
665
- console.log(`🔵 ${activityBy(activ)}`);
668
+ responsiveOutput(`🔵 ${activityBy(activ, likedCount)}`);
666
669
  }
667
670
  // avoiding rate-limit
668
671
  yield new Promise((resolve) => {
@@ -722,14 +725,14 @@ Statistics (Manga):
722
725
  activityId: activ.id,
723
726
  });
724
727
  likedCount++;
725
- console.info(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
728
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, likedCount)}`);
726
729
  }
727
730
  catch (error) {
728
731
  console.error(`Activity possibly deleted. ${error.message}`);
729
732
  }
730
733
  }
731
734
  else {
732
- console.log(`🔵 ${activityBy(activ)}`);
735
+ responsiveOutput(`🔵 ${activityBy(activ, likedCount)}`);
733
736
  }
734
737
  // Avoiding rate limit
735
738
  yield new Promise((resolve) => {
@@ -763,7 +766,9 @@ Statistics (Manga):
763
766
  let hasNextPage = true;
764
767
  let page = 1;
765
768
  let liked = 0;
769
+ // ------------------------
766
770
  // Fetch all following users
771
+ // ------------------------
767
772
  spinner.start(`Gathering following information...`);
768
773
  while (hasNextPage) {
769
774
  spinner.update(`Fetched page ${page}...`);
@@ -782,10 +787,28 @@ Statistics (Manga):
782
787
  spinner.stop(`Got ${allFollowingUsers.length} following user.`);
783
788
  // Extract the IDs of all following users
784
789
  const followingUserIds = allFollowingUsers.map((user) => user.id);
785
- console.log(`\nTotal Following: ${followingUserIds.length}\nApproximately ${followingUserIds.length * perPage} activities to like.\nWill take around ${((followingUserIds.length * perPage * 1200) /
786
- 1000 /
787
- 60).toFixed(2)} minutes.`);
788
- // 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
+ // -------------------
789
812
  let userNumber = 0;
790
813
  for (const userId of followingUserIds) {
791
814
  userNumber++;
@@ -808,7 +831,7 @@ Statistics (Manga):
808
831
  const like = yield fetcher(likeActivityMutation, {
809
832
  activityId: activ.id,
810
833
  });
811
- console.info(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, i + 1)}`);
834
+ responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? "✅" : "❌"} ${activityBy(activ, i + 1)}`);
812
835
  if (like === null || like === void 0 ? void 0 : like.data) {
813
836
  liked++;
814
837
  }
@@ -818,7 +841,7 @@ Statistics (Manga):
818
841
  }
819
842
  }
820
843
  else {
821
- console.log(`🔵 ${activityBy(activ, i + 1)}`);
844
+ responsiveOutput(`🔵 ${activityBy(activ, i + 1)}`);
822
845
  }
823
846
  // Avoid rate-limiting
824
847
  yield new Promise((resolve) => setTimeout(resolve, 1200));
@@ -844,9 +867,10 @@ Statistics (Manga):
844
867
  name: "activityType",
845
868
  message: "Select activity type:",
846
869
  choices: [
847
- { name: "Following", value: 1 },
848
- { name: "Global", value: 2 },
849
- { 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 },
850
874
  ],
851
875
  pageSize: 10,
852
876
  },
@@ -855,10 +879,21 @@ Statistics (Manga):
855
879
  case 1:
856
880
  yield this.LikeFollowing();
857
881
  break;
858
- case 2:
859
- 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);
860
891
  break;
892
+ }
861
893
  case 3:
894
+ yield this.LikeGlobal();
895
+ break;
896
+ case 4:
862
897
  yield this.LikeSpecificUser();
863
898
  break;
864
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"}.`);
@@ -16,9 +16,10 @@ import { Auth } from "./auth.js";
16
16
  import { fetcher } from "./fetcher.js";
17
17
  import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, } from "./mutations.js";
18
18
  import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaDetailsQuery, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
19
+ import { responsiveOutput } from "./truncate.js";
19
20
  import { AniListMediaStatus, } from "./types.js";
20
21
  import { Validate } from "./validation.js";
21
- 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";
22
23
  class AniList {
23
24
  static importAnime() {
24
25
  return __awaiter(this, void 0, void 0, function* () {
@@ -35,8 +36,7 @@ class AniList {
35
36
  return;
36
37
  }
37
38
  let count = 0;
38
- const batchSize = 1; // Number of requests in each batch
39
- const delay = 1100; // delay to avoid rate-limiting
39
+ const batchSize = 1;
40
40
  for (let i = 0; i < importedData.length; i += batchSize) {
41
41
  const batch = importedData.slice(i, i + batchSize);
42
42
  yield Promise.all(batch.map((anime) => __awaiter(this, void 0, void 0, function* () {
@@ -63,8 +63,6 @@ class AniList {
63
63
  console.error(`\nError saving ${anime === null || anime === void 0 ? void 0 : anime.id}: ${error.message}`);
64
64
  }
65
65
  })));
66
- // Avoid rate-limiting: Wait before sending the next batch
67
- yield new Promise((resolve) => setTimeout(resolve, delay));
68
66
  }
69
67
  console.log(`\nTotal ${count} anime(s) imported successfully.`);
70
68
  }
@@ -88,9 +86,7 @@ class AniList {
88
86
  return;
89
87
  }
90
88
  let count = 0;
91
- const batchSize = 1; // Adjust batch size as per rate-limit constraints
92
- const delay = 1100; // 2 seconds delay to avoid rate-limit
93
- // Process in batches
89
+ const batchSize = 1;
94
90
  for (let i = 0; i < importedData.length; i += batchSize) {
95
91
  const batch = importedData.slice(i, i + batchSize);
96
92
  yield Promise.all(batch.map((manga) => __awaiter(this, void 0, void 0, function* () {
@@ -115,8 +111,6 @@ class AniList {
115
111
  console.error(`\nError saving ${manga === null || manga === void 0 ? void 0 : manga.id}: ${err.message}`);
116
112
  }
117
113
  })));
118
- // Avoid rate-limit by adding delay after processing each batch
119
- yield new Promise((resolve) => setTimeout(resolve, delay));
120
114
  }
121
115
  console.log(`\nTotal ${count} manga(s) imported successfully.`);
122
116
  }
@@ -620,7 +614,7 @@ class AniList {
620
614
  }
621
615
  static getUserByUsername(username) {
622
616
  return __awaiter(this, void 0, void 0, function* () {
623
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
617
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
624
618
  try {
625
619
  const response = yield fetcher(userQuery, { username });
626
620
  if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
@@ -642,26 +636,11 @@ class AniList {
642
636
  });
643
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;
644
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;
645
- console.log(`\nID:\t\t${user.id}`);
646
- console.log(`Name:\t\t${user.name}`);
647
- console.log(`Site URL:\t${user.siteUrl}`);
648
- console.log(`Donator Tier:\t${user.donatorTier}`);
649
- console.log(`Donator Badge:\t${user.donatorBadge}`);
650
- console.log(`Account Created:\t${user.createdAt ? new Date(user.createdAt * 1000).toUTCString() : "N/A"}`);
651
- console.log(`Account Updated:\t${user.updatedAt ? new Date(user.updatedAt * 1000).toUTCString() : "N/A"}`);
652
- console.log(`Blocked:\t${user.isBlocked}`);
653
- console.log(`Follower:\t${user.isFollower}`);
654
- console.log(`Following:\t${user.isFollowing}`);
655
- console.log(`Profile Color:\t${(_o = user.options) === null || _o === void 0 ? void 0 : _o.profileColor}`);
656
- console.log(`Timezone:\t${((_p = user.options) === null || _p === void 0 ? void 0 : _p.timezone) ? (_q = user.options) === null || _q === void 0 ? void 0 : _q.timezone : "N/A"}`);
657
- console.log(`\nFollowers:\t${followersCount}`);
658
- console.log(`Following:\t${followingCount}`);
659
- console.log(`\nStatistics (Anime)\n\tCount: ${((_s = (_r = user.statistics) === null || _r === void 0 ? void 0 : _r.anime) === null || _s === void 0 ? void 0 : _s.count) || 0}\tEpisodes Watched: ${((_u = (_t = user.statistics) === null || _t === void 0 ? void 0 : _t.anime) === null || _u === void 0 ? void 0 : _u.episodesWatched) || 0}\tMinutes Watched: ${((_w = (_v = user.statistics) === null || _v === void 0 ? void 0 : _v.anime) === null || _w === void 0 ? void 0 : _w.minutesWatched) || 0}`);
660
- console.log(`Statistics (Manga)\n\tCount: ${((_y = (_x = user.statistics) === null || _x === void 0 ? void 0 : _x.manga) === null || _y === void 0 ? void 0 : _y.count) || 0}\tChapters Read: ${((_0 = (_z = user.statistics) === null || _z === void 0 ? void 0 : _z.manga) === null || _0 === void 0 ? void 0 : _0.chaptersRead) || 0}\tVolumes Read: ${((_2 = (_1 = user.statistics) === null || _1 === void 0 ? void 0 : _1.manga) === null || _2 === void 0 ? void 0 : _2.volumesRead) || 0}`);
639
+ logUserDetails(user, followersCount, followingCount);
661
640
  if (activities.length > 0) {
662
641
  console.log(`\nRecent Activities:`);
663
642
  activities.forEach(({ status, progress, media, createdAt }) => {
664
- console.log(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
643
+ responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ""}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
665
644
  });
666
645
  }
667
646
  else {
@@ -894,8 +873,6 @@ class MyAnimeList {
894
873
  count++;
895
874
  console.log(`[${count}] ${entryId} ✅`);
896
875
  }
897
- // Rate limit each API call to avoid server overload
898
- yield new Promise((resolve) => setTimeout(resolve, 1100));
899
876
  }
900
877
  else {
901
878
  console.error(`Could not retrieve AniList ID for MAL ID ${malId}`);
@@ -1119,10 +1096,8 @@ class AniDB {
1119
1096
  const entryId = (_b = (_a = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _a === void 0 ? void 0 : _a.SaveMediaListEntry) === null || _b === void 0 ? void 0 : _b.id;
1120
1097
  if (entryId) {
1121
1098
  count++;
1122
- console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
1099
+ responsiveOutput(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
1123
1100
  }
1124
- // Rate limit each API call to avoid server overload
1125
- // await new Promise((resolve) => setTimeout(resolve, 1100))
1126
1101
  }
1127
1102
  catch (error) {
1128
1103
  console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
@@ -1136,9 +1111,9 @@ class AniDB {
1136
1111
  });
1137
1112
  }
1138
1113
  }
1139
- console.log(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
1114
+ responsiveOutput(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
1140
1115
  if (missed.length > 0) {
1141
- console.log(`Exporting missed entries to JSON file, Please add them manually.`);
1116
+ responsiveOutput(`Exporting missed entries to JSON file, Please add them manually.`);
1142
1117
  yield saveJSONasJSON(missed, "anidb-missed");
1143
1118
  }
1144
1119
  }
@@ -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, };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Truncate text (No line break)
3
+ * @param str - Long text to trancate
4
+ */
5
+ declare function responsiveOutput(str: string): void;
6
+ export { responsiveOutput };
@@ -0,0 +1,10 @@
1
+ import cliTruncate from "cli-truncate";
2
+ import process from "process";
3
+ /**
4
+ * Truncate text (No line break)
5
+ * @param str - Long text to trancate
6
+ */
7
+ function responsiveOutput(str) {
8
+ console.log(cliTruncate(str, process.stdout.columns - 5));
9
+ }
10
+ export { responsiveOutput };
@@ -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
  }
@@ -382,22 +384,23 @@ const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void
382
384
  });
383
385
  function activityBy(activity, count) {
384
386
  var _a, _b, _c, _d;
387
+ const countStr = `[${count ? count : "?"}]`.padEnd(6);
385
388
  if ((_a = activity === null || activity === void 0 ? void 0 : activity.messenger) === null || _a === void 0 ? void 0 : _a.name) {
386
- return `[${count ? count : "?"}]\t${activity.messenger.name} >> messaged ${activity.recipient.name}`;
389
+ return `${countStr}${activity.messenger.name} >> messaged ${activity.recipient.name}`;
387
390
  }
388
391
  else if ((_c = (_b = activity === null || activity === void 0 ? void 0 : activity.media) === null || _b === void 0 ? void 0 : _b.title) === null || _c === void 0 ? void 0 : _c.userPreferred) {
389
392
  if (activity.progress) {
390
- return `[${count ? count : "?"}]\t${activity.user.name} >> ${activity.status} ${activity.progress} of ${activity.media.title.userPreferred}`;
393
+ return `${countStr}${activity.user.name} >> ${activity.status} ${activity.progress} of ${activity.media.title.userPreferred}`;
391
394
  }
392
395
  else {
393
- return `[${count ? count : "?"}]\t${activity.user.name} >> ${activity.status} ${activity.media.title.userPreferred}`;
396
+ return `${countStr}${activity.user.name} >> ${activity.status} ${activity.media.title.userPreferred}`;
394
397
  }
395
398
  }
396
399
  else if ((_d = activity === null || activity === void 0 ? void 0 : activity.user) === null || _d === void 0 ? void 0 : _d.name) {
397
- return `[${count ? count : "?"}]\t${activity.user.name}`;
400
+ return `${countStr}${activity.user.name}`;
398
401
  }
399
402
  else {
400
- return `[${count ? count : "?"} ???`;
403
+ return `${countStr}???`;
401
404
  }
402
405
  }
403
406
  /**
@@ -417,4 +420,57 @@ function simpleDateFormat(date) {
417
420
  }
418
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}`;
419
422
  }
420
- 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.5",
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,25 +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",
75
+ "cli-truncate": "^4.0.0",
74
76
  "commander": "^13.1.0",
75
- "fast-xml-parser": "^5.0.6",
76
- "inquirer": "^12.4.2",
77
+ "fast-xml-parser": "^5.0.9",
78
+ "inquirer": "^12.5.0",
77
79
  "jsonrepair": "^3.12.0",
78
80
  "node-fetch": "^3.3.2",
79
81
  "open": "^10.1.0",