@irfanshadikrishad/anilist 1.0.1 → 1.0.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.
package/README.md CHANGED
@@ -39,20 +39,21 @@ here `<client-id>` and `<client-secret>` should be replaced by the ones that you
39
39
 
40
40
  #### CLI Commands Overview
41
41
 
42
- | **Command** | **Options** | **Description** |
43
- | ----------------------------------- | -------------------------------- | ------------------------------------------------ |
44
- | **`login`** | `-i, --id` `-s, --secret` | Log in with your AniList credentials |
45
- | **`logout`** | _None_ | Log out from your AniList account |
46
- | **`me`** | _None_ | Display information about the logged-in user |
47
- | **`-V, --version`** | _None_ | Display the current version of the CLI |
48
- | **`-h, --help`** | _None_ | Display available commands and options |
49
- | **`trending`** <br> _(alias: `tr`)_ | `-c (default: 10)` | Fetch trending anime (default count is 10) |
50
- | **`popular`** <br> _(alias: `plr`)_ | `-c (default: 10)` | Fetch popular anime (default count is 10) |
51
- | **`user`** | `-un (username)` | Get information about a specific AniList user |
52
- | **`lists`** <br> _(alias: `ls`)_ | `-a, --anime` <br> `-m, --manga` | Fetch anime or manga lists of the logged-in user |
53
- | **`delete`** <br> _(alias: `del`)_ | `-a, --anime` <br> `-m, --manga` | Delete collections of anime or manga |
54
- | **`upcoming`** <br> _(alias:`up`)_ | `-c (default: 10)` | Fetch upcoming anime (default count is 10) |
55
- | **`anime`** | `anime Id` | Get anime details by Anime Id |
42
+ | **Command** | **Options** | **Description** |
43
+ | ----------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------ |
44
+ | **`login`** | `-i, --id` `-s, --secret` | Log in with your AniList credentials |
45
+ | **`logout`** | _None_ | Log out from your AniList account |
46
+ | **`me`** | _None_ | Display information about the logged-in user |
47
+ | **`-V, --version`** | _None_ | Display the current version of the CLI |
48
+ | **`-h, --help`** | _None_ | Display available commands and options |
49
+ | **`trending`** <br> _(alias: `tr`)_ | `-c (default: 10)` | Fetch trending anime (default count is 10) |
50
+ | **`popular`** <br> _(alias: `plr`)_ | `-c (default: 10)` | Fetch popular anime (default count is 10) |
51
+ | **`user`** | `-un (username)` | Get information about a specific AniList user |
52
+ | **`lists`** <br> _(alias: `ls`)_ | `-a, --anime` <br> `-m, --manga` | Fetch anime or manga lists of the logged-in user |
53
+ | **`delete`** <br> _(alias: `del`)_ | `-a, --anime` <br> `-m, --manga` <br> `-ac, --activity` | Delete collections of anime, manga or activities |
54
+ | **`upcoming`** <br> _(alias:`up`)_ | `-c (default: 10)` | Fetch upcoming anime (default count is 10) |
55
+ | **`anime`** | `anime Id` | Get anime details by Anime Id |
56
+ | **`search`** <br> _(alias:`srch`/`find`)_ | `<query>` <br> `-a, --anime` <br> `-m, --manga` <br> `-c (default: 10)` | Get anime/manga search results |
56
57
 
57
58
  #### Command Breakdown:
58
59
 
@@ -115,6 +116,7 @@ here `<client-id>` and `<client-secret>` should be replaced by the ones that you
115
116
  - **Options**:
116
117
  - `-a, --anime`: Delete your specific anime collection that you want.
117
118
  - `-m, --manga`: Delete your specific manga collection that you want.
119
+ - `-ac, --activity`: Delete all or any type of activities you want.
118
120
  - **Description**: Delete the entire anime or manga collection from the logged-in user's profile.
119
121
 
120
122
  #### `anime`
@@ -123,6 +125,15 @@ here `<client-id>` and `<client-secret>` should be replaced by the ones that you
123
125
  - `anime Id` _(eg: 21)_ : Id of the anime you want to get details of.
124
126
  - **Description**: Get anime details by anime Id.
125
127
 
128
+ #### `search` _(alias: `srch`/`find`)_:
129
+
130
+ - **Options**:
131
+ - `<query>` : What you want to search (eg: naruto).
132
+ - `-a, --anime`: To get results of anime search.
133
+ - `-m, --manga`: To get results of manga search.
134
+ - `-c (count)`: Specify how many items to fetch (default: 10).
135
+ - **Description**: Get anime/manga search results
136
+
126
137
  #### Security
127
138
 
128
139
  Since you are creating your own API client for login no else else can get your credentials and the generated access token will be stored in your own system. So, As long as you don't share your device (in case you do, just logout) you are safe.
@@ -1,9 +1,10 @@
1
1
  declare function getAccessTokenFromUser(): Promise<any>;
2
2
  declare function storeAccessToken(token: string): Promise<void>;
3
3
  declare function retriveAccessToken(): Promise<string>;
4
- declare function anilistUserLogin(cID: number, cSECRET: string): Promise<void>;
5
- declare function currentUserInfo(): Promise<void>;
4
+ declare function anilistUserLogin(clientId: number, clientSecret: string): Promise<void>;
5
+ declare function currentUserInfo(): Promise<any>;
6
6
  declare function isLoggedIn(): Promise<Boolean>;
7
7
  declare function logoutUser(): Promise<void>;
8
8
  declare function currentUsersId(): Promise<any>;
9
- export { getAccessTokenFromUser, storeAccessToken, retriveAccessToken, anilistUserLogin, currentUserInfo, isLoggedIn, logoutUser, currentUsersId, };
9
+ declare function currentUsersName(): Promise<any>;
10
+ export { getAccessTokenFromUser, storeAccessToken, retriveAccessToken, anilistUserLogin, currentUserInfo, isLoggedIn, logoutUser, currentUsersId, currentUsersName, };
@@ -20,19 +20,24 @@ const home_dir = os.homedir();
20
20
  const save_path = path.join(home_dir, ".anilist_token");
21
21
  function getAccessTokenFromUser() {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
- const answers = yield inquirer.prompt([
23
+ const { token } = yield inquirer.prompt([
24
24
  {
25
25
  type: "password",
26
26
  name: "token",
27
27
  message: "Please enter your AniList access token:",
28
28
  },
29
29
  ]);
30
- return answers.token;
30
+ return token;
31
31
  });
32
32
  }
33
33
  function storeAccessToken(token) {
34
34
  return __awaiter(this, void 0, void 0, function* () {
35
- fs.writeFileSync(save_path, token, { encoding: "utf8" });
35
+ try {
36
+ fs.writeFileSync(save_path, token, { encoding: "utf8" });
37
+ }
38
+ catch (error) {
39
+ console.error(`Error storing acess-token.`);
40
+ }
36
41
  });
37
42
  }
38
43
  function retriveAccessToken() {
@@ -45,10 +50,10 @@ function retriveAccessToken() {
45
50
  }
46
51
  });
47
52
  }
48
- function anilistUserLogin(cID, cSECRET) {
53
+ function anilistUserLogin(clientId, clientSecret) {
49
54
  return __awaiter(this, void 0, void 0, function* () {
50
55
  console.log("Starting AniList login...");
51
- const authUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${cID}&redirect_uri=${redirectUri}&response_type=code`;
56
+ const authUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`;
52
57
  console.log("Opening browser for AniList login...");
53
58
  open(authUrl);
54
59
  const authCode = yield getAccessTokenFromUser();
@@ -59,16 +64,22 @@ function anilistUserLogin(cID, cSECRET) {
59
64
  },
60
65
  body: JSON.stringify({
61
66
  grant_type: "authorization_code",
62
- client_id: String(cID),
63
- client_secret: cSECRET,
67
+ client_id: String(clientId),
68
+ client_secret: clientSecret,
64
69
  redirect_uri: redirectUri,
65
70
  code: authCode,
66
71
  }),
67
72
  });
68
73
  const token_Data = yield tokenResponse.json();
69
74
  if (token_Data === null || token_Data === void 0 ? void 0 : token_Data.access_token) {
70
- console.log("Login successful!");
71
75
  yield storeAccessToken(token_Data === null || token_Data === void 0 ? void 0 : token_Data.access_token);
76
+ const name = yield currentUsersName();
77
+ if (name) {
78
+ console.log(`\nWelcome Back, ${name}!`);
79
+ }
80
+ else {
81
+ console.log(`Logged in successfull!`);
82
+ }
72
83
  }
73
84
  else {
74
85
  console.error("Failed to get access token:", token_Data);
@@ -97,7 +108,7 @@ function currentUserInfo() {
97
108
  id: user === null || user === void 0 ? void 0 : user.id,
98
109
  page: 1,
99
110
  perPage: 10,
100
- }, headers);
111
+ });
101
112
  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;
102
113
  console.log(`\nID:\t\t\t${user === null || user === void 0 ? void 0 : user.id}`);
103
114
  console.log(`Name:\t\t\t${user === null || user === void 0 ? void 0 : user.name}`);
@@ -119,13 +130,16 @@ function currentUserInfo() {
119
130
  ? console.log(`${status} ${progress} of ${getTitle(media === null || media === void 0 ? void 0 : media.title)}`)
120
131
  : console.log(`${status} ${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
121
132
  });
133
+ return user;
122
134
  }
123
135
  else {
124
136
  console.log(`Something went wrong. Please log in again. ${errors[0].message}`);
137
+ return null;
125
138
  }
126
139
  }
127
140
  else {
128
141
  console.log(`User not logged in. Please login first.`);
142
+ return null;
129
143
  }
130
144
  });
131
145
  }
@@ -145,7 +159,7 @@ function logoutUser() {
145
159
  if (fs.existsSync(save_path)) {
146
160
  try {
147
161
  fs.unlinkSync(save_path);
148
- console.log("Logout successful.");
162
+ console.log("\nLogout successful.");
149
163
  }
150
164
  catch (error) {
151
165
  console.error("Error logging out:", error);
@@ -176,4 +190,24 @@ function currentUsersId() {
176
190
  }
177
191
  });
178
192
  }
179
- export { getAccessTokenFromUser, storeAccessToken, retriveAccessToken, anilistUserLogin, currentUserInfo, isLoggedIn, logoutUser, currentUsersId, };
193
+ function currentUsersName() {
194
+ return __awaiter(this, void 0, void 0, function* () {
195
+ var _a;
196
+ const request = yield fetch(aniListEndpoint, {
197
+ method: "POST",
198
+ headers: {
199
+ "Content-Type": "application/json",
200
+ Authorization: `Bearer ${yield retriveAccessToken()}`,
201
+ },
202
+ body: JSON.stringify({ query: currentUserQuery }),
203
+ });
204
+ const { data } = yield request.json();
205
+ if (request.status === 200) {
206
+ return (_a = data === null || data === void 0 ? void 0 : data.Viewer) === null || _a === void 0 ? void 0 : _a.name;
207
+ }
208
+ else {
209
+ return null;
210
+ }
211
+ });
212
+ }
213
+ export { getAccessTokenFromUser, storeAccessToken, retriveAccessToken, anilistUserLogin, currentUserInfo, isLoggedIn, logoutUser, currentUsersId, currentUsersName, };
@@ -1,2 +1,12 @@
1
- declare function fetcher(query: string, variables: object, headers: HeadersInit): Promise<any>;
1
+ /**
2
+ * Sends a GraphQL request to the AniList API.
3
+ *
4
+ * This function constructs a request with the provided query and variables,
5
+ * handles authorization, and processes the API response.
6
+ *
7
+ * @param {string} query - The AniList GraphQL query to be executed.
8
+ * @param {object} variables - An object containing the variables for the query.
9
+ * @returns {Promise<object|null>} The response from the API as a JSON object if successful; otherwise, null.
10
+ */
11
+ declare function fetcher(query: string, variables: object): Promise<object | null>;
2
12
  export { fetcher };
@@ -9,10 +9,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import fetch from "node-fetch";
11
11
  import { aniListEndpoint } from "./workers.js";
12
- function fetcher(query, variables, headers) {
12
+ import { isLoggedIn, retriveAccessToken } from "./auth.js";
13
+ /**
14
+ * Sends a GraphQL request to the AniList API.
15
+ *
16
+ * This function constructs a request with the provided query and variables,
17
+ * handles authorization, and processes the API response.
18
+ *
19
+ * @param {string} query - The AniList GraphQL query to be executed.
20
+ * @param {object} variables - An object containing the variables for the query.
21
+ * @returns {Promise<object|null>} The response from the API as a JSON object if successful; otherwise, null.
22
+ */
23
+ function fetcher(query, variables) {
13
24
  return __awaiter(this, void 0, void 0, function* () {
14
25
  var _a;
15
26
  try {
27
+ const LOGGEDIN = yield isLoggedIn();
28
+ const headers = {
29
+ "content-type": "application/json",
30
+ };
31
+ if (LOGGEDIN) {
32
+ headers["Authorization"] = `Bearer ${yield retriveAccessToken()}`;
33
+ }
16
34
  const request = yield fetch(aniListEndpoint, {
17
35
  method: "POST",
18
36
  headers: headers,
@@ -13,9 +13,11 @@ import { aniListEndpoint, getNextSeasonAndYear, getTitle } from "./workers.js";
13
13
  import { deleteMangaEntryMutation, deleteMediaEntryMutation, popularQuery, trendingQuery, upcomingAnimesQuery, } from "./queries.js";
14
14
  import { currentUserAnimeList, currentUserMangaList } from "./queries.js";
15
15
  import { isLoggedIn, currentUsersId, retriveAccessToken } from "./auth.js";
16
+ import { addAnimeToListMutation } from "./mutations.js";
17
+ import { fetcher } from "./fetcher.js";
16
18
  function getTrending(count) {
17
19
  return __awaiter(this, void 0, void 0, function* () {
18
- var _a, _b, _c;
20
+ var _a, _b, _c, _d;
19
21
  try {
20
22
  const request = yield fetch(aniListEndpoint, {
21
23
  method: "POST",
@@ -31,13 +33,56 @@ function getTrending(count) {
31
33
  if (request.status === 200) {
32
34
  const media = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
33
35
  if ((media === null || media === void 0 ? void 0 : media.length) > 0) {
34
- media.map((tr, idx) => {
35
- console.log(`${idx + 1}\t${getTitle(tr === null || tr === void 0 ? void 0 : tr.title)}`);
36
- });
36
+ const { selectedAnime } = yield inquirer.prompt([
37
+ {
38
+ type: "list",
39
+ name: "selectedAnime",
40
+ message: "Select anime to add to the list:",
41
+ choices: media.map((upx) => ({
42
+ name: getTitle(upx === null || upx === void 0 ? void 0 : upx.title),
43
+ value: upx === null || upx === void 0 ? void 0 : upx.id,
44
+ })),
45
+ },
46
+ ]);
47
+ // Where to save
48
+ const { selectedListType } = yield inquirer.prompt([
49
+ {
50
+ type: "list",
51
+ name: "selectedListType",
52
+ message: "Select the list where you want to save this anime:",
53
+ choices: [
54
+ { name: "Planning", value: "PLANNING" },
55
+ { name: "Watching", value: "CURRENT" },
56
+ { name: "Completed", value: "COMPLETED" },
57
+ { name: "Paused", value: "PAUSED" },
58
+ { name: "Dropped", value: "DROPPED" },
59
+ ],
60
+ },
61
+ ]);
62
+ // Lets save to the list now
63
+ const ISLOGGEDIN = yield isLoggedIn();
64
+ if (ISLOGGEDIN) {
65
+ const query = addAnimeToListMutation;
66
+ const variables = {
67
+ mediaId: selectedAnime,
68
+ status: selectedListType,
69
+ };
70
+ const response = yield fetcher(query, variables);
71
+ if (response) {
72
+ const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
73
+ console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
74
+ }
75
+ }
76
+ else {
77
+ console.error(`Please log in first to use this feature.`);
78
+ }
79
+ }
80
+ else {
81
+ console.log(`\nNo trending available at the moment.`);
37
82
  }
38
83
  }
39
84
  else {
40
- console.log(`Something went wrong. ${(_c = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _c === void 0 ? void 0 : _c.message}`);
85
+ console.log(`Something went wrong. ${(_d = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _d === void 0 ? void 0 : _d.message}`);
41
86
  }
42
87
  }
43
88
  catch (error) {
@@ -47,7 +92,7 @@ function getTrending(count) {
47
92
  }
48
93
  function getPopular(count) {
49
94
  return __awaiter(this, void 0, void 0, function* () {
50
- var _a, _b, _c;
95
+ var _a, _b, _c, _d;
51
96
  try {
52
97
  const request = yield fetch(aniListEndpoint, {
53
98
  method: "POST",
@@ -63,13 +108,56 @@ function getPopular(count) {
63
108
  if (request.status === 200) {
64
109
  const media = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
65
110
  if ((media === null || media === void 0 ? void 0 : media.length) > 0) {
66
- media.map((tr, idx) => {
67
- console.log(`${idx + 1}\t${getTitle(tr === null || tr === void 0 ? void 0 : tr.title)}`);
68
- });
111
+ const { selectedAnime } = yield inquirer.prompt([
112
+ {
113
+ type: "list",
114
+ name: "selectedAnime",
115
+ message: "Select anime to add to the list:",
116
+ choices: media.map((upx) => ({
117
+ name: getTitle(upx === null || upx === void 0 ? void 0 : upx.title),
118
+ value: upx === null || upx === void 0 ? void 0 : upx.id,
119
+ })),
120
+ },
121
+ ]);
122
+ // Where to save
123
+ const { selectedListType } = yield inquirer.prompt([
124
+ {
125
+ type: "list",
126
+ name: "selectedListType",
127
+ message: "Select the list where you want to save this anime:",
128
+ choices: [
129
+ { name: "Planning", value: "PLANNING" },
130
+ { name: "Watching", value: "CURRENT" },
131
+ { name: "Completed", value: "COMPLETED" },
132
+ { name: "Paused", value: "PAUSED" },
133
+ { name: "Dropped", value: "DROPPED" },
134
+ ],
135
+ },
136
+ ]);
137
+ // Lets save to the list now
138
+ const ISLOGGEDIN = yield isLoggedIn();
139
+ if (ISLOGGEDIN) {
140
+ const query = addAnimeToListMutation;
141
+ const variables = {
142
+ mediaId: selectedAnime,
143
+ status: selectedListType,
144
+ };
145
+ const response = yield fetcher(query, variables);
146
+ if (response) {
147
+ const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
148
+ console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
149
+ }
150
+ }
151
+ else {
152
+ console.error(`Please log in first to use this feature.`);
153
+ }
154
+ }
155
+ else {
156
+ console.log(`No popular available at this moment.`);
69
157
  }
70
158
  }
71
159
  else {
72
- console.log(`Something went wrong. ${(_c = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _c === void 0 ? void 0 : _c.message}`);
160
+ console.log(`Something went wrong. ${(_d = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _d === void 0 ? void 0 : _d.message}`);
73
161
  }
74
162
  }
75
163
  catch (error) {
@@ -377,7 +465,7 @@ function deleteMangaByMangaId(id, title) {
377
465
  }
378
466
  function getUpcomingAnimes(count) {
379
467
  return __awaiter(this, void 0, void 0, function* () {
380
- var _a, _b, _c, _d;
468
+ var _a, _b, _c, _d, _e;
381
469
  try {
382
470
  const { nextSeason, nextYear } = getNextSeasonAndYear();
383
471
  const loggedIn = yield isLoggedIn();
@@ -398,15 +486,49 @@ function getUpcomingAnimes(count) {
398
486
  const response = yield request.json();
399
487
  if (request.status === 200) {
400
488
  const upcoming = (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media) !== null && _c !== void 0 ? _c : [];
401
- console.log("");
402
- upcoming.forEach(({ id, title, startDate, genres }, idx) => {
403
- const titleName = (title === null || title === void 0 ? void 0 : title.userPreffered) || getTitle(title);
404
- const formattedDate = `${(startDate === null || startDate === void 0 ? void 0 : startDate.day) ? `${startDate === null || startDate === void 0 ? void 0 : startDate.day}/` : ""}${startDate === null || startDate === void 0 ? void 0 : startDate.month}/${startDate === null || startDate === void 0 ? void 0 : startDate.year}`;
405
- console.log(`[${idx + 1}] ${titleName}\n\t${formattedDate} ${genres.join(", ")}`);
406
- });
489
+ const { selectedAnime } = yield inquirer.prompt([
490
+ {
491
+ type: "list",
492
+ name: "selectedAnime",
493
+ message: "Select anime to add to the list:",
494
+ choices: upcoming.map((upx) => ({
495
+ name: getTitle(upx === null || upx === void 0 ? void 0 : upx.title),
496
+ value: upx === null || upx === void 0 ? void 0 : upx.id,
497
+ })),
498
+ },
499
+ ]);
500
+ // Where to save
501
+ const { selectedListType } = yield inquirer.prompt([
502
+ {
503
+ type: "list",
504
+ name: "selectedListType",
505
+ message: "Select the list where you want to save this anime:",
506
+ choices: [
507
+ { name: "Planning", value: "PLANNING" },
508
+ { name: "Watching", value: "CURRENT" },
509
+ { name: "Completed", value: "COMPLETED" },
510
+ { name: "Paused", value: "PAUSED" },
511
+ { name: "Dropped", value: "DROPPED" },
512
+ ],
513
+ },
514
+ ]);
515
+ // Lets save to the list now
516
+ const ISLOGGEDIN = yield isLoggedIn();
517
+ if (ISLOGGEDIN) {
518
+ const query = addAnimeToListMutation;
519
+ const variables = { mediaId: selectedAnime, status: selectedListType };
520
+ const response = yield fetcher(query, variables);
521
+ if (response) {
522
+ const saved = (_d = response === null || response === void 0 ? void 0 : response.data) === null || _d === void 0 ? void 0 : _d.SaveMediaListEntry;
523
+ console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
524
+ }
525
+ }
526
+ else {
527
+ console.error(`Please log in first to use this feature.`);
528
+ }
407
529
  }
408
530
  else {
409
- console.error(`Something went wrong. ${(_d = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _d === void 0 ? void 0 : _d.message}`);
531
+ console.error(`Something went wrong. ${(_e = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _e === void 0 ? void 0 : _e.message}`);
410
532
  }
411
533
  }
412
534
  catch (error) {
@@ -1,3 +1,6 @@
1
1
  declare function getUserInfoByUsername(username: string): Promise<void>;
2
2
  declare function getAnimeDetailsByID(anilistID: number): Promise<void>;
3
- export { getUserInfoByUsername, getAnimeDetailsByID };
3
+ declare function getAnimeSearchResults(search: string, count: number): Promise<void>;
4
+ declare function getMangaSearchResults(search: string, count: number): Promise<void>;
5
+ declare function deleteUserActivities(): Promise<void>;
6
+ export { getUserInfoByUsername, getAnimeDetailsByID, getAnimeSearchResults, getMangaSearchResults, deleteUserActivities, };
@@ -8,14 +8,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import fetch from "node-fetch";
11
- import { animeDetailsQuery, userActivityQuery, userQuery } from "./queries.js";
12
- import { isLoggedIn, retriveAccessToken } from "./auth.js";
11
+ import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, animeDetailsQuery, animeSearchQuery, mangaSearchQuery, userActivityQuery, userQuery, } from "./queries.js";
12
+ import { currentUsersId, isLoggedIn, retriveAccessToken } from "./auth.js";
13
13
  import { aniListEndpoint, formatDateObject, getTitle, removeHtmlAndMarkdown, } from "./workers.js";
14
14
  import { fetcher } from "./fetcher.js";
15
- import { colorize_Anilist, colorize_Brown } from "./colorize.js";
15
+ import inquirer from "inquirer";
16
+ import { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, } from "./mutations.js";
16
17
  function getUserInfoByUsername(username) {
17
18
  return __awaiter(this, void 0, void 0, function* () {
18
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
19
20
  try {
20
21
  const loggedIn = yield isLoggedIn();
21
22
  let headers = {
@@ -32,12 +33,12 @@ function getUserInfoByUsername(username) {
32
33
  const response = yield request.json();
33
34
  if (request.status === 200) {
34
35
  const user = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.User;
35
- const { data } = yield fetcher(userActivityQuery, {
36
+ const responseUserActivity = yield fetcher(userActivityQuery, {
36
37
  id: user === null || user === void 0 ? void 0 : user.id,
37
38
  page: 1,
38
39
  perPage: 10,
39
- }, headers);
40
- const activities = (_b = data === null || data === void 0 ? void 0 : data.Page) === null || _b === void 0 ? void 0 : _b.activities;
40
+ });
41
+ const activities = ((_c = (_b = responseUserActivity === null || responseUserActivity === void 0 ? void 0 : responseUserActivity.data) === null || _b === void 0 ? void 0 : _b.Page) === null || _c === void 0 ? void 0 : _c.activities) || [];
41
42
  console.log(`\nID:\t\t${user === null || user === void 0 ? void 0 : user.id}`);
42
43
  console.log(`Name:\t\t${user === null || user === void 0 ? void 0 : user.name}`);
43
44
  console.log(`siteUrl:\t${user === null || user === void 0 ? void 0 : user.siteUrl}`);
@@ -51,10 +52,10 @@ function getUserInfoByUsername(username) {
51
52
  console.log(`I blocked?\t${user === null || user === void 0 ? void 0 : user.isBlocked}`);
52
53
  console.log(`My follower:\t${user === null || user === void 0 ? void 0 : user.isFollower}`);
53
54
  console.log(`I'm following:\t${user === null || user === void 0 ? void 0 : user.isFollowing}`);
54
- console.log(`Color:\t${(_c = user === null || user === void 0 ? void 0 : user.options) === null || _c === void 0 ? void 0 : _c.profileColor}`);
55
- console.log(`Timezone:\t${(_d = user === null || user === void 0 ? void 0 : user.options) === null || _d === void 0 ? void 0 : _d.timezone}`);
56
- console.log(`\nStatistics (Anime)\nCount: ${(_f = (_e = user === null || user === void 0 ? void 0 : user.statistics) === null || _e === void 0 ? void 0 : _e.anime) === null || _f === void 0 ? void 0 : _f.count} episodesWatched: ${(_h = (_g = user === null || user === void 0 ? void 0 : user.statistics) === null || _g === void 0 ? void 0 : _g.anime) === null || _h === void 0 ? void 0 : _h.episodesWatched} minutesWatched: ${(_k = (_j = user === null || user === void 0 ? void 0 : user.statistics) === null || _j === void 0 ? void 0 : _j.anime) === null || _k === void 0 ? void 0 : _k.minutesWatched}`);
57
- console.log(`Statistics (Manga)\nCount: ${(_m = (_l = user === null || user === void 0 ? void 0 : user.statistics) === null || _l === void 0 ? void 0 : _l.manga) === null || _m === void 0 ? void 0 : _m.count} Chapter Read: ${(_p = (_o = user === null || user === void 0 ? void 0 : user.statistics) === null || _o === void 0 ? void 0 : _o.manga) === null || _p === void 0 ? void 0 : _p.chaptersRead} Volumes Read: ${(_r = (_q = user === null || user === void 0 ? void 0 : user.statistics) === null || _q === void 0 ? void 0 : _q.manga) === null || _r === void 0 ? void 0 : _r.volumesRead}`);
55
+ console.log(`Color:\t${(_d = user === null || user === void 0 ? void 0 : user.options) === null || _d === void 0 ? void 0 : _d.profileColor}`);
56
+ console.log(`Timezone:\t${(_e = user === null || user === void 0 ? void 0 : user.options) === null || _e === void 0 ? void 0 : _e.timezone}`);
57
+ console.log(`\nStatistics (Anime)\nCount: ${(_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} episodesWatched: ${(_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.episodesWatched} minutesWatched: ${(_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}`);
58
+ console.log(`Statistics (Manga)\nCount: ${(_o = (_m = user === null || user === void 0 ? void 0 : user.statistics) === null || _m === void 0 ? void 0 : _m.manga) === null || _o === void 0 ? void 0 : _o.count} Chapter Read: ${(_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.chaptersRead} Volumes Read: ${(_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.volumesRead}`);
58
59
  console.log(`\nRecent Activities:`);
59
60
  activities.length > 0 &&
60
61
  activities.map(({ id, status, progress, createdAt, media }, idx) => {
@@ -64,7 +65,7 @@ function getUserInfoByUsername(username) {
64
65
  });
65
66
  }
66
67
  else {
67
- console.log(`Something went wrong. ${(_s = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _s === void 0 ? void 0 : _s.message}`);
68
+ console.log(`Something went wrong. ${(_t = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _t === void 0 ? void 0 : _t.message}`);
68
69
  }
69
70
  }
70
71
  catch (error) {
@@ -75,25 +76,17 @@ function getUserInfoByUsername(username) {
75
76
  function getAnimeDetailsByID(anilistID) {
76
77
  return __awaiter(this, void 0, void 0, function* () {
77
78
  var _a;
78
- const loggedIn = yield isLoggedIn();
79
79
  let query = animeDetailsQuery;
80
80
  let variables = { id: anilistID };
81
- let headers = { "content-type": "application/json" };
82
- if (loggedIn) {
83
- headers["Authorization"] = `Bearer ${yield retriveAccessToken()}`;
84
- }
85
- const details = yield fetcher(query, variables, headers);
81
+ const details = yield fetcher(query, variables);
86
82
  if (details) {
87
83
  const { id, idMal, title, description, episodes, nextAiringEpisode, duration, startDate, endDate, countryOfOrigin, isAdult, status, season, format, genres, siteUrl, stats, } = (_a = details === null || details === void 0 ? void 0 : details.data) === null || _a === void 0 ? void 0 : _a.Media;
88
- let titl = colorize_Anilist((title === null || title === void 0 ? void 0 : title.userPreffered) || getTitle(title));
89
- let st_tus = colorize_Anilist(String(status));
90
- let descri = colorize_Brown(removeHtmlAndMarkdown(description));
91
84
  console.log(`\nID: ${id}`);
92
- console.log(`Title: `, titl);
93
- console.log(`Description: `, descri);
85
+ console.log(`Title: ${(title === null || title === void 0 ? void 0 : title.userPreffered) || getTitle(title)}`);
86
+ console.log(`Description: ${removeHtmlAndMarkdown(description)}`);
94
87
  console.log(`Episode Duration: ${duration}min`);
95
88
  console.log(`Origin: ${countryOfOrigin}`);
96
- console.log(`Status: `, st_tus);
89
+ console.log(`Status: ${String(status)}`);
97
90
  console.log(`Format: ${format}`);
98
91
  console.log(`Genres: ${genres.join(", ")}`);
99
92
  console.log(`Season: ${season}`);
@@ -104,4 +97,181 @@ function getAnimeDetailsByID(anilistID) {
104
97
  }
105
98
  });
106
99
  }
107
- export { getUserInfoByUsername, getAnimeDetailsByID };
100
+ function getAnimeSearchResults(search, count) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ var _a, _b, _c;
103
+ const query = animeSearchQuery;
104
+ const variables = { search, page: 1, perPage: count };
105
+ const searchResults = yield fetcher(query, variables);
106
+ if (searchResults) {
107
+ const results = (_b = (_a = searchResults === null || searchResults === void 0 ? void 0 : searchResults.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
108
+ const { selectedList } = yield inquirer.prompt([
109
+ {
110
+ type: "list",
111
+ name: "selectedList",
112
+ message: "Select anime to add to your list:",
113
+ choices: results.map((res, idx) => ({
114
+ name: getTitle(res === null || res === void 0 ? void 0 : res.title),
115
+ value: res === null || res === void 0 ? void 0 : res.id,
116
+ })),
117
+ },
118
+ ]);
119
+ // Where to save
120
+ const { selectedListType } = yield inquirer.prompt([
121
+ {
122
+ type: "list",
123
+ name: "selectedListType",
124
+ message: "Select the list where you want to save this anime:",
125
+ choices: [
126
+ { name: "Planning", value: "PLANNING" },
127
+ { name: "Watching", value: "CURRENT" },
128
+ { name: "Completed", value: "COMPLETED" },
129
+ { name: "Paused", value: "PAUSED" },
130
+ { name: "Dropped", value: "DROPPED" },
131
+ ],
132
+ },
133
+ ]);
134
+ // Lets save to the list now
135
+ const ISLOGGEDIN = yield isLoggedIn();
136
+ if (ISLOGGEDIN) {
137
+ const query = addAnimeToListMutation;
138
+ const variables = { mediaId: selectedList, status: selectedListType };
139
+ const response = yield fetcher(query, variables);
140
+ if (response) {
141
+ const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
142
+ console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
143
+ }
144
+ }
145
+ else {
146
+ console.error(`Please log in first to use this feature.`);
147
+ }
148
+ }
149
+ else {
150
+ console.error(`Something went wrong.`);
151
+ }
152
+ });
153
+ }
154
+ function getMangaSearchResults(search, count) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ var _a, _b, _c;
157
+ const query = mangaSearchQuery;
158
+ const variables = { search, page: 1, perPage: count };
159
+ const mangaSearchResult = yield fetcher(query, variables);
160
+ if (mangaSearchResult) {
161
+ const results = (_b = (_a = mangaSearchResult === null || mangaSearchResult === void 0 ? void 0 : mangaSearchResult.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.media;
162
+ // List of manga search results
163
+ const { selectedMangaId } = yield inquirer.prompt([
164
+ {
165
+ type: "list",
166
+ name: "selectedMangaId",
167
+ message: "Select manga to add to your list:",
168
+ choices: results.map((res) => ({
169
+ name: getTitle(res === null || res === void 0 ? void 0 : res.title),
170
+ value: res === null || res === void 0 ? void 0 : res.id,
171
+ })),
172
+ },
173
+ ]);
174
+ // Options to save to the list
175
+ const { selectedListType } = yield inquirer.prompt([
176
+ {
177
+ type: "list",
178
+ name: "selectedListType",
179
+ message: "Select the list where you want to save this manga:",
180
+ choices: [
181
+ { name: "Planning", value: "PLANNING" },
182
+ { name: "Reading", value: "CURRENT" },
183
+ { name: "Completed", value: "COMPLETED" },
184
+ { name: "Paused", value: "PAUSED" },
185
+ { name: "Dropped", value: "DROPPED" },
186
+ ],
187
+ },
188
+ ]);
189
+ // If logged in save to the list
190
+ const ISLOGGEDIN = yield isLoggedIn();
191
+ if (ISLOGGEDIN) {
192
+ const mutation = addMangaToListMutation;
193
+ const variables = { mediaId: selectedMangaId, status: selectedListType };
194
+ const response = yield fetcher(mutation, variables);
195
+ if (response) {
196
+ const saved = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.SaveMediaListEntry;
197
+ console.log(`\nEntry ${saved === null || saved === void 0 ? void 0 : saved.id}. Saved as ${saved === null || saved === void 0 ? void 0 : saved.status}.`);
198
+ }
199
+ }
200
+ else {
201
+ console.error(`Please log in first to use this feature.`);
202
+ }
203
+ }
204
+ else {
205
+ console.error(`Something went wrong.`);
206
+ }
207
+ });
208
+ }
209
+ function deleteUserActivities() {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ var _a, _b, _c, _d;
212
+ const LOGGEDIN = yield isLoggedIn();
213
+ if (LOGGEDIN) {
214
+ const { activityType } = yield inquirer.prompt([
215
+ {
216
+ type: "list",
217
+ name: "activityType",
218
+ message: "What type of activity you want to delete?",
219
+ choices: [
220
+ { name: "All Activity", value: 0 },
221
+ { name: "Text Activity", value: 1 },
222
+ { name: "Media List Activity", value: 2 },
223
+ { name: "Anime List Activity", value: 3 },
224
+ { name: "Manga List Activity", value: 4 },
225
+ { name: "Message Activity", value: 5 },
226
+ ],
227
+ },
228
+ ]);
229
+ let query = ``;
230
+ const userId = yield currentUsersId();
231
+ let variables = { page: 1, perPage: 100, userId };
232
+ switch (activityType) {
233
+ case 0:
234
+ query = activityAllQuery;
235
+ break;
236
+ case 1:
237
+ query = activityTextQuery;
238
+ break;
239
+ case 2:
240
+ query = activityMediaList;
241
+ break;
242
+ case 3:
243
+ query = activityAnimeListQuery;
244
+ break;
245
+ case 4:
246
+ query = activityMangaListQuery;
247
+ break;
248
+ case 5:
249
+ query = activityMessageQuery;
250
+ break;
251
+ }
252
+ const response = yield fetcher(query, variables);
253
+ if (response) {
254
+ const activities = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities;
255
+ if (activities.length <= 0) {
256
+ console.log(`\nNo activities available of this type.`);
257
+ }
258
+ else {
259
+ for (let act of activities) {
260
+ const activityID = act === null || act === void 0 ? void 0 : act.id;
261
+ const deleteResponse = yield fetcher(deleteActivityMutation, {
262
+ id: activityID,
263
+ });
264
+ const isDeleted = (_d = (_c = deleteResponse === null || deleteResponse === void 0 ? void 0 : deleteResponse.data) === null || _c === void 0 ? void 0 : _c.DeleteActivity) === null || _d === void 0 ? void 0 : _d.deleted;
265
+ console.log(`${activityID} ${isDeleted ? "✅" : "❌"}`);
266
+ // avoiding rate-limit
267
+ yield new Promise((resolve) => setTimeout(resolve, 2000));
268
+ }
269
+ }
270
+ }
271
+ }
272
+ else {
273
+ console.error(`Please log in to use this feature.`);
274
+ }
275
+ });
276
+ }
277
+ export { getUserInfoByUsername, getAnimeDetailsByID, getAnimeSearchResults, getMangaSearchResults, deleteUserActivities, };
@@ -0,0 +1,4 @@
1
+ declare const addAnimeToListMutation = "\nmutation($mediaId: Int, $status: MediaListStatus) {\n SaveMediaListEntry(mediaId: $mediaId, status: $status) { id status }\n}\n";
2
+ declare const addMangaToListMutation = "\n mutation($mediaId: Int, $status: MediaListStatus) {\n SaveMediaListEntry(mediaId: $mediaId, status: $status) {\n id\n status\n media { title { romaji english } }\n }\n }\n";
3
+ declare const deleteActivityMutation = "\nmutation($id: Int!) {\n DeleteActivity(id: $id) { deleted }\n}\n";
4
+ export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, };
@@ -0,0 +1,20 @@
1
+ const addAnimeToListMutation = `
2
+ mutation($mediaId: Int, $status: MediaListStatus) {
3
+ SaveMediaListEntry(mediaId: $mediaId, status: $status) { id status }
4
+ }
5
+ `;
6
+ const addMangaToListMutation = `
7
+ mutation($mediaId: Int, $status: MediaListStatus) {
8
+ SaveMediaListEntry(mediaId: $mediaId, status: $status) {
9
+ id
10
+ status
11
+ media { title { romaji english } }
12
+ }
13
+ }
14
+ `;
15
+ const deleteActivityMutation = `
16
+ mutation($id: Int!) {
17
+ DeleteActivity(id: $id) { deleted }
18
+ }
19
+ `;
20
+ export { addAnimeToListMutation, addMangaToListMutation, deleteActivityMutation, };
@@ -1,12 +1,20 @@
1
- declare const currentUserQuery = "\n{\n Viewer {\n id name about bans siteUrl\n options { profileColor timezone activityMergeTime }\n donatorTier donatorBadge createdAt updatedAt\n unreadNotificationCount\n previousNames { name createdAt updatedAt }\n moderatorRoles\n favourites {\n anime { nodes { id title { romaji english } } }\n manga { nodes { id title { romaji english } } }\n }\n statistics {\n anime { count meanScore minutesWatched }\n manga { count chaptersRead volumesRead }\n }\n mediaListOptions {\n scoreFormat rowOrder\n animeList { sectionOrder }\n mangaList { sectionOrder }\n }\n }\n}";
2
- declare const trendingQuery = "\nquery ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: TRENDING_DESC, type: ANIME) {\n id title { romaji english }\n }\n }\n}";
3
- declare const popularQuery = "\nquery ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: POPULARITY_DESC, type: ANIME) {\n id title { romaji english }\n }\n }\n}";
4
- declare const userQuery = "\nquery ($username: String) {\n User(name: $username) {\n id name siteUrl donatorTier donatorBadge createdAt updatedAt\n previousNames { name createdAt updatedAt }\n isBlocked isFollower isFollowing\n options { profileColor timezone activityMergeTime }\n statistics {\n anime { count episodesWatched minutesWatched }\n manga { count chaptersRead volumesRead }\n }\n }\n}";
5
- declare const currentUserAnimeList = "\nquery ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id media { id title { romaji english } } } }\n }\n}";
6
- declare const currentUserMangaList = "\nquery ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id media { title { romaji english } } } }\n }\n}";
7
- declare const deleteMediaEntryMutation = "\nmutation($id: Int!) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
8
- declare const deleteMangaEntryMutation = "\nmutation ($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
9
- declare const upcomingAnimesQuery = "\nquery 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 }\n season seasonYear startDate { year month day }\n episodes description genres\n }\n }\n}";
10
- declare const animeDetailsQuery = "\nquery ($id: Int) {\n Media(id: $id) {\n id idMal title { romaji english native userPreferred }\n episodes nextAiringEpisode { id }\n duration startDate { year month day }\n endDate { year month day }\n countryOfOrigin description isAdult status season format genres siteUrl\n stats {\n scoreDistribution { score amount }\n statusDistribution { status amount }\n }\n }\n}";
11
- declare const userActivityQuery = "\nquery ($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 {\n id status progress createdAt\n media { id title { romaji english } }\n }\n }\n }\n}";
12
- export { currentUserQuery, trendingQuery, popularQuery, userQuery, currentUserAnimeList, currentUserMangaList, deleteMediaEntryMutation, deleteMangaEntryMutation, upcomingAnimesQuery, animeDetailsQuery, userActivityQuery, };
1
+ declare const currentUserQuery = "{\n Viewer {\n id name about bans siteUrl options { profileColor timezone activityMergeTime }\n donatorTier donatorBadge createdAt updatedAt unreadNotificationCount\n previousNames { name createdAt updatedAt } moderatorRoles\n favourites { anime { nodes { id title { romaji english } } } manga { nodes { id title { romaji english } } }\n }\n statistics { anime { count meanScore minutesWatched } manga { count chaptersRead volumesRead } }\n mediaListOptions { scoreFormat rowOrder animeList { sectionOrder } mangaList { sectionOrder } }\n }\n}";
2
+ declare const trendingQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: TRENDING_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
3
+ declare const popularQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: POPULARITY_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
4
+ declare const userQuery = "query ($username: String) {\n User(name: $username) {\n id name siteUrl donatorTier donatorBadge createdAt updatedAt previousNames { name createdAt updatedAt }\n isBlocked isFollower isFollowing options { profileColor timezone activityMergeTime }\n statistics { anime { count episodesWatched minutesWatched } manga { count chaptersRead volumesRead } }\n }\n}";
5
+ declare const currentUserAnimeList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id media { id title { romaji english } } } }\n }\n}";
6
+ declare const currentUserMangaList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id media { title { romaji english } } } }\n }\n}";
7
+ declare const deleteMediaEntryMutation = "mutation($id: Int!) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
8
+ declare const deleteMangaEntryMutation = "mutation ($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
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
+ 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
+ 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}";
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
+ declare const activityTextQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: TEXT) {\n ... on TextActivity { id type text createdAt user { id name } }\n }\n }\n}";
15
+ declare const activityAnimeListQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: ANIME_LIST) {\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n }\n }\n}";
16
+ declare const activityMangaListQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: MANGA_LIST) {\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n }\n }\n}";
17
+ declare const activityMessageQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId, type: MESSAGE) {\n ... on MessageActivity { id type message recipient { id name } createdAt }\n }\n }\n}";
18
+ declare const activityAllQuery = "query ($userId: Int, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n activities(userId: $userId) {\n ... on TextActivity { id type text createdAt user { id name } }\n ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }\n ... on MessageActivity { id type message recipient { id name } createdAt }\n }\n }\n}";
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) {\n ... on ListActivity { id type status progress media { id title { romaji english native } format } createdAt }\n }\n }\n}";
20
+ export { currentUserQuery, trendingQuery, popularQuery, userQuery, currentUserAnimeList, currentUserMangaList, deleteMediaEntryMutation, deleteMangaEntryMutation, upcomingAnimesQuery, animeDetailsQuery, userActivityQuery, animeSearchQuery, mangaSearchQuery, activityAllQuery, activityMediaList, activityAnimeListQuery, activityMangaListQuery, activityMessageQuery, activityTextQuery, };
@@ -1,109 +1,122 @@
1
- const currentUserQuery = `
2
- {
1
+ const currentUserQuery = `{
3
2
  Viewer {
4
- id name about bans siteUrl
5
- options { profileColor timezone activityMergeTime }
6
- donatorTier donatorBadge createdAt updatedAt
7
- unreadNotificationCount
8
- previousNames { name createdAt updatedAt }
9
- moderatorRoles
10
- favourites {
11
- anime { nodes { id title { romaji english } } }
12
- manga { nodes { id title { romaji english } } }
13
- }
14
- statistics {
15
- anime { count meanScore minutesWatched }
16
- manga { count chaptersRead volumesRead }
17
- }
18
- mediaListOptions {
19
- scoreFormat rowOrder
20
- animeList { sectionOrder }
21
- mangaList { sectionOrder }
3
+ id name about bans siteUrl options { profileColor timezone activityMergeTime }
4
+ donatorTier donatorBadge createdAt updatedAt unreadNotificationCount
5
+ previousNames { name createdAt updatedAt } moderatorRoles
6
+ favourites { anime { nodes { id title { romaji english } } } manga { nodes { id title { romaji english } } }
22
7
  }
8
+ statistics { anime { count meanScore minutesWatched } manga { count chaptersRead volumesRead } }
9
+ mediaListOptions { scoreFormat rowOrder animeList { sectionOrder } mangaList { sectionOrder } }
23
10
  }
24
11
  }`;
25
- const trendingQuery = `
26
- query ($page: Int, $perPage: Int) {
12
+ const trendingQuery = `query ($page: Int, $perPage: Int) {
27
13
  Page(page: $page, perPage: $perPage) {
28
- media(sort: TRENDING_DESC, type: ANIME) {
29
- id title { romaji english }
30
- }
14
+ media(sort: TRENDING_DESC, type: ANIME) { id title { romaji english } }
31
15
  }
32
16
  }`;
33
- const popularQuery = `
34
- query ($page: Int, $perPage: Int) {
17
+ const popularQuery = `query ($page: Int, $perPage: Int) {
35
18
  Page(page: $page, perPage: $perPage) {
36
- media(sort: POPULARITY_DESC, type: ANIME) {
37
- id title { romaji english }
38
- }
19
+ media(sort: POPULARITY_DESC, type: ANIME) { id title { romaji english } }
39
20
  }
40
21
  }`;
41
- const userQuery = `
42
- query ($username: String) {
22
+ const userQuery = `query ($username: String) {
43
23
  User(name: $username) {
44
- id name siteUrl donatorTier donatorBadge createdAt updatedAt
45
- previousNames { name createdAt updatedAt }
46
- isBlocked isFollower isFollowing
47
- options { profileColor timezone activityMergeTime }
48
- statistics {
49
- anime { count episodesWatched minutesWatched }
50
- manga { count chaptersRead volumesRead }
51
- }
24
+ id name siteUrl donatorTier donatorBadge createdAt updatedAt previousNames { name createdAt updatedAt }
25
+ isBlocked isFollower isFollowing options { profileColor timezone activityMergeTime }
26
+ statistics { anime { count episodesWatched minutesWatched } manga { count chaptersRead volumesRead } }
52
27
  }
53
28
  }`;
54
- const currentUserAnimeList = `
55
- query ($id: Int) {
29
+ const currentUserAnimeList = `query ($id: Int) {
56
30
  MediaListCollection(userId: $id, type: ANIME) {
57
31
  lists { name entries { id media { id title { romaji english } } } }
58
32
  }
59
33
  }`;
60
- const currentUserMangaList = `
61
- query ($id: Int) {
34
+ const currentUserMangaList = `query ($id: Int) {
62
35
  MediaListCollection(userId: $id, type: MANGA) {
63
36
  lists { name entries { id media { title { romaji english } } } }
64
37
  }
65
38
  }`;
66
- const deleteMediaEntryMutation = `
67
- mutation($id: Int!) {
39
+ const deleteMediaEntryMutation = `mutation($id: Int!) {
68
40
  DeleteMediaListEntry(id: $id) { deleted }
69
41
  }`;
70
- const deleteMangaEntryMutation = `
71
- mutation ($id: Int) {
42
+ const deleteMangaEntryMutation = `mutation ($id: Int) {
72
43
  DeleteMediaListEntry(id: $id) { deleted }
73
44
  }`;
74
- const upcomingAnimesQuery = `
75
- query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {
45
+ const upcomingAnimesQuery = `query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {
76
46
  Page(perPage: $perPage) {
77
47
  media(season: $nextSeason, seasonYear: $nextYear, type: ANIME, sort: POPULARITY_DESC) {
78
- id title { romaji english native userPreferred }
79
- season seasonYear startDate { year month day }
48
+ id title { romaji english native userPreferred } season seasonYear startDate { year month day }
80
49
  episodes description genres
81
50
  }
82
51
  }
83
52
  }`;
84
- const animeDetailsQuery = `
85
- query ($id: Int) {
53
+ const animeDetailsQuery = `query ($id: Int) {
86
54
  Media(id: $id) {
87
- id idMal title { romaji english native userPreferred }
88
- episodes nextAiringEpisode { id }
89
- duration startDate { year month day }
90
- endDate { year month day }
91
- countryOfOrigin description isAdult status season format genres siteUrl
92
- stats {
93
- scoreDistribution { score amount }
94
- statusDistribution { status amount }
95
- }
55
+ id idMal title { romaji english native userPreferred } episodes nextAiringEpisode { id }
56
+ duration startDate { year month day } endDate { year month day } countryOfOrigin description isAdult status season format genres siteUrl
57
+ stats { scoreDistribution { score amount } statusDistribution { status amount } }
96
58
  }
97
59
  }`;
98
- const userActivityQuery = `
99
- query ($id: Int, $page: Int, $perPage: Int) {
60
+ const userActivityQuery = `query ($id: Int, $page: Int, $perPage: Int) {
100
61
  Page(page: $page, perPage: $perPage) {
101
62
  activities(userId: $id, type_in: [ANIME_LIST, MANGA_LIST], sort: ID_DESC) {
102
- ... on ListActivity {
103
- id status progress createdAt
104
- media { id title { romaji english } }
105
- }
63
+ ... on ListActivity { id status progress createdAt media { id title { romaji english } } }
64
+ }
65
+ }
66
+ }`;
67
+ const animeSearchQuery = `query ($search: String, $perPage: Int) {
68
+ Page(perPage: $perPage) {
69
+ media(search: $search, type: ANIME) { id title { romaji english native userPreferred } episodes status description }
70
+ }
71
+ }`;
72
+ const mangaSearchQuery = `query ($search: String, $perPage: Int) {
73
+ Page(perPage: $perPage) {
74
+ media(search: $search, type: MANGA) { id title { romaji english native userPreferred } chapters status description }
75
+ }
76
+ }`;
77
+ const activityTextQuery = `query ($userId: Int, $page: Int, $perPage: Int) {
78
+ Page(page: $page, perPage: $perPage) {
79
+ activities(userId: $userId, type: TEXT) {
80
+ ... on TextActivity { id type text createdAt user { id name } }
81
+ }
82
+ }
83
+ }`;
84
+ const activityAnimeListQuery = `query ($userId: Int, $page: Int, $perPage: Int) {
85
+ Page(page: $page, perPage: $perPage) {
86
+ activities(userId: $userId, type: ANIME_LIST) {
87
+ ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }
88
+ }
89
+ }
90
+ }`;
91
+ const activityMangaListQuery = `query ($userId: Int, $page: Int, $perPage: Int) {
92
+ Page(page: $page, perPage: $perPage) {
93
+ activities(userId: $userId, type: MANGA_LIST) {
94
+ ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }
95
+ }
96
+ }
97
+ }`;
98
+ const activityMessageQuery = `query ($userId: Int, $page: Int, $perPage: Int) {
99
+ Page(page: $page, perPage: $perPage) {
100
+ activities(userId: $userId, type: MESSAGE) {
101
+ ... on MessageActivity { id type message recipient { id name } createdAt }
102
+ }
103
+ }
104
+ }`;
105
+ const activityAllQuery = `query ($userId: Int, $page: Int, $perPage: Int) {
106
+ Page(page: $page, perPage: $perPage) {
107
+ activities(userId: $userId) {
108
+ ... on TextActivity { id type text createdAt user { id name } }
109
+ ... on ListActivity { id type status progress createdAt media { id title { romaji english native } } }
110
+ ... on MessageActivity { id type message recipient { id name } createdAt }
111
+ }
112
+ }
113
+ }`;
114
+ const activityMediaList = `query ($userId: Int, $page: Int, $perPage: Int, $type: ActivityType) {
115
+ Page(page: $page, perPage: $perPage) {
116
+ pageInfo { total currentPage lastPage hasNextPage perPage }
117
+ activities(userId: $userId, type: $type) {
118
+ ... on ListActivity { id type status progress media { id title { romaji english native } format } createdAt }
106
119
  }
107
120
  }
108
121
  }`;
109
- export { currentUserQuery, trendingQuery, popularQuery, userQuery, currentUserAnimeList, currentUserMangaList, deleteMediaEntryMutation, deleteMangaEntryMutation, upcomingAnimesQuery, animeDetailsQuery, userActivityQuery, };
122
+ export { currentUserQuery, trendingQuery, popularQuery, userQuery, currentUserAnimeList, currentUserMangaList, deleteMediaEntryMutation, deleteMangaEntryMutation, upcomingAnimesQuery, animeDetailsQuery, userActivityQuery, animeSearchQuery, mangaSearchQuery, activityAllQuery, activityMediaList, activityAnimeListQuery, activityMangaListQuery, activityMessageQuery, activityTextQuery, };
@@ -1,21 +1,13 @@
1
1
  const aniListEndpoint = `https://graphql.anilist.co`;
2
2
  const redirectUri = "https://anilist.co/api/v2/oauth/pin";
3
3
  function getTitle(title) {
4
- if (title === null || title === void 0 ? void 0 : title.english) {
5
- return title === null || title === void 0 ? void 0 : title.english;
6
- }
7
- else if (title === null || title === void 0 ? void 0 : title.romaji) {
8
- return title === null || title === void 0 ? void 0 : title.romaji;
9
- }
10
- else {
11
- return "???";
12
- }
4
+ return (title === null || title === void 0 ? void 0 : title.english) || (title === null || title === void 0 ? void 0 : title.romaji) || "???";
13
5
  }
14
6
  function formatDateObject(dateObj) {
15
7
  if (!dateObj)
16
8
  return "null";
17
- const { day = "", month = "", year = "" } = dateObj;
18
- return [day, month, year].filter(Boolean).join("/");
9
+ return ([dateObj.day, dateObj.month, dateObj.year].filter(Boolean).join("/") ||
10
+ "null");
19
11
  }
20
12
  function getNextSeasonAndYear() {
21
13
  const currentMonth = new Date().getMonth() + 1;
package/bin/index.js CHANGED
@@ -11,9 +11,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  import { Command } from "commander";
12
12
  import { anilistUserLogin, currentUserInfo, logoutUser, } from "./helpers/auth.js";
13
13
  import { deleteAnimeCollection, deleteMangaCollection, getPopular, getTrending, getUpcomingAnimes, loggedInUsersAnimeLists, loggedInUsersMangaLists, } from "./helpers/lists.js";
14
- import { getAnimeDetailsByID, getUserInfoByUsername } from "./helpers/more.js";
14
+ import { getAnimeDetailsByID, getAnimeSearchResults, getMangaSearchResults, deleteUserActivities, getUserInfoByUsername, } from "./helpers/more.js";
15
15
  const cli = new Command();
16
- cli.name("anilist").description("Unofficial AniList CLI").version("1.0.0");
16
+ cli.name("anilist").description("Unofficial AniList CLI").version("1.0.1");
17
17
  cli
18
18
  .command("login")
19
19
  .description("Login with AniList")
@@ -82,19 +82,29 @@ cli
82
82
  cli
83
83
  .command("delete")
84
84
  .alias("del")
85
- .description("Delete entire collections of anime or mang")
85
+ .description("Delete entire collections of anime or manga")
86
86
  .option("-a, --anime", "For anime list of authenticated user", false)
87
87
  .option("-m, --manga", "For manga list of authenticated user", false)
88
- .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ anime, manga }) {
89
- if ((!anime && !manga) || (anime && manga)) {
90
- console.error(`Must select an option, either --anime or --manga`);
88
+ .option("-ac, --activity", "For activity of authenticated user", false)
89
+ .action((_a) => __awaiter(void 0, [_a], void 0, function* ({ anime, manga, activity }) {
90
+ const selectedOptions = [anime, manga, activity].filter(Boolean).length;
91
+ if (selectedOptions === 0) {
92
+ console.error(`Must select one option: either --anime, --manga, or --activity`);
93
+ process.exit(1);
91
94
  }
92
- else if (anime) {
95
+ if (selectedOptions > 1) {
96
+ console.error(`Only one option can be selected at a time: --anime, --manga, or --activity`);
97
+ process.exit(1);
98
+ }
99
+ if (anime) {
93
100
  yield deleteAnimeCollection();
94
101
  }
95
102
  else if (manga) {
96
103
  yield deleteMangaCollection();
97
104
  }
105
+ else if (activity) {
106
+ yield deleteUserActivities();
107
+ }
98
108
  }));
99
109
  cli
100
110
  .command("upcoming")
@@ -105,7 +115,7 @@ cli
105
115
  yield getUpcomingAnimes(Number(count));
106
116
  }));
107
117
  cli
108
- .command("anime [id]")
118
+ .command("anime <id>")
109
119
  .description("Get anime details by their ID")
110
120
  .action((id) => __awaiter(void 0, void 0, void 0, function* () {
111
121
  if (id && !Number.isNaN(Number(id))) {
@@ -115,4 +125,28 @@ cli
115
125
  console.error("Invalid or missing ID. Please provide a valid numeric ID.");
116
126
  }
117
127
  }));
128
+ cli
129
+ .command("search <query>")
130
+ .alias("srch")
131
+ .alias("find")
132
+ .description("Search anime or manga.")
133
+ .option("-a, --anime", "To get the anime search results.", false)
134
+ .option("-m, --manga", "To get the manga search results.", false)
135
+ .option("-c, --count", "Number of search results to show.", "10")
136
+ .action((query_1, _a) => __awaiter(void 0, [query_1, _a], void 0, function* (query, { anime, manga, count }) {
137
+ if ((!anime && !manga) || (anime && manga)) {
138
+ console.error(`Must select an option, either --anime or --manga`);
139
+ }
140
+ else {
141
+ if (anime) {
142
+ yield getAnimeSearchResults(query, Number(count));
143
+ }
144
+ else if (manga) {
145
+ yield getMangaSearchResults(query, Number(count));
146
+ }
147
+ else {
148
+ console.error(`Must select an option, either --anime or --manga`);
149
+ }
150
+ }
151
+ }));
118
152
  cli.parse(process.argv);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@irfanshadikrishad/anilist",
3
3
  "description": "Unofficial AniList CLI",
4
4
  "author": "Irfan Shadik Rishad",
5
- "version": "1.0.1",
5
+ "version": "1.0.2",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "type": "git",
24
24
  "url": "https://github.com/irfanshadikrishad/anilist"
25
25
  },
26
+ "homepage": "https://github.com/irfanshadikrishad/anilist",
26
27
  "bugs": {
27
28
  "url": "https://github.com/irfanshadikrishad/anilist/issues"
28
29
  },
@@ -32,7 +33,6 @@
32
33
  "typescript": "^5.6.3"
33
34
  },
34
35
  "dependencies": {
35
- "chalk": "^5.3.0",
36
36
  "commander": "^12.1.0",
37
37
  "inquirer": "^12.0.0",
38
38
  "node-fetch": "^3.3.2",
@@ -1,5 +0,0 @@
1
- declare function colorize_Error(text: string): void;
2
- declare function colorize_Anilist(text: string): string;
3
- declare function colorize_Brown(text: string): string;
4
- declare function colorize_Hex(text: string, hex: string): void;
5
- export { colorize_Error, colorize_Anilist, colorize_Brown, colorize_Hex };
@@ -1,14 +0,0 @@
1
- import chalk from "chalk";
2
- function colorize_Error(text) {
3
- console.log(chalk.red(text));
4
- }
5
- function colorize_Anilist(text) {
6
- return chalk.hex("#03a8fc")(text);
7
- }
8
- function colorize_Brown(text) {
9
- return chalk.hex("#ce9c69")(text);
10
- }
11
- function colorize_Hex(text, hex) {
12
- console.log(chalk.hex(hex)(text));
13
- }
14
- export { colorize_Error, colorize_Anilist, colorize_Brown, colorize_Hex };