package main import ( "io" "net/http" "os" "regexp" "strings" "time" tgbotapi "git.zio.sh/astra/telegram-bot-api" "github.com/astravexton/logger" "github.com/dghubble/sling" "github.com/google/uuid" ) const ddgURL = "https://duckduckgo.com" // ImgResult ... type ImgResult struct { Ads interface{} `json:"ads"` Next string `json:"next"` Query string `json:"query"` QueryEncoded string `json:"queryEncoded"` ResponseType string `json:"response_type"` Results []Results `json:"results"` Vqd struct { Testing string `json:"testing"` } `json:"vqd"` } type Results struct { Height int `json:"height"` Image string `json:"image"` Source string `json:"source"` Thumbnail string `json:"thumbnail"` Title string `json:"title"` URL string `json:"url"` Width int `json:"width"` } type Params struct { Query string `url:"q,omitempty"` L string `url:"l,omitempty"` O string `url:"o,omitempty"` Q string `url:"q,omitempty"` VQD string `url:"vqd,omitempty"` F string `url:"f,omitempty"` P string `url:"p,omitempty"` S string `url:"s,omitempty"` U string `url:"u,omitempty"` } func main() { logger.Layout = time.Stamp logger.BitwiseLevel = logger.LogInfo | logger.LogWarning | logger.LogCritical bot, err := tgbotapi.NewBotAPI(os.Getenv("BOT_TOKEN")) if err != nil { logger.Critical(err.Error()) } me, err := bot.GetMe() if err != nil { logger.Critical(err.Error()) } logger.Info("Authorized as %s", me.UserName) u := tgbotapi.NewUpdate(0) u.Timeout = 60 updates := bot.GetUpdatesChan(u) for update := range updates { if update.InlineQuery != nil { if update.InlineQuery.Query != "" { logger.Debug("Inline query %q from %s", update.InlineQuery.Query, update.InlineQuery.From) var results []interface{} images := getImageList(update.InlineQuery.Query) for c, image := range images { if c == 50 { break } var result interface{} if strings.HasSuffix(image.Image, ".gif") { result = &tgbotapi.InlineQueryResultGIF{ Type: "gif", ID: uuid.New().String(), URL: image.Image, ThumbURL: image.Thumbnail, } } else { result = &tgbotapi.InlineQueryResultPhoto{ Type: "photo", ID: uuid.New().String(), URL: image.Image, ThumbURL: image.Thumbnail, } } results = append(results, result) } inlineConf := tgbotapi.InlineConfig{ InlineQueryID: update.InlineQuery.ID, IsPersonal: false, CacheTime: 1, Results: results, } bot.Request(inlineConf) } } } } func getImageList(query string) []Results { safeSearch := "-1" // -1 = safe off, 1 = safe on if len(query) >= 8 { if strings.HasPrefix(query, "safe:on") { safeSearch = "1" query = query[8:] } } params := &Params{Query: query} s := sling.New().Get(ddgURL) s.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36") s.QueryStruct(params) req, err := s.Request() if err != nil { logger.Critical(err.Error()) } client := &http.Client{} client.Timeout = time.Second * 3 res, err := client.Do(req) if err != nil { logger.Critical(err.Error()) } defer res.Body.Close() body, _ := io.ReadAll(res.Body) bodyContents := string(body) r := regexp.MustCompile(`vqd=([\d-]+)`) token := strings.ReplaceAll(r.FindString(bodyContents), "vqd=", "") params = &Params{ L: "us-en", O: "json", Q: query, VQD: token, F: ",,,,,", P: safeSearch, S: "0", U: "bing", } s = s.Get(ddgURL).Path("/i.js").QueryStruct(params) s.Set("Authority", "duckduckgo.com") s.Set("Accept", "application/json, text/javascript, */*; q=0.01") s.Set("Cookie", "bc=1; at=-1; au=-1; av=1; ax=-1; ak=-1; ao=-1; ap=-1; 1=-1; 5=1; aq=-1; ay=b; ah=uk-en; l=wt-wt; p=-2") s.Set("Referer", "https://duckduckgo.com/") imageList := &ImgResult{} _, err = s.ReceiveSuccess(imageList) if err != nil { logger.Critical(err.Error()) } return imageList.Results }