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'); }; module.exports = { docName: 'oembed', read: { permissions: false, data: [ 'url' ], options: [], query({data}) { let {url} = data; function unknownProvider() { return Promise.reject(new common.errors.ValidationError({ message: common.i18n.t('errors.api.oembed.unknownProvider'), context: url })); } 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(); }); } } };