client.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package instagram
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "time"
  7. "git.linuxforward.com/byom/byom-trends/config"
  8. "git.linuxforward.com/byom/byom-trends/logger"
  9. "github.com/sirupsen/logrus"
  10. )
  11. type Client struct {
  12. httpClient *http.Client
  13. apiKey string
  14. baseURL string
  15. logger *logrus.Entry
  16. }
  17. type ProfileStats struct {
  18. Username string `json:"username"`
  19. FollowerCount int64 `json:"follower_count"`
  20. Following int64 `json:"following"`
  21. PostCount int64 `json:"post_count"`
  22. Engagement float64 `json:"engagement"`
  23. }
  24. type Post struct {
  25. ID string `json:"id"`
  26. Type string `json:"type"`
  27. Caption string `json:"caption"`
  28. MediaURL string `json:"media_url"`
  29. Timestamp time.Time `json:"timestamp"`
  30. LikeCount int64 `json:"like_count"`
  31. CommentCount int64 `json:"comment_count"`
  32. }
  33. func NewClient(cfg *config.InstagramConfig) *Client {
  34. return &Client{
  35. httpClient: &http.Client{
  36. Timeout: time.Second * 10,
  37. },
  38. apiKey: cfg.APIKey,
  39. baseURL: cfg.BaseURL,
  40. logger: logger.NewLogger("instagram-client"),
  41. }
  42. }
  43. func (c *Client) GetProfileStats(username string) (*ProfileStats, error) {
  44. if username == "" {
  45. return nil, fmt.Errorf("username cannot be empty")
  46. }
  47. url := fmt.Sprintf("%s/users/%s", c.baseURL, username)
  48. req, err := http.NewRequest("GET", url, nil)
  49. if err != nil {
  50. return nil, fmt.Errorf("create request: %w", err)
  51. }
  52. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey))
  53. resp, err := c.httpClient.Do(req)
  54. if err != nil {
  55. return nil, fmt.Errorf("do request: %w", err)
  56. }
  57. defer resp.Body.Close()
  58. if resp.StatusCode != http.StatusOK {
  59. return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
  60. }
  61. var stats ProfileStats
  62. if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
  63. return nil, fmt.Errorf("decode response: %w", err)
  64. }
  65. return &stats, nil
  66. }
  67. func (c *Client) GetRecentPosts(username string, limit int) ([]Post, error) {
  68. url := fmt.Sprintf("%s/users/%s/media/recent?limit=%d", c.baseURL, username, limit)
  69. req, err := http.NewRequest("GET", url, nil)
  70. if err != nil {
  71. return nil, fmt.Errorf("create request: %w", err)
  72. }
  73. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey))
  74. resp, err := c.httpClient.Do(req)
  75. if err != nil {
  76. return nil, fmt.Errorf("do request: %w", err)
  77. }
  78. defer resp.Body.Close()
  79. if resp.StatusCode != http.StatusOK {
  80. return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
  81. }
  82. var posts []Post
  83. if err := json.NewDecoder(resp.Body).Decode(&posts); err != nil {
  84. return nil, fmt.Errorf("decode response: %w", err)
  85. }
  86. return posts, nil
  87. }
  88. func (c *Client) CalculateEngagement(posts []Post) float64 {
  89. if len(posts) == 0 {
  90. return 0
  91. }
  92. var totalEngagement int64
  93. for _, post := range posts {
  94. totalEngagement += post.LikeCount + post.CommentCount
  95. }
  96. return float64(totalEngagement) / float64(len(posts))
  97. }