github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/unfurl/scrape_giphy.go (about) 1 package unfurl 2 3 import ( 4 "context" 5 "errors" 6 "net/url" 7 "strconv" 8 "strings" 9 10 "github.com/gocolly/colly/v2" 11 "github.com/keybase/client/go/protocol/chat1" 12 ) 13 14 var giphyFavicon = "https://giphy.com/static/img/icons/apple-touch-icon-180px.png" 15 16 func (s *Scraper) scrapeGiphyWithMetadata(ctx context.Context, sourceURL string) (res chat1.UnfurlRaw, err error) { 17 defer s.Trace(ctx, &err, "scrapeGiphyWithMetadata")() 18 url, err := url.Parse(sourceURL) 19 if err != nil { 20 return res, err 21 } 22 if url.Fragment == "" { 23 return res, errors.New("no fragment") 24 } 25 toks := strings.Split(url.Fragment, "&") 26 if len(toks) != 3 { 27 return res, errors.New("not enough params") 28 } 29 var rawgiphy chat1.UnfurlGiphyRaw 30 var video chat1.UnfurlVideo 31 var height, width int64 32 isVideo := false 33 for _, tok := range toks { 34 vals := strings.Split(tok, "=") 35 if len(vals) != 2 { 36 return res, errors.New("invalid val") 37 } 38 switch vals[0] { 39 case "height": 40 if height, err = strconv.ParseInt(vals[1], 0, 0); err != nil { 41 return res, err 42 } 43 case "width": 44 if width, err = strconv.ParseInt(vals[1], 0, 0); err != nil { 45 return res, err 46 } 47 case "isvideo": 48 if isVideo, err = strconv.ParseBool(vals[1]); err != nil { 49 return res, err 50 } 51 } 52 } 53 rawgiphy.FaviconUrl = &giphyFavicon 54 if isVideo { 55 video.Height = int(height) 56 video.Width = int(width) 57 video.Url = sourceURL 58 video.MimeType = "video/mp4" 59 rawgiphy.Video = &video 60 } else { 61 rawgiphy.ImageUrl = &sourceURL 62 } 63 return chat1.NewUnfurlRawWithGiphy(rawgiphy), nil 64 } 65 66 func (s *Scraper) scrapeGiphy(ctx context.Context, sourceURL string) (res chat1.UnfurlRaw, err error) { 67 defer s.Trace(ctx, &err, "scrapeGiphy")() 68 if res, err = s.scrapeGiphyWithMetadata(ctx, sourceURL); err == nil { 69 s.Debug(ctx, "scrapeGiphy: successfully scraped with metadata") 70 return res, nil 71 } 72 73 c := s.makeCollector() 74 var rawgiphy chat1.UnfurlGiphyRaw 75 var video chat1.UnfurlVideo 76 video.MimeType = "video/mp4" 77 generic := new(scoredGenericRaw) 78 if err = s.addGenericScraperToCollector(ctx, c, generic, sourceURL, "giphy.com"); err != nil { 79 return res, err 80 } 81 82 c.OnHTML("head meta[content][property]", func(e *colly.HTMLElement) { 83 attr := strings.ToLower(e.Attr("property")) 84 if attr == "og:video" || attr == "og:video:url" || attr == "og:video:secure_url" { 85 video.Url = e.Attr("content") 86 } else if attr == "og:video:width" { 87 if width, err := strconv.Atoi(e.Attr("content")); err == nil { 88 video.Width = width 89 } 90 91 } else if attr == "og:video:height" { 92 if height, err := strconv.Atoi(e.Attr("content")); err == nil { 93 video.Height = height 94 } 95 } else { 96 s.setAttr(ctx, attr, "giphy.com", "giphy.com", generic, e) 97 } 98 }) 99 if err := c.Visit(sourceURL); err != nil { 100 return res, err 101 } 102 if generic.ImageUrl == nil { 103 // If we couldn't find an image, then just return the generic 104 s.Debug(ctx, "scrapeGiphy: failed to find an image, just returning generic unfurl") 105 return s.exportGenericResult(generic) 106 } 107 if len(video.Url) > 0 && video.Height > 0 && video.Width > 0 { 108 rawgiphy.Video = &video 109 } 110 rawgiphy.ImageUrl = generic.ImageUrl 111 rawgiphy.FaviconUrl = generic.FaviconUrl 112 return chat1.NewUnfurlRawWithGiphy(rawgiphy), nil 113 }