forked from apostrophecms/oembetter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
oembed.js
136 lines (122 loc) · 3.77 KB
/
oembed.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
var request = require('request');
var urls = require('url');
var xml2js = require('xml2js');
var async = require('async');
var cheerio = require('cheerio');
var forceXml = false;
module.exports = oembed;
// The _canonical option is used internally to prevent
// infinite recursion when retrying with a canonical URL.
// Don't worry about it in your code.
function oembed(url, options, endpoint, mainCallback, _canonical) {
var oUrl;
var result;
return async.series({
discover: function(callback) {
// if we're being told the end point, use it
if (endpoint)
{
if (!options) {
options = {};
}
oUrl = endpoint;
options.url = url;
return callback(null);
}
// otherwise discover it
return request(url, {
headers: {
'User-Agent': 'oembetter'
}
}, function(err, response, body) {
if (err) {
return callback(err);
}
var $ = cheerio.load(body);
// <link rel="alternate" type="application/json+oembed" href="http://www.youtube.com/oembed?format=json&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dzsl_auoGuy4" title="An Engineer's Guide to Cats 2.0 - The Sequel">
// Allow for all the dumb stuff we've seen.
// (Only application/json+oembed and
// text/xmloembed are in the standard.)
var ideas = [
'link[type="application/json+oembed"]',
'link[type="text/json+oembed"]',
'link[type="application/xml+oembed"]',
'link[type="text/xml+oembed"]'
];
var i;
for (i = 0; (i < ideas.length); i++) {
oUrl = $(ideas[i]).attr('href');
if (oUrl) {
break;
}
}
if (!oUrl) {
if (!_canonical) {
// No oembed information here, however if
// there is a canonical URL retry with that instead
var canonical = $('link[rel="canonical"]').attr('href');
if (canonical && (canonical !== url)) {
return oembed(canonical, options, endpoint, mainCallback, true);
}
}
return callback(new Error('no oembed discovery information available'));
}
return callback(null);
});
},
fetch: function(callback) {
// Just for testing - a lot of modern services
// default to JSON and we want to make sure we
// still test XML too
if (forceXml) {
oUrl = oUrl.replace('json', 'xml');
}
if (options) {
var parsed = urls.parse(oUrl);
var keys = Object.keys(options);
if (!parsed.query) {
parsed.query = {};
}
keys.forEach(function(key) {
parsed.query[key] = options[key];
});
oUrl = urls.format(parsed);
}
return request(oUrl, {
headers: {
'User-Agent': 'oembetter'
}
}, function(err, response, body) {
if (err) {
return callback(err);
}
if (body[0] === '<') {
return xml2js.parseString(body, { explicitArray: false }, function(err, _result) {
if (err) {
return callback(err);
}
if (!_result.oembed) {
return callback(new Error('XML response lacks oembed element'));
}
_result = _result.oembed;
_result._xml = true;
result = _result;
return callback(null);
});
} else {
result = JSON.parse(body);
return callback(null);
}
});
}
}, function(err) {
if (err) {
return mainCallback(err);
}
return mainCallback(null, result);
});
};
// For testing
module.exports.setForceXml = function(flag) {
forceXml = flag;
};