github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/unfurl/scrape_giphy.go (about)

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