onebox 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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