/
urls.go
157 lines (131 loc) · 3.62 KB
/
urls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package urls
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/keighl/metabolize"
)
type OembedData struct {
ProviderName string `json:"provider_name"`
Title string `json:"title"`
ThumbnailURL string `json:"thumbnail_url"`
}
type LinkPreviewData struct {
Site string `json:"site" meta:"og:site_name"`
Title string `json:"title" meta:"og:title"`
ThumbnailURL string `json:"thumbnailUrl" meta:"og:image"`
ContentType string `json:"contentType"`
}
type Site struct {
Title string `json:"title"`
Address string `json:"address"`
ImageSite bool `json:"imageSite"`
}
const YouTubeOembedLink = "https://www.youtube.com/oembed?format=json&url=%s"
var httpClient = http.Client{
Timeout: 30 * time.Second,
}
func LinkPreviewWhitelist() []Site {
return []Site{
Site{
Title: "YouTube",
Address: "youtube.com",
ImageSite: false,
},
Site{
Title: "YouTube shortener",
Address: "youtu.be",
ImageSite: false,
},
Site{
Title: "Tenor GIFs",
Address: "tenor.com",
ImageSite: true,
},
Site{
Title: "GIPHY GIFs",
Address: "giphy.com",
ImageSite: true,
},
Site{
Title: "GitHub",
Address: "github.com",
ImageSite: false,
},
}
}
func GetURLContent(url string) (data []byte, err error) {
// nolint: gosec
response, err := httpClient.Get(url)
if err != nil {
return data, fmt.Errorf("Can't get content from link %s", url)
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
func GetYoutubeOembed(url string) (data OembedData, err error) {
oembedLink := fmt.Sprintf(YouTubeOembedLink, url)
jsonBytes, err := GetURLContent(oembedLink)
if err != nil {
return data, fmt.Errorf("Can't get bytes from youtube oembed response on %s link", oembedLink)
}
err = json.Unmarshal(jsonBytes, &data)
if err != nil {
return data, fmt.Errorf("Can't unmarshall json")
}
return data, nil
}
func GetYoutubePreviewData(link string) (previewData LinkPreviewData, err error) {
oembedData, err := GetYoutubeOembed(link)
if err != nil {
return previewData, err
}
previewData.Title = oembedData.Title
previewData.Site = oembedData.ProviderName
previewData.ThumbnailURL = oembedData.ThumbnailURL
return previewData, nil
}
func GetGithubPreviewData(link string) (previewData LinkPreviewData, err error) {
// nolint: gosec
res, err := httpClient.Get(link)
if err != nil {
return previewData, fmt.Errorf("Can't get content from link %s", link)
}
err = metabolize.Metabolize(res.Body, &previewData)
if err != nil {
return previewData, fmt.Errorf("Can't get meta info from link %s", link)
}
return previewData, nil
}
func GetLinkPreviewData(link string) (previewData LinkPreviewData, err error) {
url, err := url.Parse(link)
if err != nil {
return previewData, fmt.Errorf("Cant't parse link %s", link)
}
hostname := strings.ToLower(url.Hostname())
youtubeHostnames := []string{"youtube.com", "www.youtube.com", "youtu.be"}
for _, youtubeHostname := range youtubeHostnames {
if youtubeHostname == hostname {
return GetYoutubePreviewData(link)
}
}
if "github.com" == hostname {
return GetGithubPreviewData(link)
}
for _, site := range LinkPreviewWhitelist() {
if strings.HasSuffix(hostname, site.Address) && site.ImageSite {
content, contentErr := GetURLContent(link)
if contentErr != nil {
return previewData, contentErr
}
previewData.ThumbnailURL = link
previewData.ContentType = http.DetectContentType(content)
return previewData, nil
}
}
return previewData, fmt.Errorf("Link %s isn't whitelisted. Hostname - %s", link, url.Hostname())
}