oembed-parser
Advanced tools
Comparing version 1.5.2 to 2.0.0-rc1
@@ -0,1 +1,4 @@ | ||
// eval.js | ||
// to quickly test with a single url or file | ||
const { extract } = require('./src/main') | ||
@@ -2,0 +5,0 @@ |
@@ -22,3 +22,3 @@ // Type definitions for oembed-parser 1.3.5 | ||
export interface Provider { | ||
"provider_name": string; | ||
"providerName": string; | ||
"provider_url": string; | ||
@@ -25,0 +25,0 @@ "endpoints": Endpoint[]; |
{ | ||
"version": "1.5.2", | ||
"version": "2.0.0rc1", | ||
"name": "oembed-parser", | ||
@@ -12,2 +12,3 @@ "description": "Get oEmbed data from given URL.", | ||
"main": "./index.js", | ||
"types": "./index.d.ts", | ||
"engines": { | ||
@@ -26,5 +27,8 @@ "node": ">= 10.14.2" | ||
}, | ||
"dependencies": { | ||
"got": "^11.8.3" | ||
}, | ||
"devDependencies": { | ||
"jest": "^27.3.1", | ||
"typescript": "^4.4.4" | ||
"jest": "^27.4.3", | ||
"nock": "^13.2.1" | ||
}, | ||
@@ -37,7 +41,3 @@ "keywords": [ | ||
], | ||
"license": "MIT", | ||
"types": "./index.d.ts", | ||
"dependencies": { | ||
"got": "^11.8.2" | ||
} | ||
"license": "MIT" | ||
} |
@@ -17,3 +17,2 @@ # oembed-parser | ||
## Demo | ||
@@ -81,2 +80,25 @@ | ||
#### .findProvider(String URL) | ||
Return provider which is relevant to given URL. | ||
For example: | ||
```js | ||
import { | ||
findProvider | ||
} from 'oembed-parser' | ||
findProvider('https://www.facebook.com/video.php?v=999999999') | ||
// get something like below: | ||
// { | ||
// fetchEndpoint: 'https://graph.facebook.com/v10.0/oembed_video', | ||
// providerName: 'Facebook', | ||
// providerUrl: 'https://www.facebook.com/' | ||
// } | ||
``` | ||
#### .setProviderList(Array of provider definitions) | ||
@@ -98,13 +120,13 @@ | ||
## Changes with Instagram | ||
## Facebook and Instagram | ||
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. | ||
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 or later to be able to extract oembed data from Instagram and Facebook. | ||
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. | ||
Technically, now we have to use Facebook Graph API, with the access token from a valid and live Facebook app. | ||
``` | ||
```bash | ||
export FACEBOOK_APP_ID=your_app_id | ||
export FACEBOOK_CLIENT_TOKEN=your_client_token | ||
``` | ||
@@ -111,0 +133,0 @@ |
@@ -1,12 +0,10 @@ | ||
// main | ||
/** | ||
* oembed parser | ||
* @ndaidong | ||
**/ | ||
const { | ||
isValidURL, | ||
findProvider, | ||
fetchEmbed, | ||
providersFromList | ||
} = require('./utils') | ||
const isValidURL = require('./utils/isValidURL') | ||
const fetchEmbed = require('./utils/fetchEmbed') | ||
const defaultProviderList = require('./utils/providers.json') | ||
let providers = providersFromList(defaultProviderList) | ||
const provider = require('./utils/provider') | ||
@@ -17,3 +15,3 @@ const extract = async (url, params = {}) => { | ||
} | ||
const p = findProvider(url, providers) | ||
const p = provider.find(url) | ||
if (!p) { | ||
@@ -26,14 +24,7 @@ throw new Error(`No provider found with given url "${url}"`) | ||
const hasProvider = (url) => { | ||
return findProvider(url, providers) !== null | ||
} | ||
const setProviderList = (list) => { | ||
providers = providersFromList(list) | ||
} | ||
module.exports = { | ||
extract, | ||
hasProvider, | ||
setProviderList | ||
hasProvider: provider.has, | ||
findProvider: provider.find, | ||
setProviderList: provider.set | ||
} |
// main | ||
/* eslint-env jest */ | ||
const nock = require('nock') | ||
const { | ||
extract, | ||
hasProvider, | ||
findProvider, | ||
setProviderList | ||
@@ -43,2 +46,10 @@ } = require('./main') | ||
const parseUrl = (url) => { | ||
const re = new URL(url) | ||
return { | ||
baseUrl: `${re.protocol}//${re.host}`, | ||
path: re.pathname | ||
} | ||
} | ||
const hasProperty = (obj, key) => { | ||
@@ -64,5 +75,5 @@ return Object.prototype.hasOwnProperty.call(obj, key) | ||
}) | ||
}; | ||
} | ||
(() => { | ||
describe('test extract(bad url)', () => { | ||
const badSamples = [ | ||
@@ -81,3 +92,3 @@ '', | ||
const testBadOne = (url) => { | ||
badSamples.forEach((url) => { | ||
test(`testing extract bad url "${url}"`, async () => { | ||
@@ -90,49 +101,114 @@ try { | ||
}) | ||
} | ||
}) | ||
}) | ||
return badSamples.map(testBadOne) | ||
})() | ||
test('test extract YouTube link', async () => { | ||
try { | ||
const url = 'https://www.youtube.com/watch?v=ciS8aCrX-9s' | ||
const result = await extract(url) | ||
expect(hasRichKeys(result)).toBe(true) | ||
} catch (err) { | ||
expect(err).toBe(null) | ||
} | ||
const url = 'https://www.youtube.com/watch?v=ciS8aCrX-9s' | ||
const provider = findProvider(url) | ||
const { baseUrl, path } = parseUrl(provider.fetchEndpoint) | ||
const scope = nock(baseUrl, { encodedQueryParams: true }) | ||
const params = new URLSearchParams({ | ||
url, | ||
format: 'json' | ||
}) | ||
scope.get(path) | ||
.query(params) | ||
.replyWithFile(200, './test-data/youtube_ciS8aCrX-9s.json', { | ||
'Content-Type': 'application/json' | ||
}) | ||
const result = await extract(url) | ||
expect(hasRichKeys(result)).toBe(true) | ||
expect(result.provider_name).toEqual('YouTube') | ||
expect(result.type).toEqual('video') | ||
}) | ||
test('test extract Flickr link', async () => { | ||
try { | ||
const url = 'https://flic.kr/p/2iYctUr' | ||
const result = await extract(url) | ||
expect(hasPhotoKeys(result)).toBe(true) | ||
} catch (err) { | ||
expect(err).toBe(null) | ||
} | ||
const url = 'https://flic.kr/p/2iYctUr' | ||
const provider = findProvider(url) | ||
const { baseUrl, path } = parseUrl(provider.fetchEndpoint) | ||
const scope = nock(baseUrl, { encodedQueryParams: true }) | ||
const params = new URLSearchParams({ | ||
url, | ||
format: 'json' | ||
}) | ||
scope.get(path) | ||
.query(params) | ||
.replyWithFile(200, './test-data/flickr_2iYctUr.json', { | ||
'Content-Type': 'application/json' | ||
}) | ||
const result = await extract(url) | ||
expect(hasPhotoKeys(result)).toBe(true) | ||
expect(result.provider_name).toEqual('Flickr') | ||
expect(result.type).toEqual('photo') | ||
expect(result.width).toEqual(1024) | ||
expect(result.height).toEqual(768) | ||
}) | ||
test('test extract Flickr link with params', async () => { | ||
try { | ||
const url = 'https://flic.kr/p/2iYctUr' | ||
const result = await extract(url, { maxwidth: 640, maxheight: 480 }) | ||
expect(hasPhotoKeys(result)).toBe(true) | ||
} catch (err) { | ||
expect(err).toBe(null) | ||
} | ||
const url = 'https://flic.kr/p/2iYctUr' | ||
const provider = findProvider(url) | ||
const { baseUrl, path } = parseUrl(provider.fetchEndpoint) | ||
const scope = nock(baseUrl, { encodedQueryParams: true }) | ||
const params = new URLSearchParams({ | ||
url, | ||
maxwidth: 640, | ||
maxheight: 480, | ||
format: 'json' | ||
}) | ||
scope.get(path) | ||
.query(params) | ||
.replyWithFile(200, './test-data/flickr_2iYctUr_640x480.json', { | ||
'Content-Type': 'application/json' | ||
}) | ||
const result = await extract(url, { maxwidth: 640, maxheight: 480 }) | ||
expect(hasPhotoKeys(result)).toBe(true) | ||
expect(result.provider_name).toEqual('Flickr') | ||
expect(result.type).toEqual('photo') | ||
expect(result.width).toBeLessThanOrEqual(640) | ||
expect(result.height).toBeLessThanOrEqual(480) | ||
}) | ||
test('test extract Instagram link', async () => { | ||
try { | ||
const url = 'https://www.instagram.com/p/ic7kRDqOlt/' | ||
const result = await extract(url) | ||
expect(hasInstagramKeys(result)).toBe(true) | ||
} catch (err) { | ||
// could not wait for reviewing 'Oembed Read' feature | ||
// https://developers.facebook.com/docs/apps/review | ||
expect(err).toBeTruthy() | ||
} | ||
const url = 'https://www.instagram.com/p/ic7kRDqOlt/' | ||
const provider = findProvider(url) | ||
const { baseUrl, path } = parseUrl(provider.fetchEndpoint) | ||
const scope = nock(baseUrl, { encodedQueryParams: true }) | ||
const params = new URLSearchParams({ | ||
url, | ||
format: 'json', | ||
access_token: '845078789498971|8ff3ab4ddd45b8f018b35c4fb7edac62' | ||
}) | ||
scope.get(path) | ||
.query(params) | ||
.replyWithFile(200, './test-data/instagram_ic7kRDqOlt.json', { | ||
'Content-Type': 'application/json' | ||
}) | ||
const result = await extract(url) | ||
expect(hasInstagramKeys(result)).toBe(true) | ||
expect(result.provider_name).toEqual('Instagram') | ||
expect(result.type).toEqual('rich') | ||
}) | ||
test('test extract Facebook video', async () => { | ||
const url = 'https://www.facebook.com/facebook/videos/10153231379946729/' | ||
const provider = findProvider(url) | ||
const { baseUrl, path } = parseUrl(provider.fetchEndpoint) | ||
const scope = nock(baseUrl, { encodedQueryParams: true }) | ||
const params = new URLSearchParams({ | ||
url, | ||
format: 'json', | ||
access_token: '845078789498971|8ff3ab4ddd45b8f018b35c4fb7edac62' | ||
}) | ||
scope.get(path) | ||
.query(params) | ||
.replyWithFile(200, './test-data/facebook.json', { | ||
'Content-Type': 'application/json' | ||
}) | ||
const result = await extract(url) | ||
expect(hasRichKeys(result)).toBe(true) | ||
expect(result).toBeTruthy() | ||
expect(result.provider_name).toEqual('Facebook') | ||
expect(result.type).toEqual('video') | ||
}) | ||
test('test .hasProvider() method', () => { | ||
@@ -139,0 +215,0 @@ expect(hasProvider('https://www.youtube.com/watch?v=ciS8aCrX-9s')).toBe(true) |
// utils -> fetchEmbed | ||
const got = require('got') | ||
const retrieve = require('./retrieve') | ||
const { name, version } = require('../../package.json') | ||
const fetchOptions = { | ||
headers: { | ||
'user-agent': `${name}/${version}`, | ||
accept: 'application/json; charset=utf-8' | ||
}, | ||
timeout: 30 * 1e3, | ||
redirect: 'follow' | ||
const isFacebookGraphDependent = (url) => { | ||
return url.includes('facebook.com') || url.includes('instagram.com') | ||
} | ||
const isFacebookGraphDependent = (provider) => { | ||
return provider.provider_name === 'Facebook' || provider.provider_name === 'Instagram' | ||
} | ||
const getFacebookGraphToken = () => { | ||
const env = process.env || {} | ||
const appId = env.FACEBOOK_APP_ID || '845078789498971' | ||
const clientToken = env.FACEBOOK_CLIENT_TOKEN || '0d4b05bf3f7e201c636441912423a491' | ||
const clientToken = env.FACEBOOK_CLIENT_TOKEN || '8ff3ab4ddd45b8f018b35c4fb7edac62' | ||
@@ -33,7 +22,2 @@ return `access_token=${appId}|${clientToken}` | ||
const fetchEmbed = async (url, provider, params = {}) => { | ||
const { | ||
provider_name, // eslint-disable-line camelcase | ||
provider_url // eslint-disable-line camelcase | ||
} = provider | ||
const queries = [ | ||
@@ -56,3 +40,3 @@ 'format=json', | ||
if (isFacebookGraphDependent(provider)) { | ||
if (isFacebookGraphDependent(provider.providerUrl)) { | ||
queries.push(getFacebookGraphToken()) | ||
@@ -63,7 +47,4 @@ } | ||
const link = getRegularUrl(query, provider.url) | ||
const res = got(link, fetchOptions) | ||
const body = await res.json() | ||
body.provider_name = provider_name // eslint-disable-line camelcase | ||
body.provider_url = provider_url // eslint-disable-line camelcase | ||
const link = getRegularUrl(query, provider.fetchEndpoint) | ||
const body = retrieve(link) | ||
return body | ||
@@ -70,0 +51,0 @@ } |
@@ -5,6 +5,7 @@ // utils -> isValidUrl | ||
try { | ||
return new URL(url) !== null | ||
const ourl = new URL(url) | ||
return ourl !== null && ourl.protocol.startsWith('http') | ||
} catch (err) { | ||
return null | ||
return false | ||
} | ||
} |
16
sync.js
@@ -8,4 +8,8 @@ #!/usr/bin/env node | ||
const fetch = require('cross-fetch') | ||
const got = require('got') | ||
const { | ||
fetchOptions | ||
} = require('./src/config') | ||
const source = 'https://oembed.com/providers.json' | ||
@@ -17,3 +21,3 @@ const target = './src/utils/providers.json' | ||
const merge = (data) => { | ||
const merge = async () => { | ||
// backup previous version | ||
@@ -26,2 +30,5 @@ writeFileSync( | ||
const res = got(source, fetchOptions) | ||
const data = await res.json() | ||
// merging | ||
@@ -37,5 +44,2 @@ unlinkSync(target) | ||
fetch(source) | ||
.then((res) => res.json()) | ||
.then(merge) | ||
.catch(console.trace) | ||
merge() |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
233065
35
9171
151
1
Updatedgot@^11.8.3