@irfanshadikrishad/anilist 1.7.0 → 2.0.0-forbidden
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/LICENSE.md +382 -0
- package/README.md +0 -1
- package/bin/helpers/auth.d.ts +6 -1
- package/bin/helpers/auth.js +413 -78
- package/bin/helpers/fetcher.js +7 -7
- package/bin/helpers/lib/colorize.d.ts +8 -0
- package/bin/helpers/lib/colorize.js +19 -0
- package/bin/helpers/lists.d.ts +1 -5
- package/bin/helpers/lists.js +166 -289
- package/bin/helpers/mutations.d.ts +2 -2
- package/bin/helpers/mutations.js +6 -9
- package/bin/helpers/queries.d.ts +4 -1
- package/bin/helpers/queries.js +35 -1
- package/bin/helpers/truncate.js +2 -2
- package/bin/helpers/types.d.ts +53 -15
- package/bin/helpers/validation.js +8 -8
- package/bin/helpers/workers.d.ts +3 -2
- package/bin/helpers/workers.js +114 -94
- package/bin/index.js +79 -93
- package/package.json +87 -84
- package/CITATION.cff +0 -8
package/bin/helpers/auth.js
CHANGED
|
@@ -7,24 +7,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { Cipher } from
|
|
11
|
-
import fs from
|
|
12
|
-
import inquirer from
|
|
13
|
-
import fetch from
|
|
14
|
-
import open from
|
|
15
|
-
import os from
|
|
16
|
-
import path from
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
10
|
+
import { Cipher } from '@irfanshadikrishad/cipher';
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import inquirer from 'inquirer';
|
|
13
|
+
import fetch from 'node-fetch';
|
|
14
|
+
import open from 'open';
|
|
15
|
+
import os from 'os';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { exit } from 'process';
|
|
18
|
+
import Spinner from 'tiny-spinner';
|
|
19
|
+
import { fetcher } from './fetcher.js';
|
|
20
|
+
import { colorize } from './lib/colorize.js';
|
|
21
|
+
import { AniDB, AniList, MyAnimeList } from './lists.js';
|
|
22
|
+
import { deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, likeActivityMutation, saveTextActivityMutation, toggleFollowMutation, } from './mutations.js';
|
|
23
|
+
import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, followingActivitiesQuery, globalActivitiesQuery, specificUserActivitiesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from './queries.js';
|
|
24
|
+
import { responsiveOutput } from './truncate.js';
|
|
25
|
+
import { activityBy, aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from './workers.js';
|
|
24
26
|
const home_dir = os.homedir();
|
|
25
|
-
const save_path = path.join(home_dir,
|
|
27
|
+
const save_path = path.join(home_dir, '.anilist_token');
|
|
26
28
|
const spinner = new Spinner();
|
|
27
|
-
const vigenere = new Cipher.Vigenere(
|
|
29
|
+
const vigenere = new Cipher.Vigenere('anilist');
|
|
28
30
|
class Auth {
|
|
29
31
|
/**
|
|
30
32
|
* Get access-token from user
|
|
@@ -34,13 +36,13 @@ class Auth {
|
|
|
34
36
|
try {
|
|
35
37
|
const { token } = yield inquirer.prompt([
|
|
36
38
|
{
|
|
37
|
-
type:
|
|
38
|
-
name:
|
|
39
|
-
message:
|
|
39
|
+
type: 'password',
|
|
40
|
+
name: 'token',
|
|
41
|
+
message: 'Please enter your AniList access token:',
|
|
40
42
|
},
|
|
41
43
|
]);
|
|
42
44
|
if (!token) {
|
|
43
|
-
console.warn(
|
|
45
|
+
console.warn('\nNo token entered. Please try again.');
|
|
44
46
|
return null;
|
|
45
47
|
}
|
|
46
48
|
return token;
|
|
@@ -55,10 +57,10 @@ class Auth {
|
|
|
55
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
58
|
try {
|
|
57
59
|
if (!token) {
|
|
58
|
-
console.warn(
|
|
60
|
+
console.warn('\nNo token provided. Nothing to store.');
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
61
|
-
fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding:
|
|
63
|
+
fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: 'utf8' });
|
|
62
64
|
}
|
|
63
65
|
catch (error) {
|
|
64
66
|
console.error(`\nError storing access token: ${error.message}`);
|
|
@@ -69,7 +71,7 @@ class Auth {
|
|
|
69
71
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
72
|
try {
|
|
71
73
|
if (fs.existsSync(save_path)) {
|
|
72
|
-
return vigenere.decrypt(fs.readFileSync(save_path, { encoding:
|
|
74
|
+
return vigenere.decrypt(fs.readFileSync(save_path, { encoding: 'utf8' }));
|
|
73
75
|
}
|
|
74
76
|
else {
|
|
75
77
|
return null;
|
|
@@ -84,18 +86,18 @@ class Auth {
|
|
|
84
86
|
static Login(clientId, clientSecret) {
|
|
85
87
|
return __awaiter(this, void 0, void 0, function* () {
|
|
86
88
|
try {
|
|
87
|
-
console.log(
|
|
89
|
+
console.log('Starting AniList login...');
|
|
88
90
|
const authUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`;
|
|
89
|
-
console.log(
|
|
91
|
+
console.log('Opening browser for AniList login...');
|
|
90
92
|
open(authUrl);
|
|
91
93
|
const authCode = yield Auth.GetAccessToken();
|
|
92
|
-
const tokenResponse = yield fetch(
|
|
93
|
-
method:
|
|
94
|
+
const tokenResponse = yield fetch('https://anilist.co/api/v2/oauth/token', {
|
|
95
|
+
method: 'POST',
|
|
94
96
|
headers: {
|
|
95
|
-
|
|
97
|
+
'Content-Type': 'application/json',
|
|
96
98
|
},
|
|
97
99
|
body: JSON.stringify({
|
|
98
|
-
grant_type:
|
|
100
|
+
grant_type: 'authorization_code',
|
|
99
101
|
client_id: String(clientId),
|
|
100
102
|
client_secret: clientSecret,
|
|
101
103
|
redirect_uri: redirectUri,
|
|
@@ -114,7 +116,7 @@ class Auth {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
else {
|
|
117
|
-
console.error(
|
|
119
|
+
console.error('\nFailed to get access token:', token_Data);
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
catch (error) {
|
|
@@ -128,11 +130,11 @@ class Auth {
|
|
|
128
130
|
try {
|
|
129
131
|
if (yield Auth.isLoggedIn()) {
|
|
130
132
|
const headers = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
'Authorization': `Bearer ${yield Auth.RetriveAccessToken()}`,
|
|
133
135
|
};
|
|
134
136
|
const request = yield fetch(aniListEndpoint, {
|
|
135
|
-
method:
|
|
137
|
+
method: 'POST',
|
|
136
138
|
headers: headers,
|
|
137
139
|
body: JSON.stringify({ query: currentUserQuery }),
|
|
138
140
|
});
|
|
@@ -185,7 +187,7 @@ Statistics (Manga):
|
|
|
185
187
|
console.log(`\nRecent Activities:`);
|
|
186
188
|
if (activities.length > 0) {
|
|
187
189
|
activities.map(({ status, progress, media, createdAt }) => {
|
|
188
|
-
responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` :
|
|
190
|
+
responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ''}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
|
|
189
191
|
});
|
|
190
192
|
}
|
|
191
193
|
return user;
|
|
@@ -227,11 +229,11 @@ Statistics (Manga):
|
|
|
227
229
|
console.log(`\nLogout successful. See you soon, ${username}.`);
|
|
228
230
|
}
|
|
229
231
|
catch (error) {
|
|
230
|
-
console.error(
|
|
232
|
+
console.error('\nFailed to remove the save file during logout:', error.message);
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
else {
|
|
234
|
-
console.warn(
|
|
236
|
+
console.warn('\nNo active session found. You may already be logged out.');
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
catch (error) {
|
|
@@ -271,16 +273,16 @@ Statistics (Manga):
|
|
|
271
273
|
}
|
|
272
274
|
const { activityType } = yield inquirer.prompt([
|
|
273
275
|
{
|
|
274
|
-
type:
|
|
275
|
-
name:
|
|
276
|
-
message:
|
|
276
|
+
type: 'list',
|
|
277
|
+
name: 'activityType',
|
|
278
|
+
message: 'What type of activity you want to delete?',
|
|
277
279
|
choices: [
|
|
278
|
-
{ name:
|
|
279
|
-
{ name:
|
|
280
|
-
{ name:
|
|
281
|
-
{ name:
|
|
282
|
-
{ name:
|
|
283
|
-
{ name:
|
|
280
|
+
{ name: 'All Activity', value: 0 },
|
|
281
|
+
{ name: 'Text Activity', value: 1 },
|
|
282
|
+
{ name: 'Media List Activity', value: 2 },
|
|
283
|
+
{ name: 'Anime List Activity', value: 3 },
|
|
284
|
+
{ name: 'Manga List Activity', value: 4 },
|
|
285
|
+
{ name: 'Message Activity', value: 5 },
|
|
284
286
|
],
|
|
285
287
|
},
|
|
286
288
|
]);
|
|
@@ -317,7 +319,7 @@ Statistics (Manga):
|
|
|
317
319
|
const isDeleted = (_f = (_e = deleteResponse === null || deleteResponse === void 0 ? void 0 : deleteResponse.data) === null || _e === void 0 ? void 0 : _e.DeleteActivity) === null || _f === void 0 ? void 0 : _f.deleted;
|
|
318
320
|
count++;
|
|
319
321
|
totalCount++;
|
|
320
|
-
console.log(`[${count}/${activities.length}/${totalCount}]\t${act === null || act === void 0 ? void 0 : act.id} ${isDeleted ?
|
|
322
|
+
console.log(`[${count}/${activities.length}/${totalCount}]\t${act === null || act === void 0 ? void 0 : act.id} ${isDeleted ? colorize.Green('✔') : colorize.Red('✘')}`);
|
|
321
323
|
// Avoiding rate-limit
|
|
322
324
|
yield new Promise((resolve) => setTimeout(resolve, 1100));
|
|
323
325
|
}
|
|
@@ -353,9 +355,9 @@ Statistics (Manga):
|
|
|
353
355
|
if (lists.length > 0) {
|
|
354
356
|
const { selectedList } = yield inquirer.prompt([
|
|
355
357
|
{
|
|
356
|
-
type:
|
|
357
|
-
name:
|
|
358
|
-
message:
|
|
358
|
+
type: 'list',
|
|
359
|
+
name: 'selectedList',
|
|
360
|
+
message: 'Select an anime list:',
|
|
359
361
|
choices: lists.map((list) => list.name),
|
|
360
362
|
pageSize: 10,
|
|
361
363
|
},
|
|
@@ -375,7 +377,7 @@ Statistics (Manga):
|
|
|
375
377
|
}
|
|
376
378
|
}
|
|
377
379
|
else {
|
|
378
|
-
console.log(
|
|
380
|
+
console.log('No entries found.');
|
|
379
381
|
}
|
|
380
382
|
}
|
|
381
383
|
else {
|
|
@@ -394,7 +396,7 @@ Statistics (Manga):
|
|
|
394
396
|
const response = yield fetcher(deleteMediaEntryMutation, { id: id });
|
|
395
397
|
if (response === null || response === void 0 ? void 0 : response.data) {
|
|
396
398
|
const deleted = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.DeleteMediaListEntry) === null || _b === void 0 ? void 0 : _b.deleted;
|
|
397
|
-
console.log(`del ${title ? getTitle(title) :
|
|
399
|
+
console.log(`del ${title ? getTitle(title) : ''} ${deleted ? colorize.Green('✔') : colorize.Red('✘')}`);
|
|
398
400
|
}
|
|
399
401
|
else {
|
|
400
402
|
console.log(`\nError deleting anime. ${(_c = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _c === void 0 ? void 0 : _c.message}`);
|
|
@@ -427,9 +429,9 @@ Statistics (Manga):
|
|
|
427
429
|
if (lists.length > 0) {
|
|
428
430
|
const { selectedList } = yield inquirer.prompt([
|
|
429
431
|
{
|
|
430
|
-
type:
|
|
431
|
-
name:
|
|
432
|
-
message:
|
|
432
|
+
type: 'list',
|
|
433
|
+
name: 'selectedList',
|
|
434
|
+
message: 'Select a manga list:',
|
|
433
435
|
choices: lists.map((list) => list.name),
|
|
434
436
|
pageSize: 10,
|
|
435
437
|
},
|
|
@@ -449,7 +451,7 @@ Statistics (Manga):
|
|
|
449
451
|
}
|
|
450
452
|
}
|
|
451
453
|
else {
|
|
452
|
-
console.error(
|
|
454
|
+
console.error('\nNo entries found.');
|
|
453
455
|
}
|
|
454
456
|
}
|
|
455
457
|
else {
|
|
@@ -466,10 +468,10 @@ Statistics (Manga):
|
|
|
466
468
|
var _a, _b, _c, _d;
|
|
467
469
|
try {
|
|
468
470
|
const response = yield fetcher(deleteMangaEntryMutation, { id });
|
|
469
|
-
const statusMessage = title ? getTitle(title) :
|
|
471
|
+
const statusMessage = title ? getTitle(title) : '';
|
|
470
472
|
if (response === null || response === void 0 ? void 0 : response.data) {
|
|
471
473
|
const deleted = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.DeleteMediaListEntry) === null || _b === void 0 ? void 0 : _b.deleted;
|
|
472
|
-
console.log(`del ${statusMessage} ${deleted ?
|
|
474
|
+
console.log(`del ${statusMessage} ${deleted ? colorize.Green('✔') : colorize.Red('✘')}`);
|
|
473
475
|
}
|
|
474
476
|
else {
|
|
475
477
|
console.error(`Error deleting manga. ${(_d = (_c = response === null || response === void 0 ? void 0 : response.errors) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.message}`);
|
|
@@ -508,13 +510,13 @@ Statistics (Manga):
|
|
|
508
510
|
try {
|
|
509
511
|
const { source } = yield inquirer.prompt([
|
|
510
512
|
{
|
|
511
|
-
type:
|
|
512
|
-
name:
|
|
513
|
-
message:
|
|
513
|
+
type: 'list',
|
|
514
|
+
name: 'source',
|
|
515
|
+
message: 'Select a source:',
|
|
514
516
|
choices: [
|
|
515
|
-
{ name:
|
|
516
|
-
{ name:
|
|
517
|
-
{ name:
|
|
517
|
+
{ name: 'Exported JSON file.', value: 1 },
|
|
518
|
+
{ name: 'MyAnimeList (XML)', value: 2 },
|
|
519
|
+
{ name: 'AniDB (json-large)', value: 3 },
|
|
518
520
|
],
|
|
519
521
|
pageSize: 10,
|
|
520
522
|
},
|
|
@@ -544,12 +546,12 @@ Statistics (Manga):
|
|
|
544
546
|
try {
|
|
545
547
|
const { source } = yield inquirer.prompt([
|
|
546
548
|
{
|
|
547
|
-
type:
|
|
548
|
-
name:
|
|
549
|
-
message:
|
|
549
|
+
type: 'list',
|
|
550
|
+
name: 'source',
|
|
551
|
+
message: 'Select a source:',
|
|
550
552
|
choices: [
|
|
551
|
-
{ name:
|
|
552
|
-
{ name:
|
|
553
|
+
{ name: 'Exported JSON file.', value: 1 },
|
|
554
|
+
{ name: 'MyAnimeList (XML)', value: 2 },
|
|
553
555
|
],
|
|
554
556
|
pageSize: 10,
|
|
555
557
|
},
|
|
@@ -571,6 +573,342 @@ Statistics (Manga):
|
|
|
571
573
|
}
|
|
572
574
|
});
|
|
573
575
|
}
|
|
576
|
+
static LikeFollowing() {
|
|
577
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
578
|
+
var _a, _b, _c, _d, _e, _f;
|
|
579
|
+
try {
|
|
580
|
+
let page = 1;
|
|
581
|
+
let hasMoreActivities = true;
|
|
582
|
+
let retryCount = 0;
|
|
583
|
+
const maxRetries = 5;
|
|
584
|
+
let likedCount = 0;
|
|
585
|
+
while (hasMoreActivities) {
|
|
586
|
+
const activities = yield fetcher(followingActivitiesQuery, {
|
|
587
|
+
page,
|
|
588
|
+
perPage: 50,
|
|
589
|
+
});
|
|
590
|
+
if (activities && ((_b = (_a = activities === null || activities === void 0 ? void 0 : activities.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities.length) > 0) {
|
|
591
|
+
spinner.success(`Got ${(_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities.length} activities..`);
|
|
592
|
+
retryCount = 0; // Reset retry count on successful fetch
|
|
593
|
+
const activiti = (_f = (_e = activities === null || activities === void 0 ? void 0 : activities.data) === null || _e === void 0 ? void 0 : _e.Page) === null || _f === void 0 ? void 0 : _f.activities;
|
|
594
|
+
for (let activ of activiti) {
|
|
595
|
+
if (!activ.isLiked && activ.id) {
|
|
596
|
+
try {
|
|
597
|
+
const like = yield fetcher(likeActivityMutation, {
|
|
598
|
+
activityId: activ.id,
|
|
599
|
+
});
|
|
600
|
+
if (like === null || like === void 0 ? void 0 : like.data) {
|
|
601
|
+
likedCount++;
|
|
602
|
+
}
|
|
603
|
+
responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
console.error(`Activity possibly deleted. ${error.message}`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
|
|
611
|
+
}
|
|
612
|
+
// avoiding rate-limit
|
|
613
|
+
yield new Promise((resolve) => {
|
|
614
|
+
setTimeout(resolve, 2000);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
page++;
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
if (retryCount < maxRetries) {
|
|
621
|
+
spinner.start('Getting activities...');
|
|
622
|
+
retryCount++;
|
|
623
|
+
spinner.update(`Empty activities returned. Retrying... (${retryCount}/${maxRetries})`);
|
|
624
|
+
yield new Promise((resolve) => setTimeout(resolve, 2000));
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
spinner.error(`Probably the end of activities after ${maxRetries} retries.`);
|
|
628
|
+
hasMoreActivities = false;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch (error) {
|
|
634
|
+
console.error(`\nError from likeFollowing. ${error.message}`);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
static LikeGlobal() {
|
|
639
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
640
|
+
var _a, _b, _c, _d, _e, _f;
|
|
641
|
+
try {
|
|
642
|
+
let page = 1;
|
|
643
|
+
let hasMoreActivities = true;
|
|
644
|
+
let likedCount = 0;
|
|
645
|
+
spinner.start(`Getting global activities...`);
|
|
646
|
+
while (hasMoreActivities) {
|
|
647
|
+
const activities = yield fetcher(globalActivitiesQuery, {
|
|
648
|
+
page,
|
|
649
|
+
perPage: 50,
|
|
650
|
+
});
|
|
651
|
+
if (activities && ((_b = (_a = activities === null || activities === void 0 ? void 0 : activities.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.activities.length) > 0) {
|
|
652
|
+
const activiti = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities;
|
|
653
|
+
spinner.success(`Got ${activiti.length} activities...`);
|
|
654
|
+
for (let activ of activiti) {
|
|
655
|
+
if (!activ.isLiked && activ.id) {
|
|
656
|
+
try {
|
|
657
|
+
const like = yield fetcher(likeActivityMutation, {
|
|
658
|
+
activityId: activ.id,
|
|
659
|
+
});
|
|
660
|
+
// const ToggleLike = like?.data?.ToggleLike
|
|
661
|
+
likedCount++;
|
|
662
|
+
responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
console.error(`Activity possibly deleted. ${error.message}`);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
|
|
670
|
+
}
|
|
671
|
+
// avoiding rate-limit
|
|
672
|
+
yield new Promise((resolve) => {
|
|
673
|
+
setTimeout(resolve, 1500);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
page++;
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
// No more activities to like
|
|
680
|
+
spinner.error(`Probably the end of activities. ${(_f = (_e = activities === null || activities === void 0 ? void 0 : activities.data) === null || _e === void 0 ? void 0 : _e.Page) === null || _f === void 0 ? void 0 : _f.activities}`);
|
|
681
|
+
hasMoreActivities = false;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
catch (error) {
|
|
686
|
+
console.error(`\nError from likeFollowing. ${error.message}`);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
static LikeSpecificUser() {
|
|
691
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
692
|
+
var _a, _b, _c, _d;
|
|
693
|
+
try {
|
|
694
|
+
const { username } = yield inquirer.prompt([
|
|
695
|
+
{
|
|
696
|
+
type: 'input',
|
|
697
|
+
name: 'username',
|
|
698
|
+
message: 'Username of the user:',
|
|
699
|
+
},
|
|
700
|
+
]);
|
|
701
|
+
const { toLikeAmount } = yield inquirer.prompt([
|
|
702
|
+
{
|
|
703
|
+
type: 'number',
|
|
704
|
+
name: 'toLikeAmount',
|
|
705
|
+
message: 'Likes to give:',
|
|
706
|
+
},
|
|
707
|
+
]);
|
|
708
|
+
const userDetails = yield fetcher(userQuery, { username: username });
|
|
709
|
+
spinner.start(`Getting activities by ${username}`);
|
|
710
|
+
if ((_b = (_a = userDetails === null || userDetails === void 0 ? void 0 : userDetails.data) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.id) {
|
|
711
|
+
let page = 1;
|
|
712
|
+
const perPage = 50;
|
|
713
|
+
const userId = userDetails.data.User.id;
|
|
714
|
+
let likedCount = 0;
|
|
715
|
+
while (likedCount < toLikeAmount) {
|
|
716
|
+
const activities = yield fetcher(specificUserActivitiesQuery, {
|
|
717
|
+
page,
|
|
718
|
+
perPage,
|
|
719
|
+
userId,
|
|
720
|
+
});
|
|
721
|
+
const activiti = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities;
|
|
722
|
+
if (!activiti || activiti.length === 0) {
|
|
723
|
+
spinner.error('No more activities found.');
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
spinner.success(`Got ${activiti.length} activities...`);
|
|
727
|
+
for (let activ of activiti) {
|
|
728
|
+
if (!activ.isLiked && activ.id) {
|
|
729
|
+
try {
|
|
730
|
+
const like = yield fetcher(likeActivityMutation, {
|
|
731
|
+
activityId: activ.id,
|
|
732
|
+
});
|
|
733
|
+
likedCount++;
|
|
734
|
+
responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, likedCount)}`);
|
|
735
|
+
if (likedCount >= toLikeAmount) {
|
|
736
|
+
spinner.success(`Finished liking ${likedCount} activities of ${username}.`);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
console.error(`Activity possibly deleted. ${error.message}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, likedCount)}`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
page += 1;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
spinner.error(`User ${username} does not exist.`);
|
|
753
|
+
exit(1);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
console.error(`\nError from LikeSpecificUser. ${error.message}`);
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
static LikeFollowingActivityV2(perPage) {
|
|
762
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
763
|
+
var _a, _b, _c, _d, _e;
|
|
764
|
+
try {
|
|
765
|
+
if (!(yield Auth.isLoggedIn())) {
|
|
766
|
+
console.error(`\nPlease log in to use this feature.`);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const allFollowingUsers = [];
|
|
770
|
+
let hasNextPage = true;
|
|
771
|
+
let page = 1;
|
|
772
|
+
let liked = 0;
|
|
773
|
+
// ------------------------
|
|
774
|
+
// Fetch all following users
|
|
775
|
+
// ------------------------
|
|
776
|
+
spinner.start(`Gathering following information...`);
|
|
777
|
+
while (hasNextPage) {
|
|
778
|
+
spinner.update(`Fetched page ${page}...`);
|
|
779
|
+
const followingUsers = yield fetcher(userFollowingQuery, {
|
|
780
|
+
userId: yield Auth.MyUserId(),
|
|
781
|
+
page,
|
|
782
|
+
});
|
|
783
|
+
if (!((_b = (_a = followingUsers === null || followingUsers === void 0 ? void 0 : followingUsers.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.following)) {
|
|
784
|
+
console.error(`\nFailed to fetch following users.`);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
allFollowingUsers.push(...followingUsers.data.Page.following);
|
|
788
|
+
hasNextPage = followingUsers.data.Page.pageInfo.hasNextPage;
|
|
789
|
+
page++;
|
|
790
|
+
}
|
|
791
|
+
spinner.stop(`Got ${allFollowingUsers.length} following user.`);
|
|
792
|
+
// Extract the IDs of all following users
|
|
793
|
+
const followingUserIds = allFollowingUsers.map((user) => user.id);
|
|
794
|
+
// --------------------
|
|
795
|
+
// APPROXIMATE TIME
|
|
796
|
+
// --------------------
|
|
797
|
+
const totalActivities = followingUserIds.length * perPage;
|
|
798
|
+
const perActivityTimeInSec = 1;
|
|
799
|
+
const rateLimitTimeInSec = 60;
|
|
800
|
+
const batchSize = 29;
|
|
801
|
+
const batches = Math.floor(totalActivities / batchSize);
|
|
802
|
+
const remaining = totalActivities % batchSize;
|
|
803
|
+
const processingTime = batches * batchSize * perActivityTimeInSec +
|
|
804
|
+
remaining * perActivityTimeInSec;
|
|
805
|
+
const waitTime = (batches - 1) * rateLimitTimeInSec;
|
|
806
|
+
const totalWaitTimeInSec = processingTime + (batches > 0 ? waitTime : 0);
|
|
807
|
+
const hours = Math.floor(totalWaitTimeInSec / 3600);
|
|
808
|
+
const minutes = Math.floor((totalWaitTimeInSec % 3600) / 60);
|
|
809
|
+
const seconds = totalWaitTimeInSec % 60;
|
|
810
|
+
const time = `${String(hours).padStart(2, '0')}h ${String(minutes).padStart(2, '0')}m ${String(seconds).padStart(2, '0')}s`;
|
|
811
|
+
console.log(`\nTotal following: ${followingUserIds.length}\nApproximately ${totalActivities} to like.\nWill take around ${time}`);
|
|
812
|
+
// -------------------
|
|
813
|
+
// Traverse the array and
|
|
814
|
+
// fetch users' activities one by one
|
|
815
|
+
// -------------------
|
|
816
|
+
let userNumber = 0;
|
|
817
|
+
for (const userId of followingUserIds) {
|
|
818
|
+
userNumber++;
|
|
819
|
+
console.log(`\n[${userNumber}]\tID: ${userId}`);
|
|
820
|
+
// Fetch `perPage` activities for the current user
|
|
821
|
+
const activities = yield fetcher(specificUserActivitiesQuery, {
|
|
822
|
+
userId,
|
|
823
|
+
page: 1, // Always fetch from the first page
|
|
824
|
+
perPage,
|
|
825
|
+
});
|
|
826
|
+
if (!((_e = (_d = (_c = activities === null || activities === void 0 ? void 0 : activities.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
827
|
+
console.log(`[${userNumber}] No activities found for User ID: ${userId}`);
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
const activiti = activities.data.Page.activities;
|
|
831
|
+
for (let i = 0; i < activiti.length; i++) {
|
|
832
|
+
const activ = activiti[i];
|
|
833
|
+
if (!activ.isLiked && activ.id) {
|
|
834
|
+
try {
|
|
835
|
+
const like = yield fetcher(likeActivityMutation, {
|
|
836
|
+
activityId: activ.id,
|
|
837
|
+
});
|
|
838
|
+
responsiveOutput(`${(like === null || like === void 0 ? void 0 : like.data) ? colorize.Green('✔') : colorize.Red('✘')} ${activityBy(activ, i + 1)}`);
|
|
839
|
+
if (like === null || like === void 0 ? void 0 : like.data) {
|
|
840
|
+
liked++;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
catch (error) {
|
|
844
|
+
console.error(`Activity possibly deleted. ${error.message}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
responsiveOutput(`${colorize.Yellow('⚉')} ${activityBy(activ, i + 1)}`);
|
|
849
|
+
}
|
|
850
|
+
// Avoid rate-limiting
|
|
851
|
+
yield new Promise((resolve) => setTimeout(resolve, 1200));
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
console.log(`\n${colorize.Green('✔')} All ${liked} activities liked successfully.`);
|
|
855
|
+
}
|
|
856
|
+
catch (error) {
|
|
857
|
+
console.error(`\nError in LikeFollowingActivityV2: ${error.message}`);
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
static AutoLike() {
|
|
862
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
863
|
+
try {
|
|
864
|
+
if (!(yield Auth.isLoggedIn())) {
|
|
865
|
+
console.error(`\nPlease login to use this feature.`);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const { activityType } = yield inquirer.prompt([
|
|
869
|
+
{
|
|
870
|
+
type: 'list',
|
|
871
|
+
name: 'activityType',
|
|
872
|
+
message: 'Select activity type:',
|
|
873
|
+
choices: [
|
|
874
|
+
{ name: 'Following • v1', value: 1 },
|
|
875
|
+
{ name: 'Following • v2', value: 2 },
|
|
876
|
+
{ name: 'Global', value: 3 },
|
|
877
|
+
{ name: 'Specific User', value: 4 },
|
|
878
|
+
],
|
|
879
|
+
pageSize: 10,
|
|
880
|
+
},
|
|
881
|
+
]);
|
|
882
|
+
switch (activityType) {
|
|
883
|
+
case 1:
|
|
884
|
+
yield this.LikeFollowing();
|
|
885
|
+
break;
|
|
886
|
+
case 2: {
|
|
887
|
+
const { count } = yield inquirer.prompt([
|
|
888
|
+
{
|
|
889
|
+
type: 'number',
|
|
890
|
+
name: 'count',
|
|
891
|
+
message: 'Likes to give:',
|
|
892
|
+
},
|
|
893
|
+
]);
|
|
894
|
+
yield this.LikeFollowingActivityV2(count);
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
case 3:
|
|
898
|
+
yield this.LikeGlobal();
|
|
899
|
+
break;
|
|
900
|
+
case 4:
|
|
901
|
+
yield this.LikeSpecificUser();
|
|
902
|
+
break;
|
|
903
|
+
default:
|
|
904
|
+
console.error(`\nInvalid choice. (${activityType})`);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
catch (error) {
|
|
908
|
+
console.error(`\nError from autolike. ${error.message}`);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
}
|
|
574
912
|
}
|
|
575
913
|
class Social {
|
|
576
914
|
/**
|
|
@@ -584,7 +922,7 @@ class Social {
|
|
|
584
922
|
let hasNextPage = true;
|
|
585
923
|
let allFollowerUsers = [];
|
|
586
924
|
let followedBack = 0;
|
|
587
|
-
spinner.start(
|
|
925
|
+
spinner.start('Fetching all the followers...');
|
|
588
926
|
while (hasNextPage) {
|
|
589
927
|
const followerUsers = yield fetcher(userFollowersQuery, {
|
|
590
928
|
userId: yield Auth.MyUserId(),
|
|
@@ -597,7 +935,7 @@ class Social {
|
|
|
597
935
|
allFollowerUsers.push(...(((_h = (_g = followerUsers === null || followerUsers === void 0 ? void 0 : followerUsers.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.followers) || []));
|
|
598
936
|
pager++;
|
|
599
937
|
}
|
|
600
|
-
spinner.stop(
|
|
938
|
+
spinner.stop('Fetched all the followers. Starting follow back.');
|
|
601
939
|
// Filter users that do no follow me
|
|
602
940
|
const notFollowing = allFollowerUsers
|
|
603
941
|
.filter(({ isFollowing }) => !isFollowing)
|
|
@@ -613,10 +951,7 @@ class Social {
|
|
|
613
951
|
for (let nf of notFollowing) {
|
|
614
952
|
try {
|
|
615
953
|
const follow = yield fetcher(toggleFollowMutation, { userId: nf.id });
|
|
616
|
-
console.log(`${String(`[${nf.id}]`).padEnd(maxIdLength)}`
|
|
617
|
-
`\t${String(`[${(_k = (_j = follow === null || follow === void 0 ? void 0 : follow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]`).padEnd(maxNameLength)}` +
|
|
618
|
-
`\t${((_m = (_l = follow === null || follow === void 0 ? void 0 : follow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? "✅" : "🈵"}`);
|
|
619
|
-
// Count the followed back users
|
|
954
|
+
console.log(`${String(`[${nf.id}]`).padEnd(maxIdLength)}\t${String(`[${(_k = (_j = follow === null || follow === void 0 ? void 0 : follow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]`).padEnd(maxNameLength)}\t${((_m = (_l = follow === null || follow === void 0 ? void 0 : follow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? colorize.Green('✔') : colorize.Red('✘')}`); // Count the followed back users
|
|
620
955
|
if ((_p = (_o = follow === null || follow === void 0 ? void 0 : follow.data) === null || _o === void 0 ? void 0 : _o.ToggleFollow) === null || _p === void 0 ? void 0 : _p.id) {
|
|
621
956
|
followedBack++;
|
|
622
957
|
}
|
|
@@ -625,7 +960,7 @@ class Social {
|
|
|
625
960
|
console.log(`automate_follow_toggle_follow: ${error.message}`);
|
|
626
961
|
}
|
|
627
962
|
}
|
|
628
|
-
console.log(`\n
|
|
963
|
+
console.log(`\n${colorize.Green('✔')} Followed back ${followedBack} users.`);
|
|
629
964
|
}
|
|
630
965
|
catch (error) {
|
|
631
966
|
console.log(`\nautomate_follow ${error.message}`);
|
|
@@ -643,7 +978,7 @@ class Social {
|
|
|
643
978
|
let hasNextPage = true;
|
|
644
979
|
let allFollowingUsers = [];
|
|
645
980
|
let unfollowedUsers = 0;
|
|
646
|
-
spinner.start(
|
|
981
|
+
spinner.start('Fetching all following users...');
|
|
647
982
|
while (hasNextPage) {
|
|
648
983
|
const followingUsers = yield fetcher(userFollowingQuery, {
|
|
649
984
|
userId: yield Auth.MyUserId(),
|
|
@@ -674,7 +1009,7 @@ class Social {
|
|
|
674
1009
|
const unfollow = yield fetcher(toggleFollowMutation, {
|
|
675
1010
|
userId: nfm.id,
|
|
676
1011
|
});
|
|
677
|
-
console.log(`[${nfm.id}]\t[${(_k = (_j = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]\t${((_m = (_l = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ?
|
|
1012
|
+
console.log(`[${nfm.id}]\t[${(_k = (_j = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _j === void 0 ? void 0 : _j.ToggleFollow) === null || _k === void 0 ? void 0 : _k.name}]\t${((_m = (_l = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _l === void 0 ? void 0 : _l.ToggleFollow) === null || _m === void 0 ? void 0 : _m.id) ? colorize.Green('✔') : colorize.Red('✘')}`);
|
|
678
1013
|
// Count the unfollowed users
|
|
679
1014
|
if ((_p = (_o = unfollow === null || unfollow === void 0 ? void 0 : unfollow.data) === null || _o === void 0 ? void 0 : _o.ToggleFollow) === null || _p === void 0 ? void 0 : _p.id) {
|
|
680
1015
|
unfollowedUsers++;
|
|
@@ -684,7 +1019,7 @@ class Social {
|
|
|
684
1019
|
console.log(`unfollow_toggle_follow. ${error.message}`);
|
|
685
1020
|
}
|
|
686
1021
|
}
|
|
687
|
-
console.log(`\
|
|
1022
|
+
console.log(`\n${colorize.Green('✔')} Total Unfollowed: ${unfollowedUsers} of ${nfmCount} users.`);
|
|
688
1023
|
}
|
|
689
1024
|
catch (error) {
|
|
690
1025
|
console.error(`\nautomate_unfollow: ${error.message}`);
|