@irfanshadikrishad/anilist 1.2.6 → 1.2.8

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,25 +44,25 @@ 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/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
- | \*\*`social` <br> _(alias: `sol`)_ | `-f, --follow` <br> `-u, --unfollow` | Follow users who follows you or Unfollow who doesn't follow you back with a simple command |
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
+ | `social` <br> _(alias: `sol`)_ | `-f, --follow` <br> `-u, --unfollow` | Follow users who follows you or Unfollow who doesn't follow you back with a simple command |
66
66
 
67
67
  #### Command Breakdown:
68
68
 
@@ -72,10 +72,10 @@ anilist login -i <client-id> -s <client-secret>
72
72
  anilist login -i <client-id> -s <client-secret>
73
73
  ```
74
74
 
75
- - **Options**:
75
+ - Options:
76
76
  - `-i, --id`: Specify AniList Client ID
77
77
  - `-s, --secret`: Provide the AniList Client Secret
78
- - **Usage**: Authenticate and log in to AniList using your ID and secret credentials.
78
+ - Usage: Authenticate and log in to AniList using your ID and secret credentials.
79
79
 
80
80
  #### `logout`:
81
81
 
@@ -83,7 +83,7 @@ anilist login -i <client-id> -s <client-secret>
83
83
  anilist logout
84
84
  ```
85
85
 
86
- - **Description**: End the current session and log out from your AniList account.
86
+ - Description: End the current session and log out from your AniList account.
87
87
 
88
88
  #### `me`:
89
89
 
@@ -91,7 +91,7 @@ anilist logout
91
91
  anilist me
92
92
  ```
93
93
 
94
- - **Description**: Retrieve and display information about the currently logged-in user, including stats and profile details.
94
+ - Description: Retrieve and display information about the currently logged-in user, including stats and profile details.
95
95
 
96
96
  #### `-V, --version`:
97
97
 
@@ -99,7 +99,7 @@ anilist me
99
99
  anilist -V
100
100
  ```
101
101
 
102
- - **Description**: Quickly check which version of the CLI you are running.
102
+ - Description: Quickly check which version of the CLI you are running.
103
103
 
104
104
  #### `-h, --help`:
105
105
 
@@ -107,7 +107,7 @@ anilist -V
107
107
  anilist -h
108
108
  ```
109
109
 
110
- - **Description**: List all available commands and their usage details for quick reference.
110
+ - Description: List all available commands and their usage details for quick reference.
111
111
 
112
112
  #### `trending` _(alias: `tr`)_:
113
113
 
@@ -115,9 +115,9 @@ anilist -h
115
115
  anilist tr -c 15
116
116
  ```
117
117
 
118
- - **Options**:
118
+ - Options:
119
119
  - `-c (count)`: Specify how many trending anime to fetch (default: 10).
120
- - **Description**: Fetch the current trending anime series, with the option to customize how many results to display.
120
+ - Description: Fetch the current trending anime series, with the option to customize how many results to display.
121
121
 
122
122
  #### `popular` _(alias: `plr`)_:
123
123
 
@@ -125,9 +125,9 @@ anilist tr -c 15
125
125
  anilist popular
126
126
  ```
127
127
 
128
- - **Options**:
128
+ - Options:
129
129
  - `-c (count)`: Specify how many popular anime to fetch (default: 10).
130
- - **Description**: Fetch the most popular anime series, with the option to customize how many results to display.
130
+ - Description: Fetch the most popular anime series, with the option to customize how many results to display.
131
131
 
132
132
  #### `upcoming` _(alias: `up`)_:
133
133
 
@@ -135,9 +135,9 @@ anilist popular
135
135
  anilist up -c 25
136
136
  ```
137
137
 
138
- - **Options**:
138
+ - Options:
139
139
  - `-c (count)`: Specify how many upcoming anime to fetch (default: 10).
140
- - **Description**: Fetch the upcoming anime series next season, with the option to customize how many results to display.
140
+ - Description: Fetch the upcoming anime series next season, with the option to customize how many results to display.
141
141
 
142
142
  #### `user`:
143
143
 
@@ -145,9 +145,9 @@ anilist up -c 25
145
145
  anilist user <username>
146
146
  ```
147
147
 
148
- - **Options**:
148
+ - Options:
149
149
  - `<username>`: Specify the AniList username to fetch.
150
- - **Description**: Retrieve profile information about a specific AniList user.
150
+ - Description: Retrieve profile information about a specific AniList user.
151
151
 
152
152
  #### `lists` _(alias: `ls`)_:
153
153
 
@@ -155,10 +155,10 @@ anilist user <username>
155
155
  anilist ls -a
156
156
  ```
157
157
 
158
- - **Options**:
158
+ - Options:
159
159
  - `-a, --anime`: Fetch the authenticated user's anime list.
160
160
  - `-m, --manga`: Fetch the authenticated user's manga list.
161
- - **Description**: Get the anime or manga lists of the logged-in user.
161
+ - Description: Get the anime or manga lists of the logged-in user.
162
162
 
163
163
  #### `delete` _(alias: `del`)_:
164
164
 
@@ -166,11 +166,11 @@ anilist ls -a
166
166
  anilist del -ac
167
167
  ```
168
168
 
169
- - **Options**:
169
+ - Options:
170
170
  - `-a, --anime`: Delete your specific anime collection that you want.
171
171
  - `-m, --manga`: Delete your specific manga collection that you want.
172
172
  - `-ac, --activity`: Delete all or any type of activities you want.
173
- - **Description**: Delete the entire anime or manga collection from the logged-in user's profile.
173
+ - Description: Delete the entire anime or manga collection from the logged-in user's profile.
174
174
 
175
175
  #### `anime`
176
176
 
@@ -178,9 +178,9 @@ anilist del -ac
178
178
  anilist anime <anime-id>
179
179
  ```
180
180
 
181
- - **Options**
181
+ - Options
182
182
  - `<anime-id>` _(eg: 21)_ : Id of the anime you want to get details of.
183
- - **Description**: Get anime details by anime Id.
183
+ - Description: Get anime details by anime Id.
184
184
 
185
185
  #### `search` _(alias: `srch`/`find`)_:
186
186
 
@@ -188,12 +188,12 @@ anilist anime <anime-id>
188
188
  anilist search <query> -a -c 20
189
189
  ```
190
190
 
191
- - **Options**:
191
+ - Options:
192
192
  - `<query>` : What you want to search (eg: naruto).
193
193
  - `-a, --anime`: To get results of anime search.
194
194
  - `-m, --manga`: To get results of manga search.
195
195
  - `-c (count)`: Specify how many items to fetch (default: 10).
196
- - **Description**: Get anime/manga search results
196
+ - Description: Get anime/manga search results
197
197
 
198
198
  #### `status` _(alias: `write`/`post`)_:
199
199
 
@@ -201,9 +201,9 @@ anilist search <query> -a -c 20
201
201
  anilist write <status>
202
202
  ```
203
203
 
204
- - **Options**:
204
+ - Options:
205
205
  - `<status>` : This is what you want to write, It can be HTML, Markdown and/or Text. But wrap it with quotation mark (") else it might get cut-off.
206
- - **Description**: Get anime/manga search results
206
+ - Description: Get anime/manga search results
207
207
 
208
208
  #### `export` _(alias: `exp`)_:
209
209
 
@@ -211,10 +211,10 @@ anilist write <status>
211
211
  anilist export -a
212
212
  ```
213
213
 
214
- - **Options**:
214
+ - Options:
215
215
  - `-a, --anime`: To export anime list.
216
216
  - `-m, --manga`: To export manga list.
217
- - **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
+ - 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`.
218
218
 
219
219
  #### `import` _(alias: `imp`)_:
220
220
 
@@ -222,10 +222,10 @@ anilist export -a
222
222
  anilist import -m
223
223
  ```
224
224
 
225
- - **Options**:
225
+ - Options:
226
226
  - `-a, --anime`: To import anime list.
227
227
  - `-m, --manga`: To import manga list.
228
- - **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
+ - 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).
229
229
 
230
230
  > [!NOTE]
231
231
  > 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.
@@ -239,10 +239,10 @@ anilist import -m
239
239
  anilist sol -f
240
240
  ```
241
241
 
242
- - **Options**:
242
+ - Options:
243
243
  - `-f, --follow`: To follow users who follows you automatically.
244
244
  - `-u, --unfollow`: To unfollow users who doesn't follow you back.
245
- - **Description**: It follows users who follows you or unfollow users who doesn't follow you back at ease.
245
+ - Description: It follows users who follows you or unfollow users who doesn't follow you back at ease.
246
246
 
247
247
  #### Security
248
248
 
@@ -252,4 +252,4 @@ Since you are creating your own API client for login no else else can get your c
252
252
 
253
253
  Want to contribute to the project? Check out complete guideline [here](CONTRIBUTING.md).
254
254
 
255
- #### **_Thanks for visiting 💙_**
255
+ #### _Thanks for visiting 💙_
@@ -18,15 +18,23 @@ import { fetcher } from "./fetcher.js";
18
18
  import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMutation, saveMangaWithProgressMutation, } from "./mutations.js";
19
19
  import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
20
20
  import { AniListMediaStatus, } from "./types.js";
21
+ import { Validate } from "./validation.js";
21
22
  import { anidbToanilistMapper, createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, } from "./workers.js";
22
23
  class AniList {
23
24
  static importAnime() {
24
25
  return __awaiter(this, void 0, void 0, function* () {
25
26
  try {
26
27
  const filename = yield selectFile(".json");
28
+ if (!filename) {
29
+ return;
30
+ }
27
31
  const filePath = join(getDownloadFolderPath(), filename);
28
32
  const fileContent = yield readFile(filePath, "utf8");
29
33
  const importedData = JSON.parse(fileContent);
34
+ if (!Validate.Import_JSON(importedData)) {
35
+ console.error(`\nInvalid JSON file.`);
36
+ return;
37
+ }
30
38
  let count = 0;
31
39
  const batchSize = 1; // Number of requests in each batch
32
40
  const delay = 1100; // delay to avoid rate-limiting
@@ -70,9 +78,16 @@ class AniList {
70
78
  return __awaiter(this, void 0, void 0, function* () {
71
79
  try {
72
80
  const filename = yield selectFile(".json");
81
+ if (!filename) {
82
+ return;
83
+ }
73
84
  const filePath = join(getDownloadFolderPath(), filename);
74
85
  const fileContent = yield readFile(filePath, "utf8");
75
86
  const importedData = JSON.parse(fileContent);
87
+ if (!Validate.Import_JSON(importedData)) {
88
+ console.error(`\nInvalid JSON file.`);
89
+ return;
90
+ }
76
91
  let count = 0;
77
92
  const batchSize = 1; // Adjust batch size as per rate-limit constraints
78
93
  const delay = 1100; // 2 seconds delay to avoid rate-limit
@@ -813,8 +828,15 @@ class MyAnimeList {
813
828
  var _a, _b, _c, _d, _e;
814
829
  try {
815
830
  const filename = yield selectFile(".xml");
831
+ if (!filename) {
832
+ return;
833
+ }
816
834
  const filePath = join(getDownloadFolderPath(), filename);
817
835
  const fileContent = yield readFile(filePath, "utf8");
836
+ if (!(yield Validate.Import_AnimeXML(fileContent))) {
837
+ console.error(`\nInvalid XML file.`);
838
+ return;
839
+ }
818
840
  const parser = new XMLParser();
819
841
  if (fileContent) {
820
842
  const XMLObject = parser.parse(fileContent);
@@ -878,8 +900,15 @@ class MyAnimeList {
878
900
  var _a, _b, _c, _d, _e;
879
901
  try {
880
902
  const filename = yield selectFile(".xml");
903
+ if (!filename) {
904
+ return;
905
+ }
881
906
  const filePath = join(getDownloadFolderPath(), filename);
882
907
  const fileContent = yield readFile(filePath, "utf8");
908
+ if (!(yield Validate.Import_MangaXML(fileContent))) {
909
+ console.error(`\nInvalid XML file.`);
910
+ return;
911
+ }
883
912
  const parser = new XMLParser();
884
913
  if (fileContent) {
885
914
  const XMLObject = parser.parse(fileContent);
@@ -1023,10 +1052,17 @@ class AniDB {
1023
1052
  var _a, _b;
1024
1053
  try {
1025
1054
  const filename = yield selectFile(".json");
1055
+ if (!filename) {
1056
+ return;
1057
+ }
1026
1058
  const filePath = join(getDownloadFolderPath(), filename);
1027
1059
  const fileContent = yield readFile(filePath, "utf8");
1028
1060
  const js0n_repaired = jsonrepair(fileContent);
1029
- if (fileContent) {
1061
+ if (!(yield Validate.Import_AniDBJSONLarge(js0n_repaired))) {
1062
+ console.error(`\nInvalid JSON Large file.`);
1063
+ return;
1064
+ }
1065
+ if (js0n_repaired) {
1030
1066
  const obj3ct = yield JSON.parse(js0n_repaired);
1031
1067
  const animeList = obj3ct === null || obj3ct === void 0 ? void 0 : obj3ct.anime;
1032
1068
  if ((animeList === null || animeList === void 0 ? void 0 : animeList.length) > 0) {
@@ -1068,7 +1104,7 @@ class AniDB {
1068
1104
  const entryId = (_b = (_a = saveResponse === null || saveResponse === void 0 ? void 0 : saveResponse.data) === null || _a === void 0 ? void 0 : _a.SaveMediaListEntry) === null || _b === void 0 ? void 0 : _b.id;
1069
1105
  if (entryId) {
1070
1106
  count++;
1071
- console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}→${getStatus(status, ownEpisodes)}`);
1107
+ console.log(`[${count}]\t${entryId} ✅\t${anidbId}\t${anilistId}\t(${ownEpisodes}/${totalEpisodes})\t${status}–>${getStatus(status, ownEpisodes)}`);
1072
1108
  }
1073
1109
  // Rate limit each API call to avoid server overload
1074
1110
  // await new Promise((resolve) => setTimeout(resolve, 1100))
@@ -0,0 +1,29 @@
1
+ declare class Validate {
2
+ /**
3
+ * Validate importable JSON file
4
+ * @param data string
5
+ * @returns boolean
6
+ */
7
+ static Import_JSON(data: {
8
+ id: number;
9
+ }[]): boolean;
10
+ /**
11
+ * Validate if MyAnimeList Anime XML file is valid or not
12
+ * @param xmlData string
13
+ * @returns boolean
14
+ */
15
+ static Import_AnimeXML(xmlData: string): Promise<boolean>;
16
+ /**
17
+ * Validate if MyAnimeList Anime XML file is valid or not
18
+ * @param xmlData string
19
+ * @returns boolean
20
+ */
21
+ static Import_MangaXML(xmlData: string): Promise<boolean>;
22
+ /**
23
+ * Validate AniDB json-large file
24
+ * @param file string of anidb json-large
25
+ * @returns boolean
26
+ */
27
+ static Import_AniDBJSONLarge(file: string): Promise<boolean>;
28
+ }
29
+ export { Validate };
@@ -0,0 +1,117 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { parseStringPromise } from "xml2js";
11
+ class Validate {
12
+ /**
13
+ * Validate importable JSON file
14
+ * @param data string
15
+ * @returns boolean
16
+ */
17
+ static Import_JSON(data) {
18
+ return (Array.isArray(data) &&
19
+ data.every((item) => typeof item === "object" && item !== null && "id" in item));
20
+ }
21
+ /**
22
+ * Validate if MyAnimeList Anime XML file is valid or not
23
+ * @param xmlData string
24
+ * @returns boolean
25
+ */
26
+ static Import_AnimeXML(xmlData) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ try {
29
+ const result = yield parseStringPromise(xmlData, { explicitArray: false });
30
+ if (!result || !result.myanimelist) {
31
+ console.error("Invalid XML structure: Missing 'myanimelist' root element.");
32
+ return false;
33
+ }
34
+ const animeList = result.myanimelist.anime;
35
+ if (!animeList) {
36
+ console.error("Invalid XML structure: Missing 'anime' elements.");
37
+ return false;
38
+ }
39
+ const animeArray = Array.isArray(animeList) ? animeList : [animeList];
40
+ const isValid = animeArray.every((anime) => {
41
+ const isValidId = anime.series_animedb_id && !isNaN(Number(anime.series_animedb_id));
42
+ const hasRequiredFields = anime.series_title && anime.my_status;
43
+ return isValidId && hasRequiredFields;
44
+ });
45
+ if (!isValid) {
46
+ console.error("Validation failed: Some anime entries are missing required fields or have invalid IDs.");
47
+ }
48
+ return isValid;
49
+ }
50
+ catch (error) {
51
+ console.error("Error parsing or validating XML:", error);
52
+ return false;
53
+ }
54
+ });
55
+ }
56
+ /**
57
+ * Validate if MyAnimeList Anime XML file is valid or not
58
+ * @param xmlData string
59
+ * @returns boolean
60
+ */
61
+ static Import_MangaXML(xmlData) {
62
+ return __awaiter(this, void 0, void 0, function* () {
63
+ try {
64
+ const result = yield parseStringPromise(xmlData, { explicitArray: false });
65
+ if (!result || !result.myanimelist) {
66
+ console.error("Invalid XML structure: Missing 'myanimelist' root element.");
67
+ return false;
68
+ }
69
+ const mangaList = result.myanimelist.manga;
70
+ if (!mangaList) {
71
+ console.error("Invalid XML structure: Missing 'manga' elements.");
72
+ return false;
73
+ }
74
+ const mangaArray = Array.isArray(mangaList) ? mangaList : [mangaList];
75
+ const isValid = mangaArray.every((manga) => {
76
+ const isValidId = manga.manga_mangadb_id && !isNaN(Number(manga.manga_mangadb_id));
77
+ const hasRequiredFields = manga.manga_title && manga.my_status;
78
+ return isValidId && hasRequiredFields;
79
+ });
80
+ if (!isValid) {
81
+ console.error("Validation failed: Some manga entries are missing required fields or have invalid IDs.");
82
+ }
83
+ return isValid;
84
+ }
85
+ catch (error) {
86
+ console.error("Error parsing or validating XML:", error);
87
+ return false;
88
+ }
89
+ });
90
+ }
91
+ /**
92
+ * Validate AniDB json-large file
93
+ * @param file string of anidb json-large
94
+ * @returns boolean
95
+ */
96
+ static Import_AniDBJSONLarge(file) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ try {
99
+ if (!(file === null || file === void 0 ? void 0 : file.trim())) {
100
+ console.error("File content is empty or invalid.");
101
+ return false;
102
+ }
103
+ const obj3ct = JSON.parse(file);
104
+ if (!obj3ct || !Array.isArray(obj3ct.anime)) {
105
+ console.error("Invalid JSON structure: Missing or malformed 'anime' array.");
106
+ return false;
107
+ }
108
+ return true;
109
+ }
110
+ catch (error) {
111
+ console.error("Failed to parse JSON file:", error);
112
+ return false;
113
+ }
114
+ });
115
+ }
116
+ }
117
+ export { Validate };
@@ -162,12 +162,13 @@ function selectFile(fileType) {
162
162
  return answers.fileName;
163
163
  }
164
164
  else {
165
- throw new Error(`\nNo importable ${fileType} file(s) found in download folder.`);
165
+ console.error(`\nNo importable ${fileType} file(s) found in download folder.`);
166
+ return null;
166
167
  }
167
168
  }
168
169
  catch (error) {
169
170
  console.error("\nError selecting file:", error);
170
- throw error;
171
+ return null;
171
172
  }
172
173
  });
173
174
  }
@@ -226,7 +227,9 @@ function createAnimeListXML(mediaWithProgress) {
226
227
  PAUSED: MALAnimeStatus.ON_HOLD,
227
228
  DROPPED: MALAnimeStatus.DROPPED,
228
229
  };
229
- const xmlEntries = mediaWithProgress.map((anime) => {
230
+ // Filter out anime without malId
231
+ const filteredMedia = mediaWithProgress.filter((anime) => anime.malId);
232
+ const xmlEntries = filteredMedia.map((anime) => {
230
233
  const malId = anime.malId;
231
234
  const progress = anime.progress;
232
235
  const episodes = anime.episodes;
@@ -259,7 +262,9 @@ function createMangaListXML(mediaWithProgress) {
259
262
  PAUSED: MALMangaStatus.ON_HOLD,
260
263
  DROPPED: MALMangaStatus.DROPPED,
261
264
  };
262
- const xmlEntries = mediaWithProgress.map((manga) => {
265
+ // Filter out manga without malId
266
+ const filteredMedia = mediaWithProgress.filter((manga) => manga.malId);
267
+ const xmlEntries = filteredMedia.map((manga) => {
263
268
  const malId = manga.malId;
264
269
  const progress = manga.progress;
265
270
  const chapters = manga.chapters;
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.6",
5
+ "version": "1.2.8",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -59,6 +59,7 @@
59
59
  "@types/jest": "^29.5.14",
60
60
  "@types/json2csv": "^5.0.7",
61
61
  "@types/node": "^22.10.5",
62
+ "@types/xml2js": "^0.4.14",
62
63
  "@typescript-eslint/eslint-plugin": "^8.19.0",
63
64
  "eslint": "^9.17.0",
64
65
  "globals": "^15.14.0",
@@ -77,6 +78,7 @@
77
78
  "jsonrepair": "^3.11.2",
78
79
  "node-fetch": "^3.3.2",
79
80
  "open": "^10.1.0",
80
- "tiny-spinner": "^2.0.4"
81
+ "tiny-spinner": "^2.0.4",
82
+ "xml2js": "^0.6.2"
81
83
  }
82
84
  }