Skip to content
This repository was archived by the owner on Apr 9, 2020. It is now read-only.

Commit 22aed18

Browse files
committed
🚧 Created worked version of the package
Need documenting source code, checks by linters, add CI config
1 parent bdbc12d commit 22aed18

11 files changed

+2976
-0
lines changed

fetch_embed.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package oembed
2+
3+
import (
4+
"strconv"
5+
6+
json "github.com/pquerna/ffjson/ffjson"
7+
http "github.com/valyala/fasthttp"
8+
template "github.com/valyala/fasttemplate"
9+
)
10+
11+
type Params struct {
12+
MaxWidth int
13+
MaxHeight int
14+
}
15+
16+
func fetchEmbed(url string, provider providerCandidate, params *Params) (*Response, error) {
17+
resourceUrl := provider.URL
18+
resourceUrl = template.ExecuteString(resourceUrl, "{", "}", map[string]interface{}{"format": "json"})
19+
20+
link := http.AcquireURI()
21+
defer http.ReleaseURI(link)
22+
link.Update(resourceUrl)
23+
qa := link.QueryArgs()
24+
qa.Add("format", "json")
25+
qa.Add("url", url)
26+
27+
if params != nil && params.MaxWidth != 0 {
28+
qa.Add("maxwidth", strconv.Itoa(params.MaxWidth))
29+
}
30+
if params != nil && params.MaxHeight != 0 {
31+
qa.Add("maxheight", strconv.Itoa(params.MaxHeight))
32+
}
33+
link.SetQueryStringBytes(qa.QueryString())
34+
35+
req := http.AcquireRequest()
36+
defer http.ReleaseRequest(req)
37+
req.SetRequestURIBytes(link.FullURI())
38+
39+
resp := http.AcquireResponse()
40+
defer http.ReleaseResponse(resp)
41+
42+
if err := http.Do(req, resp); err != nil {
43+
return nil, err
44+
}
45+
46+
var response Response
47+
if err := json.Unmarshal(resp.Body(), &response); err != nil {
48+
return nil, err
49+
}
50+
response.ProviderName = provider.ProviderName
51+
response.ProviderURL = provider.ProviderURL
52+
return &response, nil
53+
}

fetch_embed_test.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package oembed
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestFetchEmbed(t *testing.T) {
10+
assert := assert.New(t)
11+
t.Run("valid", func(t *testing.T) {
12+
resp, err := fetchEmbed(
13+
"https://www.youtube.com/watch?v=8jPQjjsBbIc",
14+
makeCandidate(Provider{
15+
Name: "YouTube",
16+
URL: "https://www.youtube.com/",
17+
Endpoints: []Endpoint{Endpoint{
18+
Schemes: []string{
19+
"https://*.youtube.com/watch*",
20+
"https://*.youtube.com/v/*\"",
21+
"https://youtu.be/*",
22+
},
23+
URL: "https://www.youtube.com/oembed",
24+
Discovery: true,
25+
}},
26+
}),
27+
&Params{
28+
MaxWidth: 250,
29+
MaxHeight: 250,
30+
},
31+
)
32+
assert.NoError(err)
33+
assert.NotNil(resp)
34+
})
35+
t.Run("invalid", func(t *testing.T) {
36+
for _, url := range []string{
37+
"",
38+
"htt:/abc.com/failed-none-sense",
39+
"https://abc.com/failed-none-sense",
40+
"http://badcom/146753785",
41+
"https://674458092126388225",
42+
"http://www.ted.com/talks/something-does-not-exist",
43+
"https://soundcloud^(*%%$%^$$%$$*&(&)())",
44+
"https://www.flickr.com/services/oembed/?url=http%3A//www.flickr.com/photos/bees/23416sa/",
45+
} {
46+
url := url
47+
t.Run(url, func(t *testing.T) {
48+
c := findProvider(url)
49+
if c == nil {
50+
c = new(providerCandidate)
51+
}
52+
53+
_, err := fetchEmbed(url, *c, nil)
54+
assert.Error(err)
55+
})
56+
}
57+
})
58+
}

find_provider.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package oembed
2+
3+
import (
4+
"regexp"
5+
"strings"
6+
7+
http "github.com/valyala/fasthttp"
8+
)
9+
10+
type providerCandidate struct {
11+
Domain string
12+
ProviderName string
13+
ProviderURL string
14+
Schemes []string
15+
URL string
16+
}
17+
18+
func getHostname(url string) string {
19+
u := http.AcquireURI()
20+
defer http.ReleaseURI(u)
21+
u.Update(url)
22+
if u.Host() != nil {
23+
return strings.TrimPrefix(string(u.Host()), "www.")
24+
}
25+
return ""
26+
}
27+
28+
func makeCandidate(p Provider) providerCandidate {
29+
endpoint := p.Endpoints[0]
30+
domain := getHostname(endpoint.URL)
31+
if domain != "" {
32+
domain = strings.TrimPrefix(domain, "www.")
33+
} else {
34+
domain = ""
35+
}
36+
37+
return providerCandidate{
38+
ProviderName: p.Name,
39+
ProviderURL: p.URL,
40+
Schemes: endpoint.Schemes,
41+
URL: endpoint.URL,
42+
Domain: domain,
43+
}
44+
45+
}
46+
47+
func findProvider(url string) *providerCandidate {
48+
var candidates []providerCandidate
49+
for _, provider := range providersList {
50+
provider := provider
51+
candidate := makeCandidate(provider)
52+
if len(candidate.Schemes) == 0 {
53+
if !strings.Contains(url, candidate.Domain) {
54+
continue
55+
}
56+
candidates = append(candidates, candidate)
57+
continue
58+
}
59+
for _, scheme := range candidate.Schemes {
60+
scheme := scheme
61+
reg := regexp.MustCompile(strings.Replace(scheme, "*", "(.*)", -1))
62+
if !reg.MatchString(url) {
63+
continue
64+
}
65+
66+
candidates = append(candidates, candidate)
67+
break
68+
}
69+
}
70+
if len(candidates) == 0 {
71+
return nil
72+
}
73+
return &candidates[0]
74+
}

find_provider_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package oembed
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestGetHostname(t *testing.T) {
10+
assert := assert.New(t)
11+
for k, v := range map[string]string{
12+
"https://mais.uol.com.br/": "mais.uol.com.br",
13+
"http://www.wootled.com/": "wootled.com",
14+
"http://yfrog.com": "yfrog.com",
15+
"https://www.youtube.com": "youtube.com",
16+
"https://www.znipe.tv": "znipe.tv",
17+
"http://": "",
18+
"": "",
19+
} {
20+
t.Run(k, func(t *testing.T) { assert.Equal(v, getHostname(k)) })
21+
}
22+
}
23+
24+
func TestMakeCandidate(t *testing.T) {
25+
assert.NotNil(t, makeCandidate(Provider{
26+
Name: "YouTube",
27+
URL: "https://www.youtube.com/",
28+
Endpoints: []Endpoint{
29+
Endpoint{
30+
Schemes: []string{
31+
"https://*.youtube.com/watch*",
32+
"https://*.youtube.com/v/*\"",
33+
"https://youtu.be/*",
34+
},
35+
URL: "https://www.youtube.com/oembed",
36+
Discovery: true,
37+
},
38+
},
39+
}))
40+
}
41+
42+
func TestFindProvider(t *testing.T) {
43+
assert.NotNil(t, findProvider("https://www.beautiful.ai/"))
44+
}

is_valid_url.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package oembed
2+
3+
import "net/url"
4+
5+
func isValidURL(src string) bool {
6+
_, err := url.ParseRequestURI(src)
7+
return err == nil
8+
}

is_valid_url_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package oembed
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func Test_IsValidURL(t *testing.T) {
10+
assert := assert.New(t)
11+
t.Run("invalid", func(t *testing.T) {
12+
assert.False(isValidURL("str"))
13+
})
14+
t.Run("valid", func(t *testing.T) {
15+
assert.True(isValidURL("http://www.kickstarter.com"))
16+
})
17+
}

oembed.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package oembed
2+
3+
import (
4+
"golang.org/x/xerrors"
5+
)
6+
7+
var (
8+
ErrInvalidInputURL = xerrors.New("invalid input url")
9+
ErrNoProviderFound = xerrors.New("no provider found with given url")
10+
)
11+
12+
func Extract(url string, params *Params) (*Response, error) {
13+
if !isValidURL(url) {
14+
return nil, ErrInvalidInputURL
15+
}
16+
if c := findProvider(url); c != nil {
17+
return fetchEmbed(url, *c, params)
18+
}
19+
return nil, ErrNoProviderFound
20+
}
21+
22+
func HasProvider(url string) bool {
23+
return findProvider(url) != nil
24+
}

oembed_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package oembed
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestExtract(t *testing.T) {
10+
assert := assert.New(t)
11+
t.Run("valid", func(t *testing.T) {
12+
resp, err := Extract("https://www.youtube.com/watch?v=8jPQjjsBbIc", &Params{
13+
MaxWidth: 250,
14+
MaxHeight: 250,
15+
})
16+
assert.NoError(err)
17+
assert.NotNil(resp)
18+
})
19+
t.Run("invalid", func(t *testing.T) {
20+
for _, url := range []string{
21+
"",
22+
"htt:/abc.com/failed-none-sense",
23+
"https://abc.com/failed-none-sense",
24+
"http://badcom/146753785",
25+
"https://674458092126388225",
26+
"http://www.ted.com/talks/something-does-not-exist",
27+
"https://soundcloud^(*%%$%^$$%$$*&(&)())",
28+
"https://www.flickr.com/services/oembed/?url=http%3A//www.flickr.com/photos/bees/23416sa/",
29+
} {
30+
url := url
31+
t.Run(url, func(t *testing.T) {
32+
_, err := Extract(url, nil)
33+
assert.Error(err)
34+
})
35+
}
36+
})
37+
}
38+
39+
func TestHasProvider(t *testing.T) {
40+
t.Run("true", func(t *testing.T) {
41+
assert.True(t, HasProvider("https://www.youtube.com/watch?v=8jPQjjsBbIc"))
42+
})
43+
t.Run("false", func(t *testing.T) {
44+
assert.False(t, HasProvider("https://blog.toby3d.me/"))
45+
})
46+
}

sync.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package oembed
2+
3+
import (
4+
"io/ioutil"
5+
"log"
6+
"os"
7+
"path/filepath"
8+
9+
json "github.com/pquerna/ffjson/ffjson"
10+
http "github.com/valyala/fasthttp"
11+
)
12+
13+
const source string = "https://oembed.com/providers.json"
14+
15+
var (
16+
providersList []Provider
17+
18+
target = filepath.Join(
19+
os.Getenv("GOPATH"), "src", "gitlab.com", "toby3d", "oembed", "assets", "providers.json",
20+
)
21+
)
22+
23+
func init() {
24+
if err := fetch(source, target); err != nil {
25+
panic(err)
26+
}
27+
}
28+
29+
func fetch(url, target string) error {
30+
status, src, err := http.Get(nil, url)
31+
if err != nil || status != http.StatusOK {
32+
if src, err = ioutil.ReadFile(target); err != nil {
33+
return err
34+
}
35+
}
36+
37+
if err := json.Unmarshal(src, &providersList); err != nil {
38+
return err
39+
}
40+
41+
if status == http.StatusOK {
42+
if err = ioutil.WriteFile(target, src, os.ModePerm); err != nil {
43+
return err
44+
}
45+
}
46+
47+
log.Println("providers.json has been updated")
48+
return nil
49+
}

0 commit comments

Comments
 (0)