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

Commit 6b9a7b7

Browse files
committed
♻️ Refactored source code, packed providers.json
1 parent 22aed18 commit 6b9a7b7

11 files changed

+892
-800
lines changed

a_oembed-packr.go

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

errors.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package oembed
2+
3+
import (
4+
"fmt"
5+
6+
"golang.org/x/xerrors"
7+
)
8+
9+
// Error represent a complex error
10+
type Error struct {
11+
Message string
12+
URL string
13+
Details xerrors.Frame
14+
}
15+
16+
// Error returns a string formatted error
17+
func (e Error) Error() string {
18+
return fmt.Sprint(e)
19+
}
20+
21+
// Format implements fmt.Formatter method
22+
func (e Error) Format(f fmt.State, c rune) {
23+
xerrors.FormatError(e, f, c)
24+
}
25+
26+
// FormatError implements xerrors.Formatter method
27+
func (e Error) FormatError(p xerrors.Printer) error {
28+
p.Printf("ERROR: %d [url:%s]", e.Message, e.URL)
29+
if p.Detail() {
30+
e.Details.Format(p)
31+
}
32+
return nil
33+
}

fetch_embed.go

+18-11
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@ import (
88
template "github.com/valyala/fasttemplate"
99
)
1010

11+
// Params represent a optional parameters for Extract method.
1112
type Params struct {
1213
MaxWidth int
1314
MaxHeight int
1415
}
1516

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"})
17+
func fetchEmbed(url string, provider *Provider, params *Params) (*OEmbed, error) {
18+
resourceURL := provider.Endpoints[0].URL
19+
resourceURL = template.ExecuteString(resourceURL, "{", "}", map[string]interface{}{"format": "json"})
1920

2021
link := http.AcquireURI()
2122
defer http.ReleaseURI(link)
22-
link.Update(resourceUrl)
23+
link.Update(resourceURL)
2324
qa := link.QueryArgs()
2425
qa.Add("format", "json")
2526
qa.Add("url", url)
@@ -40,14 +41,20 @@ func fetchEmbed(url string, provider providerCandidate, params *Params) (*Respon
4041
defer http.ReleaseResponse(resp)
4142

4243
if err := http.Do(req, resp); err != nil {
43-
return nil, err
44+
return nil, Error{
45+
Message: err.Error(),
46+
URL: url,
47+
}
4448
}
4549

46-
var response Response
47-
if err := json.Unmarshal(resp.Body(), &response); err != nil {
48-
return nil, err
50+
var oEmbed OEmbed
51+
if err := json.UnmarshalFast(resp.Body(), &oEmbed); err != nil {
52+
return nil, Error{
53+
Message: err.Error(),
54+
URL: url,
55+
}
4956
}
50-
response.ProviderName = provider.ProviderName
51-
response.ProviderURL = provider.ProviderURL
52-
return &response, nil
57+
oEmbed.ProviderName = provider.Name
58+
oEmbed.ProviderURL = provider.URL
59+
return &oEmbed, nil
5360
}

fetch_embed_test.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ func TestFetchEmbed(t *testing.T) {
1111
t.Run("valid", func(t *testing.T) {
1212
resp, err := fetchEmbed(
1313
"https://www.youtube.com/watch?v=8jPQjjsBbIc",
14-
makeCandidate(Provider{
14+
&Provider{
1515
Name: "YouTube",
1616
URL: "https://www.youtube.com/",
17-
Endpoints: []Endpoint{Endpoint{
17+
Endpoints: []Endpoint{{
1818
Schemes: []string{
1919
"https://*.youtube.com/watch*",
2020
"https://*.youtube.com/v/*\"",
@@ -23,7 +23,7 @@ func TestFetchEmbed(t *testing.T) {
2323
URL: "https://www.youtube.com/oembed",
2424
Discovery: true,
2525
}},
26-
}),
26+
},
2727
&Params{
2828
MaxWidth: 250,
2929
MaxHeight: 250,
@@ -34,7 +34,6 @@ func TestFetchEmbed(t *testing.T) {
3434
})
3535
t.Run("invalid", func(t *testing.T) {
3636
for _, url := range []string{
37-
"",
3837
"htt:/abc.com/failed-none-sense",
3938
"https://abc.com/failed-none-sense",
4039
"http://badcom/146753785",
@@ -45,12 +44,12 @@ func TestFetchEmbed(t *testing.T) {
4544
} {
4645
url := url
4746
t.Run(url, func(t *testing.T) {
48-
c := findProvider(url)
49-
if c == nil {
50-
c = new(providerCandidate)
47+
provider := findProvider(url)
48+
if provider == nil {
49+
provider = &Provider{Endpoints: []Endpoint{Endpoint{}}}
5150
}
5251

53-
_, err := fetchEmbed(url, *c, nil)
52+
_, err := fetchEmbed(url, provider, nil)
5453
assert.Error(err)
5554
})
5655
}

find_provider.go

+17-9
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,34 @@ func makeCandidate(p Provider) providerCandidate {
4444

4545
}
4646

47-
func findProvider(url string) *providerCandidate {
48-
var candidates []providerCandidate
49-
for _, provider := range providersList {
47+
func findProvider(url string) *Provider {
48+
var candidates []Provider
49+
for _, provider := range Providers {
5050
provider := provider
51-
candidate := makeCandidate(provider)
52-
if len(candidate.Schemes) == 0 {
53-
if !strings.Contains(url, candidate.Domain) {
51+
52+
endpoint := provider.Endpoints[0]
53+
domain := getHostname(endpoint.URL)
54+
if domain != "" {
55+
domain = strings.TrimPrefix(domain, "www.")
56+
} else {
57+
domain = ""
58+
}
59+
60+
if len(endpoint.Schemes) == 0 {
61+
if !strings.Contains(url, domain) {
5462
continue
5563
}
56-
candidates = append(candidates, candidate)
64+
candidates = append(candidates, provider)
5765
continue
5866
}
59-
for _, scheme := range candidate.Schemes {
67+
for _, scheme := range endpoint.Schemes {
6068
scheme := scheme
6169
reg := regexp.MustCompile(strings.Replace(scheme, "*", "(.*)", -1))
6270
if !reg.MatchString(url) {
6371
continue
6472
}
6573

66-
candidates = append(candidates, candidate)
74+
candidates = append(candidates, provider)
6775
break
6876
}
6977
}

find_provider_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func TestGetHostname(t *testing.T) {
1717
"http://": "",
1818
"": "",
1919
} {
20+
k, v := k, v
2021
t.Run(k, func(t *testing.T) { assert.Equal(v, getHostname(k)) })
2122
}
2223
}
@@ -26,7 +27,7 @@ func TestMakeCandidate(t *testing.T) {
2627
Name: "YouTube",
2728
URL: "https://www.youtube.com/",
2829
Endpoints: []Endpoint{
29-
Endpoint{
30+
{
3031
Schemes: []string{
3132
"https://*.youtube.com/watch*",
3233
"https://*.youtube.com/v/*\"",

oembed.go

+24-13
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
11
package oembed
22

3-
import (
4-
"golang.org/x/xerrors"
5-
)
3+
import "golang.org/x/xerrors"
64

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) {
5+
// Extract try fetch oEmbed object for input url with params (if represent).
6+
// Return OEmbed if success.
7+
func Extract(url string, params *Params) (*OEmbed, error) {
138
if !isValidURL(url) {
14-
return nil, ErrInvalidInputURL
9+
return nil, Error{
10+
Message: "invalid input url",
11+
URL: url,
12+
}
13+
}
14+
if provider := findProvider(url); provider != nil {
15+
resp, err := fetchEmbed(url, provider, params)
16+
if err != nil {
17+
return nil, Error{
18+
Message: err.Error(),
19+
URL: url,
20+
Details: xerrors.Caller(1),
21+
}
22+
}
23+
return resp, nil
1524
}
16-
if c := findProvider(url); c != nil {
17-
return fetchEmbed(url, *c, params)
25+
26+
return nil, Error{
27+
Message: "no provider found with given url",
28+
URL: url,
1829
}
19-
return nil, ErrNoProviderFound
2030
}
2131

32+
// HasProvider checks what input url has oEmbed provider
2233
func HasProvider(url string) bool {
2334
return findProvider(url) != nil
2435
}

sync.go

+20-24
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
11
package oembed
22

33
import (
4-
"io/ioutil"
54
"log"
6-
"os"
7-
"path/filepath"
5+
"time"
86

7+
"github.com/gobuffalo/packr"
98
json "github.com/pquerna/ffjson/ffjson"
109
http "github.com/valyala/fasthttp"
1110
)
1211

13-
const source string = "https://oembed.com/providers.json"
12+
// SourceURL is a official url of supported providers list
13+
const SourceURL string = "https://oembed.com/providers.json"
1414

15-
var (
16-
providersList []Provider
15+
// Providers contains all default (or new synced) providers
16+
var Providers []Provider //nolint:gochecknoglobals
1717

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 {
18+
func init() { //nolint:gochecknoinits
19+
if err := Sync(SourceURL); err != nil {
2520
panic(err)
2621
}
2722
}
2823

29-
func fetch(url, target string) error {
30-
status, src, err := http.Get(nil, url)
24+
// Sync try update Providers variable via request and parsing body of sourceURL
25+
func Sync(sourceURL string) error {
26+
status, src, err := http.GetTimeout(nil, sourceURL, 2*time.Second)
3127
if err != nil || status != http.StatusOK {
32-
if src, err = ioutil.ReadFile(target); err != nil {
33-
return err
28+
if src, err = packr.NewBox("./assets").Find("providers.json"); err != nil {
29+
return Error{
30+
Message: err.Error(),
31+
URL: sourceURL,
32+
}
3433
}
3534
}
3635

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
36+
if err = json.Unmarshal(src, &Providers); err != nil {
37+
return Error{
38+
Message: err.Error(),
39+
URL: sourceURL,
4440
}
4541
}
4642

sync_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package oembed
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestSync(t *testing.T) {
10+
t.Run("invalid", func(t *testing.T) {
11+
t.Run("source url", func(t *testing.T) {
12+
assert.NoError(t, Sync("wtf"))
13+
assert.NotZero(t, len(Providers))
14+
})
15+
t.Run("resource body", func(t *testing.T) {
16+
assert.Error(t, Sync("https://ddg.gg/"))
17+
assert.NotZero(t, len(Providers))
18+
})
19+
})
20+
t.Run("valid url", func(t *testing.T) {
21+
assert.NoError(t, Sync(SourceURL))
22+
assert.NotZero(t, len(Providers))
23+
})
24+
}

types.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
package oembed
33

44
type (
5+
// Provider represent a single provider info
56
Provider struct {
67
Name string `json:"provider_name"`
78
URL string `json:"provider_url"`
89
Endpoints []Endpoint `json:"endpoints"`
910
}
1011

12+
// Provider represent a single endpoint of Provider
1113
Endpoint struct {
1214
Schemes []string `json:"schemes,omitempty"`
1315
URL string `json:"url"`
@@ -17,7 +19,7 @@ type (
1719

1820
// Response can specify a resource type, such as photo or video.
1921
// Each type has specific parameters associated with it.
20-
Response struct {
22+
OEmbed struct {
2123
// The resource type.
2224
Type string `json:"type"` // required
2325

@@ -88,7 +90,7 @@ type (
8890
// Link type allow a provider to return any generic embed data (such as title and author_name), without
8991
// providing either the url or html parameters. The consumer may then link to the resource, using the URL
9092
// specified in the original request.
91-
Link string
93+
// Link string
9294

9395
// Rich is used for rich HTML content that does not fall under one of the other categories.
9496
Rich struct {

0 commit comments

Comments
 (0)