Skip to content

Commit

Permalink
feat: get following by sort order (earliest, latest)
Browse files Browse the repository at this point in the history
  • Loading branch information
Davincible committed Sep 14, 2022
1 parent 3dd6a5b commit 27d9fde
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 55 deletions.
40 changes: 24 additions & 16 deletions account.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,28 +275,36 @@ func (account *Account) changePublic(endpoint string) error {

// Followers returns a list of user followers.
//
// Users.Next can be used to paginate
// Query can be used to search for a specific user.
// Be aware that it only matches from the start, e.g.
// "theprimeagen" will only match "theprime" not "prime".
// To fetch all user an empty string "".
//
// See example: examples/account/followers.go
func (account *Account) Followers() *Users {
endpoint := fmt.Sprintf(urlFollowers, account.ID)
users := &Users{}
users.insta = account.insta
users.endpoint = endpoint
return users
// Users.Next can be used to paginate
func (account *Account) Followers(query string, order FollowOrder) *Users {
user := &User{
insta: account.insta,
ID: account.ID,
}

return user.Followers(query, order)
}

// Following returns a list of user following.
//
// Users.Next can be used to paginate
// Query can be used to search for a specific user.
// Be aware that it only matches from the start, e.g.
// "theprimeagen" will only match "theprime" not "prime".
// To fetch all user an empty string "".
//
// See example: examples/account/following.go
func (account *Account) Following() *Users {
endpoint := fmt.Sprintf(urlFollowing, account.ID)
users := &Users{}
users.insta = account.insta
users.endpoint = endpoint
return users
// Users.Next can be used to paginate
func (account *Account) Following(query string, order FollowOrder) *Users {
user := &User{
insta: account.insta,
ID: account.ID,
}

return user.Following(query, order)
}

// Feed returns current account feed
Expand Down
35 changes: 35 additions & 0 deletions tests/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,38 @@ func TestPendingFriendships(t *testing.T) {
}
t.Logf("After approving there are %d pending friendships remaining\n", count)
}

func TestFollowList(t *testing.T) {
insta, err := goinsta.EnvRandAcc()
if err != nil {
t.Fatal(err)
}
t.Logf("Logged in as %s\n", insta.Account.Username)

users := insta.Account.Following("", goinsta.DefaultOrder)
for users.Next() {
t.Logf("Fetched %d following", len(users.Users))
}
t.Logf("Fetched %d following", len(users.Users))
if users.Error() != goinsta.ErrNoMore {
t.Fatal(users.Error())
}

users = insta.Account.Following("", goinsta.LatestOrder)
for users.Next() {
t.Logf("Fetched %d following (latest order)", len(users.Users))
}
t.Logf("Fetched %d following (latest order)", len(users.Users))
if users.Error() != goinsta.ErrNoMore {
t.Fatal(users.Error())
}

users = insta.Account.Followers("", goinsta.DefaultOrder)
for users.Next() {
t.Logf("Fetched %d followers", len(users.Users))
}
t.Logf("Fetched %d followers", len(users.Users))
if users.Error() != goinsta.ErrNoMore {
t.Fatal(users.Error())
}
}
114 changes: 75 additions & 39 deletions users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ import (
"time"
)

type FollowOrder string

const (
DefaultOrder FollowOrder = "default"
LatestOrder FollowOrder = "date_followed_latest"
EarliestOrder FollowOrder = "date_followed_earliest"
)

// Users is a struct that stores many user's returned by many different methods.
type Users struct {
insta *Instagram

// It's a bit confusing have the same structure
// It's a bit confusing to have the same structure
// in the Instagram strucure and in the multiple users
// calls

err error
endpoint string
query map[string]string

Status string `json:"status"`
BigList bool `json:"big_list"`
Expand All @@ -27,12 +36,6 @@ type Users struct {
NextID string `json:"-"`
}

func newUsers(insta *Instagram) *Users {
users := &Users{insta: insta}

return users
}

// SetInstagram sets new instagram to user structure
func (users *Users) SetInstagram(insta *Instagram) {
users.insta = insta
Expand All @@ -52,47 +55,61 @@ func (users *Users) Next() bool {
insta := users.insta
endpoint := users.endpoint

query := map[string]string{
"max_id": users.NextID,
"ig_sig_key_version": instaSigKeyVersion,
"rank_token": insta.rankToken,
}

for key, value := range users.query {
query[key] = value
}

body, _, err := insta.sendRequest(
&reqOptions{
Endpoint: endpoint,
Query: map[string]string{
"max_id": users.NextID,
"ig_sig_key_version": instaSigKeyVersion,
"rank_token": insta.rankToken,
},
Query: query,
},
)
if err != nil {
users.err = err
return false
}
usrs := Users{}
err = json.Unmarshal(body, &usrs)
if err != nil {

var newUsers Users
if err := json.Unmarshal(body, &newUsers); err != nil {
users.err = err
return false
}

if len(usrs.RawNextID) > 0 && usrs.RawNextID[0] == '"' && usrs.RawNextID[len(usrs.RawNextID)-1] == '"' {
if err := json.Unmarshal(usrs.RawNextID, &usrs.NextID); err != nil {
// check whether the nextID contains quotes (string type) or not (int64 type)
if len(newUsers.RawNextID) > 0 && newUsers.RawNextID[0] == '"' && newUsers.RawNextID[len(newUsers.RawNextID)-1] == '"' {
if err := json.Unmarshal(newUsers.RawNextID, &users.NextID); err != nil {
users.err = err
return false
}
} else if usrs.RawNextID != nil {
} else if newUsers.RawNextID != nil {
var nextID int64
if err := json.Unmarshal(usrs.RawNextID, &nextID); err != nil {
if err := json.Unmarshal(newUsers.RawNextID, &nextID); err != nil {
users.err = err
return false
}
usrs.NextID = strconv.FormatInt(nextID, 10)
users.NextID = strconv.FormatInt(nextID, 10)
}
*users = usrs
if usrs.NextID == "" {

users.Status = newUsers.Status
users.BigList = newUsers.BigList
users.Users = newUsers.Users
users.PageSize = newUsers.PageSize
users.RawNextID = newUsers.RawNextID

users.setValues()

if users.NextID == "" {
users.err = ErrNoMore
return false
}
users.insta = insta
users.endpoint = endpoint
users.setValues()

return true
}

Expand Down Expand Up @@ -345,26 +362,45 @@ func (user *User) Sync(params ...interface{}) error {

// Following returns a list of user following.
//
// Users.Next can be used to paginate
// Query can be used to search for a specific user.
// Be aware that it only matches from the start, e.g.
// "theprimeagen" will only match "theprime" not "prime".
// To fetch all user an empty string "".
//
// See example: examples/user/following.go
func (user *User) Following() *Users {
users := &Users{}
users.insta = user.insta
users.endpoint = fmt.Sprintf(urlFollowing, user.ID)
return users
// Users.Next can be used to paginate
func (user *User) Following(query string, order FollowOrder) *Users {
return user.followList(urlFollowing, query, order)
}

// Followers returns a list of user followers.
//
// Users.Next can be used to paginate
// Query can be used to search for a specific user.
// Be aware that it only matches from the start, e.g.
// "theprimeagen" will only match "theprime" not "prime".
// To fetch all user an empty string "".
//
// See example: examples/user/followers.go
func (user *User) Followers() *Users {
users := &Users{}
users.insta = user.insta
users.endpoint = fmt.Sprintf(urlFollowers, user.ID)
return users
// Users.Next can be used to paginate
func (user *User) Followers(query string) *Users {
return user.followList(urlFollowers, query, DefaultOrder)
}

func (user *User) followList(url, query string, order FollowOrder) *Users {
users := Users{
insta: user.insta,
endpoint: fmt.Sprintf(url, user.ID),
query: map[string]string{
"includes_hashtags": "true",
"search_surface": "follow_list_page",
"query": query,
"enable_groups": "true",
},
}

if order != DefaultOrder {
users.query["order"] = string(order)
}

return &users
}

// Block blocks user
Expand Down

0 comments on commit 27d9fde

Please sign in to comment.