diff --git a/run.sh b/run.sh index 10b5c0c..59426bb 100755 --- a/run.sh +++ b/run.sh @@ -1,3 +1,3 @@ #!/bin/bash -go run main.go text-google.go images.go imageproxy.go video.go map.go text.go \ No newline at end of file +go run main.go text-google.go images.go imageproxy.go video.go map.go text.go text-quant.go \ No newline at end of file diff --git a/text-google.go b/text-google.go index abf874f..b9b2b29 100644 --- a/text-google.go +++ b/text-google.go @@ -1,24 +1,16 @@ +// text-google.go package main import ( - "fmt" - "html/template" "log" "net/http" "net/url" "strings" - "time" "github.com/PuerkitoBio/goquery" ) -type TextSearchResult struct { - URL string - Header string - Description string -} - -func PerformTextSearch(query, safe, lang string) ([]TextSearchResult, error) { +func PerformGoogleTextSearch(query, safe, lang string) ([]TextSearchResult, error) { var results []TextSearchResult client := &http.Client{} @@ -73,41 +65,3 @@ func PerformTextSearch(query, safe, lang string) ([]TextSearchResult, error) { return results, nil } - -func handleTextSearchGoogle(w http.ResponseWriter, query, safe, lang string) { - // Perform the text search - results, err := PerformTextSearch(query, safe, lang) - if err != nil { - log.Printf("Error performing text search: %v", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - // Assuming you have a separate template for text search results - tmpl, err := template.ParseFiles("templates/text.html") // Ensure this path matches your templates' location - if err != nil { - log.Printf("Error parsing template: %v", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - data := struct { - Results []TextSearchResult // Ensure this type matches the structure expected by your template - Query string - Fetched string - LanguageOptions []LanguageOption - CurrentLang string - }{ - Results: results, - Query: query, - Fetched: fmt.Sprintf("%.2f seconds", time.Since(time.Now()).Seconds()), // Example fetched time, adjust as necessary - LanguageOptions: languageOptions, // Assuming this is defined globally or elsewhere - CurrentLang: lang, - } - - err = tmpl.Execute(w, data) - if err != nil { - log.Printf("Error executing template: %v", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - } -} diff --git a/text-quant.go b/text-quant.go new file mode 100644 index 0000000..b697c1b --- /dev/null +++ b/text-quant.go @@ -0,0 +1,67 @@ +// text-quant.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 { + Title string `json:"title"` + Url string `json:"url"` + Snippet string `json:"desc"` + } `json:"items"` + } `json:"result"` + } `json:"data"` +} + +func PerformQwantTextSearch(query, safe, lang string) ([]TextSearchResult, error) { + const resultsPerPage = 10 + apiURL := fmt.Sprintf("https://api.qwant.com/v3/search/web?t=web&q=%s&count=%d&locale=%s&safesearch=%s", + url.QueryEscape(query), + resultsPerPage, + lang, + safe) + + 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) + } + + var results []TextSearchResult + for _, item := range apiResp.Data.Result.Items { + results = append(results, TextSearchResult{ + URL: item.Url, + Header: item.Title, + Description: item.Snippet, + }) + } + + return results, nil +} diff --git a/text.go b/text.go index 9e967b5..cba25bb 100644 --- a/text.go +++ b/text.go @@ -2,16 +2,83 @@ package main import ( + "fmt" + "html/template" + "log" "net/http" + "sort" + "time" ) -// HandleTextSearch determines which text search engine to use and calls the appropriate function -func handleTextSearch(w http.ResponseWriter, query, safe, lang string) { - // Add logic here to determine which search engine to use, for now it just uses Google - handleTextSearchGoogle(w, query, safe, lang) +type TextSearchResult struct { + URL string + Header string + Description string } -func displayResults(w http.ResponseWriter, results string) { - // Implement your result display logic here - w.Write([]byte(results)) +func handleTextSearch(w http.ResponseWriter, query, safe, lang string) { + googleResults, googleErr := PerformGoogleTextSearch(query, safe, lang) + if googleErr != nil { + log.Printf("Error performing Google text search: %v", googleErr) + } + + qwantResults, qwantErr := PerformQwantTextSearch(query, safe, lang) + if qwantErr != nil { + log.Printf("Error performing Qwant text search: %v", qwantErr) + } + + // Use a map to track URLs and prioritize Qwant results + resultMap := make(map[string]TextSearchResult) + + // Add Qwant results to the map first + for _, result := range qwantResults { + resultMap[result.URL] = result + } + + // Add Google results to the map if the URL is not already present + for _, result := range googleResults { + if _, exists := resultMap[result.URL]; !exists { + resultMap[result.URL] = result + } + } + + // Convert the map back to a slice + var combinedResults []TextSearchResult + for _, result := range resultMap { + combinedResults = append(combinedResults, result) + } + + // Sort results (optional, based on some criteria) + sort.SliceStable(combinedResults, func(i, j int) bool { + return combinedResults[i].Header < combinedResults[j].Header + }) + + displayResults(w, combinedResults, query, lang) +} + +func displayResults(w http.ResponseWriter, results []TextSearchResult, query, lang string) { + tmpl, err := template.ParseFiles("templates/text.html") + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + data := struct { + Results []TextSearchResult + Query string + Fetched string + LanguageOptions []LanguageOption + CurrentLang string + }{ + Results: results, + Query: query, + Fetched: fmt.Sprintf("%.2f seconds", time.Since(time.Now()).Seconds()), + LanguageOptions: languageOptions, + CurrentLang: lang, + } + + err = tmpl.Execute(w, data) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } }