@irfanshadikrishad/anilist 1.1.10 → 1.2.0-forbidden.6

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.
@@ -7,16 +7,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
10
21
  import fs from "fs";
11
22
  import { readdir, writeFile } from "fs/promises";
12
23
  import inquirer from "inquirer";
13
- import { parse } from "json2csv";
24
+ import { createRequire } from "module";
14
25
  import open from "open";
15
26
  import { homedir } from "os";
27
+ import Papa from "papaparse";
16
28
  import { join } from "path";
17
29
  import process from "process";
18
30
  import { Auth } from "./auth.js";
19
- import { MALAnimeStatus, MALMangaStatus } from "./types.js";
31
+ import { fetcher } from "./fetcher.js";
32
+ import { animeSearchQuery } from "./queries.js";
33
+ import { MALAnimeStatus, MALMangaStatus, } from "./types.js";
20
34
  const aniListEndpoint = `https://graphql.anilist.co`;
21
35
  const redirectUri = "https://anilist.co/api/v2/oauth/pin";
22
36
  function getTitle(title) {
@@ -94,13 +108,13 @@ function getFormattedDate() {
94
108
  /**
95
109
  * Export JSON as JSON
96
110
  * @param js0n
97
- * @param dataType (eg: anime/manga)
111
+ * @param dataType (eg: anime|manga)
98
112
  */
99
113
  function saveJSONasJSON(js0n, dataType) {
100
114
  return __awaiter(this, void 0, void 0, function* () {
101
115
  try {
102
116
  const jsonData = JSON.stringify(js0n, null, 2);
103
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${dataType}-${getFormattedDate()}.json`);
117
+ const path = yield saveToPath(dataType, ".json");
104
118
  yield writeFile(path, jsonData, "utf8");
105
119
  console.log(`\nSaved as JSON successfully.`);
106
120
  open(getDownloadFolderPath());
@@ -113,13 +127,17 @@ function saveJSONasJSON(js0n, dataType) {
113
127
  /**
114
128
  * Export JSON as CSV
115
129
  * @param js0n
116
- * @param dataType (eg: anime/manga)
130
+ * @param dataType (eg: anime|manga)
117
131
  */
118
132
  function saveJSONasCSV(js0n, dataType) {
119
133
  return __awaiter(this, void 0, void 0, function* () {
120
134
  try {
121
- const csvData = parse(js0n);
122
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${dataType}-${getFormattedDate()}.csv`);
135
+ const js0n_WTAS = js0n.map((_a) => {
136
+ var { title } = _a, rest = __rest(_a, ["title"]);
137
+ return (Object.assign(Object.assign({}, rest), { title: getTitle(title) }));
138
+ });
139
+ const csvData = Papa.unparse(js0n_WTAS);
140
+ const path = yield saveToPath(dataType, ".csv");
123
141
  yield writeFile(path, csvData, "utf8");
124
142
  console.log(`\nSaved as CSV successfully.`);
125
143
  open(getDownloadFolderPath());
@@ -129,6 +147,20 @@ function saveJSONasCSV(js0n, dataType) {
129
147
  }
130
148
  });
131
149
  }
150
+ function saveJSONasXML(js0n, data_type) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ try {
153
+ const xmlContent = data_type === 0 ? createAnimeListXML(js0n) : createMangaListXML(js0n);
154
+ const path = yield saveToPath(data_type === 0 ? "anime" : "manga", ".xml");
155
+ yield writeFile(path, yield xmlContent, "utf8");
156
+ console.log(`\nGenerated XML for MyAnimeList.`);
157
+ open(getDownloadFolderPath());
158
+ }
159
+ catch (error) {
160
+ console.error(`Error saving XML data:`, error);
161
+ }
162
+ });
163
+ }
132
164
  function listFilesInDownloadFolder() {
133
165
  return __awaiter(this, void 0, void 0, function* () {
134
166
  const downloadFolderPath = getDownloadFolderPath();
@@ -140,9 +172,10 @@ function selectFile(fileType) {
140
172
  return __awaiter(this, void 0, void 0, function* () {
141
173
  try {
142
174
  const files = yield listFilesInDownloadFolder();
175
+ console.log(getDownloadFolderPath());
143
176
  // Filter to include only files, not directories, with the specified extension
144
177
  const onlyFiles = files.filter((file) => {
145
- const filePath = `./downloads/${file}`; // Adjust this to the correct path
178
+ const filePath = `${getDownloadFolderPath()}/${file}`; // Adjust this to the correct path
146
179
  const isFile = fs.lstatSync(filePath).isFile(); // Check if it's a file
147
180
  return isFile && file.endsWith(fileType);
148
181
  });
@@ -158,59 +191,60 @@ function selectFile(fileType) {
158
191
  return answers.fileName;
159
192
  }
160
193
  else {
161
- throw new Error(`\nNo importable ${fileType} file(s) found in download folder.`);
194
+ console.error(`\nNo importable ${fileType} file(s) found in download folder.`);
195
+ return null;
162
196
  }
163
197
  }
164
198
  catch (error) {
165
199
  console.error("\nError selecting file:", error);
166
- throw error;
200
+ return null;
167
201
  }
168
202
  });
169
203
  }
170
- function createAnimeXML(malId, progress, status, episodes, title) {
171
- return `
172
- <anime>
173
- <series_animedb_id>${malId}</series_animedb_id>
174
- <series_title><![CDATA[${title}]]></series_title>
175
- <series_type>""</series_type>
176
- <series_episodes>${episodes}</series_episodes>
177
- <my_id>0</my_id>
178
- <my_watched_episodes>${progress}</my_watched_episodes>
179
- <my_start_date>0000-00-00</my_start_date>
180
- <my_finish_date>0000-00-00</my_finish_date>
181
- <my_score>0</my_score>
182
- <my_storage_value>0.00</my_storage_value>
183
- <my_status>${status}</my_status>
184
- <my_comments><![CDATA[]]></my_comments>
185
- <my_times_watched>0</my_times_watched>
186
- <my_rewatch_value></my_rewatch_value>
187
- <my_priority>LOW</my_priority>
188
- <my_tags><![CDATA[]]></my_tags>
189
- <my_rewatching>0</my_rewatching>
190
- <my_rewatching_ep>0</my_rewatching_ep>
191
- <my_discuss>0</my_discuss>
192
- <my_sns>default</my_sns>
193
- <update_on_import>1</update_on_import>
204
+ function createAnimeXML(malId, progress, status, episodes, title, format) {
205
+ return `
206
+ <anime>
207
+ <series_animedb_id>${malId}</series_animedb_id>
208
+ <series_title><![CDATA[${title}]]></series_title>
209
+ <series_type>${format}</series_type>
210
+ <series_episodes>${episodes}</series_episodes>
211
+ <my_id>0</my_id>
212
+ <my_watched_episodes>${progress}</my_watched_episodes>
213
+ <my_start_date>0000-00-00</my_start_date>
214
+ <my_finish_date>0000-00-00</my_finish_date>
215
+ <my_score>0</my_score>
216
+ <my_storage_value>0.00</my_storage_value>
217
+ <my_status>${status}</my_status>
218
+ <my_comments><![CDATA[]]></my_comments>
219
+ <my_times_watched>0</my_times_watched>
220
+ <my_rewatch_value></my_rewatch_value>
221
+ <my_priority>LOW</my_priority>
222
+ <my_tags><![CDATA[]]></my_tags>
223
+ <my_rewatching>0</my_rewatching>
224
+ <my_rewatching_ep>0</my_rewatching_ep>
225
+ <my_discuss>0</my_discuss>
226
+ <my_sns>default</my_sns>
227
+ <update_on_import>1</update_on_import>
194
228
  </anime>`;
195
229
  }
196
230
  function createMangaXML(malId, progress, status, chapters, title) {
197
- return `
198
- <manga>
199
- <manga_mangadb_id>${malId}</manga_mangadb_id>
200
- <manga_title><![CDATA[${title ? title : "unknown"}]]></manga_title>
201
- <manga_volumes>0</manga_volumes>
202
- <manga_chapters>${chapters ? chapters : 0}</manga_chapters>
203
- <my_id>0</my_id>
204
- <my_read_chapters>${progress}</my_read_chapters>
205
- <my_start_date>0000-00-00</my_start_date>
206
- <my_finish_date>0000-00-00</my_finish_date>
207
- <my_score>0</my_score>
208
- <my_status>${status}</my_status>
209
- <my_reread_value></my_reread_value>
210
- <my_priority>LOW</my_priority>
211
- <my_rereading>0</my_rereading>
212
- <my_discuss>0</my_discuss>
213
- <update_on_import>1</update_on_import>
231
+ return `
232
+ <manga>
233
+ <manga_mangadb_id>${malId}</manga_mangadb_id>
234
+ <manga_title><![CDATA[${title ? title : "unknown"}]]></manga_title>
235
+ <manga_volumes>0</manga_volumes>
236
+ <manga_chapters>${chapters ? chapters : 0}</manga_chapters>
237
+ <my_id>0</my_id>
238
+ <my_read_chapters>${progress}</my_read_chapters>
239
+ <my_start_date>0000-00-00</my_start_date>
240
+ <my_finish_date>0000-00-00</my_finish_date>
241
+ <my_score>0</my_score>
242
+ <my_status>${status}</my_status>
243
+ <my_reread_value></my_reread_value>
244
+ <my_priority>LOW</my_priority>
245
+ <my_rereading>0</my_rereading>
246
+ <my_discuss>0</my_discuss>
247
+ <update_on_import>1</update_on_import>
214
248
  </manga>`;
215
249
  }
216
250
  function createAnimeListXML(mediaWithProgress) {
@@ -222,27 +256,30 @@ function createAnimeListXML(mediaWithProgress) {
222
256
  PAUSED: MALAnimeStatus.ON_HOLD,
223
257
  DROPPED: MALAnimeStatus.DROPPED,
224
258
  };
225
- const xmlEntries = mediaWithProgress.map((anime) => {
259
+ // Filter out anime without malId
260
+ const filteredMedia = mediaWithProgress.filter((anime) => anime.malId);
261
+ const xmlEntries = filteredMedia.map((anime) => {
226
262
  const malId = anime.malId;
227
263
  const progress = anime.progress;
228
264
  const episodes = anime.episodes;
229
265
  const title = getTitle(anime.title);
230
266
  const status = statusMap[anime.status];
231
- return createAnimeXML(malId, progress, status, episodes, title);
267
+ const format = anime.format ? anime.format : "";
268
+ return createAnimeXML(malId, progress, status, episodes, title, format);
232
269
  });
233
- return `<myanimelist>
234
- <myinfo>
235
- <user_id/>
236
- <user_name>${yield Auth.MyUserName()}</user_name>
237
- <user_export_type>1</user_export_type>
238
- <user_total_anime>0</user_total_anime>
239
- <user_total_watching>0</user_total_watching>
240
- <user_total_completed>0</user_total_completed>
241
- <user_total_onhold>0</user_total_onhold>
242
- <user_total_dropped>0</user_total_dropped>
243
- <user_total_plantowatch>0</user_total_plantowatch>
244
- </myinfo>
245
- \n${xmlEntries.join("\n")}\n
270
+ return `<myanimelist>
271
+ <myinfo>
272
+ <user_id/>
273
+ <user_name>${yield Auth.MyUserName()}</user_name>
274
+ <user_export_type>1</user_export_type>
275
+ <user_total_anime>0</user_total_anime>
276
+ <user_total_watching>0</user_total_watching>
277
+ <user_total_completed>0</user_total_completed>
278
+ <user_total_onhold>0</user_total_onhold>
279
+ <user_total_dropped>0</user_total_dropped>
280
+ <user_total_plantowatch>0</user_total_plantowatch>
281
+ </myinfo>
282
+ \n${xmlEntries.join("\n")}\n
246
283
  </myanimelist>`;
247
284
  });
248
285
  }
@@ -255,7 +292,9 @@ function createMangaListXML(mediaWithProgress) {
255
292
  PAUSED: MALMangaStatus.ON_HOLD,
256
293
  DROPPED: MALMangaStatus.DROPPED,
257
294
  };
258
- const xmlEntries = mediaWithProgress.map((manga) => {
295
+ // Filter out manga without malId
296
+ const filteredMedia = mediaWithProgress.filter((manga) => manga.malId);
297
+ const xmlEntries = filteredMedia.map((manga) => {
259
298
  const malId = manga.malId;
260
299
  const progress = manga.progress;
261
300
  const chapters = manga.chapters;
@@ -263,20 +302,120 @@ function createMangaListXML(mediaWithProgress) {
263
302
  const status = statusMap[manga.status];
264
303
  return createMangaXML(malId, progress, status, chapters, title);
265
304
  });
266
- return `<myanimelist>
267
- <myinfo>
268
- <user_id/>
269
- <user_name>${yield Auth.MyUserName()}</user_name>
270
- <user_export_type>2</user_export_type>
271
- <user_total_manga>5</user_total_manga>
272
- <user_total_reading>1</user_total_reading>
273
- <user_total_completed>1</user_total_completed>
274
- <user_total_onhold>1</user_total_onhold>
275
- <user_total_dropped>1</user_total_dropped>
276
- <user_total_plantoread>1</user_total_plantoread>
277
- </myinfo>
278
- \n${xmlEntries.join("\n")}\n
305
+ return `<myanimelist>
306
+ <myinfo>
307
+ <user_id/>
308
+ <user_name>${yield Auth.MyUserName()}</user_name>
309
+ <user_export_type>2</user_export_type>
310
+ <user_total_manga>5</user_total_manga>
311
+ <user_total_reading>1</user_total_reading>
312
+ <user_total_completed>1</user_total_completed>
313
+ <user_total_onhold>1</user_total_onhold>
314
+ <user_total_dropped>1</user_total_dropped>
315
+ <user_total_plantoread>1</user_total_plantoread>
316
+ </myinfo>
317
+ \n${xmlEntries.join("\n")}\n
279
318
  </myanimelist>`;
280
319
  });
281
320
  }
282
- export { aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, };
321
+ function getCurrentPackageVersion() {
322
+ const require = createRequire(import.meta.url);
323
+ const packageJson = require("../../package.json");
324
+ const version = packageJson.version;
325
+ return version || null;
326
+ }
327
+ function timestampToTimeAgo(timestamp) {
328
+ const now = Math.floor(Date.now() / 1000);
329
+ const elapsed = now - timestamp;
330
+ if (elapsed < 60) {
331
+ return `${elapsed} second${elapsed === 1 ? "" : "s"} ago`;
332
+ }
333
+ else if (elapsed < 3600) {
334
+ const minutes = Math.floor(elapsed / 60);
335
+ return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
336
+ }
337
+ else if (elapsed < 86400) {
338
+ const hours = Math.floor(elapsed / 3600);
339
+ return `${hours} hour${hours === 1 ? "" : "s"} ago`;
340
+ }
341
+ else if (elapsed < 2592000) {
342
+ const days = Math.floor(elapsed / 86400);
343
+ return `${days} day${days === 1 ? "" : "s"} ago`;
344
+ }
345
+ else if (elapsed < 31536000) {
346
+ const months = Math.floor(elapsed / 2592000);
347
+ return `${months} month${months === 1 ? "" : "s"} ago`;
348
+ }
349
+ else {
350
+ const years = Math.floor(elapsed / 31536000);
351
+ return `${years} year${years === 1 ? "" : "s"} ago`;
352
+ }
353
+ }
354
+ const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void 0, void 0, void 0, function* () {
355
+ const fetchAnime = (search) => __awaiter(void 0, void 0, void 0, function* () {
356
+ var _a;
357
+ try {
358
+ const response = yield fetcher(animeSearchQuery, {
359
+ search,
360
+ perPage: 50,
361
+ });
362
+ return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.Page.media) || [];
363
+ }
364
+ catch (error) {
365
+ console.error("Error fetching AniList data:", error);
366
+ return [];
367
+ }
368
+ });
369
+ // Search using romanjiName first
370
+ let results = yield fetchAnime(romanjiName);
371
+ // If no results, fallback to englishName
372
+ if (!results.length && englishName) {
373
+ results = yield fetchAnime(englishName);
374
+ }
375
+ // Match using year
376
+ for (const anime of results) {
377
+ if (anime.startDate.year === year) {
378
+ return anime.id;
379
+ }
380
+ }
381
+ return null;
382
+ });
383
+ function activityBy(activity, count) {
384
+ var _a, _b, _c, _d;
385
+ const countStr = `[${count ? count : "?"}]`.padEnd(6);
386
+ if ((_a = activity === null || activity === void 0 ? void 0 : activity.messenger) === null || _a === void 0 ? void 0 : _a.name) {
387
+ return `${countStr}${activity.messenger.name} >> messaged ${activity.recipient.name}`;
388
+ }
389
+ 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) {
390
+ if (activity.progress) {
391
+ return `${countStr}${activity.user.name} >> ${activity.status} ${activity.progress} of ${activity.media.title.userPreferred}`;
392
+ }
393
+ else {
394
+ return `${countStr}${activity.user.name} >> ${activity.status} ${activity.media.title.userPreferred}`;
395
+ }
396
+ }
397
+ else if ((_d = activity === null || activity === void 0 ? void 0 : activity.user) === null || _d === void 0 ? void 0 : _d.name) {
398
+ return `${countStr}${activity.user.name}`;
399
+ }
400
+ else {
401
+ return `${countStr}???`;
402
+ }
403
+ }
404
+ /**
405
+ * Extract the save file path
406
+ * @param data_type - anime|manga
407
+ * @param file_format - save format (eg: .json|.csv)
408
+ * @returns string of file path
409
+ */
410
+ function saveToPath(data_type, file_format) {
411
+ return __awaiter(this, void 0, void 0, function* () {
412
+ return join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${data_type}-${getFormattedDate()}.${file_format}`);
413
+ });
414
+ }
415
+ function simpleDateFormat(date) {
416
+ if (!date.day && !date.month && !date.year) {
417
+ return `null`;
418
+ }
419
+ return `${date === null || date === void 0 ? void 0 : date.day}/${date === null || date === void 0 ? void 0 : date.month}/${date === null || date === void 0 ? void 0 : date.year}`;
420
+ }
421
+ export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, simpleDateFormat, timestampToTimeAgo, };
package/bin/index.js CHANGED
@@ -9,18 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  import { Command } from "commander";
12
- import { createRequire } from "module";
13
12
  import process from "process";
14
- import { Auth } from "./helpers/auth.js";
13
+ import { Auth, Social } from "./helpers/auth.js";
15
14
  import { AniList } from "./helpers/lists.js";
16
- const require = createRequire(import.meta.url);
17
- const packageJson = require("../package.json");
18
- const version = packageJson.version;
15
+ import { getCurrentPackageVersion } from "./helpers/workers.js";
19
16
  const cli = new Command();
20
17
  cli
21
18
  .name("anilist")
22
19
  .description("Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts.")
23
- .version(version);
20
+ .version(getCurrentPackageVersion());
24
21
  cli
25
22
  .command("login")
26
23
  .description("Login with AniList")
@@ -35,7 +32,7 @@ cli
35
32
  }
36
33
  }));
37
34
  cli
38
- .command("me")
35
+ .command("whoami")
39
36
  .description("Get details of the logged in user")
40
37
  .action(() => __awaiter(void 0, void 0, void 0, function* () {
41
38
  yield Auth.Myself();
@@ -91,7 +88,7 @@ cli
91
88
  .description("Delete entire collections of anime or manga")
92
89
  .option("-a, --anime", "For anime list of authenticated user", false)
93
90
  .option("-m, --manga", "For manga list of authenticated user", false)
94
- .option("-ac, --activity", "For activity of authenticated user", false)
91
+ .option("-s, --activity", "For activity of authenticated user", false)
95
92
  .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ anime, manga, activity }) {
96
93
  const selectedOptions = [anime, manga, activity].filter(Boolean).length;
97
94
  if (selectedOptions === 0) {
@@ -131,6 +128,13 @@ cli
131
128
  console.error(`\nInvalid or missing ID (${id}). Please provide a valid numeric ID.`);
132
129
  }
133
130
  }));
131
+ cli
132
+ .command("manga <id>")
133
+ .description("Get manga details by their ID")
134
+ .option("-c, --count <number>", "Number of items to get", "10")
135
+ .action((id) => __awaiter(void 0, void 0, void 0, function* () {
136
+ yield AniList.getMangaDetailsByID(id);
137
+ }));
134
138
  cli
135
139
  .command("search <query>")
136
140
  .alias("srch")
@@ -206,4 +210,42 @@ cli
206
210
  }
207
211
  }
208
212
  }));
213
+ cli
214
+ .command("autolike")
215
+ .alias("al")
216
+ .option("-2, --v2", "Like the activities", false)
217
+ .option("-c, --count <number>", "Number of activities to like", "25")
218
+ .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
+ }
226
+ }));
227
+ cli
228
+ .command("social")
229
+ .alias("sol")
230
+ .description("Automate your process")
231
+ .option("-f, --follow", "Follow the user whos following you.", false)
232
+ .option("-u, --unfollow", "Unfollow the user whos not following you.", false)
233
+ .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ follow, unfollow }) {
234
+ if (!follow && !unfollow) {
235
+ console.error(`\nMust select an option, either --follow or --unfollow`);
236
+ }
237
+ else {
238
+ if (yield Auth.isLoggedIn()) {
239
+ if (follow) {
240
+ yield Social.follow();
241
+ }
242
+ else if (unfollow) {
243
+ yield Social.unfollow();
244
+ }
245
+ }
246
+ else {
247
+ console.error(`\nPlease login to use this feature.`);
248
+ }
249
+ }
250
+ }));
209
251
  cli.parse(process.argv);
package/package.json CHANGED
@@ -1,75 +1,86 @@
1
- {
2
- "name": "@irfanshadikrishad/anilist",
3
- "description": "Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts",
4
- "author": "Irfan Shadik Rishad",
5
- "version": "1.1.10",
6
- "main": "./bin/index.js",
7
- "type": "module",
8
- "types": "./bin/index.d.ts",
9
- "bin": {
10
- "anilist": "./bin/index.js"
11
- },
12
- "publishConfig": {
13
- "access": "public"
14
- },
15
- "scripts": {
16
- "build": "rm -rf ./bin && tsc",
17
- "buildw": "rm -rf ./bin && tsc -w",
18
- "format": "prettier . --write",
19
- "format:check": "prettier . --check",
20
- "lint": "eslint ./dist",
21
- "lint:fix": "eslint ./dist --fix",
22
- "all": "npm run lint && npm run lint:fix && npm run format",
23
- "test": "echo Not yet implemented."
24
- },
25
- "keywords": [
26
- "anilist",
27
- "CLI",
28
- "anime",
29
- "manga",
30
- "anime list",
31
- "manga list",
32
- "anime tracker",
33
- "manga tracker",
34
- "anilist API",
35
- "anime progress",
36
- "manga progress",
37
- "media list",
38
- "export anime",
39
- "import anime",
40
- "export manga",
41
- "import manga",
42
- "status tracker",
43
- "watchlist",
44
- "reading list",
45
- "graphql"
46
- ],
47
- "repository": {
48
- "type": "git",
49
- "url": "https://github.com/irfanshadikrishad/anilist"
50
- },
51
- "homepage": "https://github.com/irfanshadikrishad/anilist",
52
- "bugs": {
53
- "url": "https://github.com/irfanshadikrishad/anilist/issues"
54
- },
55
- "license": "MPL-2.0",
56
- "devDependencies": {
57
- "@eslint/js": "^9.17.0",
58
- "@types/json2csv": "^5.0.7",
59
- "@types/node": "^22.10.2",
60
- "eslint": "^9.17.0",
61
- "globals": "^15.14.0",
62
- "prettier": "^3.4.2",
63
- "prettier-plugin-organize-imports": "^4.1.0",
64
- "typescript": "^5.7.2",
65
- "typescript-eslint": "^8.18.2"
66
- },
67
- "dependencies": {
68
- "commander": "^12.1.0",
69
- "fast-xml-parser": "^4.5.1",
70
- "inquirer": "^12.3.0",
71
- "json2csv": "^6.0.0-alpha.2",
72
- "node-fetch": "^3.3.2",
73
- "open": "^10.1.0"
74
- }
75
- }
1
+ {
2
+ "name": "@irfanshadikrishad/anilist",
3
+ "description": "Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts",
4
+ "author": "Irfan Shadik Rishad",
5
+ "version": "1.2.0-forbidden.6",
6
+ "main": "./bin/index.js",
7
+ "type": "module",
8
+ "types": "./bin/index.d.ts",
9
+ "bin": {
10
+ "anilist": "./bin/index.js"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "build": "rm -rf ./bin && tsc",
17
+ "build:watch": "rm -rf ./bin && tsc -w",
18
+ "format": "prettier . --write",
19
+ "format:check": "prettier . --check",
20
+ "lint": "eslint ./dist",
21
+ "lint:fix": "eslint ./dist --fix",
22
+ "all": "npm run build && npm run lint && npm run lint:fix && npm run format && npm test",
23
+ "test": "jest ./tests"
24
+ },
25
+ "keywords": [
26
+ "anilist",
27
+ "CLI",
28
+ "anime",
29
+ "manga",
30
+ "anime list",
31
+ "manga list",
32
+ "anime tracker",
33
+ "manga tracker",
34
+ "anilist API",
35
+ "anime progress",
36
+ "manga progress",
37
+ "media list",
38
+ "export anime",
39
+ "import anime",
40
+ "export manga",
41
+ "import manga",
42
+ "status tracker",
43
+ "watchlist",
44
+ "reading list",
45
+ "graphql"
46
+ ],
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "https://github.com/irfanshadikrishad/anilist"
50
+ },
51
+ "homepage": "https://github.com/irfanshadikrishad/anilist",
52
+ "bugs": {
53
+ "url": "https://github.com/irfanshadikrishad/anilist/issues"
54
+ },
55
+ "license": "MPL-2.0",
56
+ "devDependencies": {
57
+ "@babel/preset-env": "^7.26.9",
58
+ "@eslint/js": "^9.21.0",
59
+ "@types/jest": "^29.5.14",
60
+ "@types/node": "^22.13.5",
61
+ "@types/papaparse": "^5.3.15",
62
+ "@types/xml2js": "^0.4.14",
63
+ "@typescript-eslint/eslint-plugin": "^8.24.1",
64
+ "eslint": "^9.21.0",
65
+ "globals": "^16.0.0",
66
+ "jest": "^29.7.0",
67
+ "prettier": "^3.5.2",
68
+ "prettier-plugin-organize-imports": "^4.1.0",
69
+ "ts-jest": "^29.2.6",
70
+ "ts-node": "^10.9.2",
71
+ "typescript": "^5.7.3"
72
+ },
73
+ "dependencies": {
74
+ "@irfanshadikrishad/cipher": "^1.0.1",
75
+ "cli-truncate": "^4.0.0",
76
+ "commander": "^13.1.0",
77
+ "fast-xml-parser": "^5.0.6",
78
+ "inquirer": "^12.4.2",
79
+ "jsonrepair": "^3.12.0",
80
+ "node-fetch": "^3.3.2",
81
+ "open": "^10.1.0",
82
+ "papaparse": "^5.5.2",
83
+ "tiny-spinner": "^2.0.5",
84
+ "xml2js": "^0.6.2"
85
+ }
86
+ }