Davincible / goinsta

Unofficial Instagram API written in Golang (v2022)
MIT License
182 stars 56 forks source link

Sync to get FollowedBy #6

Closed tcurdt closed 3 years ago

tcurdt commented 3 years ago

Shouldn't the Sync update the FollowedBy. Seems to be always false for me.

    following := user.Following()
    for following.Next() {
      for _, f := range following.Users {
        err := f.Sync()
        if err != nil {
          logger.Printf("user=%s err=%s\n", f.Username, err)
        } else {
          logger.Printf("user=%s following=%v\n", f.Username, f.Friendship.FollowedBy)
        }
      }
    }
Davincible commented 3 years ago

@tcurdt I've just reinspected the requests the app makes when fetching the Following list, and unfortunately, the FollowedBy field is not present. This means you have to fetch the profile-info/friendship for each account individually to get this field. As such, if you want to get this information for a lot of profiles, an equal amount of requests has to be made at the minimum, so be careful with the request rates if you end up doing this.

tcurdt commented 3 years ago

That's a bummer. OK. Thanks for looking into that. Do you happen to know what the current request limits are?

tcurdt commented 3 years ago

Hm. This is still giving me false

following := user.Following()
for following.Next() {
  for _, f := range following.Users {

    logger.Printf("[%s] lookup\n", f.Username)
    u, err := insta.Profiles.ByName(f.Username)
    if err != nil {
      return
    }

    logger.Printf("[%s] following=%v followedby=%v\n", u.Username, u.Friendship.Following, u.Friendship.FollowedBy)

    randomizedSleep(1000*15)
  }
  randomizedSleep(millis)
}
Davincible commented 3 years ago

@tcurdt Yes, because ByName or ByID return a default user struct with minimal information (profile pic, bio etc.), you'd need to manually call extra methods to fetch either posts, or the friendship. The VisitProfile method as used in the wiki makes all these calls for you, but thus also makes much more calls, which might not be what you want in your usecase. To get the friendship of a 'bare' user you can call user.GetFriendship(). You can call this directly after ByName without delay.

This is a bit confusing in Go for these purposes I think, as it's hard to quickly see if a value is truly false, or just not set. Which is also why I used pointers for some child structs throughout goinsta so it's easier to check if it has been set or not.

About the limits, this is very hard to say, as it all happens internally in their servers, and shadow flagging and such happens without any user feedback. However I'd try to stick to things that make sense, what would more or less natural user behavior be.

tcurdt commented 3 years ago

Seems like the profile lookup is not even required. This here seems to do the job.

following := user.Following()
for following.Next() {
  for _, f := range following.Users {

    fs, err := f.GetFriendship()
    if err != nil {
      return
    }

    logger.Printf("[%s] following=%v followedby=%v\n", f.Username, fs.Following, fs.FollowedBy)

    randomizedSleep(1000*15)
  }
  randomizedSleep(millis)
}

Which kind of makes sense. Just to leave this here. Thanks for the help! ...and the fact that you are maintaining a fork!

Davincible commented 3 years ago

Glad you figured it out, and thanks! Happy to see people are using it