package services import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" ) type SearchResultItem struct { Title string `json:"title"` Link string `json:"link"` Pagemap struct { CseImage []struct { Src string `json:"src"` } `json:"cse_image"` CseThumbnail []struct { Src string `json:"src"` } `json:"cse_thumbnail"` } `json:"pagemap"` } type SearchResponse struct { Items []SearchResultItem `json:"items"` } // PerformSearch calls Google Custom Search API targeting YouTube, TikTok, Envato, Artgrid func PerformSearch(query string) ([]string, error) { apiKey := os.Getenv("GOOGLE_CSE_API_KEY") cx := os.Getenv("GOOGLE_CSE_ID") if apiKey == "" || cx == "" { return nil, fmt.Errorf("Google CSE credentials not configured") } // We append "site:youtube.com OR site:tiktok.com OR site:envato.com OR site:artgrid.io" to restrict // depending on CSE settings, but the easiest is doing it in query string fullQuery := fmt.Sprintf("%s site:youtube.com OR site:tiktok.com OR site:envato.com OR site:artgrid.io", query) url := fmt.Sprintf("https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=%s&searchType=image&num=10", apiKey, cx, fullQuery) resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("Google CSE API returned status: %d", resp.StatusCode) } body, _ := ioutil.ReadAll(resp.Body) var res SearchResponse if err := json.Unmarshal(body, &res); err != nil { return nil, err } var thumbnails []string for _, item := range res.Items { thumbnails = append(thumbnails, item.Link) } return thumbnails, nil }