package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "net/url" "strings" "git.fromouter.space/hamcha/tg" ) type SearchResult struct { Name string Description *string Alternatives []string None bool } type SearchResultData struct { ItemListElement []struct { Result struct { Name []struct { Value string `json:"@value"` Lang string `json:"@language"` } `json:"name,omitempty"` Description []struct { Value string `json:"@value"` Lang string `json:"@language"` } `json:"description,omitempty"` DetailedDescription []struct { Value string `json:"articleBody"` Lang string `json:"inLanguage"` } `json:"detailedDescription,omitempty"` } `json:"result"` } `json:"itemListElement"` Error struct { Code int `json:"code"` Message string `json:"message"` } `json:"error,omitempty"` } const MAX_SEARCH_ALTS = 2 func search_init() { if strings.HasPrefix(*gapikey, "@") { data, err := ioutil.ReadFile((*gapikey)[1:]) if err != nil { panic(err) } *gapikey = strings.TrimSpace(string(data)) } if *gapikey == "" { panic(fmt.Errorf("Missing GAPI key for search module (provide it or --disable search)")) } } func search_message(broker *tg.Broker, update tg.APIMessage) { if isCommand(update, "search") { parts := strings.SplitN(*(update.Text), " ", 2) if len(parts) < 2 { broker.SendTextMessage(update.Chat, "Non mi hai dato niente da cercare!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } broker.SendChatAction(update.Chat, tg.ActionTyping) result, err := searchAPI(parts[1]) if err != nil { log.Printf("[search] %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } if result.None { broker.SendTextMessage(update.Chat, "Non ho trovato nulla, mi spiace :(", &tg.MessageOptions{ ReplyID: &update.MessageID, }) return } resulttxt := fmt.Sprintf("Ecco la prima cosa che ho trovato:\n%s", result.Name) if result.Description != nil { resulttxt += "\n" + *(result.Description) } if len(result.Alternatives) > 0 { resulttxt += "\nAlternativamente:\n - " + strings.Join(result.Alternatives, "\n - ") } broker.SendTextMessage(update.Chat, resulttxt, &tg.MessageOptions{ ReplyID: &update.MessageID, }) } } func searchAPI(term string) (SearchResult, error) { resp, err := http.Get("https://kgsearch.googleapis.com/v1/entities:search?indent=true&languages=it&languages=en&query=" + url.QueryEscape(term) + "&key=" + *gapikey) if err != nil { return SearchResult{}, err } defer resp.Body.Close() var res SearchResultData err = json.NewDecoder(resp.Body).Decode(&res) if err != nil { return SearchResult{}, err } if res.Error.Message != "" { return SearchResult{}, fmt.Errorf("Request error: %d %s", res.Error.Code, res.Error.Message) } if len(res.ItemListElement) < 1 { return SearchResult{None: true}, nil } out := SearchResult{None: false} for _, item := range res.ItemListElement { // Skip elements without a name if item.Result.Name == nil || len(item.Result.Name) == 0 { continue } namestr := item.Result.Name[0].Value // Check if it has a small description if item.Result.Description != nil && len(item.Result.Description) > 0 { namestr += " (" + item.Result.Description[0].Value + ")" } // If we already had an item, add it to alternatives and find others if out.Name != "" { out.Alternatives = append(out.Alternatives, namestr) if len(out.Alternatives) > MAX_SEARCH_ALTS { break } continue } out.Name = namestr // Check for a description if item.Result.DetailedDescription != nil || len(item.Result.DetailedDescription) > 0 { out.Description = &(item.Result.DetailedDescription[0].Value) } } return out, nil }