package cards import ( "encoding/json" "fmt" "html/template" "net/http" "net/url" "time" ) func init() { Register("ddg", 3, NewDDGCard) } // ddgAttribution is HTML for attribution of DuckDuckGo at their request const ddgAttribution = `

  Results from DuckDuckGo »

` // DDGCard represents a DuckDuckGo Instant Answer API card type DDGCard struct { query string userAgent string resp DDGInstAns } // DDGInstAns represents a DuckDuckGo Instant Answer API response type DDGInstAns struct { Abstract string AbstractText string AbstractSource string AbstractURL string Image string Heading string Answer string AnswerType string } // NewDDGCard isa NewCardFunc that creates a new DDGCard func NewDDGCard(query, userAgent string) Card { return &DDGCard{ query: url.QueryEscape(query), userAgent: userAgent, } } // RunQuery requests the query from the instant answer API func (ddg *DDGCard) RunQuery() error { http.DefaultClient.Timeout = 5 * time.Second // Create new API request req, err := http.NewRequest( http.MethodGet, "https://api.duckduckgo.com/?q="+ddg.query+"&format=json", nil, ) if err != nil { return err } req.Header.Set("User-Agent", ddg.userAgent) // Perform request res, err := http.DefaultClient.Do(req) if err != nil { return err } // Decode response into repsonse struct err = json.NewDecoder(res.Body).Decode(&ddg.resp) if err != nil { return err } return nil } func (ddg *DDGCard) Returned() bool { // Value was returned if abstract is not empty return ddg.resp.Abstract != "" } func (ddg *DDGCard) Matches() bool { // Everything matches since there are no keys return true } func (ddg *DDGCard) StripKey() string { // No key to strip, so return query return ddg.query } func (ddg *DDGCard) Title() string { return ddg.resp.Heading } func (ddg *DDGCard) Content() template.HTML { // Return abstract with attribution return template.HTML(ddg.resp.Abstract + fmt.Sprintf(ddgAttribution, ddg.query)) } func (ddg *DDGCard) Footer() template.HTML { // Return footer with abstract url and source return template.HTML(fmt.Sprintf( ``, ddg.resp.AbstractURL, ddg.resp.AbstractSource, )) } func (ddg *DDGCard) Head() template.HTML { return "" }