client.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package tiktok
  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. FollowingCount int64 `json:"following_count"`
  21. VideoCount int64 `json:"video_count"`
  22. LikeCount int64 `json:"like_count"`
  23. Engagement float64 `json:"engagement"`
  24. VerifiedStatus bool `json:"verified_status"`
  25. }
  26. type Video struct {
  27. ID string `json:"id"`
  28. Description string `json:"description"`
  29. CreateTime time.Time `json:"create_time"`
  30. Duration int `json:"duration"`
  31. LikeCount int64 `json:"like_count"`
  32. CommentCount int64 `json:"comment_count"`
  33. ShareCount int64 `json:"share_count"`
  34. ViewCount int64 `json:"view_count"`
  35. ThumbnailURL string `json:"thumbnail_url"`
  36. VideoURL string `json:"video_url"`
  37. MusicInfo string `json:"music_info"`
  38. HashTags []string `json:"hashtags"`
  39. }
  40. func NewClient(cfg *config.TikTokConfig) *Client {
  41. return &Client{
  42. httpClient: &http.Client{
  43. Timeout: time.Second * 10,
  44. },
  45. apiKey: cfg.APIKey,
  46. baseURL: cfg.BaseURL,
  47. logger: logger.NewLogger("tiktok-client"),
  48. }
  49. }
  50. func (c *Client) GetProfileStats(username string) (*ProfileStats, error) {
  51. url := fmt.Sprintf("%s/users/%s", c.baseURL, username)
  52. req, err := http.NewRequest("GET", url, nil)
  53. if err != nil {
  54. return nil, fmt.Errorf("create request: %w", err)
  55. }
  56. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey))
  57. resp, err := c.httpClient.Do(req)
  58. if err != nil {
  59. return nil, fmt.Errorf("do request: %w", err)
  60. }
  61. defer resp.Body.Close()
  62. if resp.StatusCode != http.StatusOK {
  63. return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
  64. }
  65. var stats ProfileStats
  66. if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
  67. return nil, fmt.Errorf("decode response: %w", err)
  68. }
  69. return &stats, nil
  70. }
  71. func (c *Client) GetRecentVideos(username string, limit int) ([]Video, error) {
  72. url := fmt.Sprintf("%s/users/%s/videos?limit=%d", c.baseURL, username, limit)
  73. req, err := http.NewRequest("GET", url, nil)
  74. if err != nil {
  75. return nil, fmt.Errorf("create request: %w", err)
  76. }
  77. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey))
  78. resp, err := c.httpClient.Do(req)
  79. if err != nil {
  80. return nil, fmt.Errorf("do request: %w", err)
  81. }
  82. defer resp.Body.Close()
  83. if resp.StatusCode != http.StatusOK {
  84. return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
  85. }
  86. var videos []Video
  87. if err := json.NewDecoder(resp.Body).Decode(&videos); err != nil {
  88. return nil, fmt.Errorf("decode response: %w", err)
  89. }
  90. return videos, nil
  91. }
  92. func (c *Client) CalculateEngagement(videos []Video) float64 {
  93. if len(videos) == 0 {
  94. return 0
  95. }
  96. var totalEngagement int64
  97. for _, video := range videos {
  98. // TikTok engagement includes likes, comments, shares, and views
  99. totalEngagement += video.LikeCount + video.CommentCount + video.ShareCount + video.ViewCount
  100. }
  101. return float64(totalEngagement) / float64(len(videos))
  102. }
  103. func (c *Client) GetTrendingHashtags(videos []Video) map[string]int {
  104. hashtags := make(map[string]int)
  105. for _, video := range videos {
  106. for _, tag := range video.HashTags {
  107. hashtags[tag]++
  108. }
  109. }
  110. return hashtags
  111. }