dilame / instagram-private-api

NodeJS Instagram private API SDK. Written in TypeScript.
MIT License
5.99k stars 1.14k forks source link

Unfollow Users who aren't following you. #1451

Open sell opened 3 years ago

sell commented 3 years ago

General Question

Form

Put an [x] if you meet the condition, else leave [ ].

Question

Hello, i have wrote a little code to unfollow users who aren't following you. Can you please take a look at it, and maybe add it as a template or you can critique and improve it.

Code

A meaningful section of your code (else delete this). If you are using TypeScript replace js with typescript.


const { IgApiClient } = require('instagram-private-api');

const ig = new IgApiClient();

ig.state.generateDevice(process.env.USERNAME);

(async () => {
    await ig.simulate.preLoginFlow();
    /*
     Logging in to account
     */
    const auth = await ig.account.login(process.env.USERNAME, process.env.PASSWORD);
    const followersFeed = ig.feed.accountFollowers(auth.pk);
    const followingFeed = ig.feed.accountFollowing(auth.pk);
    const followers = [
        ...await followersFeed.items(),
        ...await followersFeed.items(),
    ]
    const following = [
        ...await followingFeed.items(),
        ...await followingFeed.items(),
    ]
   /*
     Making a new set of all user usernames 
     */
    const users = new Set(followers.map(({ username }) => username));
    /*
     Filtering the ones who aren't following you back
     */ 
    const notFollowingYou = following.filter(({ username }) => !users.has(username));
    /*
     Loop through eash and unfollowing them.
     (suggested change by nerix)
     */
    for (const user of notFollowingYou) {
        await ig.friendship.destroy(user.pk);
        console.log(`unfollowed ${user.username}`)
    }
})();
Nerixyz commented 3 years ago

Can you please take a look at it, and maybe add it as a template or you can critique and improve it.

This really depends on the account you're doing this with.

Just to note: In the inapp followers-page, you can select accounts you don't follow back, however it's not supported in this library.

const followers = [
    ...await followersFeed.items(),
    ...await followersFeed.items(),
]
const following = [
    ...await followingFeed.items(),
    ...await followingFeed.items(),
]

Don't do this. This is only possible if you know how many followers the account has. You should use a function. It can be generic over the item of a feed. Here is an example (Comment).

notFollowingYou.forEach((user) => {
    ig.friendship.destroy(user.pk);
    console.log(`unfollowed ${user.username}`)
});

This code works but it will probably break if there are too many users,

  1. Use a for-each loop and await
for (const user of notFollowingYou) {
    await ig.friendship.destroy(user.pk);
    console.log(`unfollowed ${user.username}`)
}
  1. Optionally add a try-catch to handle errors
  2. Optionally add a delay between too many requests
sell commented 3 years ago

Thanks for the feedback, so in my original one I had a random delay between 3 and 10 seconds. I should of used a for-each loop, don't know why I didn't use it here, maybe because I was rushing.

Also, you're right should of used a try/catch as I am dealing with await here.

Thanks for the response and actually taking your time to write all of this, will make the neccesary changes. I assume, I don't need to update the code as others can just see your comment and make the changes themselves.

sell commented 3 years ago

@Nerixyz, made necessary changes. Here is a gist: https://gist.github.com/sell/be175dcd85954f41af94858ca231a3b4

Let me know, if this is much better.

Nerixyz commented 3 years ago
This is my attempt ```js const { IgApiClient } = require('instagram-private-api'); const { promisify } = require('util'); const sleep = promisify(setTimeout); const ig = new IgApiClient(); ig.state.generateDevice(process.env.USERNAME); (async () => { await ig.account.login(process.env.USERNAME, process.env.PASSWORD); const followersFeed = ig.feed.accountFollowers(ig.state.cookieUserId); const followingFeed = ig.feed.accountFollowing(ig.state.cookieUserId); const followers = await getAllItemsFromFeed(followersFeed); const following = await getAllItemsFromFeed(followingFeed); // Add all usernames to a set. This way, checking wether a user is a follower or not. const followerNames = new Set(followers.map(({ username }) => username)); // Get all the users that aren't in the followers-set and thus aren't following. const notFollowingYou = following.filter(({ username }) => !followerNames.has(username)) // Unfollow all users for (const user of notFollowingYou) { await ig.friendship.destroy(user.pk); console.log(`unfollowed ${user.username}`); // You can't unfollow all users immediately and you have to add some delay to the actions. // Keep in mind, this is just an example. const sleepTime = Math.round(Math.random() * (6000)) + 1000; await sleep(sleepTime); } })(); /** * Source: https://github.com/dilame/instagram-private-api/issues/969#issuecomment-551436680 * @param feed {} Any feed * @returns The items of the feed */ async function getAllItemsFromFeed(feed) { let items = []; do { items = items.concat(await feed.items()); // If there are too many items, you can also call `sleep` here. } while(feed.isMoreAvailable()); return items; } ```
sell commented 3 years ago

Maybe instead of importing util, maybe we can just do this?

const time = Math.round(Math.random() * (6000)) + 1000;
await new Promise((resolve) => setTimeout(resolve, time));

Just saves a few lines of code. Thanks for critiquing again, shall I make it into ts or will you do so?

Edit: Also, nice package you guys made.

Nerixyz commented 3 years ago

Maybe instead of importing util, maybe we can just do this?

Yeah it's essentially the same.

Thanks for critiquing again, shall I make it into ts or will you do so?

Feel free to open a PR.

sell commented 3 years ago

Feel free to open a PR.

PR Submitted