@irfanshadikrishad/anilist 1.0.0-forbidden.1 → 1.0.0-forbidden.2

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.
@@ -11,12 +11,15 @@ import fs from "fs";
11
11
  import { readdir, writeFile } from "fs/promises";
12
12
  import inquirer from "inquirer";
13
13
  import { parse } from "json2csv";
14
+ import { createRequire } from "module";
14
15
  import open from "open";
15
16
  import { homedir } from "os";
16
17
  import { join } from "path";
17
18
  import process from "process";
18
19
  import { Auth } from "./auth.js";
19
- 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";
20
23
  const aniListEndpoint = `https://graphql.anilist.co`;
21
24
  const redirectUri = "https://anilist.co/api/v2/oauth/pin";
22
25
  function getTitle(title) {
@@ -140,9 +143,10 @@ function selectFile(fileType) {
140
143
  return __awaiter(this, void 0, void 0, function* () {
141
144
  try {
142
145
  const files = yield listFilesInDownloadFolder();
146
+ console.log(getDownloadFolderPath());
143
147
  // Filter to include only files, not directories, with the specified extension
144
148
  const onlyFiles = files.filter((file) => {
145
- const filePath = `./downloads/${file}`; // Adjust this to the correct path
149
+ const filePath = `${getDownloadFolderPath()}/${file}`; // Adjust this to the correct path
146
150
  const isFile = fs.lstatSync(filePath).isFile(); // Check if it's a file
147
151
  return isFile && file.endsWith(fileType);
148
152
  });
@@ -168,49 +172,49 @@ function selectFile(fileType) {
168
172
  });
169
173
  }
170
174
  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>
175
+ return `
176
+ <anime>
177
+ <series_animedb_id>${malId}</series_animedb_id>
178
+ <series_title><![CDATA[${title}]]></series_title>
179
+ <series_type>""</series_type>
180
+ <series_episodes>${episodes}</series_episodes>
181
+ <my_id>0</my_id>
182
+ <my_watched_episodes>${progress}</my_watched_episodes>
183
+ <my_start_date>0000-00-00</my_start_date>
184
+ <my_finish_date>0000-00-00</my_finish_date>
185
+ <my_score>0</my_score>
186
+ <my_storage_value>0.00</my_storage_value>
187
+ <my_status>${status}</my_status>
188
+ <my_comments><![CDATA[]]></my_comments>
189
+ <my_times_watched>0</my_times_watched>
190
+ <my_rewatch_value></my_rewatch_value>
191
+ <my_priority>LOW</my_priority>
192
+ <my_tags><![CDATA[]]></my_tags>
193
+ <my_rewatching>0</my_rewatching>
194
+ <my_rewatching_ep>0</my_rewatching_ep>
195
+ <my_discuss>0</my_discuss>
196
+ <my_sns>default</my_sns>
197
+ <update_on_import>1</update_on_import>
194
198
  </anime>`;
195
199
  }
196
200
  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>
201
+ return `
202
+ <manga>
203
+ <manga_mangadb_id>${malId}</manga_mangadb_id>
204
+ <manga_title><![CDATA[${title ? title : "unknown"}]]></manga_title>
205
+ <manga_volumes>0</manga_volumes>
206
+ <manga_chapters>${chapters ? chapters : 0}</manga_chapters>
207
+ <my_id>0</my_id>
208
+ <my_read_chapters>${progress}</my_read_chapters>
209
+ <my_start_date>0000-00-00</my_start_date>
210
+ <my_finish_date>0000-00-00</my_finish_date>
211
+ <my_score>0</my_score>
212
+ <my_status>${status}</my_status>
213
+ <my_reread_value></my_reread_value>
214
+ <my_priority>LOW</my_priority>
215
+ <my_rereading>0</my_rereading>
216
+ <my_discuss>0</my_discuss>
217
+ <update_on_import>1</update_on_import>
214
218
  </manga>`;
215
219
  }
216
220
  function createAnimeListXML(mediaWithProgress) {
@@ -230,19 +234,19 @@ function createAnimeListXML(mediaWithProgress) {
230
234
  const status = statusMap[anime.status];
231
235
  return createAnimeXML(malId, progress, status, episodes, title);
232
236
  });
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
237
+ return `<myanimelist>
238
+ <myinfo>
239
+ <user_id/>
240
+ <user_name>${yield Auth.MyUserName()}</user_name>
241
+ <user_export_type>1</user_export_type>
242
+ <user_total_anime>0</user_total_anime>
243
+ <user_total_watching>0</user_total_watching>
244
+ <user_total_completed>0</user_total_completed>
245
+ <user_total_onhold>0</user_total_onhold>
246
+ <user_total_dropped>0</user_total_dropped>
247
+ <user_total_plantowatch>0</user_total_plantowatch>
248
+ </myinfo>
249
+ \n${xmlEntries.join("\n")}\n
246
250
  </myanimelist>`;
247
251
  });
248
252
  }
@@ -263,20 +267,102 @@ function createMangaListXML(mediaWithProgress) {
263
267
  const status = statusMap[manga.status];
264
268
  return createMangaXML(malId, progress, status, chapters, title);
265
269
  });
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
270
+ return `<myanimelist>
271
+ <myinfo>
272
+ <user_id/>
273
+ <user_name>${yield Auth.MyUserName()}</user_name>
274
+ <user_export_type>2</user_export_type>
275
+ <user_total_manga>5</user_total_manga>
276
+ <user_total_reading>1</user_total_reading>
277
+ <user_total_completed>1</user_total_completed>
278
+ <user_total_onhold>1</user_total_onhold>
279
+ <user_total_dropped>1</user_total_dropped>
280
+ <user_total_plantoread>1</user_total_plantoread>
281
+ </myinfo>
282
+ \n${xmlEntries.join("\n")}\n
279
283
  </myanimelist>`;
280
284
  });
281
285
  }
282
- export { aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, };
286
+ function getCurrentPackageVersion() {
287
+ const require = createRequire(import.meta.url);
288
+ const packageJson = require("../../package.json");
289
+ const version = packageJson.version;
290
+ return version || null;
291
+ }
292
+ function timestampToTimeAgo(timestamp) {
293
+ const now = Math.floor(Date.now() / 1000);
294
+ const elapsed = now - timestamp;
295
+ if (elapsed < 60) {
296
+ return `${elapsed} second${elapsed === 1 ? "" : "s"} ago`;
297
+ }
298
+ else if (elapsed < 3600) {
299
+ const minutes = Math.floor(elapsed / 60);
300
+ return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
301
+ }
302
+ else if (elapsed < 86400) {
303
+ const hours = Math.floor(elapsed / 3600);
304
+ return `${hours} hour${hours === 1 ? "" : "s"} ago`;
305
+ }
306
+ else if (elapsed < 2592000) {
307
+ const days = Math.floor(elapsed / 86400);
308
+ return `${days} day${days === 1 ? "" : "s"} ago`;
309
+ }
310
+ else if (elapsed < 31536000) {
311
+ const months = Math.floor(elapsed / 2592000);
312
+ return `${months} month${months === 1 ? "" : "s"} ago`;
313
+ }
314
+ else {
315
+ const years = Math.floor(elapsed / 31536000);
316
+ return `${years} year${years === 1 ? "" : "s"} ago`;
317
+ }
318
+ }
319
+ function activityBy(activity) {
320
+ var _a, _b, _c, _d;
321
+ if ((_a = activity === null || activity === void 0 ? void 0 : activity.messenger) === null || _a === void 0 ? void 0 : _a.name) {
322
+ return `[${activity.id}]\t${activity.messenger.name} messaged ${activity.recipient.name}`;
323
+ }
324
+ 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) {
325
+ if (activity.progress) {
326
+ return `[${activity.id}]\t${activity.user.name} ${activity.status} ${activity.progress} of ${activity.media.title.userPreferred}`;
327
+ }
328
+ else {
329
+ return `[${activity.id}]\t${activity.user.name} ${activity.status} ${activity.media.title.userPreferred}`;
330
+ }
331
+ }
332
+ else if ((_d = activity === null || activity === void 0 ? void 0 : activity.user) === null || _d === void 0 ? void 0 : _d.name) {
333
+ return `[${activity.id}]\t${activity.user.name}`;
334
+ }
335
+ else {
336
+ return `[${activity === null || activity === void 0 ? void 0 : activity.id}] ???`;
337
+ }
338
+ }
339
+ const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void 0, void 0, void 0, function* () {
340
+ const fetchAnime = (search) => __awaiter(void 0, void 0, void 0, function* () {
341
+ var _a;
342
+ try {
343
+ const response = yield fetcher(animeSearchQuery, {
344
+ search,
345
+ perPage: 50,
346
+ });
347
+ return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.Page.media) || [];
348
+ }
349
+ catch (error) {
350
+ console.error("Error fetching AniList data:", error);
351
+ return [];
352
+ }
353
+ });
354
+ // Search using romanjiName first
355
+ let results = yield fetchAnime(romanjiName);
356
+ // If no results, fallback to englishName
357
+ if (!results.length && englishName) {
358
+ results = yield fetchAnime(englishName);
359
+ }
360
+ // Match using year
361
+ for (const anime of results) {
362
+ if (anime.startDate.year === year) {
363
+ return anime.id;
364
+ }
365
+ }
366
+ return null;
367
+ });
368
+ export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, 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
13
  import { Auth } 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) {
@@ -209,8 +206,15 @@ cli
209
206
  cli
210
207
  .command("autolike")
211
208
  .alias("al")
209
+ .option("-2, --v2", "Like the activities", false)
210
+ .option("-c, --count <number>", "Number of activities to like", "25")
212
211
  .description("Autolike following or global activities.")
213
- .action(() => __awaiter(void 0, void 0, void 0, function* () {
214
- yield Auth.AutoLike();
212
+ .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ v2, count }) {
213
+ if (v2) {
214
+ yield Auth.LikeFollowingActivityV2(count);
215
+ }
216
+ else {
217
+ yield Auth.AutoLike();
218
+ }
215
219
  }));
216
220
  cli.parse(process.argv);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@irfanshadikrishad/anilist",
3
3
  "description": "Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts",
4
4
  "author": "Irfan Shadik Rishad",
5
- "version": "1.0.0-forbidden.1",
5
+ "version": "1.0.0-forbidden.2",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -13,12 +13,14 @@
13
13
  "access": "public"
14
14
  },
15
15
  "scripts": {
16
- "build": "rm -rf ./bin && tsc -w",
16
+ "build": "rm -rf ./bin && tsc",
17
+ "buildw": "rm -rf ./bin && tsc -w",
17
18
  "format": "prettier . --write",
18
19
  "format:check": "prettier . --check",
19
20
  "lint": "eslint ./dist",
20
21
  "lint:fix": "eslint ./dist --fix",
21
- "all": "npm run lint && npm run lint:fix && npm run format"
22
+ "all": "npm run build && npm run lint && npm run lint:fix && npm run format && npm test",
23
+ "test": "jest ./tests"
22
24
  },
23
25
  "keywords": [
24
26
  "anilist",
@@ -52,21 +54,27 @@
52
54
  },
53
55
  "license": "MPL-2.0",
54
56
  "devDependencies": {
55
- "@eslint/js": "^9.17.0",
57
+ "@babel/preset-env": "^7.26.0",
58
+ "@eslint/js": "^9.18.0",
59
+ "@types/jest": "^29.5.14",
56
60
  "@types/json2csv": "^5.0.7",
57
- "@types/node": "^22.10.2",
58
- "eslint": "^9.17.0",
61
+ "@types/node": "^22.10.7",
62
+ "@typescript-eslint/eslint-plugin": "^8.20.0",
63
+ "eslint": "^9.18.0",
59
64
  "globals": "^15.14.0",
65
+ "jest": "^29.7.0",
60
66
  "prettier": "^3.4.2",
61
67
  "prettier-plugin-organize-imports": "^4.1.0",
62
- "typescript": "^5.7.2",
63
- "typescript-eslint": "^8.18.1"
68
+ "ts-jest": "^29.2.5",
69
+ "ts-node": "^10.9.2",
70
+ "typescript": "^5.7.3"
64
71
  },
65
72
  "dependencies": {
66
- "commander": "^12.1.0",
73
+ "commander": "^13.0.0",
67
74
  "fast-xml-parser": "^4.5.1",
68
- "inquirer": "^12.2.0",
75
+ "inquirer": "^12.3.2",
69
76
  "json2csv": "^6.0.0-alpha.2",
77
+ "jsonrepair": "^3.11.2",
70
78
  "node-fetch": "^3.3.2",
71
79
  "open": "^10.1.0"
72
80
  }
Binary file
File without changes