Ghost/core/server/api/v0.1/oembed.js

96 lines
2.7 KiB
JavaScript
Raw Normal View History

const common = require('../../lib/common');
const {extract, hasProvider} = require('oembed-parser');
const Promise = require('bluebird');
const request = require('../../lib/request');
const cheerio = require('cheerio');
const findUrlWithProvider = (url) => {
let provider;
// build up a list of URL variations to test against because the oembed
// providers list is not always up to date with scheme or www vs non-www
let baseUrl = url.replace(/^\/\/|^https?:\/\/(?:www\.)?/, '');
let testUrls = [
`http://${baseUrl}`,
`https://${baseUrl}`,
`http://www.${baseUrl}`,
`https://www.${baseUrl}`
];
for (let testUrl of testUrls) {
provider = hasProvider(testUrl);
if (provider) {
url = testUrl;
break;
}
}
return {url, provider};
};
const getOembedUrlFromHTML = (html) => {
return cheerio('link[type="application/json+oembed"]', html).attr('href');
};
const oembed = {
read(options) {
let {url} = options;
if (!url || !url.trim()) {
return Promise.reject(new common.errors.BadRequestError({
message: common.i18n.t('errors.api.oembed.noUrlProvided')
}));
}
function unknownProvider() {
return Promise.reject(new common.errors.ValidationError({
message: common.i18n.t('errors.api.oembed.unknownProvider')
}));
}
function knownProvider(url) {
return extract(url).catch((err) => {
return Promise.reject(new common.errors.InternalServerError({
message: err.message
}));
});
}
let provider;
({url, provider} = findUrlWithProvider(url));
if (provider) {
return knownProvider(url);
}
// see if the URL is a redirect to cater for shortened urls
return request(url, {
method: 'GET',
timeout: 2 * 1000,
followRedirect: true
}).then((response) => {
if (response.url !== url) {
({url, provider} = findUrlWithProvider(response.url));
return provider ? knownProvider(url) : unknownProvider();
}
const oembedUrl = getOembedUrlFromHTML(response.body);
if (!oembedUrl) {
return unknownProvider();
}
return request(oembedUrl, {
method: 'GET',
json: true
}).then((response) => {
return response.body;
});
}).catch(() => {
return unknownProvider();
});
}
};
module.exports = oembed;