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.

150 lines
3.7 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. // Package guggy implements a Service which adds !commands for Guggy.
  2. package guggy
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "math"
  9. "net/http"
  10. "strings"
  11. "github.com/matrix-org/go-neb/types"
  12. "github.com/matrix-org/gomatrix"
  13. log "github.com/sirupsen/logrus"
  14. )
  15. // ServiceType of the Guggy service
  16. const ServiceType = "guggy"
  17. var httpClient = &http.Client{}
  18. type guggyQuery struct {
  19. // "mp4" or "gif"
  20. Format string `json:"format"`
  21. // Query sentence
  22. Sentence string `json:"sentence"`
  23. }
  24. type guggyGifResult struct {
  25. ReqID string `json:"reqId"`
  26. GIF string `json:"gif"`
  27. Width float64 `json:"width"`
  28. Height float64 `json:"height"`
  29. }
  30. // Service contains the Config fields for the Guggy service.
  31. //
  32. // Example request:
  33. // {
  34. // "api_key": "fkweugfyuwegfweyg"
  35. // }
  36. type Service struct {
  37. types.DefaultService
  38. // The Guggy API key to use when making HTTP requests to Guggy.
  39. APIKey string `json:"api_key"`
  40. }
  41. // Commands supported:
  42. // !guggy some search query without quotes
  43. // Responds with a suitable GIF into the same room as the command.
  44. func (s *Service) Commands(client *gomatrix.Client) []types.Command {
  45. return []types.Command{
  46. types.Command{
  47. Path: []string{"guggy"},
  48. Command: func(roomID, userID string, args []string) (interface{}, error) {
  49. return s.cmdGuggy(client, roomID, userID, args)
  50. },
  51. },
  52. }
  53. }
  54. func (s *Service) cmdGuggy(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) {
  55. // only 1 arg which is the text to search for.
  56. querySentence := strings.Join(args, " ")
  57. gifResult, err := s.text2gifGuggy(querySentence)
  58. if err != nil {
  59. return nil, fmt.Errorf("Failed to query Guggy: %s", err.Error())
  60. }
  61. if gifResult.GIF == "" {
  62. return gomatrix.TextMessage{
  63. MsgType: "m.notice",
  64. Body: "No GIF found!",
  65. }, nil
  66. }
  67. resUpload, err := client.UploadLink(gifResult.GIF)
  68. if err != nil {
  69. return nil, fmt.Errorf("Failed to upload Guggy image to matrix: %s", err.Error())
  70. }
  71. return gomatrix.ImageMessage{
  72. MsgType: "m.image",
  73. Body: querySentence,
  74. URL: resUpload.ContentURI,
  75. Info: gomatrix.ImageInfo{
  76. Height: uint(math.Floor(gifResult.Height)),
  77. Width: uint(math.Floor(gifResult.Width)),
  78. Mimetype: "image/gif",
  79. },
  80. }, nil
  81. }
  82. // text2gifGuggy returns info about a gif
  83. func (s *Service) text2gifGuggy(querySentence string) (*guggyGifResult, error) {
  84. log.Info("Transforming to GIF query ", querySentence)
  85. var query guggyQuery
  86. query.Format = "gif"
  87. query.Sentence = querySentence
  88. reqBody, err := json.Marshal(query)
  89. if err != nil {
  90. return nil, err
  91. }
  92. reader := bytes.NewReader(reqBody)
  93. req, err := http.NewRequest("POST", "https://text2gif.guggy.com/guggify", reader)
  94. if err != nil {
  95. log.Error(err)
  96. return nil, err
  97. }
  98. req.Header.Add("Content-Type", "application/json")
  99. req.Header.Add("apiKey", s.APIKey)
  100. res, err := httpClient.Do(req)
  101. if res != nil {
  102. defer res.Body.Close()
  103. }
  104. if err != nil {
  105. log.Error(err)
  106. return nil, err
  107. }
  108. if res.StatusCode < 200 || res.StatusCode >= 300 {
  109. resBytes, err := ioutil.ReadAll(res.Body)
  110. if err != nil {
  111. log.WithError(err).Error("Failed to decode Guggy response body")
  112. }
  113. log.WithFields(log.Fields{
  114. "code": res.StatusCode,
  115. "body": string(resBytes),
  116. }).Error("Failed to query Guggy")
  117. return nil, fmt.Errorf("Failed to decode response (HTTP %d)", res.StatusCode)
  118. }
  119. var result guggyGifResult
  120. if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
  121. return nil, fmt.Errorf("Failed to decode response (HTTP %d): %s", res.StatusCode, err.Error())
  122. }
  123. return &result, nil
  124. }
  125. func init() {
  126. types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service {
  127. return &Service{
  128. DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType),
  129. }
  130. })
  131. }