@irfanshadikrishad/anilist 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,24 +44,24 @@ anilist login -i <client-id> -s <client-secret>
44
44
 
45
45
  #### CLI Commands Overview
46
46
 
47
- | **Command** | **Options** | **Description** |
48
- | ------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------ |
49
- | **`login`** | `-i, --id` `-s, --secret` | Log in with your AniList credentials |
50
- | **`logout`** | _None_ | Log out from your AniList account |
51
- | **`whoami`** | _None_ | Display information about the logged-in user |
52
- | **`-V, --version`** | _None_ | Display the current version of the CLI |
53
- | **`-h, --help`** | _None_ | Display available commands and options |
54
- | **`trending`** <br> _(alias: `tr`)_ | `-c (default: 10)` | Fetch trending anime (default count is 10) |
55
- | **`popular`** <br> _(alias: `plr`)_ | `-c (default: 10)` | Fetch popular anime (default count is 10) |
56
- | **`user`** | `<username>` | Get information about a specific AniList user |
57
- | **`lists`** <br> _(alias: `ls`)_ | `-a, --anime` <br> `-m, --manga` | Fetch anime or manga lists of the logged-in user |
58
- | **`delete`** <br> _(alias: `del`)_ | `-a, --anime` <br> `-m, --manga` <br> `-s, --activity` | Delete collections of anime, manga or activities |
59
- | **`upcoming`** <br> _(alias:`up`)_ | `-c (default: 10)` | Fetch upcoming anime (default count is 10) |
60
- | **`anime`** | `<anime-id>` | Get anime details by Anime Id |
61
- | **`search`** <br> _(alias:`srch`/`find`)_ | `<query>` <br> `-a, --anime` <br> `-m, --manga` <br> `-c (default: 10)` | Get anime/manga search results |
62
- | **`status`** <br> _(alias: `write`/`post`)_ | `<status>` | Write a status... (text/markdown/html) |
63
- | **`export`** <br> _(alias: `exp`)_ | `-a, --anime` <br> `-m, --manga` | Export anime or manga list in JSON, CSV or XML (MyAnimeList) |
64
- | **`import`** <br> _(alias: `imp`)_ | `-a, --anime` <br> `-m, --manga` | Import anime or manga list from exported JSON or MyAnimeList (XML) |
47
+ | **Command** | **Options** | **Description** |
48
+ | ------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
49
+ | **`login`** | `-i, --id` `-s, --secret` | Log in with your AniList credentials |
50
+ | **`logout`** | _None_ | Log out from your AniList account |
51
+ | **`whoami`** | _None_ | Display information about the logged-in user |
52
+ | **`-V, --version`** | _None_ | Display the current version of the CLI |
53
+ | **`-h, --help`** | _None_ | Display available commands and options |
54
+ | **`trending`** <br> _(alias: `tr`)_ | `-c (default: 10)` | Fetch trending anime (default count is 10) |
55
+ | **`popular`** <br> _(alias: `plr`)_ | `-c (default: 10)` | Fetch popular anime (default count is 10) |
56
+ | **`user`** | `<username>` | Get information about a specific AniList user |
57
+ | **`lists`** <br> _(alias: `ls`)_ | `-a, --anime` <br> `-m, --manga` | Fetch anime or manga lists of the logged-in user |
58
+ | **`delete`** <br> _(alias: `del`)_ | `-a, --anime` <br> `-m, --manga` <br> `-s, --activity` | Delete collections of anime, manga or activities |
59
+ | **`upcoming`** <br> _(alias:`up`)_ | `-c (default: 10)` | Fetch upcoming anime (default count is 10) |
60
+ | **`anime`** | `<anime-id>` | Get anime details by Anime Id |
61
+ | **`search`** <br> _(alias:`srch`/`find`)_ | `<query>` <br> `-a, --anime` <br> `-m, --manga` <br> `-c (default: 10)` | Get anime/manga search results |
62
+ | **`status`** <br> _(alias: `write`/`post`)_ | `<status>` | Write a status... (text/markdown/html) |
63
+ | **`export`** <br> _(alias: `exp`)_ | `-a, --anime` <br> `-m, --manga` | Export anime or manga list in JSON, CSV or XML (MyAnimeList/AniDB) |
64
+ | **`import`** <br> _(alias: `imp`)_ | `-a, --anime` <br> `-m, --manga` | Import anime or manga list from exported JSON, MyAnimeList (XML) or AniDB (json-large) |
65
65
 
66
66
  #### Command Breakdown:
67
67
 
@@ -213,7 +213,7 @@ anilist export -a
213
213
  - **Options**:
214
214
  - `-a, --anime`: To export anime list.
215
215
  - `-m, --manga`: To export manga list.
216
- - **Description**: Export anime or manga list. For `XML (MyAnimeList)` file, to import it on MyAnimeList, go [here](https://myanimelist.net/import.php) and choose `MyAnimeList Import`.
216
+ - **Description**: Export anime or manga list. For `XML (MyAnimeList/AniDB)` file, to import it on MyAnimeList, go [here](https://myanimelist.net/import.php) and choose `MyAnimeList Import` for `AniDB` go [here](https://anidb.net/user/import) and select `MyAnimeList.net - XML anime list export`.
217
217
 
218
218
  #### `import` _(alias: `imp`)_:
219
219
 
@@ -224,7 +224,10 @@ anilist import -m
224
224
  - **Options**:
225
225
  - `-a, --anime`: To import anime list.
226
226
  - `-m, --manga`: To import manga list.
227
- - **Description**: Import anime or manga list. If you want to import anime/manga list from MyAnimeList, export the XML from [here](https://myanimelist.net/panel.php?go=export).
227
+ - **Description**: Import anime or manga list. If you want to import anime/manga list from `MyAnimeList`, export the XML from [here](https://myanimelist.net/panel.php?go=export), for exporting list from `AniDB` go [here](https://anidb.net/user/export).
228
+
229
+ > [!NOTE]
230
+ > If you have exported from `AniDB`, you will have to unzip it, and there should be a file named `mylist.json`, copy and paste it in your systems download folder, and select it from import option.
228
231
 
229
232
  > [!IMPORTANT]
230
233
  > If you are importing from a file, place the file in the system specific download folder, And the exported file will also be exported there as well.
@@ -14,9 +14,9 @@ import open from "open";
14
14
  import os from "os";
15
15
  import path from "path";
16
16
  import { fetcher } from "./fetcher.js";
17
- import { AniList, MyAnimeList } from "./lists.js";
17
+ import { AniDB, AniList, MyAnimeList } from "./lists.js";
18
18
  import { deleteActivityMutation, saveTextActivityMutation, } from "./mutations.js";
19
- import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, userActivityQuery, } from "./queries.js";
19
+ import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, userActivityQuery, userFollowersQuery, userFollowingQuery, } from "./queries.js";
20
20
  import { aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from "./workers.js";
21
21
  const home_dir = os.homedir();
22
22
  const save_path = path.join(home_dir, ".anilist_token");
@@ -109,7 +109,7 @@ class Auth {
109
109
  }
110
110
  static Myself() {
111
111
  return __awaiter(this, void 0, void 0, function* () {
112
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
112
+ 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;
113
113
  try {
114
114
  if (yield Auth.isLoggedIn()) {
115
115
  const headers = {
@@ -130,30 +130,42 @@ class Auth {
130
130
  perPage: 10,
131
131
  });
132
132
  const activities = (_b = (_a = activiResponse === null || activiResponse === void 0 ? void 0 : activiResponse.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities;
133
+ // Get follower/following information
134
+ const req_followers = yield fetcher(userFollowersQuery, {
135
+ userId: user === null || user === void 0 ? void 0 : user.id,
136
+ });
137
+ const req_following = yield fetcher(userFollowingQuery, {
138
+ userId: user === null || user === void 0 ? void 0 : user.id,
139
+ });
140
+ 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;
141
+ 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;
133
142
  console.log(`
134
143
  ID: ${user === null || user === void 0 ? void 0 : user.id}
135
144
  Name: ${user === null || user === void 0 ? void 0 : user.name}
136
145
  siteUrl: ${user === null || user === void 0 ? void 0 : user.siteUrl}
137
- profileColor: ${(_c = user === null || user === void 0 ? void 0 : user.options) === null || _c === void 0 ? void 0 : _c.profileColor}
138
- timeZone: ${(_d = user === null || user === void 0 ? void 0 : user.options) === null || _d === void 0 ? void 0 : _d.timezone}
139
- activityMergeTime: ${(_e = user === null || user === void 0 ? void 0 : user.options) === null || _e === void 0 ? void 0 : _e.activityMergeTime}
146
+ profileColor: ${(_j = user === null || user === void 0 ? void 0 : user.options) === null || _j === void 0 ? void 0 : _j.profileColor}
147
+ timeZone: ${(_k = user === null || user === void 0 ? void 0 : user.options) === null || _k === void 0 ? void 0 : _k.timezone}
148
+ activityMergeTime: ${(_l = user === null || user === void 0 ? void 0 : user.options) === null || _l === void 0 ? void 0 : _l.activityMergeTime}
140
149
  donatorTier: ${user === null || user === void 0 ? void 0 : user.donatorTier}
141
150
  donatorBadge: ${user === null || user === void 0 ? void 0 : user.donatorBadge}
142
151
  unreadNotificationCount:${user === null || user === void 0 ? void 0 : user.unreadNotificationCount}
143
152
  Account Created: ${new Date((user === null || user === void 0 ? void 0 : user.createdAt) * 1000).toUTCString()}
144
153
  Account Updated: ${new Date((user === null || user === void 0 ? void 0 : user.updatedAt) * 1000).toUTCString()}
154
+
155
+ Followers: ${followersCount}
156
+ Following: ${followingCount}
145
157
 
146
158
  Statistics (Anime):
147
- Count: ${(_g = (_f = user === null || user === void 0 ? void 0 : user.statistics) === null || _f === void 0 ? void 0 : _f.anime) === null || _g === void 0 ? void 0 : _g.count}
148
- Mean Score: ${(_j = (_h = user === null || user === void 0 ? void 0 : user.statistics) === null || _h === void 0 ? void 0 : _h.anime) === null || _j === void 0 ? void 0 : _j.meanScore}
149
- Minutes Watched: ${(_l = (_k = user === null || user === void 0 ? void 0 : user.statistics) === null || _k === void 0 ? void 0 : _k.anime) === null || _l === void 0 ? void 0 : _l.minutesWatched}
150
- Episodes Watched: ${(_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.episodesWatched}
159
+ 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}
160
+ 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}
161
+ 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}
162
+ 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}
151
163
 
152
164
  Statistics (Manga):
153
- Count: ${(_q = (_p = user === null || user === void 0 ? void 0 : user.statistics) === null || _p === void 0 ? void 0 : _p.manga) === null || _q === void 0 ? void 0 : _q.count}
154
- Mean Score: ${(_s = (_r = user === null || user === void 0 ? void 0 : user.statistics) === null || _r === void 0 ? void 0 : _r.manga) === null || _s === void 0 ? void 0 : _s.meanScore}
155
- Chapters Read: ${(_u = (_t = user === null || user === void 0 ? void 0 : user.statistics) === null || _t === void 0 ? void 0 : _t.manga) === null || _u === void 0 ? void 0 : _u.chaptersRead}
156
- Volumes Read: ${(_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.volumesRead}
165
+ 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}
166
+ 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}
167
+ 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}
168
+ 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}
157
169
  `);
158
170
  console.log(`\nRecent Activities:`);
159
171
  if (activities.length > 0) {
@@ -528,6 +540,7 @@ Statistics (Manga):
528
540
  choices: [
529
541
  { name: "Exported JSON file.", value: 1 },
530
542
  { name: "MyAnimeList (XML)", value: 2 },
543
+ { name: "AniDB (json-large)", value: 3 },
531
544
  ],
532
545
  pageSize: 10,
533
546
  },
@@ -539,6 +552,9 @@ Statistics (Manga):
539
552
  case 2:
540
553
  yield MyAnimeList.importAnime();
541
554
  break;
555
+ case 3:
556
+ yield AniDB.importAnime();
557
+ break;
542
558
  default:
543
559
  console.log(`\nInvalid Choice.`);
544
560
  break;
@@ -19,4 +19,7 @@ declare class MyAnimeList {
19
19
  static exportAnime(): Promise<void>;
20
20
  static exportManga(): Promise<void>;
21
21
  }
22
- export { AniList, MyAnimeList };
22
+ declare class AniDB {
23
+ static importAnime(): Promise<void>;
24
+ }
25
+ export { AniDB, AniList, MyAnimeList };
@@ -10,13 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { XMLParser } from "fast-xml-parser";
11
11
  import { readFile, writeFile } from "fs/promises";
12
12
  import inquirer from "inquirer";
13
+ import { jsonrepair } from "jsonrepair";
14
+ import open from "open";
13
15
  import { join } from "path";
14
16
  import { Auth } from "./auth.js";
15
17
  import { fetcher } from "./fetcher.js";
16
18
  import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, } from "./mutations.js";
17
- import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userQuery, } from "./queries.js";
19
+ import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
18
20
  import { AniListMediaStatus, } from "./types.js";
19
- import { createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, } from "./workers.js";
21
+ import { anidbToanilistMapper, createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, } from "./workers.js";
20
22
  class AniList {
21
23
  static importAnime() {
22
24
  return __awaiter(this, void 0, void 0, function* () {
@@ -121,7 +123,7 @@ class AniList {
121
123
  choices: [
122
124
  { name: "CSV", value: 1 },
123
125
  { name: "JSON", value: 2 },
124
- { name: "XML (MyAnimeList)", value: 3 },
126
+ { name: "XML (MyAnimeList/AniDB)", value: 3 },
125
127
  ],
126
128
  pageSize: 10,
127
129
  },
@@ -612,7 +614,7 @@ class AniList {
612
614
  }
613
615
  static getUserByUsername(username) {
614
616
  return __awaiter(this, void 0, void 0, function* () {
615
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
617
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
616
618
  try {
617
619
  const response = yield fetcher(userQuery, { username });
618
620
  if (!((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User)) {
@@ -625,6 +627,15 @@ class AniList {
625
627
  perPage: 10,
626
628
  });
627
629
  const activities = (_f = (_e = (_d = userActivityResponse === null || userActivityResponse === void 0 ? void 0 : userActivityResponse.data) === null || _d === void 0 ? void 0 : _d.Page) === null || _e === void 0 ? void 0 : _e.activities) !== null && _f !== void 0 ? _f : [];
630
+ // Get follower/following information
631
+ const req_followers = yield fetcher(userFollowersQuery, {
632
+ userId: user === null || user === void 0 ? void 0 : user.id,
633
+ });
634
+ const req_following = yield fetcher(userFollowingQuery, {
635
+ userId: user === null || user === void 0 ? void 0 : user.id,
636
+ });
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;
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;
628
639
  console.log(`\nID:\t\t${user.id}`);
629
640
  console.log(`Name:\t\t${user.name}`);
630
641
  console.log(`Site URL:\t${user.siteUrl}`);
@@ -635,10 +646,12 @@ class AniList {
635
646
  console.log(`Blocked:\t${user.isBlocked}`);
636
647
  console.log(`Follower:\t${user.isFollower}`);
637
648
  console.log(`Following:\t${user.isFollowing}`);
638
- console.log(`Profile Color:\t${(_g = user.options) === null || _g === void 0 ? void 0 : _g.profileColor}`);
639
- console.log(`Timezone:\t${(_h = user.options) === null || _h === void 0 ? void 0 : _h.timezone}`);
640
- console.log(`\nStatistics (Anime)\nCount: ${((_k = (_j = user.statistics) === null || _j === void 0 ? void 0 : _j.anime) === null || _k === void 0 ? void 0 : _k.count) || 0} Episodes Watched: ${((_m = (_l = user.statistics) === null || _l === void 0 ? void 0 : _l.anime) === null || _m === void 0 ? void 0 : _m.episodesWatched) || 0} Minutes Watched: ${((_p = (_o = user.statistics) === null || _o === void 0 ? void 0 : _o.anime) === null || _p === void 0 ? void 0 : _p.minutesWatched) || 0}`);
641
- console.log(`Statistics (Manga)\nCount: ${((_r = (_q = user.statistics) === null || _q === void 0 ? void 0 : _q.manga) === null || _r === void 0 ? void 0 : _r.count) || 0} Chapters Read: ${((_t = (_s = user.statistics) === null || _s === void 0 ? void 0 : _s.manga) === null || _t === void 0 ? void 0 : _t.chaptersRead) || 0} Volumes Read: ${((_v = (_u = user.statistics) === null || _u === void 0 ? void 0 : _u.manga) === null || _v === void 0 ? void 0 : _v.volumesRead) || 0}`);
649
+ console.log(`Profile Color:\t${(_o = user.options) === null || _o === void 0 ? void 0 : _o.profileColor}`);
650
+ 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"}`);
651
+ console.log(`\nFollowers:\t${followersCount}`);
652
+ console.log(`Following:\t${followingCount}`);
653
+ 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}`);
654
+ console.log(`Statistics (Manga)\n\tCount: ${((_y = (_x = user.statistics) === null || _x === void 0 ? void 0 : _x.manga) === null || _y === void 0 ? void 0 : _y.count) || 0}\tChapters Read: ${((_0 = (_z = user.statistics) === null || _z === void 0 ? void 0 : _z.manga) === null || _0 === void 0 ? void 0 : _0.chaptersRead) || 0}\tVolumes Read: ${((_2 = (_1 = user.statistics) === null || _1 === void 0 ? void 0 : _1.manga) === null || _2 === void 0 ? void 0 : _2.volumesRead) || 0}`);
642
655
  if (activities.length > 0) {
643
656
  console.log(`\nRecent Activities:`);
644
657
  activities.forEach(({ status, progress, media, createdAt }) => {
@@ -1008,4 +1021,92 @@ class MyAnimeList {
1008
1021
  });
1009
1022
  }
1010
1023
  }
1011
- export { AniList, MyAnimeList };
1024
+ class AniDB {
1025
+ static importAnime() {
1026
+ return __awaiter(this, void 0, void 0, function* () {
1027
+ var _a, _b;
1028
+ try {
1029
+ const filename = yield selectFile(".json");
1030
+ const filePath = join(getDownloadFolderPath(), filename);
1031
+ const fileContent = yield readFile(filePath, "utf8");
1032
+ const js0n_repaired = jsonrepair(fileContent);
1033
+ if (fileContent) {
1034
+ const obj3ct = yield JSON.parse(js0n_repaired);
1035
+ const animeList = obj3ct === null || obj3ct === void 0 ? void 0 : obj3ct.anime;
1036
+ if ((animeList === null || animeList === void 0 ? void 0 : animeList.length) > 0) {
1037
+ let count = 0;
1038
+ let iteration = 0;
1039
+ let missed = [];
1040
+ for (const anime of animeList) {
1041
+ iteration++;
1042
+ const anidbId = anime.id;
1043
+ const released = anime.broadcastDate; // DD-MM-YYYY (eg: "23.07.2016")
1044
+ const status = anime.status;
1045
+ // const type = anime.type
1046
+ const totalEpisodes = anime.totalEpisodes;
1047
+ const ownEpisodes = anime.ownEpisodes;
1048
+ const romanjiName = anime.romanjiName;
1049
+ const englishName = anime.englishName;
1050
+ function getStatus(anidbStatus, episodesSeen) {
1051
+ if (anidbStatus === "complete") {
1052
+ return AniListMediaStatus.COMPLETED;
1053
+ }
1054
+ else if (anidbStatus === "incomplete" &&
1055
+ Number(episodesSeen) > 0) {
1056
+ return AniListMediaStatus.CURRENT;
1057
+ }
1058
+ else {
1059
+ return AniListMediaStatus.PLANNING;
1060
+ }
1061
+ }
1062
+ let anilistId = yield anidbToanilistMapper(romanjiName, Number(released.split(".")[2]), englishName);
1063
+ if (anilistId) {
1064
+ try {
1065
+ const saveResponse = yield fetcher(saveAnimeWithProgressMutation, {
1066
+ mediaId: anilistId,
1067
+ progress: ownEpisodes - 2,
1068
+ status: getStatus(status, ownEpisodes),
1069
+ hiddenFromStatusLists: false,
1070
+ private: false,
1071
+ });
1072
+ 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;
1073
+ if (entryId) {
1074
+ count++;
1075
+ console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}→${getStatus(status, ownEpisodes)}`);
1076
+ }
1077
+ // Rate limit each API call to avoid server overload
1078
+ // await new Promise((resolve) => setTimeout(resolve, 1100))
1079
+ }
1080
+ catch (error) {
1081
+ console.error(`Error processing AniDB ID ${anidbId}: ${error.message}`);
1082
+ }
1083
+ }
1084
+ else {
1085
+ missed.push({
1086
+ anidbId: anidbId,
1087
+ englishTitle: englishName,
1088
+ romajiTitle: romanjiName,
1089
+ });
1090
+ }
1091
+ }
1092
+ console.log(`\nAccuracy: ${(((animeList.length - missed.length) / animeList.length) * 100).toFixed(2)}%\tTotal Processed: ${iteration}\tMissed: ${missed.length}`);
1093
+ if (missed.length > 0) {
1094
+ console.log(`Exporting missed entries to JSON file, Please add them manually.`);
1095
+ yield saveJSONasJSON(missed, "anidb-missed");
1096
+ }
1097
+ }
1098
+ else {
1099
+ console.log(`\nNo anime list found in the file.`);
1100
+ }
1101
+ }
1102
+ else {
1103
+ console.log(`\nNo content found in the file or unable to read.`);
1104
+ }
1105
+ }
1106
+ catch (error) {
1107
+ console.error(`\nError in AniDB import process: ${error.message}`);
1108
+ }
1109
+ });
1110
+ }
1111
+ }
1112
+ export { AniDB, AniList, MyAnimeList };
@@ -9,7 +9,7 @@ declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaLis
9
9
  declare const upcomingAnimesQuery = "query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {\n Page(perPage: $perPage) {\n media(season: $nextSeason, seasonYear: $nextYear, type: ANIME, sort: POPULARITY_DESC) {\n id title { romaji english native userPreferred } season seasonYear startDate { year month day }\n episodes description genres\n }\n }\n}";
10
10
  declare const animeDetailsQuery = "query ($id: Int) {\n Media(id: $id) {\n id idMal title { romaji english native userPreferred } episodes nextAiringEpisode { id }\n duration startDate { year month day } endDate { year month day } countryOfOrigin description isAdult status season format genres siteUrl\n stats { scoreDistribution { score amount } statusDistribution { status amount } }\n }\n}";
11
11
  declare const userActivityQuery = "query ($id: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $id, type_in: [ANIME_LIST, MANGA_LIST], sort: ID_DESC) {\n ... on ListActivity { id status progress createdAt media { id title { romaji english } } }\n }\n }\n}";
12
- declare const animeSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: ANIME) { id title { romaji english native userPreferred } episodes status description }\n }\n}";
12
+ declare const animeSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: ANIME) { id title { romaji english native userPreferred } startDate { day month year } episodes status description }\n }\n}";
13
13
  declare const mangaSearchQuery = "query ($search: String, $perPage: Int) {\n Page(perPage: $perPage) {\n media(search: $search, type: MANGA) { id title { romaji english native userPreferred } chapters status description }\n }\n}";
14
14
  declare const activityTextQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: TEXT, sort: ID_DESC) {\n ... on TextActivity { id type text createdAt user { id name } }\n }\n }\n}";
15
15
  declare const activityAnimeListQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: ANIME_LIST, sort: ID_DESC) {\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n }\n }\n}";
@@ -19,4 +19,6 @@ declare const activityAllQuery = "query ($userId: Int, $page: Int, $perPage: Int
19
19
  declare const activityMediaList = "query ($userId: Int, $page: Int, $perPage: Int, $type: ActivityType) {\n Page(page: $page, perPage: $perPage) {\n pageInfo { total currentPage lastPage hasNextPage perPage }\n activities(userId: $userId, type: $type, sort: ID_DESC) {\n ... on ListActivity { id type status progress media { id title { romaji english native } format } createdAt }\n }\n }\n}";
20
20
  declare const malIdToAnilistAnimeId = "query ($malId: Int) {\n Media(idMal: $malId, type: ANIME) {\n id title { romaji english } } \n}\n";
21
21
  declare const malIdToAnilistMangaId = "query ($malId: Int) {\n Media(idMal: $malId, type: MANGA) {\n id title { romaji english } } \n}\n";
22
- export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userQuery, };
22
+ declare const userFollowingQuery = "query ($userId: Int!) {\n Page {\n pageInfo { total perPage currentPage lastPage hasNextPage }\n following(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage }\n }\n}\n";
23
+ declare const userFollowersQuery = "query ($userId: Int!) {\n Page {\n pageInfo { total perPage currentPage lastPage hasNextPage }\n followers(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage }\n }\n}\n";
24
+ export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
@@ -66,7 +66,7 @@ const userActivityQuery = `query ($id: Int, $page: Int, $perPage: Int) {
66
66
  }`;
67
67
  const animeSearchQuery = `query ($search: String, $perPage: Int) {
68
68
  Page(perPage: $perPage) {
69
- media(search: $search, type: ANIME) { id title { romaji english native userPreferred } episodes status description }
69
+ media(search: $search, type: ANIME) { id title { romaji english native userPreferred } startDate { day month year } episodes status description }
70
70
  }
71
71
  }`;
72
72
  const mangaSearchQuery = `query ($search: String, $perPage: Int) {
@@ -129,4 +129,18 @@ const malIdToAnilistMangaId = `query ($malId: Int) {
129
129
  id title { romaji english } }
130
130
  }
131
131
  `;
132
- export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userQuery, };
132
+ const userFollowingQuery = `query ($userId: Int!) {
133
+ Page {
134
+ pageInfo { total perPage currentPage lastPage hasNextPage }
135
+ following(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage }
136
+ }
137
+ }
138
+ `;
139
+ const userFollowersQuery = `query ($userId: Int!) {
140
+ Page {
141
+ pageInfo { total perPage currentPage lastPage hasNextPage }
142
+ followers(userId: $userId, sort: [USERNAME]) { id name avatar { large medium } bannerImage }
143
+ }
144
+ }
145
+ `;
146
+ export { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, deleteMangaEntryMutation, deleteMediaEntryMutation, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, };
@@ -171,9 +171,9 @@ interface Myself {
171
171
  }[];
172
172
  }
173
173
  interface DateMonthYear {
174
- day?: string;
175
- month?: string;
176
- year?: string;
174
+ day?: number;
175
+ month?: number;
176
+ year?: number;
177
177
  }
178
178
  interface AnimeDetails {
179
179
  data?: {
@@ -212,4 +212,123 @@ interface MediaListEntry {
212
212
  hiddenFromStatusLists?: boolean;
213
213
  private?: boolean;
214
214
  }
215
- export { AniListMediaStatus, AnimeDetails, AnimeList, DateMonthYear, DeleteMangaResponse, List, MALAnimeStatus, MALAnimeXML, MALMangaStatus, MalIdToAnilistIdResponse, MediaEntry, MediaList, MediaListEntry, MediaTitle, MediaWithProgress, Myself, saveAnimeWithProgressResponse, };
215
+ type UserActivitiesResponse = {
216
+ data?: {
217
+ Page: {
218
+ activities: {
219
+ status: string;
220
+ progress: number;
221
+ createdAt: number;
222
+ media: {
223
+ title: MediaTitle;
224
+ };
225
+ }[];
226
+ };
227
+ };
228
+ errors?: {
229
+ message: string;
230
+ }[];
231
+ };
232
+ type UserResponse = {
233
+ data?: {
234
+ User: {
235
+ id: number;
236
+ name: string;
237
+ siteUrl: string;
238
+ donatorTier: string;
239
+ donatorBadge: string;
240
+ createdAt: number;
241
+ updatedAt: number;
242
+ isBlocked: boolean;
243
+ isFollower: boolean;
244
+ isFollowing: boolean;
245
+ options: {
246
+ profileColor: string;
247
+ timezone: string;
248
+ };
249
+ statistics: {
250
+ anime: {
251
+ count: number;
252
+ episodesWatched: number;
253
+ minutesWatched: number;
254
+ };
255
+ manga: {
256
+ count: number;
257
+ chaptersRead: number;
258
+ volumesRead: number;
259
+ };
260
+ };
261
+ };
262
+ };
263
+ errors?: {
264
+ message: string;
265
+ }[];
266
+ };
267
+ type UserFollower = {
268
+ data?: {
269
+ Page: {
270
+ pageInfo: {
271
+ total: number;
272
+ perPage: number;
273
+ currentPage: number;
274
+ lastPage: number;
275
+ hasNextPage: boolean;
276
+ };
277
+ followers: {
278
+ id: number;
279
+ name: string;
280
+ avatar: {
281
+ large: string;
282
+ medium: string;
283
+ };
284
+ bannerImage: string;
285
+ }[];
286
+ };
287
+ };
288
+ errors?: {
289
+ message: string;
290
+ }[];
291
+ };
292
+ type UserFollowing = {
293
+ data?: {
294
+ Page: {
295
+ pageInfo: {
296
+ total: number;
297
+ perPage: number;
298
+ currentPage: number;
299
+ lastPage: number;
300
+ hasNextPage: boolean;
301
+ };
302
+ following: {
303
+ id: number;
304
+ name: string;
305
+ avatar: {
306
+ large: string;
307
+ medium: string;
308
+ };
309
+ bannerImage: string;
310
+ }[];
311
+ };
312
+ };
313
+ errors?: {
314
+ message: string;
315
+ }[];
316
+ };
317
+ type AnimeSearchResponse = {
318
+ data?: {
319
+ Page: {
320
+ media: {
321
+ id: number;
322
+ title: MediaTitle;
323
+ startDate: DateMonthYear;
324
+ episodes: number;
325
+ status: string;
326
+ description: string;
327
+ }[];
328
+ };
329
+ };
330
+ errors?: {
331
+ message: string;
332
+ }[];
333
+ };
334
+ export { AniListMediaStatus, AnimeDetails, AnimeList, AnimeSearchResponse, DateMonthYear, DeleteMangaResponse, List, MALAnimeStatus, MALAnimeXML, MALMangaStatus, MalIdToAnilistIdResponse, MediaEntry, MediaList, MediaListEntry, MediaTitle, MediaWithProgress, Myself, UserActivitiesResponse, UserFollower, UserFollowing, UserResponse, saveAnimeWithProgressResponse, };
@@ -6,9 +6,9 @@ declare function getTitle(title: {
6
6
  romaji?: string;
7
7
  }): string;
8
8
  declare function formatDateObject(dateObj: {
9
- day?: string;
10
- month?: string;
11
- year?: string;
9
+ day?: number;
10
+ month?: number;
11
+ year?: number;
12
12
  } | null): string;
13
13
  declare function getNextSeasonAndYear(): {
14
14
  nextSeason: string;
@@ -36,4 +36,5 @@ declare function createAnimeListXML(mediaWithProgress: MediaWithProgress[]): Pro
36
36
  declare function createMangaListXML(mediaWithProgress: MediaWithProgress[]): Promise<string>;
37
37
  declare function getCurrentPackageVersion(): string | null;
38
38
  declare function timestampToTimeAgo(timestamp: number): string;
39
- export { aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
39
+ declare const anidbToanilistMapper: (romanjiName: string, year: number, englishName?: string) => Promise<number | null>;
40
+ export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
@@ -17,7 +17,9 @@ import { homedir } from "os";
17
17
  import { join } from "path";
18
18
  import process from "process";
19
19
  import { Auth } from "./auth.js";
20
- import { MALAnimeStatus, MALMangaStatus } from "./types.js";
20
+ import { fetcher } from "./fetcher.js";
21
+ import { animeSearchQuery } from "./queries.js";
22
+ import { MALAnimeStatus, MALMangaStatus, } from "./types.js";
21
23
  const aniListEndpoint = `https://graphql.anilist.co`;
22
24
  const redirectUri = "https://anilist.co/api/v2/oauth/pin";
23
25
  function getTitle(title) {
@@ -314,4 +316,33 @@ function timestampToTimeAgo(timestamp) {
314
316
  return `${years} year${years === 1 ? "" : "s"} ago`;
315
317
  }
316
318
  }
317
- export { aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
319
+ const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void 0, void 0, void 0, function* () {
320
+ const fetchAnime = (search) => __awaiter(void 0, void 0, void 0, function* () {
321
+ var _a;
322
+ try {
323
+ const response = yield fetcher(animeSearchQuery, {
324
+ search,
325
+ perPage: 50,
326
+ });
327
+ return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.Page.media) || [];
328
+ }
329
+ catch (error) {
330
+ console.error("Error fetching AniList data:", error);
331
+ return [];
332
+ }
333
+ });
334
+ // Search using romanjiName first
335
+ let results = yield fetchAnime(romanjiName);
336
+ // If no results, fallback to englishName
337
+ if (!results.length && englishName) {
338
+ results = yield fetchAnime(englishName);
339
+ }
340
+ // Match using year
341
+ for (const anime of results) {
342
+ if (anime.startDate.year === year) {
343
+ return anime.id;
344
+ }
345
+ }
346
+ return null;
347
+ });
348
+ export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
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.2.4",
5
+ "version": "1.2.5",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -54,10 +54,12 @@
54
54
  },
55
55
  "license": "MPL-2.0",
56
56
  "devDependencies": {
57
+ "@babel/preset-env": "^7.26.0",
57
58
  "@eslint/js": "^9.17.0",
58
59
  "@types/jest": "^29.5.14",
59
60
  "@types/json2csv": "^5.0.7",
60
61
  "@types/node": "^22.10.5",
62
+ "@typescript-eslint/eslint-plugin": "^8.19.0",
61
63
  "eslint": "^9.17.0",
62
64
  "globals": "^15.14.0",
63
65
  "jest": "^29.7.0",
@@ -65,15 +67,14 @@
65
67
  "prettier-plugin-organize-imports": "^4.1.0",
66
68
  "ts-jest": "^29.2.5",
67
69
  "ts-node": "^10.9.2",
68
- "typescript": "^5.7.2",
69
- "@babel/preset-env": "^7.26.0",
70
- "@typescript-eslint/eslint-plugin": "^8.19.0"
70
+ "typescript": "^5.7.2"
71
71
  },
72
72
  "dependencies": {
73
73
  "commander": "^13.0.0",
74
74
  "fast-xml-parser": "^4.5.1",
75
75
  "inquirer": "^12.3.0",
76
76
  "json2csv": "^6.0.0-alpha.2",
77
+ "jsonrepair": "^3.11.2",
77
78
  "node-fetch": "^3.3.2",
78
79
  "open": "^10.1.0"
79
80
  }