-
Notifications
You must be signed in to change notification settings - Fork 2
/
thread.go
124 lines (107 loc) · 3.78 KB
/
thread.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package threads
import (
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"github.com/dwarvesf/go-threads/model"
"github.com/dwarvesf/go-threads/private"
)
// PrivateAPI interface for private API
type PrivateAPI interface {
CreatePost(content model.CreatePostRequest) (*model.CreatePostResponse, error)
GetUserFollowers(id int) (*model.UserFollowersResponse, error)
GetFollowers() (*model.UserFollowersResponse, error)
GetFollowing() (*model.UserFollowingResponse, error)
GetThreadByID(ID string) (*model.ThreadDetailResponse, error)
SearchUser(query string) (*model.UserResponse, error)
LikeThread(id string) (map[string]interface{}, error)
UnLikeThread(id string) (map[string]interface{}, error)
FollowUser(id int) (*model.FollowUserResponse, error)
UnFollowUser(id int) (*model.FollowUserResponse, error)
}
// NewPrivateAPIClient new api client for private API
func NewPrivateAPIClient(cfg *Config) (PrivateAPI, error) {
if err := cfg.ReadyCheck(); err != nil {
return nil, err
}
ins := &private.PrivateAPI{
UserID: cfg.UserID,
Username: cfg.Username,
Password: cfg.Password,
TimezoneOffset: cfg.TimezoneOffset,
DeviceID: cfg.DeviceID,
DeviceManufacturer: cfg.DeviceManufacturer,
DeviceModel: cfg.DeviceModel,
DeviceOsVersion: cfg.DeviceOsVersion,
DeviceOsRelease: cfg.DeviceOsRelease,
APIToken: cfg.APIToken,
}
return ins, nil
}
// InitAPIClient new api client for private API
func InitAPIClient(cfgFn ...ConfigFn) (PrivateAPI, error) {
cfg, err := InitConfig(cfgFn...)
if err != nil {
return nil, err
}
if err := cfg.ReadyCheck(); err != nil {
return nil, err
}
ins := &private.PrivateAPI{
UserID: cfg.UserID,
Username: cfg.Username,
Password: cfg.Password,
TimezoneOffset: cfg.TimezoneOffset,
DeviceID: cfg.DeviceID,
DeviceManufacturer: cfg.DeviceManufacturer,
DeviceModel: cfg.DeviceModel,
DeviceOsVersion: cfg.DeviceOsVersion,
DeviceOsRelease: cfg.DeviceOsRelease,
APIToken: cfg.APIToken,
}
return ins, nil
}
var fetchHTMLHeaders = map[string]string{
"Authority": "www.threads.net",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Accept-Language": "en-US,en;q=0.9",
"Cache-Control": "no-cache",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://www.threads.net",
"Pragma": "no-cache",
"Referer": "https://www.instagram.com",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
}
// GetUserByUsername get user by username via instagram api
func GetUserByUsername(username string) (int, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", fmt.Sprintf("https://www.instagram.com/%s", username), nil)
if err != nil {
return 0, fmt.Errorf("failed to create HTTP request: %v", err)
}
for key, value := range fetchHTMLHeaders {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return 0, fmt.Errorf("failed to send HTTP request: %v", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return 0, fmt.Errorf("failed to read response body: %v", err)
}
userIDKeyPattern := regexp.MustCompile(`"user_id":"(\d+)",`)
userIDKeyMatch := userIDKeyPattern.FindStringSubmatch(string(respBody))
if userIDKeyMatch == nil {
return 0, fmt.Errorf("failed to find user ID in the response")
}
userID := userIDKeyMatch[1]
return strconv.Atoi(userID)
}