onebox 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +7 -452
  4. data/Gemfile +1 -1
  5. data/README.md +23 -45
  6. data/lib/onebox.rb +21 -13
  7. data/lib/onebox/engine.rb +53 -43
  8. data/lib/onebox/engine/amazon_onebox.rb +34 -7
  9. data/lib/onebox/engine/classic_google_maps_onebox.rb +37 -0
  10. data/lib/onebox/engine/github_blob_onebox.rb +27 -7
  11. data/lib/onebox/engine/github_commit_onebox.rb +8 -15
  12. data/lib/onebox/engine/github_gist_onebox.rb +10 -10
  13. data/lib/onebox/engine/github_pullrequest_onebox.rb +7 -15
  14. data/lib/onebox/engine/google_play_app_onebox.rb +30 -0
  15. data/lib/onebox/engine/html.rb +10 -1
  16. data/lib/onebox/engine/image_onebox.rb +13 -0
  17. data/lib/onebox/engine/stack_exchange_onebox.rb +25 -11
  18. data/lib/onebox/engine/standard_embed.rb +48 -0
  19. data/lib/onebox/engine/twitter_status_onebox.rb +100 -0
  20. data/lib/onebox/engine/whitelisted_generic_onebox.rb +223 -0
  21. data/lib/onebox/engine/wikipedia_onebox.rb +27 -5
  22. data/lib/onebox/engine/youtube_onebox.rb +22 -0
  23. data/lib/onebox/helpers.rb +24 -0
  24. data/lib/onebox/layout.rb +67 -0
  25. data/lib/onebox/layout_support.rb +16 -0
  26. data/lib/onebox/matcher.rb +6 -1
  27. data/lib/onebox/preview.rb +19 -6
  28. data/lib/onebox/version.rb +1 -1
  29. data/lib/onebox/view.rb +7 -12
  30. data/onebox.gemspec +7 -5
  31. data/spec/fixtures/amazon.response +1336 -2971
  32. data/spec/fixtures/githubblob.response +49 -921
  33. data/spec/fixtures/{android.response → googleplayapp.response} +1 -1
  34. data/spec/fixtures/stackexchange.response +1 -1889
  35. data/spec/fixtures/twitterstatus.response +3006 -0
  36. data/spec/fixtures/youtube-json.response +1 -0
  37. data/spec/fixtures/youtube.response +1625 -0
  38. data/spec/lib/onebox/engine/amazon_onebox_spec.rb +5 -20
  39. data/spec/lib/onebox/engine/classic_google_maps_onebox_spec.rb +28 -0
  40. data/spec/lib/onebox/engine/github_blob_onebox_spec.rb +6 -15
  41. data/spec/lib/onebox/engine/github_commit_onebox_spec.rb +14 -22
  42. data/spec/lib/onebox/engine/github_gist_onebox_spec.rb +6 -14
  43. data/spec/lib/onebox/engine/github_pullrequest_onebox_spec.rb +14 -26
  44. data/spec/lib/onebox/engine/google_play_app_onebox_spec.rb +28 -0
  45. data/spec/lib/onebox/engine/html_spec.rb +4 -6
  46. data/spec/lib/onebox/engine/json_spec.rb +4 -6
  47. data/spec/lib/onebox/engine/stack_exchange_onebox_spec.rb +4 -17
  48. data/spec/lib/onebox/engine/twitter_status_onebox_spec.rb +103 -0
  49. data/spec/lib/onebox/engine/whitelisted_generic_onebox_spec.rb +51 -0
  50. data/spec/lib/onebox/engine/wikipedia_onebox_spec.rb +4 -17
  51. data/spec/lib/onebox/engine/youtube_onebox_spec.rb +17 -0
  52. data/spec/lib/onebox/engine_spec.rb +35 -32
  53. data/spec/lib/onebox/layout_spec.rb +77 -0
  54. data/spec/lib/onebox/matcher_spec.rb +0 -15
  55. data/spec/lib/onebox/preview_spec.rb +39 -9
  56. data/spec/lib/onebox_spec.rb +15 -11
  57. data/spec/spec_helper.rb +60 -4
  58. data/spec/support/html_spec_helper.rb +2 -1
  59. data/templates/_layout.mustache +11 -4
  60. data/templates/amazon.mustache +4 -3
  61. data/templates/githubblob.mustache +7 -5
  62. data/templates/githubcommit.mustache +20 -11
  63. data/templates/githubpullrequest.mustache +19 -12
  64. data/templates/googleplayapp.mustache +4 -0
  65. data/templates/stackexchange.mustache +19 -3
  66. data/templates/twitterstatus.mustache +12 -0
  67. data/templates/whitelistedgeneric.mustache +5 -0
  68. data/templates/wikipedia.mustache +4 -3
  69. metadata +57 -166
  70. data/lib/onebox/engine/bliptv_onebox.rb +0 -28
  71. data/lib/onebox/engine/clikthrough_onebox.rb +0 -25
  72. data/lib/onebox/engine/college_humor_onebox.rb +0 -27
  73. data/lib/onebox/engine/dailymotion_onebox.rb +0 -28
  74. data/lib/onebox/engine/dotsub_onebox.rb +0 -27
  75. data/lib/onebox/engine/example_onebox.rb +0 -24
  76. data/lib/onebox/engine/flickr_onebox.rb +0 -26
  77. data/lib/onebox/engine/funny_or_die_onebox.rb +0 -28
  78. data/lib/onebox/engine/hulu_onebox.rb +0 -29
  79. data/lib/onebox/engine/imgur_image_onebox.rb +0 -26
  80. data/lib/onebox/engine/itunes_onebox.rb +0 -28
  81. data/lib/onebox/engine/kinomap_onebox.rb +0 -27
  82. data/lib/onebox/engine/nfb_onebox.rb +0 -28
  83. data/lib/onebox/engine/open_graph.rb +0 -11
  84. data/lib/onebox/engine/qik_onebox.rb +0 -25
  85. data/lib/onebox/engine/revision3_onebox.rb +0 -27
  86. data/lib/onebox/engine/slideshare_onebox.rb +0 -27
  87. data/lib/onebox/engine/sound_cloud_onebox.rb +0 -27
  88. data/lib/onebox/engine/spotify_onebox.rb +0 -27
  89. data/lib/onebox/engine/ted_onebox.rb +0 -28
  90. data/lib/onebox/engine/twitter_onebox.rb +0 -31
  91. data/lib/onebox/engine/viddler_onebox.rb +0 -28
  92. data/lib/onebox/engine/vimeo_onebox.rb +0 -27
  93. data/lib/onebox/engine/yfrog_onebox.rb +0 -28
  94. data/spec/fixtures/bliptv.response +0 -724
  95. data/spec/fixtures/clikthrough.response +0 -1472
  96. data/spec/fixtures/collegehumor.response +0 -1272
  97. data/spec/fixtures/dailymotion.response +0 -575
  98. data/spec/fixtures/dotsub.response +0 -1257
  99. data/spec/fixtures/example.response +0 -50
  100. data/spec/fixtures/flickr.response +0 -1292
  101. data/spec/fixtures/funnyordie.response +0 -2010
  102. data/spec/fixtures/githubgist.response +0 -468
  103. data/spec/fixtures/hulu.response +0 -339
  104. data/spec/fixtures/imguralbum.response +0 -941
  105. data/spec/fixtures/imgurimage.response +0 -872
  106. data/spec/fixtures/itunes.response +0 -402
  107. data/spec/fixtures/kinomap.response +0 -299
  108. data/spec/fixtures/nfb.response +0 -810
  109. data/spec/fixtures/opengraph.response +0 -27
  110. data/spec/fixtures/qik.response +0 -371
  111. data/spec/fixtures/revision3.response +0 -985
  112. data/spec/fixtures/rottentomatoesfresh.response +0 -3275
  113. data/spec/fixtures/rottentomatoesincomplete.response +0 -2313
  114. data/spec/fixtures/rottentomatoesrotten.response +0 -3549
  115. data/spec/fixtures/slideshare.response +0 -1745
  116. data/spec/fixtures/soundcloud.response +0 -1409
  117. data/spec/fixtures/spotify.response +0 -250
  118. data/spec/fixtures/ted.response +0 -1341
  119. data/spec/fixtures/twitter.response +0 -1712
  120. data/spec/fixtures/viddler.response +0 -442
  121. data/spec/fixtures/vimeo.response +0 -571
  122. data/spec/fixtures/yfrog.response +0 -464
  123. data/spec/lib/onebox/engine/bliptv_onebox_spec.rb +0 -37
  124. data/spec/lib/onebox/engine/clikthrough_onebox_spec.rb +0 -29
  125. data/spec/lib/onebox/engine/college_humor_onebox_spec.rb +0 -37
  126. data/spec/lib/onebox/engine/dailymotion_onebox_spec.rb +0 -39
  127. data/spec/lib/onebox/engine/dotsub_onebox_spec.rb +0 -39
  128. data/spec/lib/onebox/engine/example_onebox_spec.rb +0 -21
  129. data/spec/lib/onebox/engine/flickr_onebox_spec.rb +0 -33
  130. data/spec/lib/onebox/engine/funny_or_die_onebox_spec.rb +0 -37
  131. data/spec/lib/onebox/engine/hulu_onebox_spec.rb +0 -37
  132. data/spec/lib/onebox/engine/imgur_image_onebox_spec.rb +0 -29
  133. data/spec/lib/onebox/engine/itunes_onebox_spec.rb +0 -29
  134. data/spec/lib/onebox/engine/kinomap_onebox_spec.rb +0 -37
  135. data/spec/lib/onebox/engine/nfb_onebox_spec.rb +0 -38
  136. data/spec/lib/onebox/engine/open_graph_spec.rb +0 -27
  137. data/spec/lib/onebox/engine/qik_onebox_spec.rb +0 -38
  138. data/spec/lib/onebox/engine/revision3_onebox_spec.rb +0 -39
  139. data/spec/lib/onebox/engine/slideshare_onebox_spec.rb +0 -33
  140. data/spec/lib/onebox/engine/sound_cloud_onebox_spec.rb +0 -39
  141. data/spec/lib/onebox/engine/spotify_onebox_spec.rb +0 -36
  142. data/spec/lib/onebox/engine/ted_onebox_spec.rb +0 -33
  143. data/spec/lib/onebox/engine/twitter_onebox_spec.rb +0 -47
  144. data/spec/lib/onebox/engine/viddler_onebox_spec.rb +0 -39
  145. data/spec/lib/onebox/engine/vimeo_onebox_spec.rb +0 -37
  146. data/spec/lib/onebox/engine/yfrog_onebox_spec.rb +0 -33
  147. data/spec/lib/onebox/view_spec.rb +0 -16
  148. data/templates/bliptv.mustache +0 -5
  149. data/templates/clikthrough.mustache +0 -4
  150. data/templates/collegehumor.mustache +0 -5
  151. data/templates/dailymotion.mustache +0 -5
  152. data/templates/dotsub.mustache +0 -5
  153. data/templates/example.mustache +0 -2
  154. data/templates/flickr.mustache +0 -4
  155. data/templates/funnyordie.mustache +0 -6
  156. data/templates/githubgist.mustache +0 -3
  157. data/templates/hulu.mustache +0 -6
  158. data/templates/imgurimage.mustache +0 -3
  159. data/templates/itunes.mustache +0 -4
  160. data/templates/kinomap.mustache +0 -5
  161. data/templates/nfb.mustache +0 -5
  162. data/templates/qik.mustache +0 -4
  163. data/templates/revision3.mustache +0 -5
  164. data/templates/slideshare.mustache +0 -4
  165. data/templates/soundcloud.mustache +0 -5
  166. data/templates/spotify.mustache +0 -4
  167. data/templates/ted.mustache +0 -5
  168. data/templates/twitter.mustache +0 -7
  169. data/templates/viddler.mustache +0 -5
  170. data/templates/vimeo.mustache +0 -5
  171. data/templates/yfrog.mustache +0 -4
@@ -2,6 +2,7 @@ module Onebox
2
2
  module Engine
3
3
  class GithubCommitOnebox
4
4
  include Engine
5
+ include LayoutSupport
5
6
  include JSON
6
7
 
7
8
  matches do
@@ -14,29 +15,21 @@ module Onebox
14
15
  end
15
16
 
16
17
  def url
17
- "https://api.github.com/repos/#{match[:owner]}/#{match[:repo]}/commits/#{match[:number]}"
18
+ "https://api.github.com/repos/#{match[:owner]}/#{match[:repository]}/commits/#{match[:sha]}"
18
19
  end
19
20
 
20
21
  private
21
22
 
22
23
  def match
23
- @url.match(/github\.com\/(?<owner>[^\/]+)\/(?<repo>[^\/]+)\/commit\/(?<number>[^\/]+)/)
24
+ @match ||= @url.match(%{github\.com/(?<owner>[^/]+)/(?<repository>[^/]+)/commit/(?<sha>[^/]+)})
24
25
  end
25
26
 
26
27
  def data
27
- {
28
- url: @url,
29
- owner: match[:owner],
30
- repo: match[:repo],
31
- sha: raw["sha"],
32
- gravatar: raw["author"]["avatar_url"],
33
- message: raw["commit"]["message"],
34
- author: raw["author"]["login"],
35
- time_date: raw["commit"]["committer"]["date"],
36
- files_changed: raw["files"].length,
37
- additions: raw["stats"]["additions"],
38
- deletions: raw["stats"]["deletions"]
39
- }
28
+ result = raw.clone
29
+ result['link'] = link
30
+ result['title'] = result['commit']['message']
31
+ result['commit_date'] = Time.parse(result['commit']['author']['date']).strftime("%I:%M%p - %d %b %y")
32
+ result
40
33
  end
41
34
  end
42
35
  end
@@ -2,7 +2,6 @@ module Onebox
2
2
  module Engine
3
3
  class GithubGistOnebox
4
4
  include Engine
5
- include JSON
6
5
 
7
6
  matches do
8
7
  http
@@ -12,22 +11,23 @@ module Onebox
12
11
  end
13
12
 
14
13
  def url
15
- "https://api.github.com/gists/#{match[:number]}"
14
+ "https://api.github.com/gists/#{match[:sha]}"
15
+ end
16
+
17
+ def to_html
18
+ "<script src=\"http://gist.github.com/#{match[:sha]}.js\"></script>"
16
19
  end
17
20
 
18
21
  private
19
22
 
20
- def match
21
- @url.match(/gist\.github\.com\/([^\/]+\/)?(?<number>[0-9a-f]+)/)
23
+ def data
24
+ { sha: match[:sha], title: match[:sha], link: @url }
22
25
  end
23
26
 
24
- def data
25
- {
26
- url: @url,
27
- content: raw["files"].first[1]["content"],
28
- author: raw["user"]["login"]
29
- }
27
+ def match
28
+ @match ||= @url.match(%r{gist\.github\.com/([^/]+/)?(?<sha>[0-9a-f]+)})
30
29
  end
30
+
31
31
  end
32
32
  end
33
33
  end
@@ -2,6 +2,7 @@ module Onebox
2
2
  module Engine
3
3
  class GithubPullRequestOnebox
4
4
  include Engine
5
+ include LayoutSupport
5
6
  include JSON
6
7
 
7
8
  matches do
@@ -14,29 +15,20 @@ module Onebox
14
15
  end
15
16
 
16
17
  def url
17
- "https://api.github.com/repos/#{match[:owner]}/#{match[:repo]}/pulls/#{match[:number]}"
18
+ "https://api.github.com/repos/#{match[:owner]}/#{match[:repository]}/pulls/#{match[:number]}"
18
19
  end
19
20
 
20
21
  private
21
22
 
22
23
  def match
23
- @url.match(/github\.com\/(?<owner>[^\/]+)\/(?<repo>[^\/]+)\/pull\/(?<number>[^\/]+)/)
24
+ @match ||= @url.match(%r{github\.com/(?<owner>[^/]+)/(?<repository>[^/]+)/pull/(?<number>[^/]+)})
24
25
  end
25
26
 
26
27
  def data
27
- {
28
- url: @url,
29
- author: raw["user"]["login"],
30
- gravatar: raw["user"]["avatar_url"],
31
- title: raw["title"],
32
- repo: raw["base"]["repo"]["full_name"],
33
- time_date: raw["created_at"],
34
- commits: raw["commits"],
35
- additions: raw["additions"],
36
- deletions: raw["deletions"],
37
- changed_files: raw["changed_files"],
38
- description: raw["body"]
39
- }
28
+ result = raw.clone
29
+ result['link'] = link
30
+ result['created_at'] = Time.parse(result['created_at']).strftime("%I:%M%p - %d %b %y")
31
+ result
40
32
  end
41
33
  end
42
34
  end
@@ -0,0 +1,30 @@
1
+ module Onebox
2
+ module Engine
3
+ class GooglePlayAppOnebox
4
+ include Engine
5
+ include LayoutSupport
6
+ include HTML
7
+
8
+ matches do
9
+ http
10
+ with("play.")
11
+ domain("google")
12
+ tld("com")
13
+ with("/store/apps/")
14
+ end
15
+
16
+ private
17
+
18
+ def data
19
+ {
20
+ link: link,
21
+ title: raw.css(".document-title div").inner_text,
22
+ developer: raw.css(".document-subtitle.primary").inner_text,
23
+ image: raw.css(".cover-image").first["src"],
24
+ description: raw.css(".text-body div").inner_text,
25
+ price: raw.css(".price.buy meta[itemprop=price]").first["content"]
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -3,8 +3,17 @@ module Onebox
3
3
  module HTML
4
4
  private
5
5
 
6
+ # Overwrite for any custom headers
7
+ def http_params
8
+ {}
9
+ end
10
+
6
11
  def raw
7
- @raw ||= Nokogiri::HTML(open(url, read_timeout: timeout))
12
+ @raw ||= Nokogiri::HTML(open(url, {read_timeout: timeout}.merge(http_params)).read)
13
+ end
14
+
15
+ def html?
16
+ raw.respond_to(:css)
8
17
  end
9
18
  end
10
19
  end
@@ -0,0 +1,13 @@
1
+ module Onebox
2
+ module Engine
3
+ class ImageOnebox
4
+ include Engine
5
+
6
+ matches_regexp /^(https?:)?\/\/.+\.(png|jpg|jpeg|gif|bmp|tif|tiff)$/i
7
+
8
+ def to_html
9
+ "<a href='#{@url}' target='_blank'><img src='#{@url}'></a>"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,23 +2,37 @@ module Onebox
2
2
  module Engine
3
3
  class StackExchangeOnebox
4
4
  include Engine
5
- include HTML
5
+ include LayoutSupport
6
+ include JSON
6
7
 
7
- matches do
8
- http
9
- domain("stackoverflow")
10
- tld("com")
11
- with("/questions/")
8
+ def self.domains
9
+ %w(stackexchange stackoverflow superuser serverfault askubuntu)
12
10
  end
13
11
 
12
+ matches_regexp /^http:\/\/(?:(?:(?<subsubdomain>\w*)\.)?(?<subdomain>\w*)\.)?(?<domain>#{domains.join('|')})\.com\/(?:questions|q)\/(?<question>\d*)/
13
+
14
14
  private
15
15
 
16
+ def match
17
+ @match ||= @url.match(@@matcher)
18
+ end
19
+
20
+ def url
21
+ domain = match[:subsubdomain] || match[:subdomain] || match[:domain]
22
+ "http://api.stackexchange.com/2.1/questions/#{match[:question]}?site=#{domain}"
23
+ end
24
+
16
25
  def data
17
- {
18
- url: @url,
19
- title: raw.css(".question-hyperlink").inner_text,
20
- question: raw.css(".question .post-text p").first.inner_text
21
- }
26
+ return @data if @data
27
+
28
+ result = raw['items'][0]
29
+ if result
30
+ result['creation_date'] =
31
+ Time.at(result['creation_date'].to_i).strftime("%I:%M%p - %d %b %y")
32
+
33
+ result['tags'] = result['tags'].take(4).join(', ')
34
+ end
35
+ @data = result
22
36
  end
23
37
  end
24
38
  end
@@ -0,0 +1,48 @@
1
+ module Onebox
2
+ module Engine
3
+ module StandardEmbed
4
+
5
+ def raw
6
+ return @raw if @raw
7
+ response = fetch_response(url)
8
+
9
+ html_doc = Nokogiri::HTML(response.body)
10
+
11
+ # Determine if we should use OEmbed or OpenGraph
12
+ oembed_alternate = html_doc.at("//link[@type='application/json+oembed']") || html_doc.at("//link[@type='text/json+oembed']")
13
+ if oembed_alternate
14
+ # If the oembed request fails, we can still try the opengraph below.
15
+ begin
16
+ @raw = Onebox::Helpers.symbolize_keys(::MultiJson.load(fetch_response(oembed_alternate['href']).body))
17
+ rescue Errno::ECONNREFUSED, Net::HTTPError, MultiJson::LoadError
18
+ @raw = nil
19
+ end
20
+ end
21
+
22
+ open_graph = OpenGraph.new(response.body, false)
23
+ if @raw
24
+ @raw[:image] = open_graph.images.first if @raw[:image].nil? && open_graph && open_graph.images
25
+
26
+ return @raw
27
+ end
28
+
29
+ @raw = open_graph
30
+ end
31
+
32
+ private
33
+
34
+ def fetch_response(location, limit = 3)
35
+ raise Net::HTTPError.new('HTTP redirect too deep', location) if limit == 0
36
+
37
+ response = Net::HTTP.get_response(URI(location))
38
+ case response
39
+ when Net::HTTPSuccess then response
40
+ when Net::HTTPRedirection then fetch_response(response['location'], limit - 1)
41
+ else
42
+ response.error!
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,100 @@
1
+ module Onebox
2
+ module Engine
3
+ class TwitterStatusOnebox
4
+ include Engine
5
+ include LayoutSupport
6
+ include HTML
7
+
8
+ matches do
9
+ http
10
+ maybe("www.")
11
+ domain("twitter")
12
+ tld("com")
13
+ anything
14
+ has("/status/")
15
+ end
16
+
17
+ private
18
+
19
+ def match
20
+ @match ||= @url.match(%r{twitter\.com/.+?/status/(?<id>\d+)})
21
+ end
22
+
23
+ def client
24
+ Onebox.options.twitter_client
25
+ end
26
+
27
+ def raw
28
+ if client
29
+ @raw ||= OpenStruct.new(client.status(match[:id]).to_hash)
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def access(*keys)
36
+ keys.reduce(raw) do |memo, key|
37
+ memo[key] || memo[key.to_s]
38
+ end
39
+ end
40
+
41
+ def tweet
42
+ if raw.html?
43
+ raw.css(".tweet-text")[0].inner_text
44
+ else
45
+ access(:text)
46
+ end
47
+ end
48
+
49
+ def timestamp
50
+ if raw.html?
51
+ raw.css(".metadata span").inner_text
52
+ else
53
+ access(:created_at)
54
+ end
55
+ end
56
+
57
+ def title
58
+ if raw.html?
59
+ raw.css(".stream-item-header .username").inner_text
60
+ else
61
+ access(:user, :screen_name)
62
+ end
63
+ end
64
+
65
+ def avatar
66
+ if raw.html?
67
+ raw.css(".avatar")[2]["src"]
68
+ else
69
+ access(:user, :profile_image_url)
70
+ end
71
+ end
72
+
73
+ def favorites
74
+ if raw.html?
75
+ raw.css(".stats li .request-favorited-popup").inner_text
76
+ else
77
+ access(:favorite_count)
78
+ end
79
+ end
80
+
81
+ def retweets
82
+ if raw.html?
83
+ raw.css(".stats li .request-retweeted-popup").inner_text
84
+ else
85
+ access(:retweet_count)
86
+ end
87
+ end
88
+
89
+ def data
90
+ { link: link,
91
+ tweet: tweet,
92
+ timestamp: timestamp,
93
+ title: title,
94
+ avatar: avatar,
95
+ favorites: favorites,
96
+ retweets: retweets }
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,223 @@
1
+ module Onebox
2
+ module Engine
3
+ class WhitelistedGenericOnebox
4
+ include Engine
5
+ include StandardEmbed
6
+ include LayoutSupport
7
+
8
+ def self.whitelist=(list)
9
+ @whitelist = list
10
+ end
11
+
12
+ def self.whitelist
13
+ @whitelist ||= default_whitelist.dup
14
+ end
15
+
16
+ def self.default_whitelist
17
+ %w(500px.com
18
+ about.com
19
+ answers.com
20
+ ask.com
21
+ battle.net
22
+ bbc.co.uk
23
+ bbs.boingboing.net
24
+ bestbuy.ca
25
+ bestbuy.com
26
+ blip.tv
27
+ bloomberg.com
28
+ businessinsider.com
29
+ clikthrough.com
30
+ cnet.com
31
+ cnn.com
32
+ collegehumor.com
33
+ coursera.org
34
+ cracked.com
35
+ dailymail.co.uk
36
+ dailymotion.com
37
+ deadline.com
38
+ dell.com
39
+ digg.com
40
+ dotsub.com
41
+ ebay.ca
42
+ ebay.co.uk
43
+ ebay.com
44
+ ehow.com
45
+ espn.go.com
46
+ etsy.com
47
+ findery.com
48
+ flickr.com
49
+ forbes.com
50
+ foxnews.com
51
+ funnyordie.com
52
+ groupon.com
53
+ howtogeek.com
54
+ huffingtonpost.com
55
+ huffingtonpost.ca
56
+ hulu.com
57
+ ign.com
58
+ ikea.com
59
+ imgur.com
60
+ indiatimes.com
61
+ instagr.am
62
+ instagram.com
63
+ itunes.apple.com
64
+ khanacademy.org
65
+ kickstarter.com
66
+ kinomap.com
67
+ mashable.com
68
+ mlb.com
69
+ myspace.com
70
+ nba.com
71
+ npr.org
72
+ photobucket.com
73
+ pinterest.com
74
+ reference.com
75
+ revision3.com
76
+ rottentomatoes.com
77
+ samsung.com
78
+ screenr.com
79
+ scribd.com
80
+ slideshare.net
81
+ soundcloud.com
82
+ sourceforge.net
83
+ spotify.com
84
+ squidoo.com
85
+ techcrunch.com
86
+ ted.com
87
+ thefreedictionary.com
88
+ theglobeandmail.com
89
+ theonion.com
90
+ thestar.com
91
+ thesun.co.uk
92
+ thinkgeek.com
93
+ tmz.com
94
+ torontosun.com
95
+ tumblr.com
96
+ twitpic.com
97
+ usatoday.com
98
+ vimeo.com
99
+ walmart.com
100
+ washingtonpost.com
101
+ wikia.com
102
+ wikihow.com
103
+ wired.com
104
+ wistia.com
105
+ wi.st
106
+ wonderhowto.com
107
+ wsj.com
108
+ zappos.com
109
+ zillow.com)
110
+ end
111
+
112
+ # A re-written URL coverts https:// -> // - it is useful on HTTPS sites that embed
113
+ # youtube for example
114
+ def self.rewrites
115
+ @rewrites ||= default_rewrites.dup
116
+ end
117
+
118
+ def self.rewrites=(new_list)
119
+ @rewrites = new_list
120
+ end
121
+
122
+ def self.default_rewrites
123
+ %w()
124
+ end
125
+
126
+ def self.host_matches(uri, list)
127
+ !!list.find {|h| %r((^|\.)#{Regexp.escape(h)}$).match(uri.host) }
128
+ end
129
+
130
+ def self.===(other)
131
+ if other.kind_of?(URI)
132
+ return WhitelistedGenericOnebox.host_matches(other, WhitelistedGenericOnebox.whitelist)
133
+ else
134
+ super
135
+ end
136
+ end
137
+
138
+ # Generates the HTML for the embedded content
139
+ def photo_type?
140
+ data[:type] =~ /photo/ || data[:type] =~ /image/
141
+ end
142
+
143
+ def rewrite_agnostic(html)
144
+ return html unless html
145
+ uri = URI(@url)
146
+ if WhitelistedGenericOnebox.host_matches(uri, WhitelistedGenericOnebox.rewrites)
147
+ html.gsub!(/https?:\/\//, '//')
148
+ end
149
+ html
150
+ end
151
+
152
+ def generic_html
153
+ return data[:html] if data[:html]
154
+ return html_for_video(data[:video]) if data[:video]
155
+ return image_html if photo_type?
156
+ return nil unless data[:title]
157
+ layout.to_html
158
+ end
159
+
160
+ def to_html
161
+ rewrite_agnostic(generic_html)
162
+ end
163
+
164
+ def placeholder_html
165
+ result = nil
166
+ result = image_html if data[:html] || data[:video] || photo_type?
167
+ result || to_html
168
+ end
169
+
170
+ def data
171
+ return raw if raw.is_a?(Hash)
172
+
173
+ data_hash = { link: link, title: raw.title, description: raw.description }
174
+ data_hash[:image] = raw.images.first if raw.images && raw.images.first
175
+ data_hash[:type] = raw.type if raw.type
176
+
177
+ if raw.metadata && raw.metadata[:video] && raw.metadata[:video].first
178
+ data_hash[:video] = raw.metadata[:video].first
179
+ end
180
+
181
+ data_hash
182
+ end
183
+
184
+ private
185
+
186
+ def image_html
187
+ return @image_html if @image_html
188
+
189
+ return @image_html = "<img src=\"#{data[:image]}\">" if data[:image]
190
+
191
+ if data[:thumbnail_url]
192
+ @image_html = "<img src=\"#{data[:thumbnail_url]}\""
193
+ @image_html << " width=\"#{data[:thumbnail_width]}\"" if data[:thumbnail_width]
194
+ @image_html << " height=\"#{data[:thumbnail_height]}\"" if data[:thumbnail_height]
195
+ @image_html << ">"
196
+ end
197
+
198
+ @image_html
199
+ end
200
+
201
+ def html_for_video(video)
202
+ video_url = video[:_value]
203
+
204
+ if video_url
205
+ html = "<iframe src=\"#{video_url}\" frameborder=\"0\" title=\"#{data[:title]}\""
206
+
207
+ append_attribute(:width, html, video)
208
+ append_attribute(:height, html, video)
209
+
210
+ html << "></iframe>"
211
+ return html
212
+ end
213
+ end
214
+
215
+ def append_attribute(attribute, html, video)
216
+ if video[attribute] && video[attribute].first
217
+ val = video[attribute].first[:_value]
218
+ html << " #{attribute.to_s}=\"#{val}\""
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end