Search/suggestions.go
2024-08-21 22:36:45 +02:00

161 lines
4.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
)
func handleSuggestions(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
if query == "" {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `["",[]]`)
return
}
// Define the fallback sequence with Google lower in the hierarchy
suggestionSources := []func(string) []string{
fetchDuckDuckGoSuggestions,
fetchEdgeSuggestions,
fetchBraveSuggestions,
fetchEcosiaSuggestions,
fetchQwantSuggestions,
fetchStartpageSuggestions,
// fetchGoogleSuggestions, // I advise against it, but you can use it if you want to
}
var suggestions []string
for _, fetchFunc := range suggestionSources {
suggestions = fetchFunc(query)
if len(suggestions) > 0 {
log.Printf("Suggestions found using %T\n", fetchFunc)
break
} else {
log.Printf("%T did not return any suggestions or failed.\n", fetchFunc)
}
}
if len(suggestions) == 0 {
log.Println("All suggestion services failed. Returning empty response.")
}
// Return the final suggestions as JSON
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `["",%s]`, toJSONStringArray(suggestions))
}
func fetchGoogleSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("http://suggestqueries.google.com/complete/search?client=firefox&q=%s", encodedQuery)
log.Println("Fetching suggestions from Google:", url)
return fetchSuggestionsFromURL(url)
}
func fetchDuckDuckGoSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://duckduckgo.com/ac/?q=%s&type=list", encodedQuery)
log.Println("Fetching suggestions from DuckDuckGo:", url)
return fetchSuggestionsFromURL(url)
}
func fetchEdgeSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://api.bing.com/osjson.aspx?query=%s", encodedQuery)
log.Println("Fetching suggestions from Edge (Bing):", url)
return fetchSuggestionsFromURL(url)
}
func fetchBraveSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://search.brave.com/api/suggest?q=%s", encodedQuery)
log.Println("Fetching suggestions from Brave:", url)
return fetchSuggestionsFromURL(url)
}
func fetchEcosiaSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://ac.ecosia.org/?q=%s&type=list", encodedQuery)
log.Println("Fetching suggestions from Ecosia:", url)
return fetchSuggestionsFromURL(url)
}
func fetchQwantSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://api.qwant.com/v3/suggest?q=%s", encodedQuery)
log.Println("Fetching suggestions from Qwant:", url)
return fetchSuggestionsFromURL(url)
}
func fetchStartpageSuggestions(query string) []string {
encodedQuery := url.QueryEscape(query)
url := fmt.Sprintf("https://startpage.com/suggestions?q=%s", encodedQuery)
log.Println("Fetching suggestions from Startpage:", url)
return fetchSuggestionsFromURL(url)
}
func fetchSuggestionsFromURL(url string) []string {
resp, err := http.Get(url)
if err != nil {
log.Println("Error fetching suggestions from", url, ":", err)
return []string{}
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Println("Error reading response body from", url, ":", err)
return []string{}
}
// Log the Content-Type for debugging
contentType := resp.Header.Get("Content-Type")
log.Println("Response Content-Type from", url, ":", contentType)
// Check if the body is non-empty
if len(body) == 0 {
log.Println("Received empty response body from", url)
return []string{}
}
// Attempt to parse the response as JSON regardless of Content-Type
var parsedResponse []interface{}
if err := json.Unmarshal(body, &parsedResponse); err != nil {
log.Println("Error parsing JSON from", url, ":", err)
log.Println("Response body:", string(body)) // Log the body for debugging
return []string{}
}
// Ensure the response structure is as expected
if len(parsedResponse) < 2 {
log.Println("Unexpected response format from", url, ":", string(body))
return []string{}
}
suggestions := []string{}
if items, ok := parsedResponse[1].([]interface{}); ok {
for _, item := range items {
if suggestion, ok := item.(string); ok {
suggestions = append(suggestions, suggestion)
}
}
} else {
log.Println("Unexpected suggestions format in response from", url)
}
return suggestions
}
func toJSONStringArray(strings []string) string {
result := ""
for i, str := range strings {
result += fmt.Sprintf(`"%s"`, str)
if i < len(strings)-1 {
result += ","
}
}
return "[" + result + "]"
}