package engines import ( "context" "fmt" "io" "net/http" "net/url" "regexp" "strings" "github.com/metamorphosis-dev/kafka/internal/contracts" ) type BraveEngine struct { client *http.Client } func (e *BraveEngine) Name() string { return "brave" } func (e *BraveEngine) Search(ctx context.Context, req contracts.SearchRequest) (contracts.SearchResponse, error) { if strings.TrimSpace(req.Query) == "" { return contracts.SearchResponse{Query: req.Query}, nil } start := (req.Pageno - 1) * 20 u := fmt.Sprintf( "https://search.brave.com/search?q=%s&offset=%d&source=web", url.QueryEscape(req.Query), start, ) httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return contracts.SearchResponse{}, err } httpReq.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36") httpReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") httpReq.Header.Set("Accept-Language", "en-US,en;q=0.9") resp, err := e.client.Do(httpReq) if err != nil { return contracts.SearchResponse{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { io.Copy(io.Discard, io.LimitReader(resp.Body, 4096)) return contracts.SearchResponse{}, fmt.Errorf("brave error: status %d", resp.StatusCode) } body, err := io.ReadAll(io.LimitReader(resp.Body, 128*1024)) if err != nil { return contracts.SearchResponse{}, err } results := parseBraveResults(string(body)) return contracts.SearchResponse{ Query: req.Query, NumberOfResults: len(results), Results: results, Answers: []map[string]any{}, Corrections: []string{}, Infoboxes: []map[string]any{}, Suggestions: extractBraveSuggestions(string(body)), UnresponsiveEngines: [][2]string{}, }, nil } func parseBraveResults(body string) []contracts.MainResult { var results []contracts.MainResult // Brave wraps each result in divs with data-type="web" or data-type="news". // Pattern:
]+class="[^"]*description[^"]*"[^>]*>(.*?)
`, `]+class="[^"]*snippet[^"]*"[^>]*>(.*?)`, } for _, pat := range patterns { re := regexp.MustCompile(`(?s)` + pat) m := re.FindStringSubmatch(block) if len(m) >= 2 { text := stripTags(m[1]) if text != "" { return strings.TrimSpace(text) } } } return "" } func extractBraveFavicon(block string) string { imgPattern := regexp.MustCompile(`