99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
// QwantTextAPIResponse represents the JSON response structure from Qwant API
|
|
type QwantTextAPIResponse struct {
|
|
Data struct {
|
|
Result struct {
|
|
Items struct {
|
|
Mainline []struct {
|
|
Items []struct {
|
|
URL string `json:"url"`
|
|
Title string `json:"title"`
|
|
Description string `json:"desc"`
|
|
} `json:"items"`
|
|
} `json:"mainline"`
|
|
} `json:"items"`
|
|
} `json:"result"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// PerformQwantTextSearch contacts the Qwant API and returns a slice of TextSearchResult
|
|
func PerformQwantTextSearch(query, safe, lang string) ([]TextSearchResult, error) {
|
|
const resultsPerPage = 10
|
|
const offset = 0
|
|
|
|
// Ensure safe search is disabled by default if not specified
|
|
if safe == "" {
|
|
safe = "0"
|
|
}
|
|
|
|
// Default to English Canada locale if not specified
|
|
if lang == "" {
|
|
lang = "en_CA"
|
|
}
|
|
|
|
apiURL := fmt.Sprintf("https://api.qwant.com/v3/search/web?q=%s&count=%d&locale=%s&offset=%d&device=desktop",
|
|
url.QueryEscape(query),
|
|
resultsPerPage,
|
|
lang,
|
|
offset)
|
|
|
|
client := &http.Client{Timeout: 10 * time.Second}
|
|
|
|
req, err := http.NewRequest("GET", apiURL, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating request: %v", err)
|
|
}
|
|
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("making request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
|
}
|
|
|
|
var apiResp QwantTextAPIResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
|
|
return nil, fmt.Errorf("decoding response: %v", err)
|
|
}
|
|
|
|
// Extracting results from the nested JSON structure
|
|
if len(apiResp.Data.Result.Items.Mainline) == 0 {
|
|
return nil, fmt.Errorf("no search results found")
|
|
}
|
|
|
|
var results []TextSearchResult
|
|
for _, item := range apiResp.Data.Result.Items.Mainline[0].Items {
|
|
cleanURL := cleanQwantURL(item.URL)
|
|
results = append(results, TextSearchResult{
|
|
URL: cleanURL,
|
|
Header: item.Title,
|
|
Description: item.Description,
|
|
Source: "Qwant",
|
|
})
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// cleanQwantURL extracts the main part of the URL, removing tracking information
|
|
func cleanQwantURL(rawURL string) string {
|
|
u, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
return rawURL
|
|
}
|
|
return u.Scheme + "://" + u.Host + u.Path
|
|
}
|