Browse Source

Handle image search results

pull/158/head
Richard Lewis 8 years ago
parent
commit
823d3277c7
  1. 6
      config.sample.yaml
  2. 1
      src/github.com/matrix-org/go-neb/goneb.go
  3. 79
      src/github.com/matrix-org/go-neb/services/imgur/imgur.go
  4. 36
      src/github.com/matrix-org/go-neb/services/imgur/imgur_test.go

6
config.sample.yaml

@ -81,6 +81,12 @@ services:
api_key: "AIzaSyA4FD39m9" api_key: "AIzaSyA4FD39m9"
cx: "AIASDFWSRRtrtr" cx: "AIASDFWSRRtrtr"
- ID: "imgur_service"
Type: "imgur"
UserID: "@imgur:localhost" # requires a Syncing client
Config:
api_key: "AIzaSyA4FD39m9"
- ID: "rss_service" - ID: "rss_service"
Type: "rssbot" Type: "rssbot"
UserID: "@another_goneb:localhost" UserID: "@another_goneb:localhost"

1
src/github.com/matrix-org/go-neb/goneb.go

@ -24,6 +24,7 @@ import (
_ "github.com/matrix-org/go-neb/services/github" _ "github.com/matrix-org/go-neb/services/github"
_ "github.com/matrix-org/go-neb/services/google" _ "github.com/matrix-org/go-neb/services/google"
_ "github.com/matrix-org/go-neb/services/guggy" _ "github.com/matrix-org/go-neb/services/guggy"
_ "github.com/matrix-org/go-neb/services/imgur"
_ "github.com/matrix-org/go-neb/services/jira" _ "github.com/matrix-org/go-neb/services/jira"
_ "github.com/matrix-org/go-neb/services/rssbot" _ "github.com/matrix-org/go-neb/services/rssbot"
_ "github.com/matrix-org/go-neb/services/slackapi" _ "github.com/matrix-org/go-neb/services/slackapi"

79
src/github.com/matrix-org/go-neb/services/imgur/imgur.go

@ -5,13 +5,13 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/matrix-org/go-neb/types" "github.com/matrix-org/go-neb/types"
"github.com/matrix-org/gomatrix"
) )
// ServiceType of the Imgur service // ServiceType of the Imgur service
@ -108,12 +108,12 @@ type Service struct {
} }
// Commands supported: // Commands supported:
// !imgur image some_search_query_without_quotes
// !imgur some_search_query_without_quotes
// Responds with a suitable image into the same room as the command. // Responds with a suitable image into the same room as the command.
func (s *Service) Commands(client *gomatrix.Client) []types.Command { func (s *Service) Commands(client *gomatrix.Client) []types.Command {
return []types.Command{ return []types.Command{
types.Command{ types.Command{
Path: []string{"imgur", "image"},
Path: []string{"imgur"},
Command: func(roomID, userID string, args []string) (interface{}, error) { Command: func(roomID, userID string, args []string) (interface{}, error) {
return s.cmdImgurImgSearch(client, roomID, userID, args) return s.cmdImgurImgSearch(client, roomID, userID, args)
}, },
@ -130,7 +130,7 @@ func (s *Service) Commands(client *gomatrix.Client) []types.Command {
// usageMessage returns a matrix TextMessage representation of the service usage // usageMessage returns a matrix TextMessage representation of the service usage
func usageMessage() *gomatrix.TextMessage { func usageMessage() *gomatrix.TextMessage {
return &gomatrix.TextMessage{"m.notice", return &gomatrix.TextMessage{"m.notice",
`Usage: !imgur image image_search_text`}
`Usage: !imgur image_search_text`}
} }
func (s *Service) cmdImgurImgSearch(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { func (s *Service) cmdImgurImgSearch(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) {
@ -142,36 +142,49 @@ func (s *Service) cmdImgurImgSearch(client *gomatrix.Client, roomID, userID stri
// Get the query text to search for. // Get the query text to search for.
querySentence := strings.Join(args, " ") querySentence := strings.Join(args, " ")
searchResult, err := s.text2imgImgur(querySentence)
searchResultImage, searchResultAlbum, err := s.text2imgImgur(querySentence)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var imgURL = searchResult.Link
if imgURL == "" {
// Image returned
if searchResultImage != nil {
var imgURL = searchResultImage.Link
if imgURL == "" {
return gomatrix.TextMessage{
MsgType: "m.notice",
Body: "No image found!",
}, nil
}
// FIXME -- Sometimes upload fails with a cryptic error - "msg=Upload request failed code=400"
resUpload, err := client.UploadLink(imgURL)
if err != nil {
return nil, fmt.Errorf("Failed to upload Imgur image to matrix: %s", err.Error())
}
return gomatrix.ImageMessage{
MsgType: "m.image",
Body: querySentence,
URL: resUpload.ContentURI,
Info: gomatrix.ImageInfo{
Height: uint(searchResultImage.Height),
Width: uint(searchResultImage.Width),
Mimetype: searchResultImage.Type,
},
}, nil
} else if searchResultAlbum != nil {
return gomatrix.TextMessage{
MsgType: "m.notice",
Body: "Search returned an album - Not currently supported",
}, nil
} else {
return gomatrix.TextMessage{ return gomatrix.TextMessage{
MsgType: "m.notice", MsgType: "m.notice",
Body: "No image found!", Body: "No image found!",
}, nil }, nil
} }
// FIXME -- Sometimes upload fails with a cryptic error - "msg=Upload request failed code=400"
resUpload, err := client.UploadLink(imgURL)
if err != nil {
return nil, fmt.Errorf("Failed to upload Imgur image to matrix: %s", err.Error())
}
return gomatrix.ImageMessage{
MsgType: "m.image",
Body: querySentence,
URL: resUpload.ContentURI,
Info: gomatrix.ImageInfo{
Height: uint(math.Floor(searchResult.Height)),
Width: uint(math.Floor(searchResult.Width)),
Mimetype: searchResult.Type,
},
}, nil
} }
// text2imgImgur returns info about an image or an album // text2imgImgur returns info about an image or an album
@ -179,8 +192,8 @@ func (s *Service) text2imgImgur(query string) (*imgurGalleryImage, *imgurGallery
log.Info("Searching Imgur for an image of a ", query) log.Info("Searching Imgur for an image of a ", query)
var base = "https://api.imgur.com/3/gallery/search/" var base = "https://api.imgur.com/3/gallery/search/"
var sort = "time" // time | viral | top
var window = all // day | week | month | year | all
var sort = "time" // time | viral | top
var window = "all" // day | week | month | year | all
var page = 1 var page = 1
var urlString = fmt.Sprintf("%s/%s/%s/%d", base, sort, window, page) var urlString = fmt.Sprintf("%s/%s/%s/%d", base, sort, window, page)
@ -201,33 +214,33 @@ func (s *Service) text2imgImgur(query string) (*imgurGalleryImage, *imgurGallery
return nil, nil, fmt.Errorf("Request error: %d, %s", res.StatusCode, response2String(res)) return nil, nil, fmt.Errorf("Request error: %d, %s", res.StatusCode, response2String(res))
} }
var searchResults imgurSearchResults
if err := json.NewDecoder(res.Body).Decode(&searchResults); err != nil || !searchResults.data {
var searchResults imgurSearchResponse
if err := json.NewDecoder(res.Body).Decode(&searchResults); err != nil || !searchResults.Data {
return nil, nil, fmt.Errorf("No images found - %s", err.Error()) return nil, nil, fmt.Errorf("No images found - %s", err.Error())
} }
// Check if we have an image or a gallery // Check if we have an image or a gallery
var dataInt map[string]interface{} var dataInt map[string]interface{}
if err := json.Unmarshal(searchResults.Data, &dataInt); err != nil || !searchResults.data {
if err := json.Unmarshal(searchResults.Data, &dataInt); err != nil || !searchResults.Data {
return nil, nil, fmt.Errorf("Failed to parse response data - %s", err.Error()) return nil, nil, fmt.Errorf("Failed to parse response data - %s", err.Error())
} }
// Return an album // Return an album
if dataInt["is_album"].(bool) { if dataInt["is_album"].(bool) {
var album imgurGalleryAlbum var album imgurGalleryAlbum
if err := json.Unmarshal(searchResults.Data, &album); err != nill {
if err := json.Unmarshal(searchResults.Data, &album); err != nil {
return nil, nil, fmt.Errorf("Failed to parse album data - %s", err.Error()) return nil, nil, fmt.Errorf("Failed to parse album data - %s", err.Error())
} }
return nil, album, nil
return nil, &album, nil
} }
// Return an image // Return an image
var image imgurGalleryImage var image imgurGalleryImage
if err := json.Unmarshal(searchResults.Data, &image); err != nill {
if err := json.Unmarshal(searchResults.Data, &image); err != nil {
return nil, nil, fmt.Errorf("Failed to parse image data - %s", err.Error()) return nil, nil, fmt.Errorf("Failed to parse image data - %s", err.Error())
} }
return image, nil, nil
return &image, nil, nil
} }
// response2String returns a string representation of an HTTP response body // response2String returns a string representation of an HTTP response body

36
src/github.com/matrix-org/go-neb/services/imgur/imgur_test.go

@ -20,16 +20,16 @@ import (
func TestCommand(t *testing.T) { func TestCommand(t *testing.T) {
database.SetServiceDB(&database.NopStorage{}) database.SetServiceDB(&database.NopStorage{})
apiKey := "secret" apiKey := "secret"
googleImageURL := "https://www.googleapis.com/customsearch/v1"
imgurImageURL := "https://www.imgurapis.com/customsearch/v1"
// Mock the response from Google
googleTrans := testutils.NewRoundTripper(func(req *http.Request) (*http.Response, error) {
googleURL := "https://www.googleapis.com/customsearch/v1"
// Mock the response from imgur
imgurTrans := testutils.NewRoundTripper(func(req *http.Request) (*http.Response, error) {
imgurURL := "https://www.imgurapis.com/customsearch/v1"
query := req.URL.Query() query := req.URL.Query()
// Check the base API URL // Check the base API URL
if !strings.HasPrefix(req.URL.String(), googleURL) {
t.Fatalf("Bad URL: got %s want prefix %s", req.URL.String(), googleURL)
if !strings.HasPrefix(req.URL.String(), imgurURL) {
t.Fatalf("Bad URL: got %s want prefix %s", req.URL.String(), imgurURL)
} }
// Check the request method // Check the request method
if req.Method != "GET" { if req.Method != "GET" {
@ -46,12 +46,12 @@ func TestCommand(t *testing.T) {
t.Fatalf("Bad search string: got \"%s\" (%d characters) ", searchString, searchStringLength) t.Fatalf("Bad search string: got \"%s\" (%d characters) ", searchString, searchStringLength)
} }
resImage := googleImage{
resImage := imgurImage{
Width: 64, Width: 64,
Height: 64, Height: 64,
} }
res := googleSearchResult{
res := imgurSearchResult{
Title: "A Cat", Title: "A Cat",
Link: "http://cat.com/cat.jpg", Link: "http://cat.com/cat.jpg",
Mime: "image/jpeg", Mime: "image/jpeg",
@ -60,29 +60,29 @@ func TestCommand(t *testing.T) {
b, err := json.Marshal(res) b, err := json.Marshal(res)
if err != nil { if err != nil {
t.Fatalf("Failed to marshal Google response - %s", err)
t.Fatalf("Failed to marshal imgur response - %s", err)
} }
return &http.Response{ return &http.Response{
StatusCode: 200, StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBuffer(b)), Body: ioutil.NopCloser(bytes.NewBuffer(b)),
}, nil }, nil
}) })
// clobber the Google service http client instance
httpClient = &http.Client{Transport: googleTrans}
// clobber the imgur service http client instance
httpClient = &http.Client{Transport: imgurTrans}
// Create the Google service
srv, err := types.CreateService("id", ServiceType, "@googlebot:hyrule", []byte(
// Create the imgur service
srv, err := types.CreateService("id", ServiceType, "@imgurbot:hyrule", []byte(
`{"api_key":"`+apiKey+`"}`, `{"api_key":"`+apiKey+`"}`,
)) ))
if err != nil { if err != nil {
t.Fatal("Failed to create Google service: ", err)
t.Fatal("Failed to create imgur service: ", err)
} }
google := srv.(*Service)
imgur := srv.(*Service)
// Mock the response from Matrix // Mock the response from Matrix
matrixTrans := struct{ testutils.MockTransport }{} matrixTrans := struct{ testutils.MockTransport }{}
matrixTrans.RT = func(req *http.Request) (*http.Response, error) { matrixTrans.RT = func(req *http.Request) (*http.Response, error) {
if req.URL.String() == googleImageURL { // getting the Google image
if req.URL.String() == imgurImageURL { // getting the imgur image
return &http.Response{ return &http.Response{
StatusCode: 200, StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString("some image data")), Body: ioutil.NopCloser(bytes.NewBufferString("some image data")),
@ -95,11 +95,11 @@ func TestCommand(t *testing.T) {
} }
return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) return nil, fmt.Errorf("Unknown URL: %s", req.URL.String())
} }
matrixCli, _ := gomatrix.NewClient("https://hyrule", "@googlebot:hyrule", "its_a_secret")
matrixCli, _ := gomatrix.NewClient("https://hyrule", "@imgurbot:hyrule", "its_a_secret")
matrixCli.Client = &http.Client{Transport: matrixTrans} matrixCli.Client = &http.Client{Transport: matrixTrans}
// Execute the matrix !command // Execute the matrix !command
cmds := google.Commands(matrixCli)
cmds := imgur.Commands(matrixCli)
if len(cmds) != 2 { if len(cmds) != 2 {
t.Fatalf("Unexpected number of commands: %d", len(cmds)) t.Fatalf("Unexpected number of commands: %d", len(cmds))
} }

Loading…
Cancel
Save