Skip to content

Commit 6690aef

Browse files
authored
Merge pull request #108 from ndaidong/v2.0.0
v2.0.0
2 parents f85921b + 27bbf4a commit 6690aef

33 files changed

+1382
-1249
lines changed

README.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Extract eEmbed content from given URL.
1414
- [Changes with Instagram](#changes-with-instagram)
1515

1616

17-
1817
## Demo
1918

2019
- [Give it a try!](https://ndaidong.github.io/oembed-parser-demo)
@@ -77,6 +76,29 @@ console.log(data)
7776

7877
Return boolean. True if the URL matches with any provider in the list.
7978

79+
#### .findProvider(String URL)
80+
81+
Return provider which is relevant to given URL.
82+
83+
For example:
84+
85+
```js
86+
import {
87+
findProvider
88+
} from 'oembed-parser'
89+
90+
findProvider('https://www.facebook.com/video.php?v=999999999')
91+
92+
// get something like below:
93+
94+
// {
95+
// fetchEndpoint: 'https://graph.facebook.com/v10.0/oembed_video',
96+
// providerName: 'Facebook',
97+
// providerUrl: 'https://www.facebook.com/'
98+
// }
99+
```
100+
101+
80102
#### .setProviderList(Array of provider definitions)
81103

82104
Sets the list of providers to use, overriding the defaults.
@@ -93,17 +115,17 @@ For the expected format, see the
93115
List of resource providers is a clone of [oembed.com](http://oembed.com/providers.json) and available [here](https://raw.githubusercontent.com/ndaidong/oembed-parser/master/src/utils/providers.json).
94116

95117

96-
## Changes with Instagram
118+
## Facebook and Instagram
97119

98-
Since October 24 2020, Facebook have deprecated their legacy urls and applied a new Facebook oEmbed endpoints. Please update your `oembed-parser` version to v1.4.2 to be able to extract Instagram links.
120+
Since October 24 2020, Facebook have deprecated their legacy urls and applied a new Facebook oEmbed endpoints.
121+
Please update your `oembed-parser` version to v1.4.2 or later to be able to extract oembed data from Instagram and Facebook.
99122

100-
Technically, now we have to use Facebook Graph API, with the access token from a valid and live Facebook app. By default, `oembed-parser` build Graph API endpoint using a pre-existing access token. Althrough it should work in almost cases. However, we recommend to add your own ones.
123+
Technically, now we have to use Facebook Graph API, with the access token from a valid and live Facebook app.
101124

102125

103-
```
126+
```bash
104127
export FACEBOOK_APP_ID=your_app_id
105128
export FACEBOOK_CLIENT_TOKEN=your_client_token
106-
107129
```
108130

109131
For more info, please refer:

eval.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// eval.js
2+
// to quickly test with a single url or file
3+
14
const { extract } = require('./src/main')
25

36
const run = async (url) => {

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface Endpoint {
1919
}
2020

2121
export interface Provider {
22-
"provider_name": string;
22+
"providerName": string;
2323
"provider_url": string;
2424
"endpoints": Endpoint[];
2525
}

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.5.2",
2+
"version": "2.0.0rc1",
33
"name": "oembed-parser",
44
"description": "Get oEmbed data from given URL.",
55
"homepage": "https://www.npmjs.com/package/oembed-parser",
@@ -9,6 +9,7 @@
99
},
1010
"author": "@ndaidong",
1111
"main": "./index.js",
12+
"types": "./index.d.ts",
1213
"engines": {
1314
"node": ">= 10.14.2"
1415
},
@@ -22,19 +23,18 @@
2223
"build": "tsc",
2324
"reset": "node reset"
2425
},
26+
"dependencies": {
27+
"got": "^11.8.3"
28+
},
2529
"devDependencies": {
26-
"jest": "^27.3.1",
27-
"typescript": "^4.4.4"
30+
"jest": "^27.4.3",
31+
"nock": "^13.2.1"
2832
},
2933
"keywords": [
3034
"oembed",
3135
"extractor",
3236
"parser",
3337
"util"
3438
],
35-
"license": "MIT",
36-
"types": "./index.d.ts",
37-
"dependencies": {
38-
"got": "^11.8.2"
39-
}
39+
"license": "MIT"
4040
}

src/config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// config
2+
3+
const fetchOptions = {
4+
headers: {
5+
'user-agent': 'Mozilla/5.0 (X11; Linux i686; rv:94.0) Gecko/20100101 Firefox/94.0',
6+
accept: 'application/json; charset=utf-8'
7+
},
8+
responseType: 'json',
9+
timeout: 30 * 1e3,
10+
redirect: 'follow'
11+
}
12+
13+
module.exports = {
14+
fetchOptions
15+
}

src/main.js

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,28 @@
1-
// main
1+
/**
2+
* oembed parser
3+
* @ndaidong
4+
**/
25

3-
const {
4-
isValidURL,
5-
findProvider,
6-
fetchEmbed,
7-
providersFromList
8-
} = require('./utils')
6+
const isValidURL = require('./utils/isValidURL')
7+
const fetchEmbed = require('./utils/fetchEmbed')
98

10-
const defaultProviderList = require('./utils/providers.json')
11-
let providers = providersFromList(defaultProviderList)
9+
const provider = require('./utils/provider')
1210

1311
const extract = async (url, params = {}) => {
1412
if (!isValidURL(url)) {
1513
throw new Error('Invalid input URL')
1614
}
17-
const p = findProvider(url, providers)
15+
const p = provider.find(url)
1816
if (!p) {
1917
throw new Error(`No provider found with given url "${url}"`)
2018
}
2119
const data = await fetchEmbed(url, p, params)
2220
return data
2321
}
2422

25-
const hasProvider = (url) => {
26-
return findProvider(url, providers) !== null
27-
}
28-
29-
const setProviderList = (list) => {
30-
providers = providersFromList(list)
31-
}
32-
3323
module.exports = {
3424
extract,
35-
hasProvider,
36-
setProviderList
25+
hasProvider: provider.has,
26+
findProvider: provider.find,
27+
setProviderList: provider.set
3728
}

src/main.test.js

Lines changed: 113 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// main
22
/* eslint-env jest */
33

4+
const nock = require('nock')
5+
46
const {
57
extract,
68
hasProvider,
9+
findProvider,
710
setProviderList
811
} = require('./main')
912

@@ -40,6 +43,14 @@ const InstagramKeys = [
4043
...required
4144
]
4245

46+
const parseUrl = (url) => {
47+
const re = new URL(url)
48+
return {
49+
baseUrl: `${re.protocol}//${re.host}`,
50+
path: re.pathname
51+
}
52+
}
53+
4354
const hasProperty = (obj, key) => {
4455
return Object.prototype.hasOwnProperty.call(obj, key)
4556
}
@@ -60,9 +71,9 @@ const hasInstagramKeys = (o) => {
6071
return InstagramKeys.every((k) => {
6172
return hasProperty(o, k)
6273
})
63-
};
74+
}
6475

65-
(() => {
76+
describe('test extract(bad url)', () => {
6677
const badSamples = [
6778
'',
6879
{ k: 9 },
@@ -76,59 +87,124 @@ const hasInstagramKeys = (o) => {
7687
'https://soundcloud^(*%%$%^$$%$$*&(&)())'
7788
]
7889

79-
const testBadOne = (url) => {
90+
badSamples.forEach((url) => {
8091
test(`testing extract bad url "${url}"`, async () => {
8192
try {
8293
await extract(url)
8394
} catch (err) {
8495
expect(err).toBeTruthy()
8596
}
8697
})
87-
}
88-
89-
return badSamples.map(testBadOne)
90-
})()
98+
})
99+
})
91100

92101
test('test extract YouTube link', async () => {
93-
try {
94-
const url = 'https://www.youtube.com/watch?v=ciS8aCrX-9s'
95-
const result = await extract(url)
96-
expect(hasRichKeys(result)).toBe(true)
97-
} catch (err) {
98-
expect(err).toBe(null)
99-
}
102+
const url = 'https://www.youtube.com/watch?v=ciS8aCrX-9s'
103+
const provider = findProvider(url)
104+
const { baseUrl, path } = parseUrl(provider.fetchEndpoint)
105+
const scope = nock(baseUrl, { encodedQueryParams: true })
106+
const params = new URLSearchParams({
107+
url,
108+
format: 'json'
109+
})
110+
scope.get(path)
111+
.query(params)
112+
.replyWithFile(200, './test-data/youtube_ciS8aCrX-9s.json', {
113+
'Content-Type': 'application/json'
114+
})
115+
const result = await extract(url)
116+
expect(hasRichKeys(result)).toBe(true)
117+
expect(result.provider_name).toEqual('YouTube')
118+
expect(result.type).toEqual('video')
100119
})
101120

102121
test('test extract Flickr link', async () => {
103-
try {
104-
const url = 'https://flic.kr/p/2iYctUr'
105-
const result = await extract(url)
106-
expect(hasPhotoKeys(result)).toBe(true)
107-
} catch (err) {
108-
expect(err).toBe(null)
109-
}
122+
const url = 'https://flic.kr/p/2iYctUr'
123+
const provider = findProvider(url)
124+
const { baseUrl, path } = parseUrl(provider.fetchEndpoint)
125+
const scope = nock(baseUrl, { encodedQueryParams: true })
126+
const params = new URLSearchParams({
127+
url,
128+
format: 'json'
129+
})
130+
scope.get(path)
131+
.query(params)
132+
.replyWithFile(200, './test-data/flickr_2iYctUr.json', {
133+
'Content-Type': 'application/json'
134+
})
135+
const result = await extract(url)
136+
expect(hasPhotoKeys(result)).toBe(true)
137+
expect(result.provider_name).toEqual('Flickr')
138+
expect(result.type).toEqual('photo')
139+
expect(result.width).toEqual(1024)
140+
expect(result.height).toEqual(768)
110141
})
111142

112143
test('test extract Flickr link with params', async () => {
113-
try {
114-
const url = 'https://flic.kr/p/2iYctUr'
115-
const result = await extract(url, { maxwidth: 640, maxheight: 480 })
116-
expect(hasPhotoKeys(result)).toBe(true)
117-
} catch (err) {
118-
expect(err).toBe(null)
119-
}
144+
const url = 'https://flic.kr/p/2iYctUr'
145+
const provider = findProvider(url)
146+
const { baseUrl, path } = parseUrl(provider.fetchEndpoint)
147+
const scope = nock(baseUrl, { encodedQueryParams: true })
148+
const params = new URLSearchParams({
149+
url,
150+
maxwidth: 640,
151+
maxheight: 480,
152+
format: 'json'
153+
})
154+
scope.get(path)
155+
.query(params)
156+
.replyWithFile(200, './test-data/flickr_2iYctUr_640x480.json', {
157+
'Content-Type': 'application/json'
158+
})
159+
const result = await extract(url, { maxwidth: 640, maxheight: 480 })
160+
expect(hasPhotoKeys(result)).toBe(true)
161+
expect(result.provider_name).toEqual('Flickr')
162+
expect(result.type).toEqual('photo')
163+
expect(result.width).toBeLessThanOrEqual(640)
164+
expect(result.height).toBeLessThanOrEqual(480)
120165
})
121166

122167
test('test extract Instagram link', async () => {
123-
try {
124-
const url = 'https://www.instagram.com/p/ic7kRDqOlt/'
125-
const result = await extract(url)
126-
expect(hasInstagramKeys(result)).toBe(true)
127-
} catch (err) {
128-
// could not wait for reviewing 'Oembed Read' feature
129-
// https://developers.facebook.com/docs/apps/review
130-
expect(err).toBeTruthy()
131-
}
168+
const url = 'https://www.instagram.com/p/ic7kRDqOlt/'
169+
const provider = findProvider(url)
170+
const { baseUrl, path } = parseUrl(provider.fetchEndpoint)
171+
const scope = nock(baseUrl, { encodedQueryParams: true })
172+
const params = new URLSearchParams({
173+
url,
174+
format: 'json',
175+
access_token: '845078789498971|8ff3ab4ddd45b8f018b35c4fb7edac62'
176+
})
177+
scope.get(path)
178+
.query(params)
179+
.replyWithFile(200, './test-data/instagram_ic7kRDqOlt.json', {
180+
'Content-Type': 'application/json'
181+
})
182+
const result = await extract(url)
183+
expect(hasInstagramKeys(result)).toBe(true)
184+
expect(result.provider_name).toEqual('Instagram')
185+
expect(result.type).toEqual('rich')
186+
})
187+
188+
test('test extract Facebook video', async () => {
189+
const url = 'https://www.facebook.com/facebook/videos/10153231379946729/'
190+
const provider = findProvider(url)
191+
const { baseUrl, path } = parseUrl(provider.fetchEndpoint)
192+
const scope = nock(baseUrl, { encodedQueryParams: true })
193+
const params = new URLSearchParams({
194+
url,
195+
format: 'json',
196+
access_token: '845078789498971|8ff3ab4ddd45b8f018b35c4fb7edac62'
197+
})
198+
scope.get(path)
199+
.query(params)
200+
.replyWithFile(200, './test-data/facebook.json', {
201+
'Content-Type': 'application/json'
202+
})
203+
const result = await extract(url)
204+
expect(hasRichKeys(result)).toBe(true)
205+
expect(result).toBeTruthy()
206+
expect(result.provider_name).toEqual('Facebook')
207+
expect(result.type).toEqual('video')
132208
})
133209

134210
test('test .hasProvider() method', () => {

0 commit comments

Comments
 (0)