mirror of https://github.com/matrix-org/go-neb.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.5 KiB
147 lines
3.5 KiB
// Package giphy implements a Service which adds !commands for Giphy.
|
|
package giphy
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/matrix-org/go-neb/types"
|
|
"github.com/matrix-org/gomatrix"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ServiceType of the Giphy service.
|
|
const ServiceType = "giphy"
|
|
|
|
type image struct {
|
|
URL string `json:"url"`
|
|
// Giphy returns ints as strings..
|
|
Width string `json:"width"`
|
|
Height string `json:"height"`
|
|
Size string `json:"size"`
|
|
}
|
|
|
|
type result struct {
|
|
Slug string `json:"slug"`
|
|
Images struct {
|
|
Downsized image `json:"downsized"`
|
|
Original image `json:"original"`
|
|
} `json:"images"`
|
|
}
|
|
|
|
type giphySearch struct {
|
|
Data result `json:"data"`
|
|
}
|
|
|
|
// Service contains the Config fields for the Giphy Service.
|
|
//
|
|
// Example request:
|
|
// {
|
|
// "api_key": "dc6zaTOxFJmzC",
|
|
// "use_downsized": false
|
|
// }
|
|
type Service struct {
|
|
types.DefaultService
|
|
// The Giphy API key to use when making HTTP requests to Giphy.
|
|
// The public beta API key is "dc6zaTOxFJmzC".
|
|
APIKey string `json:"api_key"`
|
|
// Whether to use the downsized image from Giphy.
|
|
// Uses the original image when set to false.
|
|
// Defaults to false.
|
|
UseDownsized bool `json:"use_downsized"`
|
|
}
|
|
|
|
// Commands supported:
|
|
// !giphy some search query without quotes
|
|
// Responds with a suitable GIF into the same room as the command.
|
|
func (s *Service) Commands(client *gomatrix.Client) []types.Command {
|
|
return []types.Command{
|
|
types.Command{
|
|
Path: []string{"giphy"},
|
|
Command: func(roomID, userID string, args []string) (interface{}, error) {
|
|
return s.cmdGiphy(client, roomID, userID, args)
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (s *Service) cmdGiphy(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) {
|
|
// only 1 arg which is the text to search for.
|
|
query := strings.Join(args, " ")
|
|
gifResult, err := s.searchGiphy(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
image := gifResult.Images.Original
|
|
if s.UseDownsized {
|
|
image = gifResult.Images.Downsized
|
|
}
|
|
|
|
if image.URL == "" {
|
|
return nil, fmt.Errorf("No results")
|
|
}
|
|
resUpload, err := client.UploadLink(image.URL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return gomatrix.ImageMessage{
|
|
MsgType: "m.image",
|
|
Body: gifResult.Slug,
|
|
URL: resUpload.ContentURI,
|
|
Info: gomatrix.ImageInfo{
|
|
Height: asInt(image.Height),
|
|
Width: asInt(image.Width),
|
|
Mimetype: "image/gif",
|
|
Size: asInt(image.Size),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// searchGiphy returns info about a gif
|
|
func (s *Service) searchGiphy(query string) (*result, error) {
|
|
log.Info("Searching giphy for ", query)
|
|
u, err := url.Parse("http://api.giphy.com/v1/gifs/translate")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q := u.Query()
|
|
q.Set("s", query)
|
|
q.Set("api_key", s.APIKey)
|
|
u.RawQuery = q.Encode()
|
|
res, err := http.Get(u.String())
|
|
if res != nil {
|
|
defer res.Body.Close()
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var search giphySearch
|
|
if err := json.NewDecoder(res.Body).Decode(&search); err != nil {
|
|
// Giphy returns a JSON object which has { data: [] } if there are 0 results.
|
|
// This fails to be deserialised by Go.
|
|
return nil, fmt.Errorf("No results")
|
|
}
|
|
return &search.Data, nil
|
|
}
|
|
|
|
func asInt(strInt string) uint {
|
|
u64, err := strconv.ParseUint(strInt, 10, 32)
|
|
if err != nil {
|
|
return 0 // default to 0 since these are all just hints to the client
|
|
}
|
|
return uint(u64)
|
|
}
|
|
|
|
func init() {
|
|
types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service {
|
|
return &Service{
|
|
DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType),
|
|
}
|
|
})
|
|
}
|