@irfanshadikrishad/anilist
Version:
Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts
697 lines (693 loc) • 37.7 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Cipher } from '@irfanshadikrishad/cipher';
import fs from 'fs';
import inquirer from 'inquirer';
import fetch from 'node-fetch';
import open from 'open';
import os from 'os';
import path from 'path';
import Spinner from 'tiny-spinner';
import { colorize } from '../lib/colorize.js';
import { fetcher } from './fetcher.js';
import { AniDB, AniList, MyAnimeList } from './lists.js';
import { deleteActivityMutation, deleteMangaEntryMutation, deleteMediaEntryMutation, saveTextActivityMutation, toggleFollowMutation, } from './mutations.js';
import { activityAllQuery, activityAnimeListQuery, activityMangaListQuery, activityMediaList, activityMessageQuery, activityTextQuery, currentUserAnimeList, currentUserMangaList, currentUserQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, } from './queries.js';
import { responsiveOutput } from './truncate.js';
import { aniListEndpoint, getTitle, redirectUri, timestampToTimeAgo, } from './workers.js';
const home_dir = os.homedir();
const save_path = path.join(home_dir, '.anilist_tok3n');
const spinner = new Spinner();
const vigenere = new Cipher.Vigenere('anilist');
class Auth {
/**
* Get access-token from user
*/
static GetAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
try {
const { token } = yield inquirer.prompt([
{
type: 'password',
name: 'token',
message: 'Please enter your AniList access token:',
},
]);
if (!token) {
console.warn('\nNo token entered. Please try again.');
return null;
}
return token;
}
catch (error) {
console.error(`\nAn error occurred while getting the access token: ${error.message}`);
return null;
}
});
}
static StoreAccessToken(token) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (!token) {
console.warn('\nNo token provided. Nothing to store.');
return;
}
fs.writeFileSync(save_path, vigenere.encrypt(token), { encoding: 'utf8' });
}
catch (error) {
console.error(`\nError storing access token: ${error.message}`);
}
});
}
static RetriveAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
try {
if (fs.existsSync(save_path)) {
return vigenere.decrypt(fs.readFileSync(save_path, { encoding: 'utf8' }));
}
else {
return null;
}
}
catch (error) {
console.error(`\nError retriving acess-token. ${error.message}`);
return null;
}
});
}
static Login(clientId, clientSecret) {
return __awaiter(this, void 0, void 0, function* () {
try {
console.log('Starting AniList login...');
const authUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`;
console.log('Opening browser for AniList login...');
open(authUrl);
const authCode = yield Auth.GetAccessToken();
const tokenResponse = yield fetch('https://anilist.co/api/v2/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: String(clientId),
client_secret: clientSecret,
redirect_uri: redirectUri,
code: authCode,
}),
});
const token_Data = yield tokenResponse.json();
if (token_Data === null || token_Data === void 0 ? void 0 : token_Data.access_token) {
yield Auth.StoreAccessToken(token_Data === null || token_Data === void 0 ? void 0 : token_Data.access_token);
const name = yield Auth.MyUserName();
if (name) {
console.log(`\nWelcome Back, ${name}!`);
}
else {
console.log(`\nLogged in successfull!`);
}
}
else {
console.error('\nFailed to get access token:', token_Data);
}
}
catch (error) {
console.error(`\nFailed logging in. ${error.message}`);
}
});
}
static Myself() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
try {
if (yield Auth.isLoggedIn()) {
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${yield Auth.RetriveAccessToken()}`,
};
const request = yield fetch(aniListEndpoint, {
method: 'POST',
headers: headers,
body: JSON.stringify({ query: currentUserQuery }),
});
const { data, errors } = yield request.json();
if (request.status === 200) {
const user = data === null || data === void 0 ? void 0 : data.Viewer;
const activiResponse = yield fetcher(userActivityQuery, {
id: user === null || user === void 0 ? void 0 : user.id,
page: 1,
perPage: 10,
});
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;
// Get follower/following information
const req_followers = yield fetcher(userFollowersQuery, {
userId: user === null || user === void 0 ? void 0 : user.id,
});
const req_following = yield fetcher(userFollowingQuery, {
userId: user === null || user === void 0 ? void 0 : user.id,
});
const followersCount = ((_e = (_d = (_c = req_followers === null || req_followers === void 0 ? void 0 : req_followers.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.pageInfo) === null || _e === void 0 ? void 0 : _e.total) || 0;
const followingCount = ((_h = (_g = (_f = req_following === null || req_following === void 0 ? void 0 : req_following.data) === null || _f === void 0 ? void 0 : _f.Page) === null || _g === void 0 ? void 0 : _g.pageInfo) === null || _h === void 0 ? void 0 : _h.total) || 0;
console.log(`
ID: ${user === null || user === void 0 ? void 0 : user.id}
Name: ${user === null || user === void 0 ? void 0 : user.name}
siteUrl: ${user === null || user === void 0 ? void 0 : user.siteUrl}
profileColor: ${(_j = user === null || user === void 0 ? void 0 : user.options) === null || _j === void 0 ? void 0 : _j.profileColor}
timeZone: ${(_k = user === null || user === void 0 ? void 0 : user.options) === null || _k === void 0 ? void 0 : _k.timezone}
activityMergeTime: ${(_l = user === null || user === void 0 ? void 0 : user.options) === null || _l === void 0 ? void 0 : _l.activityMergeTime}
donatorTier: ${user === null || user === void 0 ? void 0 : user.donatorTier}
donatorBadge: ${user === null || user === void 0 ? void 0 : user.donatorBadge}
unreadNotificationCount:${user === null || user === void 0 ? void 0 : user.unreadNotificationCount}
Account Created: ${new Date((user === null || user === void 0 ? void 0 : user.createdAt) * 1000).toUTCString()}
Account Updated: ${new Date((user === null || user === void 0 ? void 0 : user.updatedAt) * 1000).toUTCString()}
Followers: ${followersCount}
Following: ${followingCount}
Statistics (Anime):
Count: ${(_o = (_m = user === null || user === void 0 ? void 0 : user.statistics) === null || _m === void 0 ? void 0 : _m.anime) === null || _o === void 0 ? void 0 : _o.count}
Mean Score: ${(_q = (_p = user === null || user === void 0 ? void 0 : user.statistics) === null || _p === void 0 ? void 0 : _p.anime) === null || _q === void 0 ? void 0 : _q.meanScore}
Minutes Watched: ${(_s = (_r = user === null || user === void 0 ? void 0 : user.statistics) === null || _r === void 0 ? void 0 : _r.anime) === null || _s === void 0 ? void 0 : _s.minutesWatched}
Episodes Watched: ${(_u = (_t = user === null || user === void 0 ? void 0 : user.statistics) === null || _t === void 0 ? void 0 : _t.anime) === null || _u === void 0 ? void 0 : _u.episodesWatched}
Statistics (Manga):
Count: ${(_w = (_v = user === null || user === void 0 ? void 0 : user.statistics) === null || _v === void 0 ? void 0 : _v.manga) === null || _w === void 0 ? void 0 : _w.count}
Mean Score: ${(_y = (_x = user === null || user === void 0 ? void 0 : user.statistics) === null || _x === void 0 ? void 0 : _x.manga) === null || _y === void 0 ? void 0 : _y.meanScore}
Chapters Read: ${(_0 = (_z = user === null || user === void 0 ? void 0 : user.statistics) === null || _z === void 0 ? void 0 : _z.manga) === null || _0 === void 0 ? void 0 : _0.chaptersRead}
Volumes Read: ${(_2 = (_1 = user === null || user === void 0 ? void 0 : user.statistics) === null || _1 === void 0 ? void 0 : _1.manga) === null || _2 === void 0 ? void 0 : _2.volumesRead}
`);
console.log(`\nRecent Activities:`);
if (activities.length > 0) {
activities.map(({ status, progress, media, createdAt }) => {
responsiveOutput(`${timestampToTimeAgo(createdAt)}\t${status} ${progress ? `${progress} of ` : ''}${getTitle(media === null || media === void 0 ? void 0 : media.title)}`);
});
}
return user;
}
else {
console.error(`\nSomething went wrong. Please log in again. ${errors[0].message}`);
return null;
}
}
else {
console.error(`\nPlease login first to use this feature.`);
return null;
}
}
catch (error) {
console.error(`\nError from Myself. ${error.message}`);
}
});
}
static isLoggedIn() {
return __awaiter(this, void 0, void 0, function* () {
try {
const token = yield Auth.RetriveAccessToken();
return token !== null;
}
catch (error) {
console.error(`Error checking login status: ${error.message}`);
return false;
}
});
}
static Logout() {
return __awaiter(this, void 0, void 0, function* () {
try {
const username = yield Auth.MyUserName();
if (fs.existsSync(save_path)) {
try {
fs.unlinkSync(save_path);
console.log(`\nLogout successful. See you soon, ${username}.`);
}
catch (error) {
console.error('\nFailed to remove the save file during logout:', error.message);
}
}
else {
console.warn('\nNo active session found. You may already be logged out.');
}
}
catch (error) {
console.error(`\nAn error occurred during logout: ${error.message}`);
}
});
}
static MyUserId() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (!(yield Auth.isLoggedIn())) {
console.warn(`\nUser not logged in.`);
return null;
}
const { data } = yield fetcher(currentUserQuery, {});
return (_b = (_a = data === null || data === void 0 ? void 0 : data.Viewer) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
});
}
static MyUserName() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (!(yield Auth.isLoggedIn())) {
console.log(`\nUser not logged in.`);
return null;
}
const { data } = yield fetcher(currentUserQuery, {});
return (_b = (_a = data === null || data === void 0 ? void 0 : data.Viewer) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null;
});
}
static DeleteMyActivities() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
try {
if (!(yield Auth.isLoggedIn())) {
console.error(`\nPlease log in to delete your activities.`);
return;
}
const { activityType } = yield inquirer.prompt([
{
type: 'list',
name: 'activityType',
message: 'What type of activity you want to delete?',
choices: [
{ name: 'All Activity', value: 0 },
{ name: 'Text Activity', value: 1 },
{ name: 'Media List Activity', value: 2 },
{ name: 'Anime List Activity', value: 3 },
{ name: 'Manga List Activity', value: 4 },
{ name: 'Message Activity', value: 5 },
],
},
]);
const queryMap = {
0: activityAllQuery,
1: activityTextQuery,
2: activityMediaList,
3: activityAnimeListQuery,
4: activityMangaListQuery,
5: activityMessageQuery,
};
const query = queryMap[activityType];
let hasMoreActivities = true;
let totalCount = 0;
while (hasMoreActivities) {
const response = yield fetcher(query, {
page: 1,
perPage: 50,
userId: yield Auth.MyUserId(),
});
if ((_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) {
let count = 0;
const activities = (_d = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.Page) === null || _d === void 0 ? void 0 : _d.activities;
if (!activities || activities.length === 0) {
console.log(`\nNo more activities available.`);
hasMoreActivities = false;
}
else {
for (const act of activities) {
if (act === null || act === void 0 ? void 0 : act.id) {
const deleteResponse = yield fetcher(deleteActivityMutation, {
id: act === null || act === void 0 ? void 0 : act.id,
});
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;
count++;
totalCount++;
console.log(`[${count}/${activities.length}/${totalCount}]\t${act === null || act === void 0 ? void 0 : act.id} ${isDeleted ? '✔' : '✘'}`);
// Avoiding rate-limit
yield new Promise((resolve) => setTimeout(resolve, 1100));
}
}
}
}
else {
// In case of an unexpected null response, exit the loop
console.log(`\nProbably deleted all the activities of this type.`);
hasMoreActivities = false;
}
}
}
catch (error) {
console.error(`\nSomething went wrong. ${error.message}`);
}
});
}
static DeleteMyAnimeList() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
if (!(yield Auth.isLoggedIn())) {
console.error(`\nPlease log in first to delete your lists.`);
return;
}
if (!(yield Auth.MyUserId())) {
console.log(`\nFailed getting current user Id.`);
return;
}
const response = yield fetcher(currentUserAnimeList, { id: yield Auth.MyUserId() });
if (response !== null) {
const lists = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists;
if (lists.length > 0) {
const { selectedList } = yield inquirer.prompt([
{
type: 'select',
name: 'selectedList',
message: 'Select an anime list:',
choices: lists.map((list) => list.name),
pageSize: 10,
},
]);
const selectedEntries = lists.find((list) => list.name === selectedList);
if (selectedEntries) {
console.log(`\nDeleting entries of '${selectedEntries.name}':`);
for (const [, entry] of selectedEntries.entries.entries()) {
if (entry === null || entry === void 0 ? void 0 : entry.id) {
yield Auth.DeleteAnimeById(entry === null || entry === void 0 ? void 0 : entry.id, (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title);
yield new Promise((resolve) => setTimeout(resolve, 1100));
}
else {
console.log(`No id in entry.`);
console.log(entry);
}
}
}
else {
console.log('No entries found.');
}
}
else {
console.log(`\nNo anime(s) found in any list.`);
}
}
else {
console.log(`\nSomething went wrong. ${(_d = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _d === void 0 ? void 0 : _d.message}`);
}
});
}
static DeleteAnimeById(id, title) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
try {
const response = yield fetcher(deleteMediaEntryMutation, { id: id });
if (response === null || response === void 0 ? void 0 : response.data) {
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;
console.log(`del ${title ? getTitle(title) : ''} ${deleted ? '✔' : '✘'}`);
}
else {
console.log(`\nError deleting anime. ${(_c = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _c === void 0 ? void 0 : _c.message}`);
console.log(response);
}
}
catch (error) {
console.log(`\nError deleting anime. ${id} ${error.message}`);
}
});
}
static DeleteMyMangaList() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
try {
if (!(yield Auth.isLoggedIn())) {
console.error(`\nPlease log in first to delete your lists.`);
return;
}
if (!(yield Auth.MyUserId())) {
console.error(`\nFailed getting current user Id.`);
return;
}
const response = yield fetcher(currentUserMangaList, { id: yield Auth.MyUserId() });
if (!(response === null || response === void 0 ? void 0 : response.data)) {
console.error(`\nSomething went wrong. ${(_a = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _a === void 0 ? void 0 : _a.message}`);
return;
}
const lists = (_c = (_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.MediaListCollection) === null || _c === void 0 ? void 0 : _c.lists;
if (lists.length > 0) {
const { selectedList } = yield inquirer.prompt([
{
type: 'select',
name: 'selectedList',
message: 'Select a manga list:',
choices: lists.map((list) => list.name),
pageSize: 10,
},
]);
const selectedEntries = lists.find((list) => list.name === selectedList);
if (selectedEntries) {
console.log(`\nDeleting entries of '${selectedEntries.name}':`);
for (const [, entry] of selectedEntries.entries.entries()) {
if (entry === null || entry === void 0 ? void 0 : entry.id) {
yield Auth.DeleteMangaById(entry === null || entry === void 0 ? void 0 : entry.id, (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.title);
yield new Promise((resolve) => setTimeout(resolve, 1100));
}
else {
console.log(`No id in entry.`);
console.log(entry);
}
}
}
else {
console.error('\nNo entries found.');
}
}
else {
console.error(`\nNo manga(s) found in any list.`);
}
}
catch (error) {
console.error(`\nError deleting manga. ${error.message}`);
}
});
}
static DeleteMangaById(id, title) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
try {
const response = yield fetcher(deleteMangaEntryMutation, { id });
const statusMessage = title ? getTitle(title) : '';
if (response === null || response === void 0 ? void 0 : response.data) {
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;
console.log(`del ${statusMessage} ${deleted ? '✔' : '✘'}`);
}
else {
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}`);
}
}
catch (error) {
console.error(`Error deleting manga. ${id} ${error instanceof Error ? error.message : error}`);
}
});
}
static Write(status) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (!(yield Auth.isLoggedIn())) {
console.error(`\nPlease login to use this feature.`);
return;
}
const { data } = yield fetcher(saveTextActivityMutation, {
status: status,
});
if (!data) {
console.error(`\nSomething went wrong. ${data}.`);
return;
}
if (data.SaveTextActivity.id) {
console.log(`\n[${data.SaveTextActivity.id}] status saved successfully!`);
}
}
catch (error) {
console.error(`\n${error.message}`);
}
});
}
static callAnimeImporter() {
return __awaiter(this, void 0, void 0, function* () {
try {
const { source } = yield inquirer.prompt([
{
type: 'select',
name: 'source',
message: 'Select a source:',
choices: [
{ name: 'Exported JSON file.', value: 1 },
{ name: 'MyAnimeList (XML)', value: 2 },
{ name: 'AniDB (json-large)', value: 3 },
],
pageSize: 10,
},
]);
switch (source) {
case 1:
yield AniList.importAnime();
break;
case 2:
yield MyAnimeList.importAnime();
break;
case 3:
yield AniDB.importAnime();
break;
default:
console.log(`\nInvalid Choice.`);
break;
}
}
catch (error) {
console.error(`\n${error.message}`);
}
});
}
static callMangaImporter() {
return __awaiter(this, void 0, void 0, function* () {
try {
const { source } = yield inquirer.prompt([
{
type: 'select',
name: 'source',
message: 'Select a source:',
choices: [
{ name: 'Exported JSON file.', value: 1 },
{ name: 'MyAnimeList (XML)', value: 2 },
],
pageSize: 10,
},
]);
switch (source) {
case 1:
yield AniList.importManga();
break;
case 2:
yield MyAnimeList.importManga();
break;
default:
console.log(`\nInvalid Choice.`);
break;
}
}
catch (error) {
console.error(`\n${error.message}`);
}
});
}
}
class Social {
/**
* Follow the users that follows you
*/
static follow() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
try {
let pager = 1;
let hasNextPage = true;
const allFollowerUsers = [];
let followedBack = 0;
spinner.start('Fetching all the followers...');
while (hasNextPage) {
const followerUsers = yield fetcher(userFollowersQuery, {
userId: yield Auth.MyUserId(),
page: pager,
});
spinner.update(`Fetched page ${pager} of ${(_c = (_b = (_a = followerUsers === null || followerUsers === void 0 ? void 0 : followerUsers.data) === null || _a === void 0 ? void 0 : _a.Page) === null || _b === void 0 ? void 0 : _b.pageInfo) === null || _c === void 0 ? void 0 : _c.lastPage}...`);
if (!((_f = (_e = (_d = followerUsers === null || followerUsers === void 0 ? void 0 : followerUsers.data) === null || _d === void 0 ? void 0 : _d.Page) === null || _e === void 0 ? void 0 : _e.pageInfo) === null || _f === void 0 ? void 0 : _f.hasNextPage)) {
hasNextPage = false;
}
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) || []));
pager++;
}
spinner.stop('Fetched all the followers. Starting follow back.');
// Filter users that do no follow me
const notFollowing = allFollowerUsers
.filter(({ isFollowing }) => !isFollowing)
.map(({ id, name }) => ({ id: id, name: name }));
console.log(`\nTotal follower ${allFollowerUsers.length}.\nNot followed back ${notFollowing.length}\n`);
if (notFollowing.length <= 0) {
console.log(`Probably followed back all the users.`);
return;
}
// Traverse and follow back
const maxIdLength = Math.max(...notFollowing.map(({ id }) => String(id).length));
const maxNameLength = Math.max(...notFollowing.map(({ name }) => name.length));
for (const nf of notFollowing) {
try {
const follow = yield fetcher(toggleFollowMutation, { userId: nf.id });
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
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) {
followedBack++;
}
}
catch (error) {
console.log(`automate_follow_toggle_follow: ${error.message}`);
}
}
console.log(`\n${colorize.Green('✔')} Followed back ${followedBack} users.`);
}
catch (error) {
console.log(`\nautomate_follow ${error.message}`);
}
});
}
/**
* Unfollow the users thats not following you
*/
static unfollow() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
try {
let pager = 1;
let hasNextPage = true;
const allFollowingUsers = [];
let unfollowedUsers = 0;
spinner.start('Fetching all following users...');
while (hasNextPage) {
const followingUsers = yield fetcher(userFollowingQuery, {
userId: yield Auth.MyUserId(),
page: pager,
});
spinner.update(`Fetched page ${pager} of ${(_c = (_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.pageInfo) === null || _c === void 0 ? void 0 : _c.lastPage}...`);
if (!((_f = (_e = (_d = followingUsers === null || followingUsers === void 0 ? void 0 : followingUsers.data) === null || _d === void 0 ? void 0 : _d.Page) === null || _e === void 0 ? void 0 : _e.pageInfo) === null || _f === void 0 ? void 0 : _f.hasNextPage)) {
hasNextPage = false;
}
allFollowingUsers.push(...(((_h = (_g = followingUsers === null || followingUsers === void 0 ? void 0 : followingUsers.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.following) || []));
pager++;
}
spinner.update(`${colorize.Green('✔')} Fetching complete. Total got ${allFollowingUsers.length} users.`);
// Filter users that do no follow me
const notFollowingMe = allFollowingUsers
.filter((user) => !user.isFollower)
.map((u3r) => ({ id: u3r.id, name: u3r.name }));
if (notFollowingMe.length <= 0) {
spinner.stop(`No users to unfollow. Exiting operation...`);
return;
}
spinner.stop(`Unfollow process activated with ${notFollowingMe.length} users.`);
let nfmCount = 0;
console.log(`\n`);
for (const nfm of notFollowingMe) {
nfmCount++;
try {
const unfollow = yield fetcher(toggleFollowMutation, {
userId: nfm.id,
});
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('✘')}`);
// Count the unfollowed users
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) {
unfollowedUsers++;
}
}
catch (error) {
console.log(`unfollow_toggle_follow. ${error.message}`);
}
}
console.log(`\nTotal Unfollowed: ${unfollowedUsers} of ${nfmCount} users.`);
}
catch (error) {
console.error(`\nautomate_unfollow: ${error.message}`);
}
});
}
}
export { Auth, Social };