Implement Imgur info
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
27e7dab209
commit
137e18e6c1
|
@ -7,3 +7,6 @@ steps:
|
||||||
image: golang
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- go test
|
- go test
|
||||||
|
environment:
|
||||||
|
IMGUR_CLIENT_ID:
|
||||||
|
from_secret: imgur_client_id
|
135
imgur.go
135
imgur.go
|
@ -1,9 +1,140 @@
|
||||||
package linkinfo
|
package linkinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const imgurApiUrl = "https://api.imgur.com/3/%s/%s.json"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
imgurHosts = []string{"imgur.com", "i.imgur.com"}
|
imgurHosts = []string{"imgur.com", "i.imgur.com"}
|
||||||
|
|
||||||
|
imgurAlbumRegexp = regexp.MustCompile("^/(a|gallery)/")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i *LinkInfoApi) ImgurLinkHandler(link string) (*LinkInfo, error) {
|
type ImgurOptions struct {
|
||||||
return nil, nil
|
Option
|
||||||
|
|
||||||
|
ClientId string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImgurInfoApi struct {
|
||||||
|
api *LinkInfoApi
|
||||||
|
opts *ImgurOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type imgurResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Data imgurData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type imgurData struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
Animated bool `json:"animated"`
|
||||||
|
Nsfw bool `json:"nsfw"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ImgurInfoApi) Handler(link string) (*LinkInfo, error) {
|
||||||
|
if i.opts.ClientId == "" {
|
||||||
|
return nil, errors.New("invalid client id")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := filepath.Base(u.Path)
|
||||||
|
|
||||||
|
extension := filepath.Ext(id)
|
||||||
|
|
||||||
|
if extension != "" {
|
||||||
|
id = id[0 : len(id)-len(extension)]
|
||||||
|
}
|
||||||
|
|
||||||
|
imageType := "image"
|
||||||
|
|
||||||
|
if imgurAlbumRegexp.MatchString(link) {
|
||||||
|
imageType = "album"
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", fmt.Sprintf(imgurApiUrl, imageType, id), nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Client-ID "+i.opts.ClientId)
|
||||||
|
|
||||||
|
res, err := i.api.Client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var response imgurResponse
|
||||||
|
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Success {
|
||||||
|
return nil, errors.New("imgur api returned success=false")
|
||||||
|
}
|
||||||
|
|
||||||
|
var title string
|
||||||
|
|
||||||
|
if response.Data.Title != "" {
|
||||||
|
title = "Imgur - " + response.Data.Title
|
||||||
|
} else {
|
||||||
|
title = "Imgur - " + id
|
||||||
|
|
||||||
|
switch response.Data.Type {
|
||||||
|
case "image/jpeg":
|
||||||
|
title += ".jpg"
|
||||||
|
case "image/png":
|
||||||
|
title += ".png"
|
||||||
|
case "image/gif":
|
||||||
|
title += ".gif"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attribs := make([]string, 0)
|
||||||
|
|
||||||
|
if imageType == "album" {
|
||||||
|
attribs = append(attribs, "Album")
|
||||||
|
} else {
|
||||||
|
attribs = append(attribs, fmt.Sprintf("%dx%d", response.Data.Width, response.Data.Height))
|
||||||
|
|
||||||
|
if response.Data.Animated {
|
||||||
|
attribs = append(attribs, "Animated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
title += " (" + strings.Join(attribs, ", ") + ")"
|
||||||
|
|
||||||
|
if response.Data.Nsfw {
|
||||||
|
attribs = append(attribs, "NSFW")
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &LinkInfo{
|
||||||
|
Title: title,
|
||||||
|
Description: response.Data.Description,
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package linkinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImgurInfoApi_Handler(t *testing.T) {
|
||||||
|
api := New(&ImgurOptions{
|
||||||
|
ClientId: os.Getenv("IMGUR_CLIENT_ID"),
|
||||||
|
})
|
||||||
|
|
||||||
|
info, err := api.Imgur.Handler("https://i.imgur.com/1GKJg79.gifv")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error getting imgur info:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Title != "Imgur - Approaching the weekend like (720x404, Animated)" {
|
||||||
|
t.Fatal("Unexpected title", info.Title)
|
||||||
|
}
|
||||||
|
}
|
27
linkinfo.go
27
linkinfo.go
|
@ -12,7 +12,9 @@ type LinkHandler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkInfoApi struct {
|
type LinkInfoApi struct {
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
|
|
||||||
|
Imgur *ImgurInfoApi
|
||||||
linkHandlers []*LinkHandler
|
linkHandlers []*LinkHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,26 +27,45 @@ type LinkInfo struct {
|
||||||
Redirects []string `json:"redirects,omitempty"`
|
Redirects []string `json:"redirects,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *LinkInfoApi {
|
func New(opts ...Option) *LinkInfoApi {
|
||||||
api := &LinkInfoApi{
|
api := &LinkInfoApi{
|
||||||
Client: &http.Client{
|
Client: &http.Client{
|
||||||
Timeout: 60 * time.Second,
|
Timeout: 60 * time.Second,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
switch opt.(type) {
|
||||||
|
case *ImgurOptions:
|
||||||
|
api.Imgur = &ImgurInfoApi{api, opt.(*ImgurOptions)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
api.registerDefaultHandlers()
|
api.registerDefaultHandlers()
|
||||||
|
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *LinkInfoApi) registerDefaultHandlers() {
|
func (i *LinkInfoApi) registerDefaultHandlers() {
|
||||||
|
i.linkHandlers = make([]*LinkHandler, 0)
|
||||||
|
|
||||||
|
if i.Imgur != nil {
|
||||||
|
i.linkHandlers = append(i.linkHandlers, &LinkHandler{
|
||||||
|
Hosts: imgurHosts,
|
||||||
|
Handler: i.Imgur.Handler,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
i.linkHandlers = []*LinkHandler{
|
i.linkHandlers = []*LinkHandler{
|
||||||
{Hosts: youtubeHosts, Handler: i.YoutubeLinkHandler},
|
{Hosts: youtubeHosts, Handler: i.YoutubeLinkHandler},
|
||||||
{Hosts: imgurHosts, Handler: i.ImgurLinkHandler},
|
|
||||||
{Hosts: twitterHosts, Handler: i.TwitterLinkHandler},
|
{Hosts: twitterHosts, Handler: i.TwitterLinkHandler},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *LinkInfoApi) AddHandler(handler *LinkHandler) {
|
||||||
|
i.linkHandlers = append(i.linkHandlers, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func (i *LinkInfoApi) Retrieve(link string) (*LinkInfo, error) {
|
func (i *LinkInfoApi) Retrieve(link string) (*LinkInfo, error) {
|
||||||
u, err := url.Parse(link)
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package linkinfo
|
||||||
|
|
||||||
|
type Option interface {
|
||||||
|
}
|
Loading…
Reference in New Issue