package threadsapi import ( "context" "encoding/json" "fmt" "net/http" "net/url" "time" ) type MediaStats struct { LikeCount int `json:"like_count"` ReplyCount int `json:"reply_count"` RepostCount int `json:"repost_count"` QuoteCount int `json:"quote_count"` } func GetMediaStats(ctx context.Context, accessToken, mediaID string) (*MediaStats, error) { u := fmt.Sprintf("%s/%s", graphBaseURL, mediaID) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, err } q := url.Values{} q.Set("fields", "like_count,reply_count,repost_count,quote_count") q.Set("access_token", accessToken) req.URL.RawQuery = q.Encode() resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("threads api media stats error: %s", resp.Status) } var raw struct { ID string `json:"id"` LikeCount int `json:"like_count"` ReplyCount int `json:"reply_count"` RepostCount int `json:"repost_count"` QuoteCount int `json:"quote_count"` } if err := json.NewDecoder(resp.Body).Decode(&raw); err != nil { return nil, err } return &MediaStats{ LikeCount: raw.LikeCount, ReplyCount: raw.ReplyCount, RepostCount: raw.RepostCount, QuoteCount: raw.QuoteCount, }, nil } type TokenRefreshResult struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` ExpiresIn int `json:"expires_in"` } func RefreshAccessToken(ctx context.Context, currentToken string) (*TokenRefreshResult, error) { u := fmt.Sprintf("%s/refresh_access_token", graphBaseURL) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, err } q := url.Values{} q.Set("grant_type", "th_refresh_token") q.Set("access_token", currentToken) req.URL.RawQuery = q.Encode() resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("threads api token refresh error: %s", resp.Status) } var result TokenRefreshResult if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } if result.AccessToken == "" { return nil, fmt.Errorf("threads api token refresh returned empty token") } return &result, nil } func NsFromNow(seconds int) int64 { return time.Now().UnixNano() + int64(seconds)*1e9 }