UNPKG

@irfanshadikrishad/anilist

Version:

Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts

696 lines (692 loc) 37.5 kB
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 { 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: "list", 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: "list", 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: "list", 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: "list", 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; let 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 (let 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) ? "✅" : "🈵"}`); // 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✅ 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; let 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(`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 (let 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) ? "✅" : "🈵"}`); // 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 };