onebox 1.8.80 → 1.8.81
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.ruby-gemset +0 -0
- data/.travis.yml +0 -0
- data/CHANGELOG.md +26 -26
- data/Gemfile +0 -0
- data/Gemfile.lock +154 -152
- data/Guardfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +223 -223
- data/Rakefile +0 -0
- data/lib/onebox.rb +0 -0
- data/lib/onebox/engine.rb +188 -188
- data/lib/onebox/engine/amazon_onebox.rb +167 -167
- data/lib/onebox/engine/asciinema_onebox.rb +0 -0
- data/lib/onebox/engine/audio_onebox.rb +0 -0
- data/lib/onebox/engine/audioboom_onebox.rb +24 -24
- data/lib/onebox/engine/bandcamp_onebox.rb +32 -32
- data/lib/onebox/engine/cloudapp_onebox.rb +51 -51
- data/lib/onebox/engine/coub_onebox.rb +21 -21
- data/lib/onebox/engine/douban_onebox.rb +0 -0
- data/lib/onebox/engine/five_hundred_px_onebox.rb +17 -17
- data/lib/onebox/engine/flickr_onebox.rb +0 -0
- data/lib/onebox/engine/flickr_shortened_onebox.rb +0 -0
- data/lib/onebox/engine/gfycat_onebox.rb +0 -0
- data/lib/onebox/engine/giphy_onebox.rb +22 -22
- data/lib/onebox/engine/github_blob_onebox.rb +0 -0
- data/lib/onebox/engine/github_commit_onebox.rb +0 -0
- data/lib/onebox/engine/github_gist_onebox.rb +0 -0
- data/lib/onebox/engine/github_issue_onebox.rb +0 -0
- data/lib/onebox/engine/github_pullrequest_onebox.rb +0 -0
- data/lib/onebox/engine/gitlab_blob_onebox.rb +0 -0
- data/lib/onebox/engine/google_calendar_onebox.rb +0 -0
- data/lib/onebox/engine/google_docs_onebox.rb +0 -0
- data/lib/onebox/engine/google_maps_onebox.rb +0 -0
- data/lib/onebox/engine/google_photos_onebox.rb +57 -57
- data/lib/onebox/engine/google_play_app_onebox.rb +0 -0
- data/lib/onebox/engine/html.rb +0 -0
- data/lib/onebox/engine/image_onebox.rb +0 -0
- data/lib/onebox/engine/imgur_onebox.rb +65 -65
- data/lib/onebox/engine/instagram_onebox.rb +32 -32
- data/lib/onebox/engine/json.rb +0 -0
- data/lib/onebox/engine/kaltura_onebox.rb +31 -31
- data/lib/onebox/engine/mixcloud_onebox.rb +20 -20
- data/lib/onebox/engine/opengraph_image.rb +12 -12
- data/lib/onebox/engine/pastebin_onebox.rb +0 -0
- data/lib/onebox/engine/pdf_onebox.rb +0 -0
- data/lib/onebox/engine/pubmed_onebox.rb +0 -0
- data/lib/onebox/engine/replit_onebox.rb +24 -24
- data/lib/onebox/engine/sketchfab_onebox.rb +31 -31
- data/lib/onebox/engine/slides_onebox.rb +0 -0
- data/lib/onebox/engine/soundcloud_onebox.rb +31 -31
- data/lib/onebox/engine/stack_exchange_onebox.rb +0 -0
- data/lib/onebox/engine/standard_embed.rb +145 -145
- data/lib/onebox/engine/steam_store_onebox.rb +37 -37
- data/lib/onebox/engine/trello_onebox.rb +0 -0
- data/lib/onebox/engine/twitch_clips_onebox.rb +0 -0
- data/lib/onebox/engine/twitch_stream_onebox.rb +0 -0
- data/lib/onebox/engine/twitch_video_onebox.rb +0 -0
- data/lib/onebox/engine/twitter_status_onebox.rb +0 -0
- data/lib/onebox/engine/typeform_onebox.rb +41 -41
- data/lib/onebox/engine/video_onebox.rb +0 -0
- data/lib/onebox/engine/vimeo_onebox.rb +20 -20
- data/lib/onebox/engine/wechat_mp_onebox.rb +0 -0
- data/lib/onebox/engine/whitelisted_generic_onebox.rb +366 -366
- data/lib/onebox/engine/wikimedia_onebox.rb +0 -0
- data/lib/onebox/engine/wikipedia_onebox.rb +0 -0
- data/lib/onebox/engine/wistia_onebox.rb +27 -27
- data/lib/onebox/engine/xkcd_onebox.rb +0 -0
- data/lib/onebox/engine/youku_onebox.rb +0 -0
- data/lib/onebox/engine/youtube_onebox.rb +163 -163
- data/lib/onebox/file_type_finder.rb +0 -0
- data/lib/onebox/helpers.rb +188 -188
- data/lib/onebox/layout.rb +0 -0
- data/lib/onebox/layout_support.rb +0 -0
- data/lib/onebox/matcher.rb +0 -0
- data/lib/onebox/mixins/git_blob_onebox.rb +0 -0
- data/lib/onebox/mixins/twitch_onebox.rb +0 -0
- data/lib/onebox/oembed.rb +15 -12
- data/lib/onebox/open_graph.rb +90 -88
- data/lib/onebox/preview.rb +0 -0
- data/lib/onebox/sanitize_config.rb +0 -0
- data/lib/onebox/status_check.rb +0 -0
- data/lib/onebox/template_support.rb +0 -0
- data/lib/onebox/version.rb +5 -5
- data/lib/onebox/view.rb +0 -0
- data/lib/onebox/web.rb +0 -0
- data/lib/onebox/web_helpers.rb +0 -0
- data/onebox.gemspec +0 -0
- data/templates/_layout.mustache +0 -0
- data/templates/amazon.mustache +0 -0
- data/templates/douban.mustache +0 -0
- data/templates/githubblob.mustache +0 -0
- data/templates/githubcommit.mustache +0 -0
- data/templates/githubgist.mustache +0 -0
- data/templates/githubissue.mustache +0 -0
- data/templates/githubpullrequest.mustache +0 -0
- data/templates/gitlabblob.mustache +0 -0
- data/templates/googledocs.mustache +0 -0
- data/templates/googleplayapp.mustache +0 -0
- data/templates/instagram.mustache +0 -0
- data/templates/pastebin.mustache +0 -0
- data/templates/pdf.mustache +0 -0
- data/templates/pubmed.mustache +0 -0
- data/templates/stackexchange.mustache +0 -0
- data/templates/twitterstatus.mustache +0 -0
- data/templates/wechatmp.mustache +0 -0
- data/templates/whitelistedgeneric.mustache +0 -0
- data/templates/wikimedia.mustache +0 -0
- data/templates/wikipedia.mustache +0 -0
- data/templates/xkcd.mustache +0 -0
- metadata +4 -3
File without changes
|
@@ -1,20 +1,20 @@
|
|
1
|
-
module Onebox
|
2
|
-
module Engine
|
3
|
-
class VimeoOnebox
|
4
|
-
include Engine
|
5
|
-
include StandardEmbed
|
6
|
-
|
7
|
-
matches_regexp(/^https?:\/\/(www\.)?vimeo\.com\/\d+(\/[^\/]+)?$/)
|
8
|
-
always_https
|
9
|
-
|
10
|
-
def placeholder_html
|
11
|
-
oembed = get_oembed
|
12
|
-
"<img src='#{oembed.thumbnail_url}' width='#{oembed.thumbnail_width}' height='#{oembed.thumbnail_height}' #{oembed.title_attr}>"
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_html
|
16
|
-
get_oembed.html
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
1
|
+
module Onebox
|
2
|
+
module Engine
|
3
|
+
class VimeoOnebox
|
4
|
+
include Engine
|
5
|
+
include StandardEmbed
|
6
|
+
|
7
|
+
matches_regexp(/^https?:\/\/(www\.)?vimeo\.com\/\d+(\/[^\/]+)?$/)
|
8
|
+
always_https
|
9
|
+
|
10
|
+
def placeholder_html
|
11
|
+
oembed = get_oembed
|
12
|
+
"<img src='#{oembed.thumbnail_url}' width='#{oembed.thumbnail_width}' height='#{oembed.thumbnail_height}' #{oembed.title_attr}>"
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_html
|
16
|
+
get_oembed.html
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
File without changes
|
@@ -1,366 +1,366 @@
|
|
1
|
-
require 'htmlentities'
|
2
|
-
|
3
|
-
module Onebox
|
4
|
-
module Engine
|
5
|
-
class WhitelistedGenericOnebox
|
6
|
-
include Engine
|
7
|
-
include StandardEmbed
|
8
|
-
include LayoutSupport
|
9
|
-
|
10
|
-
def self.whitelist=(list)
|
11
|
-
@whitelist = list
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.whitelist
|
15
|
-
@whitelist ||= default_whitelist.dup
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.default_whitelist
|
19
|
-
%w(
|
20
|
-
23hq.com
|
21
|
-
500px.com
|
22
|
-
8tracks.com
|
23
|
-
abc.net.au
|
24
|
-
about.com
|
25
|
-
answers.com
|
26
|
-
arstechnica.com
|
27
|
-
ask.com
|
28
|
-
battle.net
|
29
|
-
bbc.co.uk
|
30
|
-
bbs.boingboing.net
|
31
|
-
bestbuy.ca
|
32
|
-
bestbuy.com
|
33
|
-
blip.tv
|
34
|
-
bloomberg.com
|
35
|
-
businessinsider.com
|
36
|
-
change.org
|
37
|
-
clikthrough.com
|
38
|
-
cnet.com
|
39
|
-
cnn.com
|
40
|
-
codepen.io
|
41
|
-
collegehumor.com
|
42
|
-
consider.it
|
43
|
-
coursera.org
|
44
|
-
cracked.com
|
45
|
-
dailymail.co.uk
|
46
|
-
dailymotion.com
|
47
|
-
deadline.com
|
48
|
-
dell.com
|
49
|
-
deviantart.com
|
50
|
-
digg.com
|
51
|
-
dotsub.com
|
52
|
-
ebay.ca
|
53
|
-
ebay.co.uk
|
54
|
-
ebay.com
|
55
|
-
ehow.com
|
56
|
-
espn.go.com
|
57
|
-
etsy.com
|
58
|
-
findery.com
|
59
|
-
folksy.com
|
60
|
-
forbes.com
|
61
|
-
foxnews.com
|
62
|
-
funnyordie.com
|
63
|
-
gifs.com
|
64
|
-
groupon.com
|
65
|
-
howtogeek.com
|
66
|
-
huffingtonpost.ca
|
67
|
-
huffingtonpost.com
|
68
|
-
hulu.com
|
69
|
-
ign.com
|
70
|
-
ikea.com
|
71
|
-
imdb.com
|
72
|
-
indiatimes.com
|
73
|
-
itunes.apple.com
|
74
|
-
khanacademy.org
|
75
|
-
kickstarter.com
|
76
|
-
kinomap.com
|
77
|
-
lessonplanet.com
|
78
|
-
liveleak.com
|
79
|
-
livestream.com
|
80
|
-
mashable.com
|
81
|
-
medium.com
|
82
|
-
meetup.com
|
83
|
-
mixcloud.com
|
84
|
-
mlb.com
|
85
|
-
myshopify.com
|
86
|
-
myspace.com
|
87
|
-
nba.com
|
88
|
-
npr.org
|
89
|
-
nytimes.com
|
90
|
-
photobucket.com
|
91
|
-
pinterest.com
|
92
|
-
reference.com
|
93
|
-
revision3.com
|
94
|
-
rottentomatoes.com
|
95
|
-
samsung.com
|
96
|
-
screenr.com
|
97
|
-
scribd.com
|
98
|
-
simplecast.com
|
99
|
-
slideshare.net
|
100
|
-
sourceforge.net
|
101
|
-
speakerdeck.com
|
102
|
-
spotify.com
|
103
|
-
squidoo.com
|
104
|
-
streamable.com
|
105
|
-
techcrunch.com
|
106
|
-
ted.com
|
107
|
-
thefreedictionary.com
|
108
|
-
theglobeandmail.com
|
109
|
-
thenextweb.com
|
110
|
-
theonion.com
|
111
|
-
thestar.com
|
112
|
-
thesun.co.uk
|
113
|
-
thinkgeek.com
|
114
|
-
tmz.com
|
115
|
-
torontosun.com
|
116
|
-
tumblr.com
|
117
|
-
twitpic.com
|
118
|
-
usatoday.com
|
119
|
-
viddler.com
|
120
|
-
videojug.com
|
121
|
-
vine.co
|
122
|
-
walmart.com
|
123
|
-
washingtonpost.com
|
124
|
-
wi.st
|
125
|
-
wikia.com
|
126
|
-
wikihow.com
|
127
|
-
wired.com
|
128
|
-
wistia.com
|
129
|
-
wonderhowto.com
|
130
|
-
wsj.com
|
131
|
-
zappos.com
|
132
|
-
zillow.com
|
133
|
-
)
|
134
|
-
end
|
135
|
-
|
136
|
-
# Often using the `html` attribute is not what we want, like for some blogs that
|
137
|
-
# include the entire page HTML. However for some providers like Flickr it allows us
|
138
|
-
# to return gifv and galleries.
|
139
|
-
def self.default_html_providers
|
140
|
-
['Flickr', 'Meetup']
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.html_providers
|
144
|
-
@html_providers ||= default_html_providers.dup
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.html_providers=(new_provs)
|
148
|
-
@html_providers = new_provs
|
149
|
-
end
|
150
|
-
|
151
|
-
# A re-written URL converts http:// -> https://
|
152
|
-
def self.rewrites
|
153
|
-
@rewrites ||= https_hosts.dup
|
154
|
-
end
|
155
|
-
|
156
|
-
def self.rewrites=(new_list)
|
157
|
-
@rewrites = new_list
|
158
|
-
end
|
159
|
-
|
160
|
-
def self.https_hosts
|
161
|
-
%w(slideshare.net dailymotion.com livestream.com imgur.com flickr.com)
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.host_matches(uri, list)
|
165
|
-
!!list.find { |h| %r((^|\.)#{Regexp.escape(h)}$).match(uri.host) }
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.probable_discourse(uri)
|
169
|
-
!!(uri.path =~ /\/t\/[^\/]+\/\d+(\/\d+)?(\?.*)?$/)
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.probable_wordpress(uri)
|
173
|
-
!!(uri.path =~ /\d{4}\/\d{2}\//)
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.twitter_label_whitelist
|
177
|
-
['brand', 'price', 'usd', 'cad', 'reading time', 'likes']
|
178
|
-
end
|
179
|
-
|
180
|
-
def self.===(other)
|
181
|
-
other.kind_of?(URI) ?
|
182
|
-
host_matches(other, whitelist) || probable_wordpress(other) || probable_discourse(other) :
|
183
|
-
super
|
184
|
-
end
|
185
|
-
|
186
|
-
def to_html
|
187
|
-
rewrite_https(generic_html)
|
188
|
-
end
|
189
|
-
|
190
|
-
def placeholder_html
|
191
|
-
return article_html if is_article?
|
192
|
-
return image_html if has_image? && (is_video? || is_image?)
|
193
|
-
return article_html if has_text? && is_embedded?
|
194
|
-
to_html
|
195
|
-
end
|
196
|
-
|
197
|
-
def data
|
198
|
-
@data ||= begin
|
199
|
-
html_entities = HTMLEntities.new
|
200
|
-
d = { link: link }.merge(raw)
|
201
|
-
|
202
|
-
if !Onebox::Helpers.blank?(d[:title])
|
203
|
-
d[:title] = html_entities.decode(Onebox::Helpers.truncate(d[:title], 80))
|
204
|
-
end
|
205
|
-
|
206
|
-
d[:description] ||= d[:summary]
|
207
|
-
if !Onebox::Helpers.blank?(d[:description])
|
208
|
-
d[:description] = html_entities.decode(Onebox::Helpers.truncate(d[:description], 250))
|
209
|
-
end
|
210
|
-
|
211
|
-
if !Onebox::Helpers.blank?(d[:site_name])
|
212
|
-
d[:domain] = html_entities.decode(Onebox::Helpers.truncate(d[:site_name], 80))
|
213
|
-
elsif !Onebox::Helpers.blank?(d[:domain])
|
214
|
-
d[:domain] = "http://#{d[:domain]}" unless d[:domain] =~ /^https?:\/\//
|
215
|
-
d[:domain] = URI(d[:domain]).host.to_s.sub(/^www\./, '') rescue nil
|
216
|
-
end
|
217
|
-
|
218
|
-
# prefer secure URLs
|
219
|
-
d[:image] = d[:image_secure_url] || d[:image_url] || d[:thumbnail_url] || d[:image]
|
220
|
-
d[:image] = Onebox::Helpers::get_absolute_image_url(d[:image], @url)
|
221
|
-
|
222
|
-
d[:video] = d[:video_secure_url] || d[:video_url] || d[:video]
|
223
|
-
|
224
|
-
d[:published_time] = d[:article_published_time] unless Onebox::Helpers.blank?(d[:article_published_time])
|
225
|
-
if !Onebox::Helpers.blank?(d[:published_time])
|
226
|
-
d[:article_published_time] = Time.parse(d[:published_time]).strftime("%-d %b %y")
|
227
|
-
d[:article_published_time_title] = Time.parse(d[:published_time]).strftime("%I:%M%p - %d %B %Y")
|
228
|
-
end
|
229
|
-
|
230
|
-
# Twitter labels
|
231
|
-
if !Onebox::Helpers.blank?(d[:label1]) && !Onebox::Helpers.blank?(d[:data1]) && !!WhitelistedGenericOnebox.twitter_label_whitelist.find { |l| d[:label1] =~ /#{l}/i }
|
232
|
-
d[:label_1] = Onebox::Helpers.truncate(d[:label1])
|
233
|
-
d[:data_1] = Onebox::Helpers.truncate(d[:data1])
|
234
|
-
end
|
235
|
-
if !Onebox::Helpers.blank?(d[:label2]) && !Onebox::Helpers.blank?(d[:data2]) && !!WhitelistedGenericOnebox.twitter_label_whitelist.find { |l| d[:label2] =~ /#{l}/i }
|
236
|
-
unless Onebox::Helpers.blank?(d[:label_1])
|
237
|
-
d[:label_2] = Onebox::Helpers.truncate(d[:label2])
|
238
|
-
d[:data_2] = Onebox::Helpers.truncate(d[:data2])
|
239
|
-
else
|
240
|
-
d[:label_1] = Onebox::Helpers.truncate(d[:label2])
|
241
|
-
d[:data_1] = Onebox::Helpers.truncate(d[:data2])
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
if Onebox::Helpers.blank?(d[:label_1]) && !Onebox::Helpers.blank?(d[:price_amount]) && !Onebox::Helpers.blank?(d[:price_currency])
|
246
|
-
d[:label_1] = "Price"
|
247
|
-
d[:data_1] = Onebox::Helpers.truncate("#{d[:price_currency].strip} #{d[:price_amount].strip}")
|
248
|
-
end
|
249
|
-
|
250
|
-
d
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
private
|
255
|
-
|
256
|
-
def rewrite_https(html)
|
257
|
-
return unless html
|
258
|
-
uri = URI(@url)
|
259
|
-
html.gsub!("http://", "https://") if WhitelistedGenericOnebox.host_matches(uri, WhitelistedGenericOnebox.rewrites)
|
260
|
-
html
|
261
|
-
end
|
262
|
-
|
263
|
-
def generic_html
|
264
|
-
return card_html if is_card?
|
265
|
-
return article_html if is_article?
|
266
|
-
return video_html if is_video?
|
267
|
-
return image_html if is_image?
|
268
|
-
return embedded_html if is_embedded?
|
269
|
-
return article_html if has_text?
|
270
|
-
end
|
271
|
-
|
272
|
-
def is_card?
|
273
|
-
data[:card] == 'player' && data[:player] =~ URI::regexp
|
274
|
-
end
|
275
|
-
|
276
|
-
def is_article?
|
277
|
-
(data[:type] =~ /article/ || data[:asset_type] =~ /article/) &&
|
278
|
-
has_text?
|
279
|
-
end
|
280
|
-
|
281
|
-
def has_text?
|
282
|
-
!Onebox::Helpers.blank?(data[:title]) &&
|
283
|
-
!Onebox::Helpers.blank?(data[:description])
|
284
|
-
end
|
285
|
-
|
286
|
-
def is_image?
|
287
|
-
data[:type] =~ /photo|image/ &&
|
288
|
-
data[:type] !~ /photostream/ &&
|
289
|
-
has_image?
|
290
|
-
end
|
291
|
-
|
292
|
-
def has_image?
|
293
|
-
!Onebox::Helpers.blank?(data[:image])
|
294
|
-
end
|
295
|
-
|
296
|
-
def is_video?
|
297
|
-
data[:type] =~ /^video[\/\.]/ && !Onebox::Helpers.blank?(data[:video])
|
298
|
-
end
|
299
|
-
|
300
|
-
def is_embedded?
|
301
|
-
data[:html] &&
|
302
|
-
data[:height] &&
|
303
|
-
(
|
304
|
-
data[:html]["iframe"] ||
|
305
|
-
WhitelistedGenericOnebox.html_providers.include?(data[:provider_name])
|
306
|
-
)
|
307
|
-
end
|
308
|
-
|
309
|
-
def card_html
|
310
|
-
escaped_url = ::Onebox::Helpers.normalize_url_for_output(data[:player])
|
311
|
-
|
312
|
-
<<~RAW
|
313
|
-
<iframe src="#{escaped_url}"
|
314
|
-
width="#{data[:player_width] || "100%"}"
|
315
|
-
height="#{data[:player_height]}"
|
316
|
-
scrolling="no"
|
317
|
-
frameborder="0">
|
318
|
-
</iframe>
|
319
|
-
RAW
|
320
|
-
end
|
321
|
-
|
322
|
-
def article_html
|
323
|
-
layout.to_html
|
324
|
-
end
|
325
|
-
|
326
|
-
def image_html
|
327
|
-
return if Onebox::Helpers.blank?(data[:image])
|
328
|
-
|
329
|
-
escaped_src = ::Onebox::Helpers.normalize_url_for_output(data[:image])
|
330
|
-
|
331
|
-
alt = data[:description] || data[:title]
|
332
|
-
width = data[:image_width] || data[:thumbnail_width] || data[:width]
|
333
|
-
height = data[:image_height] || data[:thumbnail_height] || data[:height]
|
334
|
-
|
335
|
-
"<img src='#{escaped_src}' alt='#{alt}' width='#{width}' height='#{height}' class='onebox'>"
|
336
|
-
end
|
337
|
-
|
338
|
-
def video_html
|
339
|
-
escaped_src = ::Onebox::Helpers.normalize_url_for_output(data[:video])
|
340
|
-
|
341
|
-
<<-HTML
|
342
|
-
<video title='#{data[:title]}'
|
343
|
-
width='#{data[:video_width]}'
|
344
|
-
height='#{data[:video_height]}'
|
345
|
-
style='max-width:100%'
|
346
|
-
controls=''>
|
347
|
-
<source src='#{escaped_src}'>
|
348
|
-
</video>
|
349
|
-
HTML
|
350
|
-
end
|
351
|
-
|
352
|
-
def embedded_html
|
353
|
-
fragment = Nokogiri::HTML::fragment(data[:html])
|
354
|
-
fragment.css("img").each { |img| img["class"] = "thumbnail" }
|
355
|
-
if iframe = fragment.at_css("iframe")
|
356
|
-
iframe.remove_attribute("style")
|
357
|
-
iframe["width"] = data[:width] || "100%"
|
358
|
-
iframe["height"] = data[:height]
|
359
|
-
iframe["scrolling"] = "no"
|
360
|
-
iframe["frameborder"] = "0"
|
361
|
-
end
|
362
|
-
fragment.to_html
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
end
|
1
|
+
require 'htmlentities'
|
2
|
+
|
3
|
+
module Onebox
|
4
|
+
module Engine
|
5
|
+
class WhitelistedGenericOnebox
|
6
|
+
include Engine
|
7
|
+
include StandardEmbed
|
8
|
+
include LayoutSupport
|
9
|
+
|
10
|
+
def self.whitelist=(list)
|
11
|
+
@whitelist = list
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.whitelist
|
15
|
+
@whitelist ||= default_whitelist.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.default_whitelist
|
19
|
+
%w(
|
20
|
+
23hq.com
|
21
|
+
500px.com
|
22
|
+
8tracks.com
|
23
|
+
abc.net.au
|
24
|
+
about.com
|
25
|
+
answers.com
|
26
|
+
arstechnica.com
|
27
|
+
ask.com
|
28
|
+
battle.net
|
29
|
+
bbc.co.uk
|
30
|
+
bbs.boingboing.net
|
31
|
+
bestbuy.ca
|
32
|
+
bestbuy.com
|
33
|
+
blip.tv
|
34
|
+
bloomberg.com
|
35
|
+
businessinsider.com
|
36
|
+
change.org
|
37
|
+
clikthrough.com
|
38
|
+
cnet.com
|
39
|
+
cnn.com
|
40
|
+
codepen.io
|
41
|
+
collegehumor.com
|
42
|
+
consider.it
|
43
|
+
coursera.org
|
44
|
+
cracked.com
|
45
|
+
dailymail.co.uk
|
46
|
+
dailymotion.com
|
47
|
+
deadline.com
|
48
|
+
dell.com
|
49
|
+
deviantart.com
|
50
|
+
digg.com
|
51
|
+
dotsub.com
|
52
|
+
ebay.ca
|
53
|
+
ebay.co.uk
|
54
|
+
ebay.com
|
55
|
+
ehow.com
|
56
|
+
espn.go.com
|
57
|
+
etsy.com
|
58
|
+
findery.com
|
59
|
+
folksy.com
|
60
|
+
forbes.com
|
61
|
+
foxnews.com
|
62
|
+
funnyordie.com
|
63
|
+
gifs.com
|
64
|
+
groupon.com
|
65
|
+
howtogeek.com
|
66
|
+
huffingtonpost.ca
|
67
|
+
huffingtonpost.com
|
68
|
+
hulu.com
|
69
|
+
ign.com
|
70
|
+
ikea.com
|
71
|
+
imdb.com
|
72
|
+
indiatimes.com
|
73
|
+
itunes.apple.com
|
74
|
+
khanacademy.org
|
75
|
+
kickstarter.com
|
76
|
+
kinomap.com
|
77
|
+
lessonplanet.com
|
78
|
+
liveleak.com
|
79
|
+
livestream.com
|
80
|
+
mashable.com
|
81
|
+
medium.com
|
82
|
+
meetup.com
|
83
|
+
mixcloud.com
|
84
|
+
mlb.com
|
85
|
+
myshopify.com
|
86
|
+
myspace.com
|
87
|
+
nba.com
|
88
|
+
npr.org
|
89
|
+
nytimes.com
|
90
|
+
photobucket.com
|
91
|
+
pinterest.com
|
92
|
+
reference.com
|
93
|
+
revision3.com
|
94
|
+
rottentomatoes.com
|
95
|
+
samsung.com
|
96
|
+
screenr.com
|
97
|
+
scribd.com
|
98
|
+
simplecast.com
|
99
|
+
slideshare.net
|
100
|
+
sourceforge.net
|
101
|
+
speakerdeck.com
|
102
|
+
spotify.com
|
103
|
+
squidoo.com
|
104
|
+
streamable.com
|
105
|
+
techcrunch.com
|
106
|
+
ted.com
|
107
|
+
thefreedictionary.com
|
108
|
+
theglobeandmail.com
|
109
|
+
thenextweb.com
|
110
|
+
theonion.com
|
111
|
+
thestar.com
|
112
|
+
thesun.co.uk
|
113
|
+
thinkgeek.com
|
114
|
+
tmz.com
|
115
|
+
torontosun.com
|
116
|
+
tumblr.com
|
117
|
+
twitpic.com
|
118
|
+
usatoday.com
|
119
|
+
viddler.com
|
120
|
+
videojug.com
|
121
|
+
vine.co
|
122
|
+
walmart.com
|
123
|
+
washingtonpost.com
|
124
|
+
wi.st
|
125
|
+
wikia.com
|
126
|
+
wikihow.com
|
127
|
+
wired.com
|
128
|
+
wistia.com
|
129
|
+
wonderhowto.com
|
130
|
+
wsj.com
|
131
|
+
zappos.com
|
132
|
+
zillow.com
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Often using the `html` attribute is not what we want, like for some blogs that
|
137
|
+
# include the entire page HTML. However for some providers like Flickr it allows us
|
138
|
+
# to return gifv and galleries.
|
139
|
+
def self.default_html_providers
|
140
|
+
['Flickr', 'Meetup']
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.html_providers
|
144
|
+
@html_providers ||= default_html_providers.dup
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.html_providers=(new_provs)
|
148
|
+
@html_providers = new_provs
|
149
|
+
end
|
150
|
+
|
151
|
+
# A re-written URL converts http:// -> https://
|
152
|
+
def self.rewrites
|
153
|
+
@rewrites ||= https_hosts.dup
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.rewrites=(new_list)
|
157
|
+
@rewrites = new_list
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.https_hosts
|
161
|
+
%w(slideshare.net dailymotion.com livestream.com imgur.com flickr.com)
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.host_matches(uri, list)
|
165
|
+
!!list.find { |h| %r((^|\.)#{Regexp.escape(h)}$).match(uri.host) }
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.probable_discourse(uri)
|
169
|
+
!!(uri.path =~ /\/t\/[^\/]+\/\d+(\/\d+)?(\?.*)?$/)
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.probable_wordpress(uri)
|
173
|
+
!!(uri.path =~ /\d{4}\/\d{2}\//)
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.twitter_label_whitelist
|
177
|
+
['brand', 'price', 'usd', 'cad', 'reading time', 'likes']
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.===(other)
|
181
|
+
other.kind_of?(URI) ?
|
182
|
+
host_matches(other, whitelist) || probable_wordpress(other) || probable_discourse(other) :
|
183
|
+
super
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_html
|
187
|
+
rewrite_https(generic_html)
|
188
|
+
end
|
189
|
+
|
190
|
+
def placeholder_html
|
191
|
+
return article_html if is_article?
|
192
|
+
return image_html if has_image? && (is_video? || is_image?)
|
193
|
+
return article_html if has_text? && is_embedded?
|
194
|
+
to_html
|
195
|
+
end
|
196
|
+
|
197
|
+
def data
|
198
|
+
@data ||= begin
|
199
|
+
html_entities = HTMLEntities.new
|
200
|
+
d = { link: link }.merge(raw)
|
201
|
+
|
202
|
+
if !Onebox::Helpers.blank?(d[:title])
|
203
|
+
d[:title] = html_entities.decode(Onebox::Helpers.truncate(d[:title], 80))
|
204
|
+
end
|
205
|
+
|
206
|
+
d[:description] ||= d[:summary]
|
207
|
+
if !Onebox::Helpers.blank?(d[:description])
|
208
|
+
d[:description] = html_entities.decode(Onebox::Helpers.truncate(d[:description], 250))
|
209
|
+
end
|
210
|
+
|
211
|
+
if !Onebox::Helpers.blank?(d[:site_name])
|
212
|
+
d[:domain] = html_entities.decode(Onebox::Helpers.truncate(d[:site_name], 80))
|
213
|
+
elsif !Onebox::Helpers.blank?(d[:domain])
|
214
|
+
d[:domain] = "http://#{d[:domain]}" unless d[:domain] =~ /^https?:\/\//
|
215
|
+
d[:domain] = URI(d[:domain]).host.to_s.sub(/^www\./, '') rescue nil
|
216
|
+
end
|
217
|
+
|
218
|
+
# prefer secure URLs
|
219
|
+
d[:image] = d[:image_secure_url] || d[:image_url] || d[:thumbnail_url] || d[:image]
|
220
|
+
d[:image] = Onebox::Helpers::get_absolute_image_url(d[:image], @url)
|
221
|
+
|
222
|
+
d[:video] = d[:video_secure_url] || d[:video_url] || d[:video]
|
223
|
+
|
224
|
+
d[:published_time] = d[:article_published_time] unless Onebox::Helpers.blank?(d[:article_published_time])
|
225
|
+
if !Onebox::Helpers.blank?(d[:published_time])
|
226
|
+
d[:article_published_time] = Time.parse(d[:published_time]).strftime("%-d %b %y")
|
227
|
+
d[:article_published_time_title] = Time.parse(d[:published_time]).strftime("%I:%M%p - %d %B %Y")
|
228
|
+
end
|
229
|
+
|
230
|
+
# Twitter labels
|
231
|
+
if !Onebox::Helpers.blank?(d[:label1]) && !Onebox::Helpers.blank?(d[:data1]) && !!WhitelistedGenericOnebox.twitter_label_whitelist.find { |l| d[:label1] =~ /#{l}/i }
|
232
|
+
d[:label_1] = Onebox::Helpers.truncate(d[:label1])
|
233
|
+
d[:data_1] = Onebox::Helpers.truncate(d[:data1])
|
234
|
+
end
|
235
|
+
if !Onebox::Helpers.blank?(d[:label2]) && !Onebox::Helpers.blank?(d[:data2]) && !!WhitelistedGenericOnebox.twitter_label_whitelist.find { |l| d[:label2] =~ /#{l}/i }
|
236
|
+
unless Onebox::Helpers.blank?(d[:label_1])
|
237
|
+
d[:label_2] = Onebox::Helpers.truncate(d[:label2])
|
238
|
+
d[:data_2] = Onebox::Helpers.truncate(d[:data2])
|
239
|
+
else
|
240
|
+
d[:label_1] = Onebox::Helpers.truncate(d[:label2])
|
241
|
+
d[:data_1] = Onebox::Helpers.truncate(d[:data2])
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
if Onebox::Helpers.blank?(d[:label_1]) && !Onebox::Helpers.blank?(d[:price_amount]) && !Onebox::Helpers.blank?(d[:price_currency])
|
246
|
+
d[:label_1] = "Price"
|
247
|
+
d[:data_1] = Onebox::Helpers.truncate("#{d[:price_currency].strip} #{d[:price_amount].strip}")
|
248
|
+
end
|
249
|
+
|
250
|
+
d
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def rewrite_https(html)
|
257
|
+
return unless html
|
258
|
+
uri = URI(@url)
|
259
|
+
html.gsub!("http://", "https://") if WhitelistedGenericOnebox.host_matches(uri, WhitelistedGenericOnebox.rewrites)
|
260
|
+
html
|
261
|
+
end
|
262
|
+
|
263
|
+
def generic_html
|
264
|
+
return card_html if is_card?
|
265
|
+
return article_html if is_article?
|
266
|
+
return video_html if is_video?
|
267
|
+
return image_html if is_image?
|
268
|
+
return embedded_html if is_embedded?
|
269
|
+
return article_html if has_text?
|
270
|
+
end
|
271
|
+
|
272
|
+
def is_card?
|
273
|
+
data[:card] == 'player' && data[:player] =~ URI::regexp
|
274
|
+
end
|
275
|
+
|
276
|
+
def is_article?
|
277
|
+
(data[:type] =~ /article/ || data[:asset_type] =~ /article/) &&
|
278
|
+
has_text?
|
279
|
+
end
|
280
|
+
|
281
|
+
def has_text?
|
282
|
+
!Onebox::Helpers.blank?(data[:title]) &&
|
283
|
+
!Onebox::Helpers.blank?(data[:description])
|
284
|
+
end
|
285
|
+
|
286
|
+
def is_image?
|
287
|
+
data[:type] =~ /photo|image/ &&
|
288
|
+
data[:type] !~ /photostream/ &&
|
289
|
+
has_image?
|
290
|
+
end
|
291
|
+
|
292
|
+
def has_image?
|
293
|
+
!Onebox::Helpers.blank?(data[:image])
|
294
|
+
end
|
295
|
+
|
296
|
+
def is_video?
|
297
|
+
data[:type] =~ /^video[\/\.]/ && !Onebox::Helpers.blank?(data[:video])
|
298
|
+
end
|
299
|
+
|
300
|
+
def is_embedded?
|
301
|
+
data[:html] &&
|
302
|
+
data[:height] &&
|
303
|
+
(
|
304
|
+
data[:html]["iframe"] ||
|
305
|
+
WhitelistedGenericOnebox.html_providers.include?(data[:provider_name])
|
306
|
+
)
|
307
|
+
end
|
308
|
+
|
309
|
+
def card_html
|
310
|
+
escaped_url = ::Onebox::Helpers.normalize_url_for_output(data[:player])
|
311
|
+
|
312
|
+
<<~RAW
|
313
|
+
<iframe src="#{escaped_url}"
|
314
|
+
width="#{data[:player_width] || "100%"}"
|
315
|
+
height="#{data[:player_height]}"
|
316
|
+
scrolling="no"
|
317
|
+
frameborder="0">
|
318
|
+
</iframe>
|
319
|
+
RAW
|
320
|
+
end
|
321
|
+
|
322
|
+
def article_html
|
323
|
+
layout.to_html
|
324
|
+
end
|
325
|
+
|
326
|
+
def image_html
|
327
|
+
return if Onebox::Helpers.blank?(data[:image])
|
328
|
+
|
329
|
+
escaped_src = ::Onebox::Helpers.normalize_url_for_output(data[:image])
|
330
|
+
|
331
|
+
alt = data[:description] || data[:title]
|
332
|
+
width = data[:image_width] || data[:thumbnail_width] || data[:width]
|
333
|
+
height = data[:image_height] || data[:thumbnail_height] || data[:height]
|
334
|
+
|
335
|
+
"<img src='#{escaped_src}' alt='#{alt}' width='#{width}' height='#{height}' class='onebox'>"
|
336
|
+
end
|
337
|
+
|
338
|
+
def video_html
|
339
|
+
escaped_src = ::Onebox::Helpers.normalize_url_for_output(data[:video])
|
340
|
+
|
341
|
+
<<-HTML
|
342
|
+
<video title='#{data[:title]}'
|
343
|
+
width='#{data[:video_width]}'
|
344
|
+
height='#{data[:video_height]}'
|
345
|
+
style='max-width:100%'
|
346
|
+
controls=''>
|
347
|
+
<source src='#{escaped_src}'>
|
348
|
+
</video>
|
349
|
+
HTML
|
350
|
+
end
|
351
|
+
|
352
|
+
def embedded_html
|
353
|
+
fragment = Nokogiri::HTML::fragment(data[:html])
|
354
|
+
fragment.css("img").each { |img| img["class"] = "thumbnail" }
|
355
|
+
if iframe = fragment.at_css("iframe")
|
356
|
+
iframe.remove_attribute("style")
|
357
|
+
iframe["width"] = data[:width] || "100%"
|
358
|
+
iframe["height"] = data[:height]
|
359
|
+
iframe["scrolling"] = "no"
|
360
|
+
iframe["frameborder"] = "0"
|
361
|
+
end
|
362
|
+
fragment.to_html
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|